create-zudo-doc 0.1.0

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 (212) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/bin/create-zudo-doc.js +2 -0
  4. package/dist/api.d.ts +20 -0
  5. package/dist/api.js +13 -0
  6. package/dist/claude-md-gen.d.ts +2 -0
  7. package/dist/claude-md-gen.js +113 -0
  8. package/dist/cli.d.ts +39 -0
  9. package/dist/cli.js +157 -0
  10. package/dist/compose.d.ts +95 -0
  11. package/dist/compose.js +206 -0
  12. package/dist/constants.d.ts +20 -0
  13. package/dist/constants.js +224 -0
  14. package/dist/features/body-foot-util.d.ts +10 -0
  15. package/dist/features/body-foot-util.js +12 -0
  16. package/dist/features/claude-resources.d.ts +2 -0
  17. package/dist/features/claude-resources.js +6 -0
  18. package/dist/features/design-token-panel.d.ts +14 -0
  19. package/dist/features/design-token-panel.js +27 -0
  20. package/dist/features/doc-history.d.ts +9 -0
  21. package/dist/features/doc-history.js +11 -0
  22. package/dist/features/doc-tags.d.ts +19 -0
  23. package/dist/features/doc-tags.js +33 -0
  24. package/dist/features/footer-taglist.d.ts +14 -0
  25. package/dist/features/footer-taglist.js +17 -0
  26. package/dist/features/footer.d.ts +8 -0
  27. package/dist/features/footer.js +10 -0
  28. package/dist/features/i18n.d.ts +22 -0
  29. package/dist/features/i18n.js +41 -0
  30. package/dist/features/image-enlarge.d.ts +11 -0
  31. package/dist/features/image-enlarge.js +13 -0
  32. package/dist/features/index.d.ts +15 -0
  33. package/dist/features/index.js +53 -0
  34. package/dist/features/llms-txt.d.ts +11 -0
  35. package/dist/features/llms-txt.js +13 -0
  36. package/dist/features/search.d.ts +9 -0
  37. package/dist/features/search.js +11 -0
  38. package/dist/features/sidebar-resizer.d.ts +14 -0
  39. package/dist/features/sidebar-resizer.js +16 -0
  40. package/dist/features/sidebar-toggle.d.ts +13 -0
  41. package/dist/features/sidebar-toggle.js +15 -0
  42. package/dist/features/tag-governance.d.ts +14 -0
  43. package/dist/features/tag-governance.js +16 -0
  44. package/dist/features/tauri-dev.d.ts +2 -0
  45. package/dist/features/tauri-dev.js +25 -0
  46. package/dist/features/tauri.d.ts +11 -0
  47. package/dist/features/tauri.js +52 -0
  48. package/dist/features/versioning.d.ts +27 -0
  49. package/dist/features/versioning.js +43 -0
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.js +150 -0
  52. package/dist/preset.d.ts +37 -0
  53. package/dist/preset.js +156 -0
  54. package/dist/prompts.d.ts +32 -0
  55. package/dist/prompts.js +248 -0
  56. package/dist/scaffold.d.ts +4 -0
  57. package/dist/scaffold.js +344 -0
  58. package/dist/settings-gen.d.ts +2 -0
  59. package/dist/settings-gen.js +237 -0
  60. package/dist/utils.d.ts +8 -0
  61. package/dist/utils.js +34 -0
  62. package/dist/zfb-config-gen.d.ts +19 -0
  63. package/dist/zfb-config-gen.js +222 -0
  64. package/package.json +65 -0
  65. package/templates/base/.htmlvalidate.json +5 -0
  66. package/templates/base/.zfb/doc-history-meta.json +1 -0
  67. package/templates/base/pages/404.tsx +55 -0
  68. package/templates/base/pages/_data.ts +179 -0
  69. package/templates/base/pages/_mdx-components.ts +249 -0
  70. package/templates/base/pages/docs/[...slug].tsx +448 -0
  71. package/templates/base/pages/index.tsx +158 -0
  72. package/templates/base/pages/lib/_body-end-islands.tsx +201 -0
  73. package/templates/base/pages/lib/_category-nav.tsx +148 -0
  74. package/templates/base/pages/lib/_category-tree-nav.tsx +104 -0
  75. package/templates/base/pages/lib/_compose-meta-title.ts +29 -0
  76. package/templates/base/pages/lib/_details.tsx +30 -0
  77. package/templates/base/pages/lib/_doc-history-area.tsx +178 -0
  78. package/templates/base/pages/lib/_doc-metainfo-area.tsx +100 -0
  79. package/templates/base/pages/lib/_doc-tags-area.tsx +89 -0
  80. package/templates/base/pages/lib/_extract-headings.ts +81 -0
  81. package/templates/base/pages/lib/_footer-with-defaults.tsx +234 -0
  82. package/templates/base/pages/lib/_frontmatter-preview-data.ts +53 -0
  83. package/templates/base/pages/lib/_head-with-defaults.tsx +113 -0
  84. package/templates/base/pages/lib/_header-with-defaults.tsx +386 -0
  85. package/templates/base/pages/lib/_inline-version-switcher.tsx +84 -0
  86. package/templates/base/pages/lib/_math-block.tsx +63 -0
  87. package/templates/base/pages/lib/_nav-source-docs.ts +68 -0
  88. package/templates/base/pages/lib/_preset-generator.tsx +81 -0
  89. package/templates/base/pages/lib/_search-widget-script.ts +388 -0
  90. package/templates/base/pages/lib/_search-widget.tsx +196 -0
  91. package/templates/base/pages/lib/_sidebar-with-defaults.tsx +176 -0
  92. package/templates/base/pages/lib/_site-tree-nav.tsx +128 -0
  93. package/templates/base/pages/lib/locale-merge.ts +58 -0
  94. package/templates/base/pages/lib/route-enumerators.ts +302 -0
  95. package/templates/base/pages/sitemap.xml.tsx +51 -0
  96. package/templates/base/plugins/connect-adapter.mjs +144 -0
  97. package/templates/base/plugins/copy-public-plugin.mjs +50 -0
  98. package/templates/base/plugins/search-index-plugin.mjs +54 -0
  99. package/templates/base/scripts/run-b4push.sh +102 -0
  100. package/templates/base/src/components/ai-chat-modal.tsx +15 -0
  101. package/templates/base/src/components/client-router-bootstrap.tsx +14 -0
  102. package/templates/base/src/components/content/component-map.ts +25 -0
  103. package/templates/base/src/components/content/content-blockquote.tsx +16 -0
  104. package/templates/base/src/components/content/content-code.tsx +117 -0
  105. package/templates/base/src/components/content/content-link.tsx +83 -0
  106. package/templates/base/src/components/content/content-ol.tsx +19 -0
  107. package/templates/base/src/components/content/content-paragraph.tsx +10 -0
  108. package/templates/base/src/components/content/content-strong.tsx +16 -0
  109. package/templates/base/src/components/content/content-table.tsx +18 -0
  110. package/templates/base/src/components/content/content-ul.tsx +18 -0
  111. package/templates/base/src/components/content/heading-h2.tsx +26 -0
  112. package/templates/base/src/components/content/heading-h3.tsx +26 -0
  113. package/templates/base/src/components/content/heading-h4.tsx +26 -0
  114. package/templates/base/src/components/design-token-panel-bootstrap.tsx +15 -0
  115. package/templates/base/src/components/desktop-sidebar-toggle.tsx +15 -0
  116. package/templates/base/src/components/doc-history.tsx +18 -0
  117. package/templates/base/src/components/html-preview/highlighted-code.tsx +74 -0
  118. package/templates/base/src/components/html-preview/html-preview.tsx +108 -0
  119. package/templates/base/src/components/html-preview/preflight.ts +112 -0
  120. package/templates/base/src/components/html-preview/preview-base.tsx +159 -0
  121. package/templates/base/src/components/image-enlarge.tsx +19 -0
  122. package/templates/base/src/components/mobile-toc.tsx +94 -0
  123. package/templates/base/src/components/preset-generator.tsx +14 -0
  124. package/templates/base/src/components/sidebar-toggle.tsx +98 -0
  125. package/templates/base/src/components/sidebar-tree.tsx +543 -0
  126. package/templates/base/src/components/site-tree-nav.tsx +233 -0
  127. package/templates/base/src/components/theme-toggle.tsx +93 -0
  128. package/templates/base/src/components/toc.tsx +63 -0
  129. package/templates/base/src/components/tree-nav-shared.tsx +71 -0
  130. package/templates/base/src/config/color-scheme-utils.ts +182 -0
  131. package/templates/base/src/config/color-schemes.ts +128 -0
  132. package/templates/base/src/config/frontmatter-preview-defaults.ts +24 -0
  133. package/templates/base/src/config/frontmatter-preview-renderers.tsx +46 -0
  134. package/templates/base/src/config/i18n.ts +225 -0
  135. package/templates/base/src/config/settings-types.ts +162 -0
  136. package/templates/base/src/config/sidebars.ts +66 -0
  137. package/templates/base/src/config/tag-vocabulary-types.ts +39 -0
  138. package/templates/base/src/config/tag-vocabulary.ts +20 -0
  139. package/templates/base/src/hooks/use-active-heading.ts +133 -0
  140. package/templates/base/src/plugins/docs-source-map.ts +103 -0
  141. package/templates/base/src/plugins/hast-utils.ts +10 -0
  142. package/templates/base/src/plugins/rehype-code-title.ts +50 -0
  143. package/templates/base/src/plugins/rehype-heading-links.ts +53 -0
  144. package/templates/base/src/plugins/rehype-image-enlarge.ts +113 -0
  145. package/templates/base/src/plugins/rehype-mermaid.ts +41 -0
  146. package/templates/base/src/plugins/rehype-strip-md-extension.ts +58 -0
  147. package/templates/base/src/plugins/remark-admonitions.ts +99 -0
  148. package/templates/base/src/plugins/remark-resolve-markdown-links.ts +127 -0
  149. package/templates/base/src/plugins/url-utils.ts +4 -0
  150. package/templates/base/src/styles/global.css +1066 -0
  151. package/templates/base/src/types/docs-entry.ts +39 -0
  152. package/templates/base/src/types/heading.ts +5 -0
  153. package/templates/base/src/types/locale.ts +10 -0
  154. package/templates/base/src/utils/base.ts +139 -0
  155. package/templates/base/src/utils/content-files.ts +106 -0
  156. package/templates/base/src/utils/dedent.ts +24 -0
  157. package/templates/base/src/utils/docs.ts +335 -0
  158. package/templates/base/src/utils/git-info.ts +70 -0
  159. package/templates/base/src/utils/github.ts +19 -0
  160. package/templates/base/src/utils/header-right-items.ts +38 -0
  161. package/templates/base/src/utils/nav-scope.ts +63 -0
  162. package/templates/base/src/utils/sidebar.ts +104 -0
  163. package/templates/base/src/utils/slug.ts +10 -0
  164. package/templates/base/src/utils/smart-break.tsx +126 -0
  165. package/templates/base/src/utils/tags.ts +126 -0
  166. package/templates/base/tsconfig.json +36 -0
  167. package/templates/features/bodyFootUtil/files/src/utils/github.ts +19 -0
  168. package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +137 -0
  169. package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +34 -0
  170. package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/generate.test.ts +376 -0
  171. package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +93 -0
  172. package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +586 -0
  173. package/templates/features/designTokenPanel/files/src/components/design-token-panel-bootstrap.tsx +15 -0
  174. package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +99 -0
  175. package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +177 -0
  176. package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +50 -0
  177. package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +99 -0
  178. package/templates/features/docHistory/files/src/components/doc-history.tsx +598 -0
  179. package/templates/features/docHistory/files/src/types/doc-history.ts +23 -0
  180. package/templates/features/docHistory/files/src/utils/doc-history.ts +180 -0
  181. package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +116 -0
  182. package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +99 -0
  183. package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +101 -0
  184. package/templates/features/docTags/files/pages/docs/tags/index.tsx +86 -0
  185. package/templates/features/i18n/files/pages/[locale]/docs/[...slug].tsx +467 -0
  186. package/templates/features/i18n/files/pages/[locale]/index.tsx +213 -0
  187. package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +248 -0
  188. package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +74 -0
  189. package/templates/features/sidebarResizer/files/src/scripts/sidebar-resizer.ts +185 -0
  190. package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +126 -0
  191. package/templates/features/tagGovernance/files/scripts/tags-audit.ts +576 -0
  192. package/templates/features/tagGovernance/files/scripts/tags-suggest.ts +428 -0
  193. package/templates/features/tauri/files/src/components/find-bar.tsx +122 -0
  194. package/templates/features/tauri/files/src/components/find-in-page-init.tsx +53 -0
  195. package/templates/features/tauri/files/src/utils/find-in-page.ts +175 -0
  196. package/templates/features/tauri/files/src-tauri/Cargo.toml +14 -0
  197. package/templates/features/tauri/files/src-tauri/build.rs +3 -0
  198. package/templates/features/tauri/files/src-tauri/capabilities/default.json +11 -0
  199. package/templates/features/tauri/files/src-tauri/src/main.rs +250 -0
  200. package/templates/features/tauri/files/src-tauri/tauri.conf.json +25 -0
  201. package/templates/features/tauriDev/files/src-tauri-dev/Cargo.toml +15 -0
  202. package/templates/features/tauriDev/files/src-tauri-dev/build.rs +3 -0
  203. package/templates/features/tauriDev/files/src-tauri-dev/capabilities/default.json +7 -0
  204. package/templates/features/tauriDev/files/src-tauri-dev/frontend/index.html +187 -0
  205. package/templates/features/tauriDev/files/src-tauri-dev/icons/icon.png +0 -0
  206. package/templates/features/tauriDev/files/src-tauri-dev/src/main.rs +995 -0
  207. package/templates/features/tauriDev/files/src-tauri-dev/tauri.conf.json +22 -0
  208. package/templates/features/tauriDev/files/src-tauri-dev/test-launch.sh +65 -0
  209. package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +100 -0
  210. package/templates/features/versioning/files/pages/docs/versions.tsx +78 -0
  211. package/templates/features/versioning/files/pages/v/[version]/docs/[...slug].tsx +451 -0
  212. package/templates/features/versioning/files/pages/v/[version]/ja/docs/[...slug].tsx +490 -0
@@ -0,0 +1,1066 @@
1
+ @import "tailwindcss/preflight";
2
+ @import "tailwindcss/utilities";
3
+
4
+ /* ========================================
5
+ * Tailwind v4 content sources
6
+ *
7
+ * Without a `.git` directory in the project root Tailwind v4's content
8
+ * scanner falls back to explicit @source directives for class detection.
9
+ * Builds that run outside a git checkout (E2E fixtures, CI containers
10
+ * that copy the source tree without history, etc.) hit this fallback,
11
+ * and zfb's default content roots only cover `pages/`. Components and
12
+ * shared package code that hold responsive variants (`lg:hidden`,
13
+ * `lg:block`, `xl:hidden`), design-token utilities (`h-icon-lg`,
14
+ * `bg-bg`, `text-fg`), and absolute-position primitives (`sticky`,
15
+ * `inset-0`, `top-[3.5rem]`) live outside pages/, so without these
16
+ * directives Tailwind drops every utility class those modules emit and
17
+ * the dist stylesheet collapses — breaking mobile-sidebar visibility,
18
+ * desktop-sidebar reveal, and mobile-toc accordion at non-git build
19
+ * targets. Keep these in sync with `src/styles/global.css` in the host
20
+ * repo (zudolab/zudo-doc#1355 wave 13 topic 2; pages/ added in #1444).
21
+ * ======================================== */
22
+
23
+ @source "src/components/**/*.{tsx,ts,jsx,js,mdx,md}";
24
+ @source "src/content/**/*.{mdx,md}";
25
+ @source "src/hooks/**/*.{tsx,ts,jsx,js}";
26
+ @source "src/utils/**/*.{tsx,ts,jsx,js}";
27
+ @source "pages/**/*.{tsx,ts,jsx,js}";
28
+
29
+ /* ========================================
30
+ * Design Token System
31
+ *
32
+ * Tight token strategy: import preflight + utilities only (no default theme).
33
+ * Only project-specific tokens are available.
34
+ *
35
+ * Raw palette: --zd-0 to --zd-15 + bg/fg/sel (injected by ColorSchemeProvider)
36
+ * Tailwind tokens: registered below via @theme
37
+ *
38
+ * Palette slots:
39
+ * 0/8: black / bright-black (surfaces, muted text, borders)
40
+ * 1/9: red / bright-red
41
+ * 2/10: green / bright-green
42
+ * 3/11: yellow / bright-yellow
43
+ * 4/12: blue / bright-blue
44
+ * 5/13: magenta / bright-magenta
45
+ * 6/14: cyan / bright-cyan
46
+ * 7/15: white / bright-white
47
+ * ======================================== */
48
+
49
+ @theme {
50
+ /* ========================================
51
+ * Colors — Three-tier token system
52
+ * ======================================== */
53
+
54
+ /* ── Base ── */
55
+ --color-bg: var(--zd-bg);
56
+ --color-fg: var(--zd-fg);
57
+ --color-sel-bg: var(--zd-sel-bg);
58
+ --color-sel-fg: var(--zd-sel-fg);
59
+
60
+ /* ── Raw palette (p0–p15) ── */
61
+ --color-p0: var(--zd-0);
62
+ --color-p1: var(--zd-1);
63
+ --color-p2: var(--zd-2);
64
+ --color-p3: var(--zd-3);
65
+ --color-p4: var(--zd-4);
66
+ --color-p5: var(--zd-5);
67
+ --color-p6: var(--zd-6);
68
+ --color-p7: var(--zd-7);
69
+ --color-p8: var(--zd-8);
70
+ --color-p9: var(--zd-9);
71
+ --color-p10: var(--zd-10);
72
+ --color-p11: var(--zd-11);
73
+ --color-p12: var(--zd-12);
74
+ --color-p13: var(--zd-13);
75
+ --color-p14: var(--zd-14);
76
+ --color-p15: var(--zd-15);
77
+
78
+ /* ── Semantic aliases ── */
79
+ --color-surface: var(--zd-surface);
80
+ --color-muted: var(--zd-muted);
81
+ --color-accent: var(--zd-accent);
82
+ --color-accent-hover: var(--zd-accent-hover);
83
+ --color-code-bg: var(--zd-code-bg);
84
+ --color-code-fg: var(--zd-code-fg);
85
+ --color-success: var(--zd-success);
86
+ --color-danger: var(--zd-danger);
87
+ --color-warning: var(--zd-warning);
88
+ --color-info: var(--zd-info);
89
+ /* Overlay is intentionally theme-independent (always dark, not scheme-driven) */
90
+ --color-overlay: #000;
91
+ --color-image-overlay-bg: var(--zd-image-overlay-bg);
92
+ --color-image-overlay-fg: var(--zd-image-overlay-fg);
93
+ --color-mermaid-node-bg: var(--zd-mermaid-node-bg);
94
+ --color-mermaid-text: var(--zd-mermaid-text);
95
+ --color-mermaid-line: var(--zd-mermaid-line);
96
+ --color-mermaid-label-bg: var(--zd-mermaid-label-bg);
97
+ --color-mermaid-note-bg: var(--zd-mermaid-note-bg);
98
+ --color-matched-keyword-bg: var(--zd-matched-keyword-bg);
99
+ --color-matched-keyword-fg: var(--zd-matched-keyword-fg);
100
+ /* @slot:global-css:theme-tokens */
101
+
102
+ /* ========================================
103
+ * Spacing — hsp (horizontal) + vsp (vertical)
104
+ * ======================================== */
105
+ --spacing-0: 0;
106
+ --spacing-px: 1px;
107
+
108
+ /* Horizontal spacing (7 steps) */
109
+ --spacing-hsp-2xs: 0.125rem; /* 2px — tight inline */
110
+ --spacing-hsp-xs: 0.375rem; /* 6px — compact inline */
111
+ --spacing-hsp-sm: 0.5rem; /* 8px — small padding */
112
+ --spacing-hsp-md: 0.75rem; /* 12px — default gaps */
113
+ --spacing-hsp-lg: 1rem; /* 16px — standard padding */
114
+ --spacing-hsp-xl: 1.5rem; /* 24px — generous padding */
115
+ --spacing-hsp-2xl: 2rem; /* 32px — large padding */
116
+
117
+ /* Vertical spacing (7 steps) */
118
+ --spacing-vsp-2xs: 0.4375rem; /* 7px — tight gap */
119
+ --spacing-vsp-xs: 0.875rem; /* 14px — small gap */
120
+ --spacing-vsp-sm: 1.25rem; /* 20px — compact gap */
121
+ --spacing-vsp-md: 1.5rem; /* 24px — standard gap */
122
+ --spacing-vsp-lg: 1.75rem; /* 28px — section gap */
123
+ --spacing-vsp-xl: 2.5rem; /* 40px — large section gap */
124
+ --spacing-vsp-2xl: 3.5rem; /* 56px — page-level gap */
125
+
126
+ /* ========================================
127
+ * Element sizes — semantic icon dimensions
128
+ * ======================================== */
129
+ --spacing-icon-xs: 0.75rem; /* 12px — inline meta icons, chevrons */
130
+ --spacing-icon-sm: 1rem; /* 16px — standard UI icons */
131
+ --spacing-icon-md: 1.25rem; /* 20px — medium emphasis icons */
132
+ --spacing-icon-lg: 1.5rem; /* 24px — large / mobile icons */
133
+
134
+ /* Image overlay button chrome */
135
+ --spacing-image-overlay-inset: 0.5rem; /* 8px — overlay button corner inset + internal padding */
136
+
137
+ /* ========================================
138
+ * Typography
139
+ * ======================================== */
140
+
141
+ /* ── Tier 2: Semantic font-size tokens (reference Tier 1 scale only) ── */
142
+ --text-micro: var(--text-scale-2xs); /* 12px — compact panel labels, color swatch annotations */
143
+ --text-caption: var(--text-scale-xs); /* labels, timestamps */
144
+ --text-small: var(--text-scale-sm); /* secondary text, nav items */
145
+ --text-body: var(--text-scale-md); /* paragraphs, default */
146
+ --text-title: var(--text-scale-lg); /* card titles, section labels */
147
+ --text-heading: var(--text-scale-xl); /* page headings */
148
+ --text-display: var(--text-scale-2xl); /* hero text */
149
+
150
+ /* Font families */
151
+ --font-sans: system-ui, sans-serif;
152
+ --font-mono: ui-monospace, monospace;
153
+
154
+ /* Font weights (4 steps) */
155
+ --font-weight-normal: 400;
156
+ --font-weight-medium: 500;
157
+ --font-weight-semibold: 600;
158
+ --font-weight-bold: 700;
159
+
160
+ /* Line heights (4 steps) */
161
+ --leading-tight: 1.25;
162
+ --leading-snug: 1.375;
163
+ --leading-normal: 1.5;
164
+ --leading-relaxed: 1.625;
165
+
166
+ /* ========================================
167
+ * Border radius (3 steps)
168
+ * ======================================== */
169
+ --radius-DEFAULT: 0.25rem; /* 4px — rounded */
170
+ --radius-lg: 0.5rem; /* 8px — rounded-lg */
171
+ --radius-full: 9999px; /* rounded-full */
172
+
173
+ /* ========================================
174
+ * Breakpoints (3 steps)
175
+ * ======================================== */
176
+ --breakpoint-sm: 640px;
177
+ --breakpoint-lg: 1024px;
178
+ --breakpoint-xl: 1280px;
179
+ }
180
+
181
+ :root {
182
+ /* Default responsive range; sidebar-resizer.ts allows 192–448px for explicit resizing */
183
+ --zd-sidebar-w: clamp(14rem, 20vw, 22rem);
184
+
185
+ /* ── Tier 1: Abstract font-size scale (raw values — NOT for direct component use) ── */
186
+ /* Used only as a source of truth for Tier 2 semantic tokens above. */
187
+ --text-scale-2xs: 0.75rem; /* 12px */
188
+ --text-scale-xs: 0.875rem; /* 14px */
189
+ --text-scale-sm: 1rem; /* 16px */
190
+ --text-scale-md: 1.2rem; /* 19.2px */
191
+ --text-scale-lg: 1.4rem; /* 22.4px */
192
+ --text-scale-xl: 3rem; /* 48px */
193
+ --text-scale-2xl: 3.75rem; /* 60px */
194
+ }
195
+
196
+ /* ========================================
197
+ * Base styles
198
+ * ======================================== */
199
+
200
+ [id] {
201
+ scroll-margin-top: 80px;
202
+ }
203
+
204
+ body {
205
+ background-color: var(--color-bg);
206
+ color: var(--color-fg);
207
+ }
208
+
209
+ ::selection {
210
+ background-color: var(--color-sel-bg);
211
+ color: var(--color-sel-fg);
212
+ }
213
+
214
+ @layer base {
215
+ a {
216
+ text-underline-offset: 4px;
217
+ }
218
+ button {
219
+ cursor: pointer;
220
+ }
221
+ }
222
+
223
+ /* ========================================
224
+ * Content typography (.zd-content)
225
+ *
226
+ * Direct element styling — no prose plugin.
227
+ * Uses :where() for zero specificity (easy to override).
228
+ * Font size pattern inspired by zpaper: paired size + line-height.
229
+ * ======================================== */
230
+
231
+ .zd-content {
232
+ color: var(--color-fg);
233
+ font-size: var(--text-body);
234
+ line-height: var(--leading-relaxed);
235
+ }
236
+
237
+ /* ── Flow spacing (vertical rhythm) ── */
238
+
239
+ .zd-content > :where(* + *) {
240
+ margin-top: var(--flow-space, var(--spacing-vsp-md));
241
+ }
242
+
243
+ /* ── Headings ── */
244
+
245
+ .zd-content :where(h2) {
246
+ font-size: var(--text-title);
247
+ font-weight: var(--font-weight-bold);
248
+ line-height: var(--leading-tight);
249
+ margin-top: var(--spacing-vsp-2xl);
250
+ margin-bottom: var(--spacing-vsp-xs);
251
+ padding-top: var(--spacing-vsp-sm);
252
+ border-top: 3px solid transparent;
253
+ border-image: linear-gradient(to right, var(--color-fg), transparent) 1;
254
+ }
255
+
256
+ .zd-content :where(h3) {
257
+ font-size: var(--text-body);
258
+ font-weight: var(--font-weight-bold);
259
+ line-height: var(--leading-snug);
260
+ margin-top: var(--spacing-vsp-xl);
261
+ margin-bottom: var(--spacing-vsp-xs);
262
+ padding-top: var(--spacing-vsp-xs);
263
+ border-top: 2px solid transparent;
264
+ border-image: linear-gradient(to right, var(--color-muted), transparent) 1;
265
+ }
266
+
267
+ .zd-content :where(h4) {
268
+ font-size: var(--text-body);
269
+ font-weight: var(--font-weight-semibold);
270
+ line-height: var(--leading-snug);
271
+ margin-top: var(--spacing-vsp-lg);
272
+ margin-bottom: var(--spacing-vsp-xs);
273
+ padding-top: var(--spacing-vsp-xs);
274
+ border-top: 1px solid transparent;
275
+ border-image: linear-gradient(to right, var(--color-muted), transparent) 1;
276
+ }
277
+
278
+ .zd-content :where(h5, h6) {
279
+ font-size: var(--text-small);
280
+ font-weight: var(--font-weight-semibold);
281
+ line-height: var(--leading-snug);
282
+ margin-top: var(--spacing-vsp-md);
283
+ margin-bottom: var(--spacing-vsp-2xs);
284
+ }
285
+
286
+ /* ── Heading auto-links ── */
287
+
288
+ .zd-content :where(h2, h3, h4, h5, h6) .hash-link {
289
+ text-decoration: none;
290
+ margin-left: var(--spacing-hsp-sm);
291
+ opacity: 0;
292
+ transition: opacity 0.15s;
293
+ }
294
+
295
+ .zd-content :where(h2, h3, h4, h5, h6) .hash-link::after {
296
+ content: "#";
297
+ color: var(--color-accent);
298
+ }
299
+
300
+ .zd-content :where(h2, h3, h4, h5, h6):hover .hash-link {
301
+ opacity: 1;
302
+ }
303
+
304
+ .zd-content :where(h2, h3, h4, h5, h6) .hash-link:focus-visible {
305
+ opacity: 1;
306
+ outline: 2px solid var(--color-accent);
307
+ outline-offset: 2px;
308
+ }
309
+
310
+ /* Tighten spacing after headings */
311
+ .zd-content :where(h2 + *, h3 + *, h4 + *, h5 + *, h6 + *) {
312
+ margin-top: 0;
313
+ }
314
+
315
+ /* ── Paragraphs ── */
316
+
317
+ .zd-content :where(p) {
318
+ margin-top: 0;
319
+ margin-bottom: var(--spacing-vsp-md);
320
+ }
321
+
322
+ /* ── Links ── */
323
+
324
+ .zd-content :where(a:not(.block):not([data-site-nav] *)) {
325
+ color: var(--color-accent);
326
+ text-decoration: underline;
327
+ }
328
+
329
+ .zd-content :where(a:not(.block):not([data-site-nav] *):hover) {
330
+ color: var(--color-accent-hover);
331
+ }
332
+
333
+ /* ── Bold / Strong ── */
334
+
335
+ .zd-content :where(strong) {
336
+ font-weight: var(--font-weight-bold);
337
+ color: var(--color-fg);
338
+ }
339
+
340
+ /* ── Lists ── */
341
+
342
+ .zd-content :where(ul) {
343
+ list-style-type: disc;
344
+ padding-left: var(--spacing-hsp-xl);
345
+ margin-bottom: var(--spacing-vsp-md);
346
+ }
347
+
348
+ .zd-content :where(ol) {
349
+ list-style-type: decimal;
350
+ padding-left: var(--spacing-hsp-xl);
351
+ margin-bottom: var(--spacing-vsp-md);
352
+ }
353
+
354
+ .zd-content :where(li) {
355
+ margin-bottom: var(--spacing-vsp-xs);
356
+ }
357
+
358
+ .zd-content :where(li::marker) {
359
+ color: var(--color-muted);
360
+ }
361
+
362
+ .zd-content :where(li > ul, li > ol) {
363
+ margin-top: var(--spacing-vsp-xs);
364
+ margin-bottom: 0;
365
+ }
366
+
367
+ /* ── Blockquotes ── */
368
+
369
+ .zd-content :where(blockquote) {
370
+ border-left: 3px solid var(--color-muted);
371
+ padding-left: var(--spacing-hsp-lg);
372
+ color: var(--color-muted);
373
+ font-style: italic;
374
+ margin-bottom: var(--spacing-vsp-md);
375
+ }
376
+
377
+ .zd-content :where(blockquote p) {
378
+ margin-bottom: var(--spacing-vsp-xs);
379
+ }
380
+
381
+ /* ── Inline code ── */
382
+
383
+ .zd-content :where(code:not(pre code)) {
384
+ font-size: var(--text-small);
385
+ font-weight: var(--font-weight-medium);
386
+ font-family: var(--font-mono);
387
+ background-color: var(--color-code-bg);
388
+ color: var(--color-code-fg);
389
+ border-radius: var(--radius-DEFAULT);
390
+ padding: 2px var(--spacing-hsp-xs);
391
+ }
392
+
393
+ /* ── Code blocks (pre) ── */
394
+
395
+ .zd-content :where(pre) {
396
+ font-size: var(--text-small);
397
+ line-height: var(--leading-relaxed);
398
+ border: 1px solid var(--color-muted);
399
+ padding: var(--spacing-vsp-sm) var(--spacing-hsp-lg);
400
+ margin-bottom: var(--spacing-vsp-md);
401
+ overflow-x: auto;
402
+ }
403
+
404
+ .zd-content :where(pre code) {
405
+ background: transparent;
406
+ padding: 0;
407
+ border: none;
408
+ color: inherit;
409
+ font-size: inherit;
410
+ }
411
+
412
+ /* ── Tables ── */
413
+
414
+ .zd-content :where(table) {
415
+ width: 100%;
416
+ border-collapse: collapse;
417
+ font-size: var(--text-small);
418
+ margin-bottom: var(--spacing-vsp-md);
419
+ }
420
+
421
+ .zd-content :where(th),
422
+ .zd-content :where(td) {
423
+ padding: var(--spacing-vsp-xs) var(--spacing-hsp-md);
424
+ border-bottom: 1px solid var(--color-muted);
425
+ overflow-wrap: break-word;
426
+ }
427
+
428
+ .zd-content :where(th) {
429
+ font-weight: var(--font-weight-semibold);
430
+ text-align: left;
431
+ border-bottom-width: 2px;
432
+ }
433
+
434
+ /* ── Horizontal rules ── */
435
+
436
+ .zd-content :where(hr) {
437
+ border: none;
438
+ border-top: 1px solid var(--color-muted);
439
+ margin: var(--spacing-vsp-xl) 0;
440
+ }
441
+
442
+ /* ── Images ── */
443
+
444
+ .zd-content :where(img) {
445
+ max-width: 100%;
446
+ height: auto;
447
+ }
448
+
449
+ /* ── Definition lists ── */
450
+
451
+ .zd-content :where(dt) {
452
+ font-weight: var(--font-weight-semibold);
453
+ margin-top: var(--spacing-vsp-md);
454
+ }
455
+
456
+ .zd-content :where(dd) {
457
+ padding-left: var(--spacing-hsp-xl);
458
+ margin-bottom: var(--spacing-vsp-xs);
459
+ }
460
+
461
+ /* ========================================
462
+ * Admonitions ([data-admonition])
463
+ *
464
+ * Variant→color mapping: note→accent, tip→success, info→info,
465
+ * warning→warning, danger→danger. Background tint uses
466
+ * `color-mix(in srgb, var(--color-X) 12%, var(--color-bg))` for an opaque
467
+ * per-theme tinted backdrop. Class names are dynamic (admonition-${variant})
468
+ * so Tailwind cannot scan them; rules must live here explicitly.
469
+ * See zudolab/zudo-doc#1357 / #1444 / #1456.
470
+ * ======================================== */
471
+
472
+ [data-admonition] {
473
+ border-left: 4px solid var(--color-muted);
474
+ /* Asymmetric padding mirrors the Astro reference: generous top, snug bottom. */
475
+ padding: var(--spacing-vsp-md) var(--spacing-hsp-lg) var(--spacing-vsp-2xs);
476
+ background-color: color-mix(in srgb, var(--color-muted) 12%, var(--color-bg));
477
+ border-radius: 0 var(--radius-DEFAULT) var(--radius-DEFAULT) 0;
478
+ }
479
+
480
+ .admonition-title {
481
+ font-weight: var(--font-weight-semibold);
482
+ font-size: var(--text-small);
483
+ margin-bottom: var(--spacing-vsp-2xs);
484
+ }
485
+
486
+ /* Variant icon — emoji rendered via ::before so the stub markup stays
487
+ * variant-agnostic and the icon vocabulary lives next to its color rule. */
488
+ .admonition-title::before {
489
+ margin-right: var(--spacing-hsp-2xs);
490
+ }
491
+
492
+ .admonition-body > :first-child {
493
+ margin-top: 0;
494
+ }
495
+
496
+ .admonition-body > :last-child {
497
+ margin-bottom: 0;
498
+ }
499
+
500
+ [data-admonition="note"],
501
+ .admonition-note {
502
+ border-left-color: var(--color-accent);
503
+ background-color: color-mix(in srgb, var(--color-accent) 12%, var(--color-bg));
504
+ }
505
+
506
+ [data-admonition="note"] .admonition-title,
507
+ .admonition-note .admonition-title {
508
+ color: var(--color-accent);
509
+ }
510
+
511
+ [data-admonition="note"] .admonition-title::before,
512
+ .admonition-note .admonition-title::before {
513
+ content: "📝";
514
+ }
515
+
516
+ [data-admonition="tip"],
517
+ .admonition-tip {
518
+ border-left-color: var(--color-success);
519
+ background-color: color-mix(in srgb, var(--color-success) 12%, var(--color-bg));
520
+ }
521
+
522
+ [data-admonition="tip"] .admonition-title,
523
+ .admonition-tip .admonition-title {
524
+ color: var(--color-success);
525
+ }
526
+
527
+ [data-admonition="tip"] .admonition-title::before,
528
+ .admonition-tip .admonition-title::before {
529
+ content: "💡";
530
+ }
531
+
532
+ [data-admonition="info"],
533
+ .admonition-info {
534
+ border-left-color: var(--color-info);
535
+ background-color: color-mix(in srgb, var(--color-info) 12%, var(--color-bg));
536
+ }
537
+
538
+ [data-admonition="info"] .admonition-title,
539
+ .admonition-info .admonition-title {
540
+ color: var(--color-info);
541
+ }
542
+
543
+ [data-admonition="info"] .admonition-title::before,
544
+ .admonition-info .admonition-title::before {
545
+ content: "ℹ️";
546
+ }
547
+
548
+ [data-admonition="warning"],
549
+ .admonition-warning {
550
+ border-left-color: var(--color-warning);
551
+ background-color: color-mix(in srgb, var(--color-warning) 12%, var(--color-bg));
552
+ }
553
+
554
+ [data-admonition="warning"] .admonition-title,
555
+ .admonition-warning .admonition-title {
556
+ color: var(--color-warning);
557
+ }
558
+
559
+ [data-admonition="warning"] .admonition-title::before,
560
+ .admonition-warning .admonition-title::before {
561
+ content: "⚠️";
562
+ }
563
+
564
+ [data-admonition="danger"],
565
+ .admonition-danger {
566
+ border-left-color: var(--color-danger);
567
+ background-color: color-mix(in srgb, var(--color-danger) 12%, var(--color-bg));
568
+ }
569
+
570
+ [data-admonition="danger"] .admonition-title,
571
+ .admonition-danger .admonition-title {
572
+ color: var(--color-danger);
573
+ }
574
+
575
+ [data-admonition="danger"] .admonition-title::before,
576
+ .admonition-danger .admonition-title::before {
577
+ content: "🚨";
578
+ }
579
+
580
+ /* ========================================
581
+ * Code block buttons (copy + word wrap)
582
+ * ======================================== */
583
+
584
+ .code-block-wrapper {
585
+ position: relative;
586
+ }
587
+
588
+ pre[class^="syntect-"].word-wrap {
589
+ overflow-x: hidden;
590
+ }
591
+
592
+ pre[class^="syntect-"].word-wrap code {
593
+ white-space: pre-wrap;
594
+ overflow-wrap: anywhere;
595
+ }
596
+
597
+ .code-block-sr-announce {
598
+ position: absolute;
599
+ width: 1px;
600
+ height: 1px;
601
+ overflow: hidden;
602
+ clip: rect(0, 0, 0, 0);
603
+ white-space: nowrap;
604
+ }
605
+
606
+ .code-buttons {
607
+ position: absolute;
608
+ top: var(--spacing-hsp-sm);
609
+ right: var(--spacing-hsp-sm);
610
+ display: flex;
611
+ gap: var(--spacing-hsp-2xs);
612
+ opacity: 0;
613
+ transition: opacity 0.15s;
614
+ z-index: 1;
615
+ }
616
+
617
+ .code-block-wrapper:hover .code-buttons,
618
+ .code-block-wrapper:focus-within .code-buttons {
619
+ opacity: 1;
620
+ }
621
+
622
+ .code-btn {
623
+ display: flex;
624
+ align-items: center;
625
+ justify-content: center;
626
+ width: var(--spacing-hsp-2xl);
627
+ height: var(--spacing-hsp-2xl);
628
+ padding: 0;
629
+ border: 1px solid var(--color-muted);
630
+ border-radius: var(--radius-lg);
631
+ background-color: var(--color-surface);
632
+ color: var(--color-fg);
633
+ cursor: pointer;
634
+ transition:
635
+ color 0.15s,
636
+ border-color 0.15s,
637
+ background-color 0.15s;
638
+ }
639
+
640
+ .code-btn:hover {
641
+ color: var(--color-fg);
642
+ border-color: var(--color-fg);
643
+ }
644
+
645
+ .code-btn .code-icon {
646
+ width: var(--spacing-hsp-lg);
647
+ height: var(--spacing-hsp-lg);
648
+ }
649
+
650
+ /* Copy: icon swap */
651
+ .code-btn-copy .code-icon-check {
652
+ display: none;
653
+ }
654
+ .code-btn-copy .code-icon-copy {
655
+ display: block;
656
+ }
657
+ .code-btn-copy.copied .code-icon-check {
658
+ display: block;
659
+ color: var(--color-success);
660
+ }
661
+ .code-btn-copy.copied .code-icon-copy {
662
+ display: none;
663
+ }
664
+
665
+ /* Word wrap active state */
666
+ .code-btn-wrap.active {
667
+ color: var(--color-accent);
668
+ border-color: var(--color-accent);
669
+ }
670
+
671
+ @media (scripting: none) {
672
+ .code-buttons {
673
+ display: none;
674
+ }
675
+ }
676
+
677
+ /* ========================================
678
+ * Code-block syntax-highlight token color rule
679
+ * ======================================== */
680
+
681
+ /* Build-time: zfb's Rust pipeline runs SyntectPlugin and emits
682
+ * <pre class="syntect-..."> with inline style="color:#hex" on every token
683
+ * span. The inline hex is the desired token color — this rule must NOT
684
+ * override it (so: NO !important on `color`).
685
+ *
686
+ * Runtime (design-token-tweak panel, when enabled): Shiki re-highlights on
687
+ * demand and emits spans with inline style="--shiki-light:#X;--shiki-dark:#Y"
688
+ * — CSS custom properties only, no `color` declaration — depending on this
689
+ * rule to resolve light-dark(var(--shiki-light), var(--shiki-dark)) to the
690
+ * active theme. Shiki spans have no inline `color`, so the rule applies
691
+ * without needing !important. */
692
+ [data-theme] .shiki,
693
+ [data-theme] .shiki span,
694
+ [data-theme] pre[class^="syntect-"],
695
+ [data-theme] pre[class^="syntect-"] span {
696
+ color: light-dark(var(--shiki-light), var(--shiki-dark));
697
+ background-color: light-dark(var(--shiki-light-bg), var(--shiki-dark-bg));
698
+ font-style: light-dark(
699
+ var(--shiki-light-font-style, inherit),
700
+ var(--shiki-dark-font-style, inherit)
701
+ );
702
+ }
703
+
704
+ /* HtmlPreview component — Shiki code blocks
705
+ * Token colors inherit from the global [data-theme] .shiki rule above.
706
+ * These rules only adjust layout and background for the preview context. */
707
+ .zd-html-preview-code pre.shiki {
708
+ margin: 0;
709
+ padding: 0.75rem;
710
+ font-size: 0.875rem;
711
+ line-height: 1.6;
712
+ overflow-x: auto;
713
+ }
714
+
715
+ .zd-html-preview-code pre.shiki code {
716
+ font-family: var(--font-mono);
717
+ white-space: pre;
718
+ }
719
+
720
+ /* ========================================
721
+ * Code block line highlighting
722
+ * ======================================== */
723
+
724
+ /* Line highlighting via {1,3-5} meta syntax */
725
+ pre[class^="syntect-"] .line.highlighted {
726
+ background-color: color-mix(in srgb, var(--color-accent) 15%, transparent);
727
+ }
728
+
729
+ /* Word highlighting via /word/ meta syntax */
730
+ pre[class^="syntect-"] .line .highlighted-word {
731
+ background-color: color-mix(in srgb, var(--color-accent) 25%, transparent);
732
+ border-bottom: 1px solid var(--color-accent);
733
+ }
734
+
735
+ /* ========================================
736
+ * Code block titles
737
+ * ======================================== */
738
+
739
+ .code-block-container {
740
+ margin-top: 1em;
741
+ margin-bottom: 1em;
742
+ }
743
+
744
+ .code-block-title {
745
+ font-family: var(--font-mono);
746
+ font-size: var(--text-small);
747
+ color: var(--color-muted);
748
+ background-color: var(--color-code-bg);
749
+ border: 1px solid var(--color-muted);
750
+ border-bottom: none;
751
+ padding: var(--spacing-vsp-2xs) var(--spacing-hsp-lg);
752
+ }
753
+
754
+ .code-block-container pre[class^="syntect-"] {
755
+ margin-top: 0 !important;
756
+ border-top-left-radius: 0;
757
+ border-top-right-radius: 0;
758
+ }
759
+
760
+ /* ========================================
761
+ * Mermaid diagrams
762
+ * ======================================== */
763
+
764
+ .zd-content .mermaid {
765
+ @apply my-vsp-lg flex justify-center;
766
+ }
767
+
768
+ .zd-content .mermaid svg {
769
+ max-width: 100%;
770
+ height: auto;
771
+ overflow: visible;
772
+ }
773
+
774
+ /* Prevent mermaid edge labels from clipping text (foreignObject uses overflow:hidden) */
775
+ .zd-content .mermaid foreignObject {
776
+ overflow: visible;
777
+ }
778
+
779
+ /* KaTeX math equations */
780
+ .katex {
781
+ font-size: 1.1em;
782
+ }
783
+
784
+ .katex-display {
785
+ margin: var(--spacing-vsp-md) 0;
786
+ overflow-x: auto;
787
+ overflow-y: hidden;
788
+ padding: var(--spacing-vsp-xs) 0;
789
+ }
790
+
791
+ .katex-display > .katex {
792
+ white-space: nowrap;
793
+ }
794
+
795
+ /* Make KaTeX respect our color scheme */
796
+ .katex .base {
797
+ color: var(--zd-fg);
798
+ }
799
+
800
+ /* ── Search highlight ── */
801
+ [data-search-results] mark {
802
+ background-color: var(--color-matched-keyword-bg);
803
+ color: var(--color-matched-keyword-fg);
804
+ padding: 0;
805
+ border-radius: 2px;
806
+ }
807
+
808
+ /* ========================================
809
+ * Page transition animations
810
+ * ======================================== */
811
+
812
+ @keyframes contentFadeIn {
813
+ from {
814
+ opacity: 0;
815
+ transform: translateY(-0.75rem);
816
+ }
817
+ to {
818
+ opacity: 1;
819
+ transform: translateY(0);
820
+ }
821
+ }
822
+
823
+ @keyframes contentFadeOut {
824
+ from {
825
+ opacity: 1;
826
+ }
827
+ to {
828
+ opacity: 0;
829
+ }
830
+ }
831
+
832
+ /* Root cross-fade for same-document View Transitions (Strategy B).
833
+ *
834
+ * @view-transition { navigation: auto; } (Strategy A, cross-document) is
835
+ * deleted — Strategy B uses <ClientRouter /> which drives same-document
836
+ * transitions via document.startViewTransition on each navigation.
837
+ *
838
+ * Chrome extraction via view-transition-name (Strategy B+, zudolab/zudo-doc#1558):
839
+ * <header>, <aside id="desktop-sidebar">, <footer>, and the desktop-sidebar-toggle
840
+ * button each carry a data-zfb-transition-persist attribute whose value is keyed
841
+ * by locale and nav-section. The four attribute selectors below assign a stable
842
+ * view-transition-name based on the attribute value prefix, extracting those
843
+ * elements from the root snapshot into their own named layers:
844
+ * - header-{lang} → zfb-header
845
+ * - sidebar-{locale}-… → zfb-sidebar
846
+ * - footer-{lang} → zfb-footer
847
+ * - desktop-sidebar-toggle → zfb-sidebar-toggle
848
+ *
849
+ * Once extracted, the root cross-fade animates only non-chrome content (main,
850
+ * article, TOC, etc.). The twelve ::view-transition-{old,new,group}(<name>)
851
+ * rules disable animation for all four chrome layers. The group pseudo must be
852
+ * neutralised too — even when old/new are static the group container can still
853
+ * produce a geometry-morph animation when snapshot size/position differs. */
854
+
855
+ /* Chrome extraction — assign view-transition-name from data-zfb-transition-persist */
856
+ [data-zfb-transition-persist^="header-"] { view-transition-name: zfb-header; }
857
+ [data-zfb-transition-persist^="sidebar-"] { view-transition-name: zfb-sidebar; }
858
+ [data-zfb-transition-persist^="footer-"] { view-transition-name: zfb-footer; }
859
+ [data-zfb-transition-persist="desktop-sidebar-toggle"] { view-transition-name: zfb-sidebar-toggle; }
860
+
861
+ /* Disable animation for all four chrome layers (old, new, and group) */
862
+ ::view-transition-old(zfb-header),
863
+ ::view-transition-new(zfb-header),
864
+ ::view-transition-group(zfb-header),
865
+ ::view-transition-old(zfb-sidebar),
866
+ ::view-transition-new(zfb-sidebar),
867
+ ::view-transition-group(zfb-sidebar),
868
+ ::view-transition-old(zfb-footer),
869
+ ::view-transition-new(zfb-footer),
870
+ ::view-transition-group(zfb-footer),
871
+ ::view-transition-old(zfb-sidebar-toggle),
872
+ ::view-transition-new(zfb-sidebar-toggle),
873
+ ::view-transition-group(zfb-sidebar-toggle) { animation: none; }
874
+
875
+ /* Root cross-fade rules — animate only the non-chrome snapshot */
876
+ ::view-transition-old(root) {
877
+ animation: 150ms ease-in both contentFadeOut;
878
+ }
879
+ ::view-transition-new(root) {
880
+ animation: 300ms ease-out both contentFadeIn;
881
+ }
882
+
883
+ /* Version-switcher responsive visibility (moved out of the component to
884
+ * avoid <style>-inside-<div> HTML5 content-model violation; required when
885
+ * the i18nVersion feature ships a <VersionSwitcher> wrapped in
886
+ * `<div class="hidden lg:block">`. Inert when no version-switcher is on
887
+ * the page. */
888
+ @media (min-width: 64rem) {
889
+ .hidden:has(> [data-version-switcher]) {
890
+ display: block;
891
+ }
892
+ }
893
+
894
+ /* ========================================
895
+ * Desktop sidebar toggle (W7A: unconditional — feature gates at runtime)
896
+ * ======================================== */
897
+
898
+ @media (min-width: 1024px) {
899
+ #desktop-sidebar {
900
+ transition:
901
+ transform 200ms ease-in-out,
902
+ visibility 200ms;
903
+ }
904
+
905
+ html[data-sidebar-hidden] #desktop-sidebar {
906
+ transform: translateX(calc(-1 * var(--zd-sidebar-w)));
907
+ visibility: hidden;
908
+ }
909
+
910
+ .zd-sidebar-content-wrapper {
911
+ transition: margin-left 200ms ease-in-out;
912
+ }
913
+
914
+ html[data-sidebar-hidden] .zd-sidebar-content-wrapper {
915
+ margin-left: 0;
916
+ }
917
+ }
918
+
919
+ /* Sidebar toggle button — left position uses CSS variable, needs global rule */
920
+ @media (min-width: 1024px) {
921
+ .zd-desktop-sidebar-toggle {
922
+ left: var(--zd-sidebar-w);
923
+ }
924
+
925
+ html[data-sidebar-hidden] .zd-desktop-sidebar-toggle {
926
+ left: 0;
927
+ }
928
+ }
929
+
930
+ /* ── Find-in-page highlight (W7A: unconditional — Tauri feature gates at runtime) ── */
931
+ .find-match {
932
+ background-color: color-mix(in oklch, var(--color-warning) 40%, transparent);
933
+ border-radius: 2px;
934
+ }
935
+ .find-match-active {
936
+ background-color: color-mix(in oklch, var(--color-warning) 70%, transparent);
937
+ border-radius: 2px;
938
+ outline: 2px solid color-mix(in oklch, var(--color-warning) 90%, transparent);
939
+ }
940
+
941
+ /* ========================================
942
+ * Image enlarge (.zd-enlargeable) — W7A: unconditional, runtime-gated
943
+ * ======================================== */
944
+
945
+ .zd-enlargeable {
946
+ position: relative;
947
+ display: block;
948
+ margin-inline: 0;
949
+ margin-block-end: 0;
950
+ border: 1px solid transparent;
951
+ transition: border-color var(--default-transition-duration);
952
+ }
953
+
954
+ /* Eligible images (expand-btn visible): the entire image becomes the click target.
955
+ * Show a subtle border as the interactivity affordance, accent on hover. */
956
+ .zd-enlargeable:has(.zd-enlarge-btn:not([hidden])) {
957
+ border-color: var(--color-muted);
958
+ cursor: pointer;
959
+ }
960
+
961
+ .zd-enlargeable:has(.zd-enlarge-btn:not([hidden])):hover {
962
+ border-color: var(--color-accent);
963
+ }
964
+
965
+ .zd-enlargeable img {
966
+ display: block;
967
+ max-width: 100%;
968
+ height: auto;
969
+ }
970
+
971
+ .zd-enlarge-btn {
972
+ position: absolute;
973
+ top: var(--spacing-image-overlay-inset);
974
+ right: var(--spacing-image-overlay-inset);
975
+ display: flex;
976
+ align-items: center;
977
+ justify-content: center;
978
+ padding: var(--spacing-image-overlay-inset);
979
+ border: none;
980
+ background: transparent;
981
+ cursor: pointer;
982
+ z-index: 1;
983
+ transition: opacity var(--default-transition-duration);
984
+ }
985
+
986
+ .zd-enlarge-btn::before {
987
+ content: "";
988
+ position: absolute;
989
+ inset: 0;
990
+ background: color-mix(in oklch, var(--color-image-overlay-bg) 80%, transparent);
991
+ z-index: 0;
992
+ }
993
+
994
+ .zd-enlarge-btn > svg {
995
+ position: relative;
996
+ z-index: 1;
997
+ width: var(--spacing-icon-sm);
998
+ height: var(--spacing-icon-sm);
999
+ color: var(--color-image-overlay-fg);
1000
+ fill: currentColor;
1001
+ }
1002
+
1003
+ .zd-enlarge-btn:hover {
1004
+ opacity: 0.8;
1005
+ }
1006
+
1007
+ .zd-enlarge-btn[hidden] {
1008
+ display: none !important;
1009
+ }
1010
+
1011
+ dialog.zd-enlarge-dialog::backdrop {
1012
+ background: color-mix(in oklch, var(--color-overlay) 80%, transparent);
1013
+ }
1014
+
1015
+ /* Close button is positioned to the VIEWPORT corner (not the dialog) so it
1016
+ * stays visually distinct against any image, regardless of the dialog's size. */
1017
+ .zd-enlarge-dialog-close {
1018
+ position: fixed;
1019
+ top: 4px;
1020
+ right: 4px;
1021
+ display: flex;
1022
+ align-items: center;
1023
+ justify-content: center;
1024
+ padding: var(--spacing-image-overlay-inset);
1025
+ border: none;
1026
+ background: transparent;
1027
+ cursor: pointer;
1028
+ z-index: 1;
1029
+ transition: opacity var(--default-transition-duration);
1030
+ }
1031
+
1032
+ .zd-enlarge-dialog-close:hover {
1033
+ opacity: 0.8;
1034
+ }
1035
+
1036
+ .zd-enlarge-dialog-close::before {
1037
+ content: "";
1038
+ position: absolute;
1039
+ inset: 0;
1040
+ background: color-mix(in oklch, var(--color-image-overlay-bg) 80%, transparent);
1041
+ z-index: 0;
1042
+ }
1043
+
1044
+ .zd-enlarge-dialog-close > svg {
1045
+ position: relative;
1046
+ z-index: 1;
1047
+ width: var(--spacing-icon-lg);
1048
+ height: var(--spacing-icon-lg);
1049
+ color: var(--color-image-overlay-fg);
1050
+ fill: currentColor;
1051
+ }
1052
+
1053
+ /* Wide viewport: ~3× larger close button to read clearly against any image. */
1054
+ @media (min-width: 1024px) {
1055
+ .zd-enlarge-dialog-close {
1056
+ top: 10px;
1057
+ right: 10px;
1058
+ }
1059
+
1060
+ .zd-enlarge-dialog-close > svg {
1061
+ width: calc(var(--spacing-icon-lg) * 3);
1062
+ height: calc(var(--spacing-icon-lg) * 3);
1063
+ }
1064
+ }
1065
+
1066
+ /* @slot:global-css:feature-styles */