@takazudo/zudo-doc 0.2.8 → 0.2.10

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.
@@ -76,6 +76,56 @@ function buildMermaidInitScript(cdnUrl) {
76
76
  return value;
77
77
  }
78
78
 
79
+ // The --zd-* tokens the value-reader v() consumes. The observer gate
80
+ // snapshots their RESOLVED computed values so a :root[style] mutation
81
+ // that touches none of them correctly no-ops, while one that changes a
82
+ // tracked token (or data-theme) re-renders (zudolab/zudo-doc#2181).
83
+ var TRACKED_TOKENS = [
84
+ "--zd-bg",
85
+ "--zd-mermaid-node-bg",
86
+ "--zd-mermaid-text",
87
+ "--zd-mermaid-line",
88
+ "--zd-mermaid-note-bg",
89
+ "--zd-mermaid-label-bg",
90
+ ];
91
+
92
+ /**
93
+ * Snapshot the active theme state: the data-theme attribute plus the
94
+ * RESOLVED computed value of every tracked token. getComputedStyle is
95
+ * read fresh (not the raw style-attribute string) so an unrelated
96
+ * :root[style] change does not look like a token change, and a real
97
+ * token change is caught even when written indirectly.
98
+ */
99
+ function captureThemeState() {
100
+ var cs = getComputedStyle(document.documentElement);
101
+ var tokens = {};
102
+ TRACKED_TOKENS.forEach(function (name) {
103
+ tokens[name] = cs.getPropertyValue(name).trim();
104
+ });
105
+ return {
106
+ theme: document.documentElement.getAttribute("data-theme"),
107
+ tokens: tokens,
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Decide whether a genuine theme/token change occurred between two
113
+ * snapshots. Treats an empty/undefined -> real-value transition as a
114
+ * change: --zd-bg may be UNSET at first paint (luminance NaN); the
115
+ * observer is exactly what reinits once ColorSchemeProvider later
116
+ * populates the tokens, so that first colorization MUST still fire
117
+ * (zudolab/zudo-doc#2181).
118
+ */
119
+ function hasThemeStateChanged(prev, next) {
120
+ if (!prev) return true;
121
+ if (prev.theme !== next.theme) return true;
122
+ for (var i = 0; i < TRACKED_TOKENS.length; i++) {
123
+ var name = TRACKED_TOKENS[i];
124
+ if (prev.tokens[name] !== next.tokens[name]) return true;
125
+ }
126
+ return false;
127
+ }
128
+
79
129
  async function initMermaid() {
80
130
  var els = document.querySelectorAll("[data-mermaid]:not([data-mermaid-rendered])");
81
131
  if (els.length === 0) return;
@@ -172,6 +222,18 @@ function buildMermaidInitScript(cdnUrl) {
172
222
  theme: "base",
173
223
  themeVariables: themeVariables,
174
224
  });
225
+ // Cache each diagram's source BEFORE mermaid.run consumes it
226
+ // (mermaid replaces the graph text with the rendered <svg> and
227
+ // sets data-processed). Use textContent \u2014 the DECODED source
228
+ // mermaid consumes \u2014 NOT innerHTML, which would re-encode/decode
229
+ // entities and corrupt diagrams containing \`-->\` arrows or \`&\`.
230
+ // Only set when absent so repeated reinits keep the ORIGINAL
231
+ // source (zudolab/zudo-doc#2181).
232
+ els.forEach(function (el) {
233
+ if (!el.hasAttribute("data-mermaid-src")) {
234
+ el.setAttribute("data-mermaid-src", el.textContent);
235
+ }
236
+ });
175
237
  await mermaid.run({ nodes: Array.from(els) });
176
238
  els.forEach(function (el) { el.setAttribute("data-mermaid-rendered", ""); });
177
239
  } catch (e) {
@@ -179,14 +241,31 @@ function buildMermaidInitScript(cdnUrl) {
179
241
  }
180
242
  }
181
243
 
182
- /** Re-render all mermaid diagrams (clear rendered state so initMermaid picks them up). */
244
+ /**
245
+ * Re-render all mermaid diagrams from their cached source text.
246
+ *
247
+ * By the time this runs, mermaid.run has already CONSUMED the source
248
+ * (replaced the graph text with the rendered <svg> and set
249
+ * data-processed), so clearing data-mermaid-rendered alone leaves the
250
+ * node permanently blank \u2014 initMermaid re-selects it but mermaid.run
251
+ * skips nodes that still have data-processed, and there is no source
252
+ * left to regenerate from. Restore the cached source, drop the SVG,
253
+ * and remove BOTH data-processed AND data-mermaid-rendered so the next
254
+ * initMermaid pass regenerates cleanly. Keep data-mermaid-src so
255
+ * repeated theme toggles keep working (zudolab/zudo-doc#2181).
256
+ */
183
257
  function reinitMermaid() {
184
258
  document.querySelectorAll("[data-mermaid-rendered]").forEach(function (el) {
185
- el.removeAttribute("data-mermaid-rendered");
186
- // Remove rendered SVG so mermaid regenerates from source text.
259
+ var src = el.getAttribute("data-mermaid-src");
260
+ if (src !== null) el.textContent = src;
187
261
  var svg = el.querySelector("svg");
188
262
  if (svg) svg.remove();
263
+ el.removeAttribute("data-processed");
264
+ el.removeAttribute("data-mermaid-rendered");
189
265
  });
266
+ // Refresh the theme snapshot now that the genuine change is applied,
267
+ // so the observer's gate measures the NEXT change against this state.
268
+ lastThemeState = captureThemeState();
190
269
  initMermaid();
191
270
  }
192
271
 
@@ -207,8 +286,26 @@ function buildMermaidInitScript(cdnUrl) {
207
286
  // the new theme's hex picks from parseLightDark).
208
287
  // Debounced so a synchronous flip of both attributes triggers a
209
288
  // single re-render.
289
+ //
290
+ // zudolab/zudo-doc#2181: gate on a REAL theme/token change. zfb-runtime's
291
+ // client router (swapRootAttributes) removes+re-adds ALL :root attributes
292
+ // on every soft navigation, so unchanged data-theme/style still fire
293
+ // mutations \u2014 without this gate the observer reinits ~300ms after every
294
+ // nav and (combined with the old destructive reinit) blanks every
295
+ // diagram. New diagrams reached by soft-nav are already handled by the
296
+ // AFTER_NAVIGATE_EVENT -> initMermaid() listener above, so the observer
297
+ // only needs to fire for genuine theme/token changes.
298
+ //
299
+ // Seed the snapshot at script-eval time \u2014 BEFORE ColorSchemeProvider
300
+ // runs, so the tokens are likely empty. hasThemeStateChanged treats
301
+ // empty -> real as a change, so the first legitimate colorization still
302
+ // fires; reinitMermaid then refreshes the snapshot.
303
+ var lastThemeState = captureThemeState();
210
304
  var tweakTimer;
211
305
  new MutationObserver(function () {
306
+ var next = captureThemeState();
307
+ if (!hasThemeStateChanged(lastThemeState, next)) return;
308
+ lastThemeState = next;
212
309
  clearTimeout(tweakTimer);
213
310
  tweakTimer = setTimeout(reinitMermaid, 300);
214
311
  }).observe(document.documentElement, {
@@ -0,0 +1,448 @@
1
+ /* ============================================================================
2
+ * @takazudo/zudo-doc — content typography stylesheet (`.zd-content`)
3
+ *
4
+ * Shipped to consumers as `@takazudo/zudo-doc/content.css` (copied to
5
+ * `dist/content.css` by scripts/copy-content-css.mjs on build). This is the
6
+ * SINGLE SOURCE OF TRUTH for markdown content rendering — both this repo's
7
+ * showcase (`src/styles/global.css`) and every project scaffolded by
8
+ * `create-zudo-doc` `@import` it instead of copying these rules. Editing the
9
+ * rules here updates every consumer on the next package version (no per-project
10
+ * drift). See zudolab/zudo-doc#2188.
11
+ *
12
+ * Component-first split: the major elements (h2–h4, p, a, strong, blockquote,
13
+ * ul, ol, table) get their VISUALS from the package's `htmlOverrides` Preact
14
+ * components (Tailwind classes + inline styles), whose utilities ship in
15
+ * `dist/safelist.css`. This file owns only what those components do NOT emit:
16
+ * the flow-space vertical rhythm, heading `--flow-space` + tightening, the
17
+ * minor/structural elements (li, code, pre, th/td, hr, img, h5/h6, dt/dd,
18
+ * hash-links), and the admonitions + mermaid layout.
19
+ *
20
+ * ── Consumer contract ──────────────────────────────────────────────────────
21
+ * 1. LAYER ORDER — the consumer's stylesheet MUST declare, before importing:
22
+ * @layer zd-preflight, zd-flow;
23
+ * @import "tailwindcss/preflight" layer(zd-preflight);
24
+ * @import "tailwindcss/utilities"; (unlayered)
25
+ * The flow-space owl rule below lives in `@layer zd-flow` so unlayered
26
+ * `mt-*` utilities win over it while it still beats preflight's
27
+ * `* { margin: 0 }`. See zudolab/zudo-doc#2082 / #2109.
28
+ * 2. DESIGN TOKENS — the consumer's `@theme` MUST define every custom property
29
+ * consumed below:
30
+ * --color-{fg,bg,muted,accent,accent-hover,code-bg,code-fg,info,success,
31
+ * warning,danger,p5}
32
+ * --spacing-{vsp-2xs,vsp-xs,vsp-sm,vsp-md,vsp-lg,vsp-xl,vsp-2xl,
33
+ * hsp-2xs,hsp-xs,hsp-sm,hsp-md,hsp-lg,hsp-xl}
34
+ * --text-{body,small} --font-mono --font-weight-{medium,semibold}
35
+ * --leading-{relaxed,snug} --radius-DEFAULT
36
+ * 3. SAFELIST — the consumer MUST also `@import "@takazudo/zudo-doc/safelist.css"`
37
+ * so the component-emitted utility classes (text-title, border-t-[3px],
38
+ * text-accent, …) are generated.
39
+ * ========================================================================== */
40
+
41
+ /* ========================================
42
+ * Content typography (.zd-content)
43
+ *
44
+ * Direct element styling — no prose plugin.
45
+ * Uses :where() for zero specificity (easy to override).
46
+ * Font size pattern inspired by zpaper: paired size + line-height.
47
+ * ======================================== */
48
+
49
+ .zd-content {
50
+ color: var(--color-fg);
51
+ font-size: var(--text-body);
52
+ line-height: var(--leading-relaxed);
53
+ }
54
+
55
+ /* ── Flow spacing (vertical rhythm) ── */
56
+
57
+ /* In the `zd-flow` cascade layer (declared by the consumer at the top of its
58
+ * stylesheet) so the unlayered `tailwindcss/utilities` import wins over it:
59
+ * unlayered declarations always beat layered ones regardless of specificity or
60
+ * source order. Both this rule and a `mt-*` utility have specificity (0,1,0);
61
+ * without the layer this rule comes later in source order and silently kills
62
+ * every `mt-*` on a `.zd-content` direct child (e.g. body-foot-util-area's
63
+ * `mt-vsp-xl`). zd-flow sits ABOVE zd-preflight so this rule still beats
64
+ * preflight's `* { margin: 0 }` reset and the .zd-content rhythm is preserved
65
+ * for plain content blocks. The layer is scoped to ONLY this flow rule — every
66
+ * other `.zd-content` author rule (links, code, lists, headings, the
67
+ * `:first-child` reset, etc.) stays unlayered so utilities do NOT flip those.
68
+ * Custom-property resolution (the heading `--flow-space` overrides) is
69
+ * layer-independent, so the per-heading flow gaps are unaffected.
70
+ * See zudolab/zudo-doc#2082 / #2109. */
71
+ @layer zd-flow {
72
+ .zd-content > :where(* + *) {
73
+ margin-top: var(--flow-space, var(--spacing-vsp-md));
74
+ }
75
+ }
76
+
77
+ /* ── Headings ── */
78
+
79
+ /* Heading flow-space (structural — consumed by flow spacing system) */
80
+
81
+ .zd-content :where(h2) {
82
+ --flow-space: var(--spacing-vsp-2xl);
83
+ }
84
+
85
+ .zd-content :where(h3) {
86
+ --flow-space: var(--spacing-vsp-xl);
87
+ }
88
+
89
+ .zd-content :where(h4) {
90
+ --flow-space: var(--spacing-vsp-lg);
91
+ }
92
+
93
+ .zd-content :where(h5, h6) {
94
+ --flow-space: var(--spacing-vsp-md);
95
+ font-size: var(--text-small);
96
+ font-weight: var(--font-weight-semibold);
97
+ line-height: var(--leading-snug);
98
+ }
99
+
100
+ /* Consecutive headings: tighten to avoid accumulated whitespace */
101
+ .zd-content :where(h2, h3, h4, h5, h6) + :where(h2, h3, h4, h5, h6) {
102
+ --flow-space: var(--spacing-vsp-xs);
103
+ }
104
+
105
+ /* Content immediately after a heading: tight gap (replaces heading margin-bottom) */
106
+ .zd-content :where(h2, h3, h4, h5, h6) + :where(:not(h2, h3, h4, h5, h6)) {
107
+ --flow-space: var(--spacing-vsp-xs);
108
+ }
109
+
110
+ /* First child never needs top margin */
111
+ .zd-content > :first-child {
112
+ margin-top: 0;
113
+ }
114
+
115
+ /* Flow spacing inside nested sections (e.g., preset generator) */
116
+ .zd-content .zd-preset-gen :where(section) > :where(* + *) {
117
+ margin-top: var(--flow-space, var(--spacing-vsp-md));
118
+ }
119
+
120
+ /* ── Heading auto-links ── */
121
+
122
+ .zd-content :where(h2, h3, h4, h5, h6) .hash-link {
123
+ text-decoration: none;
124
+ margin-left: var(--spacing-hsp-sm);
125
+ opacity: 0;
126
+ transition: opacity 150ms;
127
+ }
128
+
129
+ .zd-content :where(h2, h3, h4, h5, h6) .hash-link::after {
130
+ content: "#";
131
+ color: var(--color-accent);
132
+ }
133
+
134
+ .zd-content :where(h2, h3, h4, h5, h6):hover .hash-link {
135
+ opacity: 1;
136
+ }
137
+
138
+ .zd-content :where(h2, h3, h4, h5, h6) .hash-link:focus-visible {
139
+ opacity: 1;
140
+ outline: 2px solid var(--color-accent);
141
+ outline-offset: 2px;
142
+ }
143
+
144
+ /* ── Links ── */
145
+
146
+ /* Link reset inside site-nav (component can't detect ancestor context) */
147
+ .zd-content [data-site-nav] a {
148
+ color: inherit;
149
+ text-decoration: none;
150
+ }
151
+ .zd-content [data-site-nav] a:hover,
152
+ .zd-content [data-site-nav] a:focus-visible {
153
+ text-decoration: underline;
154
+ }
155
+
156
+ /* ── Lists ── */
157
+
158
+ .zd-content :where(li) {
159
+ margin-bottom: var(--spacing-vsp-xs);
160
+ }
161
+
162
+ .zd-content :where(li::marker) {
163
+ color: var(--color-muted);
164
+ }
165
+
166
+ .zd-content :where(li > ul, li > ol) {
167
+ margin-top: var(--spacing-vsp-xs);
168
+ margin-bottom: 0;
169
+ }
170
+
171
+ /* ── Blockquotes ── */
172
+ /* blockquote base styles live in ContentBlockquote component; keep nested p rule
173
+ here because MDX renders <p> children independently (component can't style them) */
174
+
175
+ .zd-content :where(blockquote p) {
176
+ margin-bottom: var(--spacing-vsp-xs);
177
+ }
178
+
179
+ /* ── Inline code ── */
180
+
181
+ .zd-content :where(code:not(pre code)) {
182
+ font-size: var(--text-small);
183
+ font-weight: var(--font-weight-medium);
184
+ font-family: var(--font-mono);
185
+ background-color: var(--color-code-bg);
186
+ color: var(--color-code-fg);
187
+ border-radius: var(--radius-DEFAULT);
188
+ padding: 2px var(--spacing-hsp-xs);
189
+ }
190
+
191
+ /* ── Code blocks (pre) ── */
192
+
193
+ .zd-content :where(pre) {
194
+ font-family: var(--font-mono);
195
+ font-size: var(--text-small);
196
+ line-height: var(--leading-relaxed);
197
+ border: 1px solid var(--color-muted);
198
+ padding: var(--spacing-vsp-sm) var(--spacing-hsp-lg);
199
+ overflow-x: auto;
200
+ }
201
+
202
+ .zd-content :where(pre code) {
203
+ background: transparent;
204
+ padding: 0;
205
+ border: none;
206
+ color: inherit;
207
+ font-size: inherit;
208
+ }
209
+
210
+ /* ── Tables ── */
211
+
212
+ .zd-content :where(th),
213
+ .zd-content :where(td) {
214
+ padding: var(--spacing-vsp-xs) var(--spacing-hsp-md);
215
+ border-bottom: 1px solid var(--color-muted);
216
+ overflow-wrap: break-word;
217
+ }
218
+
219
+ .zd-content :where(th) {
220
+ font-weight: var(--font-weight-semibold);
221
+ text-align: left;
222
+ border-bottom-width: 2px;
223
+ }
224
+
225
+ /* ── Horizontal rules ── */
226
+
227
+ .zd-content :where(hr) {
228
+ border: none;
229
+ border-top: 1px solid var(--color-muted);
230
+ margin: var(--spacing-vsp-xl) 0;
231
+ }
232
+
233
+ /* ── Images ── */
234
+
235
+ .zd-content :where(img) {
236
+ max-width: 100%;
237
+ height: auto;
238
+ }
239
+
240
+ /* ── Definition lists ── */
241
+
242
+ .zd-content :where(dt) {
243
+ font-weight: var(--font-weight-semibold);
244
+ margin-top: var(--spacing-vsp-md);
245
+ }
246
+
247
+ .zd-content :where(dd) {
248
+ padding-left: var(--spacing-hsp-xl);
249
+ margin-bottom: var(--spacing-vsp-xs);
250
+ }
251
+
252
+ /* ========================================
253
+ * Admonitions ([data-admonition])
254
+ *
255
+ * The admonition component (content-admonition.tsx, wired in
256
+ * pages/_mdx-components.ts) emits:
257
+ * <div data-admonition="<variant>" class="admonition admonition-<variant>">
258
+ * <p class="admonition-title">…</p>
259
+ * <div class="admonition-body">…</div>
260
+ * </div>
261
+ *
262
+ * Variant→color mapping (matches Astro reference theme): note→accent,
263
+ * tip→success, info→info, warning→warning, danger→danger. The icon emoji is
264
+ * added via `.admonition-title::before` keyed off `data-admonition`.
265
+ *
266
+ * Background tint uses `color-mix(in srgb, var(--color-X) 12%, var(--color-bg))`
267
+ * per the production reference — gives an opaque per-theme tinted backdrop
268
+ * rather than a transparent overlay (matches the Astro reference look exactly).
269
+ *
270
+ * Class names are dynamic (admonition-${variant}) so Tailwind cannot scan them;
271
+ * rules must live here explicitly. Closes zudolab/zudo-doc#1357 / #1444 / #1456.
272
+ *
273
+ * Spacing: the box carries NO margin — the separating gap to the next block is
274
+ * supplied by that block's flow-space `margin-top` (the owl rule above). The
275
+ * snug bottom padding keeps the body tight inside the box without inflating
276
+ * that gap. (A missing bottom margin on the box is intentional in the flow
277
+ * model — do NOT add one; see zudolab/zudo-doc#2188 for why the per-element
278
+ * margin model that needed it was retired.)
279
+ * ======================================== */
280
+
281
+ [data-admonition] {
282
+ border-left: 4px solid var(--color-muted);
283
+ /* Asymmetric padding mirrors the Astro reference (`pt-vsp-md pb-vsp-2xs`) —
284
+ * generous space at the top, snug at the bottom — so the title row sits
285
+ * under generous breathing room without inflating the bottom gap. */
286
+ padding: var(--spacing-vsp-md) var(--spacing-hsp-lg) var(--spacing-vsp-2xs);
287
+ background-color: color-mix(in srgb, var(--color-muted) 12%, var(--color-bg));
288
+ border-radius: 0 var(--radius-DEFAULT) var(--radius-DEFAULT) 0;
289
+ }
290
+
291
+ .admonition-title {
292
+ font-weight: var(--font-weight-semibold);
293
+ font-size: var(--text-small);
294
+ margin-bottom: var(--spacing-vsp-2xs);
295
+ }
296
+
297
+ /* Variant icon — emoji rendered via ::before so the stub markup stays
298
+ * variant-agnostic and the icon vocabulary lives next to its color rule.
299
+ * Matches the Astro reference (`<span class="mr-hsp-2xs">📝</span>` etc.). */
300
+ .admonition-title::before {
301
+ margin-right: var(--spacing-hsp-2xs);
302
+ }
303
+
304
+ .admonition-body > :first-child {
305
+ margin-top: 0;
306
+ }
307
+
308
+ .admonition-body > :last-child {
309
+ margin-bottom: 0;
310
+ }
311
+
312
+ [data-admonition="note"],
313
+ .admonition-note {
314
+ border-left-color: var(--color-accent);
315
+ background-color: color-mix(in srgb, var(--color-accent) 12%, var(--color-bg));
316
+ }
317
+
318
+ [data-admonition="note"] .admonition-title,
319
+ .admonition-note .admonition-title {
320
+ color: var(--color-accent);
321
+ }
322
+
323
+ [data-admonition="note"] .admonition-title::before,
324
+ .admonition-note .admonition-title::before {
325
+ content: "📝";
326
+ }
327
+
328
+ [data-admonition="tip"],
329
+ .admonition-tip {
330
+ border-left-color: var(--color-success);
331
+ background-color: color-mix(in srgb, var(--color-success) 12%, var(--color-bg));
332
+ }
333
+
334
+ [data-admonition="tip"] .admonition-title,
335
+ .admonition-tip .admonition-title {
336
+ color: var(--color-success);
337
+ }
338
+
339
+ [data-admonition="tip"] .admonition-title::before,
340
+ .admonition-tip .admonition-title::before {
341
+ content: "💡";
342
+ }
343
+
344
+ [data-admonition="info"],
345
+ .admonition-info {
346
+ border-left-color: var(--color-info);
347
+ background-color: color-mix(in srgb, var(--color-info) 12%, var(--color-bg));
348
+ }
349
+
350
+ [data-admonition="info"] .admonition-title,
351
+ .admonition-info .admonition-title {
352
+ color: var(--color-info);
353
+ }
354
+
355
+ [data-admonition="info"] .admonition-title::before,
356
+ .admonition-info .admonition-title::before {
357
+ content: "ℹ️";
358
+ }
359
+
360
+ [data-admonition="warning"],
361
+ .admonition-warning {
362
+ border-left-color: var(--color-warning);
363
+ background-color: color-mix(in srgb, var(--color-warning) 12%, var(--color-bg));
364
+ }
365
+
366
+ [data-admonition="warning"] .admonition-title,
367
+ .admonition-warning .admonition-title {
368
+ color: var(--color-warning);
369
+ }
370
+
371
+ [data-admonition="warning"] .admonition-title::before,
372
+ .admonition-warning .admonition-title::before {
373
+ content: "⚠️";
374
+ }
375
+
376
+ [data-admonition="danger"],
377
+ .admonition-danger {
378
+ border-left-color: var(--color-danger);
379
+ background-color: color-mix(in srgb, var(--color-danger) 12%, var(--color-bg));
380
+ }
381
+
382
+ [data-admonition="danger"] .admonition-title,
383
+ .admonition-danger .admonition-title {
384
+ color: var(--color-danger);
385
+ }
386
+
387
+ [data-admonition="danger"] .admonition-title::before,
388
+ .admonition-danger .admonition-title::before {
389
+ content: "🚨";
390
+ }
391
+
392
+ /* github-alerts [!IMPORTANT] → magenta/accent-adjacent (p5 = magenta palette slot) */
393
+ [data-admonition="important"],
394
+ .admonition-important {
395
+ border-left-color: var(--color-p5);
396
+ background-color: color-mix(in srgb, var(--color-p5) 12%, var(--color-bg));
397
+ }
398
+
399
+ [data-admonition="important"] .admonition-title,
400
+ .admonition-important .admonition-title {
401
+ color: var(--color-p5);
402
+ }
403
+
404
+ [data-admonition="important"] .admonition-title::before,
405
+ .admonition-important .admonition-title::before {
406
+ content: "❗";
407
+ }
408
+
409
+ /* github-alerts [!CAUTION] → danger-adjacent (high severity, distinct from danger/🚨) */
410
+ [data-admonition="caution"],
411
+ .admonition-caution {
412
+ border-left-color: var(--color-danger);
413
+ background-color: color-mix(in srgb, var(--color-danger) 12%, var(--color-bg));
414
+ }
415
+
416
+ [data-admonition="caution"] .admonition-title,
417
+ .admonition-caution .admonition-title {
418
+ color: var(--color-danger);
419
+ }
420
+
421
+ [data-admonition="caution"] .admonition-title::before,
422
+ .admonition-caution .admonition-title::before {
423
+ content: "⛔";
424
+ }
425
+
426
+ /* ========================================
427
+ * Mermaid diagrams (layout only; color theming is applied by the
428
+ * mermaid-init script via --zd-mermaid-* and is not part of this file)
429
+ * ======================================== */
430
+
431
+ .zd-content .mermaid {
432
+ /* was `@apply my-vsp-lg flex justify-center` — inlined to plain CSS so this
433
+ file ships as framework-agnostic CSS (no Tailwind processing required). */
434
+ margin-block: var(--spacing-vsp-lg);
435
+ display: flex;
436
+ justify-content: center;
437
+ }
438
+
439
+ .zd-content .mermaid svg {
440
+ max-width: 100%;
441
+ height: auto;
442
+ overflow: visible;
443
+ }
444
+
445
+ /* Prevent mermaid edge labels from clipping text (foreignObject uses overflow:hidden) */
446
+ .zd-content .mermaid foreignObject {
447
+ overflow: visible;
448
+ }
@@ -4,8 +4,10 @@ export { stripMarkdown } from '../../md-utils/index.js';
4
4
  * Markdown / JSX text-stripping helpers.
5
5
  *
6
6
  * `stripImportsAndJsx` matches the legacy Astro emitter's behaviour
7
- * byte-for-byte. Any change here is a behaviour change and must be
8
- * reflected in the byte-equality fixture corpus.
7
+ * byte-for-byte, with one deliberate divergence: it also strips JSX/MDX
8
+ * block comments (the `{/*`-delimited MDX comment form), which the legacy
9
+ * emitter leaked (zudo-doc#2175). Any other change here is a behaviour
10
+ * change and must be reflected in the byte-equality fixture corpus.
9
11
  *
10
12
  * `stripMarkdown` (used to derive a fallback `description` from the body
11
13
  * when frontmatter doesn't carry one) lives in the shared `md-utils`
@@ -1,6 +1,6 @@
1
1
  import { stripMarkdown } from "../../md-utils/index.js";
2
2
  function stripImportsAndJsx(content) {
3
- return content.replace(/^import\s+.*$/gm, "").replace(/^export\s+.*$/gm, "").replace(/<\/?[a-zA-Z][a-zA-Z0-9]*[^>]*>/g, "").replace(/\n{3,}/g, "\n\n").trim();
3
+ return content.replace(/^import\s+.*$/gm, "").replace(/^export\s+.*$/gm, "").replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/<\/?[a-zA-Z][a-zA-Z0-9]*[^>]*>/g, "").replace(/\n{3,}/g, "\n\n").trim();
4
4
  }
5
5
  export {
6
6
  stripImportsAndJsx,
@@ -32,8 +32,10 @@ interface MdDocFrontmatter {
32
32
  * Strip markdown formatting to plain text. Conservative-by-design — the
33
33
  * regex pipeline matches the legacy Astro integrations byte-for-byte so
34
34
  * search excerpts and llms-txt descriptions stay byte-equal across the
35
- * cutover. Do not add new rules without also updating the byte-equality
36
- * fixtures (topic-plugin-audit).
35
+ * cutover, with one deliberate divergence: it also strips JSX/MDX block
36
+ * comments (the `{/*`-delimited MDX comment form), which the legacy
37
+ * pipeline leaked into descriptions (zudo-doc#2175). Do not add other new
38
+ * rules without also updating the byte-equality fixtures (topic-plugin-audit).
37
39
  */
38
40
  declare function stripMarkdown(md: string): string;
39
41
  /**
@@ -2,7 +2,7 @@ import { readFileSync, readdirSync } from "node:fs";
2
2
  import { join, relative } from "node:path";
3
3
  import matter from "gray-matter";
4
4
  function stripMarkdown(md) {
5
- return md.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/<[^>]+>/g, "").replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}([^*]+)\*{1,3}/g, "$1").replace(/_{1,3}([^_]+)_{1,3}/g, "$1").replace(/!\[[^\]]*\]\([^)]+\)/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/^[\s]*[-*+]\s+/gm, "").replace(/^[\s]*\d+\.\s+/gm, "").replace(/^import\s+.*$/gm, "").replace(/^export\s+.*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
5
+ return md.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/<[^>]+>/g, "").replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}([^*]+)\*{1,3}/g, "$1").replace(/_{1,3}([^_]+)_{1,3}/g, "$1").replace(/!\[[^\]]*\]\([^)]+\)/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/^[\s]*[-*+]\s+/gm, "").replace(/^[\s]*\d+\.\s+/gm, "").replace(/^import\s+.*$/gm, "").replace(/^export\s+.*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
6
6
  }
7
7
  function collectMdFiles(dir) {
8
8
  const results = [];
package/dist/safelist.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /* generated by gen-safelist.mjs — do not edit by hand */
2
- @source inline("-mb-px [&::-webkit-details-marker]:hidden [&_a]:text-accent [&_a]:underline [&_nav]:mb-0 [doc-history-meta] [doc-layout] a a2 abbr above absolute active actual after after-breadcrumb after-content after-sidebar after-title against agent agents ai-chat ai-chat-trigger align-top all allow-same-origin allow-scripts already-executed an anchor anchored and announce antialiased any application/json applies apply-css-vars are area arg aria-controls aria-current aria-disabled aria-expanded aria-haspopup aria-hidden aria-label aria-live aria-orientation aria-pressed aria-selected aria-valuemax aria-valuemin aria-valuenow article as asc aside assets assigning assistant async at attach attribute attributes available await away b back backdrop:bg-bg/80 background backtick backticks baked banner bare based be because before below between bg bg-[#fff] bg-accent bg-bg bg-code-bg bg-fg bg-info/10 bg-muted bg-surface bg-transparent bg-warning/10 bg-warning/5 bi bigint bin blob block blockquote blocks blur body body-end-components body-end-scripts boolean bootstrap border border-accent border-b border-b-2 border-b-[5px] border-collapse border-fg border-l border-l-[3px] border-muted border-none border-r border-t border-t-[2px] border-t-[3px] border-transparent border-warning/30 both br breadcrumb:end breadcrumb:start break-words browser browsers btn bundler but button buttons by caller can cancellation cannot canonical caption cases cat-nav- catch category catppuccin-latte checkbox child ci circle cite class class-less claude claude-agents claude-commands claude-md claude-skills cleaned clear clear-css-vars click client clip close code code-block-sr-announce col col-resize colgroup collision color color-scheme color-scheme-changed color-scheme-provider color-tweak colors command commands commit component component:github-link component:language-switcher component:search component:theme-toggle component:version-switcher concrete configuration configure configured consumer container containers content content-type content-wrapper:end content-wrapper:start contents controller converts copy correct covered covers crashes crumb- css cursor cursor-not-allowed cursor-pointer custom dark data-active data-group-id data-header data-header-logo data-header-nav data-header-right data-mermaid-rendered data-nav-item data-nav-item-dropdown data-nav-more data-nav-more-menu data-nav-more-toggle data-sidebar-resizer data-tab-btn data-tab-default data-tab-label data-tab-value data-tabs data-taglist-group data-testid data-theme data-variant data-version-banner data-version-menu data-version-switcher data-version-toggle data-zfb-transition-persist dd decimal declare decoration-muted default defaults del desc description design design-token-panel design-token-trigger desktop desktop-sidebar detached details deterministic dfn diagram diagrams dialog dieser directories directory disc display:none dist div dl doc doc-card- doc-history doc-history-generate does drag draggable dropdown dropdowns dt duration-150 duration-200 during dynamically e2e earlier edge el element elements els else em emit emitting empty en entries entry error escape even eventually every exactly exit expected failed fall fallback falls false fast feed fg fieldset figcaption figure file fill fills finally fire fires first fixed fixtures flex flex-1 flex-col flex-wrap flip flipping flips focus focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 focus-visible:underline focus:underline font font-bold font-medium font-mono font-semibold footer for form free from frontmatter frontmatter-preview full function further g gap-[clamp(1.5rem,3vw,4rem)] gap-hsp-2xs gap-hsp-sm gap-hsp-xs gap-vsp-lg gap-vsp-xs gap-x-hsp-2xs gap-x-hsp-lg gap-x-hsp-md gap-x-hsp-sm gap-x-hsp-xs gap-y-vsp-2xs gap-y-vsp-lg gap-y-vsp-md gap-y-vsp-xs gaps generate generation geometry get github github-link go got gray-matter grid grid-cols-1 group group-focus-visible:underline group-focus-within:block group-hover:bg-fg group-hover:block group-hover:text-bg group-hover:underline group-open:rotate-90 guard h-[0.5rem] h-[0.875rem] h-[1.575rem] h-[1lh] h-[3.5rem] h-[calc(100vh-3.5rem)] h-icon-sm h-icon-xs h1 h2 h3 h4 h5 h6 hand handle handled handlers has hash-link have head head-links head-scripts header header-call:end header-call:start height here hex hidden highlighter history hit horizontal host hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)] hover:bg-accent-hover hover:bg-accent/10 hover:border-accent hover:border-accent-hover hover:border-fg hover:text-accent hover:text-accent-hover hover:text-fg hover:underline hr html i i2 i3 i4 identical if iframe img import imports in index inherit initial initialised inline inline-block inline-flex input ins inset-0 inside instanceof instructions intent into inverse invoke is it italic item- items items-center items-start itself javascript justify-between justify-center justify-end kbd keep keeps kept keydown khroma label landing language-switcher last:border-b-0 launch leading-relaxed leading-snug leading-tight leaf- leaving left left-0 left:calc legend lg lg:block lg:flex lg:grid-cols-[repeat(auto-fit,minmax(12rem,1fr))] lg:ml-[var(--zd-sidebar-w)] lg:pt-vsp-2xl lg:px-hsp-2xl lg:py-vsp-2xl li li2 light like line link link- list-disc list-none listener literal lives llms llms-txt load local lostpointercapture luminance m m-0 main make maps mark marks matching max-h-[80vh] max-w-[46rem] max-w-[80rem] max-w-[clamp(50rem,75vw,90rem)] max-w-full max-w-none mb-0 mb-vsp-2xs mb-vsp-lg mb-vsp-md mb-vsp-sm mb-vsp-xl mb-vsp-xs menu merged mermaid message meta metadata min-h-[calc(100vh-3.5rem)] min-h-screen min-w-0 min-w-[10rem] min-w-[8rem] mirror missing ml-auto ml-hsp-2xl ml-hsp-lg ml-hsp-sm ml-hsp-xl mod mode mounted mouseenter mouseleave mt-0 mt-vsp-2xs mt-vsp-3xs mt-vsp-lg mt-vsp-sm mt-vsp-xl must mutates mx-auto my-vsp-lg my-vsp-md name named native nav nav-card- navigating navigation navigations near needs new next no-underline node:fs node:module node:path nodes nofollow noindex non-empty non-string none noopener noreferrer normal not not-object note now null number object observe observer of og:description og:image og:title og:type og:url ol older on once one only opacity-60 option or other others out overflow overflow-auto overflow-hidden overflow-x-auto overflow-y-auto overflow-y:auto own p p-0 p-hsp-lg p-hsp-md p-hsp-sm p-hsp-xl packages padding page page-loading-overlay page-loading-spinner page-navigate-end pages paint panel panels parent parse parsed pass path pb-vsp-xl per pi pick picked picks pins pipelines pl-[1.25rem] pl-hsp-lg pl-hsp-sm pl-hsp-xl place pointer-events-none pointercancel pointerdown pointermove pointerup polite polyline populates port position position:fixed pr-hsp-lg pr-hsp-md pr-hsp-xl pre preact preact/hooks preact/jsx-runtime preload pres produced produces production propagating properties property proxy pt-vsp-3xs pt-vsp-md pt-vsp-sm pt-vsp-xl pt-vsp-xs ptag- public purely px px-hsp-lg px-hsp-md px-hsp-sm px-hsp-xl px-hsp-xs py-0 py-hsp-2xs py-hsp-sm py-hsp-xs py-vsp-2xs py-vsp-3xs py-vsp-md py-vsp-sm py-vsp-xl py-vsp-xs q r raw re-render re-run reach reaches reading ready real references regenerates reinit relative remains render rendered renders reorder replaced repopulate requires reserved resize resize-x resolve resolved resolves return returns right- right-0 ro robots role root rotate-180 rotate-90 round round-trip rounded rounded-full rounded-lg running runs runtime s safer samp schema-mismatch schema-missing script script-evaluation scripts scroll scrollbar scrolled scrollend search section section- see sel-bg sel-fg select select-none self-start separator server server-rendered set shadow-[0_1px_3px_color-mix(in_srgb,var(--color-fg)_8%,transparent)] shadow-lg shared shiki ships should show shown shrink-0 sidebar signal single sitemap- size skill skills slash slug sm:flex-row sm:grid-cols-2 sm:items-center sm:justify-between small so solid some source space-y-vsp-2xs spacing span spans spec specifiers sr-only stale state stay sticky still stored stray string strip stroke-linecap stroke-linejoin stroke-width strong style styles stylesheet sub subagents subsequent success summary sup support survives svg synchronous synchronously syntactically syntect tab tab-panel tabindex table tablist tabpanel tabs tabs-container tabs-content tabs-nav tag- tag-item- tbody td temp temp-element template temporary temporary-element test-results text text-accent text-bg text-body text-caption text-center text-code-fg text-fg text-heading text-info text-left text-micro text-muted text-muted/50 text-small text-title text-warning textarea tfoot th that the thead them theme theme-color theme-toggle then these they this through time title to toggle toggle-ai-chat toggle-design-token-panel token tokens tolerates too top-0 top-[3.5rem] top-full total tr tracking-wider trade-off transition-[background,color,border-color] transition-colors transition-transform tree-child- tree-item- tree-top- trick trigger trigger:ai-chat trigger:design-token-panel triggers true try twitter:card twitter:creator twitter:description twitter:image twitter:site twitter:title two u ul unavailable undefined under underline understand unknown unmaintained unobserve unreadable unreleased unreliable unset unsupported up uppercase use used uses utf-8 utf8 utilities v val value values var variable version- version-menu version-switcher vertical via video viewport visible vitesse-dark w w-[0.5rem] w-[0.875rem] w-[1.575rem] w-[16px] w-[280px] w-[var(--zd-sidebar-w)] w-full w-icon-sm w-icon-xs was watching wbr wbr- we when where whereas which while whitespace-nowrap whitespace-pre whole will with without word worktrees would wrap wrapper wrappers written wrote xl:flex xl:hidden y-scrollbar yet z-dropdown z-sidebar z-toolbar zd-content zd-doc-content-band zd-html-preview-code zd-sidebar-content-wrapper zfb zfb:after-swap zfb:before-preparation zudo-doc-design-tokens/v1 zudo-doc-sidebar-width zudo-doc-theme zudo-doc-theme-bridge");
2
+ @source inline("-mb-px [&::-webkit-details-marker]:hidden [&_a]:text-accent [&_a]:underline [&_nav]:mb-0 [doc-history-meta] [doc-layout] a a2 abbr above absent absolute active actual after after-breadcrumb after-content after-sidebar after-title against agent agents ai-chat ai-chat-trigger align-top all allow-same-origin allow-scripts alone already already-executed an anchor anchored and announce antialiased any application/json applies apply-css-vars are area arg aria-controls aria-current aria-disabled aria-expanded aria-haspopup aria-hidden aria-label aria-live aria-orientation aria-pressed aria-selected aria-valuemax aria-valuemin aria-valuenow arrows article as asc aside assets assigning assistant async at attach attribute attributes available await away b back backdrop:bg-bg/80 background backtick backticks baked banner bare based be because before below between bg bg-[#fff] bg-accent bg-bg bg-code-bg bg-fg bg-info/10 bg-muted bg-surface bg-transparent bg-warning/10 bg-warning/5 bi bigint bin blank blanks blob block blockquote blocks blur body body-end-components body-end-scripts boolean bootstrap border border-accent border-b border-b-2 border-b-[5px] border-collapse border-fg border-l border-l-[3px] border-muted border-none border-r border-t border-t-[2px] border-t-[3px] border-transparent border-warning/30 both br breadcrumb:end breadcrumb:start break-words browser browsers btn bundler but button buttons by cached caller can cancellation cannot canonical caption cases cat-nav- catch category catppuccin-latte caught change changes checkbox child ci circle cite class class-less claude claude-agents claude-commands claude-md claude-skills cleaned clear clear-css-vars clearing click client clip close code code-block-sr-announce col col-resize colgroup collision color color-scheme color-scheme-changed color-scheme-provider color-tweak colorization colors command commands commit component component:github-link component:language-switcher component:search component:theme-toggle component:version-switcher computed concrete configuration configure configured consumer consumes container containers containing content content-type content-wrapper:end content-wrapper:start contents controller converts copy correct correctly corrupt covered covers crashes crumb- cs css cursor cursor-not-allowed cursor-pointer custom dark data-active data-group-id data-header data-header-logo data-header-nav data-header-right data-mermaid-rendered data-mermaid-src data-nav-item data-nav-item-dropdown data-nav-more data-nav-more-menu data-nav-more-toggle data-processed data-sidebar-resizer data-tab-btn data-tab-default data-tab-label data-tab-value data-tabs data-taglist-group data-testid data-theme data-theme/style data-variant data-version-banner data-version-menu data-version-switcher data-version-toggle data-zfb-transition-persist dd decimal declare decoration-muted default defaults del desc description design design-token-panel design-token-trigger desktop desktop-sidebar destructive detached details deterministic dfn diagram diagrams dialog dieser directories directory disc display:none dist div dl doc doc-card- doc-history doc-history-generate does drag draggable drop dropdown dropdowns dt duration-150 duration-200 during dynamically e2e each earlier edge el element elements els else em emit emitting empty empty/undefined en entities entries entry error escape even eventually every exactly exit expected failed fall fallback falls false fast feed fg fieldset figcaption figure file fill fills finally fire fires first fixed fixtures flex flex-1 flex-col flex-wrap flip flipping flips focus focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 focus-visible:underline focus:underline font font-bold font-medium font-mono font-semibold footer for form free fresh from frontmatter frontmatter-preview full function further g gap-[clamp(1.5rem,3vw,4rem)] gap-hsp-2xs gap-hsp-sm gap-hsp-xs gap-vsp-lg gap-vsp-xs gap-x-hsp-2xs gap-x-hsp-lg gap-x-hsp-md gap-x-hsp-sm gap-x-hsp-xs gap-y-vsp-2xs gap-y-vsp-lg gap-y-vsp-md gap-y-vsp-xs gaps gate generate generation genuine geometry get github github-link go got graph gray-matter grid grid-cols-1 group group-focus-visible:underline group-focus-within:block group-hover:bg-fg group-hover:block group-hover:text-bg group-hover:underline group-open:rotate-90 guard h-[0.5rem] h-[0.875rem] h-[1.575rem] h-[1lh] h-[3.5rem] h-[calc(100vh-3.5rem)] h-icon-sm h-icon-xs h1 h2 h3 h4 h5 h6 hand handle handled handlers has hash-link have head head-links head-scripts header header-call:end header-call:start height here hex hidden highlighter history hit horizontal host hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)] hover:bg-accent-hover hover:bg-accent/10 hover:border-accent hover:border-accent-hover hover:border-fg hover:text-accent hover:text-accent-hover hover:text-fg hover:underline hr html i i2 i3 i4 identical if iframe img import imports in index inherit initial initialised inline inline-block inline-flex input ins inset-0 inside instanceof instructions intent into inverse invoke is it italic item- items items-center items-start itself javascript justify-between justify-center justify-end kbd keep keeps kept keydown khroma label landing language-switcher last:border-b-0 later launch leading-relaxed leading-snug leading-tight leaf- leaves leaving left left-0 left:calc legend legitimate lg lg:block lg:flex lg:grid-cols-[repeat(auto-fit,minmax(12rem,1fr))] lg:ml-[var(--zd-sidebar-w)] lg:pt-vsp-2xl lg:px-hsp-2xl lg:py-vsp-2xl li li2 light like likely line link link- list-disc list-none listener literal lives llms llms-txt load local look lostpointercapture luminance m m-0 main make maps mark marks matching max-h-[80vh] max-w-[46rem] max-w-[80rem] max-w-[clamp(50rem,75vw,90rem)] max-w-full max-w-none may mb-0 mb-vsp-2xs mb-vsp-lg mb-vsp-md mb-vsp-sm mb-vsp-xl mb-vsp-xs measures menu merged mermaid message meta metadata min-h-[calc(100vh-3.5rem)] min-h-screen min-w-0 min-w-[10rem] min-w-[8rem] mirror missing ml-auto ml-hsp-2xl ml-hsp-lg ml-hsp-sm ml-hsp-xl mod mode mounted mouseenter mouseleave mt-0 mt-vsp-2xs mt-vsp-3xs mt-vsp-lg mt-vsp-sm mt-vsp-xl must mutates mutation mutations mx-auto my-vsp-lg my-vsp-md name named native nav nav-card- navigating navigation navigations near needs new next no no-underline node node:fs node:module node:path nodes nofollow noindex non-empty non-string none noopener noreferrer normal not not-object note now null number object observe observer occurred of og:description og:image og:title og:type og:url ol old older on once one only opacity-60 option or other others out overflow overflow-auto overflow-hidden overflow-x-auto overflow-y-auto overflow-y:auto own p p-0 p-hsp-lg p-hsp-md p-hsp-sm p-hsp-xl packages padding page page-loading-overlay page-loading-spinner page-navigate-end pages paint panel panels parent parse parsed pass path pb-vsp-xl per permanently pi pick picked picks pins pipelines pl-[1.25rem] pl-hsp-lg pl-hsp-sm pl-hsp-xl place plus pointer-events-none pointercancel pointerdown pointermove pointerup polite polyline populates port position position:fixed pr-hsp-lg pr-hsp-md pr-hsp-xl pre preact preact/hooks preact/jsx-runtime preload pres produced produces production propagating properties property proxy pt-vsp-3xs pt-vsp-md pt-vsp-sm pt-vsp-xl pt-vsp-xs ptag- public purely px px-hsp-lg px-hsp-md px-hsp-sm px-hsp-xl px-hsp-xs py-0 py-hsp-2xs py-hsp-sm py-hsp-xs py-vsp-2xs py-vsp-3xs py-vsp-md py-vsp-sm py-vsp-xl py-vsp-xs q r raw re-encode/decode re-render re-renders re-run re-selects reach reached reaches read reading ready real real-value references refreshes regenerate regenerates reinit reinits relative remains remove render rendered renders reorder repeated replaced replaces repopulate requires reserved resize resize-x resolve resolved resolves return returns right- right-0 ro robots role root rotate-180 rotate-90 round round-trip rounded rounded-full rounded-lg router running runs runtime s safer samp schema-mismatch schema-missing script script-eval script-evaluation scripts scroll scrollbar scrolled scrollend search section section- see sel-bg sel-fg select select-none self-start separator server server-rendered set sets shadow-[0_1px_3px_color-mix(in_srgb,var(--color-fg)_8%,transparent)] shadow-lg shared shiki ships should show shown shrink-0 sidebar signal single sitemap- size skill skills skips slash slug sm:flex-row sm:grid-cols-2 sm:items-center sm:justify-between small snapshot snapshots so soft soft-nav solid some source space-y-vsp-2xs spacing span spans spec specifiers sr-only src stale stay sticky still stored stray string strip stroke-linecap stroke-linejoin stroke-width strong style style-attribute styles stylesheet sub subagents subsequent success summary sup support survives svg synchronous synchronously syntactically syntect tab tab-panel tabindex table tablist tabpanel tabs tabs-container tabs-content tabs-nav tag- tag-item- tbody td temp temp-element template temporary temporary-element test-results text text-accent text-bg text-body text-caption text-center text-code-fg text-fg text-heading text-info text-left text-micro text-muted text-muted/50 text-small text-title text-warning textarea tfoot th that the thead their them theme theme-color theme-toggle theme/token then there these they this through time title to toggle toggle-ai-chat toggle-design-token-panel toggles token tokens tolerates too top-0 top-[3.5rem] top-full total touches tr tracked tracking-wider trade-off transition transition-[background,color,border-color] transition-colors transition-transform treats tree-child- tree-item- tree-top- trick trigger trigger:ai-chat trigger:design-token-panel triggers true try twitter:card twitter:creator twitter:description twitter:image twitter:site twitter:title two u ul unavailable unchanged undefined under underline understand unknown unmaintained unobserve unreadable unrelated unreleased unreliable unset unsupported up uppercase use used uses utf-8 utf8 utilities v val value value-reader values var variable version- version-menu version-switcher vertical via video viewport visible vitesse-dark w w-[0.5rem] w-[0.875rem] w-[1.575rem] w-[16px] w-[280px] w-[var(--zd-sidebar-w)] w-full w-icon-sm w-icon-xs was watching wbr wbr- we what when where whereas whether which while whitespace-nowrap whitespace-pre whole will with without word working worktrees would wrap wrapper wrappers written wrote xl:flex xl:hidden y-scrollbar yet z-dropdown z-sidebar z-toolbar zd-content zd-doc-content-band zd-html-preview-code zd-sidebar-content-wrapper zfb zfb:after-swap zfb:before-preparation zudo-doc-design-tokens/v1 zudo-doc-sidebar-width zudo-doc-theme zudo-doc-theme-bridge");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "type": "module",
5
5
  "description": "zudo-doc framework primitives layer that sits on top of zfb's engine — sidebar, theme, TOC, breadcrumb, layouts, head injection, View Transitions, SSR-skip wrappers (per ADR-003).",
6
6
  "license": "MIT",
@@ -156,7 +156,8 @@
156
156
  "default": "./dist/icons/index.js"
157
157
  },
158
158
  "./safelist.css": "./dist/safelist.css",
159
- "./safelist": "./dist/safelist.css"
159
+ "./safelist": "./dist/safelist.css",
160
+ "./content.css": "./dist/content.css"
160
161
  },
161
162
  "files": [
162
163
  "dist",
@@ -164,11 +165,11 @@
164
165
  ],
165
166
  "peerDependencies": {
166
167
  "preact": "^10.29.1",
167
- "@takazudo/zfb": "^0.1.0-next.47",
168
- "@takazudo/zfb-runtime": "^0.1.0-next.47",
168
+ "@takazudo/zfb": "^0.1.0-next.51",
169
+ "@takazudo/zfb-runtime": "^0.1.0-next.51",
169
170
  "@takazudo/zdtp": "^0.2.3",
170
171
  "shiki": "^4.0.2",
171
- "@takazudo/zudo-doc-history-server": "^0.2.8"
172
+ "@takazudo/zudo-doc-history-server": "^0.2.10"
172
173
  },
173
174
  "peerDependenciesMeta": {
174
175
  "@takazudo/zudo-doc-history-server": {
@@ -193,8 +194,8 @@
193
194
  "tsup": "^8.0.0",
194
195
  "typescript": "^5.0.0",
195
196
  "vitest": "^4.1.0",
196
- "@takazudo/zfb": "0.1.0-next.47",
197
- "@takazudo/zfb-runtime": "0.1.0-next.47"
197
+ "@takazudo/zfb": "0.1.0-next.51",
198
+ "@takazudo/zfb-runtime": "0.1.0-next.51"
198
199
  },
199
200
  "scripts": {
200
201
  "build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 tsup",