@takazudo/zudo-doc 8.1.1 → 8.1.3

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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,22 @@ The format is based on Keep a Changelog, and release notes are generated from th
8
8
 
9
9
  No unreleased changes.
10
10
 
11
+ ## [8.1.3] - 2026-10-26
12
+
13
+ ### Features
14
+
15
+ - Polish the document heading hierarchy in nine theme packs (drift, fjord, hollow, manuscript, matcha, nocturne, observatory, sakura, solar): h2 gets a 2px top rule with line-height 1.3, h3 a quieter 1px muted rule with line-height 1.4, and h4 no rule with line-height 1.45, with per-pack sizes and weights. Each pack keeps its rule inks, fonts, small caps and motifs; the rules apply only to document headings, so home and compact-prose headings are unchanged. (f0ac53df)
16
+
17
+ ### Bug Fixes
18
+
19
+ - Observatory: the constellation star nodes now follow the same document-h2 selector as the constellation line, so they never appear without it. (d72441b4)
20
+
21
+ ## [8.1.2] - 2026-10-26
22
+
23
+ ### Other Changes
24
+
25
+ - Requires zfb 5.1.4: the `@takazudo/zfb`, `zfb-runtime` and `zfb-md-wasm` peer floors move from `^5.1.3` to `^5.1.4`. zfb 5.1.4 rebuilds the native engine and WASM binaries; the JavaScript API is unchanged. Update the zfb family (and `zfb-adapter-cloudflare` when used) to 5.1.4 together with this release. (833fbc78)
26
+
11
27
  ## [8.1.1] - 2026-10-26
12
28
 
13
29
  ### Bug Fixes
package/README.md CHANGED
@@ -109,7 +109,7 @@ If your project renders **semi-trusted or user-submitted** HTML in a preview, ov
109
109
 
110
110
  **6.0.0** is the coordinated major release of `@takazudo/zudo-doc`,
111
111
  `@takazudo/zudo-doc-history-server` and `create-zudo-doc`. The current workspace
112
- targets the published **zfb 5.1.3** family (peer floor **^5.1.3**).
112
+ targets the published **zfb 5.1.4** family (peer floor **^5.1.4**).
113
113
  [Upstream #4097](https://github.com/Takazudo/zudo-front-builder/issues/4097) is
114
114
  resolved; its strict published 4.3.1 consumer control passed 3/3 with no skips or
115
115
  retries in the [source-bound verification](../../docs/findings/zfb-4.3.1/verification.md).
@@ -307,27 +307,62 @@ html[data-theme-pack="drift"] a[data-nav-active] {
307
307
  0 0 18px -4px color-mix(in oklch, var(--zd-accent) 45%, transparent);
308
308
  }
309
309
 
310
- /* headings: quiet luminance instead of heavy rules. The h2 keeps a
311
- gradient bar but fades it into the accent glow — !important
312
- defeats the SSR-inlined `style="border-image:linear-gradient(...)"`
313
- (Decision 6.6's sole allowlisted carve-out). */
310
+ /* headings: quiet luminance plus a top-only rule hierarchy. h2 carries
311
+ a 2px accent rule, h3 a quieter 1px muted rule, h4 no rule at all.
312
+ The rules are top-anchored background gradients; border-image none
313
+ !important (Decision 6.6's sole allowlisted carve-out) keeps the
314
+ SSR-inlined `style="border-image:linear-gradient(...)"` from painting
315
+ a second bar. */
314
316
  html[data-theme-pack="drift"] .zd-content h1 {
315
317
  text-shadow: 0 0 34px color-mix(in oklch, var(--zd-accent) 32%, transparent);
316
318
  }
317
319
  html[data-theme-pack="drift"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
318
- font-size: 1.6rem;
319
- }
320
- html[data-theme-pack="drift"] .zd-content h2 {
321
- border-top-width: 1px;
322
- border-image: linear-gradient(
323
- to right,
324
- color-mix(in oklch, var(--zd-accent) 55%, transparent),
325
- transparent 72%
326
- )
327
- 1 !important;
320
+ border-image: none !important;
321
+ border-top-width: 0;
322
+ border-bottom-width: 0;
323
+ padding-top: 1.25rem;
324
+ padding-bottom: 0;
325
+ font-size: 1.75rem;
326
+ font-weight: 600;
327
+ line-height: 1.3;
328
+ background-image: linear-gradient(
329
+ to right,
330
+ var(--zd-accent) 0%,
331
+ var(--zd-accent) 32%,
332
+ color-mix(in oklch, var(--zd-accent) 58%, transparent) 72%,
333
+ transparent 100%
334
+ );
335
+ background-size: 100% 2px;
336
+ background-repeat: no-repeat;
337
+ background-position: top left;
328
338
  }
329
339
  html[data-theme-pack="drift"] .zd-content h3:where(:not(.zd-compact-prose *)) {
330
- border-top-width: 1px;
340
+ border-image: none !important;
341
+ border-top-width: 0;
342
+ border-bottom-width: 0;
343
+ padding-top: 0.875rem;
344
+ padding-bottom: 0;
345
+ font-size: 1.375rem;
346
+ font-weight: 600;
347
+ line-height: 1.4;
348
+ background-image: linear-gradient(
349
+ to right,
350
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
351
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
352
+ transparent 76%
353
+ );
354
+ background-size: 100% 1px;
355
+ background-repeat: no-repeat;
356
+ background-position: top left;
357
+ }
358
+ html[data-theme-pack="drift"] .zd-content h4:where(:not(.zd-compact-prose *)) {
359
+ border-width: 0;
360
+ padding-top: 0;
361
+ padding-bottom: 0;
362
+ font-size: 1.2rem;
363
+ font-weight: 500;
364
+ line-height: 1.45;
365
+ background-image: none;
331
366
  }
332
367
 
333
368
  /* links: airy underline that brightens on approach */
@@ -232,21 +232,62 @@ html[data-theme-pack="fjord"] a[data-nav-active] {
232
232
  box-shadow: 0 0 16px -4px color-mix(in oklch, var(--zd-accent) 55%, transparent);
233
233
  }
234
234
 
235
- /* headings: aurora rule over every h2 instead of the default fg
236
- fade. The SSR-inlined `style="border-image:linear-gradient(...)"`
237
- is defeated with !important (Decision 6.6's sole allowlisted
238
- carve-out) — here it is REPLACED by the aurora ribbon, not
239
- removed. */
240
- html[data-theme-pack="fjord"] .zd-content h2 {
241
- border-top-width: 2px;
242
- border-image: linear-gradient(
243
- to right,
244
- light-dark(oklch(0.6 0.1 195), oklch(0.78 0.11 185)),
245
- light-dark(oklch(0.58 0.09 250), oklch(0.66 0.1 255)) 42%,
246
- transparent 88%
247
- )
248
- 1 !important;
235
+ /* headings: a top-only rule hierarchy. h2 carries the 2px aurora
236
+ ribbon (cyan into blue) instead of the default fg fade, h3 a quieter
237
+ 1px muted rule, h4 no rule. The rules are top-anchored background
238
+ gradients; border-image none !important (Decision 6.6's sole
239
+ allowlisted carve-out) keeps the SSR-inlined
240
+ `style="border-image:linear-gradient(...)"` from painting a second
241
+ bar. */
242
+ html[data-theme-pack="fjord"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
243
+ border-image: none !important;
244
+ border-top-width: 0;
245
+ border-bottom-width: 0;
246
+ padding-top: 1.25rem;
247
+ padding-bottom: 0;
248
+ font-size: 1.75rem;
249
+ font-weight: 700;
250
+ line-height: 1.3;
251
+ background-image: linear-gradient(
252
+ to right,
253
+ light-dark(oklch(0.6 0.1 195), oklch(0.78 0.11 185)) 0%,
254
+ light-dark(oklch(0.6 0.1 195), oklch(0.78 0.11 185)) 24%,
255
+ light-dark(oklch(0.58 0.09 250), oklch(0.66 0.1 255)) 64%,
256
+ transparent 100%
257
+ );
258
+ background-size: 100% 2px;
259
+ background-repeat: no-repeat;
260
+ background-position: top left;
249
261
  }
262
+ html[data-theme-pack="fjord"] .zd-content h3:where(:not(.zd-compact-prose *)) {
263
+ border-image: none !important;
264
+ border-top-width: 0;
265
+ border-bottom-width: 0;
266
+ padding-top: 0.875rem;
267
+ padding-bottom: 0;
268
+ font-size: 1.375rem;
269
+ font-weight: 600;
270
+ line-height: 1.4;
271
+ background-image: linear-gradient(
272
+ to right,
273
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
274
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
275
+ transparent 76%
276
+ );
277
+ background-size: 100% 1px;
278
+ background-repeat: no-repeat;
279
+ background-position: top left;
280
+ }
281
+ html[data-theme-pack="fjord"] .zd-content h4:where(:not(.zd-compact-prose *)) {
282
+ border-width: 0;
283
+ padding-top: 0;
284
+ padding-bottom: 0;
285
+ font-size: 1.2rem;
286
+ font-weight: 500;
287
+ line-height: 1.45;
288
+ background-image: none;
289
+ }
290
+
250
291
  html[data-theme-pack="fjord"] .zd-content h1 {
251
292
  color: color-mix(in oklch, var(--zd-accent) 10%, var(--zd-fg));
252
293
  }
@@ -261,23 +261,58 @@ html[data-theme-pack="hollow"] .zd-content h1 {
261
261
  text-shadow: 0 0 22px light-dark(transparent, oklch(0.7 0.19 348 / 0.38));
262
262
  }
263
263
 
264
- /* h2: the SSR-inlined gradient bar is re-pointed at a fading pink
265
- rule (Decision 6.6's sole allowlisted !important carve-out —
266
- border-image only) */
264
+ /* top-only rule hierarchy: h2 carries a 2px fading pink rule, h3 a
265
+ quieter 1px muted rule, h4 no rule. The rules are top-anchored
266
+ background gradients; border-image none !important (Decision 6.6's
267
+ sole allowlisted carve-out) keeps the SSR-inlined gradient bar from
268
+ painting a second rule. */
267
269
  html[data-theme-pack="hollow"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
268
- font-size: 1.5rem;
269
- }
270
- html[data-theme-pack="hollow"] .zd-content h2 {
271
- border-image: linear-gradient(
272
- to right,
273
- color-mix(
274
- in oklch,
275
- light-dark(oklch(0.52 0.2 350), oklch(0.78 0.17 348)) 62%,
276
- transparent
277
- ),
278
- transparent 72%
279
- )
280
- 1 !important;
270
+ border-image: none !important;
271
+ border-top-width: 0;
272
+ border-bottom-width: 0;
273
+ padding-top: 1.25rem;
274
+ padding-bottom: 0;
275
+ font-size: 1.75rem;
276
+ font-weight: 700;
277
+ line-height: 1.3;
278
+ background-image: linear-gradient(
279
+ to right,
280
+ light-dark(oklch(0.52 0.2 350), oklch(0.78 0.17 348)) 0%,
281
+ light-dark(oklch(0.52 0.2 350), oklch(0.78 0.17 348)) 32%,
282
+ color-mix(in oklch, light-dark(oklch(0.52 0.2 350), oklch(0.78 0.17 348)) 58%, transparent) 72%,
283
+ transparent 100%
284
+ );
285
+ background-size: 100% 2px;
286
+ background-repeat: no-repeat;
287
+ background-position: top left;
288
+ }
289
+ html[data-theme-pack="hollow"] .zd-content h3:where(:not(.zd-compact-prose *)) {
290
+ border-image: none !important;
291
+ border-top-width: 0;
292
+ border-bottom-width: 0;
293
+ padding-top: 0.875rem;
294
+ padding-bottom: 0;
295
+ font-size: 1.375rem;
296
+ font-weight: 600;
297
+ line-height: 1.4;
298
+ background-image: linear-gradient(
299
+ to right,
300
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
301
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
302
+ transparent 76%
303
+ );
304
+ background-size: 100% 1px;
305
+ background-repeat: no-repeat;
306
+ background-position: top left;
307
+ }
308
+ html[data-theme-pack="hollow"] .zd-content h4:where(:not(.zd-compact-prose *)) {
309
+ border-width: 0;
310
+ padding-top: 0;
311
+ padding-bottom: 0;
312
+ font-size: 1.2rem;
313
+ font-weight: 500;
314
+ line-height: 1.45;
315
+ background-image: none;
281
316
  }
282
317
 
283
318
  /* links: violet, quiet underline that ignites on hover */
@@ -204,20 +204,15 @@ html[data-theme-pack="manuscript"] nav[data-zd-toc] a {
204
204
  font-size: 0.95rem;
205
205
  }
206
206
 
207
- /* the signature: letterspaced small-capital subheads. The real h2/h3 carry
208
- an SSR-inlined `style="border-image:linear-gradient(...)"` bar: the h2
209
- replaces it with a hairline rule (border-image none !important is
210
- Decision 6.6's sole allowlisted carve-out); the h3 wants NO bar, which
211
- zeroing the class-level border-top-width achieves without !important
212
- (a zero-width border area leaves the inline border-image nothing to
213
- paint on). */
207
+ /* the signature: letterspaced small-capital subheads over a top-only rule
208
+ hierarchy. Document h2 carries a 2px ink rule, h3 a quieter 1px muted
209
+ rule, h4 no rule. The rules are top-anchored background gradients;
210
+ border-image none !important (Decision 6.6's sole allowlisted carve-out)
211
+ keeps the SSR-inlined `style="border-image:linear-gradient(...)"` from
212
+ painting a second bar. The unscoped rules keep the small caps (and the
213
+ compact-prose h3 voice) everywhere else. */
214
214
  html[data-theme-pack="manuscript"] .zd-content h2 {
215
- border-image: none !important;
216
- border-top-width: 1px;
217
- border-top-color: color-mix(in oklch, var(--zd-fg) 28%, transparent);
218
- padding-top: 1.35rem;
219
215
  font-variant-caps: small-caps;
220
- font-size: 1.55rem;
221
216
  }
222
217
  html[data-theme-pack="manuscript"] .zd-content h3 {
223
218
  border-top-width: 0;
@@ -225,6 +220,56 @@ html[data-theme-pack="manuscript"] .zd-content h3 {
225
220
  letter-spacing: 0.09em;
226
221
  font-size: 1.28rem;
227
222
  }
223
+ html[data-theme-pack="manuscript"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
224
+ border-image: none !important;
225
+ border-top-width: 0;
226
+ border-bottom-width: 0;
227
+ padding-top: 1.25rem;
228
+ padding-bottom: 0;
229
+ font-size: 2rem;
230
+ font-weight: 600;
231
+ line-height: 1.3;
232
+ letter-spacing: 0.055em;
233
+ background-image: linear-gradient(
234
+ to right,
235
+ color-mix(in oklch, var(--zd-fg) 72%, var(--zd-accent)) 0%,
236
+ color-mix(in oklch, var(--zd-fg) 72%, var(--zd-accent)) 32%,
237
+ color-mix(in oklch, color-mix(in oklch, var(--zd-fg) 72%, var(--zd-accent)) 58%, transparent) 72%,
238
+ transparent 100%
239
+ );
240
+ background-size: 100% 2px;
241
+ background-repeat: no-repeat;
242
+ background-position: top left;
243
+ }
244
+ html[data-theme-pack="manuscript"] .zd-content h3:where(:not(.zd-compact-prose *)) {
245
+ border-image: none !important;
246
+ border-top-width: 0;
247
+ border-bottom-width: 0;
248
+ padding-top: 0.875rem;
249
+ padding-bottom: 0;
250
+ font-size: 1.5rem;
251
+ font-weight: 500;
252
+ line-height: 1.4;
253
+ letter-spacing: 0.045em;
254
+ background-image: linear-gradient(
255
+ to right,
256
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
257
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
258
+ transparent 76%
259
+ );
260
+ background-size: 100% 1px;
261
+ background-repeat: no-repeat;
262
+ background-position: top left;
263
+ }
264
+ html[data-theme-pack="manuscript"] .zd-content h4:where(:not(.zd-compact-prose *)) {
265
+ border-width: 0;
266
+ padding-top: 0;
267
+ padding-bottom: 0;
268
+ font-size: 1.25rem;
269
+ font-weight: 500;
270
+ line-height: 1.45;
271
+ background-image: none;
272
+ }
228
273
 
229
274
  /* rubricated drop cap on the opening paragraph. The prototype's `.lead + p`
230
275
  has no stable-DOM equivalent (the frontmatter-description <p> carries only
@@ -208,30 +208,63 @@ html[data-theme-pack="matcha"] .zd-content > p[data-doc-description] {
208
208
  line-height: 1.75;
209
209
  }
210
210
 
211
- /* h2 rule: a chashaku scoop of matcha, then the line dissolves like
212
- foam. `border-image: none !important` defeats the SSR-inlined
213
- `style="border-image:linear-gradient(...)"` (Decision 6.6's sole
214
- allowlisted carve-out); the scoop itself is a 1px background
215
- gradient so no border-image fight remains. */
216
- html[data-theme-pack="matcha"] .zd-content h2 {
211
+ /* h2 rule: a chashaku scoop of matcha, then the 2px line dissolves like
212
+ foam; h3 takes a quieter 1px muted rule and h4 none. The rules are
213
+ top-anchored background gradients; `border-image: none !important`
214
+ (Decision 6.6's sole allowlisted carve-out) defeats the SSR-inlined
215
+ `style="border-image:linear-gradient(...)"`. Mincho h2 uses the bundled
216
+ 700 face; the Zen Kaku h3/h4 use the bundled 500 face rather than a
217
+ synthetic 600. */
218
+ html[data-theme-pack="matcha"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
217
219
  border-image: none !important;
218
220
  border-top-width: 0;
219
- padding-top: 1.35rem;
221
+ border-bottom-width: 0;
222
+ padding-top: 1.25rem;
223
+ padding-bottom: 0;
224
+ font-size: 2rem;
225
+ font-weight: 700;
226
+ line-height: 1.3;
220
227
  background-image: linear-gradient(
221
228
  to right,
222
229
  var(--zd-accent) 0,
223
- var(--zd-accent) 2.75rem,
224
- color-mix(in oklch, var(--zd-muted) 32%, transparent) 2.75rem,
230
+ var(--zd-accent) 5rem,
231
+ color-mix(in oklch, var(--zd-accent) 44%, transparent) 5rem,
232
+ color-mix(in oklch, var(--zd-accent) 30%, transparent) 70%,
225
233
  transparent 100%
226
234
  );
235
+ background-size: 100% 2px;
227
236
  background-repeat: no-repeat;
228
- background-size: 100% 1px;
237
+ background-position: top left;
229
238
  }
230
-
231
- /* h3: quiet, slightly tracked (weight 600 rides --zdc-doc-h3-weight) */
232
239
  html[data-theme-pack="matcha"] .zd-content h3:where(:not(.zd-compact-prose *)) {
233
- border-top-width: 1px;
240
+ border-image: none !important;
241
+ border-top-width: 0;
242
+ border-bottom-width: 0;
243
+ padding-top: 0.875rem;
244
+ padding-bottom: 0;
245
+ font-size: 1.375rem;
246
+ font-weight: 500;
247
+ line-height: 1.4;
248
+ background-image: linear-gradient(
249
+ to right,
250
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
251
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
252
+ transparent 76%
253
+ );
254
+ background-size: 100% 1px;
255
+ background-repeat: no-repeat;
256
+ background-position: top left;
234
257
  }
258
+ html[data-theme-pack="matcha"] .zd-content h4:where(:not(.zd-compact-prose *)) {
259
+ border-width: 0;
260
+ padding-top: 0;
261
+ padding-bottom: 0;
262
+ font-size: 1.2rem;
263
+ font-weight: 500;
264
+ line-height: 1.45;
265
+ background-image: none;
266
+ }
267
+
235
268
  html[data-theme-pack="matcha"] .zd-content h3 {
236
269
  letter-spacing: 0.01em;
237
270
  }
@@ -322,25 +322,61 @@ html[data-theme-pack="nocturne"] .zd-content > p[data-doc-description] {
322
322
  color: color-mix(in oklch, var(--zd-fg) 62%, var(--zd-muted));
323
323
  }
324
324
 
325
- /* h2: gold fading rule. The SSR-inlined
326
- `style="border-image:linear-gradient(...)"` bar is defeated with
327
- border-image none !important (Decision 6.6's sole allowlisted
328
- carve-out) + a zeroed border-top; the fading gold hairline is then
329
- painted as a 1px top-anchored background gradient instead. */
330
- html[data-theme-pack="nocturne"] .zd-content h2 {
325
+ /* h2: the original gold fading rule, now 2px and kept distinct from the
326
+ lavender link ink; h3 takes a quieter 1px muted rule and h4 none. The
327
+ SSR-inlined `style="border-image:linear-gradient(...)"` bar is
328
+ defeated with border-image none !important (Decision 6.6's sole
329
+ allowlisted carve-out) + zeroed borders; each rule is a top-anchored
330
+ background gradient instead. */
331
+ html[data-theme-pack="nocturne"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
331
332
  border-image: none !important;
332
333
  border-top-width: 0;
333
- font-size: 1.9rem;
334
+ border-bottom-width: 0;
335
+ padding-top: 1.25rem;
336
+ padding-bottom: 0;
337
+ font-size: 2.125rem;
338
+ font-weight: 700;
339
+ line-height: 1.3;
334
340
  background-image: linear-gradient(
335
341
  to right,
336
- light-dark(oklch(0.53 0.105 85), oklch(0.78 0.105 87)),
337
- light-dark(oklch(0.53 0.105 85 / 0.3), oklch(0.78 0.105 87 / 0.3)) 60%,
338
- transparent
342
+ light-dark(oklch(0.53 0.105 85), oklch(0.78 0.105 87)) 0%,
343
+ light-dark(oklch(0.53 0.105 85), oklch(0.78 0.105 87)) 32%,
344
+ color-mix(in oklch, light-dark(oklch(0.53 0.105 85), oklch(0.78 0.105 87)) 58%, transparent) 72%,
345
+ transparent 100%
346
+ );
347
+ background-size: 100% 2px;
348
+ background-repeat: no-repeat;
349
+ background-position: top left;
350
+ }
351
+ html[data-theme-pack="nocturne"] .zd-content h3:where(:not(.zd-compact-prose *)) {
352
+ border-image: none !important;
353
+ border-top-width: 0;
354
+ border-bottom-width: 0;
355
+ padding-top: 0.875rem;
356
+ padding-bottom: 0;
357
+ font-size: 1.375rem;
358
+ font-weight: 600;
359
+ line-height: 1.4;
360
+ background-image: linear-gradient(
361
+ to right,
362
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
363
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
364
+ transparent 76%
339
365
  );
340
366
  background-size: 100% 1px;
341
367
  background-repeat: no-repeat;
342
368
  background-position: top left;
343
369
  }
370
+ html[data-theme-pack="nocturne"] .zd-content h4:where(:not(.zd-compact-prose *)) {
371
+ border-width: 0;
372
+ padding-top: 0;
373
+ padding-bottom: 0;
374
+ font-size: 1.2rem;
375
+ font-weight: 500;
376
+ line-height: 1.45;
377
+ background-image: none;
378
+ }
379
+
344
380
  html[data-theme-pack="nocturne"] .zd-content h3 {
345
381
  letter-spacing: 0.01em;
346
382
  }
@@ -416,47 +416,84 @@ html[data-theme-pack="observatory"] .zd-content > p[data-doc-description] {
416
416
  font-weight: 300;
417
417
  }
418
418
 
419
- /* h2 — chart-label caps over a constellation line with star nodes.
420
- The SSR-inlined `style="border-image:linear-gradient(...)"` bar is
421
- defeated with border-image none !important (Decision 6.6's sole
422
- allowlisted carve-out) + a zeroed border-top; the node-to-line rule
423
- is then painted as a top-anchored background gradient, with the two
424
- glowing star nodes as pseudo-element dots. */
419
+ /* h2 — chart-label caps over a 2px constellation line with star nodes;
420
+ h3 — a quieter 1px muted rule; h4 — no rule. The SSR-inlined
421
+ `style="border-image:linear-gradient(...)"` bar is defeated with
422
+ border-image none !important (Decision 6.6's sole allowlisted
423
+ carve-out) + zeroed borders; each rule is a top-anchored background
424
+ gradient, with the two glowing star nodes as pseudo-element dots
425
+ centred on the h2 line. */
426
+ html[data-theme-pack="observatory"] .zd-content h2 {
427
+ position: relative;
428
+ text-transform: uppercase;
429
+ }
425
430
  html[data-theme-pack="observatory"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
426
- font-size: 1.75rem;
431
+ border-image: none !important;
432
+ border-top-width: 0;
433
+ border-bottom-width: 0;
434
+ padding-top: 1.25rem;
435
+ padding-bottom: 0;
436
+ font-size: 1.875rem;
437
+ font-weight: 500;
438
+ line-height: 1.3;
439
+ letter-spacing: 0.065em;
440
+ background-image: linear-gradient(
441
+ to right,
442
+ light-dark(oklch(0.5 0.105 78), oklch(0.87 0.13 88)) 0%,
443
+ light-dark(oklch(0.5 0.105 78), oklch(0.87 0.13 88)) 32%,
444
+ color-mix(in oklch, light-dark(oklch(0.5 0.105 78), oklch(0.87 0.13 88)) 58%, transparent) 72%,
445
+ transparent 100%
446
+ );
447
+ background-size: 100% 2px;
448
+ background-repeat: no-repeat;
449
+ background-position: top left;
427
450
  }
428
- html[data-theme-pack="observatory"] .zd-content h2 {
451
+ html[data-theme-pack="observatory"] .zd-content h3:where(:not(.zd-compact-prose *)) {
429
452
  border-image: none !important;
430
453
  border-top-width: 0;
431
- position: relative;
432
- text-transform: uppercase;
454
+ border-bottom-width: 0;
455
+ padding-top: 0.875rem;
456
+ padding-bottom: 0;
457
+ font-size: 1.375rem;
458
+ font-weight: 400;
459
+ line-height: 1.4;
433
460
  background-image: linear-gradient(
434
461
  to right,
435
- light-dark(oklch(0.5 0.105 78), oklch(0.87 0.13 88)),
436
- light-dark(oklch(0.33 0.05 268 / 0.4), oklch(0.86 0.05 265 / 0.34)) 45%,
437
- transparent 85%
462
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
463
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
464
+ transparent 76%
438
465
  );
439
466
  background-size: 100% 1px;
440
467
  background-repeat: no-repeat;
441
468
  background-position: top left;
442
469
  }
443
- html[data-theme-pack="observatory"] .zd-content h2::before,
444
- html[data-theme-pack="observatory"] .zd-content h2::after {
470
+ html[data-theme-pack="observatory"] .zd-content h4:where(:not(.zd-compact-prose *)) {
471
+ border-width: 0;
472
+ padding-top: 0;
473
+ padding-bottom: 0;
474
+ font-size: 1.2rem;
475
+ font-weight: 500;
476
+ line-height: 1.45;
477
+ background-image: none;
478
+ }
479
+
480
+ html[data-theme-pack="observatory"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *))::before,
481
+ html[data-theme-pack="observatory"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *))::after {
445
482
  content: "";
446
483
  position: absolute;
447
484
  border-radius: 50%;
448
485
  background: light-dark(oklch(0.5 0.105 78), oklch(0.87 0.13 88));
449
486
  box-shadow: 0 0 6px light-dark(oklch(0.52 0.11 80 / 0.35), oklch(0.86 0.13 88 / 0.55));
450
487
  }
451
- html[data-theme-pack="observatory"] .zd-content h2::before {
452
- top: -3px;
488
+ html[data-theme-pack="observatory"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *))::before {
489
+ top: -1.5px;
453
490
  left: 0;
454
491
  width: 5px;
455
492
  height: 5px;
456
493
  }
457
- html[data-theme-pack="observatory"] .zd-content h2::after {
458
- top: -2.5px;
459
- left: 38%;
494
+ html[data-theme-pack="observatory"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *))::after {
495
+ top: -1px;
496
+ left: 58%;
460
497
  width: 4px;
461
498
  height: 4px;
462
499
  opacity: 0.85;
@@ -474,6 +511,10 @@ html[data-theme-pack="observatory"] .zd-content h3::before {
474
511
  font-size: 0.75em;
475
512
  vertical-align: 0.12em;
476
513
  }
514
+ html[data-theme-pack="observatory"] .zd-content h3:where(:not(.zd-compact-prose *))::before {
515
+ font-size: 0.65em;
516
+ opacity: 0.65;
517
+ }
477
518
 
478
519
  /* links — gilt underlines */
479
520
  html[data-theme-pack="observatory"] .zd-content a {
@@ -57,7 +57,7 @@
57
57
  }
58
58
 
59
59
  /* ---- Shippori Mincho — display serif for the title, h2 and the
60
- wordmark (static 600 heading weight + 700 logo weight).
60
+ wordmark (static 600 title weight + 700 h2/logo weight).
61
61
  Latin subsets only; the bare serif generic supplies CJK. ---- */
62
62
 
63
63
  @font-face {
@@ -280,22 +280,59 @@ html[data-theme-pack="sakura"] a[data-nav-active] {
280
280
  );
281
281
  }
282
282
 
283
- /* signature move #2 — the h2 petal rule: a rose stroke that loosens
284
- into drifting transparency. Re-points the SSR-inlined
285
- `style="border-image:linear-gradient(...)"` gradient — the
286
- border-image !important carve-out (Decision 6.6). */
283
+ /* signature move #2 — the h2 petal rule: a 2px rose stroke that loosens
284
+ into drifting transparency; h3 takes a quieter 1px muted rule and h4
285
+ none. The rules are top-anchored background gradients; border-image
286
+ none !important (the Decision 6.6 carve-out) keeps the SSR-inlined
287
+ `style="border-image:linear-gradient(...)"` from painting a second
288
+ bar. */
287
289
  html[data-theme-pack="sakura"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
288
- font-size: 1.6rem;
289
- }
290
- html[data-theme-pack="sakura"] .zd-content h2 {
291
- border-top-width: 2px;
292
- border-image: linear-gradient(
293
- to right,
294
- var(--zd-accent) 0 2.5rem,
295
- color-mix(in srgb, var(--zd-accent) 30%, transparent) 55%,
296
- transparent
297
- )
298
- 1 !important;
290
+ border-image: none !important;
291
+ border-top-width: 0;
292
+ border-bottom-width: 0;
293
+ padding-top: 1.25rem;
294
+ padding-bottom: 0;
295
+ font-size: 2rem;
296
+ font-weight: 700;
297
+ line-height: 1.3;
298
+ background-image: linear-gradient(
299
+ to right,
300
+ var(--zd-accent) 0,
301
+ var(--zd-accent) 4rem,
302
+ color-mix(in oklch, var(--zd-accent) 68%, transparent) 62%,
303
+ transparent 100%
304
+ );
305
+ background-size: 100% 2px;
306
+ background-repeat: no-repeat;
307
+ background-position: top left;
308
+ }
309
+ html[data-theme-pack="sakura"] .zd-content h3:where(:not(.zd-compact-prose *)) {
310
+ border-image: none !important;
311
+ border-top-width: 0;
312
+ border-bottom-width: 0;
313
+ padding-top: 0.875rem;
314
+ padding-bottom: 0;
315
+ font-size: 1.375rem;
316
+ font-weight: 600;
317
+ line-height: 1.4;
318
+ background-image: linear-gradient(
319
+ to right,
320
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
321
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
322
+ transparent 76%
323
+ );
324
+ background-size: 100% 1px;
325
+ background-repeat: no-repeat;
326
+ background-position: top left;
327
+ }
328
+ html[data-theme-pack="sakura"] .zd-content h4:where(:not(.zd-compact-prose *)) {
329
+ border-width: 0;
330
+ padding-top: 0;
331
+ padding-bottom: 0;
332
+ font-size: 1.2rem;
333
+ font-weight: 500;
334
+ line-height: 1.45;
335
+ background-image: none;
299
336
  }
300
337
 
301
338
  /* h3 — a round blossom bud before the heading */
@@ -309,6 +346,11 @@ html[data-theme-pack="sakura"] .zd-content h3::before {
309
346
  margin-right: 0.5em;
310
347
  vertical-align: 0.12em;
311
348
  }
349
+ html[data-theme-pack="sakura"] .zd-content h3:where(:not(.zd-compact-prose *))::before {
350
+ width: 0.3em;
351
+ height: 0.3em;
352
+ opacity: 0.7;
353
+ }
312
354
 
313
355
  /* the lead — airy, one breath rosier than body ink (10.9:1+) */
314
356
  html[data-theme-pack="sakura"] .zd-content > p[data-doc-description] {
@@ -211,26 +211,59 @@ html[data-theme-pack="solar"] main nav[aria-label="Breadcrumb"] li > span {
211
211
  }
212
212
 
213
213
  /* h2 rule: a precise 2px blue→cyan fade instead of the default fg
214
- gradient. The SSR-inlined `style="border-image:linear-gradient(...)"`
215
- bar is defeated with border-image none !important (Decision 6.6's
216
- sole allowlisted carve-out) + a zeroed border-top; the fade is then
217
- painted as a 2px top-anchored background gradient. */
214
+ gradient; h3 takes a quieter 1px muted rule and h4 none. The
215
+ SSR-inlined `style="border-image:linear-gradient(...)"` bar is
216
+ defeated with border-image none !important (Decision 6.6's sole
217
+ allowlisted carve-out) + zeroed borders; each rule is painted as a
218
+ top-anchored background gradient. */
218
219
  html[data-theme-pack="solar"] .zd-content h2:where(:not(.zd-home-heading)):where(:not(.zd-compact-prose *)) {
219
- font-size: 1.5rem;
220
- }
221
- html[data-theme-pack="solar"] .zd-content h2 {
222
220
  border-image: none !important;
223
221
  border-top-width: 0;
222
+ border-bottom-width: 0;
223
+ padding-top: 1.25rem;
224
+ padding-bottom: 0;
225
+ font-size: 1.75rem;
226
+ font-weight: 700;
227
+ line-height: 1.3;
224
228
  background-image: linear-gradient(
225
229
  to right,
226
- var(--zd-accent),
227
- var(--zd-accent-hover) 45%,
228
- transparent 88%
230
+ var(--zd-accent) 0%,
231
+ var(--zd-accent) 24%,
232
+ var(--zd-accent-hover) 65%,
233
+ transparent 100%
229
234
  );
230
235
  background-size: 100% 2px;
231
236
  background-repeat: no-repeat;
232
237
  background-position: top left;
233
238
  }
239
+ html[data-theme-pack="solar"] .zd-content h3:where(:not(.zd-compact-prose *)) {
240
+ border-image: none !important;
241
+ border-top-width: 0;
242
+ border-bottom-width: 0;
243
+ padding-top: 0.875rem;
244
+ padding-bottom: 0;
245
+ font-size: 1.375rem;
246
+ font-weight: 600;
247
+ line-height: 1.4;
248
+ background-image: linear-gradient(
249
+ to right,
250
+ color-mix(in oklch, var(--zd-muted) 42%, transparent),
251
+ color-mix(in oklch, var(--zd-muted) 22%, transparent) 40%,
252
+ transparent 76%
253
+ );
254
+ background-size: 100% 1px;
255
+ background-repeat: no-repeat;
256
+ background-position: top left;
257
+ }
258
+ html[data-theme-pack="solar"] .zd-content h4:where(:not(.zd-compact-prose *)) {
259
+ border-width: 0;
260
+ padding-top: 0;
261
+ padding-bottom: 0;
262
+ font-size: 1.2rem;
263
+ font-weight: 500;
264
+ line-height: 1.45;
265
+ background-image: none;
266
+ }
234
267
 
235
268
  /* prose links: quiet underline that sharpens to cyan on hover */
236
269
  html[data-theme-pack="solar"] .zd-content a {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "8.1.1",
3
+ "version": "8.1.3",
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",
@@ -22,8 +22,9 @@
22
22
  "documentation",
23
23
  "framework",
24
24
  "mdx",
25
- "preact",
26
- "zfb"
25
+ "zfb",
26
+ "zudo-react",
27
+ "zudo-wind"
27
28
  ],
28
29
  "publishConfig": {
29
30
  "access": "public",
@@ -752,9 +753,9 @@
752
753
  "peerDependencies": {
753
754
  "@modelcontextprotocol/sdk": "1.32.2",
754
755
  "@takazudo/zdtp": "^0.5.2 || ^0.6.0 || ^0.7.0 || ^0.8.0",
755
- "@takazudo/zfb": "^5.1.3",
756
- "@takazudo/zfb-md-wasm": "^5.1.3",
757
- "@takazudo/zfb-runtime": "^5.1.3",
756
+ "@takazudo/zfb": "^5.1.4",
757
+ "@takazudo/zfb-md-wasm": "^5.1.4",
758
+ "@takazudo/zfb-runtime": "^5.1.4",
758
759
  "@takazudo/zudo-doc-history-server": "^8.0.0",
759
760
  "diff": "^8.0.0",
760
761
  "katex": "^0.18.2 || ^0.19.0",
@@ -795,9 +796,9 @@
795
796
  "devDependencies": {
796
797
  "@modelcontextprotocol/sdk": "1.32.2",
797
798
  "@takazudo/mdx-formatter": "1.3.0",
798
- "@takazudo/zfb": "5.1.3",
799
- "@takazudo/zfb-md-wasm": "5.1.3",
800
- "@takazudo/zfb-runtime": "5.1.3",
799
+ "@takazudo/zfb": "5.1.4",
800
+ "@takazudo/zfb-md-wasm": "5.1.4",
801
+ "@takazudo/zfb-runtime": "5.1.4",
801
802
  "@types/fs-extra": "^11.0.4",
802
803
  "@types/minimist": "^1.2.5",
803
804
  "@types/node": "^25.3.5",
@@ -807,7 +808,7 @@
807
808
  "typescript": "^5.0.0",
808
809
  "vitest": "^4.1.0",
809
810
  "zod": "^4.3.6",
810
- "@takazudo/zudo-doc-history-server": "8.1.1"
811
+ "@takazudo/zudo-doc-history-server": "8.1.3"
811
812
  },
812
813
  "scripts": {
813
814
  "gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",