@takazudo/zudo-doc 0.2.20 → 0.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/bin/gen-z-index.mjs +164 -0
  2. package/bin/tags-audit-runner.ts +126 -0
  3. package/bin/tags-audit.mjs +64 -0
  4. package/dist/ai-chat-modal/index.d.ts +8 -0
  5. package/dist/ai-chat-modal/index.js +243 -0
  6. package/dist/body-foot-util/body-foot-util-area.d.ts +4 -8
  7. package/dist/body-foot-util/edit-link.d.ts +4 -8
  8. package/dist/body-foot-util/index.d.ts +4 -3
  9. package/dist/breadcrumb/breadcrumb.d.ts +5 -9
  10. package/dist/breadcrumb/find-path.d.ts +2 -5
  11. package/dist/breadcrumb/index.d.ts +4 -4
  12. package/dist/breadcrumb/types.d.ts +3 -5
  13. package/dist/category-nav/index.d.ts +86 -0
  14. package/dist/category-nav/index.js +44 -0
  15. package/dist/category-tree-nav/index.d.ts +65 -0
  16. package/dist/category-tree-nav/index.js +24 -0
  17. package/dist/code-group/index.d.ts +10 -0
  18. package/dist/code-group/index.js +37 -0
  19. package/dist/code-syntax/code-block-enhancer-script.d.ts +1 -3
  20. package/dist/code-syntax/code-block-enhancer.d.ts +3 -6
  21. package/dist/code-syntax/index.d.ts +9 -8
  22. package/dist/code-syntax/mermaid-init-script.d.ts +3 -5
  23. package/dist/code-syntax/mermaid-init.d.ts +4 -7
  24. package/dist/code-syntax/tabs-init-script.d.ts +1 -3
  25. package/dist/code-syntax/tabs-init.d.ts +3 -6
  26. package/dist/code-syntax/tabs.d.ts +4 -7
  27. package/dist/color-scheme-utils.d.ts +125 -0
  28. package/dist/color-scheme-utils.js +151 -0
  29. package/dist/compose-meta-title/index.d.ts +7 -0
  30. package/dist/compose-meta-title/index.js +10 -0
  31. package/dist/content/component-map.d.ts +13 -17
  32. package/dist/content/content-blockquote.d.ts +3 -6
  33. package/dist/content/content-code.d.ts +3 -6
  34. package/dist/content/content-code.js +1 -1
  35. package/dist/content/content-link.d.ts +3 -6
  36. package/dist/content/content-link.js +1 -1
  37. package/dist/content/content-ol.d.ts +3 -6
  38. package/dist/content/content-paragraph.d.ts +3 -6
  39. package/dist/content/content-strong.d.ts +3 -6
  40. package/dist/content/content-table.d.ts +3 -6
  41. package/dist/content/content-ul.d.ts +3 -6
  42. package/dist/content/heading-h2.d.ts +3 -6
  43. package/dist/content/heading-h3.d.ts +3 -6
  44. package/dist/content/heading-h4.d.ts +3 -6
  45. package/dist/content/index.d.ts +29 -13
  46. package/dist/content-admonition/index.d.ts +15 -0
  47. package/dist/content-admonition/index.js +14 -0
  48. package/dist/design-token-panel-bootstrap.d.ts +38 -0
  49. package/dist/design-token-panel-bootstrap.js +29 -0
  50. package/dist/desktop-sidebar-toggle-island/index.d.ts +5 -0
  51. package/dist/desktop-sidebar-toggle-island/index.js +62 -0
  52. package/dist/details/details.d.ts +3 -7
  53. package/dist/details/index.d.ts +2 -2
  54. package/dist/doc-body-end/index.d.ts +21 -0
  55. package/dist/doc-body-end/index.js +15 -0
  56. package/dist/doc-content-header/index.d.ts +69 -0
  57. package/dist/doc-content-header/index.js +49 -0
  58. package/dist/doc-history/index.d.ts +10 -0
  59. package/dist/doc-history/index.js +407 -0
  60. package/dist/doc-history-area/index.d.ts +84 -0
  61. package/dist/doc-history-area/index.js +76 -0
  62. package/dist/doc-metainfo-area/index.d.ts +46 -0
  63. package/dist/doc-metainfo-area/index.js +41 -0
  64. package/dist/doc-page-props/index.d.ts +93 -0
  65. package/dist/doc-page-props/index.js +0 -0
  66. package/dist/doc-page-renderer/index.d.ts +128 -0
  67. package/dist/doc-page-renderer/index.js +103 -0
  68. package/dist/doc-page-shell/index.d.ts +136 -0
  69. package/dist/doc-page-shell/index.js +127 -0
  70. package/dist/doc-pager/index.d.ts +25 -0
  71. package/dist/doc-pager/index.js +41 -0
  72. package/dist/doc-route-entries/index.d.ts +125 -0
  73. package/dist/doc-route-entries/index.js +76 -0
  74. package/dist/doc-route-paths/index.d.ts +54 -0
  75. package/dist/doc-route-paths/index.js +61 -0
  76. package/dist/doc-tags-area/index.d.ts +38 -0
  77. package/dist/doc-tags-area/index.js +30 -0
  78. package/dist/doclayout/anchors.d.ts +7 -9
  79. package/dist/doclayout/doc-layout-with-defaults.d.ts +16 -12
  80. package/dist/doclayout/doc-layout.d.ts +5 -9
  81. package/dist/doclayout/index.d.ts +6 -6
  82. package/dist/extract-headings/index.d.ts +43 -0
  83. package/dist/extract-headings/index.js +111 -0
  84. package/dist/factory-context/index.d.ts +80 -0
  85. package/dist/factory-context/index.js +0 -0
  86. package/dist/features.css +882 -0
  87. package/dist/footer/footer.d.ts +4 -8
  88. package/dist/footer/index.d.ts +13 -3
  89. package/dist/footer/types.d.ts +4 -6
  90. package/dist/footer-with-defaults/index.d.ts +63 -0
  91. package/dist/footer-with-defaults/index.js +128 -0
  92. package/dist/frontmatter-preview-data/index.d.ts +26 -0
  93. package/dist/frontmatter-preview-data/index.js +23 -0
  94. package/dist/github-helpers/index.d.ts +17 -0
  95. package/dist/github-helpers/index.js +16 -0
  96. package/dist/head/doc-head.d.ts +3 -6
  97. package/dist/head/index.d.ts +9 -5
  98. package/dist/head/og-tags.d.ts +4 -7
  99. package/dist/head/twitter-card.d.ts +3 -6
  100. package/dist/head/types.d.ts +1 -3
  101. package/dist/head-with-defaults/index.d.ts +49 -0
  102. package/dist/head-with-defaults/index.js +62 -0
  103. package/dist/header/header.d.ts +6 -10
  104. package/dist/header/index.d.ts +16 -6
  105. package/dist/header/nav-active.d.ts +5 -7
  106. package/dist/header/nav-overflow-script.d.ts +1 -3
  107. package/dist/header/right-items.d.ts +3 -6
  108. package/dist/header/types.d.ts +10 -12
  109. package/dist/header-with-defaults/index.d.ts +77 -0
  110. package/dist/header-with-defaults/index.js +163 -0
  111. package/dist/html-preview-wrapper/dedent.d.ts +1 -3
  112. package/dist/html-preview-wrapper/highlighted-code.d.ts +3 -7
  113. package/dist/html-preview-wrapper/html-preview-wrapper.d.ts +6 -10
  114. package/dist/html-preview-wrapper/html-preview.d.ts +5 -9
  115. package/dist/html-preview-wrapper/index.d.ts +8 -5
  116. package/dist/html-preview-wrapper/preflight.d.ts +1 -3
  117. package/dist/html-preview-wrapper/preview-base.d.ts +4 -8
  118. package/dist/i18n-version/index.d.ts +7 -5
  119. package/dist/i18n-version/language-switcher.d.ts +5 -8
  120. package/dist/i18n-version/types.d.ts +3 -5
  121. package/dist/i18n-version/version-banner.d.ts +4 -8
  122. package/dist/i18n-version/version-switcher.d.ts +7 -10
  123. package/dist/icons/index.d.ts +9 -13
  124. package/dist/image-enlarge/index.d.ts +13 -0
  125. package/dist/image-enlarge/index.js +176 -0
  126. package/dist/index.d.ts +26 -2
  127. package/dist/inline-version-switcher/index.d.ts +31 -0
  128. package/dist/inline-version-switcher/index.js +44 -0
  129. package/dist/integrations/claude-resources/escape-for-mdx.d.ts +1 -3
  130. package/dist/integrations/claude-resources/generate.d.ts +2 -4
  131. package/dist/integrations/claude-resources/index.d.ts +7 -10
  132. package/dist/integrations/doc-history/index.d.ts +21 -24
  133. package/dist/integrations/doc-history/pre-build.d.ts +7 -9
  134. package/dist/integrations/llms-txt/dev-middleware.d.ts +7 -11
  135. package/dist/integrations/llms-txt/emit.d.ts +2 -7
  136. package/dist/integrations/llms-txt/generate.d.ts +3 -8
  137. package/dist/integrations/llms-txt/index.d.ts +33 -8
  138. package/dist/integrations/llms-txt/load.d.ts +3 -7
  139. package/dist/integrations/llms-txt/strip.d.ts +2 -6
  140. package/dist/integrations/llms-txt/types.d.ts +9 -13
  141. package/dist/integrations/search-index/build-emitter.d.ts +4 -7
  142. package/dist/integrations/search-index/collect.d.ts +2 -5
  143. package/dist/integrations/search-index/dev-middleware.d.ts +5 -8
  144. package/dist/integrations/search-index/index.d.ts +7 -5
  145. package/dist/integrations/search-index/types.d.ts +5 -7
  146. package/dist/island-types/index.d.ts +44 -0
  147. package/dist/island-types/index.js +12 -0
  148. package/dist/locale-merge/index.d.ts +114 -0
  149. package/dist/locale-merge/index.js +27 -0
  150. package/dist/math-block/index.d.ts +18 -0
  151. package/dist/math-block/index.js +29 -0
  152. package/dist/md-utils/index.d.ts +6 -8
  153. package/dist/md-utils/index.js +2 -1
  154. package/dist/mdx-components/index.d.ts +46 -0
  155. package/dist/mdx-components/index.js +161 -0
  156. package/dist/mermaid-enlarge/index.d.ts +11 -0
  157. package/dist/mermaid-enlarge/index.js +290 -0
  158. package/dist/metainfo/doc-metainfo.d.ts +5 -9
  159. package/dist/metainfo/doc-tags.d.ts +7 -11
  160. package/dist/metainfo/frontmatter-preview.d.ts +8 -12
  161. package/dist/metainfo/index.d.ts +6 -4
  162. package/dist/nav-data-prep/index.d.ts +72 -0
  163. package/dist/nav-data-prep/index.js +34 -0
  164. package/dist/nav-indexing/category-nav.d.ts +4 -8
  165. package/dist/nav-indexing/category-nav.js +1 -1
  166. package/dist/nav-indexing/category-tree-nav.d.ts +4 -8
  167. package/dist/nav-indexing/doc-card-grid.d.ts +4 -8
  168. package/dist/nav-indexing/docs-sitemap.d.ts +4 -8
  169. package/dist/nav-indexing/index.d.ts +37 -10
  170. package/dist/nav-indexing/nav-card-grid.d.ts +4 -8
  171. package/dist/nav-indexing/site-tree-nav-demo.d.ts +4 -8
  172. package/dist/nav-indexing/tag-nav.d.ts +6 -10
  173. package/dist/nav-indexing/types.d.ts +6 -8
  174. package/dist/nav-indexing/versions-page-content.d.ts +4 -8
  175. package/dist/nav-scope/index.d.ts +41 -0
  176. package/dist/nav-scope/index.js +41 -0
  177. package/dist/nav-source-cache/index.d.ts +13 -0
  178. package/dist/nav-source-cache/index.js +28 -0
  179. package/dist/nav-source-docs/index.d.ts +169 -0
  180. package/dist/nav-source-docs/index.js +123 -0
  181. package/dist/page-loading/index.d.ts +1 -2
  182. package/dist/page-loading/page-loading-overlay.d.ts +4 -8
  183. package/dist/plugins/claude-resources.d.ts +3 -0
  184. package/dist/plugins/claude-resources.js +27 -0
  185. package/dist/plugins/connect-adapter.d.ts +31 -0
  186. package/dist/plugins/connect-adapter.js +78 -0
  187. package/dist/plugins/doc-history.d.ts +3 -0
  188. package/dist/plugins/doc-history.js +54 -0
  189. package/dist/plugins/llms-txt.d.ts +3 -0
  190. package/dist/plugins/llms-txt.js +48 -0
  191. package/dist/plugins/plugin-utils.d.ts +17 -0
  192. package/dist/plugins/plugin-utils.js +11 -0
  193. package/dist/plugins/search-index.d.ts +3 -0
  194. package/dist/plugins/search-index.js +24 -0
  195. package/dist/preset.d.ts +152 -0
  196. package/dist/preset.js +169 -0
  197. package/dist/render-markdown/index.d.ts +5 -0
  198. package/dist/render-markdown/index.js +115 -0
  199. package/dist/robots.d.ts +36 -0
  200. package/dist/robots.js +17 -0
  201. package/dist/route-enumerators/index.d.ts +204 -0
  202. package/dist/route-enumerators/index.js +156 -0
  203. package/dist/safelist.css +1 -1
  204. package/dist/search-widget/index.d.ts +38 -0
  205. package/dist/search-widget/index.js +169 -0
  206. package/dist/search-widget-script/index.d.ts +18 -0
  207. package/dist/search-widget-script/index.js +465 -0
  208. package/dist/settings.d.ts +255 -0
  209. package/dist/settings.js +0 -0
  210. package/dist/sidebar/index.d.ts +21 -3
  211. package/dist/sidebar/sidebar.d.ts +5 -9
  212. package/dist/sidebar/types.d.ts +4 -6
  213. package/dist/sidebar-prepaint/index.d.ts +21 -0
  214. package/dist/sidebar-prepaint/index.js +23 -0
  215. package/dist/sidebar-resizer/index.d.ts +2 -6
  216. package/dist/sidebar-resizer/sidebar-resizer-init.d.ts +6 -10
  217. package/dist/sidebar-toggle-island/index.d.ts +13 -0
  218. package/dist/sidebar-toggle-island/index.js +122 -0
  219. package/dist/sidebar-tree/build-tree.d.ts +4 -8
  220. package/dist/sidebar-tree/category-meta.d.ts +3 -6
  221. package/dist/sidebar-tree/index.d.ts +18 -3
  222. package/dist/sidebar-tree/types.d.ts +6 -8
  223. package/dist/sidebar-tree-island/index.d.ts +13 -0
  224. package/dist/sidebar-tree-island/index.js +454 -0
  225. package/dist/sidebar-utils/index.d.ts +64 -0
  226. package/dist/sidebar-utils/index.js +88 -0
  227. package/dist/sidebar-with-defaults/index.d.ts +38 -0
  228. package/dist/sidebar-with-defaults/index.js +45 -0
  229. package/dist/site-tree-nav/index.d.ts +71 -0
  230. package/dist/site-tree-nav/index.js +36 -0
  231. package/dist/site-tree-nav-island/index.d.ts +11 -0
  232. package/dist/site-tree-nav-island/index.js +176 -0
  233. package/dist/slug/index.d.ts +4 -0
  234. package/dist/slug/index.js +19 -0
  235. package/dist/smart-break/index.d.ts +55 -0
  236. package/dist/{toc/smart-break.js → smart-break/index.js} +30 -3
  237. package/dist/tab-item/index.d.ts +2 -2
  238. package/dist/tab-item/tab-item.d.ts +6 -7
  239. package/dist/tag-helpers/index.d.ts +40 -0
  240. package/dist/tag-helpers/index.js +54 -0
  241. package/dist/tag-pages/index.d.ts +114 -0
  242. package/dist/tag-pages/index.js +146 -0
  243. package/dist/tags-audit.d.ts +107 -0
  244. package/dist/tags-audit.js +321 -0
  245. package/dist/theme/color-scheme-provider.d.ts +4 -8
  246. package/dist/theme/color-tweak-export-modal.d.ts +4 -7
  247. package/dist/theme/design-token-serde.d.ts +14 -17
  248. package/dist/theme/design-token-types.d.ts +4 -6
  249. package/dist/theme/iframe-bridge.d.ts +12 -14
  250. package/dist/theme/index.d.ts +7 -9
  251. package/dist/theme/theme-toggle.d.ts +3 -8
  252. package/dist/theme-toggle/color-scheme-sync.d.ts +5 -7
  253. package/dist/theme-toggle/index.d.ts +4 -8
  254. package/dist/toc/cx.d.ts +2 -3
  255. package/dist/toc/index.d.ts +8 -6
  256. package/dist/toc/mobile-toc.d.ts +5 -9
  257. package/dist/toc/mobile-toc.js +1 -1
  258. package/dist/toc/toc-title.d.ts +1 -3
  259. package/dist/toc/toc.d.ts +5 -9
  260. package/dist/toc/toc.js +1 -1
  261. package/dist/toc/types.d.ts +1 -3
  262. package/dist/toc/use-active-heading.d.ts +4 -7
  263. package/dist/transitions/index.d.ts +1 -1
  264. package/dist/transitions/page-events.d.ts +4 -6
  265. package/dist/tree-nav-shared/index.d.ts +22 -0
  266. package/dist/tree-nav-shared/index.js +66 -0
  267. package/dist/url-helpers/index.d.ts +37 -0
  268. package/dist/url-helpers/index.js +106 -0
  269. package/dist/url-normalizer/index.d.ts +39 -1
  270. package/dist/url-normalizer/normalize.d.ts +3 -5
  271. package/dist/use-modal-dialog/index.d.ts +70 -0
  272. package/dist/use-modal-dialog/index.js +73 -0
  273. package/dist/versions-page/index.d.ts +55 -0
  274. package/dist/versions-page/index.js +73 -0
  275. package/package.json +290 -10
  276. package/dist/toc/smart-break.d.ts +0 -27
@@ -0,0 +1,882 @@
1
+ /* ============================================================================
2
+ * @takazudo/zudo-doc — non-island feature stylesheet
3
+ *
4
+ * Shipped to consumers as `@takazudo/zudo-doc/features.css` (copied to
5
+ * `dist/features.css` by scripts/copy-features-css.mjs on build). Provides
6
+ * feature CSS that is NOT coupled to a specific Preact island — it is shared
7
+ * across all projects that use @takazudo/zudo-doc regardless of which islands
8
+ * are active. See zudolab/zudo-doc#2331.
9
+ *
10
+ * ── Consumer contract ──────────────────────────────────────────────────────
11
+ * The consumer's @theme MUST define the custom properties consumed below:
12
+ * --color-{fg,muted,accent,surface,code-bg,code-fg,success,warning,
13
+ * matched-keyword-bg,matched-keyword-fg}
14
+ * --spacing-{hsp-sm,hsp-2xs,hsp-lg,hsp-md,hsp-xl,vsp-xs,vsp-2xs,vsp-md,
15
+ * icon-sm}
16
+ * --z-index-local-1
17
+ * --radius-{DEFAULT,lg}
18
+ * --font-{mono,sans}
19
+ * --text-{small,caption}
20
+ * --leading-relaxed
21
+ * --zd-fg
22
+ * --zd-sidebar-w
23
+ * --zd-header-h
24
+ * --zd-transition-slow
25
+ * --zd-transition-slower
26
+ * --default-transition-duration
27
+ * All of these are defined by the project's @theme block (which is a
28
+ * pre-condition before @importing this file).
29
+ * ─────────────────────────────────────────────────────────────────────────── */
30
+
31
+ /* ========================================
32
+ * Code block buttons (copy + word wrap)
33
+ * ======================================== */
34
+
35
+ .code-block-wrapper {
36
+ position: relative;
37
+ }
38
+
39
+ pre[class^="syntect-"].word-wrap {
40
+ overflow-x: hidden;
41
+ }
42
+
43
+ pre[class^="syntect-"].word-wrap code {
44
+ white-space: pre-wrap;
45
+ overflow-wrap: anywhere;
46
+ }
47
+
48
+ .code-block-sr-announce {
49
+ position: absolute;
50
+ width: 1px;
51
+ height: 1px;
52
+ overflow: hidden;
53
+ clip: rect(0, 0, 0, 0);
54
+ white-space: nowrap;
55
+ }
56
+
57
+ .code-buttons {
58
+ position: absolute;
59
+ top: var(--spacing-hsp-sm);
60
+ right: var(--spacing-hsp-sm);
61
+ display: flex;
62
+ gap: var(--spacing-hsp-2xs);
63
+ opacity: 0;
64
+ transition: opacity 150ms;
65
+ z-index: var(--z-index-local-1);
66
+ }
67
+
68
+ .code-block-wrapper:hover .code-buttons,
69
+ .code-block-wrapper:focus-within .code-buttons {
70
+ opacity: 1;
71
+ }
72
+
73
+ .code-btn {
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ width: 2rem; /* 32px — one-off button box; no --spacing-icon-* at this size (two-tier: keep as arbitrary) */
78
+ height: 2rem; /* 32px — see above */
79
+ padding: 0;
80
+ border: 1px solid var(--color-muted);
81
+ border-radius: var(--radius-lg);
82
+ background-color: var(--color-surface);
83
+ color: var(--color-fg);
84
+ cursor: pointer;
85
+ transition:
86
+ color 150ms,
87
+ border-color 150ms,
88
+ background-color 150ms;
89
+ }
90
+
91
+ .code-btn:hover {
92
+ color: var(--color-fg);
93
+ border-color: var(--color-fg);
94
+ }
95
+
96
+ .code-btn .code-icon {
97
+ width: var(--spacing-icon-sm); /* 16px — standard UI icon */
98
+ height: var(--spacing-icon-sm); /* 16px — standard UI icon */
99
+ }
100
+
101
+ /* Copy: icon swap */
102
+ .code-btn-copy .code-icon-check {
103
+ display: none;
104
+ }
105
+ .code-btn-copy .code-icon-copy {
106
+ display: block;
107
+ }
108
+ .code-btn-copy.copied .code-icon-check {
109
+ display: block;
110
+ color: var(--color-success);
111
+ }
112
+ .code-btn-copy.copied .code-icon-copy {
113
+ display: none;
114
+ }
115
+
116
+ /* Word wrap active state */
117
+ .code-btn-wrap.active {
118
+ color: var(--color-accent);
119
+ border-color: var(--color-accent);
120
+ }
121
+
122
+ @media (scripting: none) {
123
+ .code-buttons {
124
+ display: none;
125
+ }
126
+ }
127
+
128
+ /* ========================================
129
+ * Code-block syntax-highlight token color rule
130
+ * ======================================== */
131
+
132
+ /* Code-block token colors come from CSS custom properties in two cases on this
133
+ * site, both resolved here via light-dark():
134
+ *
135
+ * 1. Build-time — zfb DUAL-theme syntect (codeHighlight.themeLight/themeDark
136
+ * in zfb.config.ts). Emits <pre class="syntect-dual"> whose token spans
137
+ * carry style="--shiki-light:#X;--shiki-dark:#Y" (no `color` declaration)
138
+ * and whose <pre> carries --shiki-{light,dark}-bg. Zero client JS.
139
+ *
140
+ * 2. Runtime — the HtmlPreview component's Shiki blocks (<pre class="shiki">),
141
+ * which emit the same --shiki-* custom properties.
142
+ *
143
+ * Both resolve through the `color-scheme` property, which ColorSchemeProvider /
144
+ * ThemeToggle toggle per active theme — the same mechanism the palette tokens
145
+ * use — so code follows the in-page light/dark switch.
146
+ *
147
+ * Compatibility: SINGLE-theme syntect (the zfb default, NOT used here) instead
148
+ * bakes inline style="color:#hex". This rule deliberately uses NO !important so
149
+ * that such an inline `color` — a higher-precedence author declaration — still
150
+ * wins, leaving single-theme output untouched. The --shiki-* spans have no
151
+ * inline `color`, so the rule applies cleanly. Same logic for background-color
152
+ * on the <pre>. See zudolab/zudo-doc#1457.
153
+ *
154
+ * NOTE: the zdtp design-token panel does NOT highlight code — its Shiki
155
+ * integration is a no-op stub upstream. Earlier revisions of this comment
156
+ * wrongly attributed the --shiki-* vars to a zdtp client-side re-highlight. */
157
+ /* Token color + font-style on the spans (and harmlessly on the <pre>/<code>,
158
+ * where the per-token --shiki-* vars are undefined so the declaration is
159
+ * ignored). */
160
+ [data-theme] .shiki,
161
+ [data-theme] .shiki span,
162
+ [data-theme] pre[class^="syntect-"],
163
+ [data-theme] pre[class^="syntect-"] span {
164
+ color: light-dark(var(--shiki-light), var(--shiki-dark));
165
+ font-style: light-dark(
166
+ var(--shiki-light-font-style, inherit),
167
+ var(--shiki-dark-font-style, inherit)
168
+ );
169
+ }
170
+
171
+ /* Background only on the <pre> wrapper — deliberately NOT on token spans. The
172
+ * --shiki-*-bg vars are set inline on the <pre> and inherit down to spans;
173
+ * painting them per-span would lay an opaque base background over the
174
+ * translucent line-/word-highlight backgrounds that sit on the enclosing
175
+ * .line span (see .line.highlighted below). */
176
+ [data-theme] .shiki,
177
+ [data-theme] pre[class^="syntect-"] {
178
+ background-color: light-dark(var(--shiki-light-bg), var(--shiki-dark-bg));
179
+ }
180
+
181
+ /* HtmlPreview component — Shiki code blocks
182
+ * Token colors inherit from the global [data-theme] .shiki rule above.
183
+ * These rules only adjust layout and background for the preview context. */
184
+ .zd-html-preview-code pre.shiki {
185
+ margin: 0;
186
+ padding: var(--spacing-hsp-md);
187
+ font-size: var(--text-caption);
188
+ line-height: 1.6;
189
+ overflow-x: auto;
190
+ }
191
+
192
+ .zd-html-preview-code pre.shiki code {
193
+ font-family: var(--font-mono);
194
+ white-space: pre;
195
+ }
196
+
197
+ /* ========================================
198
+ * Code block line highlighting
199
+ * ======================================== */
200
+
201
+ /* Line highlighting via {1,3-5} meta syntax.
202
+ * zfb emits data-line-highlight="true" on the <span class="line"> element
203
+ * (verified empirically at next.13). The .highlighted class form is kept for
204
+ * forward-compat in case a future zfb version emits both. */
205
+ pre[class^="syntect-"] .line.highlighted,
206
+ pre[class^="syntect-"] [data-line-highlight="true"] {
207
+ background-color: color-mix(in srgb, var(--color-accent) 15%, transparent);
208
+ }
209
+
210
+ /* Word highlighting via /word/ meta syntax */
211
+ pre[class^="syntect-"] .line .highlighted-word {
212
+ background-color: color-mix(in srgb, var(--color-accent) 25%, transparent);
213
+ border-bottom: 1px solid var(--color-accent);
214
+ }
215
+
216
+ /* ========================================
217
+ * Code block titles
218
+ * ======================================== */
219
+
220
+ .code-block-container {
221
+ margin-top: 1em;
222
+ margin-bottom: 1em;
223
+ }
224
+
225
+ .code-block-title {
226
+ font-family: var(--font-mono);
227
+ font-size: var(--text-small);
228
+ color: var(--color-muted);
229
+ background-color: var(--color-code-bg);
230
+ border: 1px solid var(--color-muted);
231
+ border-bottom: none;
232
+ padding: var(--spacing-vsp-2xs) var(--spacing-hsp-lg);
233
+ }
234
+
235
+ .code-block-container pre[class^="syntect-"] {
236
+ margin-top: 0 !important;
237
+ border-top-left-radius: 0;
238
+ border-top-right-radius: 0;
239
+ }
240
+
241
+ /* ========================================
242
+ * CodeGroup raw-code panels (codeTabs Option A)
243
+ *
244
+ * zfb's :::code-group emits <CodeGroup tabs={[...]}> with one
245
+ * <pre data-lang="…">{RAW text}</pre> child per fence. These <pre> elements
246
+ * are NOT syntect-highlighted (the Rust pipeline doesn't highlight inside
247
+ * code-group fences), so they get no `.syntect-*` class. Apply explicit
248
+ * code-block visual treatment via tokens to match the syntect-highlighted
249
+ * code blocks surrounding them.
250
+ * ======================================== */
251
+
252
+ .code-group-panel pre[data-lang] {
253
+ font-family: var(--font-mono);
254
+ font-size: var(--text-small);
255
+ line-height: var(--leading-relaxed);
256
+ background-color: var(--color-code-bg);
257
+ color: var(--color-code-fg);
258
+ padding: var(--spacing-vsp-xs) var(--spacing-hsp-lg);
259
+ overflow-x: auto;
260
+ border-radius: 0 0 var(--radius-DEFAULT) var(--radius-DEFAULT);
261
+ margin: 0;
262
+ }
263
+
264
+ /* ========================================
265
+ * KaTeX math equations
266
+ * ======================================== */
267
+
268
+ .katex {
269
+ font-size: 1.1em;
270
+ }
271
+
272
+ .katex-display {
273
+ margin: var(--spacing-vsp-md) 0;
274
+ overflow-x: auto;
275
+ overflow-y: hidden;
276
+ padding: var(--spacing-vsp-xs) 0;
277
+ }
278
+
279
+ .katex-display > .katex {
280
+ white-space: nowrap;
281
+ }
282
+
283
+ /* Make KaTeX respect our color scheme */
284
+ .katex .base {
285
+ color: var(--zd-fg);
286
+ }
287
+
288
+ /* ========================================
289
+ * Desktop sidebar toggle
290
+ * ======================================== */
291
+
292
+ @media (min-width: 1024px) {
293
+ #desktop-sidebar {
294
+ transition:
295
+ transform var(--zd-transition-slow) ease-in-out,
296
+ visibility var(--zd-transition-slow);
297
+ }
298
+
299
+ html[data-sidebar-hidden] #desktop-sidebar {
300
+ transform: translateX(calc(-1 * var(--zd-sidebar-w)));
301
+ visibility: hidden;
302
+ }
303
+
304
+ .zd-sidebar-content-wrapper {
305
+ transition: margin-left var(--zd-transition-slow) ease-in-out;
306
+ }
307
+
308
+ html[data-sidebar-hidden] .zd-sidebar-content-wrapper {
309
+ margin-left: 0;
310
+ }
311
+
312
+ /* When hidden via the toggle, narrow the content band to the
313
+ * hide_sidebar frontmatter width so it centers (the flex parent already
314
+ * applies justify-content: center) instead of leaving a dead gap where
315
+ * the sidebar was. 80rem must match the `max-w-[80rem]` hide_sidebar
316
+ * branch in doc-layout.tsx. These rules are unlayered, so they win over
317
+ * the Tailwind `max-w-[clamp(...)]` utility (utilities layer). (#2002) */
318
+ .zd-doc-content-band {
319
+ transition: max-width var(--zd-transition-slow) ease-in-out;
320
+ }
321
+
322
+ html[data-sidebar-hidden] .zd-doc-content-band {
323
+ max-width: 80rem;
324
+ }
325
+ }
326
+
327
+ /* Sidebar toggle button — left position uses CSS variable, needs global rule */
328
+ @media (min-width: 1024px) {
329
+ .zd-desktop-sidebar-toggle {
330
+ left: var(--zd-sidebar-w);
331
+ }
332
+
333
+ html[data-sidebar-hidden] .zd-desktop-sidebar-toggle {
334
+ left: 0;
335
+ }
336
+ }
337
+
338
+ /* The SPA-swap flash guard (`data-sidebar-no-transition`) was removed once
339
+ * doc-layout adopted <ClientRouter preserveHtmlAttrs={["data-sidebar-hidden",
340
+ * ...]} /> (zfb-runtime >= 0.1.0-next.52): the attribute now survives the swap
341
+ * before paint, so the sidebar never wipes-and-restores and no geometry
342
+ * transition fires mid-swap. Retires the #2198 workaround (zudolab/zudo-doc#2200). */
343
+
344
+ /* ========================================
345
+ * Page transition animations (view-transition chrome)
346
+ * ======================================== */
347
+
348
+ @keyframes contentFadeIn {
349
+ from {
350
+ opacity: 0;
351
+ transform: translateY(-0.75rem);
352
+ }
353
+ to {
354
+ opacity: 1;
355
+ transform: translateY(0);
356
+ }
357
+ }
358
+
359
+ @keyframes contentFadeOut {
360
+ from {
361
+ opacity: 1;
362
+ }
363
+ to {
364
+ opacity: 0;
365
+ }
366
+ }
367
+
368
+ /* Root cross-fade for same-document View Transitions (Strategy B).
369
+ *
370
+ * @view-transition { navigation: auto; } (Strategy A, cross-document) is
371
+ * deleted — Strategy B uses <ClientRouter /> which drives same-document
372
+ * transitions via document.startViewTransition on each navigation.
373
+ *
374
+ * Chrome extraction via view-transition-name (Strategy B+, zudolab/zudo-doc#1558):
375
+ * <header>, <aside id="desktop-sidebar">, <footer>, and the desktop-sidebar-toggle
376
+ * button each carry a data-zfb-transition-persist attribute whose value is keyed
377
+ * by locale and nav-section. The four attribute selectors below assign a stable
378
+ * view-transition-name based on the attribute value prefix, extracting those
379
+ * elements from the root snapshot into their own named layers:
380
+ * - header-{lang} → zfb-header
381
+ * - sidebar-{locale}-… → zfb-sidebar
382
+ * - footer-{lang} → zfb-footer
383
+ * - desktop-sidebar-toggle → zfb-sidebar-toggle
384
+ *
385
+ * Once extracted, the root cross-fade animates only non-chrome content (main,
386
+ * article, TOC, etc.). The twelve ::view-transition-{old,new,group}(<name>)
387
+ * rules disable animation for all four chrome layers. The group pseudo must be
388
+ * neutralised too — even when old/new are static the group container can still
389
+ * produce a geometry-morph animation when snapshot size/position differs.
390
+ *
391
+ * Entry/exit cross-fade (zudolab/zudo-doc#2072): animation: none is only
392
+ * correct when the chrome element exists on BOTH pages of a navigation.
393
+ * When it exists on one side only (docs page with sidebar → top page
394
+ * without), the named group holds a single snapshot — frozen at full
395
+ * opacity for the whole transition, then dropped abruptly at finish. The
396
+ * :only-child rules below detect that one-sided case and cross-fade the
397
+ * lone snapshot in sync with the root content fade (spec-standard
398
+ * entry/exit pattern; :only-child outranks the animation: none rules via
399
+ * the extra pseudo-class specificity). */
400
+
401
+ /* Chrome extraction — assign view-transition-name from data-zfb-transition-persist */
402
+ [data-zfb-transition-persist^="header-"] { view-transition-name: zfb-header; }
403
+ [data-zfb-transition-persist^="sidebar-"] { view-transition-name: zfb-sidebar; }
404
+ [data-zfb-transition-persist^="footer-"] { view-transition-name: zfb-footer; }
405
+ [data-zfb-transition-persist="desktop-sidebar-toggle"] { view-transition-name: zfb-sidebar-toggle; }
406
+
407
+ /* Disable animation for all four chrome layers (old, new, and group) */
408
+ ::view-transition-old(zfb-header),
409
+ ::view-transition-new(zfb-header),
410
+ ::view-transition-group(zfb-header),
411
+ ::view-transition-old(zfb-sidebar),
412
+ ::view-transition-new(zfb-sidebar),
413
+ ::view-transition-group(zfb-sidebar),
414
+ ::view-transition-old(zfb-footer),
415
+ ::view-transition-new(zfb-footer),
416
+ ::view-transition-group(zfb-footer),
417
+ ::view-transition-old(zfb-sidebar-toggle),
418
+ ::view-transition-new(zfb-sidebar-toggle),
419
+ ::view-transition-group(zfb-sidebar-toggle) { animation: none; }
420
+
421
+ /* Entry/exit: chrome element present on one side only (#2072).
422
+ * Exit — lone old snapshot fades out with the content cross-fade. */
423
+ ::view-transition-old(zfb-header):only-child,
424
+ ::view-transition-old(zfb-sidebar):only-child,
425
+ ::view-transition-old(zfb-footer):only-child,
426
+ ::view-transition-old(zfb-sidebar-toggle):only-child {
427
+ animation: var(--default-transition-duration) ease-in both contentFadeOut;
428
+ }
429
+ /* Entry — lone new snapshot fades in with the content cross-fade. */
430
+ ::view-transition-new(zfb-header):only-child,
431
+ ::view-transition-new(zfb-sidebar):only-child,
432
+ ::view-transition-new(zfb-footer):only-child,
433
+ ::view-transition-new(zfb-sidebar-toggle):only-child {
434
+ animation: var(--zd-transition-slower) ease-out both contentFadeIn;
435
+ }
436
+
437
+ /* Root cross-fade rules — animate only the non-chrome snapshot */
438
+ ::view-transition-old(root) {
439
+ animation: var(--default-transition-duration) ease-in both contentFadeOut;
440
+ }
441
+ ::view-transition-new(root) {
442
+ animation: var(--zd-transition-slower) ease-out both contentFadeIn;
443
+ }
444
+
445
+ /* Reduced motion: collapse all view-transition animation to an instant
446
+ * swap (zudolab/zudo-doc#2086). With every snapshot animation at none the
447
+ * transition settles immediately — no cross-fade, no translateY slide.
448
+ * Covers the root cross-fade and the #2072 :only-child entry/exit rules;
449
+ * the both-sides chrome layers are already animation: none above. Equal
450
+ * specificity per selector, but later in source order, so these win.
451
+ * ::view-transition-group(root) must be neutralized too (zudolab/zzmod#845):
452
+ * the UA animates the root group for its full duration even when the old/new
453
+ * root snapshots are at animation: none, leaving a brief frozen,
454
+ * non-interactive frame. The chrome groups are already animation: none in the
455
+ * unconditional chrome block above, so only the root group is added here. */
456
+ @media (prefers-reduced-motion: reduce) {
457
+ ::view-transition-old(root),
458
+ ::view-transition-new(root),
459
+ ::view-transition-group(root),
460
+ ::view-transition-old(zfb-header):only-child,
461
+ ::view-transition-old(zfb-sidebar):only-child,
462
+ ::view-transition-old(zfb-footer):only-child,
463
+ ::view-transition-old(zfb-sidebar-toggle):only-child,
464
+ ::view-transition-new(zfb-header):only-child,
465
+ ::view-transition-new(zfb-sidebar):only-child,
466
+ ::view-transition-new(zfb-footer):only-child,
467
+ ::view-transition-new(zfb-sidebar-toggle):only-child {
468
+ animation: none;
469
+ }
470
+ }
471
+
472
+ /* ========================================
473
+ * AI Chat markdown (.ai-chat-md)
474
+ *
475
+ * Compact typography for chat bubbles.
476
+ * Moved from src/styles/global.css to the package by S3 (epic #2344).
477
+ * ======================================== */
478
+
479
+ .ai-chat-md :where(p) {
480
+ margin: 0 0 var(--spacing-vsp-2xs);
481
+ }
482
+
483
+ .ai-chat-md :where(p:last-child) {
484
+ margin-bottom: 0;
485
+ }
486
+
487
+ .ai-chat-md :where(strong) {
488
+ font-weight: var(--font-weight-bold);
489
+ }
490
+
491
+ .ai-chat-md :where(em) {
492
+ font-style: italic;
493
+ }
494
+
495
+ .ai-chat-md :where(a) {
496
+ color: var(--color-accent);
497
+ text-decoration: underline;
498
+ }
499
+
500
+ .ai-chat-md :where(a:hover) {
501
+ color: var(--color-accent-hover);
502
+ }
503
+
504
+ /* Chat inline-code / pre share intentional sub-token radii (3px inline, 6px block)
505
+ that are deliberately smaller than --radius-DEFAULT (4px) / --radius-lg (8px). */
506
+ .ai-chat-md {
507
+ --_chat-code-radius: 3px; /* inline code — tighter than --radius-DEFAULT (4px) */
508
+ --_chat-pre-radius: 6px; /* pre block — tighter than --radius-lg (8px) */
509
+ }
510
+
511
+ .ai-chat-md :where(code:not(pre code)) {
512
+ font-size: 0.9em; /* em-relative: scales proportionally with the chat bubble's font size */
513
+ background: color-mix(in oklch, var(--color-muted) 20%, transparent);
514
+ padding: 0.1em 0.3em;
515
+ border-radius: var(--_chat-code-radius);
516
+ }
517
+
518
+ .ai-chat-md :where(pre) {
519
+ font-family: var(--font-mono);
520
+ font-size: var(--text-caption);
521
+ line-height: var(--leading-relaxed);
522
+ background: var(--color-code-bg);
523
+ color: var(--color-code-fg);
524
+ padding: var(--spacing-vsp-2xs) var(--spacing-hsp-sm);
525
+ border-radius: var(--_chat-pre-radius);
526
+ overflow-x: auto;
527
+ margin: var(--spacing-vsp-2xs) 0;
528
+ }
529
+
530
+ .ai-chat-md :where(pre code) {
531
+ background: transparent;
532
+ padding: 0;
533
+ font-size: inherit;
534
+ }
535
+
536
+ .ai-chat-md :where(ul) {
537
+ list-style-type: disc;
538
+ padding-left: var(--spacing-hsp-lg);
539
+ margin: var(--spacing-vsp-2xs) 0;
540
+ }
541
+
542
+ .ai-chat-md :where(ol) {
543
+ list-style-type: decimal;
544
+ padding-left: var(--spacing-hsp-lg);
545
+ margin: var(--spacing-vsp-2xs) 0;
546
+ }
547
+
548
+ .ai-chat-md :where(li) {
549
+ margin-bottom: 0.15em;
550
+ }
551
+
552
+ .ai-chat-md :where(li::marker) {
553
+ color: var(--color-muted);
554
+ }
555
+
556
+ .ai-chat-md :where(h4, h5, h6) {
557
+ font-weight: var(--font-weight-bold);
558
+ margin: var(--spacing-vsp-xs) 0 var(--spacing-vsp-2xs);
559
+ }
560
+
561
+ /* ========================================
562
+ * Image enlarge (.zd-enlargeable)
563
+ * Moved from src/styles/global.css to the package by S3 (epic #2344).
564
+ * ======================================== */
565
+
566
+ .zd-enlargeable {
567
+ position: relative;
568
+ display: block;
569
+ margin-inline: 0;
570
+ margin-block-end: 0;
571
+ border: 1px solid transparent;
572
+ transition: border-color var(--default-transition-duration);
573
+ }
574
+
575
+ /* Eligible images (expand-btn visible): the entire image becomes the click target.
576
+ * Show a subtle border as the interactivity affordance, accent on hover. */
577
+ .zd-enlargeable:has(.zd-enlarge-btn:not([hidden])) {
578
+ border-color: var(--color-muted);
579
+ cursor: pointer;
580
+ }
581
+
582
+ .zd-enlargeable:has(.zd-enlarge-btn:not([hidden])):hover {
583
+ border-color: var(--color-accent);
584
+ }
585
+
586
+ .zd-enlargeable img {
587
+ display: block;
588
+ max-width: 100%;
589
+ height: auto;
590
+ }
591
+
592
+ .zd-enlarge-btn {
593
+ position: absolute;
594
+ top: var(--spacing-image-overlay-inset);
595
+ right: var(--spacing-image-overlay-inset);
596
+ display: flex;
597
+ align-items: center;
598
+ justify-content: center;
599
+ padding: var(--spacing-image-overlay-inset);
600
+ border: none;
601
+ background: transparent;
602
+ cursor: pointer;
603
+ z-index: var(--z-index-local-1);
604
+ transition: opacity var(--default-transition-duration);
605
+ }
606
+
607
+ .zd-enlarge-btn::before {
608
+ content: "";
609
+ position: absolute;
610
+ inset: 0;
611
+ background: color-mix(in oklch, var(--color-image-overlay-bg) 80%, transparent);
612
+ z-index: var(--z-index-local-1);
613
+ }
614
+
615
+ .zd-enlarge-btn > svg {
616
+ position: relative;
617
+ z-index: var(--z-index-local-2);
618
+ width: var(--spacing-icon-sm);
619
+ height: var(--spacing-icon-sm);
620
+ color: var(--color-image-overlay-fg);
621
+ fill: currentColor;
622
+ }
623
+
624
+ .zd-enlarge-btn:hover {
625
+ opacity: 0.8;
626
+ }
627
+
628
+ .zd-enlarge-btn[hidden] {
629
+ display: none !important;
630
+ }
631
+
632
+ dialog.zd-enlarge-dialog::backdrop {
633
+ background: color-mix(in oklch, var(--color-overlay) 80%, transparent);
634
+ }
635
+
636
+ /* Close button is positioned to the VIEWPORT corner (not the dialog) so it
637
+ * stays visually distinct against any image, regardless of the dialog's size.
638
+ * This relies on the dialog being transform-free (see ENLARGE_DIALOG_STYLE in
639
+ * island-types) — a transform on the dialog would re-anchor this fixed
640
+ * button to the dialog corner. */
641
+ .zd-enlarge-dialog-close {
642
+ position: fixed;
643
+ top: 4px;
644
+ right: 4px;
645
+ display: flex;
646
+ align-items: center;
647
+ justify-content: center;
648
+ padding: var(--spacing-image-overlay-inset);
649
+ border: none;
650
+ background: transparent;
651
+ cursor: pointer;
652
+ z-index: var(--z-index-local-1);
653
+ transition: opacity var(--default-transition-duration);
654
+ }
655
+
656
+ .zd-enlarge-dialog-close:hover {
657
+ opacity: 0.8;
658
+ }
659
+
660
+ .zd-enlarge-dialog-close::before {
661
+ content: "";
662
+ position: absolute;
663
+ inset: 0;
664
+ background: color-mix(in oklch, var(--color-image-overlay-bg) 80%, transparent);
665
+ z-index: var(--z-index-local-1);
666
+ }
667
+
668
+ .zd-enlarge-dialog-close > svg {
669
+ position: relative;
670
+ z-index: var(--z-index-local-2);
671
+ width: var(--spacing-icon-lg);
672
+ height: var(--spacing-icon-lg);
673
+ color: var(--color-image-overlay-fg);
674
+ fill: currentColor;
675
+ }
676
+
677
+ /* Wide viewport: ~2× larger close button to read clearly against any image. */
678
+ @media (min-width: 1024px) {
679
+ .zd-enlarge-dialog-close {
680
+ top: 10px;
681
+ right: 10px;
682
+ }
683
+
684
+ .zd-enlarge-dialog-close > svg {
685
+ width: calc(var(--spacing-icon-lg) * 2);
686
+ height: calc(var(--spacing-icon-lg) * 2);
687
+ }
688
+ }
689
+
690
+ /* ========================================
691
+ * Mermaid enlarge (.zd-mermaid-enlargeable) — issue #2176 / #2178
692
+ *
693
+ * Unlike images (SSR-wrapped in figure.zd-enlargeable), mermaid diagrams render
694
+ * client-side, so the mermaid-enlarge island injects the `.zd-enlarge-btn` into
695
+ * each rendered `.mermaid` container and adds `.zd-mermaid-enlargeable` (which
696
+ * makes the container position:relative so the button anchors to it). The
697
+ * button + close-button visuals are SHARED with image-enlarge above
698
+ * (`.zd-enlarge-btn`, `.zd-enlarge-dialog-close`).
699
+ * Moved from src/styles/global.css to the package by S3 (epic #2344).
700
+ * ======================================== */
701
+
702
+ .zd-mermaid-enlargeable {
703
+ position: relative;
704
+ border: 1px solid transparent;
705
+ border-radius: var(--radius-DEFAULT);
706
+ transition: border-color var(--default-transition-duration);
707
+ }
708
+
709
+ /* The diagram is always enlargeable once the button is injected — show a subtle
710
+ * border affordance, accent on hover (mirrors the image-enlarge affordance). */
711
+ .zd-mermaid-enlargeable:has(.zd-enlarge-btn) {
712
+ cursor: pointer;
713
+ border-color: var(--color-muted);
714
+ }
715
+
716
+ .zd-mermaid-enlargeable:has(.zd-enlarge-btn):hover {
717
+ border-color: var(--color-accent);
718
+ }
719
+
720
+ /* Zoom/pan dialog. The `<dialog>` stays transform-free (see ENLARGE_DIALOG_STYLE in
721
+ * island-types); the transform lives on .zd-mermaid-transform. */
722
+ dialog.zd-mermaid-dialog::backdrop {
723
+ background: color-mix(in oklch, var(--color-overlay) 80%, transparent);
724
+ }
725
+
726
+ /* Pan viewport — fills the dialog and clips the (possibly zoomed) diagram.
727
+ * touch-action:none so pointer-drag pans on touch without the browser
728
+ * intercepting the gesture for scrolling. */
729
+ .zd-mermaid-viewport {
730
+ width: 100%;
731
+ height: 100%;
732
+ overflow: hidden;
733
+ display: flex;
734
+ align-items: center;
735
+ justify-content: center;
736
+ touch-action: none;
737
+ }
738
+
739
+ .zd-mermaid-viewport[data-pan-active] {
740
+ cursor: grab;
741
+ /* In pan mode a drag should pan, not select diagram text. Scoped to
742
+ * [data-pan-active] so text stays selectable when pan mode is off. */
743
+ -webkit-user-select: none;
744
+ user-select: none;
745
+ }
746
+
747
+ .zd-mermaid-viewport[data-pan-active]:active {
748
+ cursor: grabbing;
749
+ }
750
+
751
+ .zd-mermaid-transform {
752
+ width: 100%;
753
+ height: 100%;
754
+ display: flex;
755
+ align-items: center;
756
+ justify-content: center;
757
+ will-change: transform;
758
+ }
759
+
760
+ /* SVG sizing — fit the cloned mermaid svg inside the dialog like
761
+ * object-fit:contain. The svg fills the viewport box (100% x 100%) and its
762
+ * viewBox content is letterboxed/centered by the default
763
+ * preserveAspectRatio="xMidYMid meet". A TALL diagram (e.g. a state diagram) no
764
+ * longer gets forced to full dialog width with `height:auto` driving the height
765
+ * far past the viewport via its aspect ratio — it now shrinks to fit the height
766
+ * instead. max-width/max-height !important neutralize the inline px sizing
767
+ * mermaid bakes onto the svg (without it the diagram renders tiny). Scoped to
768
+ * .zd-mermaid-transform (the cloned-diagram wrapper) so it does NOT hit the
769
+ * toolbar / close-button icon svgs that also live inside the dialog. */
770
+ .zd-mermaid-transform svg {
771
+ max-width: 100% !important;
772
+ max-height: 100% !important;
773
+ width: 100%;
774
+ height: 100%;
775
+ }
776
+
777
+ /* Edge labels (e.g. "Yes"/"No") render inside a tightly-sized <foreignObject>;
778
+ * when the cloned diagram is upscaled to fill the dialog, sub-pixel overflow
779
+ * makes the browser clip the last glyph at the foreignObject's right edge.
780
+ * Letting the foreignObject overflow render keeps the full label visible. */
781
+ .zd-mermaid-transform svg foreignObject {
782
+ overflow: visible;
783
+ }
784
+
785
+ /* Toolbar — bottom-right pill of zoom/pan controls (2× sized buttons). */
786
+ .zd-mermaid-toolbar {
787
+ position: absolute;
788
+ bottom: var(--spacing-image-overlay-inset);
789
+ right: var(--spacing-image-overlay-inset);
790
+ display: flex;
791
+ gap: var(--spacing-hsp-xs);
792
+ padding: var(--spacing-hsp-xs);
793
+ border: 1px solid var(--color-muted);
794
+ border-radius: var(--radius-DEFAULT);
795
+ background: color-mix(in oklch, var(--color-surface) 92%, transparent);
796
+ z-index: var(--z-index-local-2);
797
+ }
798
+
799
+ .zd-mermaid-tool-btn {
800
+ display: flex;
801
+ align-items: center;
802
+ justify-content: center;
803
+ width: calc(var(--spacing-icon-lg) * 2);
804
+ height: calc(var(--spacing-icon-lg) * 2);
805
+ padding: var(--spacing-vsp-2xs);
806
+ border: none;
807
+ border-radius: var(--radius-DEFAULT);
808
+ background: transparent;
809
+ color: var(--color-fg);
810
+ cursor: pointer;
811
+ transition:
812
+ background-color var(--default-transition-duration),
813
+ opacity var(--default-transition-duration);
814
+ }
815
+
816
+ .zd-mermaid-tool-btn:hover:not([disabled]) {
817
+ background: color-mix(in oklch, var(--color-muted) 25%, transparent);
818
+ }
819
+
820
+ .zd-mermaid-tool-btn[aria-pressed="true"] {
821
+ background: color-mix(in oklch, var(--color-accent) 30%, transparent);
822
+ color: var(--color-accent);
823
+ }
824
+
825
+ .zd-mermaid-tool-btn[disabled] {
826
+ opacity: 0.4;
827
+ cursor: default;
828
+ }
829
+
830
+ .zd-mermaid-tool-btn > svg {
831
+ width: calc(var(--spacing-icon-md) * 2);
832
+ height: calc(var(--spacing-icon-md) * 2);
833
+ }
834
+
835
+ /* ========================================
836
+ * Doc History Diff Viewer (side-by-side)
837
+ * Moved from src/styles/global.css (epic #2344, S4).
838
+ * Coupled to the DocHistory island (packages/zudo-doc/src/doc-history/).
839
+ * ======================================== */
840
+
841
+ .diff-row {
842
+ border-bottom: 1px solid color-mix(in oklch, var(--color-muted) 15%, transparent);
843
+ }
844
+
845
+ .diff-line-num {
846
+ font-family: var(--font-mono, ui-monospace, monospace);
847
+ font-size: var(--text-caption);
848
+ line-height: 1.5;
849
+ padding: 0 var(--spacing-hsp-xs);
850
+ text-align: right;
851
+ color: var(--color-muted);
852
+ user-select: none;
853
+ vertical-align: top;
854
+ border-right: 1px solid color-mix(in oklch, var(--color-muted) 15%, transparent);
855
+ }
856
+
857
+ .diff-line-content {
858
+ font-family: var(--font-mono, ui-monospace, monospace);
859
+ font-size: var(--text-caption);
860
+ line-height: 1.5;
861
+ padding: 0 var(--spacing-hsp-sm);
862
+ white-space: pre-wrap;
863
+ word-break: break-all;
864
+ vertical-align: top;
865
+ }
866
+
867
+ /* Left column right border to separate the two sides */
868
+ .diff-row td:nth-child(2) {
869
+ border-right: 2px solid var(--color-muted);
870
+ }
871
+
872
+ .diff-line-added {
873
+ background-color: color-mix(in oklch, var(--color-success) 15%, transparent);
874
+ }
875
+
876
+ .diff-line-removed {
877
+ background-color: color-mix(in oklch, var(--color-danger) 15%, transparent);
878
+ }
879
+
880
+ .diff-line-empty {
881
+ background-color: color-mix(in oklch, var(--color-muted) 8%, transparent);
882
+ }