@faqir-ui/core 1.0.0 → 1.1.1

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 (41) hide show
  1. package/README.md +45 -5
  2. package/cdn.json +38 -22
  3. package/dist/faqir-core.js +121 -57
  4. package/dist/faqir-core.min.js +3 -3
  5. package/dist/faqir-core.min.js.map +3 -3
  6. package/dist/faqir-core.mjs +75 -59
  7. package/dist/faqir.aurora.css +1209 -507
  8. package/dist/faqir.brutalist.css +1184 -489
  9. package/dist/faqir.candy.css +14152 -0
  10. package/dist/faqir.clinical.css +14152 -0
  11. package/dist/faqir.contrast.css +1198 -526
  12. package/dist/faqir.default.css +1261 -588
  13. package/dist/faqir.document-serif.css +1211 -491
  14. package/dist/faqir.document.css +1193 -490
  15. package/dist/faqir.editorial-document.css +14116 -0
  16. package/dist/faqir.editorial.css +14152 -0
  17. package/dist/faqir.fintech.css +14152 -0
  18. package/dist/faqir.glass.css +1214 -517
  19. package/dist/faqir.ink-document.css +14116 -0
  20. package/dist/faqir.ink.css +14127 -0
  21. package/dist/faqir.luxe.css +14211 -0
  22. package/dist/faqir.midnight.css +1229 -507
  23. package/dist/faqir.neo.css +14153 -0
  24. package/dist/faqir.neumorph.css +14151 -0
  25. package/dist/faqir.nordic.css +14151 -0
  26. package/dist/faqir.organic.css +14152 -0
  27. package/dist/faqir.paper.css +1200 -508
  28. package/dist/faqir.slate.css +1296 -564
  29. package/dist/faqir.soft.css +1180 -494
  30. package/dist/faqir.sunset.css +14153 -0
  31. package/dist/faqir.swiss-document.css +14116 -0
  32. package/dist/faqir.swiss.css +14153 -0
  33. package/dist/faqir.terminal.css +1187 -491
  34. package/dist/plugins/faqir-collapse.js +1 -1
  35. package/dist/plugins/faqir-intersect.js +2 -0
  36. package/dist/plugins/faqir-mask.js +27 -17
  37. package/dist/plugins/faqir-rules.js +63 -0
  38. package/dist/plugins/faqir-validate.js +471 -58
  39. package/dist/sri.json +36 -20
  40. package/faqir-core.d.ts +119 -6
  41. package/package.json +1 -1
@@ -131,6 +131,18 @@
131
131
  --font-mono: ui-monospace, 'Cascadia Code', 'JetBrains Mono', monospace;
132
132
  --font-serif: 'Georgia', 'Times New Roman', serif;
133
133
 
134
+ /* ── Font Roles (task 1.1A-01) ──
135
+ The three families above are the PALETTE; these three are the ROLES that
136
+ components actually read. A theme re-points a role once and every heading,
137
+ every paragraph and every control follows — "serif headings on a sans body"
138
+ is one declaration rather than sixty-four stylesheet edits. Components never
139
+ read --font-sans / --font-serif directly (gated by
140
+ tests/tokens/role-tokens.test.ts); --font-mono stays readable by name,
141
+ because "this is code" is a semantic choice, not a stylistic one. */
142
+ --font-heading: var(--font-sans); /* h1–h6, hero headline, card/dialog titles, stat values, doc headings */
143
+ --font-body: var(--font-sans); /* prose, text, document body, descriptions */
144
+ --font-ui: var(--font-sans); /* controls: button, input, select, badge, chip, tabs, menus */
145
+
134
146
  /* ── Font Sizes ── */
135
147
  --text-xs: 0.75rem; /* 12px */
136
148
  --text-sm: 0.875rem; /* 14px */
@@ -153,10 +165,29 @@
153
165
  --weight-medium: 500;
154
166
  --weight-semibold: 600;
155
167
  --weight-bold: 700;
168
+
169
+ /* ── Heading Voice (task 1.1A-01) ──
170
+ What makes a heading sound like the theme rather than like the body text one
171
+ size up: how heavy it is, how tightly the letters sit, whether it shouts, and
172
+ how close its own lines run. The defaults reproduce today's primary heading
173
+ exactly, so a project that sets none of them renders unchanged. A heading
174
+ that deliberately steps DOWN from the primary voice (prose h2–h4, a semibold
175
+ step below h1) keeps its own weight and leading and takes family, tracking
176
+ and case from the voice — the step is the design, not a value to re-derive. */
177
+ --heading-weight: var(--weight-bold);
178
+ --heading-tracking: 0em; /* letter-spacing — carries a unit so it
179
+ composes inside calc() where a heading
180
+ already has its own optical tightening */
181
+ --heading-transform: none; /* text-transform */
182
+ --heading-caps: normal; /* font-variant-caps — small caps are a
183
+ variant, not a transform (1.1A-25), so
184
+ they get a knob of their own that sits
185
+ beside --heading-transform */
186
+ --heading-leading: var(--leading-tight);
156
187
  }
157
188
 
158
189
  /* === tokens/effects.css === */
159
- /* @ui:tokens effects — radii, shadows, z-index */
190
+ /* @ui:tokens effects — radii, shape, shadows, focus, z-index */
160
191
 
161
192
  :root {
162
193
  /* ── Radii ── */
@@ -168,12 +199,49 @@
168
199
  --radius-2xl: 1rem; /* 16px */
169
200
  --radius-full: 9999px;
170
201
 
171
- /* ── Shadows ── */
172
- --shadow-xs: 0 1px 2px oklch(0 0 0 / 0.04);
173
- --shadow-sm: 0 1px 3px oklch(0 0 0 / 0.06), 0 1px 2px oklch(0 0 0 / 0.04);
174
- --shadow-md: 0 4px 6px oklch(0 0 0 / 0.05), 0 2px 4px oklch(0 0 0 / 0.04);
175
- --shadow-lg: 0 10px 15px oklch(0 0 0 / 0.06), 0 4px 6px oklch(0 0 0 / 0.04);
176
- --shadow-xl: 0 20px 25px oklch(0 0 0 / 0.08), 0 8px 10px oklch(0 0 0 / 0.04);
202
+ /* ── Shape ── */
203
+ /* The weight of an edge. A component names the ROLE (--border-width, or
204
+ --border-width-strong where the design leans on a thicker rule), never a
205
+ step, so a theme re-points every edge it ships with one declaration. */
206
+ --border-width-sm: 1px;
207
+ --border-width-md: 2px;
208
+ --border-width-lg: 3px;
209
+ --border-width: var(--border-width-sm); /* the default component border */
210
+ --border-width-strong: var(--border-width-md); /* emphasis: keycap, thick rule, active tab */
211
+ /* Progressive: CSS Borders 4. A browser without the property ignores it; a
212
+ value it does not know resolves to `round`, which is today's rendering. */
213
+ --corner-shape: round; /* bevel | scoop | notch where supported */
214
+
215
+ /* ── Depth ── */
216
+ /* The colour every shadow is cast in, as BARE OKLCH channels (L C H, no
217
+ `oklch()` around them) so each step can still set its own alpha:
218
+ `oklch(var(--shadow-color) / 0.06)`. A theme tints its depth warm, or
219
+ removes it entirely, with one declaration instead of rewriting five
220
+ multi-layer values. `0 0 0` is black — today's rendering, exactly. */
221
+ --shadow-color: 0 0 0;
222
+
223
+ --shadow-xs: 0 1px 2px oklch(var(--shadow-color) / 0.04);
224
+ --shadow-sm: 0 1px 3px oklch(var(--shadow-color) / 0.06), 0 1px 2px oklch(var(--shadow-color) / 0.04);
225
+ --shadow-md: 0 4px 6px oklch(var(--shadow-color) / 0.05), 0 2px 4px oklch(var(--shadow-color) / 0.04);
226
+ --shadow-lg: 0 10px 15px oklch(var(--shadow-color) / 0.06), 0 4px 6px oklch(var(--shadow-color) / 0.04);
227
+ --shadow-xl: 0 20px 25px oklch(var(--shadow-color) / 0.08), 0 8px 10px oklch(var(--shadow-color) / 0.04);
228
+
229
+ /* What an elevated surface does to whatever shows through it. Every surface
230
+ that can float — card, surface[data-variant="overlay"] and the seven
231
+ floating recipes — declares `backdrop-filter: var(--surface-backdrop)`
232
+ inside the same `@supports` guard, so a frosted theme is a token rather
233
+ than a stylesheet that reaches into seven components by selector.
234
+ `none` is the initial value of the property: no-op until a theme speaks. */
235
+ --surface-backdrop: none;
236
+
237
+ /* ── Focus ── */
238
+ /* base/reset.css owns the default ring and reads only these. Every control
239
+ that draws its own ring reads them too, so a theme changes focus once. */
240
+ --focus-ring-width: 2px;
241
+ --focus-ring-offset: 2px;
242
+ --focus-ring-style: solid;
243
+ --focus-ring-color: var(--color-ring);
244
+ --focus-shadow: none; /* a glow theme puts a shadow behind the ring */
177
245
 
178
246
  /* ── Z-Index ── */
179
247
  --z-base: 0;
@@ -186,8 +254,74 @@
186
254
  --z-max: 9999;
187
255
  }
188
256
 
257
+ /* ── Scheme islands ── */
258
+ /* The ring colour, restated where a scheme can change below the root: declared
259
+ on `:root` alone it resolves `--color-ring` once, from the page, and a nested
260
+ `data-theme="dark"` region would draw the light ring. See the same block in
261
+ tokens/aliases.css. `--focus-shadow` is deliberately NOT restated — it is a
262
+ depth value a theme owns, and restating it would replace the theme's glow
263
+ with `none` inside every island. */
264
+ [data-theme],
265
+ [data-skin] {
266
+ --focus-ring-color: var(--color-ring);
267
+ }
268
+
269
+ /* === tokens/textures.css === */
270
+ /* @ui:tokens textures — named surface materials (SVG data URIs) */
271
+
272
+ /* ══════════════════════════════════════════════════════════════════════════
273
+ The material palette.
274
+ ══════════════════════════════════════════════════════════════════════════
275
+ Six named textures, each a self-contained `url("data:image/svg+xml,…")` that
276
+ tiles. Nothing here is consumed directly: components read the two ROLE tokens
277
+ in `aliases.css` — `--texture-page` (body, document) and `--texture-surface`
278
+ (surface, card, hero) — both `none` by default, so the registry renders
279
+ exactly as it did before this file existed. A theme opts in with one
280
+ declaration:
281
+
282
+ --texture-page: var(--texture-grain);
283
+
284
+ This file is deliberately OUTSIDE the themeable surface (see
285
+ `NON_SURFACE_TOKEN_FILES` in `src/theme-manifest.ts`): a theme re-points the
286
+ two role tokens, it does not inherit six data URIs into its manifest.
287
+
288
+ On `currentColor`: the tint is written as `currentColor` so the markup states
289
+ its intent and a theme can re-point the whole token, but a data-URI SVG used
290
+ as `background-image` is its own document — `currentColor` there resolves to
291
+ that document's initial colour (black), not to the host element's `color`.
292
+ That IS the intended neutral for grain and paper, which are meant to darken a
293
+ surface slightly; the alpha in each texture, not the hue, is what carries the
294
+ effect. A theme wanting a different tint ships its own URI.
295
+
296
+ Every texture keeps its alpha low enough to survive on both schemes, and each
297
+ `<svg>` carries explicit `width`/`height` so the tile size is the token's,
298
+ not the browser's default 300×150.
299
+ ══════════════════════════════════════════════════════════════════════════ */
300
+
301
+ :root {
302
+ /* Film grain — fractal noise masking a flat currentColor fill. The mask is
303
+ what makes this a tint rather than the turbulence's own rainbow. */
304
+ --texture-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Cmask id='m'%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/mask%3E%3Crect width='160' height='160' fill='currentColor' mask='url(%23m)' opacity='0.14'/%3E%3C/svg%3E");
305
+
306
+ /* Paper fibre — lower frequency, more octaves, softer than grain. */
307
+ --texture-paper: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.04 0.85' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Cmask id='m'%3E%3Crect width='200' height='200' filter='url(%23p)'/%3E%3C/mask%3E%3Crect width='200' height='200' fill='currentColor' mask='url(%23m)' opacity='0.1'/%3E%3C/svg%3E");
308
+
309
+ /* Dot field — one dot per 16px cell. */
310
+ --texture-dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Ccircle cx='2' cy='2' r='1' fill='currentColor' opacity='0.18'/%3E%3C/svg%3E");
311
+
312
+ /* Graph-paper grid — hairlines on a 24px cell. */
313
+ --texture-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M24 0H0v24' fill='none' stroke='currentColor' stroke-width='1' opacity='0.12'/%3E%3C/svg%3E");
314
+
315
+ /* Diagonal hatching — 45°, 8px pitch. */
316
+ --texture-stripes: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M-2 2 2-2M0 8 8 0M6 10l4-4' stroke='currentColor' stroke-width='1' opacity='0.12'/%3E%3C/svg%3E");
317
+
318
+ /* Soft gradient mesh — three offset radial blooms, the only non-tiling
319
+ texture here (it is sized to cover, not to repeat). */
320
+ --texture-mesh: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='640' height='640'%3E%3CradialGradient id='a' cx='20%25' cy='20%25' r='60%25'%3E%3Cstop offset='0%25' stop-color='currentColor' stop-opacity='0.18'/%3E%3Cstop offset='100%25' stop-color='currentColor' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='b' cx='80%25' cy='30%25' r='55%25'%3E%3Cstop offset='0%25' stop-color='currentColor' stop-opacity='0.14'/%3E%3Cstop offset='100%25' stop-color='currentColor' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='c' cx='50%25' cy='90%25' r='60%25'%3E%3Cstop offset='0%25' stop-color='currentColor' stop-opacity='0.12'/%3E%3Cstop offset='100%25' stop-color='currentColor' stop-opacity='0'/%3E%3C/radialGradient%3E%3Crect width='640' height='640' fill='url(%23a)'/%3E%3Crect width='640' height='640' fill='url(%23b)'/%3E%3Crect width='640' height='640' fill='url(%23c)'/%3E%3C/svg%3E");
321
+ }
322
+
189
323
  /* === tokens/motion.css === */
190
- /* @ui:tokens motion — easings and durations */
324
+ /* @ui:tokens motion — easings, durations and motion personality */
191
325
 
192
326
  :root {
193
327
  /* ── Easings ── */
@@ -216,6 +350,35 @@
216
350
  /* Preset geometry */
217
351
  --motion-slide-distance: 0.5rem; /* slide-up travel */
218
352
  --motion-scale-from: 0.95; /* scale start/end factor */
353
+
354
+ /* ── Personality (1.1A-05 · §5.2 `motion`) ── */
355
+ /* The easing PALETTE gained a spring. Like --ease-bounce it has no consumer
356
+ of its own: a theme that wants everything to overshoot re-points
357
+ --ease-default at it, exactly as a serif theme re-points --font-body.
358
+ The declaration here is the cubic-bezier APPROXIMATION, because a custom
359
+ property stores whatever tokens it is given — a browser without `linear()`
360
+ would accept the spring happily and then drop every `transition` that used
361
+ it, landing on the initial easing rather than on a fallback. The @supports
362
+ block below is what makes the upgrade conditional. The approximation is
363
+ the bounce curve, deliberately: an overshoot-and-settle cubic-bezier is the
364
+ closest a browser without `linear()` can come to a spring. */
365
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
366
+
367
+ /* How far an interactive surface rises under the pointer. A `translate`
368
+ VALUE, not a length: `none` is the initial value of that property, so the
369
+ default registry computes exactly what it computed before this token
370
+ existed, and a theme states the lift as `0 -1px`. `translate` rather than
371
+ `transform` so a component's own transform is never clobbered. */
372
+ --motion-hover-lift: none;
373
+ }
374
+
375
+ /* The real spring, where `linear()` is understood (Chrome 113+, Safari 17.2+,
376
+ Firefox 112+). Declared second so it wins; guarded so it is never declared at
377
+ all where it would be meaningless. */
378
+ @supports (animation-timing-function: linear(0, 1)) {
379
+ :root {
380
+ --ease-spring: linear(0, 0.3 6%, 0.7 13%, 0.95 20%, 1.03 27%, 1 40%, 1);
381
+ }
219
382
  }
220
383
 
221
384
  /* === tokens/semantic.css === */
@@ -307,27 +470,123 @@
307
470
  --section-gap-lg: var(--space-32); /* 8rem — spacious, one idea per screen */
308
471
  --content-gutter: var(--space-6); /* 1.5rem — page padding-inline */
309
472
 
473
+ /* ── Material ── */
474
+ /* The two textures a theme actually points at. Components never name a
475
+ texture from `tokens/textures.css` directly — they read one of these, so a
476
+ theme re-points two tokens rather than every surface in the registry.
477
+ `--texture-page` dresses the page itself (body, document);
478
+ `--texture-surface` dresses the things that sit ON it (surface, card,
479
+ hero). Both `none`: the initial value of `background-image`, so the
480
+ default registry renders exactly as it did before they existed. */
481
+ --texture-page: none;
482
+ --texture-surface: none;
483
+
484
+ /* ── Decoration (1.1A-05 · §5.2 `decoration`) ── */
485
+ /* The marks a theme draws that are not edges, fills or type: how a link is
486
+ underlined, how a divider is dashed, what selected text looks like, what
487
+ colour a list bullet is. Every default is the value the registry already
488
+ rendered, so this section is a set of handles, not a restyle.
489
+ `--marker-color` is `currentColor` — the initial value of `::marker`'s
490
+ colour — rather than the accent, so a list only changes when a theme says
491
+ it should. */
492
+ --link-decoration: underline;
493
+ --link-underline-offset: 0.2em;
494
+ --link-thickness: 1px;
495
+ --divider-style: solid;
496
+ /* The divider's own width, following the edge by default (1.1A-26). A theme
497
+ that asks for a `double` divider raises it to at least 3px: a double rule
498
+ only splits into two lines from 3px, and the family's 1px hairline would
499
+ paint it as one. */
500
+ --divider-width: var(--border-width);
501
+ /* The zebra, so a theme dials the stripe without restating the four selectors
502
+ the table's striped variant needs (stamped and nth-child, each with a hover
503
+ twin). Deliberately NOT `--table-stripe`: `--table-level`,
504
+ `--table-thead-h` and `--table-pin-offset` are stamped and MEASURED per
505
+ element by the table controller, so claiming the `--table-*` namespace for
506
+ a theme token would put runtime state on the themeable surface. */
507
+ --stripe-bg: var(--color-bg-subtle);
508
+ --selection-bg: var(--color-primary-subtle);
509
+ --selection-fg: var(--color-fg);
510
+ --marker-color: currentColor;
511
+ /* How far a disabled control is dimmed. Seventeen rules across the primitives
512
+ and recipes each spelled `opacity: 0.5`, which left a theme with an opinion
513
+ about disabled legibility no way to state it except by out-specifying every
514
+ one of them — which is exactly what `themes/contrast.css` did, with a
515
+ blanket `:root [data-ui]:disabled` rule, until 1.1A-15 turned it into this
516
+ one declaration. `0.5` is the value those seventeen rules already held. */
517
+ --disabled-opacity: 0.5;
518
+
310
519
  /* ── Button ── */
311
520
  --button-radius: var(--radius-md);
312
521
  --button-height-sm: var(--control-height-sm);
313
522
  --button-height-md: var(--control-height-md);
314
523
  --button-height-lg: var(--control-height-lg);
315
- --button-font: var(--font-sans);
524
+ --button-font: var(--font-ui);
316
525
  --button-weight: var(--weight-medium);
526
+ --button-text-transform: none;
317
527
 
318
528
  /* ── Card ── */
319
529
  --card-radius: var(--radius-lg);
320
530
  --card-shadow: var(--shadow-sm);
321
531
  --card-border: var(--color-surface-1-border);
532
+ --card-border-width: var(--border-width);
322
533
  --card-bg: var(--color-surface-1);
323
534
  --card-padding: var(--space-6);
324
535
 
325
536
  /* ── Input ── */
326
- --input-radius: var(--radius-md);
327
- --input-height: var(--control-height-md);
328
- --input-border: var(--color-border);
329
- --input-bg: var(--color-bg);
330
- --input-font: var(--font-sans);
537
+ /* The text-control silhouette. `--input-border-width` (1.1A-02) is the edge;
538
+ `--input-fill` is what the control paints, and `input`, `textarea` and
539
+ `select` all read it, so one declaration fills every text control.
540
+ `--input-fill` defaults to `--input-bg`, so a project that sets `--input-bg`
541
+ on `:root` — the 1.0 way to fill every input — still gets it. Set BELOW the
542
+ root, `--input-bg` no longer reaches the control: `--input-fill` has already
543
+ resolved it on `:root`, which is where a theme flips the fill, and a
544
+ per-element `--input-bg` winning over that would need the component to tell
545
+ "set here" from "inherited", which CSS cannot. To fill one input, or every
546
+ input in a region, set `--input-fill` there instead. `--input-bg-filled` is
547
+ the value a "filled" theme points `--input-fill` at — named here so the
548
+ silhouette is a token a theme flips rather than a colour it has to pick. */
549
+ --input-radius: var(--radius-md);
550
+ --input-height: var(--control-height-md);
551
+ --input-border: var(--color-border);
552
+ --input-border-width: var(--border-width);
553
+ --input-bg: var(--color-bg);
554
+ --input-bg-filled: var(--color-bg-subtle);
555
+ --input-fill: var(--input-bg);
556
+ --input-font: var(--font-ui);
557
+
558
+ /* ── Checkbox / Switch ── */
559
+ /* The two control shapes that do not follow `--radius-md`: a checkbox is a
560
+ small square with a small radius, a switch is a pill. Both were literal
561
+ `var(--radius-*)` reads in the components; named here, a theme squares its
562
+ switches without touching the radius ladder every other surface uses.
563
+
564
+ The geometry beside them is not decoration — it is the rest of the
565
+ namespace. Naming ONE token `--checkbox-radius` makes `--checkbox-*` a
566
+ token family, and the registry audit then (rightly) reads every other
567
+ `--checkbox-…`/`--switch-…` the components carried as a token wearing a
568
+ fallback as a disguise. They were always the default geometry; these are
569
+ the values the fallbacks already held, said once. */
570
+ --checkbox-size: 18px;
571
+ --checkbox-radius: var(--radius-sm);
572
+ --switch-width: 44px;
573
+ --switch-height: 24px;
574
+ --switch-thumb: 18px;
575
+ --switch-travel: 20px;
576
+ --switch-radius: var(--radius-full);
577
+ --switch-bg: var(--color-bg-muted);
578
+ --switch-thumb-shadow: var(--shadow-xs);
579
+
580
+ /* ── Floating panels ── */
581
+ /* What a panel that floats above the page is filled with: the dialog and
582
+ sheet panels, the drawer, the popover content (and its arrow), the dropdown
583
+ menu and the toast. They all painted `var(--color-bg)` directly, which left
584
+ a theme no way to make a floating surface differ from the page — the frost
585
+ half of that pairing is `--surface-backdrop` (1.1A-04), and a blur behind an
586
+ opaque fill renders nothing, so the fill has to be a token too. `card` has
587
+ had `--card-bg` since 1.0; this is the same handle for the things that have
588
+ no surface of their own. [1.1A-14] */
589
+ --panel-bg: var(--color-bg);
331
590
 
332
591
  /* ── Dialog ── */
333
592
  --dialog-radius: var(--radius-xl);
@@ -336,7 +595,7 @@
336
595
 
337
596
  /* ── Badge ── */
338
597
  --badge-radius: var(--radius-full);
339
- --badge-font: var(--font-sans);
598
+ --badge-font: var(--font-ui);
340
599
 
341
600
  /* ── Avatar ── */
342
601
  --avatar-radius: var(--radius-full);
@@ -345,6 +604,39 @@
345
604
  --avatar-size-lg: 56px;
346
605
  }
347
606
 
607
+ /* ── Scheme islands ── */
608
+ /* The colour aliases above, restated wherever a scheme can change below the
609
+ root. A custom property resolves its var() on the element that DECLARES it,
610
+ so `--panel-bg: var(--color-bg)` on `:root` is computed once, from the page's
611
+ colours, and a nested `<div data-theme="dark">` inherits that light value
612
+ even though its own `--color-bg` is dark — a white dialog on a dark island.
613
+ Components that read `var(--color-bg)` directly never had the problem; the
614
+ aliases 1.1 routed them through did. Restating the declaration on
615
+ `[data-theme]` and `[data-skin]` makes it resolve again there.
616
+
617
+ Only colours are restated. Geometry does not change with the scheme, and
618
+ shadows are the depth axis every theme owns on `:root`: restating either here
619
+ would replace a theme's own value with the default inside every island. A
620
+ theme that overrides one of THESE on `:root` and wants it honoured in an
621
+ island says so on the same selectors.
622
+
623
+ The values must match the `:root` declarations above exactly;
624
+ `tests/tokens/scheme-islands.test.ts` fails if they drift. */
625
+ [data-theme],
626
+ [data-skin] {
627
+ --stripe-bg: var(--color-bg-subtle);
628
+ --selection-bg: var(--color-primary-subtle);
629
+ --selection-fg: var(--color-fg);
630
+ --card-border: var(--color-surface-1-border);
631
+ --card-bg: var(--color-surface-1);
632
+ --input-border: var(--color-border);
633
+ --input-bg: var(--color-bg);
634
+ --input-bg-filled: var(--color-bg-subtle);
635
+ --input-fill: var(--input-bg);
636
+ --switch-bg: var(--color-bg-muted);
637
+ --panel-bg: var(--color-bg);
638
+ }
639
+
348
640
  /* === tokens/document.css === */
349
641
  /* @ui:tokens document — structural tokens for document/print rendering */
350
642
  /* These tokens control page geometry, document typography, table density,
@@ -376,10 +668,10 @@
376
668
  Separate from the base typography tokens because documents have
377
669
  different optimal sizes than screen UIs. 14px body + 12px legal
378
670
  is standard for A4 business documents. */
379
- --doc-font: var(--font-sans);
671
+ --doc-font: var(--font-body);
380
672
  --doc-font-size: var(--text-sm); /* 14px — optimal for A4 */
381
673
  --doc-line-height: var(--leading-normal); /* 1.5 */
382
- --doc-heading-font: var(--font-sans);
674
+ --doc-heading-font: var(--font-heading);
383
675
  --doc-heading-weight: var(--weight-bold);
384
676
  --doc-heading-size: var(--text-xl); /* 20px for doc titles */
385
677
  --doc-subheading-size: var(--text-lg); /* 18px for section titles */
@@ -430,6 +722,16 @@
430
722
  --doc-print-border-color: oklch(0.60 0 0); /* medium gray borders in print */
431
723
  }
432
724
 
725
+ /* ── Scheme islands ── */
726
+ /* `--doc-legal-color` is the one document colour screen components read (the
727
+ key-value label and the image caption), so it is restated where a scheme can
728
+ change below the root — see the same block in tokens/aliases.css. The rest
729
+ of this file is print ink, which does not follow the scheme. */
730
+ [data-theme],
731
+ [data-skin] {
732
+ --doc-legal-color: var(--color-fg-muted);
733
+ }
734
+
433
735
  /* === tokens/doc-aliases.css === */
434
736
  /* @ui:tokens doc-aliases — component-level document tokens */
435
737
  /* Maps document-layer tokens to specific primitive/recipe attribute selectors.
@@ -476,7 +778,10 @@
476
778
  --field-error-size: var(--doc-legal-size);
477
779
  --field-error-color: var(--color-destructive);
478
780
  --field-validating-color: var(--color-fg-muted); /* async validation in flight */
479
- --field-disabled-opacity: 0.55; /* honest disabled affordance */
781
+ /* The role `--disabled-opacity` sets for every control, nudged 10% lighter:
782
+ 0.55 at the 0.5 default, which is the value this alias always held, and it
783
+ follows a theme that states the role (1.1A-27). */
784
+ --field-disabled-opacity: calc(var(--disabled-opacity) * 1.1);
480
785
  --field-required-color: var(--color-destructive);
481
786
  --field-required-marker: ' *'; /* appended to required labels */
482
787
 
@@ -496,15 +801,47 @@
496
801
  --stat-change-negative: var(--color-destructive);
497
802
  }
498
803
 
804
+ /* ── Scheme islands ── */
805
+ /* The colour aliases above, restated where a scheme can change below the root —
806
+ a custom property resolves its var() on the element that declares it, so a
807
+ `:root`-only alias would carry the page's light value into a nested
808
+ `data-theme="dark"` region. See the same block in tokens/aliases.css; the
809
+ values must match the `:root` declarations above exactly. */
810
+ [data-theme],
811
+ [data-skin] {
812
+ --kv-label-color: var(--doc-legal-color);
813
+ --kv-value-color: var(--color-fg);
814
+ --callout-bg: var(--color-bg-subtle);
815
+ --callout-fg: var(--color-fg);
816
+ --image-border: var(--color-border);
817
+ --image-caption-color: var(--doc-legal-color);
818
+ --field-label-color: var(--color-fg);
819
+ --field-description-color: var(--color-fg-muted);
820
+ --field-error-color: var(--color-destructive);
821
+ --field-validating-color: var(--color-fg-muted);
822
+ --field-required-color: var(--color-destructive);
823
+ --page-break-screen-color: var(--color-border);
824
+ --page-break-screen-label-color: var(--color-fg-muted);
825
+ --stat-label-color: var(--color-fg-muted);
826
+ --stat-change-positive: var(--color-success);
827
+ --stat-change-negative: var(--color-destructive);
828
+ }
829
+
499
830
  /* === tokens/density.css === */
500
- /* @ui:tokens density — [data-density] subtree modifier (task 0.7-11, FAQIR-NEXT §B6)
831
+ /* @ui:tokens density — [data-density] subtree modifier (task 0.7-11, FAQIR-NEXT §B6;
832
+ `spacious` added 1.1A-09, SPEC-1.0.md §4)
501
833
 
502
834
  Put `data-density="compact"` on ANY container and its whole subtree renders
503
835
  tighter: spacing steps shrink by --density-scale and interactive controls drop
504
836
  to a shorter height ramp. `data-density="comfortable"` restores the base scale,
505
- so density can be reset on an inner subtree.
837
+ so density can be reset on an inner subtree. `data-density="spacious"` is the
838
+ third point on the ladder, above comfortable: spacing grows and the control
839
+ ramp grows with it, gentler than the spacing multiplier for the same reason
840
+ compact's ramp shrinks gentler — a usable hit target has a ceiling as well as
841
+ a floor.
506
842
 
507
843
  <section data-density="compact"> … dense form / table / toolbar … </section>
844
+ <section data-density="spacious"> … roomy landing hero, kiosk UI … </section>
508
845
 
509
846
  This is 100% CSS. `data-density` is NOT a sixth protocol attribute: no
510
847
  component contract, manifest, controller or audit rule knows about it — CSS
@@ -641,169 +978,284 @@
641
978
  --content-gutter: var(--space-6);
642
979
  }
643
980
 
981
+ /* The third density: roomier than the base scale, for a landing hero or a kiosk
982
+ UI meant to be read at arm's length. Control heights grow slower than the
983
+ spacing multiplier — the same asymmetry compact's ramp has, mirrored. */
984
+ [data-density="spacious"] {
985
+ --density-scale: 1.25;
986
+
987
+ /* ── Spacing scale (× --density-scale) ── */
988
+ --space-0h: calc(0.125rem * var(--density-scale));
989
+ --space-1: calc(0.25rem * var(--density-scale));
990
+ --space-1h: calc(0.375rem * var(--density-scale));
991
+ --space-2: calc(0.5rem * var(--density-scale));
992
+ --space-2h: calc(0.625rem * var(--density-scale));
993
+ --space-3: calc(0.75rem * var(--density-scale));
994
+ --space-3h: calc(0.875rem * var(--density-scale));
995
+ --space-4: calc(1rem * var(--density-scale));
996
+ --space-5: calc(1.25rem * var(--density-scale));
997
+ --space-6: calc(1.5rem * var(--density-scale));
998
+ --space-7: calc(1.75rem * var(--density-scale));
999
+ --space-8: calc(2rem * var(--density-scale));
1000
+ --space-10: calc(2.5rem * var(--density-scale));
1001
+ --space-12: calc(3rem * var(--density-scale));
1002
+ --space-16: calc(4rem * var(--density-scale));
1003
+ --space-20: calc(5rem * var(--density-scale));
1004
+ --space-24: calc(6rem * var(--density-scale));
1005
+ --space-32: calc(8rem * var(--density-scale));
1006
+ --space-40: calc(10rem * var(--density-scale));
1007
+ --space-48: calc(12rem * var(--density-scale));
1008
+ --space-64: calc(16rem * var(--density-scale));
1009
+
1010
+ /* ── Control height ramp ── */
1011
+ --control-height-sm: 36px;
1012
+ --control-height-md: 44px;
1013
+ --control-height-lg: 52px;
1014
+
1015
+ /* ── Aliases re-substituted in this scope (values identical to the base) ── */
1016
+ --button-height-sm: var(--control-height-sm);
1017
+ --button-height-md: var(--control-height-md);
1018
+ --button-height-lg: var(--control-height-lg);
1019
+ --input-height: var(--control-height-md);
1020
+ --card-padding: var(--space-6);
1021
+ --kv-pair-gap: var(--space-3);
1022
+ --kv-grid-gap: var(--space-4);
1023
+ --callout-padding-y: var(--space-3);
1024
+ --callout-padding-x: var(--space-4);
1025
+ --field-gap: var(--space-1h);
1026
+ --section-gap-sm: var(--space-12);
1027
+ --section-gap-md: var(--space-20);
1028
+ --section-gap-lg: var(--space-32);
1029
+ --content-gutter: var(--space-6);
1030
+ }
1031
+
644
1032
  /* === themes/slate.css === */
645
1033
  /* @ui:theme slate — conservative enterprise blue-gray; safe for banks */
1034
+ /* @ui:density compact — the density this theme was designed at.
1035
+
1036
+ Density is the one axis with no token to declare: `tokens/density.css` states
1037
+ each ramp inside a `[data-density]` subtree SCOPE, and a `:root` block cannot
1038
+ override a subtree scope, so a theme states its intended density in this
1039
+ header directive instead (`axesFromCss` reads it; `faqir theme generate`
1040
+ emits the same line for a `compact` seed). A project adopting this theme sets
1041
+ `data-density="compact"` on its root element — the sanctioned modifier — and
1042
+ the shipped preview stamps it, so the gallery renders slate at the ramp it was
1043
+ drawn for rather than at the comfortable one. [1.1A-15] */
646
1044
 
647
1045
  /* ── Light Mode Overrides ── */
648
- /* Cool blue-gray neutrals with a restrained steel-blue primary */
1046
+ /* Steel-blue neutrals — a dense data surface, not a luminous white page */
649
1047
  :root {
650
- /* ── Surfaces ── */
651
- --color-bg: oklch(0.985 0.003 240); /* cool near-white */
652
- --color-bg-subtle: oklch(0.95 0.006 240); /* elevation step 1 */
653
- --color-bg-muted: oklch(0.915 0.009 240); /* elevation step 2 */
1048
+ /* ── Surfaces ──
1049
+ Deliberately deeper and more tinted than 1.0's near-white: at
1050
+ `oklch(0.985 0.003 240)` this theme's page was a colourway of `glass`'s
1051
+ (the two sat 0.0282 mean OKLab ΔE apart, under the 0.03 the framework
1052
+ demands between a CARD and the page it lies on — see
1053
+ tests/themes/distinctiveness.test.ts). The fix is not a new hue but the
1054
+ theme's own claim, finally honoured: "cool blue-gray neutrals" reads as
1055
+ steel card stock under dense tables, which is also why `--color-bg` now
1056
+ carries enough chroma for the `neutral` axis to derive `cool` instead of
1057
+ contradicting the line at the top of this file. */
1058
+ --color-bg: oklch(0.965 0.014 245); /* steel page */
1059
+ --color-bg-subtle: oklch(0.925 0.018 245); /* elevation step 1 */
1060
+ --color-bg-muted: oklch(0.878 0.022 245); /* elevation step 2 */
654
1061
  --color-surface-1: var(--color-bg-subtle);
655
1062
  --color-surface-2: var(--color-bg-muted);
656
1063
  --color-surface-1-border: var(--color-border);
657
1064
  --color-surface-2-border: var(--color-border-strong);
658
- --color-fg: oklch(0.21 0.03 250); /* deep slate */
659
- --color-fg-muted: oklch(0.45 0.025 245); /* muted slate */
660
- --color-fg-subtle: oklch(0.57 0.02 245); /* subtle slate */
1065
+ --color-fg: oklch(0.20 0.032 250); /* deep slate */
1066
+ --color-fg-muted: oklch(0.43 0.028 245); /* muted slate */
1067
+ --color-fg-subtle: oklch(0.54 0.024 245); /* subtle slate */
661
1068
 
662
1069
  /* ── Interactive: Primary (steel blue) ── */
663
1070
  --color-primary: oklch(0.45 0.09 245); /* steel blue */
664
1071
  --color-primary-hover: oklch(0.40 0.09 245);
665
1072
  --color-primary-active: oklch(0.36 0.08 245);
666
1073
  --color-primary-fg: white;
667
- --color-primary-subtle: oklch(0.93 0.03 245);
1074
+ --color-primary-subtle: oklch(0.91 0.038 245);
668
1075
 
669
1076
  /* ── Interactive: Secondary ── */
670
- --color-secondary: oklch(0.93 0.01 240);
671
- --color-secondary-hover: oklch(0.89 0.014 240);
672
- --color-secondary-fg: oklch(0.25 0.03 245);
1077
+ --color-secondary: oklch(0.905 0.02 245);
1078
+ --color-secondary-hover: oklch(0.862 0.024 245);
1079
+ --color-secondary-fg: oklch(0.24 0.032 248);
673
1080
 
674
1081
  /* ── Interactive: Destructive ── */
675
1082
  --color-destructive: oklch(0.52 0.19 25);
676
1083
  --color-destructive-hover: oklch(0.47 0.20 25);
677
1084
  --color-destructive-fg: white;
678
- --color-destructive-subtle: oklch(0.94 0.03 25);
1085
+ --color-destructive-subtle: oklch(0.92 0.038 25);
679
1086
 
680
1087
  /* ── Feedback ── */
681
1088
  --color-success: oklch(0.49 0.14 155);
682
- --color-success-subtle: oklch(0.94 0.04 155);
1089
+ --color-success-subtle: oklch(0.92 0.048 155);
683
1090
  --color-warning: oklch(0.52 0.13 80);
684
- --color-warning-subtle: oklch(0.95 0.05 80);
1091
+ --color-warning-subtle: oklch(0.93 0.058 80);
685
1092
  --color-info: oklch(0.51 0.13 245);
686
- --color-info-subtle: oklch(0.94 0.03 245);
1093
+ --color-info-subtle: oklch(0.92 0.038 245);
687
1094
 
688
1095
  /* ── Borders ── */
689
- --color-border: oklch(0.89 0.008 240);
690
- --color-border-strong: oklch(0.80 0.012 240);
1096
+ --color-border: oklch(0.855 0.018 245);
1097
+ --color-border-strong: oklch(0.755 0.022 245);
691
1098
  --color-ring: oklch(0.45 0.09 245);
692
1099
 
693
- /* ── Shadows (restrained, cool gray) ── */
694
- --shadow-xs: 0 1px 2px oklch(0.25 0.02 250 / 0.06);
695
- --shadow-sm: 0 1px 3px oklch(0.25 0.02 250 / 0.08), 0 1px 2px oklch(0.25 0.02 250 / 0.05);
696
- --shadow-md: 0 4px 6px oklch(0.25 0.02 250 / 0.07), 0 2px 4px oklch(0.25 0.02 250 / 0.05);
697
- --shadow-lg: 0 10px 15px oklch(0.25 0.02 250 / 0.08), 0 4px 6px oklch(0.25 0.02 250 / 0.05);
698
- --shadow-xl: 0 20px 25px oklch(0.25 0.02 250 / 0.10), 0 8px 10px oklch(0.25 0.02 250 / 0.05);
1100
+ /* ══════════════════════════════════════════════════════════════════════
1101
+ The identity, in tokens. "Default, but bluer" is what this theme was;
1102
+ an enterprise console is a different SHAPE, not a different hue. [1.1A-15]
1103
+ ══════════════════════════════════════════════════════════════════════ */
1104
+
1105
+ /* ── Type: a neo-grotesque, in all three roles ──
1106
+ The face an enterprise product is set in: Helvetica/Arial, the grotesque
1107
+ class, rather than whatever the operating system happens to prefer. All
1108
+ three roles move together — a console has one voice — which is what makes
1109
+ `type.pairing` derive `sans-grotesque` instead of `system`. No webfont:
1110
+ every family here is installed on the platforms a bank actually runs. */
1111
+ --font-heading: 'Helvetica Neue', Helvetica, Arial, sans-serif;
1112
+ --font-body: 'Helvetica Neue', Helvetica, Arial, sans-serif;
1113
+ --font-ui: 'Helvetica Neue', Helvetica, Arial, sans-serif;
1114
+
1115
+ /* ── Shape: crisp ──
1116
+ The whole ladder tightens, so a card, a dialog and a badge agree. 4px at
1117
+ `--radius-md` is the `crisp` band — a corner a dense table can afford,
1118
+ where the base layer's 6px starts to read as consumer-soft. */
1119
+ --radius-sm: 0.125rem; /* 2px */
1120
+ --radius-md: 0.25rem; /* 4px */
1121
+ --radius-lg: 0.25rem; /* 4px */
1122
+ --radius-xl: 0.375rem; /* 6px */
1123
+ --radius-2xl: 0.5rem; /* 8px */
1124
+
1125
+ /* ── Depth: flat ──
1126
+ A console is a plane of information, not a stack of floating cards: every
1127
+ step of the ramp is removed and the elevation is carried by the surface
1128
+ colours and the borders above, which is what the three `--color-surface-*`
1129
+ steps are for. Stated in every scheme, because a dark block that omits a
1130
+ shadow token renders with the LIGHT value. */
1131
+ --shadow-xs: none;
1132
+ --shadow-sm: none;
1133
+ --shadow-md: none;
1134
+ --shadow-lg: none;
1135
+ --shadow-xl: none;
1136
+
1137
+ /* ── Motion: snappy ──
1138
+ A short duration ON an ease-out curve, which is what `snappy` names; the
1139
+ easing is re-pointed at this theme's own `--ease-out` rather than a
1140
+ literal, so the two move together. Nothing in a trading console should
1141
+ ease in and out of place for a fifth of a second. */
1142
+ --duration-fast: 80ms;
1143
+ --duration-normal: 140ms;
1144
+ --duration-slow: 200ms;
1145
+ --ease-default: var(--ease-out);
699
1146
  }
700
1147
 
701
1148
  /* ── Dark Mode ── */
702
- /* Blue-gray slate surfaces, desaturated light-blue primary, quiet shadows */
1149
+ /* Deep navy-graphite surfaces, desaturated light-blue primary, no shadows */
703
1150
  [data-theme="dark"] {
704
- /* ── Surfaces (blue-gray slate) ── */
705
- --color-bg: oklch(0.18 0.02 250); /* deep slate */
706
- --color-bg-subtle: oklch(0.22 0.022 250); /* dark slate */
707
- --color-bg-muted: oklch(0.26 0.024 250); /* muted slate */
1151
+ /* ── Surfaces (deep navy graphite) ──
1152
+ Deeper than 1.0's mid slate for the same reason the light page moved: at
1153
+ 0.18 it sat one step from `glass`'s 0.17. A night-shift console is nearly
1154
+ black, which is both further from `glass` and easier on the eye it is read
1155
+ by for eight hours. */
1156
+ --color-bg: oklch(0.145 0.025 250); /* near-black navy */
1157
+ --color-bg-subtle: oklch(0.187 0.028 250); /* elevation step 1 */
1158
+ --color-bg-muted: oklch(0.235 0.030 250); /* elevation step 2 */
708
1159
  --color-surface-1: var(--color-bg-subtle);
709
1160
  --color-surface-2: var(--color-bg-muted);
710
1161
  --color-surface-1-border: var(--color-border);
711
1162
  --color-surface-2-border: var(--color-border-strong);
712
- --color-fg: oklch(0.95 0.005 240); /* near-white, cool */
713
- --color-fg-muted: oklch(0.68 0.02 245); /* muted cool gray */
714
- --color-fg-subtle: oklch(0.54 0.02 245); /* subtle cool gray */
1163
+ --color-fg: oklch(0.93 0.012 245); /* near-white, cool */
1164
+ --color-fg-muted: oklch(0.66 0.025 245); /* muted cool gray */
1165
+ --color-fg-subtle: oklch(0.52 0.022 245); /* subtle cool gray */
715
1166
 
716
1167
  /* ── Interactive: Primary (light steel blue) ── */
717
1168
  --color-primary: oklch(0.68 0.11 245); /* light steel blue */
718
1169
  --color-primary-hover: oklch(0.74 0.10 245); /* lighter steel */
719
1170
  --color-primary-active: oklch(0.79 0.09 245); /* lightest steel */
720
- --color-primary-fg: oklch(0.16 0.02 250); /* deep slate for contrast */
721
- --color-primary-subtle: oklch(0.26 0.033 245);
1171
+ --color-primary-fg: oklch(0.13 0.025 250); /* near-black navy */
1172
+ --color-primary-subtle: oklch(0.235 0.038 245);
722
1173
 
723
1174
  /* ── Interactive: Secondary ── */
724
- --color-secondary: oklch(0.28 0.02 250);
725
- --color-secondary-hover: oklch(0.33 0.022 250);
726
- --color-secondary-fg: oklch(0.92 0.008 240);
1175
+ --color-secondary: oklch(0.25 0.026 250);
1176
+ --color-secondary-hover: oklch(0.30 0.028 250);
1177
+ --color-secondary-fg: oklch(0.90 0.012 245);
727
1178
 
728
1179
  /* ── Interactive: Destructive ── */
729
1180
  --color-destructive: oklch(0.68 0.19 25);
730
1181
  --color-destructive-hover: oklch(0.63 0.18 25);
731
- --color-destructive-fg: oklch(0.18 0.02 250);
732
- --color-destructive-subtle: oklch(0.26 0.057 25);
1182
+ --color-destructive-fg: oklch(0.145 0.025 250);
1183
+ --color-destructive-subtle: oklch(0.235 0.060 25);
733
1184
 
734
1185
  /* ── Feedback ── */
735
1186
  --color-success: oklch(0.72 0.14 155);
736
- --color-success-subtle: oklch(0.26 0.042 155);
1187
+ --color-success-subtle: oklch(0.235 0.045 155);
737
1188
  --color-warning: oklch(0.80 0.13 85);
738
- --color-warning-subtle: oklch(0.26 0.039 85);
1189
+ --color-warning-subtle: oklch(0.235 0.042 85);
739
1190
  --color-info: oklch(0.70 0.12 245);
740
- --color-info-subtle: oklch(0.26 0.036 245);
1191
+ --color-info-subtle: oklch(0.235 0.038 245);
741
1192
 
742
1193
  /* ── Borders ── */
743
- --color-border: oklch(0.30 0.02 250);
744
- --color-border-strong: oklch(0.38 0.022 250);
1194
+ --color-border: oklch(0.270 0.026 250);
1195
+ --color-border-strong: oklch(0.360 0.028 250);
745
1196
  --color-ring: oklch(0.68 0.11 245);
746
1197
 
747
- /* ── Shadows (quiet, dark neutral) ── */
748
- --shadow-xs: 0 1px 3px oklch(0.08 0.01 250 / 0.35);
749
- --shadow-sm: 0 2px 6px oklch(0.08 0.01 250 / 0.4);
750
- --shadow-md: 0 6px 12px oklch(0.08 0.01 250 / 0.4), 0 2px 4px oklch(0.08 0.01 250 / 0.25);
751
- --shadow-lg: 0 12px 24px oklch(0.08 0.01 250 / 0.45), 0 4px 8px oklch(0.08 0.01 250 / 0.25);
752
- --shadow-xl: 0 24px 48px oklch(0.08 0.01 250 / 0.5), 0 8px 16px oklch(0.08 0.01 250 / 0.3);
1198
+ /* ── Depth: flat in dark too ── */
1199
+ --shadow-xs: none;
1200
+ --shadow-sm: none;
1201
+ --shadow-md: none;
1202
+ --shadow-lg: none;
1203
+ --shadow-xl: none;
753
1204
  }
754
1205
 
755
1206
  /* ── Auto Dark Mode (system preference) ── */
1207
+ /* Mirror of the [data-theme="dark"] block above — keep the two in sync. */
756
1208
  @media (prefers-color-scheme: dark) {
757
1209
  [data-theme="auto"] {
758
- /* ── Surfaces (blue-gray slate) ── */
759
- --color-bg: oklch(0.18 0.02 250);
760
- --color-bg-subtle: oklch(0.22 0.022 250);
761
- --color-bg-muted: oklch(0.26 0.024 250);
1210
+ /* ── Surfaces (deep navy graphite) ── */
1211
+ --color-bg: oklch(0.145 0.025 250);
1212
+ --color-bg-subtle: oklch(0.187 0.028 250);
1213
+ --color-bg-muted: oklch(0.235 0.030 250);
762
1214
  --color-surface-1: var(--color-bg-subtle);
763
1215
  --color-surface-2: var(--color-bg-muted);
764
1216
  --color-surface-1-border: var(--color-border);
765
1217
  --color-surface-2-border: var(--color-border-strong);
766
- --color-fg: oklch(0.95 0.005 240);
767
- --color-fg-muted: oklch(0.68 0.02 245);
768
- --color-fg-subtle: oklch(0.54 0.02 245);
1218
+ --color-fg: oklch(0.93 0.012 245);
1219
+ --color-fg-muted: oklch(0.66 0.025 245);
1220
+ --color-fg-subtle: oklch(0.52 0.022 245);
769
1221
 
770
1222
  /* ── Interactive: Primary (light steel blue) ── */
771
1223
  --color-primary: oklch(0.68 0.11 245);
772
1224
  --color-primary-hover: oklch(0.74 0.10 245);
773
1225
  --color-primary-active: oklch(0.79 0.09 245);
774
- --color-primary-fg: oklch(0.16 0.02 250);
775
- --color-primary-subtle: oklch(0.26 0.033 245);
1226
+ --color-primary-fg: oklch(0.13 0.025 250);
1227
+ --color-primary-subtle: oklch(0.235 0.038 245);
776
1228
 
777
1229
  /* ── Interactive: Secondary ── */
778
- --color-secondary: oklch(0.28 0.02 250);
779
- --color-secondary-hover: oklch(0.33 0.022 250);
780
- --color-secondary-fg: oklch(0.92 0.008 240);
1230
+ --color-secondary: oklch(0.25 0.026 250);
1231
+ --color-secondary-hover: oklch(0.30 0.028 250);
1232
+ --color-secondary-fg: oklch(0.90 0.012 245);
781
1233
 
782
1234
  /* ── Interactive: Destructive ── */
783
1235
  --color-destructive: oklch(0.68 0.19 25);
784
1236
  --color-destructive-hover: oklch(0.63 0.18 25);
785
- --color-destructive-fg: oklch(0.18 0.02 250);
786
- --color-destructive-subtle: oklch(0.26 0.057 25);
1237
+ --color-destructive-fg: oklch(0.145 0.025 250);
1238
+ --color-destructive-subtle: oklch(0.235 0.060 25);
787
1239
 
788
1240
  /* ── Feedback ── */
789
1241
  --color-success: oklch(0.72 0.14 155);
790
- --color-success-subtle: oklch(0.26 0.042 155);
1242
+ --color-success-subtle: oklch(0.235 0.045 155);
791
1243
  --color-warning: oklch(0.80 0.13 85);
792
- --color-warning-subtle: oklch(0.26 0.039 85);
1244
+ --color-warning-subtle: oklch(0.235 0.042 85);
793
1245
  --color-info: oklch(0.70 0.12 245);
794
- --color-info-subtle: oklch(0.26 0.036 245);
1246
+ --color-info-subtle: oklch(0.235 0.038 245);
795
1247
 
796
1248
  /* ── Borders ── */
797
- --color-border: oklch(0.30 0.02 250);
798
- --color-border-strong: oklch(0.38 0.022 250);
1249
+ --color-border: oklch(0.270 0.026 250);
1250
+ --color-border-strong: oklch(0.360 0.028 250);
799
1251
  --color-ring: oklch(0.68 0.11 245);
800
1252
 
801
- /* ── Shadows (quiet, dark neutral) ── */
802
- --shadow-xs: 0 1px 3px oklch(0.08 0.01 250 / 0.35);
803
- --shadow-sm: 0 2px 6px oklch(0.08 0.01 250 / 0.4);
804
- --shadow-md: 0 6px 12px oklch(0.08 0.01 250 / 0.4), 0 2px 4px oklch(0.08 0.01 250 / 0.25);
805
- --shadow-lg: 0 12px 24px oklch(0.08 0.01 250 / 0.45), 0 4px 8px oklch(0.08 0.01 250 / 0.25);
806
- --shadow-xl: 0 24px 48px oklch(0.08 0.01 250 / 0.5), 0 8px 16px oklch(0.08 0.01 250 / 0.3);
1253
+ /* ── Depth: flat in dark too ── */
1254
+ --shadow-xs: none;
1255
+ --shadow-sm: none;
1256
+ --shadow-md: none;
1257
+ --shadow-lg: none;
1258
+ --shadow-xl: none;
807
1259
  }
808
1260
  }
809
1261
 
@@ -821,11 +1273,38 @@
821
1273
  padding: 0;
822
1274
  }
823
1275
 
1276
+ /* Colour scheme — the one place `data-theme` is translated into the platform's
1277
+ own scheme signal. `light-dark()` in a theme reads `color-scheme`, not
1278
+ `data-theme`, so a one-block theme [1.1A-06] resolves nothing at all without
1279
+ these three rules; declaring them here (rather than in each theme) is what
1280
+ makes the two authoring forms interchangeable. Nothing else in the registry
1281
+ declares `color-scheme`, so this is purely additive.
1282
+
1283
+ Specificity does the mapping: `:root` is (0,0,1) and each attribute selector
1284
+ is (0,1,0), so `<html data-theme="dark">` takes the dark rule over the root
1285
+ default while a bare `<html>` — and `data-theme="light"` — keeps light. The
1286
+ same rules apply to a NESTED element carrying `data-theme`, which is how a
1287
+ dark island inside a light page has always worked here. */
1288
+ :root {
1289
+ color-scheme: light;
1290
+ }
1291
+
1292
+ [data-theme="dark"] {
1293
+ color-scheme: dark;
1294
+ }
1295
+
1296
+ /* `auto` hands the choice to the OS: `light dark` means "either, system first",
1297
+ which is exactly what the `@media (prefers-color-scheme: dark)` mirror block
1298
+ does for a theme authored in the three-block form. */
1299
+ [data-theme="auto"] {
1300
+ color-scheme: light dark;
1301
+ }
1302
+
824
1303
  html {
825
1304
  -webkit-text-size-adjust: 100%;
826
1305
  -moz-tab-size: 4;
827
1306
  tab-size: 4;
828
- font-family: var(--font-sans);
1307
+ font-family: var(--font-body);
829
1308
  font-size: var(--text-base);
830
1309
  line-height: var(--leading-normal);
831
1310
  color: var(--color-fg);
@@ -836,6 +1315,11 @@ html {
836
1315
 
837
1316
  body {
838
1317
  min-height: 100dvh;
1318
+ /* The page's material. `none` by default (the initial value), so this is a
1319
+ no-op until a theme points --texture-page at one of tokens/textures.css.
1320
+ `html` keeps the background COLOUR; the texture rides on `body`, which
1321
+ covers the viewport, so the two compose instead of overwriting. */
1322
+ background-image: var(--texture-page);
839
1323
  }
840
1324
 
841
1325
  img,
@@ -905,10 +1389,32 @@ table {
905
1389
  }
906
1390
  }
907
1391
 
908
- /* Focus visible — default ring */
1392
+ /* Text selection — the decoration axis reaching the one surface no component
1393
+ owns. Until 1.1 the highlight was whatever the OS drew, which is the one part
1394
+ of a themed page that never matched the theme. Both values are tokens
1395
+ (tokens/aliases.css § Decoration), so a theme states its selection once. */
1396
+ ::selection {
1397
+ background-color: var(--selection-bg);
1398
+ color: var(--selection-fg);
1399
+ }
1400
+
1401
+ /* Focus visible — the default ring, and the only place it is spelled out.
1402
+ Every value is a token (tokens/effects.css § Focus), so a theme states its
1403
+ focus once and every element that has not drawn its own ring follows. */
909
1404
  :focus-visible {
910
- outline: 2px solid var(--color-ring);
911
- outline-offset: 2px;
1405
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1406
+ outline-offset: var(--focus-ring-offset);
1407
+ }
1408
+
1409
+ /* The glow a theme may put behind the ring, at zero specificity. `box-shadow`
1410
+ is not a property focus owns: an element's resting shadow — a card's depth,
1411
+ an author's own — lives there too, and a (0,1,0) rule here replaced it with
1412
+ `none` (the default) on every keyboard focus. Under `:where()` ANY rule that
1413
+ sets a shadow outranks this one, so it lands only on an element nothing else
1414
+ shadows, and it never takes a shadow away. The controls that draw their own
1415
+ ring read `--focus-shadow` in their own `:focus-visible` rules. */
1416
+ :where(:focus-visible) {
1417
+ box-shadow: var(--focus-shadow);
912
1418
  }
913
1419
 
914
1420
  /* Hidden but accessible */
@@ -937,7 +1443,7 @@ table {
937
1443
  /* @ui:base prose — typography defaults for long-form content */
938
1444
 
939
1445
  [data-ui="prose"] {
940
- font-family: var(--font-sans);
1446
+ font-family: var(--font-body);
941
1447
  font-size: var(--text-base);
942
1448
  line-height: var(--leading-relaxed);
943
1449
  color: var(--color-fg);
@@ -945,29 +1451,45 @@ table {
945
1451
  }
946
1452
 
947
1453
  [data-ui="prose"] h1 {
1454
+ font-family: var(--font-heading);
948
1455
  font-size: var(--text-4xl);
949
- font-weight: var(--weight-bold);
950
- line-height: var(--leading-tight);
1456
+ font-weight: var(--heading-weight);
1457
+ letter-spacing: var(--heading-tracking);
1458
+ text-transform: var(--heading-transform);
1459
+ font-variant-caps: var(--heading-caps);
1460
+ line-height: var(--heading-leading);
951
1461
  margin-block: var(--space-8) var(--space-4);
952
1462
  }
953
1463
 
954
1464
  [data-ui="prose"] h2 {
1465
+ font-family: var(--font-heading);
955
1466
  font-size: var(--text-3xl);
956
1467
  font-weight: var(--weight-semibold);
957
- line-height: var(--leading-tight);
1468
+ letter-spacing: var(--heading-tracking);
1469
+ text-transform: var(--heading-transform);
1470
+ font-variant-caps: var(--heading-caps);
1471
+ line-height: var(--heading-leading);
958
1472
  margin-block: var(--space-8) var(--space-3);
959
1473
  }
960
1474
 
961
1475
  [data-ui="prose"] h3 {
1476
+ font-family: var(--font-heading);
962
1477
  font-size: var(--text-2xl);
963
1478
  font-weight: var(--weight-semibold);
1479
+ letter-spacing: var(--heading-tracking);
1480
+ text-transform: var(--heading-transform);
1481
+ font-variant-caps: var(--heading-caps);
964
1482
  line-height: var(--leading-snug);
965
1483
  margin-block: var(--space-6) var(--space-3);
966
1484
  }
967
1485
 
968
1486
  [data-ui="prose"] h4 {
1487
+ font-family: var(--font-heading);
969
1488
  font-size: var(--text-xl);
970
1489
  font-weight: var(--weight-semibold);
1490
+ letter-spacing: var(--heading-tracking);
1491
+ text-transform: var(--heading-transform);
1492
+ font-variant-caps: var(--heading-caps);
971
1493
  line-height: var(--leading-snug);
972
1494
  margin-block: var(--space-6) var(--space-2);
973
1495
  }
@@ -978,8 +1500,8 @@ table {
978
1500
 
979
1501
  [data-ui="prose"] a {
980
1502
  color: var(--color-primary);
981
- text-decoration: underline;
982
- text-underline-offset: 2px;
1503
+ text-decoration-line: var(--link-decoration);
1504
+ text-underline-offset: var(--link-underline-offset);
983
1505
  }
984
1506
 
985
1507
  [data-ui="prose"] a:hover {
@@ -1016,7 +1538,7 @@ table {
1016
1538
  }
1017
1539
 
1018
1540
  [data-ui="prose"] blockquote {
1019
- border-inline-start: 3px solid var(--color-border-strong);
1541
+ border-inline-start: var(--border-width-lg) solid var(--color-border-strong);
1020
1542
  padding-inline-start: var(--space-4);
1021
1543
  color: var(--color-fg-muted);
1022
1544
  margin-block: var(--space-4);
@@ -1038,9 +1560,15 @@ table {
1038
1560
  margin-block: var(--space-1);
1039
1561
  }
1040
1562
 
1563
+ /* The bullet. `currentColor` by default — the initial value — so a list looks
1564
+ exactly as it did; a theme that wants accented markers sets --marker-color. */
1565
+ [data-ui="prose"] li::marker {
1566
+ color: var(--marker-color);
1567
+ }
1568
+
1041
1569
  [data-ui="prose"] hr {
1042
1570
  border: none;
1043
- border-block-start: 1px solid var(--color-border);
1571
+ border-block-start: var(--border-width) solid var(--color-border);
1044
1572
  margin-block: var(--space-8);
1045
1573
  }
1046
1574
 
@@ -1059,12 +1587,12 @@ table {
1059
1587
  font-weight: var(--weight-semibold);
1060
1588
  text-align: start;
1061
1589
  padding: var(--space-2) var(--space-3);
1062
- border-block-end: 2px solid var(--color-border-strong);
1590
+ border-block-end: var(--border-width-strong) solid var(--color-border-strong);
1063
1591
  }
1064
1592
 
1065
1593
  [data-ui="prose"] td {
1066
1594
  padding: var(--space-2) var(--space-3);
1067
- border-block-end: 1px solid var(--color-border);
1595
+ border-block-end: var(--border-width) solid var(--color-border);
1068
1596
  }
1069
1597
 
1070
1598
  /* First child no top margin, last child no bottom margin */
@@ -1249,7 +1777,7 @@ table {
1249
1777
 
1250
1778
  /* === primitives/avatar.css === */
1251
1779
  /* @ui:component avatar */
1252
- /* @ui:tokens color-bg-muted color-fg-muted radius-full font-sans text-xs text-sm weight-medium */
1780
+ /* @ui:tokens color-bg-muted color-fg-muted radius-full font-ui text-xs text-sm weight-medium */
1253
1781
 
1254
1782
  /* ── Base ── */
1255
1783
  [data-ui="avatar"] {
@@ -1279,7 +1807,7 @@ table {
1279
1807
  height: 100%;
1280
1808
  background: var(--color-bg-muted);
1281
1809
  color: var(--color-fg-muted);
1282
- font-family: var(--font-sans);
1810
+ font-family: var(--font-ui);
1283
1811
  font-size: var(--text-sm);
1284
1812
  font-weight: var(--weight-medium);
1285
1813
  text-transform: uppercase;
@@ -1304,7 +1832,7 @@ table {
1304
1832
 
1305
1833
  /* === primitives/badge.css === */
1306
1834
  /* @ui:component badge */
1307
- /* @ui:tokens color-bg-muted color-fg color-primary color-primary-fg color-primary-subtle color-secondary color-secondary-fg color-destructive color-destructive-fg color-destructive-subtle color-success color-success-subtle color-warning color-warning-subtle radius-full space-1 space-2 font-sans text-xs text-sm weight-medium */
1835
+ /* @ui:tokens color-bg-muted color-fg color-primary color-primary-fg color-primary-subtle color-secondary color-secondary-fg color-destructive color-destructive-fg color-destructive-subtle color-success color-success-subtle color-warning color-warning-subtle radius-full space-1 space-2 font-ui text-xs text-sm weight-medium corner-shape */
1308
1836
 
1309
1837
  /* ── Base ── */
1310
1838
  [data-ui="badge"] {
@@ -1314,9 +1842,10 @@ table {
1314
1842
  gap: var(--space-1);
1315
1843
  padding: 0.125rem var(--space-2);
1316
1844
  border-radius: var(--badge-radius, var(--radius-full));
1845
+ corner-shape: var(--corner-shape);
1317
1846
  background: var(--color-bg-muted);
1318
1847
  color: var(--color-fg);
1319
- font-family: var(--badge-font, var(--font-sans));
1848
+ font-family: var(--badge-font, var(--font-ui));
1320
1849
  font-size: var(--text-xs);
1321
1850
  font-weight: var(--weight-medium);
1322
1851
  line-height: 1.5;
@@ -1362,11 +1891,11 @@ table {
1362
1891
 
1363
1892
  /* === primitives/breadcrumb.css === */
1364
1893
  /* @ui:component breadcrumb */
1365
- /* @ui:tokens color-fg color-fg-muted color-fg-subtle color-primary-hover color-ring radius-sm space-2 text-xs text-sm text-base font-sans weight-medium duration-fast ease-default */
1894
+ /* @ui:tokens color-fg color-fg-muted color-fg-subtle color-primary-hover color-ring radius-sm space-2 text-xs text-sm text-base font-ui weight-medium duration-fast ease-default focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow link-decoration */
1366
1895
 
1367
1896
  /* ── Root ── */
1368
1897
  [data-ui="breadcrumb"] {
1369
- font-family: var(--breadcrumb-font, var(--font-sans));
1898
+ font-family: var(--breadcrumb-font, var(--font-ui));
1370
1899
  font-size: var(--breadcrumb-size, var(--text-sm));
1371
1900
  color: var(--color-fg-muted);
1372
1901
  }
@@ -1392,12 +1921,13 @@ table {
1392
1921
 
1393
1922
  [data-ui="breadcrumb"] [data-part="item"]:hover {
1394
1923
  color: var(--color-primary-hover);
1395
- text-decoration: underline;
1924
+ text-decoration-line: var(--link-decoration);
1396
1925
  }
1397
1926
 
1398
1927
  [data-ui="breadcrumb"] [data-part="item"]:focus-visible {
1399
- outline: 2px solid var(--color-ring);
1400
- outline-offset: 2px;
1928
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1929
+ outline-offset: var(--focus-ring-offset);
1930
+ box-shadow: var(--focus-shadow);
1401
1931
  }
1402
1932
 
1403
1933
  /* ── Separator (presentational) ── */
@@ -1437,7 +1967,7 @@ table {
1437
1967
 
1438
1968
  /* === primitives/button.css === */
1439
1969
  /* @ui:component button */
1440
- /* @ui:tokens color-primary color-primary-hover color-primary-fg color-secondary color-secondary-hover color-secondary-fg color-destructive color-destructive-hover color-destructive-fg color-bg color-bg-muted color-bg-subtle color-fg color-border color-ring radius-md space-2 space-3 space-4 space-6 font-sans text-xs text-sm text-base weight-medium duration-fast ease-default shadow-xs radius-full */
1970
+ /* @ui:tokens color-primary color-primary-hover color-primary-fg color-secondary color-secondary-hover color-secondary-fg color-destructive color-destructive-hover color-destructive-fg color-bg color-bg-muted color-bg-subtle color-fg color-border color-ring radius-md space-2 space-3 space-4 space-6 font-ui text-xs text-sm text-base weight-medium duration-fast ease-default shadow-xs radius-full border-width border-width-strong corner-shape focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow button-text-transform motion-hover-lift link-decoration disabled-opacity */
1441
1971
 
1442
1972
  /* ── Base ── */
1443
1973
  [data-ui="button"] {
@@ -1447,18 +1977,21 @@ table {
1447
1977
  gap: var(--space-2);
1448
1978
  height: var(--button-height-md, 40px);
1449
1979
  padding-inline: var(--space-4);
1450
- border: 1px solid var(--color-border);
1980
+ border: var(--border-width) solid var(--color-border);
1451
1981
  border-radius: var(--button-radius, var(--radius-md));
1982
+ corner-shape: var(--corner-shape);
1452
1983
  background: var(--color-bg);
1453
1984
  color: var(--color-fg);
1454
- font-family: var(--font-sans);
1985
+ font-family: var(--font-ui);
1455
1986
  font-size: var(--text-sm);
1456
1987
  font-weight: var(--weight-medium);
1988
+ text-transform: var(--button-text-transform);
1457
1989
  line-height: 1;
1458
1990
  cursor: pointer;
1459
1991
  transition: background var(--duration-fast) var(--ease-default),
1460
1992
  border-color var(--duration-fast) var(--ease-default),
1461
1993
  color var(--duration-fast) var(--ease-default),
1994
+ translate var(--duration-fast) var(--ease-default),
1462
1995
  box-shadow var(--duration-fast) var(--ease-default);
1463
1996
  user-select: none;
1464
1997
  white-space: nowrap;
@@ -1467,11 +2000,16 @@ table {
1467
2000
 
1468
2001
  [data-ui="button"]:hover {
1469
2002
  background: var(--color-bg-muted);
2003
+ /* The hover lift. `none` by default — the initial value of `translate` — so
2004
+ this rule computes what the button computed before the token existed; a
2005
+ theme with a springy personality sets `--motion-hover-lift: 0 -1px`. */
2006
+ translate: var(--motion-hover-lift);
1470
2007
  }
1471
2008
 
1472
2009
  [data-ui="button"]:focus-visible {
1473
- outline: 2px solid var(--color-ring);
1474
- outline-offset: 2px;
2010
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2011
+ outline-offset: var(--focus-ring-offset);
2012
+ box-shadow: var(--focus-shadow);
1475
2013
  }
1476
2014
 
1477
2015
  /* ── Variants ── */
@@ -1527,7 +2065,7 @@ table {
1527
2065
  padding: 0;
1528
2066
  }
1529
2067
  [data-ui="button"][data-variant="link"]:hover {
1530
- text-decoration: underline;
2068
+ text-decoration-line: var(--link-decoration);
1531
2069
  }
1532
2070
 
1533
2071
  /* ── Sizes ── */
@@ -1546,7 +2084,7 @@ table {
1546
2084
  /* ── States ── */
1547
2085
  [data-ui="button"]:disabled,
1548
2086
  [data-ui="button"][data-state="disabled"] {
1549
- opacity: 0.5;
2087
+ opacity: var(--disabled-opacity);
1550
2088
  cursor: not-allowed;
1551
2089
  pointer-events: none;
1552
2090
  }
@@ -1561,7 +2099,7 @@ table {
1561
2099
  position: absolute;
1562
2100
  width: 1em;
1563
2101
  height: 1em;
1564
- border: 2px solid currentColor;
2102
+ border: var(--border-width-strong) solid currentColor;
1565
2103
  border-inline-end-color: transparent;
1566
2104
  border-radius: var(--radius-full);
1567
2105
  animation: faqir-spin 0.6s linear infinite;
@@ -1608,7 +2146,7 @@ table {
1608
2146
 
1609
2147
  /* === primitives/callout.css === */
1610
2148
  /* @ui:component callout */
1611
- /* @ui:tokens callout-radius callout-padding-y callout-padding-x callout-border-left-width callout-font-size callout-icon-size callout-fg color-fg color-fg-muted color-info color-info-subtle color-warning color-warning-subtle color-destructive color-destructive-subtle color-success color-success-subtle color-bg-muted color-border color-ring space-1 radius-sm font-sans weight-semibold */
2149
+ /* @ui:tokens callout-radius callout-padding-y callout-padding-x callout-border-left-width callout-font-size callout-icon-size callout-fg color-fg color-fg-muted color-info color-info-subtle color-warning color-warning-subtle color-destructive color-destructive-subtle color-success color-success-subtle color-bg-muted color-border color-ring space-1 radius-sm font-heading font-body weight-semibold focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow */
1612
2150
 
1613
2151
  /* ── Base ── */
1614
2152
  [data-ui="callout"] {
@@ -1617,7 +2155,7 @@ table {
1617
2155
  padding: var(--callout-padding-y) var(--callout-padding-x);
1618
2156
  border-radius: var(--callout-radius);
1619
2157
  border-inline-start: var(--callout-border-left-width) solid;
1620
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
2158
+ font-family: var(--doc-font, var(--font-body));
1621
2159
  font-size: var(--callout-font-size);
1622
2160
  line-height: var(--doc-line-height, 1.5);
1623
2161
  }
@@ -1648,6 +2186,7 @@ table {
1648
2186
  /* ── Title ── */
1649
2187
  [data-ui="callout"] [data-part="title"] {
1650
2188
  display: block;
2189
+ font-family: var(--font-heading);
1651
2190
  font-weight: var(--weight-semibold);
1652
2191
  margin-bottom: var(--doc-label-gap, var(--space-1, 0.25rem));
1653
2192
  }
@@ -1674,8 +2213,9 @@ table {
1674
2213
  }
1675
2214
 
1676
2215
  [data-ui="callout"] [data-part="dismiss"]:focus-visible {
1677
- outline: 2px solid var(--color-ring, var(--color-info));
1678
- outline-offset: 2px;
2216
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2217
+ outline-offset: var(--focus-ring-offset);
2218
+ box-shadow: var(--focus-shadow);
1679
2219
  opacity: 1;
1680
2220
  }
1681
2221
 
@@ -1761,17 +2301,36 @@ table {
1761
2301
 
1762
2302
  /* === primitives/card.css === */
1763
2303
  /* @ui:component card */
1764
- /* @ui:tokens color-surface-1 color-surface-2 color-surface-1-border color-surface-2-border color-fg color-fg-muted radius-lg shadow-sm space-4 space-6 font-sans text-sm text-lg text-xl weight-semibold leading-tight */
2304
+ /* @ui:tokens color-surface-1 color-surface-2 color-surface-1-border color-surface-2-border color-fg color-fg-muted radius-lg shadow-sm space-4 space-6 font-heading text-sm text-lg text-xl weight-semibold leading-tight border-width corner-shape card-border-width surface-backdrop texture-surface motion-hover-lift duration-fast ease-default */
1765
2305
 
1766
2306
  /* ── Base ── */
1767
2307
  [data-ui="card"] {
1768
2308
  display: flex;
1769
2309
  flex-direction: column;
1770
- border: 1px solid var(--card-border, var(--color-surface-1-border));
2310
+ border: var(--card-border-width) solid var(--card-border, var(--color-surface-1-border));
1771
2311
  border-radius: var(--card-radius, var(--radius-lg));
1772
- background: var(--card-bg, var(--color-surface-1));
2312
+ corner-shape: var(--corner-shape);
2313
+ /* One shorthand, two layers: the material on top, the fill beneath. The fill
2314
+ is the final layer, so `--card-bg` may be a colour OR a gradient — what 1.0
2315
+ projects set it to — and the texture (`none` by default) never clobbers it. */
2316
+ background: var(--texture-surface), var(--card-bg, var(--color-surface-1));
1773
2317
  box-shadow: var(--card-shadow, var(--shadow-sm));
1774
2318
  overflow: hidden;
2319
+ transition: translate var(--duration-fast) var(--ease-default);
2320
+ }
2321
+
2322
+ /* The hover lift, the same axis `button` reads. `none` by default (the initial
2323
+ value of `translate`), so a card sits exactly where it always sat until a
2324
+ theme says surfaces rise under the pointer. */
2325
+ [data-ui="card"]:hover {
2326
+ translate: var(--motion-hover-lift);
2327
+ }
2328
+
2329
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
2330
+ [data-ui="card"] {
2331
+ -webkit-backdrop-filter: var(--surface-backdrop);
2332
+ backdrop-filter: var(--surface-backdrop);
2333
+ }
1775
2334
  }
1776
2335
 
1777
2336
  /* ── Variants ── */
@@ -1780,7 +2339,7 @@ table {
1780
2339
  }
1781
2340
 
1782
2341
  [data-ui="card"][data-variant="filled"] {
1783
- background: var(--color-surface-2);
2342
+ background: var(--texture-surface), var(--color-surface-2);
1784
2343
  border-color: var(--color-surface-2-border);
1785
2344
  box-shadow: none;
1786
2345
  }
@@ -1795,7 +2354,7 @@ table {
1795
2354
  }
1796
2355
 
1797
2356
  [data-ui="card"] > [data-part="header"] > [data-part="title"] {
1798
- font-family: var(--font-sans);
2357
+ font-family: var(--font-heading);
1799
2358
  font-size: var(--text-lg);
1800
2359
  font-weight: var(--weight-semibold);
1801
2360
  line-height: var(--leading-tight);
@@ -1836,9 +2395,19 @@ table {
1836
2395
  padding-top: 0;
1837
2396
  }
1838
2397
 
2398
+ /* ── Motion ── */
2399
+ /* The hover lift is the only thing a card animates, and it is `none` until a
2400
+ theme states one — but the house rule is that a stylesheet which transitions
2401
+ carries its own opt-out, so a reader never has to check the token first. */
2402
+ @media (prefers-reduced-motion: reduce) {
2403
+ [data-ui="card"] {
2404
+ transition: none;
2405
+ }
2406
+ }
2407
+
1839
2408
  /* === primitives/checkbox.css === */
1840
2409
  /* @ui:component checkbox */
1841
- /* @ui:tokens color-bg color-fg color-primary color-primary-fg color-border color-border-strong color-ring radius-sm space-1 space-2 duration-fast ease-default */
2410
+ /* @ui:tokens color-bg color-fg color-primary color-primary-fg color-border color-border-strong color-ring space-1 space-2 duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow checkbox-radius checkbox-size disabled-opacity */
1842
2411
 
1843
2412
  /* -- Label wrapper -- */
1844
2413
  [data-ui="checkbox-label"] {
@@ -1850,7 +2419,7 @@ table {
1850
2419
 
1851
2420
  [data-ui="checkbox-label"]:has([data-ui="checkbox"]:disabled) {
1852
2421
  cursor: not-allowed;
1853
- opacity: 0.5;
2422
+ opacity: var(--disabled-opacity);
1854
2423
  }
1855
2424
 
1856
2425
  /* -- Base -- */
@@ -1862,8 +2431,8 @@ table {
1862
2431
  width: var(--checkbox-size, 18px);
1863
2432
  height: var(--checkbox-size, 18px);
1864
2433
  flex-shrink: 0;
1865
- border: 1px solid var(--color-border);
1866
- border-radius: var(--checkbox-radius, var(--radius-sm));
2434
+ border: var(--border-width) solid var(--color-border);
2435
+ border-radius: var(--checkbox-radius);
1867
2436
  background: var(--color-bg);
1868
2437
  cursor: pointer;
1869
2438
  transition: background var(--duration-fast) var(--ease-default),
@@ -1876,8 +2445,9 @@ table {
1876
2445
  }
1877
2446
 
1878
2447
  [data-ui="checkbox"]:focus-visible {
1879
- outline: 2px solid var(--color-ring);
1880
- outline-offset: 2px;
2448
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2449
+ outline-offset: var(--focus-ring-offset);
2450
+ box-shadow: var(--focus-shadow);
1881
2451
  }
1882
2452
 
1883
2453
  /* -- Checked -- */
@@ -1968,7 +2538,7 @@ table {
1968
2538
  The mask has to opt out of the substitution to stay readable. [W3-3] */
1969
2539
  @media (forced-colors: active) {
1970
2540
  [data-ui="checkbox"] {
1971
- border: 1px solid ButtonText;
2541
+ border: var(--border-width) solid ButtonText;
1972
2542
  }
1973
2543
 
1974
2544
  [data-ui="checkbox"]:checked,
@@ -1992,7 +2562,7 @@ table {
1992
2562
 
1993
2563
  /* === primitives/chip.css === */
1994
2564
  /* @ui:component chip */
1995
- /* @ui:tokens color-bg-muted color-fg color-fg-muted color-primary color-primary-subtle color-destructive color-destructive-subtle color-border color-ring radius-full space-1 space-2 space-3 font-sans text-xs text-sm weight-medium */
2565
+ /* @ui:tokens color-bg-muted color-fg color-fg-muted color-primary color-primary-subtle color-destructive color-destructive-subtle color-border color-ring radius-full space-1 space-2 space-3 font-ui text-xs text-sm weight-medium border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow */
1996
2566
 
1997
2567
  /* ── Base ── */
1998
2568
  [data-ui="chip"] {
@@ -2000,11 +2570,11 @@ table {
2000
2570
  align-items: center;
2001
2571
  gap: var(--space-1);
2002
2572
  padding: var(--space-1) var(--space-2);
2003
- border: 1px solid transparent;
2573
+ border: var(--border-width) solid transparent;
2004
2574
  border-radius: var(--chip-radius, var(--radius-full));
2005
2575
  background: var(--color-bg-muted);
2006
2576
  color: var(--color-fg);
2007
- font-family: var(--chip-font, var(--font-sans));
2577
+ font-family: var(--chip-font, var(--font-ui));
2008
2578
  font-size: var(--text-sm);
2009
2579
  font-weight: var(--weight-medium);
2010
2580
  line-height: 1.2;
@@ -2040,8 +2610,11 @@ table {
2040
2610
  }
2041
2611
 
2042
2612
  [data-ui="chip"] [data-part="dismiss"]:focus-visible {
2043
- outline: 2px solid var(--color-ring);
2044
- outline-offset: 1px;
2613
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2614
+ /* Half the default gap — the dismiss target is small, and the full ring
2615
+ would collide with the chip's own edge. */
2616
+ outline-offset: calc(var(--focus-ring-offset) / 2);
2617
+ box-shadow: var(--focus-shadow);
2045
2618
  }
2046
2619
 
2047
2620
  /* ── Variants ── */
@@ -2264,12 +2837,12 @@ table {
2264
2837
 
2265
2838
  /* === primitives/collapsible.css === */
2266
2839
  /* @ui:component collapsible */
2267
- /* @ui:tokens color-fg color-fg-muted color-bg-subtle color-border color-ring radius-md space-2 space-3 text-sm text-base font-sans weight-medium duration-fast duration-normal ease-default */
2840
+ /* @ui:tokens color-fg color-fg-muted color-bg-subtle color-border color-ring radius-md space-2 space-3 text-sm text-base font-ui weight-medium duration-fast duration-normal ease-default border-width border-width-strong focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow */
2268
2841
 
2269
2842
  /* ── Root — native <details>, so it opens/closes with zero JavaScript ── */
2270
2843
  [data-ui="collapsible"] {
2271
2844
  border-radius: var(--collapsible-radius, var(--radius-md));
2272
- font-family: var(--collapsible-font, var(--font-sans));
2845
+ font-family: var(--collapsible-font, var(--font-ui));
2273
2846
  color: var(--color-fg);
2274
2847
  }
2275
2848
 
@@ -2299,8 +2872,9 @@ table {
2299
2872
  }
2300
2873
 
2301
2874
  [data-ui="collapsible"] [data-part="trigger"]:focus-visible {
2302
- outline: 2px solid var(--color-ring);
2303
- outline-offset: 2px;
2875
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2876
+ outline-offset: var(--focus-ring-offset);
2877
+ box-shadow: var(--focus-shadow);
2304
2878
  }
2305
2879
 
2306
2880
  /* Chevron indicator — rotates when open, CSS-only */
@@ -2309,8 +2883,8 @@ table {
2309
2883
  flex: none;
2310
2884
  width: 0.5em;
2311
2885
  height: 0.5em;
2312
- border-inline-end: 2px solid var(--color-fg-muted);
2313
- border-block-end: 2px solid var(--color-fg-muted);
2886
+ border-inline-end: var(--border-width-strong) solid var(--color-fg-muted);
2887
+ border-block-end: var(--border-width-strong) solid var(--color-fg-muted);
2314
2888
  transform: rotate(45deg);
2315
2889
  transition: transform var(--duration-normal) var(--ease-default);
2316
2890
  }
@@ -2329,7 +2903,7 @@ table {
2329
2903
 
2330
2904
  /* ── Bordered variant ── */
2331
2905
  [data-ui="collapsible"][data-variant="bordered"] {
2332
- border: 1px solid var(--color-border);
2906
+ border: var(--border-width) solid var(--color-border);
2333
2907
  }
2334
2908
 
2335
2909
  /* ── Open/close animation via ::details-content, where supported ── */
@@ -2462,13 +3036,13 @@ table {
2462
3036
 
2463
3037
  /* === primitives/description-list.css === */
2464
3038
  /* @ui:component description-list */
2465
- /* @ui:tokens color-fg color-fg-muted color-border doc-font doc-line-height space-1 space-2 space-3 space-4 space-6 text-xs text-sm text-base font-sans weight-semibold */
3039
+ /* @ui:tokens color-fg color-fg-muted color-border doc-font doc-line-height space-1 space-2 space-3 space-4 space-6 text-xs text-sm text-base font-body weight-semibold border-width */
2466
3040
 
2467
3041
  /* ── Base ── */
2468
3042
  [data-ui="description-list"] {
2469
3043
  margin: 0;
2470
3044
  padding: 0;
2471
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3045
+ font-family: var(--doc-font, var(--font-body));
2472
3046
  }
2473
3047
 
2474
3048
  /* ── Term ── */
@@ -2524,7 +3098,7 @@ table {
2524
3098
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"],
2525
3099
  [data-ui="description-list"][data-divided]:not([data-variant]) [data-part="details"] {
2526
3100
  padding-bottom: var(--space-4);
2527
- border-bottom: 1px solid var(--color-border);
3101
+ border-bottom: var(--border-width) solid var(--color-border);
2528
3102
  }
2529
3103
 
2530
3104
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"]:last-child,
@@ -2536,7 +3110,7 @@ table {
2536
3110
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="term"],
2537
3111
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="details"] {
2538
3112
  padding-bottom: var(--space-3);
2539
- border-bottom: 1px solid var(--color-border);
3113
+ border-bottom: var(--border-width) solid var(--color-border);
2540
3114
  }
2541
3115
 
2542
3116
  /* ── Size: Small ── */
@@ -2574,7 +3148,7 @@ table {
2574
3148
 
2575
3149
  /* === primitives/empty-state.css === */
2576
3150
  /* @ui:component empty-state */
2577
- /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl */
3151
+ /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl font-heading */
2578
3152
 
2579
3153
  /* ── Base ── */
2580
3154
  [data-ui="empty-state"] {
@@ -2595,6 +3169,7 @@ table {
2595
3169
 
2596
3170
  /* ── Title ── */
2597
3171
  [data-ui="empty-state"] [data-part="title"] {
3172
+ font-family: var(--font-heading);
2598
3173
  font-size: var(--text-lg);
2599
3174
  font-weight: var(--weight-medium);
2600
3175
  color: var(--color-fg);
@@ -2642,7 +3217,7 @@ table {
2642
3217
 
2643
3218
  /* === primitives/field-group.css === */
2644
3219
  /* @ui:component field-group */
2645
- /* @ui:tokens field-label-size field-label-weight field-label-color field-description-size field-description-color field-error-size field-error-color field-required-color field-required-marker field-validating-color field-disabled-opacity color-destructive color-success space-1 space-2 space-3 space-4 text-xs text-sm font-sans */
3220
+ /* @ui:tokens field-label-size field-label-weight field-label-color field-description-size field-description-color field-error-size field-error-color field-required-color field-required-marker field-validating-color field-disabled-opacity color-destructive color-success space-1 space-2 space-3 space-4 text-xs text-sm font-body border-width */
2646
3221
 
2647
3222
  /* ── Base / spacing ownership ──
2648
3223
  A field-group owns only its tight, density-aware intra-field step: label →
@@ -2654,7 +3229,7 @@ table {
2654
3229
  display: flex;
2655
3230
  flex-direction: column;
2656
3231
  gap: var(--space-2);
2657
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3232
+ font-family: var(--doc-font, var(--font-body));
2658
3233
  }
2659
3234
 
2660
3235
  /* ── Label ── */
@@ -2724,7 +3299,7 @@ table {
2724
3299
  [data-ui="field-group"][data-state="invalid"] [data-ui="textarea"],
2725
3300
  [data-ui="field-group"][data-state="invalid"] [data-ui="select"] {
2726
3301
  border-color: var(--field-error-color);
2727
- box-shadow: 0 0 0 1px var(--field-error-color);
3302
+ box-shadow: 0 0 0 var(--border-width) var(--field-error-color);
2728
3303
  }
2729
3304
 
2730
3305
  /* ── State: Validating ──
@@ -2734,7 +3309,7 @@ table {
2734
3309
  [data-ui="field-group"][data-state="validating"] [data-ui="textarea"],
2735
3310
  [data-ui="field-group"][data-state="validating"] [data-ui="select"] {
2736
3311
  border-color: var(--field-validating-color);
2737
- box-shadow: 0 0 0 1px var(--field-validating-color);
3312
+ box-shadow: 0 0 0 var(--border-width) var(--field-validating-color);
2738
3313
  }
2739
3314
 
2740
3315
  /* ── State: Disabled ──
@@ -2753,8 +3328,8 @@ table {
2753
3328
  [data-ui="field-group"][data-state="valid"] [data-ui="input"],
2754
3329
  [data-ui="field-group"][data-state="valid"] [data-ui="textarea"],
2755
3330
  [data-ui="field-group"][data-state="valid"] [data-ui="select"] {
2756
- border-color: var(--color-success, oklch(0.62 0.19 145));
2757
- box-shadow: 0 0 0 1px var(--color-success, oklch(0.62 0.19 145));
3331
+ border-color: var(--color-success);
3332
+ box-shadow: 0 0 0 var(--border-width) var(--color-success);
2758
3333
  }
2759
3334
 
2760
3335
  /* ── Variant: Horizontal ── */
@@ -3059,7 +3634,7 @@ table {
3059
3634
 
3060
3635
  /* === primitives/image.css === */
3061
3636
  /* @ui:component image */
3062
- /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-sans */
3637
+ /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-body */
3063
3638
 
3064
3639
  /* ── Base ── */
3065
3640
  [data-ui="image"] {
@@ -3083,7 +3658,7 @@ table {
3083
3658
  [data-ui="image"] [data-part="caption"] {
3084
3659
  display: block;
3085
3660
  margin-top: var(--space-2);
3086
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3661
+ font-family: var(--doc-font, var(--font-body));
3087
3662
  font-size: var(--image-caption-size);
3088
3663
  color: var(--image-caption-color);
3089
3664
  line-height: 1.4;
@@ -3180,7 +3755,7 @@ table {
3180
3755
 
3181
3756
  /* === primitives/input.css === */
3182
3757
  /* @ui:component input */
3183
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 font-sans text-xs text-sm text-base duration-fast ease-default */
3758
+ /* @ui:tokens color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 font-ui text-xs text-sm text-base duration-fast ease-default border-width corner-shape focus-ring-width focus-ring-style focus-ring-color focus-shadow input-border-width input-fill disabled-opacity */
3184
3759
 
3185
3760
  /* ── Base ── */
3186
3761
  [data-ui="input"] {
@@ -3188,11 +3763,18 @@ table {
3188
3763
  width: 100%;
3189
3764
  height: var(--input-height, 40px);
3190
3765
  padding-inline: var(--space-3);
3191
- border: 1px solid var(--color-border);
3766
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
3767
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
3768
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
3769
+ is drawn. Identical to the shorthand at every other value of the token. */
3770
+ border-style: solid;
3771
+ border-color: var(--color-border);
3772
+ border-width: var(--input-border-width);
3192
3773
  border-radius: var(--input-radius, var(--radius-md));
3193
- background: var(--input-bg, var(--color-bg));
3774
+ corner-shape: var(--corner-shape);
3775
+ background: var(--input-fill);
3194
3776
  color: var(--color-fg);
3195
- font-family: var(--input-font, var(--font-sans));
3777
+ font-family: var(--input-font, var(--font-ui));
3196
3778
  font-size: var(--text-sm);
3197
3779
  line-height: 1;
3198
3780
  transition: border-color var(--duration-fast) var(--ease-default),
@@ -3208,8 +3790,11 @@ table {
3208
3790
  }
3209
3791
 
3210
3792
  [data-ui="input"]:focus {
3211
- outline: 2px solid var(--color-ring);
3212
- outline-offset: -1px;
3793
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
3794
+ /* The ring replaces the border rather than sitting outside it: inset by
3795
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
3796
+ outline-offset: calc(-1 * var(--input-border-width));
3797
+ box-shadow: var(--focus-shadow);
3213
3798
  border-color: transparent;
3214
3799
  }
3215
3800
 
@@ -3237,7 +3822,7 @@ table {
3237
3822
  }
3238
3823
 
3239
3824
  [data-ui="input"]:disabled {
3240
- opacity: 0.5;
3825
+ opacity: var(--disabled-opacity);
3241
3826
  cursor: not-allowed;
3242
3827
  }
3243
3828
 
@@ -3300,7 +3885,7 @@ table {
3300
3885
 
3301
3886
  /* === primitives/kbd.css === */
3302
3887
  /* @ui:component kbd */
3303
- /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs */
3888
+ /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs border-width border-width-strong */
3304
3889
 
3305
3890
  /* ── Base ── */
3306
3891
  [data-ui="kbd"] {
@@ -3310,8 +3895,8 @@ table {
3310
3895
  height: 20px;
3311
3896
  min-width: 20px;
3312
3897
  padding-inline: var(--space-1h);
3313
- border: 1px solid var(--color-border);
3314
- border-bottom-width: 2px;
3898
+ border: var(--border-width) solid var(--color-border);
3899
+ border-bottom-width: var(--border-width-strong);
3315
3900
  border-radius: var(--radius-sm);
3316
3901
  background: var(--color-bg-subtle);
3317
3902
  color: var(--color-fg);
@@ -3324,7 +3909,7 @@ table {
3324
3909
 
3325
3910
  /* === primitives/key-value.css === */
3326
3911
  /* @ui:component key-value */
3327
- /* @ui:tokens kv-label-color kv-label-weight kv-label-size kv-value-color kv-value-size kv-value-weight kv-gap kv-pair-gap kv-grid-gap text-xs text-sm text-base font-sans */
3912
+ /* @ui:tokens kv-label-color kv-label-weight kv-label-size kv-value-color kv-value-size kv-value-weight kv-gap kv-pair-gap kv-grid-gap text-xs text-sm text-base font-body */
3328
3913
 
3329
3914
  /* ── Base ── */
3330
3915
  [data-ui="key-value"] {
@@ -3333,7 +3918,7 @@ table {
3333
3918
  gap: var(--kv-pair-gap);
3334
3919
  margin: 0;
3335
3920
  padding: 0;
3336
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3921
+ font-family: var(--doc-font, var(--font-body));
3337
3922
  }
3338
3923
 
3339
3924
  /* ── Label ── */
@@ -3463,12 +4048,12 @@ table {
3463
4048
 
3464
4049
  /* === primitives/label.css === */
3465
4050
  /* @ui:component label */
3466
- /* @ui:tokens color-fg color-fg-muted color-destructive font-sans text-xs text-sm text-base weight-medium */
4051
+ /* @ui:tokens color-fg color-fg-muted color-destructive font-ui text-xs text-sm text-base weight-medium disabled-opacity */
3467
4052
 
3468
4053
  /* ── Base ── */
3469
4054
  [data-ui="label"] {
3470
4055
  display: block;
3471
- font-family: var(--font-sans);
4056
+ font-family: var(--font-ui);
3472
4057
  font-size: var(--text-sm);
3473
4058
  font-weight: var(--weight-medium);
3474
4059
  color: var(--color-fg);
@@ -3501,21 +4086,21 @@ table {
3501
4086
 
3502
4087
  /* ── States ── */
3503
4088
  [data-ui="label"][data-state="disabled"] {
3504
- opacity: 0.5;
4089
+ opacity: var(--disabled-opacity);
3505
4090
  cursor: not-allowed;
3506
4091
  }
3507
4092
 
3508
4093
  /* === primitives/link.css === */
3509
4094
  /* @ui:component link */
3510
- /* @ui:tokens color-primary color-primary-hover color-primary-active color-fg color-fg-muted color-ring radius-sm space-1 */
4095
+ /* @ui:tokens color-primary color-primary-hover color-primary-active color-fg color-fg-muted color-ring radius-sm space-1 focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow link-decoration link-thickness link-underline-offset */
3511
4096
 
3512
4097
  /* ── Base ── */
3513
4098
  [data-ui="link"] {
3514
4099
  color: var(--color-primary);
3515
4100
  font-family: inherit;
3516
- text-decoration: underline;
3517
- text-decoration-thickness: 1px;
3518
- text-underline-offset: 0.2em;
4101
+ text-decoration-line: var(--link-decoration);
4102
+ text-decoration-thickness: var(--link-thickness);
4103
+ text-underline-offset: var(--link-underline-offset);
3519
4104
  border-radius: var(--radius-sm);
3520
4105
  cursor: pointer;
3521
4106
  }
@@ -3529,8 +4114,9 @@ table {
3529
4114
  }
3530
4115
 
3531
4116
  [data-ui="link"]:focus-visible {
3532
- outline: 2px solid var(--color-ring);
3533
- outline-offset: 2px;
4117
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4118
+ outline-offset: var(--focus-ring-offset);
4119
+ box-shadow: var(--focus-shadow);
3534
4120
  }
3535
4121
 
3536
4122
  /* ── Variants ── */
@@ -3554,7 +4140,7 @@ table {
3554
4140
 
3555
4141
  /* === primitives/nav.css === */
3556
4142
  /* @ui:component nav */
3557
- /* @ui:tokens color-fg color-fg-muted color-primary color-primary-subtle color-bg-subtle color-border text-sm weight-medium radius-md space-1 space-2 space-3 space-4 duration-fast ease-default */
4143
+ /* @ui:tokens color-fg color-fg-muted color-primary color-primary-subtle color-bg-subtle color-border text-sm weight-medium radius-md space-1 space-2 space-3 space-4 duration-fast ease-default border-width border-width-strong */
3558
4144
 
3559
4145
  /* ── Base ── */
3560
4146
  [data-ui="nav"] {
@@ -3604,14 +4190,14 @@ table {
3604
4190
 
3605
4191
  /* ── Underline variant ── */
3606
4192
  [data-ui="nav"][data-variant="underline"] {
3607
- border-bottom: 1px solid var(--color-border);
4193
+ border-bottom: var(--border-width) solid var(--color-border);
3608
4194
  gap: 0;
3609
4195
  }
3610
4196
 
3611
4197
  [data-ui="nav"][data-variant="underline"] [data-part="link"] {
3612
4198
  border-radius: 0;
3613
4199
  padding: var(--space-2) var(--space-4);
3614
- border-bottom: 2px solid transparent;
4200
+ border-bottom: var(--border-width-strong) solid transparent;
3615
4201
  margin-bottom: -1px;
3616
4202
  }
3617
4203
 
@@ -3667,7 +4253,7 @@ table {
3667
4253
 
3668
4254
  /* === primitives/page-break.css === */
3669
4255
  /* @ui:component page-break */
3670
- /* @ui:tokens page-break-screen-color page-break-screen-style page-break-screen-label-color page-break-screen-label-size doc-font font-sans space-4 space-6 */
4256
+ /* @ui:tokens page-break-screen-color page-break-screen-style page-break-screen-label-color page-break-screen-label-size doc-font font-body space-4 space-6 border-width */
3671
4257
 
3672
4258
  /* ── Base (Screen) ── */
3673
4259
  [data-ui="page-break"] {
@@ -3682,12 +4268,12 @@ table {
3682
4268
  [data-ui="page-break"]::after {
3683
4269
  content: "";
3684
4270
  flex: 1;
3685
- border-top: 1px var(--page-break-screen-style) var(--page-break-screen-color);
4271
+ border-top: var(--border-width) var(--page-break-screen-style) var(--page-break-screen-color);
3686
4272
  }
3687
4273
 
3688
4274
  /* ── Label (Screen) ── */
3689
4275
  [data-ui="page-break"] {
3690
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4276
+ font-family: var(--doc-font, var(--font-body));
3691
4277
  font-size: var(--page-break-screen-label-size);
3692
4278
  color: var(--page-break-screen-label-color);
3693
4279
  letter-spacing: 0.05em;
@@ -3729,7 +4315,7 @@ table {
3729
4315
 
3730
4316
  /* === primitives/progress.css === */
3731
4317
  /* @ui:component progress */
3732
- /* @ui:tokens color-primary color-bg-muted color-success color-warning color-destructive radius-full radius-md space-1 duration-normal ease-default */
4318
+ /* @ui:tokens color-primary color-bg-muted color-success color-warning color-destructive radius-full radius-md space-1 duration-normal ease-default border-width */
3733
4319
 
3734
4320
  /* ── Base ── */
3735
4321
  [data-ui="progress"] {
@@ -3804,7 +4390,7 @@ table {
3804
4390
  substitution and paints `Highlight`; the track keeps a visible boundary. [W3-3] */
3805
4391
  @media (forced-colors: active) {
3806
4392
  [data-ui="progress"] [data-part="track"] {
3807
- border: 1px solid ButtonText;
4393
+ border: var(--border-width) solid ButtonText;
3808
4394
  }
3809
4395
 
3810
4396
  [data-ui="progress"] [data-part="fill"],
@@ -3818,7 +4404,7 @@ table {
3818
4404
 
3819
4405
  /* === primitives/radio.css === */
3820
4406
  /* @ui:component radio */
3821
- /* @ui:tokens color-bg color-fg color-primary color-primary-fg color-border color-border-strong color-ring radius-full space-1 space-2 duration-fast ease-default */
4407
+ /* @ui:tokens color-bg color-fg color-primary color-primary-fg color-border color-border-strong color-ring radius-full space-1 space-2 duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow disabled-opacity */
3822
4408
 
3823
4409
  /* -- Radio group -- */
3824
4410
  [data-ui="radio-group"] {
@@ -3840,7 +4426,7 @@ table {
3840
4426
 
3841
4427
  [data-ui="radio-label"]:has([data-ui="radio"]:disabled) {
3842
4428
  cursor: not-allowed;
3843
- opacity: 0.5;
4429
+ opacity: var(--disabled-opacity);
3844
4430
  }
3845
4431
 
3846
4432
  /* -- Base -- */
@@ -3852,7 +4438,7 @@ table {
3852
4438
  width: var(--radio-size, 18px);
3853
4439
  height: var(--radio-size, 18px);
3854
4440
  flex-shrink: 0;
3855
- border: 1px solid var(--color-border);
4441
+ border: var(--border-width) solid var(--color-border);
3856
4442
  border-radius: var(--radius-full);
3857
4443
  background: var(--color-bg);
3858
4444
  cursor: pointer;
@@ -3866,8 +4452,9 @@ table {
3866
4452
  }
3867
4453
 
3868
4454
  [data-ui="radio"]:focus-visible {
3869
- outline: 2px solid var(--color-ring);
3870
- outline-offset: 2px;
4455
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4456
+ outline-offset: var(--focus-ring-offset);
4457
+ box-shadow: var(--focus-shadow);
3871
4458
  }
3872
4459
 
3873
4460
  /* -- Checked -- */
@@ -3920,7 +4507,7 @@ table {
3920
4507
  inside a `--color-primary` circle, and the OS collapses both to one colour. [W3-3] */
3921
4508
  @media (forced-colors: active) {
3922
4509
  [data-ui="radio"] {
3923
- border: 1px solid ButtonText;
4510
+ border: var(--border-width) solid ButtonText;
3924
4511
  }
3925
4512
 
3926
4513
  [data-ui="radio"]:checked {
@@ -3940,7 +4527,7 @@ table {
3940
4527
 
3941
4528
  /* === primitives/select.css === */
3942
4529
  /* @ui:component select */
3943
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 font-sans text-xs text-sm text-base duration-fast ease-default */
4530
+ /* @ui:tokens color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 font-ui text-xs text-sm text-base duration-fast ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-shadow input-border-width input-fill disabled-opacity */
3944
4531
 
3945
4532
  /* -- Base -- */
3946
4533
  [data-ui="select"] {
@@ -3949,11 +4536,17 @@ table {
3949
4536
  height: var(--select-height, 40px);
3950
4537
  padding-inline: var(--space-3);
3951
4538
  padding-inline-end: var(--space-8, 2rem);
3952
- border: 1px solid var(--color-border);
4539
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
4540
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
4541
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
4542
+ is drawn. Identical to the shorthand at every other value of the token. */
4543
+ border-style: solid;
4544
+ border-color: var(--color-border);
4545
+ border-width: var(--input-border-width);
3953
4546
  border-radius: var(--select-radius, var(--radius-md));
3954
- background: var(--select-bg, var(--color-bg));
4547
+ background: var(--select-bg, var(--input-fill));
3955
4548
  color: var(--color-fg);
3956
- font-family: var(--select-font, var(--font-sans));
4549
+ font-family: var(--select-font, var(--font-ui));
3957
4550
  font-size: var(--text-sm);
3958
4551
  line-height: 1;
3959
4552
  cursor: pointer;
@@ -3983,8 +4576,11 @@ table {
3983
4576
  }
3984
4577
 
3985
4578
  [data-ui="select"]:focus {
3986
- outline: 2px solid var(--color-ring);
3987
- outline-offset: -1px;
4579
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4580
+ /* The ring replaces the border rather than sitting outside it: inset by
4581
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
4582
+ outline-offset: calc(-1 * var(--input-border-width));
4583
+ box-shadow: var(--focus-shadow);
3988
4584
  border-color: transparent;
3989
4585
  }
3990
4586
 
@@ -4017,7 +4613,7 @@ table {
4017
4613
  }
4018
4614
 
4019
4615
  [data-ui="select"]:disabled {
4020
- opacity: 0.5;
4616
+ opacity: var(--disabled-opacity);
4021
4617
  cursor: not-allowed;
4022
4618
  }
4023
4619
 
@@ -4030,12 +4626,12 @@ table {
4030
4626
 
4031
4627
  /* === primitives/separator.css === */
4032
4628
  /* @ui:component separator */
4033
- /* @ui:tokens color-border space-4 text-xs color-fg-muted font-sans */
4629
+ /* @ui:tokens color-border space-4 text-xs color-fg-muted font-ui border-width-strong divider-width divider-style */
4034
4630
 
4035
4631
  /* ── Base (horizontal) ── */
4036
4632
  [data-ui="separator"] {
4037
4633
  border: none;
4038
- border-top: 1px solid var(--color-border);
4634
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
4039
4635
  margin: 0;
4040
4636
  width: 100%;
4041
4637
  }
@@ -4043,7 +4639,7 @@ table {
4043
4639
  /* ── Vertical ── */
4044
4640
  [data-ui="separator"][data-variant="vertical"] {
4045
4641
  border-top: none;
4046
- border-inline-start: 1px solid var(--color-border);
4642
+ border-inline-start: var(--divider-width) var(--divider-style) var(--color-border);
4047
4643
  width: auto;
4048
4644
  height: 100%;
4049
4645
  align-self: stretch;
@@ -4061,11 +4657,11 @@ div[data-ui="separator"]::before,
4061
4657
  div[data-ui="separator"]::after {
4062
4658
  content: "";
4063
4659
  flex: 1;
4064
- border-top: 1px solid var(--color-border);
4660
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
4065
4661
  }
4066
4662
 
4067
4663
  [data-ui="separator"] [data-part="label"] {
4068
- font-family: var(--font-sans);
4664
+ font-family: var(--font-ui);
4069
4665
  font-size: var(--text-xs);
4070
4666
  color: var(--color-fg-muted);
4071
4667
  white-space: nowrap;
@@ -4103,17 +4699,17 @@ div[data-ui="separator"][data-style="dotted"]::after {
4103
4699
 
4104
4700
  /* ── Style: Thick ── */
4105
4701
  [data-ui="separator"][data-style="thick"] {
4106
- border-top-width: 2px;
4702
+ border-top-width: var(--border-width-strong);
4107
4703
  }
4108
4704
 
4109
4705
  [data-ui="separator"][data-style="thick"][data-variant="vertical"] {
4110
4706
  border-top-width: 0;
4111
- border-inline-start-width: 2px;
4707
+ border-inline-start-width: var(--border-width-strong);
4112
4708
  }
4113
4709
 
4114
4710
  div[data-ui="separator"][data-style="thick"]::before,
4115
4711
  div[data-ui="separator"][data-style="thick"]::after {
4116
- border-top-width: 2px;
4712
+ border-top-width: var(--border-width-strong);
4117
4713
  }
4118
4714
 
4119
4715
  /* ── Vertical Sizes ── */
@@ -4131,20 +4727,20 @@ div[data-ui="separator"][data-style="thick"]::after {
4131
4727
 
4132
4728
  /* === primitives/signature.css === */
4133
4729
  /* @ui:component signature */
4134
- /* @ui:tokens doc-signature-width doc-signature-gap doc-signature-line-color doc-signature-label-size doc-signature-label-color doc-font font-sans space-2 space-12 */
4730
+ /* @ui:tokens doc-signature-width doc-signature-gap doc-signature-line-color doc-signature-label-size doc-signature-label-color doc-font font-body space-2 space-12 border-width */
4135
4731
 
4136
4732
  /* ── Base ── */
4137
4733
  [data-ui="signature"] {
4138
4734
  display: flex;
4139
4735
  flex-direction: column;
4140
4736
  gap: var(--space-2);
4141
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4737
+ font-family: var(--doc-font, var(--font-body));
4142
4738
  margin-top: var(--doc-signature-gap);
4143
4739
  }
4144
4740
 
4145
4741
  /* ── Line ── */
4146
4742
  [data-ui="signature"] [data-part="line"] {
4147
- border-top: 1px solid var(--doc-signature-line-color);
4743
+ border-top: var(--border-width) solid var(--doc-signature-line-color);
4148
4744
  min-height: 1px;
4149
4745
  }
4150
4746
 
@@ -4247,14 +4843,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4247
4843
 
4248
4844
  /* === primitives/spinner.css === */
4249
4845
  /* @ui:component spinner */
4250
- /* @ui:tokens color-border color-primary radius-full duration-normal ease-default */
4846
+ /* @ui:tokens color-border color-primary radius-full duration-normal ease-default border-width-strong border-width-lg */
4251
4847
 
4252
4848
  /* ── Base ── */
4253
4849
  [data-ui="spinner"] {
4254
4850
  display: inline-block;
4255
4851
  width: 24px;
4256
4852
  height: 24px;
4257
- border: 2px solid var(--color-border);
4853
+ border: var(--border-width-strong) solid var(--color-border);
4258
4854
  border-top-color: var(--color-primary);
4259
4855
  border-radius: var(--radius-full);
4260
4856
  animation: faqir-spin 0.75s linear infinite;
@@ -4270,13 +4866,13 @@ div[data-ui="separator"][data-style="thick"]::after {
4270
4866
  [data-ui="spinner"][data-size="lg"] {
4271
4867
  width: 32px;
4272
4868
  height: 32px;
4273
- border-width: 3px;
4869
+ border-width: var(--border-width-lg);
4274
4870
  }
4275
4871
 
4276
4872
  [data-ui="spinner"][data-size="xl"] {
4277
4873
  width: 48px;
4278
4874
  height: 48px;
4279
- border-width: 3px;
4875
+ border-width: var(--border-width-lg);
4280
4876
  }
4281
4877
 
4282
4878
  /* ── Motion ── */
@@ -4858,14 +5454,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4858
5454
 
4859
5455
  /* === primitives/stat.css === */
4860
5456
  /* @ui:component stat */
4861
- /* @ui:tokens stat-value-size stat-value-weight stat-value-num-font stat-label-size stat-label-color stat-change-positive stat-change-negative color-fg color-fg-muted color-bg color-border space-1 space-2 space-4 radius-md shadow-sm font-sans text-xs text-sm text-lg text-3xl weight-semibold */
5457
+ /* @ui:tokens stat-value-size stat-value-weight stat-value-num-font stat-label-size stat-label-color stat-change-positive stat-change-negative color-fg color-fg-muted color-bg color-border space-1 space-2 space-4 radius-md shadow-sm font-heading font-body text-xs text-sm text-lg text-3xl weight-semibold border-width */
4862
5458
 
4863
5459
  /* ── Base ── */
4864
5460
  [data-ui="stat"] {
4865
5461
  display: flex;
4866
5462
  flex-direction: column;
4867
5463
  gap: var(--space-1);
4868
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
5464
+ font-family: var(--doc-font, var(--font-body));
4869
5465
  }
4870
5466
 
4871
5467
  /* ── Label ── */
@@ -4879,6 +5475,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4879
5475
 
4880
5476
  /* ── Value ── */
4881
5477
  [data-ui="stat"] [data-part="value"] {
5478
+ font-family: var(--font-heading);
4882
5479
  font-size: var(--stat-value-size);
4883
5480
  font-weight: var(--stat-value-weight);
4884
5481
  color: var(--color-fg);
@@ -4937,10 +5534,10 @@ div[data-ui="separator"][data-style="thick"]::after {
4937
5534
  /* ── Variant: Card ── */
4938
5535
  [data-ui="stat"][data-variant="card"] {
4939
5536
  padding: var(--space-4);
4940
- border: 1px solid var(--color-border);
5537
+ border: var(--border-width) solid var(--color-border);
4941
5538
  border-radius: var(--radius-md, 0.375rem);
4942
5539
  background: var(--color-bg);
4943
- box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.05));
5540
+ box-shadow: var(--shadow-sm);
4944
5541
  }
4945
5542
 
4946
5543
  /* ── Value + Change Inline ── */
@@ -4952,7 +5549,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4952
5549
  @media print {
4953
5550
  [data-ui="stat"][data-variant="card"] {
4954
5551
  box-shadow: none;
4955
- border: 1px solid var(--doc-print-border-color, var(--color-border, #ccc));
5552
+ border: var(--border-width) solid var(--doc-print-border-color, var(--color-border, #ccc));
4956
5553
  }
4957
5554
 
4958
5555
  [data-ui="stat"] {
@@ -4962,7 +5559,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4962
5559
 
4963
5560
  /* === primitives/stepper.css === */
4964
5561
  /* @ui:component stepper */
4965
- /* @ui:tokens color-primary color-primary-fg color-bg-muted color-fg-muted color-success color-success-subtle color-border text-sm text-xs weight-medium radius-full space-2 space-3 space-1 */
5562
+ /* @ui:tokens color-primary color-primary-fg color-bg-muted color-fg-muted color-success color-success-subtle color-border text-sm text-xs weight-medium radius-full space-2 space-3 space-1 border-width-strong */
4966
5563
 
4967
5564
  /* ── Base ── */
4968
5565
  [data-ui="stepper"] {
@@ -5041,7 +5638,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5041
5638
  The tight phone metrics are the base; the roomier ones arrive at `sm`. */
5042
5639
  [data-ui="stepper"] [data-part="connector"] {
5043
5640
  flex: 1;
5044
- height: 2px;
5641
+ height: var(--border-width-strong);
5045
5642
  background: var(--color-border);
5046
5643
  margin: 0 var(--space-1);
5047
5644
  min-width: var(--space-2);
@@ -5109,18 +5706,20 @@ div[data-ui="separator"][data-style="thick"]::after {
5109
5706
 
5110
5707
  /* === primitives/surface.css === */
5111
5708
  /* @ui:component surface */
5112
- /* @ui:tokens color-bg color-surface-1 color-surface-2 color-surface-1-border color-surface-2-border measure-content measure-narrow measure-prose measure-wide radius-lg shadow-sm shadow-md shadow-lg space-3 space-4 space-6 */
5709
+ /* @ui:tokens color-bg color-surface-1 color-surface-2 color-surface-1-border color-surface-2-border measure-content measure-narrow measure-prose measure-wide radius-lg shadow-sm shadow-md shadow-lg space-3 space-4 space-6 border-width corner-shape surface-backdrop texture-surface */
5113
5710
 
5114
5711
  /* ── Base ── */
5115
5712
  [data-ui="surface"] {
5116
- background: var(--color-surface-1);
5713
+ background-color: var(--color-surface-1);
5714
+ background-image: var(--texture-surface);
5117
5715
  border-radius: var(--radius-lg);
5118
- border: 1px solid var(--color-surface-1-border);
5716
+ corner-shape: var(--corner-shape);
5717
+ border: var(--border-width) solid var(--color-surface-1-border);
5119
5718
  }
5120
5719
 
5121
5720
  /* ── Elevation Variants ── */
5122
5721
  [data-ui="surface"][data-variant="flat"] {
5123
- background: var(--color-bg);
5722
+ background-color: var(--color-bg);
5124
5723
  border: none;
5125
5724
  box-shadow: none;
5126
5725
  }
@@ -5130,11 +5729,22 @@ div[data-ui="separator"][data-style="thick"]::after {
5130
5729
  }
5131
5730
 
5132
5731
  [data-ui="surface"][data-variant="overlay"] {
5133
- background: var(--color-surface-2);
5732
+ background-color: var(--color-surface-2);
5134
5733
  box-shadow: var(--shadow-lg);
5135
5734
  border-color: var(--color-surface-2-border);
5136
5735
  }
5137
5736
 
5737
+ /* An overlay is the one surface variant that floats over other content, so it
5738
+ is the one that can be frosted. Guarded exactly as themes/glass.css guards
5739
+ its own: a browser without backdrop-filter renders the solid surface above
5740
+ and never sees this rule. */
5741
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
5742
+ [data-ui="surface"][data-variant="overlay"] {
5743
+ -webkit-backdrop-filter: var(--surface-backdrop);
5744
+ backdrop-filter: var(--surface-backdrop);
5745
+ }
5746
+ }
5747
+
5138
5748
  /* ── Padding Sizes ── */
5139
5749
  [data-ui="surface"][data-size="sm"] {
5140
5750
  padding: var(--space-3);
@@ -5190,7 +5800,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5190
5800
 
5191
5801
  /* === primitives/switch.css === */
5192
5802
  /* @ui:component switch */
5193
- /* @ui:tokens color-bg-muted color-primary color-primary-fg color-border color-ring shadow-xs radius-full space-0h space-1 duration-fast ease-default */
5803
+ /* @ui:tokens color-bg-muted color-primary color-primary-fg color-border color-ring shadow-xs space-0h space-1 duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow switch-radius switch-width switch-height switch-thumb switch-travel switch-bg switch-thumb-shadow disabled-opacity */
5194
5804
 
5195
5805
  /* -- Label wrapper -- */
5196
5806
  [data-ui="switch-label"] {
@@ -5202,7 +5812,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5202
5812
 
5203
5813
  [data-ui="switch-label"]:has([data-ui="switch"]:disabled) {
5204
5814
  cursor: not-allowed;
5205
- opacity: 0.5;
5815
+ opacity: var(--disabled-opacity);
5206
5816
  }
5207
5817
 
5208
5818
  /* -- Base (track) -- */
@@ -5230,8 +5840,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5230
5840
  width: var(--switch-width, 44px);
5231
5841
  height: var(--switch-height, 24px);
5232
5842
  padding: var(--space-0h, 2px);
5233
- border: 1px solid var(--color-border);
5234
- border-radius: var(--radius-full);
5843
+ border: var(--border-width) solid var(--color-border);
5844
+ border-radius: var(--switch-radius);
5235
5845
  background: var(--switch-bg, var(--color-bg-muted));
5236
5846
  cursor: pointer;
5237
5847
  position: relative;
@@ -5241,8 +5851,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5241
5851
  }
5242
5852
 
5243
5853
  [data-ui="switch"]:focus-visible {
5244
- outline: 2px solid var(--color-ring);
5245
- outline-offset: 2px;
5854
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
5855
+ outline-offset: var(--focus-ring-offset);
5856
+ box-shadow: var(--focus-shadow);
5246
5857
  }
5247
5858
 
5248
5859
  /* -- Thumb (pseudo-element for <input>, child for custom markup) -- */
@@ -5251,7 +5862,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5251
5862
  display: block;
5252
5863
  width: var(--switch-thumb, 18px);
5253
5864
  height: var(--switch-thumb, 18px);
5254
- border-radius: var(--radius-full);
5865
+ border-radius: var(--switch-radius);
5255
5866
  background: var(--color-primary-fg);
5256
5867
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5257
5868
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5263,7 +5874,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5263
5874
  display: block;
5264
5875
  width: var(--switch-thumb, 18px);
5265
5876
  height: var(--switch-thumb, 18px);
5266
- border-radius: var(--radius-full);
5877
+ border-radius: var(--switch-radius);
5267
5878
  background: var(--color-primary-fg);
5268
5879
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5269
5880
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5345,7 +5956,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5345
5956
  the track's border is always visible, and ON fills it with `Highlight`. [W3-3] */
5346
5957
  @media (forced-colors: active) {
5347
5958
  [data-ui="switch"] {
5348
- border: 1px solid ButtonText;
5959
+ border: var(--border-width) solid ButtonText;
5349
5960
  background: ButtonFace;
5350
5961
  }
5351
5962
 
@@ -5502,25 +6113,31 @@ div[data-ui="separator"][data-style="thick"]::after {
5502
6113
 
5503
6114
  /* === primitives/text.css === */
5504
6115
  /* @ui:component text */
5505
- /* @ui:tokens color-fg color-fg-muted color-primary text-xs text-sm text-base text-lg text-xl text-2xl text-3xl text-4xl weight-normal weight-medium weight-semibold weight-bold leading-tight leading-snug leading-normal leading-relaxed font-sans font-mono */
6116
+ /* @ui:tokens color-fg color-fg-muted color-primary text-xs text-sm text-base text-lg text-xl text-2xl text-3xl text-4xl weight-normal weight-medium weight-semibold weight-bold leading-tight leading-snug leading-normal leading-relaxed font-heading font-body heading-weight heading-tracking heading-transform heading-caps heading-leading font-mono */
5506
6117
 
5507
6118
  /* ── Heading ── */
5508
6119
  [data-ui="heading"] {
5509
- font-family: var(--font-sans);
5510
- font-weight: var(--weight-bold);
6120
+ font-family: var(--font-heading);
6121
+ font-weight: var(--heading-weight);
5511
6122
  color: var(--color-fg);
5512
- line-height: var(--leading-tight);
5513
- letter-spacing: -0.01em;
6123
+ line-height: var(--heading-leading);
6124
+ text-transform: var(--heading-transform);
6125
+ font-variant-caps: var(--heading-caps);
6126
+ /* The optical tightening a large heading needs, PLUS whatever tracking the
6127
+ theme's voice asks for on top of it — so a theme that wants wide-tracked
6128
+ headings sets --heading-tracking once and every size follows, instead of
6129
+ each size having to re-derive its own number. */
6130
+ letter-spacing: calc(-0.01em + var(--heading-tracking));
5514
6131
  }
5515
6132
 
5516
6133
  [data-ui="heading"][data-size="1"] {
5517
6134
  font-size: var(--text-4xl);
5518
- letter-spacing: -0.02em;
6135
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5519
6136
  }
5520
6137
 
5521
6138
  [data-ui="heading"][data-size="2"] {
5522
6139
  font-size: var(--text-3xl);
5523
- letter-spacing: -0.02em;
6140
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5524
6141
  }
5525
6142
 
5526
6143
  [data-ui="heading"][data-size="3"] {
@@ -5544,7 +6161,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5544
6161
 
5545
6162
  /* ── Text ── */
5546
6163
  [data-ui="text"] {
5547
- font-family: var(--font-sans);
6164
+ font-family: var(--font-body);
5548
6165
  color: var(--color-fg);
5549
6166
  }
5550
6167
 
@@ -5622,7 +6239,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5622
6239
 
5623
6240
  /* === primitives/textarea.css === */
5624
6241
  /* @ui:component textarea */
5625
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 font-sans text-xs text-sm text-base duration-fast ease-default */
6242
+ /* @ui:tokens color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 font-ui text-xs text-sm text-base duration-fast ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-shadow input-border-width input-fill disabled-opacity */
5626
6243
 
5627
6244
  /* -- Base -- */
5628
6245
  [data-ui="textarea"] {
@@ -5630,11 +6247,17 @@ div[data-ui="separator"][data-style="thick"]::after {
5630
6247
  width: 100%;
5631
6248
  min-height: var(--textarea-min-height, 80px);
5632
6249
  padding: var(--space-2) var(--space-3);
5633
- border: 1px solid var(--color-border);
6250
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
6251
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
6252
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
6253
+ is drawn. Identical to the shorthand at every other value of the token. */
6254
+ border-style: solid;
6255
+ border-color: var(--color-border);
6256
+ border-width: var(--input-border-width);
5634
6257
  border-radius: var(--textarea-radius, var(--radius-md));
5635
- background: var(--textarea-bg, var(--color-bg));
6258
+ background: var(--textarea-bg, var(--input-fill));
5636
6259
  color: var(--color-fg);
5637
- font-family: var(--textarea-font, var(--font-sans));
6260
+ font-family: var(--textarea-font, var(--font-ui));
5638
6261
  font-size: var(--text-sm);
5639
6262
  line-height: 1.5;
5640
6263
  resize: vertical;
@@ -5651,8 +6274,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5651
6274
  }
5652
6275
 
5653
6276
  [data-ui="textarea"]:focus {
5654
- outline: 2px solid var(--color-ring);
5655
- outline-offset: -1px;
6277
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6278
+ /* The ring replaces the border rather than sitting outside it: inset by
6279
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
6280
+ outline-offset: calc(-1 * var(--input-border-width));
6281
+ box-shadow: var(--focus-shadow);
5656
6282
  border-color: transparent;
5657
6283
  }
5658
6284
 
@@ -5680,7 +6306,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5680
6306
  }
5681
6307
 
5682
6308
  [data-ui="textarea"]:disabled {
5683
- opacity: 0.5;
6309
+ opacity: var(--disabled-opacity);
5684
6310
  cursor: not-allowed;
5685
6311
  resize: none;
5686
6312
  }
@@ -5694,7 +6320,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5694
6320
 
5695
6321
  /* === primitives/toggle.css === */
5696
6322
  /* @ui:component toggle */
5697
- /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring radius-md space-1 space-1h space-2 space-3 space-4 text-xs text-sm text-base font-sans weight-medium duration-fast ease-default */
6323
+ /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring radius-md space-1 space-1h space-2 space-3 space-4 text-xs text-sm text-base font-ui weight-medium duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow disabled-opacity */
5698
6324
 
5699
6325
  /* ── Base (off / unpressed) ── */
5700
6326
  [data-ui="toggle"] {
@@ -5703,11 +6329,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5703
6329
  justify-content: center;
5704
6330
  gap: var(--space-1h);
5705
6331
  padding: var(--toggle-pad-y, var(--space-1h)) var(--toggle-pad-x, var(--space-3));
5706
- border: 1px solid var(--color-border);
6332
+ border: var(--border-width) solid var(--color-border);
5707
6333
  border-radius: var(--toggle-radius, var(--radius-md));
5708
6334
  background: var(--color-bg);
5709
6335
  color: var(--color-fg-muted);
5710
- font-family: var(--toggle-font, var(--font-sans));
6336
+ font-family: var(--toggle-font, var(--font-ui));
5711
6337
  font-size: var(--text-sm);
5712
6338
  font-weight: var(--weight-medium);
5713
6339
  line-height: 1;
@@ -5724,8 +6350,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5724
6350
  }
5725
6351
 
5726
6352
  [data-ui="toggle"]:focus-visible {
5727
- outline: 2px solid var(--color-ring);
5728
- outline-offset: 2px;
6353
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6354
+ outline-offset: var(--focus-ring-offset);
6355
+ box-shadow: var(--focus-shadow);
5729
6356
  }
5730
6357
 
5731
6358
  /* ── Pressed / on — styled entirely off aria-pressed, no JS ── */
@@ -5742,7 +6369,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5742
6369
 
5743
6370
  /* ── Disabled ── */
5744
6371
  [data-ui="toggle"]:disabled {
5745
- opacity: 0.5;
6372
+ opacity: var(--disabled-opacity);
5746
6373
  cursor: not-allowed;
5747
6374
  }
5748
6375
 
@@ -5766,7 +6393,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5766
6393
 
5767
6394
  /* === primitives/watermark.css === */
5768
6395
  /* @ui:component watermark */
5769
- /* @ui:tokens color-fg-muted doc-font font-sans text-xl text-2xl text-4xl weight-bold leading-tight space-8 space-20 z-raised */
6396
+ /* @ui:tokens color-fg-muted doc-font font-body text-xl text-2xl text-4xl weight-bold leading-tight space-8 space-20 z-raised */
5770
6397
 
5771
6398
  [data-ui="watermark"] {
5772
6399
  position: fixed;
@@ -5785,7 +6412,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5785
6412
 
5786
6413
  [data-ui="watermark"] > [data-part="mark"] {
5787
6414
  color: var(--color-fg-muted);
5788
- font-family: var(--doc-font, var(--font-sans));
6415
+ font-family: var(--doc-font, var(--font-body));
5789
6416
  font-size: var(--text-4xl);
5790
6417
  font-weight: var(--weight-bold);
5791
6418
  line-height: var(--leading-tight);
@@ -5843,7 +6470,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5843
6470
 
5844
6471
  /* === recipes/accordion.css === */
5845
6472
  /* @ui:component accordion */
5846
- /* @ui:tokens color-bg color-fg color-fg-muted color-border space-3 space-4 text-sm text-base weight-medium duration-normal ease-default radius-lg */
6473
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border space-3 space-4 text-sm text-base weight-medium duration-normal ease-default radius-lg font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
5847
6474
 
5848
6475
  /* ── Root ── */
5849
6476
  [data-ui="accordion"] {
@@ -5852,7 +6479,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5852
6479
 
5853
6480
  /* ── Item ── */
5854
6481
  [data-ui="accordion"] [data-part="item"] {
5855
- border-bottom: 1px solid var(--color-border);
6482
+ border-bottom: var(--border-width) solid var(--color-border);
5856
6483
  }
5857
6484
 
5858
6485
  [data-ui="accordion"] [data-part="item"]:last-child {
@@ -5869,7 +6496,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5869
6496
  border: none;
5870
6497
  background: transparent;
5871
6498
  color: var(--color-fg);
5872
- font-family: var(--font-sans, system-ui, sans-serif);
6499
+ font-family: var(--font-ui);
5873
6500
  font-size: var(--text-base);
5874
6501
  font-weight: var(--weight-medium);
5875
6502
  text-align: start;
@@ -5883,8 +6510,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5883
6510
  }
5884
6511
 
5885
6512
  [data-ui="accordion"] [data-part="trigger"]:focus-visible {
5886
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
5887
- outline-offset: -2px;
6513
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6514
+ outline-offset: calc(-1 * var(--focus-ring-offset));
5888
6515
  border-radius: var(--radius-sm, 0.25rem);
5889
6516
  }
5890
6517
 
@@ -5916,13 +6543,13 @@ div[data-ui="separator"][data-style="thick"]::after {
5916
6543
 
5917
6544
  /* ── Bordered Variant ── */
5918
6545
  [data-ui="accordion"][data-bordered="true"] {
5919
- border: 1px solid var(--color-border);
6546
+ border: var(--border-width) solid var(--color-border);
5920
6547
  border-radius: var(--radius-lg);
5921
6548
  overflow: hidden;
5922
6549
  }
5923
6550
 
5924
6551
  [data-ui="accordion"][data-bordered="true"] [data-part="item"] {
5925
- border-bottom: 1px solid var(--color-border);
6552
+ border-bottom: var(--border-width) solid var(--color-border);
5926
6553
  }
5927
6554
 
5928
6555
  [data-ui="accordion"][data-bordered="true"] [data-part="item"]:last-child {
@@ -5939,7 +6566,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5939
6566
 
5940
6567
  /* === recipes/alert-dialog.css === */
5941
6568
  /* @ui:component alert-dialog */
5942
- /* @ui:tokens radius-xl shadow-xl space-2 space-3 space-6 color-bg color-fg color-border color-fg-muted color-destructive duration-normal ease-default ease-out z-overlay z-modal */
6569
+ /* @ui:tokens radius-xl shadow-xl space-2 space-3 space-6 color-bg color-fg color-border color-fg-muted color-destructive duration-normal ease-default ease-out z-overlay z-modal font-heading border-width */
5943
6570
 
5944
6571
  /* ── Root ── */
5945
6572
  [data-ui="alert-dialog"] {
@@ -5975,7 +6602,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5975
6602
  max-height: 85vh;
5976
6603
  overflow-y: auto;
5977
6604
  background: var(--color-bg);
5978
- border: 1px solid var(--color-border);
6605
+ border: var(--border-width) solid var(--color-border);
5979
6606
  border-radius: var(--alert-dialog-radius, var(--radius-xl));
5980
6607
  box-shadow: var(--alert-dialog-shadow, var(--shadow-xl));
5981
6608
  opacity: 0;
@@ -6021,6 +6648,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6021
6648
  /* ── Title ── */
6022
6649
  [data-ui="alert-dialog"] [data-part="title"] {
6023
6650
  margin: 0;
6651
+ font-family: var(--font-heading);
6024
6652
  font-size: var(--text-lg, 1.125rem);
6025
6653
  font-weight: var(--weight-semibold, 600);
6026
6654
  color: var(--color-fg);
@@ -6060,7 +6688,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6060
6688
 
6061
6689
  /* === recipes/barcode.css === */
6062
6690
  /* @ui:component barcode */
6063
- /* @ui:tokens color-fg color-bg color-fg-muted doc-font doc-legal-color doc-legal-size font-mono font-sans space-2 space-12 space-16 space-20 */
6691
+ /* @ui:tokens color-fg color-bg color-fg-muted doc-font doc-legal-color doc-legal-size font-mono font-body space-2 space-12 space-16 space-20 */
6064
6692
 
6065
6693
  [data-ui="barcode"] {
6066
6694
  display: inline-flex;
@@ -6087,7 +6715,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6087
6715
 
6088
6716
  [data-ui="barcode"] > [data-part="caption"] {
6089
6717
  color: var(--doc-legal-color, var(--color-fg-muted));
6090
- font-family: var(--font-mono, var(--doc-font, var(--font-sans)));
6718
+ font-family: var(--font-mono, var(--doc-font, var(--font-body)));
6091
6719
  font-size: var(--doc-legal-size);
6092
6720
  line-height: var(--leading-normal);
6093
6721
  text-align: center;
@@ -6107,7 +6735,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6107
6735
 
6108
6736
  /* === recipes/calendar.css === */
6109
6737
  /* @ui:component calendar */
6110
- /* @ui:tokens color-bg color-fg color-fg-muted color-fg-subtle color-border color-primary color-primary-fg color-primary-subtle color-ring radius-md radius-full space-0 space-1 space-2 text-xs text-sm text-base weight-medium duration-fast ease-default */
6738
+ /* @ui:tokens color-bg color-fg color-fg-muted color-fg-subtle color-border color-primary color-primary-fg color-primary-subtle color-ring radius-md radius-full space-0 space-1 space-2 text-xs text-sm text-base weight-medium duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */
6111
6739
 
6112
6740
  /* ── Root ── */
6113
6741
  [data-ui="calendar"] {
@@ -6140,7 +6768,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6140
6768
  width: 28px;
6141
6769
  height: 28px;
6142
6770
  padding: 0;
6143
- border: 1px solid var(--color-border);
6771
+ border: var(--border-width) solid var(--color-border);
6144
6772
  border-radius: var(--radius-md);
6145
6773
  background: var(--color-bg);
6146
6774
  color: var(--color-fg);
@@ -6156,13 +6784,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6156
6784
 
6157
6785
  [data-ui="calendar"] [data-part="nav-prev"]:focus-visible,
6158
6786
  [data-ui="calendar"] [data-part="nav-next"]:focus-visible {
6159
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6160
- outline-offset: 2px;
6787
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6788
+ outline-offset: var(--focus-ring-offset);
6161
6789
  }
6162
6790
 
6163
6791
  [data-ui="calendar"] [data-part="nav-prev"]:disabled,
6164
6792
  [data-ui="calendar"] [data-part="nav-next"]:disabled {
6165
- opacity: 0.4;
6793
+ /* Dimmer than a disabled control — 0.4 at the 0.5 default — and it follows a
6794
+ theme's `--disabled-opacity` like every other disabled dim (1.1A-27). */
6795
+ opacity: calc(var(--disabled-opacity) * 0.8);
6166
6796
  cursor: not-allowed;
6167
6797
  }
6168
6798
 
@@ -6197,11 +6827,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6197
6827
  width: 36px;
6198
6828
  height: 36px;
6199
6829
  padding: 0;
6200
- border: 1px solid transparent;
6830
+ border: var(--border-width) solid transparent;
6201
6831
  border-radius: var(--radius-full);
6202
6832
  background: transparent;
6203
6833
  color: var(--color-fg);
6204
- font-family: var(--font-sans, system-ui, sans-serif);
6834
+ font-family: var(--font-ui);
6205
6835
  font-size: var(--text-sm);
6206
6836
  cursor: pointer;
6207
6837
  transition: background var(--duration-fast) var(--ease-default),
@@ -6214,8 +6844,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6214
6844
  }
6215
6845
 
6216
6846
  [data-ui="calendar"] [data-part="day"]:focus-visible {
6217
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6218
- outline-offset: 2px;
6847
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6848
+ outline-offset: var(--focus-ring-offset);
6219
6849
  }
6220
6850
 
6221
6851
  /* ── Today ── */
@@ -6250,7 +6880,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6250
6880
  /* ── Disabled days (aria-disabled keeps them focusable; :disabled for hard-disabled) ── */
6251
6881
  [data-ui="calendar"] [data-part="day"][aria-disabled="true"],
6252
6882
  [data-ui="calendar"] [data-part="day"]:disabled {
6253
- opacity: 0.5;
6883
+ opacity: var(--disabled-opacity);
6254
6884
  cursor: not-allowed;
6255
6885
  text-decoration: line-through;
6256
6886
  }
@@ -6314,7 +6944,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6314
6944
 
6315
6945
  /* === recipes/carousel.css === */
6316
6946
  /* @ui:component carousel */
6317
- /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-ring radius-md radius-lg space-1 space-2 space-3 space-4 text-sm font-sans duration-fast ease-default */
6947
+ /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-ring radius-md radius-lg space-1 space-2 space-3 space-4 text-sm font-ui duration-fast ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */
6318
6948
 
6319
6949
  /* The sliding is CSS, not JavaScript: the viewport is a scroll-snap strip and
6320
6950
  every slide is a snap target. Everything below works with no controller
@@ -6328,7 +6958,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6328
6958
  inline-size: 100%;
6329
6959
  min-inline-size: 0;
6330
6960
  max-inline-size: 100%;
6331
- font-family: var(--carousel-font, var(--font-sans));
6961
+ font-family: var(--carousel-font, var(--font-ui));
6332
6962
  }
6333
6963
 
6334
6964
  /* ── Viewport: the scroll-snap strip ── */
@@ -6354,8 +6984,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6354
6984
  }
6355
6985
 
6356
6986
  [data-ui="carousel"] [data-part="viewport"]:focus-visible {
6357
- outline: 2px solid var(--color-ring);
6358
- outline-offset: 2px;
6987
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6988
+ outline-offset: var(--focus-ring-offset);
6359
6989
  }
6360
6990
 
6361
6991
  /* ── Slide: one full-width snap target ── */
@@ -6363,7 +6993,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6363
6993
  flex: 0 0 var(--carousel-slide-size, 100%);
6364
6994
  min-inline-size: 0;
6365
6995
  padding: var(--space-4);
6366
- border: 1px solid var(--color-border);
6996
+ border: var(--border-width) solid var(--color-border);
6367
6997
  border-radius: var(--radius-lg);
6368
6998
  background: var(--color-bg);
6369
6999
  color: var(--color-fg);
@@ -6392,7 +7022,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6392
7022
  min-inline-size: 2rem;
6393
7023
  min-block-size: 2rem;
6394
7024
  padding: var(--space-1) var(--space-2);
6395
- border: 1px solid var(--color-border);
7025
+ border: var(--border-width) solid var(--color-border);
6396
7026
  border-radius: var(--radius-md);
6397
7027
  background: var(--color-bg);
6398
7028
  color: var(--color-fg);
@@ -6411,14 +7041,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6411
7041
  [data-ui="carousel"] [data-part="prev"]:focus-visible,
6412
7042
  [data-ui="carousel"] [data-part="next"]:focus-visible,
6413
7043
  [data-ui="carousel"] [data-part="dot"]:focus-visible {
6414
- outline: 2px solid var(--color-ring);
6415
- outline-offset: 2px;
7044
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7045
+ outline-offset: var(--focus-ring-offset);
6416
7046
  }
6417
7047
 
6418
7048
  /* Boundary contract "stop" — the controller disables the end button. */
6419
7049
  [data-ui="carousel"] [data-part="prev"]:disabled,
6420
7050
  [data-ui="carousel"] [data-part="next"]:disabled {
6421
- opacity: 0.4;
7051
+ /* 0.4 at the 0.5 default, and a theme's `--disabled-opacity` moves it (1.1A-27). */
7052
+ opacity: calc(var(--disabled-opacity) * 0.8);
6422
7053
  cursor: not-allowed;
6423
7054
  }
6424
7055
 
@@ -6427,7 +7058,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6427
7058
  inline-size: 0.625rem;
6428
7059
  block-size: 0.625rem;
6429
7060
  padding: 0;
6430
- border: 1px solid var(--color-border);
7061
+ border: var(--border-width) solid var(--color-border);
6431
7062
  border-radius: 50%;
6432
7063
  background: var(--color-bg-muted);
6433
7064
  cursor: pointer;
@@ -6463,7 +7094,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6463
7094
 
6464
7095
  /* === recipes/combobox.css === */
6465
7096
  /* @ui:component combobox */
6466
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle color-ring radius-md radius-lg shadow-md space-1 space-2 space-3 text-sm text-base z-dropdown duration-fast ease-default */
7097
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle radius-md radius-lg shadow-md space-1 space-2 space-3 text-sm text-base z-dropdown duration-fast ease-default font-ui border-width focus-ring-color focus-ring-width */
6467
7098
 
6468
7099
  /* ── Root ── */
6469
7100
  [data-ui="combobox"] {
@@ -6477,11 +7108,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6477
7108
  display: block;
6478
7109
  width: 100%;
6479
7110
  padding: var(--space-2) var(--space-3);
6480
- border: 1px solid var(--color-border);
7111
+ border: var(--border-width) solid var(--color-border);
6481
7112
  border-radius: var(--radius-md);
6482
7113
  background: var(--color-bg);
6483
7114
  color: var(--color-fg);
6484
- font-family: var(--font-sans, system-ui, sans-serif);
7115
+ font-family: var(--font-ui);
6485
7116
  font-size: var(--text-sm);
6486
7117
  line-height: 1.5;
6487
7118
  outline: none;
@@ -6494,8 +7125,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6494
7125
  }
6495
7126
 
6496
7127
  [data-ui="combobox"] [data-part="input"]:focus {
6497
- border-color: var(--color-ring, oklch(0.55 0.22 264));
6498
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
7128
+ border-color: var(--focus-ring-color);
7129
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
6499
7130
  }
6500
7131
 
6501
7132
  /* ── Listbox ── */
@@ -6507,7 +7138,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6507
7138
  z-index: var(--z-dropdown);
6508
7139
  margin-top: var(--space-1);
6509
7140
  padding: var(--space-1);
6510
- border: 1px solid var(--color-border);
7141
+ border: var(--border-width) solid var(--color-border);
6511
7142
  border-radius: var(--radius-lg);
6512
7143
  background: var(--color-bg);
6513
7144
  box-shadow: var(--shadow-md);
@@ -6592,7 +7223,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6592
7223
 
6593
7224
  /* === recipes/command-palette.css === */
6594
7225
  /* @ui:component command-palette */
6595
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle color-bg-muted shadow-xl radius-xl space-2 space-3 space-4 text-sm text-xs text-base weight-medium font-mono z-overlay z-modal duration-fast duration-normal ease-out */
7226
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle color-bg-muted shadow-xl radius-xl space-2 space-3 space-4 text-sm text-xs text-base weight-medium font-mono z-overlay z-modal duration-fast duration-normal ease-out font-ui border-width */
6596
7227
 
6597
7228
  /* ── Root ── */
6598
7229
  [data-ui="command-palette"] {
@@ -6625,7 +7256,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6625
7256
  display: flex;
6626
7257
  flex-direction: column;
6627
7258
  background: var(--color-bg);
6628
- border: 1px solid var(--color-border);
7259
+ border: var(--border-width) solid var(--color-border);
6629
7260
  border-radius: var(--radius-xl);
6630
7261
  box-shadow: var(--shadow-xl);
6631
7262
  overflow: hidden;
@@ -6657,7 +7288,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6657
7288
  display: flex;
6658
7289
  align-items: center;
6659
7290
  padding: var(--space-3) var(--space-4);
6660
- border-bottom: 1px solid var(--color-border);
7291
+ border-bottom: var(--border-width) solid var(--color-border);
6661
7292
  }
6662
7293
 
6663
7294
  /* ── Search Input ── */
@@ -6667,7 +7298,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6667
7298
  border: none;
6668
7299
  background: transparent;
6669
7300
  color: var(--color-fg);
6670
- font-family: var(--font-sans, system-ui, sans-serif);
7301
+ font-family: var(--font-ui);
6671
7302
  font-size: var(--text-base);
6672
7303
  outline: none;
6673
7304
  }
@@ -6751,7 +7382,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6751
7382
  align-items: center;
6752
7383
  gap: var(--space-1, 0.25rem);
6753
7384
  padding: var(--space-1, 0.25rem) var(--space-2);
6754
- border: 1px solid var(--color-border);
7385
+ border: var(--border-width) solid var(--color-border);
6755
7386
  border-radius: var(--radius-sm, 0.25rem);
6756
7387
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
6757
7388
  color: var(--color-fg-muted);
@@ -6780,7 +7411,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6780
7411
 
6781
7412
  /* === recipes/context-menu.css === */
6782
7413
  /* @ui:component context-menu */
6783
- /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring space-px space-1 space-2 space-3 space-4 space-20 radius-md radius-lg shadow-md text-sm weight-medium font-sans duration-fast ease-out z-dropdown */
7414
+ /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring space-px space-1 space-2 space-3 space-4 space-20 radius-md radius-lg shadow-md text-sm weight-medium font-ui duration-fast ease-out z-dropdown focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */
6784
7415
 
6785
7416
  [data-ui="context-menu"] {
6786
7417
  position: relative;
@@ -6793,12 +7424,12 @@ div[data-ui="separator"][data-style="thick"]::after {
6793
7424
  border-radius: var(--radius-lg);
6794
7425
  background: var(--color-bg-muted);
6795
7426
  color: var(--color-fg);
6796
- font-family: var(--font-sans, system-ui, sans-serif);
7427
+ font-family: var(--font-ui);
6797
7428
  }
6798
7429
 
6799
7430
  [data-ui="context-menu"] [data-part="target"]:focus-visible {
6800
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6801
- outline-offset: var(--space-1);
7431
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7432
+ outline-offset: var(--focus-ring-offset);
6802
7433
  }
6803
7434
 
6804
7435
  [data-ui="context-menu"] [data-part="menu"] {
@@ -6830,7 +7461,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6830
7461
  border-radius: var(--radius-md);
6831
7462
  background: transparent;
6832
7463
  color: var(--color-fg);
6833
- font-family: var(--font-sans, system-ui, sans-serif);
7464
+ font-family: var(--font-ui);
6834
7465
  font-size: var(--text-sm);
6835
7466
  font-weight: var(--weight-medium);
6836
7467
  text-align: start;
@@ -6854,15 +7485,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6854
7485
  focus additionally draws the ring, inset so it does not overlap the item
6855
7486
  above. [W3-3] */
6856
7487
  [data-ui="context-menu"] [data-part="item"]:focus-visible {
6857
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6858
- outline-offset: calc(var(--space-px) * -2);
7488
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7489
+ outline-offset: calc(-1 * var(--focus-ring-offset));
6859
7490
  }
6860
7491
 
6861
7492
  [data-ui="context-menu"] [data-part="item"]:disabled,
6862
7493
  [data-ui="context-menu"] [data-part="item"][aria-disabled="true"] {
6863
7494
  color: var(--color-fg-muted);
6864
7495
  cursor: not-allowed;
6865
- opacity: 0.5;
7496
+ opacity: var(--disabled-opacity);
6866
7497
  }
6867
7498
 
6868
7499
  [data-ui="context-menu"] [data-part="separator"] {
@@ -6881,7 +7512,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6881
7512
 
6882
7513
  /* === recipes/date-picker.css === */
6883
7514
  /* @ui:component date-picker */
6884
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-ring shadow-lg radius-md radius-lg space-1 space-2 space-3 space-4 text-xs text-sm z-dropdown duration-fast ease-default */
7515
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-ring shadow-lg radius-md radius-lg space-1 space-2 space-3 space-4 text-xs text-sm z-dropdown duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
6885
7516
  /* The month grid inside the popup is the `calendar` recipe — see calendar.css */
6886
7517
 
6887
7518
  /* ── Root ── */
@@ -6902,11 +7533,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6902
7533
  width: 100%;
6903
7534
  padding: var(--space-2, 0.5rem) var(--space-3);
6904
7535
  padding-inline-end: var(--space-8, 2.5rem);
6905
- border: 1px solid var(--color-border);
7536
+ border: var(--border-width) solid var(--color-border);
6906
7537
  border-radius: var(--radius-md);
6907
7538
  background: var(--color-bg);
6908
7539
  color: var(--color-fg);
6909
- font-family: var(--font-sans, system-ui, sans-serif);
7540
+ font-family: var(--font-ui);
6910
7541
  font-size: var(--text-sm);
6911
7542
  line-height: 1.5;
6912
7543
  cursor: pointer;
@@ -6918,8 +7549,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6918
7549
  }
6919
7550
 
6920
7551
  [data-ui="date-picker"] [data-part="input"]:focus-visible {
6921
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6922
- outline-offset: 2px;
7552
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7553
+ outline-offset: var(--focus-ring-offset);
6923
7554
  border-color: var(--color-primary);
6924
7555
  }
6925
7556
 
@@ -6942,7 +7573,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6942
7573
  z-index: var(--z-dropdown);
6943
7574
  margin-top: var(--space-1);
6944
7575
  padding: var(--space-3);
6945
- border: 1px solid var(--color-border);
7576
+ border: var(--border-width) solid var(--color-border);
6946
7577
  border-radius: var(--radius-lg);
6947
7578
  background: var(--color-bg);
6948
7579
  box-shadow: var(--shadow-lg);
@@ -6981,7 +7612,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6981
7612
 
6982
7613
  /* === recipes/dialog.css === */
6983
7614
  /* @ui:component dialog */
6984
- /* @ui:tokens radius-xl shadow-xl space-4 space-6 space-8 color-bg color-fg color-border color-fg-muted duration-normal duration-slow ease-default ease-out z-overlay z-modal */
7615
+ /* @ui:tokens radius-xl shadow-xl space-4 space-6 space-8 color-bg panel-bg color-fg color-border color-fg-muted duration-normal duration-slow ease-default ease-out z-overlay z-modal font-heading corner-shape border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop */
6985
7616
 
6986
7617
  /* ── Root ── */
6987
7618
  [data-ui="dialog"] {
@@ -7016,15 +7647,23 @@ div[data-ui="separator"][data-style="thick"]::after {
7016
7647
  width: 90%;
7017
7648
  max-height: 85vh;
7018
7649
  overflow-y: auto;
7019
- background: var(--color-bg);
7020
- border: 1px solid var(--color-border);
7650
+ background: var(--panel-bg);
7651
+ border: var(--border-width) solid var(--color-border);
7021
7652
  border-radius: var(--dialog-radius, var(--radius-xl));
7653
+ corner-shape: var(--corner-shape);
7022
7654
  box-shadow: var(--dialog-shadow, var(--shadow-xl));
7023
7655
  opacity: 0;
7024
7656
  transition: opacity var(--duration-normal) var(--ease-out),
7025
7657
  transform var(--duration-normal) var(--ease-out);
7026
7658
  }
7027
7659
 
7660
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7661
+ [data-ui="dialog"] [data-part="panel"] {
7662
+ -webkit-backdrop-filter: var(--surface-backdrop);
7663
+ backdrop-filter: var(--surface-backdrop);
7664
+ }
7665
+ }
7666
+
7028
7667
  [data-ui="dialog"][data-state="open"] [data-part="panel"] {
7029
7668
  opacity: 1;
7030
7669
  transform: translate(-50%, -50%) scale(1);
@@ -7073,6 +7712,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7073
7712
  /* ── Title ── */
7074
7713
  [data-ui="dialog"] [data-part="title"] {
7075
7714
  margin: 0;
7715
+ font-family: var(--font-heading);
7076
7716
  font-size: var(--text-lg, 1.125rem);
7077
7717
  font-weight: var(--weight-semibold, 600);
7078
7718
  color: var(--color-fg);
@@ -7107,8 +7747,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7107
7747
  }
7108
7748
 
7109
7749
  [data-ui="dialog"] [data-part="close"]:not([data-ui]):focus-visible {
7110
- outline: 2px solid var(--color-ring);
7111
- outline-offset: 2px;
7750
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7751
+ outline-offset: var(--focus-ring-offset);
7112
7752
  }
7113
7753
 
7114
7754
  /* ── Description ── */
@@ -7144,7 +7784,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7144
7784
 
7145
7785
  /* === recipes/drawer.css === */
7146
7786
  /* @ui:component drawer */
7147
- /* @ui:tokens color-bg color-fg color-border shadow-xl space-4 space-6 radius-none z-overlay z-modal duration-normal duration-slow ease-out ease-default */
7787
+ /* @ui:tokens color-bg panel-bg color-fg color-border shadow-xl space-4 space-6 radius-none z-overlay z-modal duration-normal duration-slow ease-out ease-default font-heading border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop */
7148
7788
 
7149
7789
  /* ── Root ── */
7150
7790
  [data-ui="drawer"] {
@@ -7179,17 +7819,24 @@ div[data-ui="separator"][data-style="thick"]::after {
7179
7819
  flex-direction: column;
7180
7820
  width: var(--drawer-width, 400px);
7181
7821
  max-width: 100vw;
7182
- background: var(--color-bg);
7822
+ background: var(--panel-bg);
7183
7823
  border: none;
7184
7824
  box-shadow: var(--drawer-shadow, var(--shadow-xl));
7185
7825
  transition: transform var(--duration-slow) var(--ease-out);
7186
7826
  }
7187
7827
 
7828
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7829
+ [data-ui="drawer"] [data-part="panel"] {
7830
+ -webkit-backdrop-filter: var(--surface-backdrop);
7831
+ backdrop-filter: var(--surface-backdrop);
7832
+ }
7833
+ }
7834
+
7188
7835
  /* ── Side Variants ── */
7189
7836
  [data-ui="drawer"] [data-part="panel"][data-variant="left"] {
7190
7837
  inset-inline-start: 0;
7191
7838
  inset-inline-end: auto;
7192
- border-inline-end: 1px solid var(--color-border);
7839
+ border-inline-end: var(--border-width) solid var(--color-border);
7193
7840
  border-radius: 0 var(--radius-none, 0) var(--radius-none, 0) 0;
7194
7841
  transform: translateX(-100%);
7195
7842
  }
@@ -7197,7 +7844,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7197
7844
  [data-ui="drawer"] [data-part="panel"][data-variant="right"] {
7198
7845
  inset-inline-end: 0;
7199
7846
  inset-inline-start: auto;
7200
- border-inline-start: 1px solid var(--color-border);
7847
+ border-inline-start: var(--border-width) solid var(--color-border);
7201
7848
  border-radius: var(--radius-none, 0) 0 0 var(--radius-none, 0);
7202
7849
  transform: translateX(100%);
7203
7850
  }
@@ -7251,6 +7898,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7251
7898
  /* ── Title ── */
7252
7899
  [data-ui="drawer"] [data-part="title"] {
7253
7900
  margin: 0;
7901
+ font-family: var(--font-heading);
7254
7902
  font-size: var(--text-lg, 1.125rem);
7255
7903
  font-weight: var(--weight-semibold, 600);
7256
7904
  color: var(--color-fg);
@@ -7285,8 +7933,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7285
7933
  }
7286
7934
 
7287
7935
  [data-ui="drawer"] [data-part="close"]:not([data-ui]):focus-visible {
7288
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7289
- outline-offset: 2px;
7936
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7937
+ outline-offset: var(--focus-ring-offset);
7290
7938
  }
7291
7939
 
7292
7940
  /* ── Body ── */
@@ -7305,7 +7953,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7305
7953
  gap: var(--space-3, 0.75rem);
7306
7954
  padding: var(--space-6);
7307
7955
  padding-top: var(--space-4);
7308
- border-top: 1px solid var(--color-border);
7956
+ border-top: var(--border-width) solid var(--color-border);
7309
7957
  flex-shrink: 0;
7310
7958
  }
7311
7959
 
@@ -7319,7 +7967,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7319
7967
 
7320
7968
  /* === recipes/dropdown.css === */
7321
7969
  /* @ui:component dropdown */
7322
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle color-primary space-1 space-2 space-3 space-4 radius-md radius-lg shadow-md text-sm weight-medium duration-fast ease-default ease-out z-dropdown */
7970
+ /* @ui:tokens color-bg panel-bg color-fg color-fg-muted color-border color-primary-subtle color-primary space-1 space-2 space-3 space-4 radius-md radius-lg shadow-md text-sm weight-medium duration-fast ease-default ease-out z-dropdown font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop disabled-opacity */
7323
7971
 
7324
7972
  /* ── Root ── */
7325
7973
  [data-ui="dropdown"] {
@@ -7333,11 +7981,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7333
7981
  align-items: center;
7334
7982
  gap: var(--space-2);
7335
7983
  padding: var(--space-2) var(--space-3);
7336
- border: 1px solid var(--color-border);
7984
+ border: var(--border-width) solid var(--color-border);
7337
7985
  border-radius: var(--radius-md);
7338
7986
  background: var(--color-bg);
7339
7987
  color: var(--color-fg);
7340
- font-family: var(--font-sans, system-ui, sans-serif);
7988
+ font-family: var(--font-ui);
7341
7989
  font-size: var(--text-sm);
7342
7990
  font-weight: var(--weight-medium);
7343
7991
  cursor: pointer;
@@ -7351,8 +7999,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7351
7999
  }
7352
8000
 
7353
8001
  [data-ui="dropdown"] [data-part="trigger"]:focus-visible {
7354
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7355
- outline-offset: 2px;
8002
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8003
+ outline-offset: var(--focus-ring-offset);
7356
8004
  }
7357
8005
 
7358
8006
  /* ── Menu ── */
@@ -7364,9 +8012,9 @@ div[data-ui="separator"][data-style="thick"]::after {
7364
8012
  min-width: 180px;
7365
8013
  margin-top: var(--space-1);
7366
8014
  padding: var(--space-1);
7367
- border: 1px solid var(--color-border);
8015
+ border: var(--border-width) solid var(--color-border);
7368
8016
  border-radius: var(--radius-lg);
7369
- background: var(--color-bg);
8017
+ background: var(--panel-bg);
7370
8018
  box-shadow: var(--shadow-md);
7371
8019
  opacity: 0;
7372
8020
  transform: translateY(-4px);
@@ -7374,6 +8022,13 @@ div[data-ui="separator"][data-style="thick"]::after {
7374
8022
  transform var(--duration-fast) var(--ease-out);
7375
8023
  }
7376
8024
 
8025
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
8026
+ [data-ui="dropdown"] [data-part="menu"] {
8027
+ -webkit-backdrop-filter: var(--surface-backdrop);
8028
+ backdrop-filter: var(--surface-backdrop);
8029
+ }
8030
+ }
8031
+
7377
8032
  [data-ui="dropdown"][data-state="open"] [data-part="menu"] {
7378
8033
  opacity: 1;
7379
8034
  transform: translateY(0);
@@ -7396,7 +8051,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7396
8051
  border-radius: var(--radius-md);
7397
8052
  background: transparent;
7398
8053
  color: var(--color-fg);
7399
- font-family: var(--font-sans, system-ui, sans-serif);
8054
+ font-family: var(--font-ui);
7400
8055
  font-size: var(--text-sm);
7401
8056
  text-align: start;
7402
8057
  cursor: pointer;
@@ -7418,12 +8073,12 @@ div[data-ui="separator"][data-style="thick"]::after {
7418
8073
  focus additionally draws the ring, inset so it does not overlap the item
7419
8074
  above. [W3-3] */
7420
8075
  [data-ui="dropdown"] [data-part="item"]:focus-visible {
7421
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7422
- outline-offset: -2px;
8076
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8077
+ outline-offset: calc(-1 * var(--focus-ring-offset));
7423
8078
  }
7424
8079
 
7425
8080
  [data-ui="dropdown"] [data-part="item"]:disabled {
7426
- opacity: 0.5;
8081
+ opacity: var(--disabled-opacity);
7427
8082
  cursor: not-allowed;
7428
8083
  pointer-events: none;
7429
8084
  }
@@ -7476,14 +8131,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7476
8131
 
7477
8132
  /* === recipes/file-upload.css === */
7478
8133
  /* @ui:component file-upload */
7479
- /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-border-strong color-primary color-primary-subtle color-ring color-destructive color-destructive-subtle space-px space-1 space-2 space-3 space-4 space-8 radius-md radius-lg text-xs text-sm text-base weight-semibold font-sans duration-fast ease-default */
8134
+ /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-border-strong color-primary color-primary-subtle color-ring color-destructive color-destructive-subtle space-px space-1 space-2 space-3 space-4 space-8 radius-md radius-lg text-xs text-sm text-base weight-semibold font-ui duration-fast ease-default focus-ring-width focus-ring-style focus-ring-color focus-ring-offset border-width disabled-opacity */
7480
8135
 
7481
8136
  [data-ui="file-upload"] {
7482
8137
  display: grid;
7483
8138
  gap: var(--space-4);
7484
8139
  inline-size: 100%;
7485
8140
  color: var(--color-fg);
7486
- font-family: var(--font-sans);
8141
+ font-family: var(--font-ui);
7487
8142
  }
7488
8143
 
7489
8144
  [data-ui="file-upload"] [data-part="dropzone"] {
@@ -7518,14 +8173,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7518
8173
  }
7519
8174
 
7520
8175
  [data-ui="file-upload"]:has([data-part="input"]:focus-visible) [data-part="dropzone"] {
7521
- outline: var(--space-px) solid var(--color-ring);
7522
- outline-offset: var(--space-1);
8176
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8177
+ outline-offset: var(--focus-ring-offset);
7523
8178
  }
7524
8179
 
7525
8180
  [data-ui="file-upload"][data-state="dragging"] [data-part="dropzone"] {
7526
8181
  border-color: var(--color-primary);
7527
8182
  background: var(--color-primary-subtle);
7528
- box-shadow: 0 0 0 var(--space-px) var(--color-primary);
8183
+ box-shadow: 0 0 0 var(--border-width) var(--color-primary);
7529
8184
  }
7530
8185
 
7531
8186
  [data-ui="file-upload"] [data-part="prompt"] {
@@ -7599,8 +8254,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7599
8254
  }
7600
8255
 
7601
8256
  [data-ui="file-upload"] [data-part="remove"]:focus-visible {
7602
- outline: var(--space-px) solid var(--color-ring);
7603
- outline-offset: var(--space-1);
8257
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8258
+ outline-offset: var(--focus-ring-offset);
7604
8259
  }
7605
8260
 
7606
8261
  [data-ui="file-upload"] [data-part="empty"] {
@@ -7622,7 +8277,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7622
8277
  }
7623
8278
 
7624
8279
  [data-ui="file-upload"][data-disabled] {
7625
- opacity: 0.5;
8280
+ opacity: var(--disabled-opacity);
7626
8281
  }
7627
8282
 
7628
8283
  [data-ui="file-upload"][data-disabled] [data-part="dropzone"],
@@ -7638,7 +8293,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7638
8293
 
7639
8294
  /* === recipes/input-otp.css === */
7640
8295
  /* @ui:component input-otp */
7641
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-border-strong color-ring color-primary color-destructive radius-md space-2 space-3 text-base text-lg font-sans duration-fast ease-default */
8296
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-border-strong color-ring color-primary color-destructive radius-md space-2 space-3 text-base text-lg font-ui duration-fast ease-default border-width disabled-opacity */
7642
8297
 
7643
8298
  /* ── Root ── */
7644
8299
  [data-ui="input-otp"] {
@@ -7653,7 +8308,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7653
8308
  gutter. The transparent input is `inset: 0`, so it follows the box the
7654
8309
  segments settle into however many rows that takes. */
7655
8310
  max-inline-size: 100%;
7656
- font-family: var(--font-sans, system-ui, sans-serif);
8311
+ font-family: var(--font-ui);
7657
8312
  }
7658
8313
 
7659
8314
  /* ── Real input ──
@@ -7698,14 +8353,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7698
8353
  justify-content: center;
7699
8354
  inline-size: var(--input-otp-segment-size);
7700
8355
  block-size: var(--input-otp-segment-size);
7701
- border: 1px solid var(--color-border);
8356
+ border: var(--border-width) solid var(--color-border);
7702
8357
  border-radius: var(--radius-md);
7703
8358
  background: var(--color-bg);
7704
8359
  color: var(--color-fg);
7705
8360
  font-size: var(--text-lg, 1.125rem);
7706
8361
  font-variant-numeric: tabular-nums;
7707
8362
  line-height: 1;
7708
- transition: border-color var(--duration-fast, 120ms) var(--ease-default, ease),
8363
+ transition: border-color var(--duration-fast) var(--ease-default),
7709
8364
  box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
7710
8365
  }
7711
8366
 
@@ -7717,7 +8372,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7717
8372
  /* Active (caret / selected) segment while focused */
7718
8373
  [data-ui="input-otp"] [data-part="segment"][data-active] {
7719
8374
  border-color: var(--color-ring);
7720
- box-shadow: 0 0 0 1px var(--color-ring);
8375
+ box-shadow: 0 0 0 var(--border-width) var(--color-ring);
7721
8376
  }
7722
8377
 
7723
8378
  /* Blinking caret in the next-to-fill empty slot */
@@ -7765,7 +8420,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7765
8420
 
7766
8421
  /* ── Disabled ── */
7767
8422
  [data-ui="input-otp"][data-disabled] {
7768
- opacity: 0.5;
8423
+ opacity: var(--disabled-opacity);
7769
8424
  cursor: not-allowed;
7770
8425
  }
7771
8426
  [data-ui="input-otp"][data-disabled] [data-part="input"] {
@@ -7789,7 +8444,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7789
8444
 
7790
8445
  /* === recipes/menubar.css === */
7791
8446
  /* @ui:component menubar */
7792
- /* @ui:tokens color-bg color-border color-fg color-fg-muted color-primary color-primary-subtle color-ring space-px space-1 space-2 space-3 space-4 space-20 radius-md radius-lg shadow-md text-xs text-sm text-base weight-medium duration-fast ease-out z-dropdown font-sans */
8447
+ /* @ui:tokens color-bg color-border color-fg color-fg-muted color-primary color-primary-subtle space-px space-1 space-2 space-3 space-4 space-20 radius-md radius-lg shadow-md text-xs text-sm text-base weight-medium duration-fast ease-out z-dropdown font-ui focus-ring-color focus-ring-width disabled-opacity */
7793
8448
 
7794
8449
  [data-ui="menubar"] {
7795
8450
  position: relative;
@@ -7807,7 +8462,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7807
8462
  border-radius: var(--radius-lg);
7808
8463
  background: var(--color-bg);
7809
8464
  color: var(--color-fg);
7810
- font-family: var(--font-sans);
8465
+ font-family: var(--font-ui);
7811
8466
  }
7812
8467
 
7813
8468
  [data-ui="menubar"] [data-part="group"] {
@@ -7849,7 +8504,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7849
8504
 
7850
8505
  [data-ui="menubar"] [data-part="trigger"]:focus-visible,
7851
8506
  [data-ui="menubar"] [data-part="item"]:focus-visible {
7852
- box-shadow: 0 0 0 calc(var(--space-px) * 2) var(--color-ring);
8507
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
7853
8508
  }
7854
8509
 
7855
8510
  [data-ui="menubar"] [data-part="submenu"] {
@@ -7884,7 +8539,10 @@ div[data-ui="separator"][data-style="thick"]::after {
7884
8539
  [data-ui="menubar"] [role="menuitem"][aria-disabled="true"] {
7885
8540
  color: var(--color-fg-muted);
7886
8541
  cursor: not-allowed;
7887
- opacity: 0.6;
8542
+ /* 0.6 at the 0.5 default — lighter than a control, since the muted colour
8543
+ already carries half the signal — and a theme's `--disabled-opacity` moves
8544
+ it (1.1A-27). */
8545
+ opacity: calc(var(--disabled-opacity) * 1.2);
7888
8546
  }
7889
8547
 
7890
8548
  [data-ui="menubar"] [data-part="separator"] {
@@ -7916,7 +8574,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7916
8574
 
7917
8575
  /* === recipes/pagination.css === */
7918
8576
  /* @ui:component pagination */
7919
- /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-primary color-primary-fg color-border radius-md space-1 space-2 space-3 text-xs text-sm text-base weight-medium duration-fast ease-default */
8577
+ /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-primary color-primary-fg color-border radius-md space-1 space-2 space-3 text-xs text-sm text-base weight-medium duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */
7920
8578
 
7921
8579
  /* ── Root ── */
7922
8580
  [data-ui="pagination"] {
@@ -7952,11 +8610,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7952
8610
  min-width: 36px;
7953
8611
  height: 36px;
7954
8612
  padding: 0 var(--space-2);
7955
- border: 1px solid var(--color-border);
8613
+ border: var(--border-width) solid var(--color-border);
7956
8614
  border-radius: var(--radius-md);
7957
8615
  background: var(--color-bg);
7958
8616
  color: var(--color-fg);
7959
- font-family: var(--font-sans, system-ui, sans-serif);
8617
+ font-family: var(--font-ui);
7960
8618
  font-size: var(--text-sm);
7961
8619
  font-weight: var(--weight-medium);
7962
8620
  cursor: pointer;
@@ -7977,8 +8635,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7977
8635
  [data-ui="pagination"] [data-part="page"]:focus-visible,
7978
8636
  [data-ui="pagination"] [data-part="prev"]:focus-visible,
7979
8637
  [data-ui="pagination"] [data-part="next"]:focus-visible {
7980
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7981
- outline-offset: 2px;
8638
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8639
+ outline-offset: var(--focus-ring-offset);
7982
8640
  }
7983
8641
 
7984
8642
  /* ── Active page ── */
@@ -8002,7 +8660,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8002
8660
  /* ── Disabled ── */
8003
8661
  [data-ui="pagination"] [data-part="prev"]:disabled,
8004
8662
  [data-ui="pagination"] [data-part="next"]:disabled {
8005
- opacity: 0.5;
8663
+ opacity: var(--disabled-opacity);
8006
8664
  cursor: not-allowed;
8007
8665
  pointer-events: none;
8008
8666
  }
@@ -8072,7 +8730,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8072
8730
 
8073
8731
  /* === recipes/popover.css === */
8074
8732
  /* @ui:component popover */
8075
- /* @ui:tokens color-bg color-fg color-border shadow-md radius-lg space-3 space-4 z-dropdown duration-fast ease-default */
8733
+ /* @ui:tokens color-bg panel-bg color-fg color-border shadow-md radius-lg space-3 space-4 z-dropdown duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop */
8076
8734
 
8077
8735
  /* ── Root ── */
8078
8736
  [data-ui="popover"] {
@@ -8086,11 +8744,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8086
8744
  align-items: center;
8087
8745
  gap: var(--space-2, 0.5rem);
8088
8746
  padding: var(--space-2, 0.5rem) var(--space-3);
8089
- border: 1px solid var(--color-border);
8747
+ border: var(--border-width) solid var(--color-border);
8090
8748
  border-radius: var(--radius-md, 0.375rem);
8091
8749
  background: var(--color-bg);
8092
8750
  color: var(--color-fg);
8093
- font-family: var(--font-sans, system-ui, sans-serif);
8751
+ font-family: var(--font-ui);
8094
8752
  font-size: var(--text-sm, 0.875rem);
8095
8753
  font-weight: var(--weight-medium, 500);
8096
8754
  cursor: pointer;
@@ -8104,8 +8762,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8104
8762
  }
8105
8763
 
8106
8764
  [data-ui="popover"] [data-part="trigger"]:focus-visible {
8107
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8108
- outline-offset: 2px;
8765
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8766
+ outline-offset: var(--focus-ring-offset);
8109
8767
  }
8110
8768
 
8111
8769
  /* ── Content ── */
@@ -8114,9 +8772,9 @@ div[data-ui="separator"][data-style="thick"]::after {
8114
8772
  z-index: var(--z-dropdown);
8115
8773
  min-width: 200px;
8116
8774
  padding: var(--space-4);
8117
- border: 1px solid var(--color-border);
8775
+ border: var(--border-width) solid var(--color-border);
8118
8776
  border-radius: var(--radius-lg);
8119
- background: var(--color-bg);
8777
+ background: var(--panel-bg);
8120
8778
  color: var(--color-fg);
8121
8779
  box-shadow: var(--shadow-md);
8122
8780
  opacity: 0;
@@ -8125,6 +8783,13 @@ div[data-ui="separator"][data-style="thick"]::after {
8125
8783
  transform var(--duration-fast) var(--ease-default);
8126
8784
  }
8127
8785
 
8786
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
8787
+ [data-ui="popover"] [data-part="content"] {
8788
+ -webkit-backdrop-filter: var(--surface-backdrop);
8789
+ backdrop-filter: var(--surface-backdrop);
8790
+ }
8791
+ }
8792
+
8128
8793
  [data-ui="popover"][data-state="open"] [data-part="content"] {
8129
8794
  opacity: 1;
8130
8795
  transform: scale(1);
@@ -8212,8 +8877,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8212
8877
  position: absolute;
8213
8878
  width: 8px;
8214
8879
  height: 8px;
8215
- background: var(--color-bg);
8216
- border: 1px solid var(--color-border);
8880
+ background: var(--panel-bg);
8881
+ border: var(--border-width) solid var(--color-border);
8217
8882
  transform: rotate(45deg);
8218
8883
  }
8219
8884
 
@@ -8314,8 +8979,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8314
8979
  }
8315
8980
 
8316
8981
  [data-ui="popover"] [data-part="close"]:focus-visible {
8317
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8318
- outline-offset: 2px;
8982
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8983
+ outline-offset: var(--focus-ring-offset);
8319
8984
  }
8320
8985
 
8321
8986
  /* ── Motion ── */
@@ -8328,7 +8993,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8328
8993
 
8329
8994
  /* === recipes/qr-code.css === */
8330
8995
  /* @ui:component qr-code */
8331
- /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-sans space-2 */
8996
+ /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-body space-2 */
8332
8997
 
8333
8998
  /* ── Base ── */
8334
8999
  [data-ui="qr-code"] {
@@ -8346,7 +9011,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8346
9011
 
8347
9012
  /* ── Caption ── */
8348
9013
  [data-ui="qr-code"] [data-part="caption"] {
8349
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
9014
+ font-family: var(--doc-font, var(--font-body));
8350
9015
  font-size: var(--doc-legal-size, var(--text-xs));
8351
9016
  color: var(--doc-legal-color, var(--color-fg-muted));
8352
9017
  text-align: center;
@@ -8387,7 +9052,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8387
9052
 
8388
9053
  /* === recipes/select-custom.css === */
8389
9054
  /* @ui:component select-custom */
8390
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-border-strong color-primary color-primary-subtle color-ring radius-md radius-lg shadow-md space-1 space-2 space-3 space-4 text-sm text-xs z-dropdown duration-fast ease-default */
9055
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-border-strong color-primary color-primary-subtle color-ring radius-md radius-lg shadow-md space-1 space-2 space-3 space-4 text-sm text-xs z-dropdown duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
8391
9056
 
8392
9057
  /* ── Root ── */
8393
9058
  [data-ui="select-custom"] {
@@ -8404,11 +9069,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8404
9069
  width: 100%;
8405
9070
  min-width: 180px;
8406
9071
  padding: var(--space-2) var(--space-3);
8407
- border: 1px solid var(--color-border);
9072
+ border: var(--border-width) solid var(--color-border);
8408
9073
  border-radius: var(--radius-md);
8409
9074
  background: var(--color-bg);
8410
9075
  color: var(--color-fg);
8411
- font-family: var(--font-sans, system-ui, sans-serif);
9076
+ font-family: var(--font-ui);
8412
9077
  font-size: var(--text-sm);
8413
9078
  cursor: pointer;
8414
9079
  white-space: nowrap;
@@ -8421,8 +9086,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8421
9086
  }
8422
9087
 
8423
9088
  [data-ui="select-custom"] [data-part="trigger"]:focus-visible {
8424
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8425
- outline-offset: 2px;
9089
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9090
+ outline-offset: var(--focus-ring-offset);
8426
9091
  }
8427
9092
 
8428
9093
  /* ── Value ── */
@@ -8458,7 +9123,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8458
9123
  z-index: var(--z-dropdown);
8459
9124
  margin-top: var(--space-1);
8460
9125
  padding: var(--space-1);
8461
- border: 1px solid var(--color-border);
9126
+ border: var(--border-width) solid var(--color-border);
8462
9127
  border-radius: var(--radius-lg);
8463
9128
  background: var(--color-bg);
8464
9129
  box-shadow: var(--shadow-md);
@@ -8482,11 +9147,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8482
9147
  padding: var(--space-2) var(--space-3);
8483
9148
  margin-bottom: var(--space-1);
8484
9149
  border: none;
8485
- border-bottom: 1px solid var(--color-border);
9150
+ border-bottom: var(--border-width) solid var(--color-border);
8486
9151
  border-radius: 0;
8487
9152
  background: transparent;
8488
9153
  color: var(--color-fg);
8489
- font-family: var(--font-sans, system-ui, sans-serif);
9154
+ font-family: var(--font-ui);
8490
9155
  font-size: var(--text-sm);
8491
9156
  outline: none;
8492
9157
  }
@@ -8580,7 +9245,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8580
9245
 
8581
9246
  /* === recipes/sheet.css === */
8582
9247
  /* @ui:component sheet */
8583
- /* @ui:tokens color-bg color-fg color-border shadow-xl radius-xl space-4 space-6 z-overlay z-modal duration-normal duration-slow ease-out */
9248
+ /* @ui:tokens color-bg panel-bg color-fg color-border shadow-xl radius-xl space-4 space-6 z-overlay z-modal duration-normal duration-slow ease-out font-heading border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop */
8584
9249
 
8585
9250
  /* ── Root ── */
8586
9251
  [data-ui="sheet"] {
@@ -8611,11 +9276,18 @@ div[data-ui="separator"][data-style="thick"]::after {
8611
9276
  z-index: var(--z-modal);
8612
9277
  display: flex;
8613
9278
  flex-direction: column;
8614
- background: var(--color-bg);
9279
+ background: var(--panel-bg);
8615
9280
  box-shadow: var(--shadow-xl);
8616
9281
  transition: transform var(--duration-slow) var(--ease-out);
8617
9282
  }
8618
9283
 
9284
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
9285
+ [data-ui="sheet"] [data-part="panel"] {
9286
+ -webkit-backdrop-filter: var(--surface-backdrop);
9287
+ backdrop-filter: var(--surface-backdrop);
9288
+ }
9289
+ }
9290
+
8619
9291
  /* ── Side: Bottom ── */
8620
9292
  [data-ui="sheet"] [data-part="panel"][data-variant="bottom"] {
8621
9293
  bottom: 0;
@@ -8643,7 +9315,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8643
9315
  bottom: 0;
8644
9316
  max-width: 100vw;
8645
9317
  border-radius: 0 var(--radius-xl) var(--radius-xl) 0;
8646
- border-inline-end: 1px solid var(--color-border);
9318
+ border-inline-end: var(--border-width) solid var(--color-border);
8647
9319
  transform: translateX(-100%);
8648
9320
  }
8649
9321
 
@@ -8654,7 +9326,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8654
9326
  bottom: 0;
8655
9327
  max-width: 100vw;
8656
9328
  border-radius: var(--radius-xl) 0 0 var(--radius-xl);
8657
- border-inline-start: 1px solid var(--color-border);
9329
+ border-inline-start: var(--border-width) solid var(--color-border);
8658
9330
  transform: translateX(100%);
8659
9331
  }
8660
9332
 
@@ -8731,6 +9403,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8731
9403
  /* ── Title ── */
8732
9404
  [data-ui="sheet"] [data-part="title"] {
8733
9405
  margin: 0;
9406
+ font-family: var(--font-heading);
8734
9407
  font-size: var(--text-lg, 1.125rem);
8735
9408
  font-weight: var(--weight-semibold, 600);
8736
9409
  color: var(--color-fg);
@@ -8765,8 +9438,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8765
9438
  }
8766
9439
 
8767
9440
  [data-ui="sheet"] [data-part="close"]:not([data-ui]):focus-visible {
8768
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8769
- outline-offset: 2px;
9441
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9442
+ outline-offset: var(--focus-ring-offset);
8770
9443
  }
8771
9444
 
8772
9445
  /* ── Body ── */
@@ -8787,7 +9460,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8787
9460
 
8788
9461
  /* === recipes/sidebar.css === */
8789
9462
  /* @ui:component sidebar */
8790
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-primary-subtle color-bg-muted color-ring shadow-xl space-1 space-2 space-3 space-4 radius-md radius-lg z-overlay z-modal text-sm text-lg weight-medium weight-semibold duration-normal duration-slow ease-out ease-default */
9463
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-primary-subtle color-bg-muted color-ring shadow-xl space-1 space-2 space-3 space-4 radius-md radius-lg z-overlay z-modal text-sm text-lg weight-medium weight-semibold duration-normal duration-slow ease-out ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
8791
9464
 
8792
9465
  /* ── Root ──
8793
9466
  The root owns the layout column from `md` up; the panel is the visual surface.
@@ -8831,7 +9504,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8831
9504
  flex-direction: column;
8832
9505
  gap: var(--space-2);
8833
9506
  background: var(--sidebar-bg);
8834
- border-inline-end: 1px solid var(--color-border);
9507
+ border-inline-end: var(--border-width) solid var(--color-border);
8835
9508
  border-start-end-radius: var(--radius-lg, 0.5rem);
8836
9509
  border-end-end-radius: var(--radius-lg, 0.5rem);
8837
9510
  box-shadow: var(--shadow-xl);
@@ -8912,8 +9585,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8912
9585
  }
8913
9586
 
8914
9587
  [data-ui="sidebar"] [data-part="trigger"]:focus-visible {
8915
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8916
- outline-offset: 2px;
9588
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9589
+ outline-offset: var(--focus-ring-offset);
8917
9590
  }
8918
9591
 
8919
9592
  /* ── Navigation ── */
@@ -8949,8 +9622,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8949
9622
  }
8950
9623
 
8951
9624
  [data-ui="sidebar"] [data-part="item"]:focus-visible {
8952
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8953
- outline-offset: -2px;
9625
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9626
+ outline-offset: calc(-1 * var(--focus-ring-offset));
8954
9627
  }
8955
9628
 
8956
9629
  [data-ui="sidebar"] [data-part="item"][aria-current="page"] {
@@ -8977,7 +9650,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8977
9650
  [data-ui="sidebar"] [data-part="footer"] {
8978
9651
  flex-shrink: 0;
8979
9652
  padding: var(--space-3) var(--space-4);
8980
- border-block-start: 1px solid var(--color-border);
9653
+ border-block-start: var(--border-width) solid var(--color-border);
8981
9654
  }
8982
9655
 
8983
9656
  /* ── Rail (icons only) ── */
@@ -9070,7 +9743,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9070
9743
 
9071
9744
  /* === recipes/slider.css === */
9072
9745
  /* @ui:component slider */
9073
- /* @ui:tokens color-bg color-fg-muted color-border color-primary color-primary-subtle color-ring color-bg-muted space-2 space-3 space-4 radius-full text-sm text-base shadow-sm duration-fast ease-default */
9746
+ /* @ui:tokens color-bg color-fg-muted color-border color-primary color-primary-subtle color-ring color-bg-muted space-2 space-3 space-4 radius-full text-sm text-base shadow-sm duration-fast ease-default font-ui border-width border-width-strong focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */
9074
9747
 
9075
9748
  /* ── Root ── */
9076
9749
  [data-ui="slider"] {
@@ -9120,28 +9793,28 @@ div[data-ui="separator"][data-style="thick"]::after {
9120
9793
  value in both LTR and RTL (translateX is physical, so -50% always recentres). */
9121
9794
  transform: translate(-50%, -50%);
9122
9795
  background: var(--color-bg, white);
9123
- border: 2px solid var(--color-primary);
9796
+ border: var(--border-width-strong) solid var(--color-primary);
9124
9797
  border-radius: var(--radius-full, 9999px);
9125
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1));
9798
+ box-shadow: var(--shadow-sm);
9126
9799
  cursor: grab;
9127
9800
  touch-action: none;
9128
- transition: box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
9801
+ transition: box-shadow var(--duration-fast) var(--ease-default);
9129
9802
  }
9130
9803
 
9131
9804
  [data-ui="slider"] [data-part="thumb"]:hover {
9132
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9133
- 0 0 0 4px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9805
+ box-shadow: var(--shadow-sm),
9806
+ 0 0 0 4px var(--color-primary-subtle);
9134
9807
  }
9135
9808
 
9136
9809
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
9137
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9138
- outline-offset: 2px;
9810
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9811
+ outline-offset: var(--focus-ring-offset);
9139
9812
  }
9140
9813
 
9141
9814
  [data-ui="slider"] [data-part="thumb"][data-state="dragging"] {
9142
9815
  cursor: grabbing;
9143
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9144
- 0 0 0 5px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9816
+ box-shadow: var(--shadow-sm),
9817
+ 0 0 0 5px var(--color-primary-subtle);
9145
9818
  }
9146
9819
 
9147
9820
  /* ── Value output ── */
@@ -9149,7 +9822,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9149
9822
  flex: 0 0 auto;
9150
9823
  min-inline-size: 3ch;
9151
9824
  color: var(--color-fg-muted);
9152
- font-family: var(--font-sans, system-ui, sans-serif);
9825
+ font-family: var(--font-ui);
9153
9826
  font-size: var(--text-sm);
9154
9827
  font-variant-numeric: tabular-nums;
9155
9828
  text-align: end;
@@ -9168,7 +9841,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9168
9841
 
9169
9842
  /* ── Disabled ── */
9170
9843
  [data-ui="slider"][data-disabled] {
9171
- opacity: 0.5;
9844
+ opacity: var(--disabled-opacity);
9172
9845
  cursor: not-allowed;
9173
9846
  pointer-events: none;
9174
9847
  }
@@ -9186,7 +9859,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9186
9859
  the substitution so the control still reads as "this much, up to here". [W3-3] */
9187
9860
  @media (forced-colors: active) {
9188
9861
  [data-ui="slider"] [data-part="track"] {
9189
- border: 1px solid ButtonText;
9862
+ border: var(--border-width) solid ButtonText;
9190
9863
  }
9191
9864
 
9192
9865
  [data-ui="slider"] [data-part="range"] {
@@ -9197,7 +9870,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9197
9870
  [data-ui="slider"] [data-part="thumb"] {
9198
9871
  forced-color-adjust: none;
9199
9872
  background: ButtonText;
9200
- border: 1px solid ButtonFace;
9873
+ border: var(--border-width) solid ButtonFace;
9201
9874
  }
9202
9875
 
9203
9876
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
@@ -9207,7 +9880,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9207
9880
 
9208
9881
  /* === recipes/table.css === */
9209
9882
  /* @ui:component table */
9210
- /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-fg-subtle color-border color-border-strong color-primary color-primary-subtle color-ring color-destructive color-destructive-subtle space-0h space-1 space-2 space-3 space-4 space-5 space-8 text-xs text-sm weight-semibold weight-bold radius-sm radius-md radius-full duration-fast ease-default doc-table-footer-bg doc-table-footer-weight doc-print-border-color */
9883
+ /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-fg-subtle color-border color-border-strong color-primary color-primary-subtle color-ring color-destructive color-destructive-subtle space-0h space-1 space-2 space-3 space-4 space-5 space-8 text-xs text-sm weight-semibold weight-bold radius-sm radius-md radius-full duration-fast ease-default doc-table-footer-bg doc-table-footer-weight doc-print-border-color font-body border-width border-width-strong focus-ring-width focus-ring-style focus-ring-color focus-ring-offset stripe-bg */
9211
9884
 
9212
9885
  /* ── Root ── */
9213
9886
  [data-ui="table"] {
@@ -9233,7 +9906,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9233
9906
  width: 100%;
9234
9907
  border-collapse: separate;
9235
9908
  border-spacing: 0;
9236
- font-family: var(--font-sans, system-ui, sans-serif);
9909
+ font-family: var(--font-body);
9237
9910
  }
9238
9911
 
9239
9912
  /* Once any column is resized the layout freezes so widths are exact. */
@@ -9255,7 +9928,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9255
9928
  font-weight: var(--weight-semibold);
9256
9929
  color: var(--color-fg-muted);
9257
9930
  background: var(--color-bg);
9258
- border-bottom: 2px solid var(--color-border);
9931
+ border-bottom: var(--border-width-strong) solid var(--color-border);
9259
9932
  white-space: nowrap;
9260
9933
  user-select: none;
9261
9934
  }
@@ -9313,8 +9986,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9313
9986
  /* Keyboard focus on cells (sortable headers + navigable grids). */
9314
9987
  [data-ui="table"] [data-part="th"]:focus-visible,
9315
9988
  [data-ui="table"] [data-part="td"]:focus-visible {
9316
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9317
- outline-offset: -2px;
9989
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9990
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9318
9991
  }
9319
9992
 
9320
9993
  /* ── Data Cell ── */
@@ -9322,7 +9995,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9322
9995
  padding: var(--space-3) var(--space-4);
9323
9996
  font-size: var(--text-sm);
9324
9997
  color: var(--color-fg);
9325
- border-bottom: 1px solid var(--color-border);
9998
+ border-bottom: var(--border-width) solid var(--color-border);
9326
9999
  background: var(--color-bg);
9327
10000
  transition: background var(--duration-fast) var(--ease-default);
9328
10001
  }
@@ -9351,31 +10024,31 @@ div[data-ui="separator"][data-style="thick"]::after {
9351
10024
  Static fallback via nth-child; once the controller stamps data-stripe on the
9352
10025
  visible rows (so hidden rows never break the pattern), the stamped rules win. */
9353
10026
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"]:not([data-stripe]):nth-child(even):not([data-selected]) [data-part="td"] {
9354
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
10027
+ background: var(--stripe-bg);
9355
10028
  }
9356
10029
 
9357
10030
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"]:not([data-stripe]):nth-child(even):not([data-selected]):hover [data-part="td"] {
9358
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
10031
+ background: var(--stripe-bg);
9359
10032
  }
9360
10033
 
9361
10034
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]) [data-part="td"] {
9362
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
10035
+ background: var(--stripe-bg);
9363
10036
  }
9364
10037
 
9365
10038
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]):hover [data-part="td"] {
9366
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
10039
+ background: var(--stripe-bg);
9367
10040
  }
9368
10041
 
9369
10042
  /* ── Bordered Variant ── */
9370
10043
  [data-ui="table"][data-variant="bordered"] [data-part="table"] {
9371
- border: 1px solid var(--color-border);
10044
+ border: var(--border-width) solid var(--color-border);
9372
10045
  border-radius: var(--radius-md, 0.375rem);
9373
10046
  overflow: hidden;
9374
10047
  }
9375
10048
 
9376
10049
  [data-ui="table"][data-variant="bordered"] [data-part="th"],
9377
10050
  [data-ui="table"][data-variant="bordered"] [data-part="td"] {
9378
- border: 1px solid var(--color-border);
10051
+ border: var(--border-width) solid var(--color-border);
9379
10052
  }
9380
10053
 
9381
10054
  /* ── Size: Small ── */
@@ -9403,7 +10076,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9403
10076
  /* ── Footer ── */
9404
10077
  [data-ui="table"] [data-part="tfoot"] [data-part="td"] {
9405
10078
  font-weight: var(--doc-table-footer-weight, var(--weight-semibold));
9406
- border-top: 2px solid var(--color-border);
10079
+ border-top: var(--border-width-strong) solid var(--color-border);
9407
10080
  border-bottom: none;
9408
10081
  background: var(--doc-table-footer-bg, var(--color-bg-subtle, oklch(0.97 0.004 260)));
9409
10082
  }
@@ -9529,7 +10202,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9529
10202
  [data-ui="table"] [data-part="filter-row"] [data-part="th"] {
9530
10203
  padding: var(--space-1) var(--space-2);
9531
10204
  background: var(--color-bg);
9532
- border-bottom: 1px solid var(--color-border);
10205
+ border-bottom: var(--border-width) solid var(--color-border);
9533
10206
  }
9534
10207
 
9535
10208
  [data-ui="table"] [data-part="filter-input"],
@@ -9541,14 +10214,14 @@ div[data-ui="separator"][data-style="thick"]::after {
9541
10214
  font-size: var(--text-xs);
9542
10215
  color: var(--color-fg);
9543
10216
  background: var(--color-bg);
9544
- border: 1px solid var(--color-border);
10217
+ border: var(--border-width) solid var(--color-border);
9545
10218
  border-radius: var(--radius-sm);
9546
10219
  }
9547
10220
 
9548
10221
  [data-ui="table"] [data-part="filter-input"]:focus,
9549
10222
  [data-ui="table"] [data-part="filter"]:focus {
9550
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9551
- outline-offset: -1px;
10223
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10224
+ outline-offset: calc(-1 * var(--border-width));
9552
10225
  border-color: var(--color-primary);
9553
10226
  }
9554
10227
 
@@ -9569,7 +10242,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9569
10242
  text-align: inherit;
9570
10243
  color: var(--color-fg);
9571
10244
  background: var(--color-bg);
9572
- border: 1px solid var(--color-primary);
10245
+ border: var(--border-width) solid var(--color-primary);
9573
10246
  border-radius: var(--radius-sm);
9574
10247
  outline: none;
9575
10248
  }
@@ -9622,11 +10295,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9622
10295
  }
9623
10296
 
9624
10297
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="before"] [data-part="td"] {
9625
- border-block-start: 2px solid var(--color-primary);
10298
+ border-block-start: var(--border-width-strong) solid var(--color-primary);
9626
10299
  }
9627
10300
 
9628
10301
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="after"] [data-part="td"] {
9629
- border-block-end: 2px solid var(--color-primary);
10302
+ border-block-end: var(--border-width-strong) solid var(--color-primary);
9630
10303
  }
9631
10304
 
9632
10305
  [data-ui="table"] [data-part="th"][data-dragging] {
@@ -9634,11 +10307,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9634
10307
  }
9635
10308
 
9636
10309
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="before"] {
9637
- border-inline-start: 2px solid var(--color-primary);
10310
+ border-inline-start: var(--border-width-strong) solid var(--color-primary);
9638
10311
  }
9639
10312
 
9640
10313
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="after"] {
9641
- border-inline-end: 2px solid var(--color-primary);
10314
+ border-inline-end: var(--border-width-strong) solid var(--color-primary);
9642
10315
  }
9643
10316
 
9644
10317
  /* ── Column Resize Handles (injected by the controller) ── */
@@ -9711,11 +10384,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9711
10384
  }
9712
10385
 
9713
10386
  [data-ui="table"] [data-pin="start"][data-pin-edge] {
9714
- border-inline-end: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10387
+ border-inline-end: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9715
10388
  }
9716
10389
 
9717
10390
  [data-ui="table"] [data-pin="end"][data-pin-edge] {
9718
- border-inline-start: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10391
+ border-inline-start: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9719
10392
  }
9720
10393
 
9721
10394
  /* ── Column Visibility ── */
@@ -9787,7 +10460,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9787
10460
  [data-ui="table"][data-stacked] [data-part="tfoot"] [data-part="tr"] {
9788
10461
  display: block;
9789
10462
  margin-block-end: var(--space-3);
9790
- border: 1px solid var(--color-border);
10463
+ border: var(--border-width) solid var(--color-border);
9791
10464
  border-radius: var(--radius-md);
9792
10465
  background: var(--color-bg);
9793
10466
  overflow: hidden;
@@ -9801,7 +10474,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9801
10474
  gap: var(--space-4);
9802
10475
  text-align: end;
9803
10476
  border-bottom: none;
9804
- border-block-end: 1px solid var(--color-border);
10477
+ border-block-end: var(--border-width) solid var(--color-border);
9805
10478
  }
9806
10479
 
9807
10480
  [data-ui="table"][data-stacked] [data-part="tr"] [data-part="td"]:last-child,
@@ -9898,7 +10571,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9898
10571
 
9899
10572
  /* === recipes/tabs.css === */
9900
10573
  /* @ui:component tabs */
9901
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-primary-subtle space-1 space-2 space-3 space-4 radius-md radius-lg text-sm text-base weight-medium duration-fast ease-default */
10574
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-primary-subtle space-1 space-2 space-3 space-4 radius-md radius-lg text-sm text-base weight-medium duration-fast ease-default font-ui border-width border-width-strong focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
9902
10575
 
9903
10576
  /* ── Root ── */
9904
10577
  [data-ui="tabs"] {
@@ -9927,7 +10600,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9927
10600
  border: none;
9928
10601
  background: transparent;
9929
10602
  color: var(--color-fg-muted);
9930
- font-family: var(--font-sans, system-ui, sans-serif);
10603
+ font-family: var(--font-ui);
9931
10604
  font-size: var(--text-sm);
9932
10605
  font-weight: var(--weight-medium);
9933
10606
  cursor: pointer;
@@ -9942,8 +10615,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9942
10615
  }
9943
10616
 
9944
10617
  [data-ui="tabs"] [data-part="trigger"]:focus-visible {
9945
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9946
- outline-offset: -2px;
10618
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10619
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9947
10620
  border-radius: var(--radius-md);
9948
10621
  }
9949
10622
 
@@ -9953,12 +10626,12 @@ div[data-ui="separator"][data-style="thick"]::after {
9953
10626
 
9954
10627
  /* ── Underline Variant ── */
9955
10628
  [data-ui="tabs"][data-variant="underline"] [data-part="list"] {
9956
- border-bottom: 1px solid var(--color-border);
10629
+ border-bottom: var(--border-width) solid var(--color-border);
9957
10630
  gap: 0;
9958
10631
  }
9959
10632
 
9960
10633
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"] {
9961
- border-bottom: 2px solid transparent;
10634
+ border-bottom: var(--border-width-strong) solid transparent;
9962
10635
  margin-bottom: -1px;
9963
10636
  border-radius: 0;
9964
10637
  }
@@ -9990,17 +10663,17 @@ div[data-ui="separator"][data-style="thick"]::after {
9990
10663
  [data-ui="tabs"][data-variant="pill"] [data-part="trigger"][aria-selected="true"] {
9991
10664
  background: var(--color-bg);
9992
10665
  color: var(--color-fg);
9993
- box-shadow: var(--shadow-xs, 0 1px 2px oklch(0 0 0 / 0.04));
10666
+ box-shadow: var(--shadow-xs);
9994
10667
  }
9995
10668
 
9996
10669
  /* ── Enclosed Variant ── */
9997
10670
  [data-ui="tabs"][data-variant="enclosed"] [data-part="list"] {
9998
- border-bottom: 1px solid var(--color-border);
10671
+ border-bottom: var(--border-width) solid var(--color-border);
9999
10672
  gap: 0;
10000
10673
  }
10001
10674
 
10002
10675
  [data-ui="tabs"][data-variant="enclosed"] [data-part="trigger"] {
10003
- border: 1px solid transparent;
10676
+ border: var(--border-width) solid transparent;
10004
10677
  border-bottom: none;
10005
10678
  border-radius: var(--radius-md) var(--radius-md) 0 0;
10006
10679
  margin-bottom: -1px;
@@ -10045,8 +10718,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10045
10718
  @media (forced-colors: active) {
10046
10719
  [data-ui="tabs"] [data-part="trigger"][aria-selected="true"] {
10047
10720
  /* An outline the OS preserves, on every variant. */
10048
- outline: 2px solid Highlight;
10049
- outline-offset: -2px;
10721
+ outline: var(--border-width-strong) solid Highlight;
10722
+ outline-offset: calc(-1 * var(--border-width-strong));
10050
10723
  }
10051
10724
 
10052
10725
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"][aria-selected="true"] {
@@ -10061,7 +10734,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10061
10734
 
10062
10735
  /* === recipes/tag-input.css === */
10063
10736
  /* @ui:component tag-input */
10064
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle color-ring radius-md radius-lg shadow-md space-1 space-1h space-2 space-3 text-sm z-dropdown duration-fast ease-default font-sans */
10737
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle radius-md radius-lg shadow-md space-1 space-1h space-2 space-3 text-sm z-dropdown duration-fast ease-default font-ui border-width focus-ring-color focus-ring-width */
10065
10738
 
10066
10739
  /* NOTE: the tags themselves are `data-ui="chip"` elements — their styling comes
10067
10740
  entirely from chip.css. This file styles only the field wrapper, the tag row,
@@ -10082,7 +10755,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10082
10755
  gap: var(--space-1h);
10083
10756
  width: 100%;
10084
10757
  padding: var(--space-1h) var(--space-2);
10085
- border: 1px solid var(--color-border);
10758
+ border: var(--border-width) solid var(--color-border);
10086
10759
  border-radius: var(--radius-md);
10087
10760
  background: var(--color-bg);
10088
10761
  list-style: none;
@@ -10091,8 +10764,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10091
10764
  }
10092
10765
 
10093
10766
  [data-ui="tag-input"] [data-part="taglist"]:focus-within {
10094
- border-color: var(--color-ring, oklch(0.55 0.22 264));
10095
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
10767
+ border-color: var(--focus-ring-color);
10768
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
10096
10769
  }
10097
10770
 
10098
10771
  /* ── Text input: borderless, grows to fill the remaining row space ── */
@@ -10103,7 +10776,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10103
10776
  border: none;
10104
10777
  background: transparent;
10105
10778
  color: var(--color-fg);
10106
- font-family: var(--font-sans, system-ui, sans-serif);
10779
+ font-family: var(--font-ui);
10107
10780
  font-size: var(--text-sm);
10108
10781
  line-height: 1.5;
10109
10782
  outline: none;
@@ -10122,7 +10795,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10122
10795
  z-index: var(--z-dropdown);
10123
10796
  margin-top: var(--space-1);
10124
10797
  padding: var(--space-1);
10125
- border: 1px solid var(--color-border);
10798
+ border: var(--border-width) solid var(--color-border);
10126
10799
  border-radius: var(--radius-lg);
10127
10800
  background: var(--color-bg);
10128
10801
  box-shadow: var(--shadow-md);
@@ -10169,7 +10842,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10169
10842
 
10170
10843
  /* === recipes/toast.css === */
10171
10844
  /* @ui:component toast */
10172
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-success color-destructive color-warning shadow-lg radius-lg space-2 space-3 space-4 text-sm weight-medium z-toast duration-normal duration-slow ease-out */
10845
+ /* @ui:tokens color-bg panel-bg color-fg color-fg-muted color-border color-success color-destructive color-warning shadow-lg radius-lg space-2 space-3 space-4 text-sm weight-medium z-toast duration-normal duration-slow ease-out font-ui border-width border-width-lg focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop */
10173
10846
 
10174
10847
  /* ── Container ── */
10175
10848
  [data-ui="toast"][data-part="container"] {
@@ -10218,8 +10891,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10218
10891
  max-width: 380px;
10219
10892
  width: max-content;
10220
10893
  padding: var(--space-3) var(--space-4);
10221
- background: var(--color-bg);
10222
- border: 1px solid var(--color-border);
10894
+ background: var(--panel-bg);
10895
+ border: var(--border-width) solid var(--color-border);
10223
10896
  border-radius: var(--radius-lg);
10224
10897
  box-shadow: var(--shadow-lg);
10225
10898
  pointer-events: auto;
@@ -10229,6 +10902,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10229
10902
  transform var(--duration-normal) var(--ease-out);
10230
10903
  }
10231
10904
 
10905
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
10906
+ [data-ui="toast"] [data-part="toast"] {
10907
+ -webkit-backdrop-filter: var(--surface-backdrop);
10908
+ backdrop-filter: var(--surface-backdrop);
10909
+ }
10910
+ }
10911
+
10232
10912
  /* ── State: Entering ── */
10233
10913
  [data-ui="toast"][data-variant="top-right"] [data-part="toast"][data-state="entering"],
10234
10914
  [data-ui="toast"][data-variant="top-left"] [data-part="toast"][data-state="entering"] {
@@ -10268,7 +10948,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10268
10948
 
10269
10949
  /* ── Tone Variants ── */
10270
10950
  [data-ui="toast"] [data-part="toast"][data-variant="success"] {
10271
- border-inline-start: 3px solid var(--color-success, oklch(0.55 0.18 145));
10951
+ border-inline-start: var(--border-width-lg) solid var(--color-success, oklch(0.55 0.18 145));
10272
10952
  }
10273
10953
 
10274
10954
  [data-ui="toast"] [data-part="toast"][data-variant="success"] [data-part="icon"] {
@@ -10276,7 +10956,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10276
10956
  }
10277
10957
 
10278
10958
  [data-ui="toast"] [data-part="toast"][data-variant="error"] {
10279
- border-inline-start: 3px solid var(--color-destructive, oklch(0.55 0.22 25));
10959
+ border-inline-start: var(--border-width-lg) solid var(--color-destructive, oklch(0.55 0.22 25));
10280
10960
  }
10281
10961
 
10282
10962
  [data-ui="toast"] [data-part="toast"][data-variant="error"] [data-part="icon"] {
@@ -10284,7 +10964,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10284
10964
  }
10285
10965
 
10286
10966
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] {
10287
- border-inline-start: 3px solid var(--color-warning, oklch(0.7 0.18 85));
10967
+ border-inline-start: var(--border-width-lg) solid var(--color-warning, oklch(0.7 0.18 85));
10288
10968
  }
10289
10969
 
10290
10970
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] [data-part="icon"] {
@@ -10306,7 +10986,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10306
10986
  /* ── Message ── */
10307
10987
  [data-ui="toast"] [data-part="message"] {
10308
10988
  flex: 1;
10309
- font-family: var(--font-sans, system-ui, sans-serif);
10989
+ font-family: var(--font-ui);
10310
10990
  font-size: var(--text-sm);
10311
10991
  font-weight: var(--weight-medium);
10312
10992
  color: var(--color-fg);
@@ -10317,11 +10997,11 @@ div[data-ui="separator"][data-style="thick"]::after {
10317
10997
  [data-ui="toast"] [data-part="action"] {
10318
10998
  flex-shrink: 0;
10319
10999
  padding: var(--space-1, 0.25rem) var(--space-2);
10320
- border: 1px solid var(--color-border);
11000
+ border: var(--border-width) solid var(--color-border);
10321
11001
  border-radius: var(--radius-md, 0.375rem);
10322
11002
  background: transparent;
10323
11003
  color: var(--color-fg);
10324
- font-family: var(--font-sans, system-ui, sans-serif);
11004
+ font-family: var(--font-ui);
10325
11005
  font-size: var(--text-xs, 0.75rem);
10326
11006
  font-weight: var(--weight-medium);
10327
11007
  cursor: pointer;
@@ -10334,8 +11014,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10334
11014
  }
10335
11015
 
10336
11016
  [data-ui="toast"] [data-part="action"]:focus-visible {
10337
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10338
- outline-offset: 2px;
11017
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11018
+ outline-offset: var(--focus-ring-offset);
10339
11019
  }
10340
11020
 
10341
11021
  /* ── Close Button ── */
@@ -10361,8 +11041,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10361
11041
  }
10362
11042
 
10363
11043
  [data-ui="toast"] [data-part="close"]:focus-visible {
10364
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10365
- outline-offset: 2px;
11044
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11045
+ outline-offset: var(--focus-ring-offset);
10366
11046
  }
10367
11047
 
10368
11048
  /* ── Motion ── */
@@ -10375,14 +11055,14 @@ div[data-ui="separator"][data-style="thick"]::after {
10375
11055
 
10376
11056
  /* === recipes/toggle-group.css === */
10377
11057
  /* @ui:component toggle-group */
10378
- /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring radius-md space-1 space-1h space-2 space-3 text-sm font-sans weight-medium duration-fast ease-default */
11058
+ /* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring radius-md space-1 space-1h space-2 space-3 text-sm font-ui weight-medium duration-fast ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */
10379
11059
 
10380
11060
  /* ── Root: a segmented row of toggle buttons ── */
10381
11061
  [data-ui="toggle-group"] {
10382
11062
  display: inline-flex;
10383
11063
  gap: var(--space-1);
10384
11064
  padding: var(--space-1);
10385
- border: 1px solid var(--color-border);
11065
+ border: var(--border-width) solid var(--color-border);
10386
11066
  border-radius: var(--radius-md);
10387
11067
  background: var(--color-bg);
10388
11068
  }
@@ -10397,7 +11077,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10397
11077
  border-radius: var(--radius-md);
10398
11078
  background: transparent;
10399
11079
  color: var(--color-fg-muted);
10400
- font-family: var(--toggle-group-font, var(--font-sans));
11080
+ font-family: var(--toggle-group-font, var(--font-ui));
10401
11081
  font-size: var(--text-sm);
10402
11082
  font-weight: var(--weight-medium);
10403
11083
  line-height: 1;
@@ -10438,13 +11118,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10438
11118
 
10439
11119
  /* ── Keyboard focus ring on the item (focus lives on the hidden control) ── */
10440
11120
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:focus-visible) {
10441
- outline: 2px solid var(--color-ring);
10442
- outline-offset: 2px;
11121
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11122
+ outline-offset: var(--focus-ring-offset);
10443
11123
  }
10444
11124
 
10445
11125
  /* ── Disabled control ── */
10446
11126
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:disabled) {
10447
- opacity: 0.5;
11127
+ opacity: var(--disabled-opacity);
10448
11128
  cursor: not-allowed;
10449
11129
  }
10450
11130
 
@@ -10457,7 +11137,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10457
11137
 
10458
11138
  /* === recipes/tooltip.css === */
10459
11139
  /* @ui:component tooltip */
10460
- /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default */
11140
+ /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default font-ui surface-backdrop */
10461
11141
 
10462
11142
  /* ── Root ── */
10463
11143
  [data-ui="tooltip"] {
@@ -10478,7 +11158,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10478
11158
  color: var(--color-bg);
10479
11159
  border-radius: var(--radius-md);
10480
11160
  padding: var(--space-1h, 0.375rem) var(--space-2);
10481
- font-family: var(--font-sans, system-ui, sans-serif);
11161
+ font-family: var(--font-ui);
10482
11162
  font-size: var(--text-xs, 0.75rem);
10483
11163
  line-height: 1.4;
10484
11164
  white-space: nowrap;
@@ -10489,6 +11169,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10489
11169
  transform var(--duration-fast) var(--ease-default);
10490
11170
  }
10491
11171
 
11172
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
11173
+ [data-ui="tooltip"] [data-part="content"] {
11174
+ -webkit-backdrop-filter: var(--surface-backdrop);
11175
+ backdrop-filter: var(--surface-backdrop);
11176
+ }
11177
+ }
11178
+
10492
11179
  /* Default position (top) when no variant is specified */
10493
11180
  [data-ui="tooltip"]:not([data-variant]) [data-part="content"] {
10494
11181
  bottom: 100%;
@@ -10604,7 +11291,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10604
11291
 
10605
11292
  /* === recipes/tree-view.css === */
10606
11293
  /* @ui:component tree-view */
10607
- /* @ui:tokens color-bg-muted color-fg color-fg-muted color-fg-subtle color-primary color-primary-subtle color-ring space-px space-1 space-2 space-5 radius-md text-sm font-sans weight-medium duration-fast ease-default */
11294
+ /* @ui:tokens color-bg-muted color-fg color-fg-muted color-fg-subtle color-primary color-primary-subtle color-ring space-px space-1 space-2 space-5 radius-md text-sm font-ui weight-medium duration-fast ease-default focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
10608
11295
 
10609
11296
  [data-ui="tree-view"],
10610
11297
  [data-ui="tree-view"] [data-part="group"] {
@@ -10617,7 +11304,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10617
11304
  inline-size: 100%;
10618
11305
  padding: var(--space-1);
10619
11306
  color: var(--color-fg);
10620
- font-family: var(--font-sans);
11307
+ font-family: var(--font-ui);
10621
11308
  font-size: var(--text-sm);
10622
11309
  }
10623
11310
 
@@ -10645,8 +11332,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10645
11332
  }
10646
11333
 
10647
11334
  [data-ui="tree-view"] [data-part="item"]:focus-visible > [data-part="label"] {
10648
- outline: var(--space-px) solid var(--color-ring);
10649
- outline-offset: var(--space-px);
11335
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11336
+ outline-offset: var(--focus-ring-offset);
10650
11337
  }
10651
11338
 
10652
11339
  [data-ui="tree-view"] [data-part="item"][aria-selected="true"] > [data-part="label"] {
@@ -10685,7 +11372,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10685
11372
 
10686
11373
  /* === patterns/auth-form.css === */
10687
11374
  /* @ui:component auth-form */
10688
- /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-border-strong color-ring color-primary color-primary-hover color-primary-fg color-destructive color-destructive-subtle color-success color-success-subtle radius-lg radius-xl shadow-sm shadow-md space-1 space-2 space-3 space-4 space-5 space-6 space-8 font-sans text-xs text-sm text-base text-lg text-xl text-2xl weight-medium weight-semibold weight-bold leading-tight leading-normal duration-fast duration-normal ease-default */
11375
+ /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-border-strong color-ring color-primary color-primary-hover color-primary-fg color-destructive color-destructive-subtle color-success color-success-subtle radius-lg radius-xl shadow-sm shadow-md space-1 space-2 space-3 space-4 space-5 space-6 space-8 font-heading font-body heading-weight heading-tracking heading-transform heading-caps heading-leading text-xs text-sm text-base text-lg text-xl text-2xl weight-medium weight-semibold weight-bold leading-tight leading-normal duration-fast duration-normal ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset link-decoration */
10689
11376
 
10690
11377
  /* ── Root Container ── */
10691
11378
  [data-ui="auth-form"] {
@@ -10693,7 +11380,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10693
11380
  align-items: center;
10694
11381
  justify-content: center;
10695
11382
  width: 100%;
10696
- font-family: var(--font-sans);
11383
+ font-family: var(--font-body);
10697
11384
  }
10698
11385
 
10699
11386
  /* Mobile-first (task 0.8-09): on a phone the card IS the page — edge to edge,
@@ -10725,9 +11412,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10725
11412
 
10726
11413
  [data-ui="auth-form"] [data-part="title"] {
10727
11414
  margin: 0;
11415
+ font-family: var(--font-heading);
10728
11416
  font-size: var(--text-xl);
10729
- font-weight: var(--weight-bold);
10730
- line-height: var(--leading-tight);
11417
+ font-weight: var(--heading-weight);
11418
+ letter-spacing: var(--heading-tracking);
11419
+ text-transform: var(--heading-transform);
11420
+ font-variant-caps: var(--heading-caps);
11421
+ line-height: var(--heading-leading);
10731
11422
  color: var(--color-fg);
10732
11423
  }
10733
11424
 
@@ -10744,7 +11435,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10744
11435
  margin: var(--space-4) var(--space-6) 0;
10745
11436
  padding: var(--space-3);
10746
11437
  background: var(--color-destructive-subtle);
10747
- border: 1px solid var(--color-destructive);
11438
+ border: var(--border-width) solid var(--color-destructive);
10748
11439
  border-radius: var(--radius-lg);
10749
11440
  color: var(--color-destructive);
10750
11441
  font-size: var(--text-sm);
@@ -10822,13 +11513,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10822
11513
  }
10823
11514
 
10824
11515
  [data-ui="auth-form"] [data-part="footer"] a:hover {
10825
- text-decoration: underline;
11516
+ text-decoration-line: var(--link-decoration);
10826
11517
  color: var(--color-primary-hover);
10827
11518
  }
10828
11519
 
10829
11520
  [data-ui="auth-form"] [data-part="footer"] a:focus-visible {
10830
- outline: 2px solid var(--color-ring);
10831
- outline-offset: 2px;
11521
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11522
+ outline-offset: var(--focus-ring-offset);
10832
11523
  border-radius: var(--radius-sm, 0.25rem);
10833
11524
  }
10834
11525
 
@@ -10956,8 +11647,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10956
11647
  max-width: var(--auth-form-max-width, 400px);
10957
11648
  border-radius: var(--card-radius, var(--radius-lg));
10958
11649
  box-shadow: var(--card-shadow, var(--shadow-sm));
10959
- border-inline-start: 1px solid var(--card-border, var(--color-border));
10960
- border-inline-end: 1px solid var(--card-border, var(--color-border));
11650
+ border-inline-start: var(--border-width) solid var(--card-border, var(--color-border));
11651
+ border-inline-end: var(--border-width) solid var(--card-border, var(--color-border));
10961
11652
  }
10962
11653
  }
10963
11654
 
@@ -10972,7 +11663,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10972
11663
 
10973
11664
  /* === patterns/crud-table.css === */
10974
11665
  /* @ui:component crud-table */
10975
- /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-fg color-destructive color-destructive-fg radius-md radius-lg shadow-sm space-1 space-2 space-3 space-4 space-6 space-8 font-sans text-sm text-base text-lg weight-medium weight-semibold duration-fast duration-normal ease-default */
11666
+ /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-fg color-destructive color-destructive-fg radius-md radius-lg shadow-sm space-1 space-2 space-3 space-4 space-6 space-8 font-body text-sm text-base text-lg weight-medium weight-semibold duration-fast duration-normal ease-default border-width */
10976
11667
 
10977
11668
  /* ── Root ── */
10978
11669
  [data-ui="crud-table"] {
@@ -10980,7 +11671,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10980
11671
  flex-direction: column;
10981
11672
  gap: var(--space-4);
10982
11673
  width: 100%;
10983
- font-family: var(--font-sans, system-ui, sans-serif);
11674
+ font-family: var(--font-body);
10984
11675
  }
10985
11676
 
10986
11677
  /* ── Toolbar ── */
@@ -11038,7 +11729,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11038
11729
  gap: var(--space-3);
11039
11730
  padding: var(--space-3) var(--space-4);
11040
11731
  background: var(--color-bg-subtle);
11041
- border: 1px solid var(--color-border);
11732
+ border: var(--border-width) solid var(--color-border);
11042
11733
  border-radius: var(--radius-md);
11043
11734
  }
11044
11735
 
@@ -11053,7 +11744,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11053
11744
  [data-ui="crud-table"] [data-part="table-wrapper"] {
11054
11745
  width: 100%;
11055
11746
  overflow-x: auto;
11056
- border: 1px solid var(--color-border);
11747
+ border: var(--border-width) solid var(--color-border);
11057
11748
  border-radius: var(--radius-lg);
11058
11749
  background: var(--color-bg);
11059
11750
  }
@@ -11083,7 +11774,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11083
11774
  padding: var(--space-8) var(--space-4);
11084
11775
  text-align: center;
11085
11776
  min-height: 240px;
11086
- border: 1px dashed var(--color-border);
11777
+ border: var(--border-width) dashed var(--color-border);
11087
11778
  border-radius: var(--radius-lg);
11088
11779
  background: var(--color-bg);
11089
11780
  }
@@ -11196,7 +11887,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11196
11887
 
11197
11888
  /* === patterns/dashboard-shell.css === */
11198
11889
  /* @ui:component dashboard-shell */
11199
- /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-border-strong color-primary color-primary-subtle color-primary-fg space-2 space-3 space-4 space-5 space-6 space-8 space-12 space-16 radius-md radius-lg shadow-sm shadow-md font-sans text-xs text-sm text-base text-lg weight-medium weight-semibold leading-tight leading-normal duration-normal duration-slow ease-default ease-out z-sticky */
11890
+ /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-border-strong color-primary color-primary-subtle color-primary-fg space-2 space-3 space-4 space-5 space-6 space-8 space-12 space-16 radius-md radius-lg shadow-sm shadow-md font-body font-ui text-xs text-sm text-base text-lg weight-medium weight-semibold leading-tight leading-normal duration-normal duration-slow ease-default ease-out z-sticky border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
11200
11891
 
11201
11892
  /* ── Shell Grid Layout ──
11202
11893
  Mobile-first (task 0.8-09): the base is the PHONE shell — one column, header
@@ -11221,7 +11912,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11221
11912
  "footer";
11222
11913
  min-height: 100vh;
11223
11914
  background: var(--color-bg);
11224
- font-family: var(--font-sans);
11915
+ font-family: var(--font-body);
11225
11916
  color: var(--color-fg);
11226
11917
  }
11227
11918
 
@@ -11245,7 +11936,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11245
11936
  gap: var(--space-2);
11246
11937
  padding: var(--space-4);
11247
11938
  background: var(--color-bg-subtle);
11248
- border-inline-end: 1px solid var(--color-border);
11939
+ border-inline-end: var(--border-width) solid var(--color-border);
11249
11940
  overflow-y: auto;
11250
11941
  position: fixed;
11251
11942
  top: 0;
@@ -11265,7 +11956,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11265
11956
 
11266
11957
  [data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"] {
11267
11958
  border-inline-end: none;
11268
- border-inline-start: 1px solid var(--color-border);
11959
+ border-inline-start: var(--border-width) solid var(--color-border);
11269
11960
  inset-inline-start: auto;
11270
11961
  inset-inline-end: 0;
11271
11962
  transform: translateX(100%);
@@ -11340,7 +12031,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11340
12031
  gap: var(--space-3);
11341
12032
  padding: var(--space-2) var(--space-3);
11342
12033
  border-radius: var(--radius-md);
11343
- font-family: var(--font-sans);
12034
+ font-family: var(--font-ui);
11344
12035
  font-size: var(--text-sm);
11345
12036
  font-weight: var(--weight-medium);
11346
12037
  line-height: var(--leading-normal);
@@ -11359,8 +12050,8 @@ div[data-ui="separator"][data-style="thick"]::after {
11359
12050
  }
11360
12051
 
11361
12052
  [data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"]:focus-visible {
11362
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
11363
- outline-offset: -2px;
12053
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
12054
+ outline-offset: calc(-1 * var(--focus-ring-offset));
11364
12055
  }
11365
12056
 
11366
12057
  /* ── Nav Item Active ── */
@@ -11407,7 +12098,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11407
12098
  gap: var(--space-2);
11408
12099
  padding: 0 var(--space-3);
11409
12100
  background: var(--color-bg);
11410
- border-bottom: 1px solid var(--color-border);
12101
+ border-bottom: var(--border-width) solid var(--color-border);
11411
12102
  position: sticky;
11412
12103
  top: 0;
11413
12104
  z-index: var(--z-sticky);
@@ -11488,7 +12179,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11488
12179
  align-items: center;
11489
12180
  gap: var(--space-3);
11490
12181
  padding: var(--space-4) var(--space-6);
11491
- border-top: 1px solid var(--color-border);
12182
+ border-top: var(--border-width) solid var(--color-border);
11492
12183
  font-size: var(--text-xs);
11493
12184
  color: var(--color-fg-muted);
11494
12185
  }
@@ -11571,7 +12262,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11571
12262
 
11572
12263
  /* === patterns/document.css === */
11573
12264
  /* @ui:component document */
11574
- /* @ui:tokens doc-max-width doc-font doc-font-size doc-line-height doc-heading-font doc-heading-weight doc-heading-size doc-subheading-size doc-legal-size doc-legal-color doc-section-gap doc-component-gap doc-running-header-height doc-running-footer-height doc-running-gap doc-bg doc-fg doc-print-border-color doc-table-header-bg doc-table-header-fg doc-table-header-weight doc-table-border doc-table-cell-pad-y doc-table-cell-pad-x doc-table-font-size doc-table-num-font doc-table-footer-bg doc-table-footer-weight doc-table-stripe-bg page-format page-orientation page-margin page-margin-top page-margin-bottom page-margin-left page-margin-right color-bg color-fg color-fg-muted color-border space-4 space-6 space-8 space-12 shadow-lg radius-md font-serif z-raised */
12265
+ /* @ui:tokens doc-max-width doc-font doc-font-size doc-line-height doc-heading-font doc-heading-weight doc-heading-size doc-subheading-size doc-legal-size doc-legal-color doc-section-gap doc-component-gap doc-running-header-height doc-running-footer-height doc-running-gap doc-bg doc-fg doc-print-border-color doc-table-header-bg doc-table-header-fg doc-table-header-weight doc-table-border doc-table-cell-pad-y doc-table-cell-pad-x doc-table-font-size doc-table-num-font doc-table-footer-bg doc-table-footer-weight doc-table-stripe-bg page-format page-orientation page-margin page-margin-top page-margin-bottom page-margin-left page-margin-right color-bg color-fg color-fg-muted color-border space-4 space-6 space-8 space-12 shadow-lg radius-md font-body weight-bold z-raised border-width texture-page */
11575
12266
 
11576
12267
  /* ── Page Rules ── */
11577
12268
  @page {
@@ -11611,14 +12302,17 @@ div[data-ui="separator"][data-style="thick"]::after {
11611
12302
  max-width: var(--doc-max-width);
11612
12303
  margin: var(--space-4) auto;
11613
12304
  padding: var(--space-6) var(--space-4);
11614
- background: var(--color-bg, #fff);
12305
+ background-color: var(--color-bg, #fff);
12306
+ background-image: var(--texture-page);
11615
12307
  color: var(--color-fg);
11616
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
12308
+ font-family: var(--doc-font, var(--font-body));
11617
12309
  font-size: var(--doc-font-size);
11618
12310
  line-height: var(--doc-line-height);
11619
- box-shadow: var(--shadow-lg,
11620
- 0 10px 15px -3px rgba(0, 0, 0, 0.1),
11621
- 0 4px 6px -4px rgba(0, 0, 0, 0.1));
12311
+ /* The fallback here used to spell out two rgba() layers, which is a shadow
12312
+ colour no theme could reach. --shadow-lg is always defined by the token
12313
+ layer, and it now carries --shadow-color, so the fallback is gone rather
12314
+ than re-tokenised. */
12315
+ box-shadow: var(--shadow-lg);
11622
12316
  border-radius: 0;
11623
12317
  position: relative;
11624
12318
  }
@@ -11634,7 +12328,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11634
12328
  [data-ui="document"] > [data-part="header"] {
11635
12329
  margin-block-end: var(--doc-section-gap);
11636
12330
  padding-block-end: var(--doc-component-gap);
11637
- border-block-end: 1px solid var(--color-border);
12331
+ border-block-end: var(--border-width) solid var(--color-border);
11638
12332
  }
11639
12333
 
11640
12334
  /* ── Body ── */
@@ -11644,13 +12338,25 @@ div[data-ui="separator"][data-style="thick"]::after {
11644
12338
  gap: var(--doc-section-gap);
11645
12339
  }
11646
12340
 
12341
+ /* ── Headings ──
12342
+ The document's own heading face and weight (1.1A-21): a print theme sets
12343
+ --doc-heading-font / --doc-heading-weight to give its titles a voice apart
12344
+ from the body copy (document-serif's Times titles over Georgia text). Both
12345
+ default to the page's heading role in tokens/document.css, and each falls
12346
+ back to what a heading rendered before the tokens had a reader. A heading
12347
+ that carries its own data-weight keeps it — that is the author asking. */
12348
+ [data-ui="document"] :is(h1, h2, h3, h4, h5, h6) {
12349
+ font-family: var(--doc-heading-font, var(--font-body));
12350
+ font-weight: var(--doc-heading-weight, var(--weight-bold));
12351
+ }
12352
+
11647
12353
  /* ── Running footer ──
11648
12354
  footer remains a non-breaking selector alias for pre-1.1.0 documents. */
11649
12355
  [data-ui="document"] > [data-part="doc-footer"],
11650
12356
  [data-ui="document"] > [data-part="footer"] {
11651
12357
  margin-block-start: var(--doc-section-gap);
11652
12358
  padding-block-start: var(--doc-component-gap);
11653
- border-block-start: 1px solid var(--color-border);
12359
+ border-block-start: var(--border-width) solid var(--color-border);
11654
12360
  font-size: var(--doc-legal-size);
11655
12361
  color: var(--doc-legal-color);
11656
12362
  }
@@ -11688,7 +12394,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11688
12394
 
11689
12395
  /* ── Variant: Report ── */
11690
12396
  [data-ui="document"][data-variant="report"] {
11691
- font-family: var(--font-serif, Georgia, "Times New Roman", serif);
12397
+ /* A report is serif-set by definition. It re-points the document's own font
12398
+ ROLE rather than its `font-family`, so every doc primitive nested inside it
12399
+ (key-value, callout, signature — all of which read --doc-font) follows the
12400
+ report into serif instead of staying sans inside a serif page. `report` is
12401
+ the author asking for serif; a theme that wants its own document face
12402
+ declares --doc-font at :root, which this variant deliberately outranks. */
12403
+ --doc-font: Georgia, 'Times New Roman', serif;
11692
12404
  line-height: 1.6;
11693
12405
  }
11694
12406
 
@@ -11783,7 +12495,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11783
12495
  z-index: var(--z-raised);
11784
12496
  margin-block-end: 0;
11785
12497
  padding-block-end: var(--doc-running-gap);
11786
- border-block-end: 1px solid var(--doc-print-border-color);
12498
+ border-block-end: var(--border-width) solid var(--doc-print-border-color);
11787
12499
  background: var(--doc-bg);
11788
12500
  transform: translateZ(0);
11789
12501
  }
@@ -11799,7 +12511,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11799
12511
  z-index: var(--z-raised);
11800
12512
  margin-block-start: 0;
11801
12513
  padding-block-start: var(--doc-running-gap);
11802
- border-block-start: 1px solid var(--doc-print-border-color);
12514
+ border-block-start: var(--border-width) solid var(--doc-print-border-color);
11803
12515
  background: var(--doc-bg);
11804
12516
  transform: translateZ(0);
11805
12517
  }
@@ -11828,7 +12540,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11828
12540
 
11829
12541
  /* === patterns/empty-state.css === */
11830
12542
  /* @ui:component empty-state */
11831
- /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-primary radius-lg shadow-sm space-2 space-3 space-4 space-6 space-8 space-10 font-sans text-sm text-base text-lg text-xl text-2xl weight-semibold leading-tight leading-normal duration-normal ease-default */
12543
+ /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-primary radius-lg shadow-sm space-2 space-3 space-4 space-6 space-8 space-10 font-heading font-body heading-tracking heading-transform heading-caps heading-leading text-sm text-base text-lg text-xl text-2xl weight-semibold leading-tight leading-normal duration-normal ease-default */
11832
12544
 
11833
12545
  /* ── Root ── */
11834
12546
  [data-ui="empty-state"] {
@@ -11839,7 +12551,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11839
12551
  text-align: center;
11840
12552
  padding: var(--space-8) var(--space-6);
11841
12553
  gap: var(--space-3);
11842
- font-family: var(--font-sans, system-ui, sans-serif);
12554
+ font-family: var(--font-body);
11843
12555
  }
11844
12556
 
11845
12557
  /* ── Icon ── */
@@ -11862,10 +12574,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11862
12574
 
11863
12575
  /* ── Title ── */
11864
12576
  [data-ui="empty-state"] [data-part="title"] {
11865
- font-family: var(--font-sans, system-ui, sans-serif);
12577
+ font-family: var(--font-heading);
11866
12578
  font-size: var(--text-lg);
11867
12579
  font-weight: var(--weight-semibold);
11868
- line-height: var(--leading-tight);
12580
+ letter-spacing: var(--heading-tracking);
12581
+ text-transform: var(--heading-transform);
12582
+ font-variant-caps: var(--heading-caps);
12583
+ line-height: var(--heading-leading);
11869
12584
  color: var(--color-fg);
11870
12585
  margin: 0;
11871
12586
  }
@@ -11963,7 +12678,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11963
12678
 
11964
12679
  /* === patterns/feature-grid.css === */
11965
12680
  /* @ui:component feature-grid */
11966
- /* @ui:tokens color-bg color-fg color-fg-muted color-primary color-primary-subtle space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 text-base text-lg text-xl text-3xl font-sans weight-semibold weight-bold leading-tight leading-normal leading-relaxed radius-md radius-lg */
12681
+ /* @ui:tokens color-bg color-fg color-fg-muted color-primary color-primary-subtle space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 text-base text-lg text-xl text-3xl font-body weight-semibold weight-bold leading-tight leading-normal leading-relaxed radius-md radius-lg */
11967
12682
 
11968
12683
  /* ── Root ──
11969
12684
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -11973,7 +12688,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11973
12688
  gap: var(--space-4);
11974
12689
  padding-block: var(--space-12);
11975
12690
  padding-inline: var(--space-4);
11976
- font-family: var(--font-sans, system-ui, sans-serif);
12691
+ font-family: var(--font-body);
11977
12692
  color: var(--color-fg);
11978
12693
  background: var(--color-bg);
11979
12694
  }
@@ -12115,7 +12830,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12115
12830
  max-inline-size: var(--measure-narrow);
12116
12831
  margin-inline: auto;
12117
12832
  padding-block: var(--space-8);
12118
- font-family: var(--font-sans);
12833
+ font-family: var(--font-body);
12119
12834
  }
12120
12835
 
12121
12836
  :where(form[l-data]:not([data-ui]) > h1) {
@@ -12135,7 +12850,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12135
12850
 
12136
12851
  /* === patterns/hero.css === */
12137
12852
  /* @ui:component hero */
12138
- /* @ui:tokens color-bg color-fg color-fg-muted space-3 space-4 space-6 space-8 space-12 space-16 space-20 text-sm text-base text-lg text-xl text-3xl text-4xl font-sans weight-bold weight-normal leading-tight leading-relaxed radius-lg */
12853
+ /* @ui:tokens color-bg color-fg color-fg-muted space-3 space-4 space-6 space-8 space-12 space-16 space-20 text-sm text-base text-lg text-xl text-3xl text-4xl font-heading font-body heading-weight heading-tracking heading-transform heading-caps heading-leading weight-bold weight-normal leading-tight leading-relaxed radius-lg texture-surface */
12139
12854
 
12140
12855
  /* ── Root ──
12141
12856
  A one-column grid by default; the layout variants only change how that grid
@@ -12149,9 +12864,10 @@ div[data-ui="separator"][data-style="thick"]::after {
12149
12864
  gap: var(--space-4);
12150
12865
  padding-block: var(--space-12);
12151
12866
  padding-inline: var(--space-4);
12152
- font-family: var(--font-sans, system-ui, sans-serif);
12867
+ font-family: var(--font-body);
12153
12868
  color: var(--color-fg);
12154
- background: var(--color-bg);
12869
+ background-color: var(--color-bg);
12870
+ background-image: var(--texture-surface);
12155
12871
  }
12156
12872
 
12157
12873
  /* ── Eyebrow ── */
@@ -12163,9 +12879,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12163
12879
  /* ── Headline ── */
12164
12880
  [data-ui="hero"] [data-part="headline"] {
12165
12881
  margin: 0;
12882
+ font-family: var(--font-heading);
12166
12883
  font-size: var(--text-3xl);
12167
- font-weight: var(--weight-bold);
12168
- line-height: var(--leading-tight);
12884
+ font-weight: var(--heading-weight);
12885
+ letter-spacing: var(--heading-tracking);
12886
+ text-transform: var(--heading-transform);
12887
+ font-variant-caps: var(--heading-caps);
12888
+ line-height: var(--heading-leading);
12169
12889
  color: var(--color-fg);
12170
12890
  text-wrap: balance;
12171
12891
  }
@@ -12284,7 +13004,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12284
13004
 
12285
13005
  /* === patterns/inbox.css === */
12286
13006
  /* @ui:component inbox */
12287
- /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-destructive color-primary color-primary-subtle color-ring space-1 space-2 space-3 space-4 space-6 space-px font-sans text-xs text-sm text-base text-xl weight-medium weight-semibold leading-tight leading-normal leading-relaxed radius-md radius-lg */
13007
+ /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-destructive color-primary color-primary-subtle color-ring space-1 space-2 space-3 space-4 space-6 space-px font-body text-xs text-sm text-base text-xl weight-medium weight-semibold leading-tight leading-normal leading-relaxed radius-md radius-lg focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
12288
13008
 
12289
13009
  /* ── Root ──
12290
13010
  ONE pane, because that is what a phone has room for. Each pane's `data-state`
@@ -12304,7 +13024,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12304
13024
  overflow: hidden;
12305
13025
  border: var(--space-px, 1px) solid var(--color-border);
12306
13026
  border-radius: var(--radius-lg);
12307
- font-family: var(--font-sans, system-ui, sans-serif);
13027
+ font-family: var(--font-body);
12308
13028
  color: var(--color-fg);
12309
13029
  background: var(--color-bg);
12310
13030
  }
@@ -12396,8 +13116,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12396
13116
  }
12397
13117
 
12398
13118
  [data-ui="inbox"] [data-part="item"]:focus-visible {
12399
- outline: 2px solid var(--color-ring);
12400
- outline-offset: 2px;
13119
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13120
+ outline-offset: var(--focus-ring-offset);
12401
13121
  }
12402
13122
 
12403
13123
  [data-ui="inbox"] [data-part="item"][data-state="selected"] {
@@ -12556,7 +13276,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12556
13276
 
12557
13277
  /* === patterns/pricing.css === */
12558
13278
  /* @ui:component pricing */
12559
- /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-primary-subtle color-primary-fg space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 text-sm text-base text-lg text-3xl font-sans weight-semibold weight-bold leading-tight leading-normal leading-relaxed radius-lg shadow-md */
13279
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-primary-subtle color-primary-fg space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 text-sm text-base text-lg text-3xl font-heading font-body heading-tracking heading-transform heading-caps heading-leading weight-semibold weight-bold leading-tight leading-normal leading-relaxed radius-lg shadow-md border-width-strong */
12560
13280
 
12561
13281
  /* ── Root ──
12562
13282
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -12566,7 +13286,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12566
13286
  gap: var(--space-4);
12567
13287
  padding-block: var(--space-12);
12568
13288
  padding-inline: var(--space-4);
12569
- font-family: var(--font-sans, system-ui, sans-serif);
13289
+ font-family: var(--font-body);
12570
13290
  color: var(--color-fg);
12571
13291
  background: var(--color-bg);
12572
13292
  }
@@ -12616,9 +13336,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12616
13336
 
12617
13337
  [data-ui="pricing"] [data-part="tier"] [data-part="title"] {
12618
13338
  margin: 0;
13339
+ font-family: var(--font-heading);
12619
13340
  font-size: var(--text-lg);
12620
13341
  font-weight: var(--weight-semibold);
12621
- line-height: var(--leading-tight);
13342
+ letter-spacing: var(--heading-tracking);
13343
+ text-transform: var(--heading-transform);
13344
+ font-variant-caps: var(--heading-caps);
13345
+ line-height: var(--heading-leading);
12622
13346
  }
12623
13347
 
12624
13348
  [data-ui="pricing"] [data-part="tier"] [data-part="header"] [data-part="description"] {
@@ -12679,7 +13403,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12679
13403
  [data-ui="pricing"] [data-part="tier"][data-state="featured"] {
12680
13404
  border-color: var(--color-primary);
12681
13405
  box-shadow: var(--shadow-md);
12682
- outline: var(--space-px, 1px) solid var(--color-primary);
13406
+ outline: var(--border-width-strong) solid var(--color-primary);
12683
13407
  }
12684
13408
 
12685
13409
  /* ── Footnote ── */
@@ -12724,14 +13448,14 @@ div[data-ui="separator"][data-style="thick"]::after {
12724
13448
 
12725
13449
  /* === patterns/search-results.css === */
12726
13450
  /* @ui:component search-results */
12727
- /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-fg radius-md radius-lg shadow-sm space-1 space-2 space-3 space-4 space-6 space-8 font-sans text-xs text-sm text-base text-lg weight-medium weight-semibold leading-tight leading-normal duration-fast duration-normal ease-default */
13451
+ /* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-fg radius-md radius-lg shadow-sm space-1 space-2 space-3 space-4 space-6 space-8 font-body text-xs text-sm text-base text-lg weight-medium weight-semibold leading-tight leading-normal duration-fast duration-normal ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
12728
13452
 
12729
13453
  /* ── Root ── */
12730
13454
  [data-ui="search-results"] {
12731
13455
  display: flex;
12732
13456
  flex-direction: column;
12733
13457
  gap: var(--space-4);
12734
- font-family: var(--font-sans, system-ui, sans-serif);
13458
+ font-family: var(--font-body);
12735
13459
  }
12736
13460
 
12737
13461
  /* ── Search Input ── */
@@ -12759,7 +13483,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12759
13483
  justify-content: space-between;
12760
13484
  gap: var(--space-4);
12761
13485
  padding-bottom: var(--space-2);
12762
- border-bottom: 1px solid var(--color-border);
13486
+ border-bottom: var(--border-width) solid var(--color-border);
12763
13487
  }
12764
13488
 
12765
13489
  [data-ui="search-results"] [data-part="results-count"] {
@@ -12794,7 +13518,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12794
13518
  flex-direction: column;
12795
13519
  gap: var(--space-2);
12796
13520
  padding: var(--space-4);
12797
- border: 1px solid var(--color-border);
13521
+ border: var(--border-width) solid var(--color-border);
12798
13522
  border-radius: var(--radius-md);
12799
13523
  background: var(--color-bg);
12800
13524
  transition: background var(--duration-fast) var(--ease-default),
@@ -12853,7 +13577,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12853
13577
  display: flex;
12854
13578
  justify-content: center;
12855
13579
  padding-top: var(--space-4);
12856
- border-top: 1px solid var(--color-border);
13580
+ border-top: var(--border-width) solid var(--color-border);
12857
13581
  }
12858
13582
 
12859
13583
  /* ── Loading ── */
@@ -12893,7 +13617,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12893
13617
 
12894
13618
  /* ── Error State ── */
12895
13619
  [data-ui="search-results"][data-state="error"] [data-part="results-list"] {
12896
- border: 1px solid var(--color-border);
13620
+ border: var(--border-width) solid var(--color-border);
12897
13621
  border-radius: var(--radius-md);
12898
13622
  padding: var(--space-6);
12899
13623
  text-align: center;
@@ -12902,8 +13626,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12902
13626
 
12903
13627
  /* ── Focus management ── */
12904
13628
  [data-ui="search-results"] [data-part="result-item"]:focus-visible {
12905
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
12906
- outline-offset: 2px;
13629
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13630
+ outline-offset: var(--focus-ring-offset);
12907
13631
  }
12908
13632
 
12909
13633
  /* ── Motion ── */
@@ -12919,7 +13643,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12919
13643
 
12920
13644
  /* === patterns/settings-page.css === */
12921
13645
  /* @ui:component settings-page */
12922
- /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-primary color-primary-fg space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-48 radius-md radius-lg shadow-sm shadow-md font-sans text-sm text-base text-lg text-xl weight-medium weight-semibold leading-tight leading-normal duration-fast duration-normal ease-default z-sticky */
13646
+ /* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-primary color-primary-fg space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-48 radius-md radius-lg shadow-sm shadow-md font-heading font-body heading-tracking heading-transform heading-caps heading-leading text-sm text-base text-lg text-xl weight-medium weight-semibold leading-tight leading-normal duration-fast duration-normal ease-default z-sticky border-width border-width-strong */
12923
13647
 
12924
13648
  /* ── Root ── */
12925
13649
  [data-ui="settings-page"] {
@@ -12929,7 +13653,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12929
13653
  width: 100%;
12930
13654
  max-width: 768px;
12931
13655
  margin-inline: auto;
12932
- font-family: var(--font-sans, system-ui, sans-serif);
13656
+ font-family: var(--font-body);
12933
13657
  color: var(--color-fg);
12934
13658
  }
12935
13659
 
@@ -12943,9 +13667,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12943
13667
  /* ── Title ── */
12944
13668
  [data-ui="settings-page"] [data-part="title"] {
12945
13669
  margin: 0;
13670
+ font-family: var(--font-heading);
12946
13671
  font-size: var(--text-xl, 1.25rem);
12947
13672
  font-weight: var(--weight-semibold, 600);
12948
- line-height: var(--leading-tight);
13673
+ letter-spacing: var(--heading-tracking);
13674
+ text-transform: var(--heading-transform);
13675
+ font-variant-caps: var(--heading-caps);
13676
+ line-height: var(--heading-leading);
12949
13677
  color: var(--color-fg);
12950
13678
  }
12951
13679
 
@@ -13009,7 +13737,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13009
13737
  gap: var(--space-3, 0.75rem);
13010
13738
  padding: var(--space-4);
13011
13739
  background: var(--color-bg);
13012
- border-top: 1px solid var(--color-border);
13740
+ border-top: var(--border-width) solid var(--color-border);
13013
13741
  border-radius: var(--radius-lg);
13014
13742
  box-shadow: var(--shadow-md);
13015
13743
  position: sticky;
@@ -13073,7 +13801,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13073
13801
  flex-direction: row;
13074
13802
  flex-wrap: wrap;
13075
13803
  border-inline-end: none;
13076
- border-bottom: 1px solid var(--color-border);
13804
+ border-bottom: var(--border-width) solid var(--color-border);
13077
13805
  padding-inline-end: 0;
13078
13806
  position: static;
13079
13807
  }
@@ -13092,7 +13820,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13092
13820
  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="list"] {
13093
13821
  flex-direction: column;
13094
13822
  border-bottom: none;
13095
- border-inline-end: 1px solid var(--color-border);
13823
+ border-inline-end: var(--border-width) solid var(--color-border);
13096
13824
  padding-inline-end: var(--space-4);
13097
13825
  position: sticky;
13098
13826
  top: var(--space-4);
@@ -13110,7 +13838,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13110
13838
  justify-content: flex-start;
13111
13839
  text-align: start;
13112
13840
  border-bottom: none;
13113
- border-inline-start: 2px solid transparent;
13841
+ border-inline-start: var(--border-width-strong) solid transparent;
13114
13842
  margin-bottom: 0;
13115
13843
  margin-inline-end: -1px;
13116
13844
  padding: var(--space-2) var(--space-3);
@@ -13144,7 +13872,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13144
13872
 
13145
13873
  /* === patterns/site-footer.css === */
13146
13874
  /* @ui:component site-footer */
13147
- /* @ui:tokens color-bg-subtle color-fg color-fg-muted color-border space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 text-sm text-base text-lg font-sans weight-semibold weight-bold leading-normal */
13875
+ /* @ui:tokens color-bg-subtle color-fg color-fg-muted color-border space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 text-sm text-base text-lg font-body weight-semibold weight-bold leading-normal border-width */
13148
13876
 
13149
13877
  /* ── Root ──
13150
13878
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -13154,11 +13882,11 @@ div[data-ui="separator"][data-style="thick"]::after {
13154
13882
  gap: var(--space-8);
13155
13883
  padding-block: var(--space-10);
13156
13884
  padding-inline: var(--space-4);
13157
- font-family: var(--font-sans, system-ui, sans-serif);
13885
+ font-family: var(--font-body);
13158
13886
  font-size: var(--text-sm);
13159
13887
  color: var(--color-fg-muted);
13160
13888
  background: var(--color-bg-subtle);
13161
- border-block-start: 1px solid var(--color-border);
13889
+ border-block-start: var(--border-width) solid var(--color-border);
13162
13890
  }
13163
13891
 
13164
13892
  /* ── Brand ── */
@@ -13290,7 +14018,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13290
14018
 
13291
14019
  /* === patterns/stats-dashboard.css === */
13292
14020
  /* @ui:component stats-dashboard */
13293
- /* @ui:tokens color-bg color-fg color-fg-muted color-border space-1 space-2 space-3 space-4 space-6 space-8 space-12 space-px font-sans text-sm text-base text-lg text-3xl weight-semibold weight-bold leading-tight leading-normal leading-relaxed */
14021
+ /* @ui:tokens color-bg color-fg color-fg-muted color-border space-1 space-2 space-3 space-4 space-6 space-8 space-12 space-px font-heading font-body heading-tracking heading-transform heading-caps heading-leading text-sm text-base text-lg text-3xl weight-semibold weight-bold leading-tight leading-normal leading-relaxed */
13294
14022
 
13295
14023
  /* ── Root ──
13296
14024
  A reporting page: title block, KPI row, then the panel region. The KPI row
@@ -13303,7 +14031,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13303
14031
  gap: var(--space-3);
13304
14032
  padding-block: var(--space-8);
13305
14033
  padding-inline: var(--space-4);
13306
- font-family: var(--font-sans, system-ui, sans-serif);
14034
+ font-family: var(--font-body);
13307
14035
  color: var(--color-fg);
13308
14036
  background: var(--color-bg);
13309
14037
  }
@@ -13377,9 +14105,13 @@ div[data-ui="separator"][data-style="thick"]::after {
13377
14105
 
13378
14106
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="title"] {
13379
14107
  margin: 0;
14108
+ font-family: var(--font-heading);
13380
14109
  font-size: var(--text-lg);
13381
14110
  font-weight: var(--weight-semibold);
13382
- line-height: var(--leading-tight);
14111
+ letter-spacing: var(--heading-tracking);
14112
+ text-transform: var(--heading-transform);
14113
+ font-variant-caps: var(--heading-caps);
14114
+ line-height: var(--heading-leading);
13383
14115
  }
13384
14116
 
13385
14117
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="header"] [data-part="description"] {
@@ -13470,7 +14202,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13470
14202
  gap: var(--space-6);
13471
14203
  max-inline-size: var(--measure-narrow);
13472
14204
  margin-inline: auto;
13473
- font-family: var(--font-sans);
14205
+ font-family: var(--font-body);
13474
14206
  }
13475
14207
 
13476
14208
  [data-ui="wizard"] [data-part="heading"] {