@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,6 +978,57 @@
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/terminal.css === */
645
1033
  /* @ui:theme terminal — phosphor green/amber on near-black; mono type, sharp corners; dark-primary CRT aesthetic */
646
1034
 
@@ -706,8 +1094,36 @@
706
1094
  --shadow-lg: 0 4px 10px oklch(0.25 0.05 145 / 0.14);
707
1095
  --shadow-xl: 0 8px 16px oklch(0.25 0.05 145 / 0.16);
708
1096
 
709
- /* ── Mono type everywhere: the UI face IS the code face ── */
710
- --font-sans: var(--font-mono);
1097
+ /* ── Mono type everywhere: the UI face IS the code face ──
1098
+ Said in ROLES since 1.1A-14. The theme used to alias the whole `--font-sans`
1099
+ PALETTE entry, which worked only because every role happened to point at it;
1100
+ naming the three roles is the same rendering and an honest statement — the
1101
+ palette still holds three faces, this theme just picks one for all of them. */
1102
+ --font-heading: var(--font-mono);
1103
+ --font-body: var(--font-mono);
1104
+ --font-ui: var(--font-mono);
1105
+
1106
+ /* ── Material: scanlines ──
1107
+ A CRT does not have a flat page. `--texture-stripes` is the registry's own
1108
+ repeating rule, tinted with `currentColor`, so the phosphor scheme carries
1109
+ its scanlines and the paper scheme gets the same ruling in ink. */
1110
+ --texture-page: var(--texture-stripes);
1111
+
1112
+ /* ── Motion (snappy — a terminal answers, it does not glide) ──
1113
+ A short duration ON an ease-out curve, which is what `snappy` names: the
1114
+ easing is re-pointed at this theme's own `--ease-out` rather than a literal. */
1115
+ --duration-normal: 140ms;
1116
+ --ease-default: var(--ease-out);
1117
+
1118
+ /* ── Focus: the cursor block, not a halo ──
1119
+ A negative offset draws the ring INSIDE the cell, the way a terminal
1120
+ highlights the field it is in. The literal is deliberate: a `calc()` here
1121
+ resolves to an expression, and an axis that cannot be read is an axis a
1122
+ theme cannot be selected by. */
1123
+ --focus-ring-offset: -2px;
1124
+
1125
+ /* ── Decoration: dashed rules, like a printout's fold ── */
1126
+ --divider-style: dashed;
711
1127
 
712
1128
  /* ── Radii (none — a terminal has sharp cells) ── */
713
1129
  --radius-sm: 0;
@@ -849,11 +1265,38 @@
849
1265
  padding: 0;
850
1266
  }
851
1267
 
1268
+ /* Colour scheme — the one place `data-theme` is translated into the platform's
1269
+ own scheme signal. `light-dark()` in a theme reads `color-scheme`, not
1270
+ `data-theme`, so a one-block theme [1.1A-06] resolves nothing at all without
1271
+ these three rules; declaring them here (rather than in each theme) is what
1272
+ makes the two authoring forms interchangeable. Nothing else in the registry
1273
+ declares `color-scheme`, so this is purely additive.
1274
+
1275
+ Specificity does the mapping: `:root` is (0,0,1) and each attribute selector
1276
+ is (0,1,0), so `<html data-theme="dark">` takes the dark rule over the root
1277
+ default while a bare `<html>` — and `data-theme="light"` — keeps light. The
1278
+ same rules apply to a NESTED element carrying `data-theme`, which is how a
1279
+ dark island inside a light page has always worked here. */
1280
+ :root {
1281
+ color-scheme: light;
1282
+ }
1283
+
1284
+ [data-theme="dark"] {
1285
+ color-scheme: dark;
1286
+ }
1287
+
1288
+ /* `auto` hands the choice to the OS: `light dark` means "either, system first",
1289
+ which is exactly what the `@media (prefers-color-scheme: dark)` mirror block
1290
+ does for a theme authored in the three-block form. */
1291
+ [data-theme="auto"] {
1292
+ color-scheme: light dark;
1293
+ }
1294
+
852
1295
  html {
853
1296
  -webkit-text-size-adjust: 100%;
854
1297
  -moz-tab-size: 4;
855
1298
  tab-size: 4;
856
- font-family: var(--font-sans);
1299
+ font-family: var(--font-body);
857
1300
  font-size: var(--text-base);
858
1301
  line-height: var(--leading-normal);
859
1302
  color: var(--color-fg);
@@ -864,6 +1307,11 @@ html {
864
1307
 
865
1308
  body {
866
1309
  min-height: 100dvh;
1310
+ /* The page's material. `none` by default (the initial value), so this is a
1311
+ no-op until a theme points --texture-page at one of tokens/textures.css.
1312
+ `html` keeps the background COLOUR; the texture rides on `body`, which
1313
+ covers the viewport, so the two compose instead of overwriting. */
1314
+ background-image: var(--texture-page);
867
1315
  }
868
1316
 
869
1317
  img,
@@ -933,10 +1381,32 @@ table {
933
1381
  }
934
1382
  }
935
1383
 
936
- /* Focus visible — default ring */
1384
+ /* Text selection — the decoration axis reaching the one surface no component
1385
+ owns. Until 1.1 the highlight was whatever the OS drew, which is the one part
1386
+ of a themed page that never matched the theme. Both values are tokens
1387
+ (tokens/aliases.css § Decoration), so a theme states its selection once. */
1388
+ ::selection {
1389
+ background-color: var(--selection-bg);
1390
+ color: var(--selection-fg);
1391
+ }
1392
+
1393
+ /* Focus visible — the default ring, and the only place it is spelled out.
1394
+ Every value is a token (tokens/effects.css § Focus), so a theme states its
1395
+ focus once and every element that has not drawn its own ring follows. */
937
1396
  :focus-visible {
938
- outline: 2px solid var(--color-ring);
939
- outline-offset: 2px;
1397
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1398
+ outline-offset: var(--focus-ring-offset);
1399
+ }
1400
+
1401
+ /* The glow a theme may put behind the ring, at zero specificity. `box-shadow`
1402
+ is not a property focus owns: an element's resting shadow — a card's depth,
1403
+ an author's own — lives there too, and a (0,1,0) rule here replaced it with
1404
+ `none` (the default) on every keyboard focus. Under `:where()` ANY rule that
1405
+ sets a shadow outranks this one, so it lands only on an element nothing else
1406
+ shadows, and it never takes a shadow away. The controls that draw their own
1407
+ ring read `--focus-shadow` in their own `:focus-visible` rules. */
1408
+ :where(:focus-visible) {
1409
+ box-shadow: var(--focus-shadow);
940
1410
  }
941
1411
 
942
1412
  /* Hidden but accessible */
@@ -965,7 +1435,7 @@ table {
965
1435
  /* @ui:base prose — typography defaults for long-form content */
966
1436
 
967
1437
  [data-ui="prose"] {
968
- font-family: var(--font-sans);
1438
+ font-family: var(--font-body);
969
1439
  font-size: var(--text-base);
970
1440
  line-height: var(--leading-relaxed);
971
1441
  color: var(--color-fg);
@@ -973,29 +1443,45 @@ table {
973
1443
  }
974
1444
 
975
1445
  [data-ui="prose"] h1 {
1446
+ font-family: var(--font-heading);
976
1447
  font-size: var(--text-4xl);
977
- font-weight: var(--weight-bold);
978
- line-height: var(--leading-tight);
1448
+ font-weight: var(--heading-weight);
1449
+ letter-spacing: var(--heading-tracking);
1450
+ text-transform: var(--heading-transform);
1451
+ font-variant-caps: var(--heading-caps);
1452
+ line-height: var(--heading-leading);
979
1453
  margin-block: var(--space-8) var(--space-4);
980
1454
  }
981
1455
 
982
1456
  [data-ui="prose"] h2 {
1457
+ font-family: var(--font-heading);
983
1458
  font-size: var(--text-3xl);
984
1459
  font-weight: var(--weight-semibold);
985
- line-height: var(--leading-tight);
1460
+ letter-spacing: var(--heading-tracking);
1461
+ text-transform: var(--heading-transform);
1462
+ font-variant-caps: var(--heading-caps);
1463
+ line-height: var(--heading-leading);
986
1464
  margin-block: var(--space-8) var(--space-3);
987
1465
  }
988
1466
 
989
1467
  [data-ui="prose"] h3 {
1468
+ font-family: var(--font-heading);
990
1469
  font-size: var(--text-2xl);
991
1470
  font-weight: var(--weight-semibold);
1471
+ letter-spacing: var(--heading-tracking);
1472
+ text-transform: var(--heading-transform);
1473
+ font-variant-caps: var(--heading-caps);
992
1474
  line-height: var(--leading-snug);
993
1475
  margin-block: var(--space-6) var(--space-3);
994
1476
  }
995
1477
 
996
1478
  [data-ui="prose"] h4 {
1479
+ font-family: var(--font-heading);
997
1480
  font-size: var(--text-xl);
998
1481
  font-weight: var(--weight-semibold);
1482
+ letter-spacing: var(--heading-tracking);
1483
+ text-transform: var(--heading-transform);
1484
+ font-variant-caps: var(--heading-caps);
999
1485
  line-height: var(--leading-snug);
1000
1486
  margin-block: var(--space-6) var(--space-2);
1001
1487
  }
@@ -1006,8 +1492,8 @@ table {
1006
1492
 
1007
1493
  [data-ui="prose"] a {
1008
1494
  color: var(--color-primary);
1009
- text-decoration: underline;
1010
- text-underline-offset: 2px;
1495
+ text-decoration-line: var(--link-decoration);
1496
+ text-underline-offset: var(--link-underline-offset);
1011
1497
  }
1012
1498
 
1013
1499
  [data-ui="prose"] a:hover {
@@ -1044,7 +1530,7 @@ table {
1044
1530
  }
1045
1531
 
1046
1532
  [data-ui="prose"] blockquote {
1047
- border-inline-start: 3px solid var(--color-border-strong);
1533
+ border-inline-start: var(--border-width-lg) solid var(--color-border-strong);
1048
1534
  padding-inline-start: var(--space-4);
1049
1535
  color: var(--color-fg-muted);
1050
1536
  margin-block: var(--space-4);
@@ -1066,9 +1552,15 @@ table {
1066
1552
  margin-block: var(--space-1);
1067
1553
  }
1068
1554
 
1555
+ /* The bullet. `currentColor` by default — the initial value — so a list looks
1556
+ exactly as it did; a theme that wants accented markers sets --marker-color. */
1557
+ [data-ui="prose"] li::marker {
1558
+ color: var(--marker-color);
1559
+ }
1560
+
1069
1561
  [data-ui="prose"] hr {
1070
1562
  border: none;
1071
- border-block-start: 1px solid var(--color-border);
1563
+ border-block-start: var(--border-width) solid var(--color-border);
1072
1564
  margin-block: var(--space-8);
1073
1565
  }
1074
1566
 
@@ -1087,12 +1579,12 @@ table {
1087
1579
  font-weight: var(--weight-semibold);
1088
1580
  text-align: start;
1089
1581
  padding: var(--space-2) var(--space-3);
1090
- border-block-end: 2px solid var(--color-border-strong);
1582
+ border-block-end: var(--border-width-strong) solid var(--color-border-strong);
1091
1583
  }
1092
1584
 
1093
1585
  [data-ui="prose"] td {
1094
1586
  padding: var(--space-2) var(--space-3);
1095
- border-block-end: 1px solid var(--color-border);
1587
+ border-block-end: var(--border-width) solid var(--color-border);
1096
1588
  }
1097
1589
 
1098
1590
  /* First child no top margin, last child no bottom margin */
@@ -1277,7 +1769,7 @@ table {
1277
1769
 
1278
1770
  /* === primitives/avatar.css === */
1279
1771
  /* @ui:component avatar */
1280
- /* @ui:tokens color-bg-muted color-fg-muted radius-full font-sans text-xs text-sm weight-medium */
1772
+ /* @ui:tokens color-bg-muted color-fg-muted radius-full font-ui text-xs text-sm weight-medium */
1281
1773
 
1282
1774
  /* ── Base ── */
1283
1775
  [data-ui="avatar"] {
@@ -1307,7 +1799,7 @@ table {
1307
1799
  height: 100%;
1308
1800
  background: var(--color-bg-muted);
1309
1801
  color: var(--color-fg-muted);
1310
- font-family: var(--font-sans);
1802
+ font-family: var(--font-ui);
1311
1803
  font-size: var(--text-sm);
1312
1804
  font-weight: var(--weight-medium);
1313
1805
  text-transform: uppercase;
@@ -1332,7 +1824,7 @@ table {
1332
1824
 
1333
1825
  /* === primitives/badge.css === */
1334
1826
  /* @ui:component badge */
1335
- /* @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 */
1827
+ /* @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 */
1336
1828
 
1337
1829
  /* ── Base ── */
1338
1830
  [data-ui="badge"] {
@@ -1342,9 +1834,10 @@ table {
1342
1834
  gap: var(--space-1);
1343
1835
  padding: 0.125rem var(--space-2);
1344
1836
  border-radius: var(--badge-radius, var(--radius-full));
1837
+ corner-shape: var(--corner-shape);
1345
1838
  background: var(--color-bg-muted);
1346
1839
  color: var(--color-fg);
1347
- font-family: var(--badge-font, var(--font-sans));
1840
+ font-family: var(--badge-font, var(--font-ui));
1348
1841
  font-size: var(--text-xs);
1349
1842
  font-weight: var(--weight-medium);
1350
1843
  line-height: 1.5;
@@ -1390,11 +1883,11 @@ table {
1390
1883
 
1391
1884
  /* === primitives/breadcrumb.css === */
1392
1885
  /* @ui:component breadcrumb */
1393
- /* @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 */
1886
+ /* @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 */
1394
1887
 
1395
1888
  /* ── Root ── */
1396
1889
  [data-ui="breadcrumb"] {
1397
- font-family: var(--breadcrumb-font, var(--font-sans));
1890
+ font-family: var(--breadcrumb-font, var(--font-ui));
1398
1891
  font-size: var(--breadcrumb-size, var(--text-sm));
1399
1892
  color: var(--color-fg-muted);
1400
1893
  }
@@ -1420,12 +1913,13 @@ table {
1420
1913
 
1421
1914
  [data-ui="breadcrumb"] [data-part="item"]:hover {
1422
1915
  color: var(--color-primary-hover);
1423
- text-decoration: underline;
1916
+ text-decoration-line: var(--link-decoration);
1424
1917
  }
1425
1918
 
1426
1919
  [data-ui="breadcrumb"] [data-part="item"]:focus-visible {
1427
- outline: 2px solid var(--color-ring);
1428
- outline-offset: 2px;
1920
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1921
+ outline-offset: var(--focus-ring-offset);
1922
+ box-shadow: var(--focus-shadow);
1429
1923
  }
1430
1924
 
1431
1925
  /* ── Separator (presentational) ── */
@@ -1465,7 +1959,7 @@ table {
1465
1959
 
1466
1960
  /* === primitives/button.css === */
1467
1961
  /* @ui:component button */
1468
- /* @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 */
1962
+ /* @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 */
1469
1963
 
1470
1964
  /* ── Base ── */
1471
1965
  [data-ui="button"] {
@@ -1475,18 +1969,21 @@ table {
1475
1969
  gap: var(--space-2);
1476
1970
  height: var(--button-height-md, 40px);
1477
1971
  padding-inline: var(--space-4);
1478
- border: 1px solid var(--color-border);
1972
+ border: var(--border-width) solid var(--color-border);
1479
1973
  border-radius: var(--button-radius, var(--radius-md));
1974
+ corner-shape: var(--corner-shape);
1480
1975
  background: var(--color-bg);
1481
1976
  color: var(--color-fg);
1482
- font-family: var(--font-sans);
1977
+ font-family: var(--font-ui);
1483
1978
  font-size: var(--text-sm);
1484
1979
  font-weight: var(--weight-medium);
1980
+ text-transform: var(--button-text-transform);
1485
1981
  line-height: 1;
1486
1982
  cursor: pointer;
1487
1983
  transition: background var(--duration-fast) var(--ease-default),
1488
1984
  border-color var(--duration-fast) var(--ease-default),
1489
1985
  color var(--duration-fast) var(--ease-default),
1986
+ translate var(--duration-fast) var(--ease-default),
1490
1987
  box-shadow var(--duration-fast) var(--ease-default);
1491
1988
  user-select: none;
1492
1989
  white-space: nowrap;
@@ -1495,11 +1992,16 @@ table {
1495
1992
 
1496
1993
  [data-ui="button"]:hover {
1497
1994
  background: var(--color-bg-muted);
1995
+ /* The hover lift. `none` by default — the initial value of `translate` — so
1996
+ this rule computes what the button computed before the token existed; a
1997
+ theme with a springy personality sets `--motion-hover-lift: 0 -1px`. */
1998
+ translate: var(--motion-hover-lift);
1498
1999
  }
1499
2000
 
1500
2001
  [data-ui="button"]:focus-visible {
1501
- outline: 2px solid var(--color-ring);
1502
- outline-offset: 2px;
2002
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2003
+ outline-offset: var(--focus-ring-offset);
2004
+ box-shadow: var(--focus-shadow);
1503
2005
  }
1504
2006
 
1505
2007
  /* ── Variants ── */
@@ -1555,7 +2057,7 @@ table {
1555
2057
  padding: 0;
1556
2058
  }
1557
2059
  [data-ui="button"][data-variant="link"]:hover {
1558
- text-decoration: underline;
2060
+ text-decoration-line: var(--link-decoration);
1559
2061
  }
1560
2062
 
1561
2063
  /* ── Sizes ── */
@@ -1574,7 +2076,7 @@ table {
1574
2076
  /* ── States ── */
1575
2077
  [data-ui="button"]:disabled,
1576
2078
  [data-ui="button"][data-state="disabled"] {
1577
- opacity: 0.5;
2079
+ opacity: var(--disabled-opacity);
1578
2080
  cursor: not-allowed;
1579
2081
  pointer-events: none;
1580
2082
  }
@@ -1589,7 +2091,7 @@ table {
1589
2091
  position: absolute;
1590
2092
  width: 1em;
1591
2093
  height: 1em;
1592
- border: 2px solid currentColor;
2094
+ border: var(--border-width-strong) solid currentColor;
1593
2095
  border-inline-end-color: transparent;
1594
2096
  border-radius: var(--radius-full);
1595
2097
  animation: faqir-spin 0.6s linear infinite;
@@ -1636,7 +2138,7 @@ table {
1636
2138
 
1637
2139
  /* === primitives/callout.css === */
1638
2140
  /* @ui:component callout */
1639
- /* @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 */
2141
+ /* @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 */
1640
2142
 
1641
2143
  /* ── Base ── */
1642
2144
  [data-ui="callout"] {
@@ -1645,7 +2147,7 @@ table {
1645
2147
  padding: var(--callout-padding-y) var(--callout-padding-x);
1646
2148
  border-radius: var(--callout-radius);
1647
2149
  border-inline-start: var(--callout-border-left-width) solid;
1648
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
2150
+ font-family: var(--doc-font, var(--font-body));
1649
2151
  font-size: var(--callout-font-size);
1650
2152
  line-height: var(--doc-line-height, 1.5);
1651
2153
  }
@@ -1676,6 +2178,7 @@ table {
1676
2178
  /* ── Title ── */
1677
2179
  [data-ui="callout"] [data-part="title"] {
1678
2180
  display: block;
2181
+ font-family: var(--font-heading);
1679
2182
  font-weight: var(--weight-semibold);
1680
2183
  margin-bottom: var(--doc-label-gap, var(--space-1, 0.25rem));
1681
2184
  }
@@ -1702,8 +2205,9 @@ table {
1702
2205
  }
1703
2206
 
1704
2207
  [data-ui="callout"] [data-part="dismiss"]:focus-visible {
1705
- outline: 2px solid var(--color-ring, var(--color-info));
1706
- outline-offset: 2px;
2208
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2209
+ outline-offset: var(--focus-ring-offset);
2210
+ box-shadow: var(--focus-shadow);
1707
2211
  opacity: 1;
1708
2212
  }
1709
2213
 
@@ -1789,17 +2293,36 @@ table {
1789
2293
 
1790
2294
  /* === primitives/card.css === */
1791
2295
  /* @ui:component card */
1792
- /* @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 */
2296
+ /* @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 */
1793
2297
 
1794
2298
  /* ── Base ── */
1795
2299
  [data-ui="card"] {
1796
2300
  display: flex;
1797
2301
  flex-direction: column;
1798
- border: 1px solid var(--card-border, var(--color-surface-1-border));
2302
+ border: var(--card-border-width) solid var(--card-border, var(--color-surface-1-border));
1799
2303
  border-radius: var(--card-radius, var(--radius-lg));
1800
- background: var(--card-bg, var(--color-surface-1));
2304
+ corner-shape: var(--corner-shape);
2305
+ /* One shorthand, two layers: the material on top, the fill beneath. The fill
2306
+ is the final layer, so `--card-bg` may be a colour OR a gradient — what 1.0
2307
+ projects set it to — and the texture (`none` by default) never clobbers it. */
2308
+ background: var(--texture-surface), var(--card-bg, var(--color-surface-1));
1801
2309
  box-shadow: var(--card-shadow, var(--shadow-sm));
1802
2310
  overflow: hidden;
2311
+ transition: translate var(--duration-fast) var(--ease-default);
2312
+ }
2313
+
2314
+ /* The hover lift, the same axis `button` reads. `none` by default (the initial
2315
+ value of `translate`), so a card sits exactly where it always sat until a
2316
+ theme says surfaces rise under the pointer. */
2317
+ [data-ui="card"]:hover {
2318
+ translate: var(--motion-hover-lift);
2319
+ }
2320
+
2321
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
2322
+ [data-ui="card"] {
2323
+ -webkit-backdrop-filter: var(--surface-backdrop);
2324
+ backdrop-filter: var(--surface-backdrop);
2325
+ }
1803
2326
  }
1804
2327
 
1805
2328
  /* ── Variants ── */
@@ -1808,7 +2331,7 @@ table {
1808
2331
  }
1809
2332
 
1810
2333
  [data-ui="card"][data-variant="filled"] {
1811
- background: var(--color-surface-2);
2334
+ background: var(--texture-surface), var(--color-surface-2);
1812
2335
  border-color: var(--color-surface-2-border);
1813
2336
  box-shadow: none;
1814
2337
  }
@@ -1823,7 +2346,7 @@ table {
1823
2346
  }
1824
2347
 
1825
2348
  [data-ui="card"] > [data-part="header"] > [data-part="title"] {
1826
- font-family: var(--font-sans);
2349
+ font-family: var(--font-heading);
1827
2350
  font-size: var(--text-lg);
1828
2351
  font-weight: var(--weight-semibold);
1829
2352
  line-height: var(--leading-tight);
@@ -1864,9 +2387,19 @@ table {
1864
2387
  padding-top: 0;
1865
2388
  }
1866
2389
 
2390
+ /* ── Motion ── */
2391
+ /* The hover lift is the only thing a card animates, and it is `none` until a
2392
+ theme states one — but the house rule is that a stylesheet which transitions
2393
+ carries its own opt-out, so a reader never has to check the token first. */
2394
+ @media (prefers-reduced-motion: reduce) {
2395
+ [data-ui="card"] {
2396
+ transition: none;
2397
+ }
2398
+ }
2399
+
1867
2400
  /* === primitives/checkbox.css === */
1868
2401
  /* @ui:component checkbox */
1869
- /* @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 */
2402
+ /* @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 */
1870
2403
 
1871
2404
  /* -- Label wrapper -- */
1872
2405
  [data-ui="checkbox-label"] {
@@ -1878,7 +2411,7 @@ table {
1878
2411
 
1879
2412
  [data-ui="checkbox-label"]:has([data-ui="checkbox"]:disabled) {
1880
2413
  cursor: not-allowed;
1881
- opacity: 0.5;
2414
+ opacity: var(--disabled-opacity);
1882
2415
  }
1883
2416
 
1884
2417
  /* -- Base -- */
@@ -1890,8 +2423,8 @@ table {
1890
2423
  width: var(--checkbox-size, 18px);
1891
2424
  height: var(--checkbox-size, 18px);
1892
2425
  flex-shrink: 0;
1893
- border: 1px solid var(--color-border);
1894
- border-radius: var(--checkbox-radius, var(--radius-sm));
2426
+ border: var(--border-width) solid var(--color-border);
2427
+ border-radius: var(--checkbox-radius);
1895
2428
  background: var(--color-bg);
1896
2429
  cursor: pointer;
1897
2430
  transition: background var(--duration-fast) var(--ease-default),
@@ -1904,8 +2437,9 @@ table {
1904
2437
  }
1905
2438
 
1906
2439
  [data-ui="checkbox"]:focus-visible {
1907
- outline: 2px solid var(--color-ring);
1908
- outline-offset: 2px;
2440
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2441
+ outline-offset: var(--focus-ring-offset);
2442
+ box-shadow: var(--focus-shadow);
1909
2443
  }
1910
2444
 
1911
2445
  /* -- Checked -- */
@@ -1996,7 +2530,7 @@ table {
1996
2530
  The mask has to opt out of the substitution to stay readable. [W3-3] */
1997
2531
  @media (forced-colors: active) {
1998
2532
  [data-ui="checkbox"] {
1999
- border: 1px solid ButtonText;
2533
+ border: var(--border-width) solid ButtonText;
2000
2534
  }
2001
2535
 
2002
2536
  [data-ui="checkbox"]:checked,
@@ -2020,7 +2554,7 @@ table {
2020
2554
 
2021
2555
  /* === primitives/chip.css === */
2022
2556
  /* @ui:component chip */
2023
- /* @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 */
2557
+ /* @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 */
2024
2558
 
2025
2559
  /* ── Base ── */
2026
2560
  [data-ui="chip"] {
@@ -2028,11 +2562,11 @@ table {
2028
2562
  align-items: center;
2029
2563
  gap: var(--space-1);
2030
2564
  padding: var(--space-1) var(--space-2);
2031
- border: 1px solid transparent;
2565
+ border: var(--border-width) solid transparent;
2032
2566
  border-radius: var(--chip-radius, var(--radius-full));
2033
2567
  background: var(--color-bg-muted);
2034
2568
  color: var(--color-fg);
2035
- font-family: var(--chip-font, var(--font-sans));
2569
+ font-family: var(--chip-font, var(--font-ui));
2036
2570
  font-size: var(--text-sm);
2037
2571
  font-weight: var(--weight-medium);
2038
2572
  line-height: 1.2;
@@ -2068,8 +2602,11 @@ table {
2068
2602
  }
2069
2603
 
2070
2604
  [data-ui="chip"] [data-part="dismiss"]:focus-visible {
2071
- outline: 2px solid var(--color-ring);
2072
- outline-offset: 1px;
2605
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2606
+ /* Half the default gap — the dismiss target is small, and the full ring
2607
+ would collide with the chip's own edge. */
2608
+ outline-offset: calc(var(--focus-ring-offset) / 2);
2609
+ box-shadow: var(--focus-shadow);
2073
2610
  }
2074
2611
 
2075
2612
  /* ── Variants ── */
@@ -2292,12 +2829,12 @@ table {
2292
2829
 
2293
2830
  /* === primitives/collapsible.css === */
2294
2831
  /* @ui:component collapsible */
2295
- /* @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 */
2832
+ /* @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 */
2296
2833
 
2297
2834
  /* ── Root — native <details>, so it opens/closes with zero JavaScript ── */
2298
2835
  [data-ui="collapsible"] {
2299
2836
  border-radius: var(--collapsible-radius, var(--radius-md));
2300
- font-family: var(--collapsible-font, var(--font-sans));
2837
+ font-family: var(--collapsible-font, var(--font-ui));
2301
2838
  color: var(--color-fg);
2302
2839
  }
2303
2840
 
@@ -2327,8 +2864,9 @@ table {
2327
2864
  }
2328
2865
 
2329
2866
  [data-ui="collapsible"] [data-part="trigger"]:focus-visible {
2330
- outline: 2px solid var(--color-ring);
2331
- outline-offset: 2px;
2867
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2868
+ outline-offset: var(--focus-ring-offset);
2869
+ box-shadow: var(--focus-shadow);
2332
2870
  }
2333
2871
 
2334
2872
  /* Chevron indicator — rotates when open, CSS-only */
@@ -2337,8 +2875,8 @@ table {
2337
2875
  flex: none;
2338
2876
  width: 0.5em;
2339
2877
  height: 0.5em;
2340
- border-inline-end: 2px solid var(--color-fg-muted);
2341
- border-block-end: 2px solid var(--color-fg-muted);
2878
+ border-inline-end: var(--border-width-strong) solid var(--color-fg-muted);
2879
+ border-block-end: var(--border-width-strong) solid var(--color-fg-muted);
2342
2880
  transform: rotate(45deg);
2343
2881
  transition: transform var(--duration-normal) var(--ease-default);
2344
2882
  }
@@ -2357,7 +2895,7 @@ table {
2357
2895
 
2358
2896
  /* ── Bordered variant ── */
2359
2897
  [data-ui="collapsible"][data-variant="bordered"] {
2360
- border: 1px solid var(--color-border);
2898
+ border: var(--border-width) solid var(--color-border);
2361
2899
  }
2362
2900
 
2363
2901
  /* ── Open/close animation via ::details-content, where supported ── */
@@ -2490,13 +3028,13 @@ table {
2490
3028
 
2491
3029
  /* === primitives/description-list.css === */
2492
3030
  /* @ui:component description-list */
2493
- /* @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 */
3031
+ /* @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 */
2494
3032
 
2495
3033
  /* ── Base ── */
2496
3034
  [data-ui="description-list"] {
2497
3035
  margin: 0;
2498
3036
  padding: 0;
2499
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3037
+ font-family: var(--doc-font, var(--font-body));
2500
3038
  }
2501
3039
 
2502
3040
  /* ── Term ── */
@@ -2552,7 +3090,7 @@ table {
2552
3090
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"],
2553
3091
  [data-ui="description-list"][data-divided]:not([data-variant]) [data-part="details"] {
2554
3092
  padding-bottom: var(--space-4);
2555
- border-bottom: 1px solid var(--color-border);
3093
+ border-bottom: var(--border-width) solid var(--color-border);
2556
3094
  }
2557
3095
 
2558
3096
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"]:last-child,
@@ -2564,7 +3102,7 @@ table {
2564
3102
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="term"],
2565
3103
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="details"] {
2566
3104
  padding-bottom: var(--space-3);
2567
- border-bottom: 1px solid var(--color-border);
3105
+ border-bottom: var(--border-width) solid var(--color-border);
2568
3106
  }
2569
3107
 
2570
3108
  /* ── Size: Small ── */
@@ -2602,7 +3140,7 @@ table {
2602
3140
 
2603
3141
  /* === primitives/empty-state.css === */
2604
3142
  /* @ui:component empty-state */
2605
- /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl */
3143
+ /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl font-heading */
2606
3144
 
2607
3145
  /* ── Base ── */
2608
3146
  [data-ui="empty-state"] {
@@ -2623,6 +3161,7 @@ table {
2623
3161
 
2624
3162
  /* ── Title ── */
2625
3163
  [data-ui="empty-state"] [data-part="title"] {
3164
+ font-family: var(--font-heading);
2626
3165
  font-size: var(--text-lg);
2627
3166
  font-weight: var(--weight-medium);
2628
3167
  color: var(--color-fg);
@@ -2670,7 +3209,7 @@ table {
2670
3209
 
2671
3210
  /* === primitives/field-group.css === */
2672
3211
  /* @ui:component field-group */
2673
- /* @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 */
3212
+ /* @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 */
2674
3213
 
2675
3214
  /* ── Base / spacing ownership ──
2676
3215
  A field-group owns only its tight, density-aware intra-field step: label →
@@ -2682,7 +3221,7 @@ table {
2682
3221
  display: flex;
2683
3222
  flex-direction: column;
2684
3223
  gap: var(--space-2);
2685
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3224
+ font-family: var(--doc-font, var(--font-body));
2686
3225
  }
2687
3226
 
2688
3227
  /* ── Label ── */
@@ -2752,7 +3291,7 @@ table {
2752
3291
  [data-ui="field-group"][data-state="invalid"] [data-ui="textarea"],
2753
3292
  [data-ui="field-group"][data-state="invalid"] [data-ui="select"] {
2754
3293
  border-color: var(--field-error-color);
2755
- box-shadow: 0 0 0 1px var(--field-error-color);
3294
+ box-shadow: 0 0 0 var(--border-width) var(--field-error-color);
2756
3295
  }
2757
3296
 
2758
3297
  /* ── State: Validating ──
@@ -2762,7 +3301,7 @@ table {
2762
3301
  [data-ui="field-group"][data-state="validating"] [data-ui="textarea"],
2763
3302
  [data-ui="field-group"][data-state="validating"] [data-ui="select"] {
2764
3303
  border-color: var(--field-validating-color);
2765
- box-shadow: 0 0 0 1px var(--field-validating-color);
3304
+ box-shadow: 0 0 0 var(--border-width) var(--field-validating-color);
2766
3305
  }
2767
3306
 
2768
3307
  /* ── State: Disabled ──
@@ -2781,8 +3320,8 @@ table {
2781
3320
  [data-ui="field-group"][data-state="valid"] [data-ui="input"],
2782
3321
  [data-ui="field-group"][data-state="valid"] [data-ui="textarea"],
2783
3322
  [data-ui="field-group"][data-state="valid"] [data-ui="select"] {
2784
- border-color: var(--color-success, oklch(0.62 0.19 145));
2785
- box-shadow: 0 0 0 1px var(--color-success, oklch(0.62 0.19 145));
3323
+ border-color: var(--color-success);
3324
+ box-shadow: 0 0 0 var(--border-width) var(--color-success);
2786
3325
  }
2787
3326
 
2788
3327
  /* ── Variant: Horizontal ── */
@@ -3087,7 +3626,7 @@ table {
3087
3626
 
3088
3627
  /* === primitives/image.css === */
3089
3628
  /* @ui:component image */
3090
- /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-sans */
3629
+ /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-body */
3091
3630
 
3092
3631
  /* ── Base ── */
3093
3632
  [data-ui="image"] {
@@ -3111,7 +3650,7 @@ table {
3111
3650
  [data-ui="image"] [data-part="caption"] {
3112
3651
  display: block;
3113
3652
  margin-top: var(--space-2);
3114
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3653
+ font-family: var(--doc-font, var(--font-body));
3115
3654
  font-size: var(--image-caption-size);
3116
3655
  color: var(--image-caption-color);
3117
3656
  line-height: 1.4;
@@ -3208,7 +3747,7 @@ table {
3208
3747
 
3209
3748
  /* === primitives/input.css === */
3210
3749
  /* @ui:component input */
3211
- /* @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 */
3750
+ /* @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 */
3212
3751
 
3213
3752
  /* ── Base ── */
3214
3753
  [data-ui="input"] {
@@ -3216,11 +3755,18 @@ table {
3216
3755
  width: 100%;
3217
3756
  height: var(--input-height, 40px);
3218
3757
  padding-inline: var(--space-3);
3219
- border: 1px solid var(--color-border);
3758
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
3759
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
3760
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
3761
+ is drawn. Identical to the shorthand at every other value of the token. */
3762
+ border-style: solid;
3763
+ border-color: var(--color-border);
3764
+ border-width: var(--input-border-width);
3220
3765
  border-radius: var(--input-radius, var(--radius-md));
3221
- background: var(--input-bg, var(--color-bg));
3766
+ corner-shape: var(--corner-shape);
3767
+ background: var(--input-fill);
3222
3768
  color: var(--color-fg);
3223
- font-family: var(--input-font, var(--font-sans));
3769
+ font-family: var(--input-font, var(--font-ui));
3224
3770
  font-size: var(--text-sm);
3225
3771
  line-height: 1;
3226
3772
  transition: border-color var(--duration-fast) var(--ease-default),
@@ -3236,8 +3782,11 @@ table {
3236
3782
  }
3237
3783
 
3238
3784
  [data-ui="input"]:focus {
3239
- outline: 2px solid var(--color-ring);
3240
- outline-offset: -1px;
3785
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
3786
+ /* The ring replaces the border rather than sitting outside it: inset by
3787
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
3788
+ outline-offset: calc(-1 * var(--input-border-width));
3789
+ box-shadow: var(--focus-shadow);
3241
3790
  border-color: transparent;
3242
3791
  }
3243
3792
 
@@ -3265,7 +3814,7 @@ table {
3265
3814
  }
3266
3815
 
3267
3816
  [data-ui="input"]:disabled {
3268
- opacity: 0.5;
3817
+ opacity: var(--disabled-opacity);
3269
3818
  cursor: not-allowed;
3270
3819
  }
3271
3820
 
@@ -3328,7 +3877,7 @@ table {
3328
3877
 
3329
3878
  /* === primitives/kbd.css === */
3330
3879
  /* @ui:component kbd */
3331
- /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs */
3880
+ /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs border-width border-width-strong */
3332
3881
 
3333
3882
  /* ── Base ── */
3334
3883
  [data-ui="kbd"] {
@@ -3338,8 +3887,8 @@ table {
3338
3887
  height: 20px;
3339
3888
  min-width: 20px;
3340
3889
  padding-inline: var(--space-1h);
3341
- border: 1px solid var(--color-border);
3342
- border-bottom-width: 2px;
3890
+ border: var(--border-width) solid var(--color-border);
3891
+ border-bottom-width: var(--border-width-strong);
3343
3892
  border-radius: var(--radius-sm);
3344
3893
  background: var(--color-bg-subtle);
3345
3894
  color: var(--color-fg);
@@ -3352,7 +3901,7 @@ table {
3352
3901
 
3353
3902
  /* === primitives/key-value.css === */
3354
3903
  /* @ui:component key-value */
3355
- /* @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 */
3904
+ /* @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 */
3356
3905
 
3357
3906
  /* ── Base ── */
3358
3907
  [data-ui="key-value"] {
@@ -3361,7 +3910,7 @@ table {
3361
3910
  gap: var(--kv-pair-gap);
3362
3911
  margin: 0;
3363
3912
  padding: 0;
3364
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3913
+ font-family: var(--doc-font, var(--font-body));
3365
3914
  }
3366
3915
 
3367
3916
  /* ── Label ── */
@@ -3491,12 +4040,12 @@ table {
3491
4040
 
3492
4041
  /* === primitives/label.css === */
3493
4042
  /* @ui:component label */
3494
- /* @ui:tokens color-fg color-fg-muted color-destructive font-sans text-xs text-sm text-base weight-medium */
4043
+ /* @ui:tokens color-fg color-fg-muted color-destructive font-ui text-xs text-sm text-base weight-medium disabled-opacity */
3495
4044
 
3496
4045
  /* ── Base ── */
3497
4046
  [data-ui="label"] {
3498
4047
  display: block;
3499
- font-family: var(--font-sans);
4048
+ font-family: var(--font-ui);
3500
4049
  font-size: var(--text-sm);
3501
4050
  font-weight: var(--weight-medium);
3502
4051
  color: var(--color-fg);
@@ -3529,21 +4078,21 @@ table {
3529
4078
 
3530
4079
  /* ── States ── */
3531
4080
  [data-ui="label"][data-state="disabled"] {
3532
- opacity: 0.5;
4081
+ opacity: var(--disabled-opacity);
3533
4082
  cursor: not-allowed;
3534
4083
  }
3535
4084
 
3536
4085
  /* === primitives/link.css === */
3537
4086
  /* @ui:component link */
3538
- /* @ui:tokens color-primary color-primary-hover color-primary-active color-fg color-fg-muted color-ring radius-sm space-1 */
4087
+ /* @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 */
3539
4088
 
3540
4089
  /* ── Base ── */
3541
4090
  [data-ui="link"] {
3542
4091
  color: var(--color-primary);
3543
4092
  font-family: inherit;
3544
- text-decoration: underline;
3545
- text-decoration-thickness: 1px;
3546
- text-underline-offset: 0.2em;
4093
+ text-decoration-line: var(--link-decoration);
4094
+ text-decoration-thickness: var(--link-thickness);
4095
+ text-underline-offset: var(--link-underline-offset);
3547
4096
  border-radius: var(--radius-sm);
3548
4097
  cursor: pointer;
3549
4098
  }
@@ -3557,8 +4106,9 @@ table {
3557
4106
  }
3558
4107
 
3559
4108
  [data-ui="link"]:focus-visible {
3560
- outline: 2px solid var(--color-ring);
3561
- outline-offset: 2px;
4109
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4110
+ outline-offset: var(--focus-ring-offset);
4111
+ box-shadow: var(--focus-shadow);
3562
4112
  }
3563
4113
 
3564
4114
  /* ── Variants ── */
@@ -3582,7 +4132,7 @@ table {
3582
4132
 
3583
4133
  /* === primitives/nav.css === */
3584
4134
  /* @ui:component nav */
3585
- /* @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 */
4135
+ /* @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 */
3586
4136
 
3587
4137
  /* ── Base ── */
3588
4138
  [data-ui="nav"] {
@@ -3632,14 +4182,14 @@ table {
3632
4182
 
3633
4183
  /* ── Underline variant ── */
3634
4184
  [data-ui="nav"][data-variant="underline"] {
3635
- border-bottom: 1px solid var(--color-border);
4185
+ border-bottom: var(--border-width) solid var(--color-border);
3636
4186
  gap: 0;
3637
4187
  }
3638
4188
 
3639
4189
  [data-ui="nav"][data-variant="underline"] [data-part="link"] {
3640
4190
  border-radius: 0;
3641
4191
  padding: var(--space-2) var(--space-4);
3642
- border-bottom: 2px solid transparent;
4192
+ border-bottom: var(--border-width-strong) solid transparent;
3643
4193
  margin-bottom: -1px;
3644
4194
  }
3645
4195
 
@@ -3695,7 +4245,7 @@ table {
3695
4245
 
3696
4246
  /* === primitives/page-break.css === */
3697
4247
  /* @ui:component page-break */
3698
- /* @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 */
4248
+ /* @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 */
3699
4249
 
3700
4250
  /* ── Base (Screen) ── */
3701
4251
  [data-ui="page-break"] {
@@ -3710,12 +4260,12 @@ table {
3710
4260
  [data-ui="page-break"]::after {
3711
4261
  content: "";
3712
4262
  flex: 1;
3713
- border-top: 1px var(--page-break-screen-style) var(--page-break-screen-color);
4263
+ border-top: var(--border-width) var(--page-break-screen-style) var(--page-break-screen-color);
3714
4264
  }
3715
4265
 
3716
4266
  /* ── Label (Screen) ── */
3717
4267
  [data-ui="page-break"] {
3718
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4268
+ font-family: var(--doc-font, var(--font-body));
3719
4269
  font-size: var(--page-break-screen-label-size);
3720
4270
  color: var(--page-break-screen-label-color);
3721
4271
  letter-spacing: 0.05em;
@@ -3757,7 +4307,7 @@ table {
3757
4307
 
3758
4308
  /* === primitives/progress.css === */
3759
4309
  /* @ui:component progress */
3760
- /* @ui:tokens color-primary color-bg-muted color-success color-warning color-destructive radius-full radius-md space-1 duration-normal ease-default */
4310
+ /* @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 */
3761
4311
 
3762
4312
  /* ── Base ── */
3763
4313
  [data-ui="progress"] {
@@ -3832,7 +4382,7 @@ table {
3832
4382
  substitution and paints `Highlight`; the track keeps a visible boundary. [W3-3] */
3833
4383
  @media (forced-colors: active) {
3834
4384
  [data-ui="progress"] [data-part="track"] {
3835
- border: 1px solid ButtonText;
4385
+ border: var(--border-width) solid ButtonText;
3836
4386
  }
3837
4387
 
3838
4388
  [data-ui="progress"] [data-part="fill"],
@@ -3846,7 +4396,7 @@ table {
3846
4396
 
3847
4397
  /* === primitives/radio.css === */
3848
4398
  /* @ui:component radio */
3849
- /* @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 */
4399
+ /* @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 */
3850
4400
 
3851
4401
  /* -- Radio group -- */
3852
4402
  [data-ui="radio-group"] {
@@ -3868,7 +4418,7 @@ table {
3868
4418
 
3869
4419
  [data-ui="radio-label"]:has([data-ui="radio"]:disabled) {
3870
4420
  cursor: not-allowed;
3871
- opacity: 0.5;
4421
+ opacity: var(--disabled-opacity);
3872
4422
  }
3873
4423
 
3874
4424
  /* -- Base -- */
@@ -3880,7 +4430,7 @@ table {
3880
4430
  width: var(--radio-size, 18px);
3881
4431
  height: var(--radio-size, 18px);
3882
4432
  flex-shrink: 0;
3883
- border: 1px solid var(--color-border);
4433
+ border: var(--border-width) solid var(--color-border);
3884
4434
  border-radius: var(--radius-full);
3885
4435
  background: var(--color-bg);
3886
4436
  cursor: pointer;
@@ -3894,8 +4444,9 @@ table {
3894
4444
  }
3895
4445
 
3896
4446
  [data-ui="radio"]:focus-visible {
3897
- outline: 2px solid var(--color-ring);
3898
- outline-offset: 2px;
4447
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4448
+ outline-offset: var(--focus-ring-offset);
4449
+ box-shadow: var(--focus-shadow);
3899
4450
  }
3900
4451
 
3901
4452
  /* -- Checked -- */
@@ -3948,7 +4499,7 @@ table {
3948
4499
  inside a `--color-primary` circle, and the OS collapses both to one colour. [W3-3] */
3949
4500
  @media (forced-colors: active) {
3950
4501
  [data-ui="radio"] {
3951
- border: 1px solid ButtonText;
4502
+ border: var(--border-width) solid ButtonText;
3952
4503
  }
3953
4504
 
3954
4505
  [data-ui="radio"]:checked {
@@ -3968,7 +4519,7 @@ table {
3968
4519
 
3969
4520
  /* === primitives/select.css === */
3970
4521
  /* @ui:component select */
3971
- /* @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 */
4522
+ /* @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 */
3972
4523
 
3973
4524
  /* -- Base -- */
3974
4525
  [data-ui="select"] {
@@ -3977,11 +4528,17 @@ table {
3977
4528
  height: var(--select-height, 40px);
3978
4529
  padding-inline: var(--space-3);
3979
4530
  padding-inline-end: var(--space-8, 2rem);
3980
- border: 1px solid var(--color-border);
4531
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
4532
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
4533
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
4534
+ is drawn. Identical to the shorthand at every other value of the token. */
4535
+ border-style: solid;
4536
+ border-color: var(--color-border);
4537
+ border-width: var(--input-border-width);
3981
4538
  border-radius: var(--select-radius, var(--radius-md));
3982
- background: var(--select-bg, var(--color-bg));
4539
+ background: var(--select-bg, var(--input-fill));
3983
4540
  color: var(--color-fg);
3984
- font-family: var(--select-font, var(--font-sans));
4541
+ font-family: var(--select-font, var(--font-ui));
3985
4542
  font-size: var(--text-sm);
3986
4543
  line-height: 1;
3987
4544
  cursor: pointer;
@@ -4011,8 +4568,11 @@ table {
4011
4568
  }
4012
4569
 
4013
4570
  [data-ui="select"]:focus {
4014
- outline: 2px solid var(--color-ring);
4015
- outline-offset: -1px;
4571
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4572
+ /* The ring replaces the border rather than sitting outside it: inset by
4573
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
4574
+ outline-offset: calc(-1 * var(--input-border-width));
4575
+ box-shadow: var(--focus-shadow);
4016
4576
  border-color: transparent;
4017
4577
  }
4018
4578
 
@@ -4045,7 +4605,7 @@ table {
4045
4605
  }
4046
4606
 
4047
4607
  [data-ui="select"]:disabled {
4048
- opacity: 0.5;
4608
+ opacity: var(--disabled-opacity);
4049
4609
  cursor: not-allowed;
4050
4610
  }
4051
4611
 
@@ -4058,12 +4618,12 @@ table {
4058
4618
 
4059
4619
  /* === primitives/separator.css === */
4060
4620
  /* @ui:component separator */
4061
- /* @ui:tokens color-border space-4 text-xs color-fg-muted font-sans */
4621
+ /* @ui:tokens color-border space-4 text-xs color-fg-muted font-ui border-width-strong divider-width divider-style */
4062
4622
 
4063
4623
  /* ── Base (horizontal) ── */
4064
4624
  [data-ui="separator"] {
4065
4625
  border: none;
4066
- border-top: 1px solid var(--color-border);
4626
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
4067
4627
  margin: 0;
4068
4628
  width: 100%;
4069
4629
  }
@@ -4071,7 +4631,7 @@ table {
4071
4631
  /* ── Vertical ── */
4072
4632
  [data-ui="separator"][data-variant="vertical"] {
4073
4633
  border-top: none;
4074
- border-inline-start: 1px solid var(--color-border);
4634
+ border-inline-start: var(--divider-width) var(--divider-style) var(--color-border);
4075
4635
  width: auto;
4076
4636
  height: 100%;
4077
4637
  align-self: stretch;
@@ -4089,11 +4649,11 @@ div[data-ui="separator"]::before,
4089
4649
  div[data-ui="separator"]::after {
4090
4650
  content: "";
4091
4651
  flex: 1;
4092
- border-top: 1px solid var(--color-border);
4652
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
4093
4653
  }
4094
4654
 
4095
4655
  [data-ui="separator"] [data-part="label"] {
4096
- font-family: var(--font-sans);
4656
+ font-family: var(--font-ui);
4097
4657
  font-size: var(--text-xs);
4098
4658
  color: var(--color-fg-muted);
4099
4659
  white-space: nowrap;
@@ -4131,17 +4691,17 @@ div[data-ui="separator"][data-style="dotted"]::after {
4131
4691
 
4132
4692
  /* ── Style: Thick ── */
4133
4693
  [data-ui="separator"][data-style="thick"] {
4134
- border-top-width: 2px;
4694
+ border-top-width: var(--border-width-strong);
4135
4695
  }
4136
4696
 
4137
4697
  [data-ui="separator"][data-style="thick"][data-variant="vertical"] {
4138
4698
  border-top-width: 0;
4139
- border-inline-start-width: 2px;
4699
+ border-inline-start-width: var(--border-width-strong);
4140
4700
  }
4141
4701
 
4142
4702
  div[data-ui="separator"][data-style="thick"]::before,
4143
4703
  div[data-ui="separator"][data-style="thick"]::after {
4144
- border-top-width: 2px;
4704
+ border-top-width: var(--border-width-strong);
4145
4705
  }
4146
4706
 
4147
4707
  /* ── Vertical Sizes ── */
@@ -4159,20 +4719,20 @@ div[data-ui="separator"][data-style="thick"]::after {
4159
4719
 
4160
4720
  /* === primitives/signature.css === */
4161
4721
  /* @ui:component signature */
4162
- /* @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 */
4722
+ /* @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 */
4163
4723
 
4164
4724
  /* ── Base ── */
4165
4725
  [data-ui="signature"] {
4166
4726
  display: flex;
4167
4727
  flex-direction: column;
4168
4728
  gap: var(--space-2);
4169
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4729
+ font-family: var(--doc-font, var(--font-body));
4170
4730
  margin-top: var(--doc-signature-gap);
4171
4731
  }
4172
4732
 
4173
4733
  /* ── Line ── */
4174
4734
  [data-ui="signature"] [data-part="line"] {
4175
- border-top: 1px solid var(--doc-signature-line-color);
4735
+ border-top: var(--border-width) solid var(--doc-signature-line-color);
4176
4736
  min-height: 1px;
4177
4737
  }
4178
4738
 
@@ -4275,14 +4835,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4275
4835
 
4276
4836
  /* === primitives/spinner.css === */
4277
4837
  /* @ui:component spinner */
4278
- /* @ui:tokens color-border color-primary radius-full duration-normal ease-default */
4838
+ /* @ui:tokens color-border color-primary radius-full duration-normal ease-default border-width-strong border-width-lg */
4279
4839
 
4280
4840
  /* ── Base ── */
4281
4841
  [data-ui="spinner"] {
4282
4842
  display: inline-block;
4283
4843
  width: 24px;
4284
4844
  height: 24px;
4285
- border: 2px solid var(--color-border);
4845
+ border: var(--border-width-strong) solid var(--color-border);
4286
4846
  border-top-color: var(--color-primary);
4287
4847
  border-radius: var(--radius-full);
4288
4848
  animation: faqir-spin 0.75s linear infinite;
@@ -4298,13 +4858,13 @@ div[data-ui="separator"][data-style="thick"]::after {
4298
4858
  [data-ui="spinner"][data-size="lg"] {
4299
4859
  width: 32px;
4300
4860
  height: 32px;
4301
- border-width: 3px;
4861
+ border-width: var(--border-width-lg);
4302
4862
  }
4303
4863
 
4304
4864
  [data-ui="spinner"][data-size="xl"] {
4305
4865
  width: 48px;
4306
4866
  height: 48px;
4307
- border-width: 3px;
4867
+ border-width: var(--border-width-lg);
4308
4868
  }
4309
4869
 
4310
4870
  /* ── Motion ── */
@@ -4886,14 +5446,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4886
5446
 
4887
5447
  /* === primitives/stat.css === */
4888
5448
  /* @ui:component stat */
4889
- /* @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 */
5449
+ /* @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 */
4890
5450
 
4891
5451
  /* ── Base ── */
4892
5452
  [data-ui="stat"] {
4893
5453
  display: flex;
4894
5454
  flex-direction: column;
4895
5455
  gap: var(--space-1);
4896
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
5456
+ font-family: var(--doc-font, var(--font-body));
4897
5457
  }
4898
5458
 
4899
5459
  /* ── Label ── */
@@ -4907,6 +5467,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4907
5467
 
4908
5468
  /* ── Value ── */
4909
5469
  [data-ui="stat"] [data-part="value"] {
5470
+ font-family: var(--font-heading);
4910
5471
  font-size: var(--stat-value-size);
4911
5472
  font-weight: var(--stat-value-weight);
4912
5473
  color: var(--color-fg);
@@ -4965,10 +5526,10 @@ div[data-ui="separator"][data-style="thick"]::after {
4965
5526
  /* ── Variant: Card ── */
4966
5527
  [data-ui="stat"][data-variant="card"] {
4967
5528
  padding: var(--space-4);
4968
- border: 1px solid var(--color-border);
5529
+ border: var(--border-width) solid var(--color-border);
4969
5530
  border-radius: var(--radius-md, 0.375rem);
4970
5531
  background: var(--color-bg);
4971
- box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.05));
5532
+ box-shadow: var(--shadow-sm);
4972
5533
  }
4973
5534
 
4974
5535
  /* ── Value + Change Inline ── */
@@ -4980,7 +5541,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4980
5541
  @media print {
4981
5542
  [data-ui="stat"][data-variant="card"] {
4982
5543
  box-shadow: none;
4983
- border: 1px solid var(--doc-print-border-color, var(--color-border, #ccc));
5544
+ border: var(--border-width) solid var(--doc-print-border-color, var(--color-border, #ccc));
4984
5545
  }
4985
5546
 
4986
5547
  [data-ui="stat"] {
@@ -4990,7 +5551,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4990
5551
 
4991
5552
  /* === primitives/stepper.css === */
4992
5553
  /* @ui:component stepper */
4993
- /* @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 */
5554
+ /* @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 */
4994
5555
 
4995
5556
  /* ── Base ── */
4996
5557
  [data-ui="stepper"] {
@@ -5069,7 +5630,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5069
5630
  The tight phone metrics are the base; the roomier ones arrive at `sm`. */
5070
5631
  [data-ui="stepper"] [data-part="connector"] {
5071
5632
  flex: 1;
5072
- height: 2px;
5633
+ height: var(--border-width-strong);
5073
5634
  background: var(--color-border);
5074
5635
  margin: 0 var(--space-1);
5075
5636
  min-width: var(--space-2);
@@ -5137,18 +5698,20 @@ div[data-ui="separator"][data-style="thick"]::after {
5137
5698
 
5138
5699
  /* === primitives/surface.css === */
5139
5700
  /* @ui:component surface */
5140
- /* @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 */
5701
+ /* @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 */
5141
5702
 
5142
5703
  /* ── Base ── */
5143
5704
  [data-ui="surface"] {
5144
- background: var(--color-surface-1);
5705
+ background-color: var(--color-surface-1);
5706
+ background-image: var(--texture-surface);
5145
5707
  border-radius: var(--radius-lg);
5146
- border: 1px solid var(--color-surface-1-border);
5708
+ corner-shape: var(--corner-shape);
5709
+ border: var(--border-width) solid var(--color-surface-1-border);
5147
5710
  }
5148
5711
 
5149
5712
  /* ── Elevation Variants ── */
5150
5713
  [data-ui="surface"][data-variant="flat"] {
5151
- background: var(--color-bg);
5714
+ background-color: var(--color-bg);
5152
5715
  border: none;
5153
5716
  box-shadow: none;
5154
5717
  }
@@ -5158,11 +5721,22 @@ div[data-ui="separator"][data-style="thick"]::after {
5158
5721
  }
5159
5722
 
5160
5723
  [data-ui="surface"][data-variant="overlay"] {
5161
- background: var(--color-surface-2);
5724
+ background-color: var(--color-surface-2);
5162
5725
  box-shadow: var(--shadow-lg);
5163
5726
  border-color: var(--color-surface-2-border);
5164
5727
  }
5165
5728
 
5729
+ /* An overlay is the one surface variant that floats over other content, so it
5730
+ is the one that can be frosted. Guarded exactly as themes/glass.css guards
5731
+ its own: a browser without backdrop-filter renders the solid surface above
5732
+ and never sees this rule. */
5733
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
5734
+ [data-ui="surface"][data-variant="overlay"] {
5735
+ -webkit-backdrop-filter: var(--surface-backdrop);
5736
+ backdrop-filter: var(--surface-backdrop);
5737
+ }
5738
+ }
5739
+
5166
5740
  /* ── Padding Sizes ── */
5167
5741
  [data-ui="surface"][data-size="sm"] {
5168
5742
  padding: var(--space-3);
@@ -5218,7 +5792,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5218
5792
 
5219
5793
  /* === primitives/switch.css === */
5220
5794
  /* @ui:component switch */
5221
- /* @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 */
5795
+ /* @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 */
5222
5796
 
5223
5797
  /* -- Label wrapper -- */
5224
5798
  [data-ui="switch-label"] {
@@ -5230,7 +5804,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5230
5804
 
5231
5805
  [data-ui="switch-label"]:has([data-ui="switch"]:disabled) {
5232
5806
  cursor: not-allowed;
5233
- opacity: 0.5;
5807
+ opacity: var(--disabled-opacity);
5234
5808
  }
5235
5809
 
5236
5810
  /* -- Base (track) -- */
@@ -5258,8 +5832,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5258
5832
  width: var(--switch-width, 44px);
5259
5833
  height: var(--switch-height, 24px);
5260
5834
  padding: var(--space-0h, 2px);
5261
- border: 1px solid var(--color-border);
5262
- border-radius: var(--radius-full);
5835
+ border: var(--border-width) solid var(--color-border);
5836
+ border-radius: var(--switch-radius);
5263
5837
  background: var(--switch-bg, var(--color-bg-muted));
5264
5838
  cursor: pointer;
5265
5839
  position: relative;
@@ -5269,8 +5843,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5269
5843
  }
5270
5844
 
5271
5845
  [data-ui="switch"]:focus-visible {
5272
- outline: 2px solid var(--color-ring);
5273
- outline-offset: 2px;
5846
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
5847
+ outline-offset: var(--focus-ring-offset);
5848
+ box-shadow: var(--focus-shadow);
5274
5849
  }
5275
5850
 
5276
5851
  /* -- Thumb (pseudo-element for <input>, child for custom markup) -- */
@@ -5279,7 +5854,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5279
5854
  display: block;
5280
5855
  width: var(--switch-thumb, 18px);
5281
5856
  height: var(--switch-thumb, 18px);
5282
- border-radius: var(--radius-full);
5857
+ border-radius: var(--switch-radius);
5283
5858
  background: var(--color-primary-fg);
5284
5859
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5285
5860
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5291,7 +5866,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5291
5866
  display: block;
5292
5867
  width: var(--switch-thumb, 18px);
5293
5868
  height: var(--switch-thumb, 18px);
5294
- border-radius: var(--radius-full);
5869
+ border-radius: var(--switch-radius);
5295
5870
  background: var(--color-primary-fg);
5296
5871
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5297
5872
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5373,7 +5948,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5373
5948
  the track's border is always visible, and ON fills it with `Highlight`. [W3-3] */
5374
5949
  @media (forced-colors: active) {
5375
5950
  [data-ui="switch"] {
5376
- border: 1px solid ButtonText;
5951
+ border: var(--border-width) solid ButtonText;
5377
5952
  background: ButtonFace;
5378
5953
  }
5379
5954
 
@@ -5530,25 +6105,31 @@ div[data-ui="separator"][data-style="thick"]::after {
5530
6105
 
5531
6106
  /* === primitives/text.css === */
5532
6107
  /* @ui:component text */
5533
- /* @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 */
6108
+ /* @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 */
5534
6109
 
5535
6110
  /* ── Heading ── */
5536
6111
  [data-ui="heading"] {
5537
- font-family: var(--font-sans);
5538
- font-weight: var(--weight-bold);
6112
+ font-family: var(--font-heading);
6113
+ font-weight: var(--heading-weight);
5539
6114
  color: var(--color-fg);
5540
- line-height: var(--leading-tight);
5541
- letter-spacing: -0.01em;
6115
+ line-height: var(--heading-leading);
6116
+ text-transform: var(--heading-transform);
6117
+ font-variant-caps: var(--heading-caps);
6118
+ /* The optical tightening a large heading needs, PLUS whatever tracking the
6119
+ theme's voice asks for on top of it — so a theme that wants wide-tracked
6120
+ headings sets --heading-tracking once and every size follows, instead of
6121
+ each size having to re-derive its own number. */
6122
+ letter-spacing: calc(-0.01em + var(--heading-tracking));
5542
6123
  }
5543
6124
 
5544
6125
  [data-ui="heading"][data-size="1"] {
5545
6126
  font-size: var(--text-4xl);
5546
- letter-spacing: -0.02em;
6127
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5547
6128
  }
5548
6129
 
5549
6130
  [data-ui="heading"][data-size="2"] {
5550
6131
  font-size: var(--text-3xl);
5551
- letter-spacing: -0.02em;
6132
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5552
6133
  }
5553
6134
 
5554
6135
  [data-ui="heading"][data-size="3"] {
@@ -5572,7 +6153,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5572
6153
 
5573
6154
  /* ── Text ── */
5574
6155
  [data-ui="text"] {
5575
- font-family: var(--font-sans);
6156
+ font-family: var(--font-body);
5576
6157
  color: var(--color-fg);
5577
6158
  }
5578
6159
 
@@ -5650,7 +6231,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5650
6231
 
5651
6232
  /* === primitives/textarea.css === */
5652
6233
  /* @ui:component textarea */
5653
- /* @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 */
6234
+ /* @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 */
5654
6235
 
5655
6236
  /* -- Base -- */
5656
6237
  [data-ui="textarea"] {
@@ -5658,11 +6239,17 @@ div[data-ui="separator"][data-style="thick"]::after {
5658
6239
  width: 100%;
5659
6240
  min-height: var(--textarea-min-height, 80px);
5660
6241
  padding: var(--space-2) var(--space-3);
5661
- border: 1px solid var(--color-border);
6242
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
6243
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
6244
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
6245
+ is drawn. Identical to the shorthand at every other value of the token. */
6246
+ border-style: solid;
6247
+ border-color: var(--color-border);
6248
+ border-width: var(--input-border-width);
5662
6249
  border-radius: var(--textarea-radius, var(--radius-md));
5663
- background: var(--textarea-bg, var(--color-bg));
6250
+ background: var(--textarea-bg, var(--input-fill));
5664
6251
  color: var(--color-fg);
5665
- font-family: var(--textarea-font, var(--font-sans));
6252
+ font-family: var(--textarea-font, var(--font-ui));
5666
6253
  font-size: var(--text-sm);
5667
6254
  line-height: 1.5;
5668
6255
  resize: vertical;
@@ -5679,8 +6266,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5679
6266
  }
5680
6267
 
5681
6268
  [data-ui="textarea"]:focus {
5682
- outline: 2px solid var(--color-ring);
5683
- outline-offset: -1px;
6269
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6270
+ /* The ring replaces the border rather than sitting outside it: inset by
6271
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
6272
+ outline-offset: calc(-1 * var(--input-border-width));
6273
+ box-shadow: var(--focus-shadow);
5684
6274
  border-color: transparent;
5685
6275
  }
5686
6276
 
@@ -5708,7 +6298,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5708
6298
  }
5709
6299
 
5710
6300
  [data-ui="textarea"]:disabled {
5711
- opacity: 0.5;
6301
+ opacity: var(--disabled-opacity);
5712
6302
  cursor: not-allowed;
5713
6303
  resize: none;
5714
6304
  }
@@ -5722,7 +6312,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5722
6312
 
5723
6313
  /* === primitives/toggle.css === */
5724
6314
  /* @ui:component toggle */
5725
- /* @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 */
6315
+ /* @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 */
5726
6316
 
5727
6317
  /* ── Base (off / unpressed) ── */
5728
6318
  [data-ui="toggle"] {
@@ -5731,11 +6321,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5731
6321
  justify-content: center;
5732
6322
  gap: var(--space-1h);
5733
6323
  padding: var(--toggle-pad-y, var(--space-1h)) var(--toggle-pad-x, var(--space-3));
5734
- border: 1px solid var(--color-border);
6324
+ border: var(--border-width) solid var(--color-border);
5735
6325
  border-radius: var(--toggle-radius, var(--radius-md));
5736
6326
  background: var(--color-bg);
5737
6327
  color: var(--color-fg-muted);
5738
- font-family: var(--toggle-font, var(--font-sans));
6328
+ font-family: var(--toggle-font, var(--font-ui));
5739
6329
  font-size: var(--text-sm);
5740
6330
  font-weight: var(--weight-medium);
5741
6331
  line-height: 1;
@@ -5752,8 +6342,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5752
6342
  }
5753
6343
 
5754
6344
  [data-ui="toggle"]:focus-visible {
5755
- outline: 2px solid var(--color-ring);
5756
- outline-offset: 2px;
6345
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6346
+ outline-offset: var(--focus-ring-offset);
6347
+ box-shadow: var(--focus-shadow);
5757
6348
  }
5758
6349
 
5759
6350
  /* ── Pressed / on — styled entirely off aria-pressed, no JS ── */
@@ -5770,7 +6361,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5770
6361
 
5771
6362
  /* ── Disabled ── */
5772
6363
  [data-ui="toggle"]:disabled {
5773
- opacity: 0.5;
6364
+ opacity: var(--disabled-opacity);
5774
6365
  cursor: not-allowed;
5775
6366
  }
5776
6367
 
@@ -5794,7 +6385,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5794
6385
 
5795
6386
  /* === primitives/watermark.css === */
5796
6387
  /* @ui:component watermark */
5797
- /* @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 */
6388
+ /* @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 */
5798
6389
 
5799
6390
  [data-ui="watermark"] {
5800
6391
  position: fixed;
@@ -5813,7 +6404,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5813
6404
 
5814
6405
  [data-ui="watermark"] > [data-part="mark"] {
5815
6406
  color: var(--color-fg-muted);
5816
- font-family: var(--doc-font, var(--font-sans));
6407
+ font-family: var(--doc-font, var(--font-body));
5817
6408
  font-size: var(--text-4xl);
5818
6409
  font-weight: var(--weight-bold);
5819
6410
  line-height: var(--leading-tight);
@@ -5871,7 +6462,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5871
6462
 
5872
6463
  /* === recipes/accordion.css === */
5873
6464
  /* @ui:component accordion */
5874
- /* @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 */
6465
+ /* @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 */
5875
6466
 
5876
6467
  /* ── Root ── */
5877
6468
  [data-ui="accordion"] {
@@ -5880,7 +6471,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5880
6471
 
5881
6472
  /* ── Item ── */
5882
6473
  [data-ui="accordion"] [data-part="item"] {
5883
- border-bottom: 1px solid var(--color-border);
6474
+ border-bottom: var(--border-width) solid var(--color-border);
5884
6475
  }
5885
6476
 
5886
6477
  [data-ui="accordion"] [data-part="item"]:last-child {
@@ -5897,7 +6488,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5897
6488
  border: none;
5898
6489
  background: transparent;
5899
6490
  color: var(--color-fg);
5900
- font-family: var(--font-sans, system-ui, sans-serif);
6491
+ font-family: var(--font-ui);
5901
6492
  font-size: var(--text-base);
5902
6493
  font-weight: var(--weight-medium);
5903
6494
  text-align: start;
@@ -5911,8 +6502,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5911
6502
  }
5912
6503
 
5913
6504
  [data-ui="accordion"] [data-part="trigger"]:focus-visible {
5914
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
5915
- outline-offset: -2px;
6505
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6506
+ outline-offset: calc(-1 * var(--focus-ring-offset));
5916
6507
  border-radius: var(--radius-sm, 0.25rem);
5917
6508
  }
5918
6509
 
@@ -5944,13 +6535,13 @@ div[data-ui="separator"][data-style="thick"]::after {
5944
6535
 
5945
6536
  /* ── Bordered Variant ── */
5946
6537
  [data-ui="accordion"][data-bordered="true"] {
5947
- border: 1px solid var(--color-border);
6538
+ border: var(--border-width) solid var(--color-border);
5948
6539
  border-radius: var(--radius-lg);
5949
6540
  overflow: hidden;
5950
6541
  }
5951
6542
 
5952
6543
  [data-ui="accordion"][data-bordered="true"] [data-part="item"] {
5953
- border-bottom: 1px solid var(--color-border);
6544
+ border-bottom: var(--border-width) solid var(--color-border);
5954
6545
  }
5955
6546
 
5956
6547
  [data-ui="accordion"][data-bordered="true"] [data-part="item"]:last-child {
@@ -5967,7 +6558,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5967
6558
 
5968
6559
  /* === recipes/alert-dialog.css === */
5969
6560
  /* @ui:component alert-dialog */
5970
- /* @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 */
6561
+ /* @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 */
5971
6562
 
5972
6563
  /* ── Root ── */
5973
6564
  [data-ui="alert-dialog"] {
@@ -6003,7 +6594,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6003
6594
  max-height: 85vh;
6004
6595
  overflow-y: auto;
6005
6596
  background: var(--color-bg);
6006
- border: 1px solid var(--color-border);
6597
+ border: var(--border-width) solid var(--color-border);
6007
6598
  border-radius: var(--alert-dialog-radius, var(--radius-xl));
6008
6599
  box-shadow: var(--alert-dialog-shadow, var(--shadow-xl));
6009
6600
  opacity: 0;
@@ -6049,6 +6640,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6049
6640
  /* ── Title ── */
6050
6641
  [data-ui="alert-dialog"] [data-part="title"] {
6051
6642
  margin: 0;
6643
+ font-family: var(--font-heading);
6052
6644
  font-size: var(--text-lg, 1.125rem);
6053
6645
  font-weight: var(--weight-semibold, 600);
6054
6646
  color: var(--color-fg);
@@ -6088,7 +6680,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6088
6680
 
6089
6681
  /* === recipes/barcode.css === */
6090
6682
  /* @ui:component barcode */
6091
- /* @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 */
6683
+ /* @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 */
6092
6684
 
6093
6685
  [data-ui="barcode"] {
6094
6686
  display: inline-flex;
@@ -6115,7 +6707,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6115
6707
 
6116
6708
  [data-ui="barcode"] > [data-part="caption"] {
6117
6709
  color: var(--doc-legal-color, var(--color-fg-muted));
6118
- font-family: var(--font-mono, var(--doc-font, var(--font-sans)));
6710
+ font-family: var(--font-mono, var(--doc-font, var(--font-body)));
6119
6711
  font-size: var(--doc-legal-size);
6120
6712
  line-height: var(--leading-normal);
6121
6713
  text-align: center;
@@ -6135,7 +6727,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6135
6727
 
6136
6728
  /* === recipes/calendar.css === */
6137
6729
  /* @ui:component calendar */
6138
- /* @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 */
6730
+ /* @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 */
6139
6731
 
6140
6732
  /* ── Root ── */
6141
6733
  [data-ui="calendar"] {
@@ -6168,7 +6760,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6168
6760
  width: 28px;
6169
6761
  height: 28px;
6170
6762
  padding: 0;
6171
- border: 1px solid var(--color-border);
6763
+ border: var(--border-width) solid var(--color-border);
6172
6764
  border-radius: var(--radius-md);
6173
6765
  background: var(--color-bg);
6174
6766
  color: var(--color-fg);
@@ -6184,13 +6776,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6184
6776
 
6185
6777
  [data-ui="calendar"] [data-part="nav-prev"]:focus-visible,
6186
6778
  [data-ui="calendar"] [data-part="nav-next"]:focus-visible {
6187
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6188
- outline-offset: 2px;
6779
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6780
+ outline-offset: var(--focus-ring-offset);
6189
6781
  }
6190
6782
 
6191
6783
  [data-ui="calendar"] [data-part="nav-prev"]:disabled,
6192
6784
  [data-ui="calendar"] [data-part="nav-next"]:disabled {
6193
- opacity: 0.4;
6785
+ /* Dimmer than a disabled control — 0.4 at the 0.5 default — and it follows a
6786
+ theme's `--disabled-opacity` like every other disabled dim (1.1A-27). */
6787
+ opacity: calc(var(--disabled-opacity) * 0.8);
6194
6788
  cursor: not-allowed;
6195
6789
  }
6196
6790
 
@@ -6225,11 +6819,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6225
6819
  width: 36px;
6226
6820
  height: 36px;
6227
6821
  padding: 0;
6228
- border: 1px solid transparent;
6822
+ border: var(--border-width) solid transparent;
6229
6823
  border-radius: var(--radius-full);
6230
6824
  background: transparent;
6231
6825
  color: var(--color-fg);
6232
- font-family: var(--font-sans, system-ui, sans-serif);
6826
+ font-family: var(--font-ui);
6233
6827
  font-size: var(--text-sm);
6234
6828
  cursor: pointer;
6235
6829
  transition: background var(--duration-fast) var(--ease-default),
@@ -6242,8 +6836,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6242
6836
  }
6243
6837
 
6244
6838
  [data-ui="calendar"] [data-part="day"]:focus-visible {
6245
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6246
- outline-offset: 2px;
6839
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6840
+ outline-offset: var(--focus-ring-offset);
6247
6841
  }
6248
6842
 
6249
6843
  /* ── Today ── */
@@ -6278,7 +6872,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6278
6872
  /* ── Disabled days (aria-disabled keeps them focusable; :disabled for hard-disabled) ── */
6279
6873
  [data-ui="calendar"] [data-part="day"][aria-disabled="true"],
6280
6874
  [data-ui="calendar"] [data-part="day"]:disabled {
6281
- opacity: 0.5;
6875
+ opacity: var(--disabled-opacity);
6282
6876
  cursor: not-allowed;
6283
6877
  text-decoration: line-through;
6284
6878
  }
@@ -6342,7 +6936,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6342
6936
 
6343
6937
  /* === recipes/carousel.css === */
6344
6938
  /* @ui:component carousel */
6345
- /* @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 */
6939
+ /* @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 */
6346
6940
 
6347
6941
  /* The sliding is CSS, not JavaScript: the viewport is a scroll-snap strip and
6348
6942
  every slide is a snap target. Everything below works with no controller
@@ -6356,7 +6950,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6356
6950
  inline-size: 100%;
6357
6951
  min-inline-size: 0;
6358
6952
  max-inline-size: 100%;
6359
- font-family: var(--carousel-font, var(--font-sans));
6953
+ font-family: var(--carousel-font, var(--font-ui));
6360
6954
  }
6361
6955
 
6362
6956
  /* ── Viewport: the scroll-snap strip ── */
@@ -6382,8 +6976,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6382
6976
  }
6383
6977
 
6384
6978
  [data-ui="carousel"] [data-part="viewport"]:focus-visible {
6385
- outline: 2px solid var(--color-ring);
6386
- outline-offset: 2px;
6979
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6980
+ outline-offset: var(--focus-ring-offset);
6387
6981
  }
6388
6982
 
6389
6983
  /* ── Slide: one full-width snap target ── */
@@ -6391,7 +6985,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6391
6985
  flex: 0 0 var(--carousel-slide-size, 100%);
6392
6986
  min-inline-size: 0;
6393
6987
  padding: var(--space-4);
6394
- border: 1px solid var(--color-border);
6988
+ border: var(--border-width) solid var(--color-border);
6395
6989
  border-radius: var(--radius-lg);
6396
6990
  background: var(--color-bg);
6397
6991
  color: var(--color-fg);
@@ -6420,7 +7014,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6420
7014
  min-inline-size: 2rem;
6421
7015
  min-block-size: 2rem;
6422
7016
  padding: var(--space-1) var(--space-2);
6423
- border: 1px solid var(--color-border);
7017
+ border: var(--border-width) solid var(--color-border);
6424
7018
  border-radius: var(--radius-md);
6425
7019
  background: var(--color-bg);
6426
7020
  color: var(--color-fg);
@@ -6439,14 +7033,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6439
7033
  [data-ui="carousel"] [data-part="prev"]:focus-visible,
6440
7034
  [data-ui="carousel"] [data-part="next"]:focus-visible,
6441
7035
  [data-ui="carousel"] [data-part="dot"]:focus-visible {
6442
- outline: 2px solid var(--color-ring);
6443
- outline-offset: 2px;
7036
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7037
+ outline-offset: var(--focus-ring-offset);
6444
7038
  }
6445
7039
 
6446
7040
  /* Boundary contract "stop" — the controller disables the end button. */
6447
7041
  [data-ui="carousel"] [data-part="prev"]:disabled,
6448
7042
  [data-ui="carousel"] [data-part="next"]:disabled {
6449
- opacity: 0.4;
7043
+ /* 0.4 at the 0.5 default, and a theme's `--disabled-opacity` moves it (1.1A-27). */
7044
+ opacity: calc(var(--disabled-opacity) * 0.8);
6450
7045
  cursor: not-allowed;
6451
7046
  }
6452
7047
 
@@ -6455,7 +7050,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6455
7050
  inline-size: 0.625rem;
6456
7051
  block-size: 0.625rem;
6457
7052
  padding: 0;
6458
- border: 1px solid var(--color-border);
7053
+ border: var(--border-width) solid var(--color-border);
6459
7054
  border-radius: 50%;
6460
7055
  background: var(--color-bg-muted);
6461
7056
  cursor: pointer;
@@ -6491,7 +7086,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6491
7086
 
6492
7087
  /* === recipes/combobox.css === */
6493
7088
  /* @ui:component combobox */
6494
- /* @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 */
7089
+ /* @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 */
6495
7090
 
6496
7091
  /* ── Root ── */
6497
7092
  [data-ui="combobox"] {
@@ -6505,11 +7100,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6505
7100
  display: block;
6506
7101
  width: 100%;
6507
7102
  padding: var(--space-2) var(--space-3);
6508
- border: 1px solid var(--color-border);
7103
+ border: var(--border-width) solid var(--color-border);
6509
7104
  border-radius: var(--radius-md);
6510
7105
  background: var(--color-bg);
6511
7106
  color: var(--color-fg);
6512
- font-family: var(--font-sans, system-ui, sans-serif);
7107
+ font-family: var(--font-ui);
6513
7108
  font-size: var(--text-sm);
6514
7109
  line-height: 1.5;
6515
7110
  outline: none;
@@ -6522,8 +7117,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6522
7117
  }
6523
7118
 
6524
7119
  [data-ui="combobox"] [data-part="input"]:focus {
6525
- border-color: var(--color-ring, oklch(0.55 0.22 264));
6526
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
7120
+ border-color: var(--focus-ring-color);
7121
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
6527
7122
  }
6528
7123
 
6529
7124
  /* ── Listbox ── */
@@ -6535,7 +7130,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6535
7130
  z-index: var(--z-dropdown);
6536
7131
  margin-top: var(--space-1);
6537
7132
  padding: var(--space-1);
6538
- border: 1px solid var(--color-border);
7133
+ border: var(--border-width) solid var(--color-border);
6539
7134
  border-radius: var(--radius-lg);
6540
7135
  background: var(--color-bg);
6541
7136
  box-shadow: var(--shadow-md);
@@ -6620,7 +7215,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6620
7215
 
6621
7216
  /* === recipes/command-palette.css === */
6622
7217
  /* @ui:component command-palette */
6623
- /* @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 */
7218
+ /* @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 */
6624
7219
 
6625
7220
  /* ── Root ── */
6626
7221
  [data-ui="command-palette"] {
@@ -6653,7 +7248,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6653
7248
  display: flex;
6654
7249
  flex-direction: column;
6655
7250
  background: var(--color-bg);
6656
- border: 1px solid var(--color-border);
7251
+ border: var(--border-width) solid var(--color-border);
6657
7252
  border-radius: var(--radius-xl);
6658
7253
  box-shadow: var(--shadow-xl);
6659
7254
  overflow: hidden;
@@ -6685,7 +7280,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6685
7280
  display: flex;
6686
7281
  align-items: center;
6687
7282
  padding: var(--space-3) var(--space-4);
6688
- border-bottom: 1px solid var(--color-border);
7283
+ border-bottom: var(--border-width) solid var(--color-border);
6689
7284
  }
6690
7285
 
6691
7286
  /* ── Search Input ── */
@@ -6695,7 +7290,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6695
7290
  border: none;
6696
7291
  background: transparent;
6697
7292
  color: var(--color-fg);
6698
- font-family: var(--font-sans, system-ui, sans-serif);
7293
+ font-family: var(--font-ui);
6699
7294
  font-size: var(--text-base);
6700
7295
  outline: none;
6701
7296
  }
@@ -6779,7 +7374,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6779
7374
  align-items: center;
6780
7375
  gap: var(--space-1, 0.25rem);
6781
7376
  padding: var(--space-1, 0.25rem) var(--space-2);
6782
- border: 1px solid var(--color-border);
7377
+ border: var(--border-width) solid var(--color-border);
6783
7378
  border-radius: var(--radius-sm, 0.25rem);
6784
7379
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
6785
7380
  color: var(--color-fg-muted);
@@ -6808,7 +7403,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6808
7403
 
6809
7404
  /* === recipes/context-menu.css === */
6810
7405
  /* @ui:component context-menu */
6811
- /* @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 */
7406
+ /* @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 */
6812
7407
 
6813
7408
  [data-ui="context-menu"] {
6814
7409
  position: relative;
@@ -6821,12 +7416,12 @@ div[data-ui="separator"][data-style="thick"]::after {
6821
7416
  border-radius: var(--radius-lg);
6822
7417
  background: var(--color-bg-muted);
6823
7418
  color: var(--color-fg);
6824
- font-family: var(--font-sans, system-ui, sans-serif);
7419
+ font-family: var(--font-ui);
6825
7420
  }
6826
7421
 
6827
7422
  [data-ui="context-menu"] [data-part="target"]:focus-visible {
6828
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6829
- outline-offset: var(--space-1);
7423
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7424
+ outline-offset: var(--focus-ring-offset);
6830
7425
  }
6831
7426
 
6832
7427
  [data-ui="context-menu"] [data-part="menu"] {
@@ -6858,7 +7453,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6858
7453
  border-radius: var(--radius-md);
6859
7454
  background: transparent;
6860
7455
  color: var(--color-fg);
6861
- font-family: var(--font-sans, system-ui, sans-serif);
7456
+ font-family: var(--font-ui);
6862
7457
  font-size: var(--text-sm);
6863
7458
  font-weight: var(--weight-medium);
6864
7459
  text-align: start;
@@ -6882,15 +7477,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6882
7477
  focus additionally draws the ring, inset so it does not overlap the item
6883
7478
  above. [W3-3] */
6884
7479
  [data-ui="context-menu"] [data-part="item"]:focus-visible {
6885
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6886
- outline-offset: calc(var(--space-px) * -2);
7480
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7481
+ outline-offset: calc(-1 * var(--focus-ring-offset));
6887
7482
  }
6888
7483
 
6889
7484
  [data-ui="context-menu"] [data-part="item"]:disabled,
6890
7485
  [data-ui="context-menu"] [data-part="item"][aria-disabled="true"] {
6891
7486
  color: var(--color-fg-muted);
6892
7487
  cursor: not-allowed;
6893
- opacity: 0.5;
7488
+ opacity: var(--disabled-opacity);
6894
7489
  }
6895
7490
 
6896
7491
  [data-ui="context-menu"] [data-part="separator"] {
@@ -6909,7 +7504,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6909
7504
 
6910
7505
  /* === recipes/date-picker.css === */
6911
7506
  /* @ui:component date-picker */
6912
- /* @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 */
7507
+ /* @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 */
6913
7508
  /* The month grid inside the popup is the `calendar` recipe — see calendar.css */
6914
7509
 
6915
7510
  /* ── Root ── */
@@ -6930,11 +7525,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6930
7525
  width: 100%;
6931
7526
  padding: var(--space-2, 0.5rem) var(--space-3);
6932
7527
  padding-inline-end: var(--space-8, 2.5rem);
6933
- border: 1px solid var(--color-border);
7528
+ border: var(--border-width) solid var(--color-border);
6934
7529
  border-radius: var(--radius-md);
6935
7530
  background: var(--color-bg);
6936
7531
  color: var(--color-fg);
6937
- font-family: var(--font-sans, system-ui, sans-serif);
7532
+ font-family: var(--font-ui);
6938
7533
  font-size: var(--text-sm);
6939
7534
  line-height: 1.5;
6940
7535
  cursor: pointer;
@@ -6946,8 +7541,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6946
7541
  }
6947
7542
 
6948
7543
  [data-ui="date-picker"] [data-part="input"]:focus-visible {
6949
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6950
- outline-offset: 2px;
7544
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7545
+ outline-offset: var(--focus-ring-offset);
6951
7546
  border-color: var(--color-primary);
6952
7547
  }
6953
7548
 
@@ -6970,7 +7565,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6970
7565
  z-index: var(--z-dropdown);
6971
7566
  margin-top: var(--space-1);
6972
7567
  padding: var(--space-3);
6973
- border: 1px solid var(--color-border);
7568
+ border: var(--border-width) solid var(--color-border);
6974
7569
  border-radius: var(--radius-lg);
6975
7570
  background: var(--color-bg);
6976
7571
  box-shadow: var(--shadow-lg);
@@ -7009,7 +7604,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7009
7604
 
7010
7605
  /* === recipes/dialog.css === */
7011
7606
  /* @ui:component dialog */
7012
- /* @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 */
7607
+ /* @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 */
7013
7608
 
7014
7609
  /* ── Root ── */
7015
7610
  [data-ui="dialog"] {
@@ -7044,15 +7639,23 @@ div[data-ui="separator"][data-style="thick"]::after {
7044
7639
  width: 90%;
7045
7640
  max-height: 85vh;
7046
7641
  overflow-y: auto;
7047
- background: var(--color-bg);
7048
- border: 1px solid var(--color-border);
7642
+ background: var(--panel-bg);
7643
+ border: var(--border-width) solid var(--color-border);
7049
7644
  border-radius: var(--dialog-radius, var(--radius-xl));
7645
+ corner-shape: var(--corner-shape);
7050
7646
  box-shadow: var(--dialog-shadow, var(--shadow-xl));
7051
7647
  opacity: 0;
7052
7648
  transition: opacity var(--duration-normal) var(--ease-out),
7053
7649
  transform var(--duration-normal) var(--ease-out);
7054
7650
  }
7055
7651
 
7652
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7653
+ [data-ui="dialog"] [data-part="panel"] {
7654
+ -webkit-backdrop-filter: var(--surface-backdrop);
7655
+ backdrop-filter: var(--surface-backdrop);
7656
+ }
7657
+ }
7658
+
7056
7659
  [data-ui="dialog"][data-state="open"] [data-part="panel"] {
7057
7660
  opacity: 1;
7058
7661
  transform: translate(-50%, -50%) scale(1);
@@ -7101,6 +7704,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7101
7704
  /* ── Title ── */
7102
7705
  [data-ui="dialog"] [data-part="title"] {
7103
7706
  margin: 0;
7707
+ font-family: var(--font-heading);
7104
7708
  font-size: var(--text-lg, 1.125rem);
7105
7709
  font-weight: var(--weight-semibold, 600);
7106
7710
  color: var(--color-fg);
@@ -7135,8 +7739,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7135
7739
  }
7136
7740
 
7137
7741
  [data-ui="dialog"] [data-part="close"]:not([data-ui]):focus-visible {
7138
- outline: 2px solid var(--color-ring);
7139
- outline-offset: 2px;
7742
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7743
+ outline-offset: var(--focus-ring-offset);
7140
7744
  }
7141
7745
 
7142
7746
  /* ── Description ── */
@@ -7172,7 +7776,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7172
7776
 
7173
7777
  /* === recipes/drawer.css === */
7174
7778
  /* @ui:component drawer */
7175
- /* @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 */
7779
+ /* @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 */
7176
7780
 
7177
7781
  /* ── Root ── */
7178
7782
  [data-ui="drawer"] {
@@ -7207,17 +7811,24 @@ div[data-ui="separator"][data-style="thick"]::after {
7207
7811
  flex-direction: column;
7208
7812
  width: var(--drawer-width, 400px);
7209
7813
  max-width: 100vw;
7210
- background: var(--color-bg);
7814
+ background: var(--panel-bg);
7211
7815
  border: none;
7212
7816
  box-shadow: var(--drawer-shadow, var(--shadow-xl));
7213
7817
  transition: transform var(--duration-slow) var(--ease-out);
7214
7818
  }
7215
7819
 
7820
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7821
+ [data-ui="drawer"] [data-part="panel"] {
7822
+ -webkit-backdrop-filter: var(--surface-backdrop);
7823
+ backdrop-filter: var(--surface-backdrop);
7824
+ }
7825
+ }
7826
+
7216
7827
  /* ── Side Variants ── */
7217
7828
  [data-ui="drawer"] [data-part="panel"][data-variant="left"] {
7218
7829
  inset-inline-start: 0;
7219
7830
  inset-inline-end: auto;
7220
- border-inline-end: 1px solid var(--color-border);
7831
+ border-inline-end: var(--border-width) solid var(--color-border);
7221
7832
  border-radius: 0 var(--radius-none, 0) var(--radius-none, 0) 0;
7222
7833
  transform: translateX(-100%);
7223
7834
  }
@@ -7225,7 +7836,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7225
7836
  [data-ui="drawer"] [data-part="panel"][data-variant="right"] {
7226
7837
  inset-inline-end: 0;
7227
7838
  inset-inline-start: auto;
7228
- border-inline-start: 1px solid var(--color-border);
7839
+ border-inline-start: var(--border-width) solid var(--color-border);
7229
7840
  border-radius: var(--radius-none, 0) 0 0 var(--radius-none, 0);
7230
7841
  transform: translateX(100%);
7231
7842
  }
@@ -7279,6 +7890,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7279
7890
  /* ── Title ── */
7280
7891
  [data-ui="drawer"] [data-part="title"] {
7281
7892
  margin: 0;
7893
+ font-family: var(--font-heading);
7282
7894
  font-size: var(--text-lg, 1.125rem);
7283
7895
  font-weight: var(--weight-semibold, 600);
7284
7896
  color: var(--color-fg);
@@ -7313,8 +7925,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7313
7925
  }
7314
7926
 
7315
7927
  [data-ui="drawer"] [data-part="close"]:not([data-ui]):focus-visible {
7316
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7317
- outline-offset: 2px;
7928
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7929
+ outline-offset: var(--focus-ring-offset);
7318
7930
  }
7319
7931
 
7320
7932
  /* ── Body ── */
@@ -7333,7 +7945,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7333
7945
  gap: var(--space-3, 0.75rem);
7334
7946
  padding: var(--space-6);
7335
7947
  padding-top: var(--space-4);
7336
- border-top: 1px solid var(--color-border);
7948
+ border-top: var(--border-width) solid var(--color-border);
7337
7949
  flex-shrink: 0;
7338
7950
  }
7339
7951
 
@@ -7347,7 +7959,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7347
7959
 
7348
7960
  /* === recipes/dropdown.css === */
7349
7961
  /* @ui:component dropdown */
7350
- /* @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 */
7962
+ /* @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 */
7351
7963
 
7352
7964
  /* ── Root ── */
7353
7965
  [data-ui="dropdown"] {
@@ -7361,11 +7973,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7361
7973
  align-items: center;
7362
7974
  gap: var(--space-2);
7363
7975
  padding: var(--space-2) var(--space-3);
7364
- border: 1px solid var(--color-border);
7976
+ border: var(--border-width) solid var(--color-border);
7365
7977
  border-radius: var(--radius-md);
7366
7978
  background: var(--color-bg);
7367
7979
  color: var(--color-fg);
7368
- font-family: var(--font-sans, system-ui, sans-serif);
7980
+ font-family: var(--font-ui);
7369
7981
  font-size: var(--text-sm);
7370
7982
  font-weight: var(--weight-medium);
7371
7983
  cursor: pointer;
@@ -7379,8 +7991,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7379
7991
  }
7380
7992
 
7381
7993
  [data-ui="dropdown"] [data-part="trigger"]:focus-visible {
7382
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7383
- outline-offset: 2px;
7994
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7995
+ outline-offset: var(--focus-ring-offset);
7384
7996
  }
7385
7997
 
7386
7998
  /* ── Menu ── */
@@ -7392,9 +8004,9 @@ div[data-ui="separator"][data-style="thick"]::after {
7392
8004
  min-width: 180px;
7393
8005
  margin-top: var(--space-1);
7394
8006
  padding: var(--space-1);
7395
- border: 1px solid var(--color-border);
8007
+ border: var(--border-width) solid var(--color-border);
7396
8008
  border-radius: var(--radius-lg);
7397
- background: var(--color-bg);
8009
+ background: var(--panel-bg);
7398
8010
  box-shadow: var(--shadow-md);
7399
8011
  opacity: 0;
7400
8012
  transform: translateY(-4px);
@@ -7402,6 +8014,13 @@ div[data-ui="separator"][data-style="thick"]::after {
7402
8014
  transform var(--duration-fast) var(--ease-out);
7403
8015
  }
7404
8016
 
8017
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
8018
+ [data-ui="dropdown"] [data-part="menu"] {
8019
+ -webkit-backdrop-filter: var(--surface-backdrop);
8020
+ backdrop-filter: var(--surface-backdrop);
8021
+ }
8022
+ }
8023
+
7405
8024
  [data-ui="dropdown"][data-state="open"] [data-part="menu"] {
7406
8025
  opacity: 1;
7407
8026
  transform: translateY(0);
@@ -7424,7 +8043,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7424
8043
  border-radius: var(--radius-md);
7425
8044
  background: transparent;
7426
8045
  color: var(--color-fg);
7427
- font-family: var(--font-sans, system-ui, sans-serif);
8046
+ font-family: var(--font-ui);
7428
8047
  font-size: var(--text-sm);
7429
8048
  text-align: start;
7430
8049
  cursor: pointer;
@@ -7446,12 +8065,12 @@ div[data-ui="separator"][data-style="thick"]::after {
7446
8065
  focus additionally draws the ring, inset so it does not overlap the item
7447
8066
  above. [W3-3] */
7448
8067
  [data-ui="dropdown"] [data-part="item"]:focus-visible {
7449
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7450
- outline-offset: -2px;
8068
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8069
+ outline-offset: calc(-1 * var(--focus-ring-offset));
7451
8070
  }
7452
8071
 
7453
8072
  [data-ui="dropdown"] [data-part="item"]:disabled {
7454
- opacity: 0.5;
8073
+ opacity: var(--disabled-opacity);
7455
8074
  cursor: not-allowed;
7456
8075
  pointer-events: none;
7457
8076
  }
@@ -7504,14 +8123,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7504
8123
 
7505
8124
  /* === recipes/file-upload.css === */
7506
8125
  /* @ui:component file-upload */
7507
- /* @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 */
8126
+ /* @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 */
7508
8127
 
7509
8128
  [data-ui="file-upload"] {
7510
8129
  display: grid;
7511
8130
  gap: var(--space-4);
7512
8131
  inline-size: 100%;
7513
8132
  color: var(--color-fg);
7514
- font-family: var(--font-sans);
8133
+ font-family: var(--font-ui);
7515
8134
  }
7516
8135
 
7517
8136
  [data-ui="file-upload"] [data-part="dropzone"] {
@@ -7546,14 +8165,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7546
8165
  }
7547
8166
 
7548
8167
  [data-ui="file-upload"]:has([data-part="input"]:focus-visible) [data-part="dropzone"] {
7549
- outline: var(--space-px) solid var(--color-ring);
7550
- outline-offset: var(--space-1);
8168
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8169
+ outline-offset: var(--focus-ring-offset);
7551
8170
  }
7552
8171
 
7553
8172
  [data-ui="file-upload"][data-state="dragging"] [data-part="dropzone"] {
7554
8173
  border-color: var(--color-primary);
7555
8174
  background: var(--color-primary-subtle);
7556
- box-shadow: 0 0 0 var(--space-px) var(--color-primary);
8175
+ box-shadow: 0 0 0 var(--border-width) var(--color-primary);
7557
8176
  }
7558
8177
 
7559
8178
  [data-ui="file-upload"] [data-part="prompt"] {
@@ -7627,8 +8246,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7627
8246
  }
7628
8247
 
7629
8248
  [data-ui="file-upload"] [data-part="remove"]:focus-visible {
7630
- outline: var(--space-px) solid var(--color-ring);
7631
- outline-offset: var(--space-1);
8249
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8250
+ outline-offset: var(--focus-ring-offset);
7632
8251
  }
7633
8252
 
7634
8253
  [data-ui="file-upload"] [data-part="empty"] {
@@ -7650,7 +8269,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7650
8269
  }
7651
8270
 
7652
8271
  [data-ui="file-upload"][data-disabled] {
7653
- opacity: 0.5;
8272
+ opacity: var(--disabled-opacity);
7654
8273
  }
7655
8274
 
7656
8275
  [data-ui="file-upload"][data-disabled] [data-part="dropzone"],
@@ -7666,7 +8285,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7666
8285
 
7667
8286
  /* === recipes/input-otp.css === */
7668
8287
  /* @ui:component input-otp */
7669
- /* @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 */
8288
+ /* @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 */
7670
8289
 
7671
8290
  /* ── Root ── */
7672
8291
  [data-ui="input-otp"] {
@@ -7681,7 +8300,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7681
8300
  gutter. The transparent input is `inset: 0`, so it follows the box the
7682
8301
  segments settle into however many rows that takes. */
7683
8302
  max-inline-size: 100%;
7684
- font-family: var(--font-sans, system-ui, sans-serif);
8303
+ font-family: var(--font-ui);
7685
8304
  }
7686
8305
 
7687
8306
  /* ── Real input ──
@@ -7726,14 +8345,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7726
8345
  justify-content: center;
7727
8346
  inline-size: var(--input-otp-segment-size);
7728
8347
  block-size: var(--input-otp-segment-size);
7729
- border: 1px solid var(--color-border);
8348
+ border: var(--border-width) solid var(--color-border);
7730
8349
  border-radius: var(--radius-md);
7731
8350
  background: var(--color-bg);
7732
8351
  color: var(--color-fg);
7733
8352
  font-size: var(--text-lg, 1.125rem);
7734
8353
  font-variant-numeric: tabular-nums;
7735
8354
  line-height: 1;
7736
- transition: border-color var(--duration-fast, 120ms) var(--ease-default, ease),
8355
+ transition: border-color var(--duration-fast) var(--ease-default),
7737
8356
  box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
7738
8357
  }
7739
8358
 
@@ -7745,7 +8364,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7745
8364
  /* Active (caret / selected) segment while focused */
7746
8365
  [data-ui="input-otp"] [data-part="segment"][data-active] {
7747
8366
  border-color: var(--color-ring);
7748
- box-shadow: 0 0 0 1px var(--color-ring);
8367
+ box-shadow: 0 0 0 var(--border-width) var(--color-ring);
7749
8368
  }
7750
8369
 
7751
8370
  /* Blinking caret in the next-to-fill empty slot */
@@ -7793,7 +8412,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7793
8412
 
7794
8413
  /* ── Disabled ── */
7795
8414
  [data-ui="input-otp"][data-disabled] {
7796
- opacity: 0.5;
8415
+ opacity: var(--disabled-opacity);
7797
8416
  cursor: not-allowed;
7798
8417
  }
7799
8418
  [data-ui="input-otp"][data-disabled] [data-part="input"] {
@@ -7817,7 +8436,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7817
8436
 
7818
8437
  /* === recipes/menubar.css === */
7819
8438
  /* @ui:component menubar */
7820
- /* @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 */
8439
+ /* @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 */
7821
8440
 
7822
8441
  [data-ui="menubar"] {
7823
8442
  position: relative;
@@ -7835,7 +8454,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7835
8454
  border-radius: var(--radius-lg);
7836
8455
  background: var(--color-bg);
7837
8456
  color: var(--color-fg);
7838
- font-family: var(--font-sans);
8457
+ font-family: var(--font-ui);
7839
8458
  }
7840
8459
 
7841
8460
  [data-ui="menubar"] [data-part="group"] {
@@ -7877,7 +8496,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7877
8496
 
7878
8497
  [data-ui="menubar"] [data-part="trigger"]:focus-visible,
7879
8498
  [data-ui="menubar"] [data-part="item"]:focus-visible {
7880
- box-shadow: 0 0 0 calc(var(--space-px) * 2) var(--color-ring);
8499
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
7881
8500
  }
7882
8501
 
7883
8502
  [data-ui="menubar"] [data-part="submenu"] {
@@ -7912,7 +8531,10 @@ div[data-ui="separator"][data-style="thick"]::after {
7912
8531
  [data-ui="menubar"] [role="menuitem"][aria-disabled="true"] {
7913
8532
  color: var(--color-fg-muted);
7914
8533
  cursor: not-allowed;
7915
- opacity: 0.6;
8534
+ /* 0.6 at the 0.5 default — lighter than a control, since the muted colour
8535
+ already carries half the signal — and a theme's `--disabled-opacity` moves
8536
+ it (1.1A-27). */
8537
+ opacity: calc(var(--disabled-opacity) * 1.2);
7916
8538
  }
7917
8539
 
7918
8540
  [data-ui="menubar"] [data-part="separator"] {
@@ -7944,7 +8566,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7944
8566
 
7945
8567
  /* === recipes/pagination.css === */
7946
8568
  /* @ui:component pagination */
7947
- /* @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 */
8569
+ /* @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 */
7948
8570
 
7949
8571
  /* ── Root ── */
7950
8572
  [data-ui="pagination"] {
@@ -7980,11 +8602,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7980
8602
  min-width: 36px;
7981
8603
  height: 36px;
7982
8604
  padding: 0 var(--space-2);
7983
- border: 1px solid var(--color-border);
8605
+ border: var(--border-width) solid var(--color-border);
7984
8606
  border-radius: var(--radius-md);
7985
8607
  background: var(--color-bg);
7986
8608
  color: var(--color-fg);
7987
- font-family: var(--font-sans, system-ui, sans-serif);
8609
+ font-family: var(--font-ui);
7988
8610
  font-size: var(--text-sm);
7989
8611
  font-weight: var(--weight-medium);
7990
8612
  cursor: pointer;
@@ -8005,8 +8627,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8005
8627
  [data-ui="pagination"] [data-part="page"]:focus-visible,
8006
8628
  [data-ui="pagination"] [data-part="prev"]:focus-visible,
8007
8629
  [data-ui="pagination"] [data-part="next"]:focus-visible {
8008
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8009
- outline-offset: 2px;
8630
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8631
+ outline-offset: var(--focus-ring-offset);
8010
8632
  }
8011
8633
 
8012
8634
  /* ── Active page ── */
@@ -8030,7 +8652,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8030
8652
  /* ── Disabled ── */
8031
8653
  [data-ui="pagination"] [data-part="prev"]:disabled,
8032
8654
  [data-ui="pagination"] [data-part="next"]:disabled {
8033
- opacity: 0.5;
8655
+ opacity: var(--disabled-opacity);
8034
8656
  cursor: not-allowed;
8035
8657
  pointer-events: none;
8036
8658
  }
@@ -8100,7 +8722,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8100
8722
 
8101
8723
  /* === recipes/popover.css === */
8102
8724
  /* @ui:component popover */
8103
- /* @ui:tokens color-bg color-fg color-border shadow-md radius-lg space-3 space-4 z-dropdown duration-fast ease-default */
8725
+ /* @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 */
8104
8726
 
8105
8727
  /* ── Root ── */
8106
8728
  [data-ui="popover"] {
@@ -8114,11 +8736,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8114
8736
  align-items: center;
8115
8737
  gap: var(--space-2, 0.5rem);
8116
8738
  padding: var(--space-2, 0.5rem) var(--space-3);
8117
- border: 1px solid var(--color-border);
8739
+ border: var(--border-width) solid var(--color-border);
8118
8740
  border-radius: var(--radius-md, 0.375rem);
8119
8741
  background: var(--color-bg);
8120
8742
  color: var(--color-fg);
8121
- font-family: var(--font-sans, system-ui, sans-serif);
8743
+ font-family: var(--font-ui);
8122
8744
  font-size: var(--text-sm, 0.875rem);
8123
8745
  font-weight: var(--weight-medium, 500);
8124
8746
  cursor: pointer;
@@ -8132,8 +8754,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8132
8754
  }
8133
8755
 
8134
8756
  [data-ui="popover"] [data-part="trigger"]:focus-visible {
8135
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8136
- outline-offset: 2px;
8757
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8758
+ outline-offset: var(--focus-ring-offset);
8137
8759
  }
8138
8760
 
8139
8761
  /* ── Content ── */
@@ -8142,9 +8764,9 @@ div[data-ui="separator"][data-style="thick"]::after {
8142
8764
  z-index: var(--z-dropdown);
8143
8765
  min-width: 200px;
8144
8766
  padding: var(--space-4);
8145
- border: 1px solid var(--color-border);
8767
+ border: var(--border-width) solid var(--color-border);
8146
8768
  border-radius: var(--radius-lg);
8147
- background: var(--color-bg);
8769
+ background: var(--panel-bg);
8148
8770
  color: var(--color-fg);
8149
8771
  box-shadow: var(--shadow-md);
8150
8772
  opacity: 0;
@@ -8153,6 +8775,13 @@ div[data-ui="separator"][data-style="thick"]::after {
8153
8775
  transform var(--duration-fast) var(--ease-default);
8154
8776
  }
8155
8777
 
8778
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
8779
+ [data-ui="popover"] [data-part="content"] {
8780
+ -webkit-backdrop-filter: var(--surface-backdrop);
8781
+ backdrop-filter: var(--surface-backdrop);
8782
+ }
8783
+ }
8784
+
8156
8785
  [data-ui="popover"][data-state="open"] [data-part="content"] {
8157
8786
  opacity: 1;
8158
8787
  transform: scale(1);
@@ -8240,8 +8869,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8240
8869
  position: absolute;
8241
8870
  width: 8px;
8242
8871
  height: 8px;
8243
- background: var(--color-bg);
8244
- border: 1px solid var(--color-border);
8872
+ background: var(--panel-bg);
8873
+ border: var(--border-width) solid var(--color-border);
8245
8874
  transform: rotate(45deg);
8246
8875
  }
8247
8876
 
@@ -8342,8 +8971,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8342
8971
  }
8343
8972
 
8344
8973
  [data-ui="popover"] [data-part="close"]:focus-visible {
8345
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8346
- outline-offset: 2px;
8974
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8975
+ outline-offset: var(--focus-ring-offset);
8347
8976
  }
8348
8977
 
8349
8978
  /* ── Motion ── */
@@ -8356,7 +8985,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8356
8985
 
8357
8986
  /* === recipes/qr-code.css === */
8358
8987
  /* @ui:component qr-code */
8359
- /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-sans space-2 */
8988
+ /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-body space-2 */
8360
8989
 
8361
8990
  /* ── Base ── */
8362
8991
  [data-ui="qr-code"] {
@@ -8374,7 +9003,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8374
9003
 
8375
9004
  /* ── Caption ── */
8376
9005
  [data-ui="qr-code"] [data-part="caption"] {
8377
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
9006
+ font-family: var(--doc-font, var(--font-body));
8378
9007
  font-size: var(--doc-legal-size, var(--text-xs));
8379
9008
  color: var(--doc-legal-color, var(--color-fg-muted));
8380
9009
  text-align: center;
@@ -8415,7 +9044,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8415
9044
 
8416
9045
  /* === recipes/select-custom.css === */
8417
9046
  /* @ui:component select-custom */
8418
- /* @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 */
9047
+ /* @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 */
8419
9048
 
8420
9049
  /* ── Root ── */
8421
9050
  [data-ui="select-custom"] {
@@ -8432,11 +9061,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8432
9061
  width: 100%;
8433
9062
  min-width: 180px;
8434
9063
  padding: var(--space-2) var(--space-3);
8435
- border: 1px solid var(--color-border);
9064
+ border: var(--border-width) solid var(--color-border);
8436
9065
  border-radius: var(--radius-md);
8437
9066
  background: var(--color-bg);
8438
9067
  color: var(--color-fg);
8439
- font-family: var(--font-sans, system-ui, sans-serif);
9068
+ font-family: var(--font-ui);
8440
9069
  font-size: var(--text-sm);
8441
9070
  cursor: pointer;
8442
9071
  white-space: nowrap;
@@ -8449,8 +9078,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8449
9078
  }
8450
9079
 
8451
9080
  [data-ui="select-custom"] [data-part="trigger"]:focus-visible {
8452
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8453
- outline-offset: 2px;
9081
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9082
+ outline-offset: var(--focus-ring-offset);
8454
9083
  }
8455
9084
 
8456
9085
  /* ── Value ── */
@@ -8486,7 +9115,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8486
9115
  z-index: var(--z-dropdown);
8487
9116
  margin-top: var(--space-1);
8488
9117
  padding: var(--space-1);
8489
- border: 1px solid var(--color-border);
9118
+ border: var(--border-width) solid var(--color-border);
8490
9119
  border-radius: var(--radius-lg);
8491
9120
  background: var(--color-bg);
8492
9121
  box-shadow: var(--shadow-md);
@@ -8510,11 +9139,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8510
9139
  padding: var(--space-2) var(--space-3);
8511
9140
  margin-bottom: var(--space-1);
8512
9141
  border: none;
8513
- border-bottom: 1px solid var(--color-border);
9142
+ border-bottom: var(--border-width) solid var(--color-border);
8514
9143
  border-radius: 0;
8515
9144
  background: transparent;
8516
9145
  color: var(--color-fg);
8517
- font-family: var(--font-sans, system-ui, sans-serif);
9146
+ font-family: var(--font-ui);
8518
9147
  font-size: var(--text-sm);
8519
9148
  outline: none;
8520
9149
  }
@@ -8608,7 +9237,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8608
9237
 
8609
9238
  /* === recipes/sheet.css === */
8610
9239
  /* @ui:component sheet */
8611
- /* @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 */
9240
+ /* @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 */
8612
9241
 
8613
9242
  /* ── Root ── */
8614
9243
  [data-ui="sheet"] {
@@ -8639,11 +9268,18 @@ div[data-ui="separator"][data-style="thick"]::after {
8639
9268
  z-index: var(--z-modal);
8640
9269
  display: flex;
8641
9270
  flex-direction: column;
8642
- background: var(--color-bg);
9271
+ background: var(--panel-bg);
8643
9272
  box-shadow: var(--shadow-xl);
8644
9273
  transition: transform var(--duration-slow) var(--ease-out);
8645
9274
  }
8646
9275
 
9276
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
9277
+ [data-ui="sheet"] [data-part="panel"] {
9278
+ -webkit-backdrop-filter: var(--surface-backdrop);
9279
+ backdrop-filter: var(--surface-backdrop);
9280
+ }
9281
+ }
9282
+
8647
9283
  /* ── Side: Bottom ── */
8648
9284
  [data-ui="sheet"] [data-part="panel"][data-variant="bottom"] {
8649
9285
  bottom: 0;
@@ -8671,7 +9307,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8671
9307
  bottom: 0;
8672
9308
  max-width: 100vw;
8673
9309
  border-radius: 0 var(--radius-xl) var(--radius-xl) 0;
8674
- border-inline-end: 1px solid var(--color-border);
9310
+ border-inline-end: var(--border-width) solid var(--color-border);
8675
9311
  transform: translateX(-100%);
8676
9312
  }
8677
9313
 
@@ -8682,7 +9318,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8682
9318
  bottom: 0;
8683
9319
  max-width: 100vw;
8684
9320
  border-radius: var(--radius-xl) 0 0 var(--radius-xl);
8685
- border-inline-start: 1px solid var(--color-border);
9321
+ border-inline-start: var(--border-width) solid var(--color-border);
8686
9322
  transform: translateX(100%);
8687
9323
  }
8688
9324
 
@@ -8759,6 +9395,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8759
9395
  /* ── Title ── */
8760
9396
  [data-ui="sheet"] [data-part="title"] {
8761
9397
  margin: 0;
9398
+ font-family: var(--font-heading);
8762
9399
  font-size: var(--text-lg, 1.125rem);
8763
9400
  font-weight: var(--weight-semibold, 600);
8764
9401
  color: var(--color-fg);
@@ -8793,8 +9430,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8793
9430
  }
8794
9431
 
8795
9432
  [data-ui="sheet"] [data-part="close"]:not([data-ui]):focus-visible {
8796
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8797
- outline-offset: 2px;
9433
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9434
+ outline-offset: var(--focus-ring-offset);
8798
9435
  }
8799
9436
 
8800
9437
  /* ── Body ── */
@@ -8815,7 +9452,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8815
9452
 
8816
9453
  /* === recipes/sidebar.css === */
8817
9454
  /* @ui:component sidebar */
8818
- /* @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 */
9455
+ /* @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 */
8819
9456
 
8820
9457
  /* ── Root ──
8821
9458
  The root owns the layout column from `md` up; the panel is the visual surface.
@@ -8859,7 +9496,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8859
9496
  flex-direction: column;
8860
9497
  gap: var(--space-2);
8861
9498
  background: var(--sidebar-bg);
8862
- border-inline-end: 1px solid var(--color-border);
9499
+ border-inline-end: var(--border-width) solid var(--color-border);
8863
9500
  border-start-end-radius: var(--radius-lg, 0.5rem);
8864
9501
  border-end-end-radius: var(--radius-lg, 0.5rem);
8865
9502
  box-shadow: var(--shadow-xl);
@@ -8940,8 +9577,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8940
9577
  }
8941
9578
 
8942
9579
  [data-ui="sidebar"] [data-part="trigger"]:focus-visible {
8943
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8944
- outline-offset: 2px;
9580
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9581
+ outline-offset: var(--focus-ring-offset);
8945
9582
  }
8946
9583
 
8947
9584
  /* ── Navigation ── */
@@ -8977,8 +9614,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8977
9614
  }
8978
9615
 
8979
9616
  [data-ui="sidebar"] [data-part="item"]:focus-visible {
8980
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8981
- outline-offset: -2px;
9617
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9618
+ outline-offset: calc(-1 * var(--focus-ring-offset));
8982
9619
  }
8983
9620
 
8984
9621
  [data-ui="sidebar"] [data-part="item"][aria-current="page"] {
@@ -9005,7 +9642,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9005
9642
  [data-ui="sidebar"] [data-part="footer"] {
9006
9643
  flex-shrink: 0;
9007
9644
  padding: var(--space-3) var(--space-4);
9008
- border-block-start: 1px solid var(--color-border);
9645
+ border-block-start: var(--border-width) solid var(--color-border);
9009
9646
  }
9010
9647
 
9011
9648
  /* ── Rail (icons only) ── */
@@ -9098,7 +9735,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9098
9735
 
9099
9736
  /* === recipes/slider.css === */
9100
9737
  /* @ui:component slider */
9101
- /* @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 */
9738
+ /* @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 */
9102
9739
 
9103
9740
  /* ── Root ── */
9104
9741
  [data-ui="slider"] {
@@ -9148,28 +9785,28 @@ div[data-ui="separator"][data-style="thick"]::after {
9148
9785
  value in both LTR and RTL (translateX is physical, so -50% always recentres). */
9149
9786
  transform: translate(-50%, -50%);
9150
9787
  background: var(--color-bg, white);
9151
- border: 2px solid var(--color-primary);
9788
+ border: var(--border-width-strong) solid var(--color-primary);
9152
9789
  border-radius: var(--radius-full, 9999px);
9153
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1));
9790
+ box-shadow: var(--shadow-sm);
9154
9791
  cursor: grab;
9155
9792
  touch-action: none;
9156
- transition: box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
9793
+ transition: box-shadow var(--duration-fast) var(--ease-default);
9157
9794
  }
9158
9795
 
9159
9796
  [data-ui="slider"] [data-part="thumb"]:hover {
9160
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9161
- 0 0 0 4px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9797
+ box-shadow: var(--shadow-sm),
9798
+ 0 0 0 4px var(--color-primary-subtle);
9162
9799
  }
9163
9800
 
9164
9801
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
9165
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9166
- outline-offset: 2px;
9802
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9803
+ outline-offset: var(--focus-ring-offset);
9167
9804
  }
9168
9805
 
9169
9806
  [data-ui="slider"] [data-part="thumb"][data-state="dragging"] {
9170
9807
  cursor: grabbing;
9171
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9172
- 0 0 0 5px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9808
+ box-shadow: var(--shadow-sm),
9809
+ 0 0 0 5px var(--color-primary-subtle);
9173
9810
  }
9174
9811
 
9175
9812
  /* ── Value output ── */
@@ -9177,7 +9814,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9177
9814
  flex: 0 0 auto;
9178
9815
  min-inline-size: 3ch;
9179
9816
  color: var(--color-fg-muted);
9180
- font-family: var(--font-sans, system-ui, sans-serif);
9817
+ font-family: var(--font-ui);
9181
9818
  font-size: var(--text-sm);
9182
9819
  font-variant-numeric: tabular-nums;
9183
9820
  text-align: end;
@@ -9196,7 +9833,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9196
9833
 
9197
9834
  /* ── Disabled ── */
9198
9835
  [data-ui="slider"][data-disabled] {
9199
- opacity: 0.5;
9836
+ opacity: var(--disabled-opacity);
9200
9837
  cursor: not-allowed;
9201
9838
  pointer-events: none;
9202
9839
  }
@@ -9214,7 +9851,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9214
9851
  the substitution so the control still reads as "this much, up to here". [W3-3] */
9215
9852
  @media (forced-colors: active) {
9216
9853
  [data-ui="slider"] [data-part="track"] {
9217
- border: 1px solid ButtonText;
9854
+ border: var(--border-width) solid ButtonText;
9218
9855
  }
9219
9856
 
9220
9857
  [data-ui="slider"] [data-part="range"] {
@@ -9225,7 +9862,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9225
9862
  [data-ui="slider"] [data-part="thumb"] {
9226
9863
  forced-color-adjust: none;
9227
9864
  background: ButtonText;
9228
- border: 1px solid ButtonFace;
9865
+ border: var(--border-width) solid ButtonFace;
9229
9866
  }
9230
9867
 
9231
9868
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
@@ -9235,7 +9872,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9235
9872
 
9236
9873
  /* === recipes/table.css === */
9237
9874
  /* @ui:component table */
9238
- /* @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 */
9875
+ /* @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 */
9239
9876
 
9240
9877
  /* ── Root ── */
9241
9878
  [data-ui="table"] {
@@ -9261,7 +9898,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9261
9898
  width: 100%;
9262
9899
  border-collapse: separate;
9263
9900
  border-spacing: 0;
9264
- font-family: var(--font-sans, system-ui, sans-serif);
9901
+ font-family: var(--font-body);
9265
9902
  }
9266
9903
 
9267
9904
  /* Once any column is resized the layout freezes so widths are exact. */
@@ -9283,7 +9920,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9283
9920
  font-weight: var(--weight-semibold);
9284
9921
  color: var(--color-fg-muted);
9285
9922
  background: var(--color-bg);
9286
- border-bottom: 2px solid var(--color-border);
9923
+ border-bottom: var(--border-width-strong) solid var(--color-border);
9287
9924
  white-space: nowrap;
9288
9925
  user-select: none;
9289
9926
  }
@@ -9341,8 +9978,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9341
9978
  /* Keyboard focus on cells (sortable headers + navigable grids). */
9342
9979
  [data-ui="table"] [data-part="th"]:focus-visible,
9343
9980
  [data-ui="table"] [data-part="td"]:focus-visible {
9344
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9345
- outline-offset: -2px;
9981
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9982
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9346
9983
  }
9347
9984
 
9348
9985
  /* ── Data Cell ── */
@@ -9350,7 +9987,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9350
9987
  padding: var(--space-3) var(--space-4);
9351
9988
  font-size: var(--text-sm);
9352
9989
  color: var(--color-fg);
9353
- border-bottom: 1px solid var(--color-border);
9990
+ border-bottom: var(--border-width) solid var(--color-border);
9354
9991
  background: var(--color-bg);
9355
9992
  transition: background var(--duration-fast) var(--ease-default);
9356
9993
  }
@@ -9379,31 +10016,31 @@ div[data-ui="separator"][data-style="thick"]::after {
9379
10016
  Static fallback via nth-child; once the controller stamps data-stripe on the
9380
10017
  visible rows (so hidden rows never break the pattern), the stamped rules win. */
9381
10018
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"]:not([data-stripe]):nth-child(even):not([data-selected]) [data-part="td"] {
9382
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
10019
+ background: var(--stripe-bg);
9383
10020
  }
9384
10021
 
9385
10022
  [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"] {
9386
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
10023
+ background: var(--stripe-bg);
9387
10024
  }
9388
10025
 
9389
10026
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]) [data-part="td"] {
9390
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
10027
+ background: var(--stripe-bg);
9391
10028
  }
9392
10029
 
9393
10030
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]):hover [data-part="td"] {
9394
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
10031
+ background: var(--stripe-bg);
9395
10032
  }
9396
10033
 
9397
10034
  /* ── Bordered Variant ── */
9398
10035
  [data-ui="table"][data-variant="bordered"] [data-part="table"] {
9399
- border: 1px solid var(--color-border);
10036
+ border: var(--border-width) solid var(--color-border);
9400
10037
  border-radius: var(--radius-md, 0.375rem);
9401
10038
  overflow: hidden;
9402
10039
  }
9403
10040
 
9404
10041
  [data-ui="table"][data-variant="bordered"] [data-part="th"],
9405
10042
  [data-ui="table"][data-variant="bordered"] [data-part="td"] {
9406
- border: 1px solid var(--color-border);
10043
+ border: var(--border-width) solid var(--color-border);
9407
10044
  }
9408
10045
 
9409
10046
  /* ── Size: Small ── */
@@ -9431,7 +10068,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9431
10068
  /* ── Footer ── */
9432
10069
  [data-ui="table"] [data-part="tfoot"] [data-part="td"] {
9433
10070
  font-weight: var(--doc-table-footer-weight, var(--weight-semibold));
9434
- border-top: 2px solid var(--color-border);
10071
+ border-top: var(--border-width-strong) solid var(--color-border);
9435
10072
  border-bottom: none;
9436
10073
  background: var(--doc-table-footer-bg, var(--color-bg-subtle, oklch(0.97 0.004 260)));
9437
10074
  }
@@ -9557,7 +10194,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9557
10194
  [data-ui="table"] [data-part="filter-row"] [data-part="th"] {
9558
10195
  padding: var(--space-1) var(--space-2);
9559
10196
  background: var(--color-bg);
9560
- border-bottom: 1px solid var(--color-border);
10197
+ border-bottom: var(--border-width) solid var(--color-border);
9561
10198
  }
9562
10199
 
9563
10200
  [data-ui="table"] [data-part="filter-input"],
@@ -9569,14 +10206,14 @@ div[data-ui="separator"][data-style="thick"]::after {
9569
10206
  font-size: var(--text-xs);
9570
10207
  color: var(--color-fg);
9571
10208
  background: var(--color-bg);
9572
- border: 1px solid var(--color-border);
10209
+ border: var(--border-width) solid var(--color-border);
9573
10210
  border-radius: var(--radius-sm);
9574
10211
  }
9575
10212
 
9576
10213
  [data-ui="table"] [data-part="filter-input"]:focus,
9577
10214
  [data-ui="table"] [data-part="filter"]:focus {
9578
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9579
- outline-offset: -1px;
10215
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10216
+ outline-offset: calc(-1 * var(--border-width));
9580
10217
  border-color: var(--color-primary);
9581
10218
  }
9582
10219
 
@@ -9597,7 +10234,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9597
10234
  text-align: inherit;
9598
10235
  color: var(--color-fg);
9599
10236
  background: var(--color-bg);
9600
- border: 1px solid var(--color-primary);
10237
+ border: var(--border-width) solid var(--color-primary);
9601
10238
  border-radius: var(--radius-sm);
9602
10239
  outline: none;
9603
10240
  }
@@ -9650,11 +10287,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9650
10287
  }
9651
10288
 
9652
10289
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="before"] [data-part="td"] {
9653
- border-block-start: 2px solid var(--color-primary);
10290
+ border-block-start: var(--border-width-strong) solid var(--color-primary);
9654
10291
  }
9655
10292
 
9656
10293
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="after"] [data-part="td"] {
9657
- border-block-end: 2px solid var(--color-primary);
10294
+ border-block-end: var(--border-width-strong) solid var(--color-primary);
9658
10295
  }
9659
10296
 
9660
10297
  [data-ui="table"] [data-part="th"][data-dragging] {
@@ -9662,11 +10299,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9662
10299
  }
9663
10300
 
9664
10301
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="before"] {
9665
- border-inline-start: 2px solid var(--color-primary);
10302
+ border-inline-start: var(--border-width-strong) solid var(--color-primary);
9666
10303
  }
9667
10304
 
9668
10305
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="after"] {
9669
- border-inline-end: 2px solid var(--color-primary);
10306
+ border-inline-end: var(--border-width-strong) solid var(--color-primary);
9670
10307
  }
9671
10308
 
9672
10309
  /* ── Column Resize Handles (injected by the controller) ── */
@@ -9739,11 +10376,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9739
10376
  }
9740
10377
 
9741
10378
  [data-ui="table"] [data-pin="start"][data-pin-edge] {
9742
- border-inline-end: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10379
+ border-inline-end: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9743
10380
  }
9744
10381
 
9745
10382
  [data-ui="table"] [data-pin="end"][data-pin-edge] {
9746
- border-inline-start: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10383
+ border-inline-start: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9747
10384
  }
9748
10385
 
9749
10386
  /* ── Column Visibility ── */
@@ -9815,7 +10452,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9815
10452
  [data-ui="table"][data-stacked] [data-part="tfoot"] [data-part="tr"] {
9816
10453
  display: block;
9817
10454
  margin-block-end: var(--space-3);
9818
- border: 1px solid var(--color-border);
10455
+ border: var(--border-width) solid var(--color-border);
9819
10456
  border-radius: var(--radius-md);
9820
10457
  background: var(--color-bg);
9821
10458
  overflow: hidden;
@@ -9829,7 +10466,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9829
10466
  gap: var(--space-4);
9830
10467
  text-align: end;
9831
10468
  border-bottom: none;
9832
- border-block-end: 1px solid var(--color-border);
10469
+ border-block-end: var(--border-width) solid var(--color-border);
9833
10470
  }
9834
10471
 
9835
10472
  [data-ui="table"][data-stacked] [data-part="tr"] [data-part="td"]:last-child,
@@ -9926,7 +10563,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9926
10563
 
9927
10564
  /* === recipes/tabs.css === */
9928
10565
  /* @ui:component tabs */
9929
- /* @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 */
10566
+ /* @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 */
9930
10567
 
9931
10568
  /* ── Root ── */
9932
10569
  [data-ui="tabs"] {
@@ -9955,7 +10592,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9955
10592
  border: none;
9956
10593
  background: transparent;
9957
10594
  color: var(--color-fg-muted);
9958
- font-family: var(--font-sans, system-ui, sans-serif);
10595
+ font-family: var(--font-ui);
9959
10596
  font-size: var(--text-sm);
9960
10597
  font-weight: var(--weight-medium);
9961
10598
  cursor: pointer;
@@ -9970,8 +10607,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9970
10607
  }
9971
10608
 
9972
10609
  [data-ui="tabs"] [data-part="trigger"]:focus-visible {
9973
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9974
- outline-offset: -2px;
10610
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10611
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9975
10612
  border-radius: var(--radius-md);
9976
10613
  }
9977
10614
 
@@ -9981,12 +10618,12 @@ div[data-ui="separator"][data-style="thick"]::after {
9981
10618
 
9982
10619
  /* ── Underline Variant ── */
9983
10620
  [data-ui="tabs"][data-variant="underline"] [data-part="list"] {
9984
- border-bottom: 1px solid var(--color-border);
10621
+ border-bottom: var(--border-width) solid var(--color-border);
9985
10622
  gap: 0;
9986
10623
  }
9987
10624
 
9988
10625
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"] {
9989
- border-bottom: 2px solid transparent;
10626
+ border-bottom: var(--border-width-strong) solid transparent;
9990
10627
  margin-bottom: -1px;
9991
10628
  border-radius: 0;
9992
10629
  }
@@ -10018,17 +10655,17 @@ div[data-ui="separator"][data-style="thick"]::after {
10018
10655
  [data-ui="tabs"][data-variant="pill"] [data-part="trigger"][aria-selected="true"] {
10019
10656
  background: var(--color-bg);
10020
10657
  color: var(--color-fg);
10021
- box-shadow: var(--shadow-xs, 0 1px 2px oklch(0 0 0 / 0.04));
10658
+ box-shadow: var(--shadow-xs);
10022
10659
  }
10023
10660
 
10024
10661
  /* ── Enclosed Variant ── */
10025
10662
  [data-ui="tabs"][data-variant="enclosed"] [data-part="list"] {
10026
- border-bottom: 1px solid var(--color-border);
10663
+ border-bottom: var(--border-width) solid var(--color-border);
10027
10664
  gap: 0;
10028
10665
  }
10029
10666
 
10030
10667
  [data-ui="tabs"][data-variant="enclosed"] [data-part="trigger"] {
10031
- border: 1px solid transparent;
10668
+ border: var(--border-width) solid transparent;
10032
10669
  border-bottom: none;
10033
10670
  border-radius: var(--radius-md) var(--radius-md) 0 0;
10034
10671
  margin-bottom: -1px;
@@ -10073,8 +10710,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10073
10710
  @media (forced-colors: active) {
10074
10711
  [data-ui="tabs"] [data-part="trigger"][aria-selected="true"] {
10075
10712
  /* An outline the OS preserves, on every variant. */
10076
- outline: 2px solid Highlight;
10077
- outline-offset: -2px;
10713
+ outline: var(--border-width-strong) solid Highlight;
10714
+ outline-offset: calc(-1 * var(--border-width-strong));
10078
10715
  }
10079
10716
 
10080
10717
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"][aria-selected="true"] {
@@ -10089,7 +10726,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10089
10726
 
10090
10727
  /* === recipes/tag-input.css === */
10091
10728
  /* @ui:component tag-input */
10092
- /* @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 */
10729
+ /* @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 */
10093
10730
 
10094
10731
  /* NOTE: the tags themselves are `data-ui="chip"` elements — their styling comes
10095
10732
  entirely from chip.css. This file styles only the field wrapper, the tag row,
@@ -10110,7 +10747,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10110
10747
  gap: var(--space-1h);
10111
10748
  width: 100%;
10112
10749
  padding: var(--space-1h) var(--space-2);
10113
- border: 1px solid var(--color-border);
10750
+ border: var(--border-width) solid var(--color-border);
10114
10751
  border-radius: var(--radius-md);
10115
10752
  background: var(--color-bg);
10116
10753
  list-style: none;
@@ -10119,8 +10756,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10119
10756
  }
10120
10757
 
10121
10758
  [data-ui="tag-input"] [data-part="taglist"]:focus-within {
10122
- border-color: var(--color-ring, oklch(0.55 0.22 264));
10123
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
10759
+ border-color: var(--focus-ring-color);
10760
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
10124
10761
  }
10125
10762
 
10126
10763
  /* ── Text input: borderless, grows to fill the remaining row space ── */
@@ -10131,7 +10768,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10131
10768
  border: none;
10132
10769
  background: transparent;
10133
10770
  color: var(--color-fg);
10134
- font-family: var(--font-sans, system-ui, sans-serif);
10771
+ font-family: var(--font-ui);
10135
10772
  font-size: var(--text-sm);
10136
10773
  line-height: 1.5;
10137
10774
  outline: none;
@@ -10150,7 +10787,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10150
10787
  z-index: var(--z-dropdown);
10151
10788
  margin-top: var(--space-1);
10152
10789
  padding: var(--space-1);
10153
- border: 1px solid var(--color-border);
10790
+ border: var(--border-width) solid var(--color-border);
10154
10791
  border-radius: var(--radius-lg);
10155
10792
  background: var(--color-bg);
10156
10793
  box-shadow: var(--shadow-md);
@@ -10197,7 +10834,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10197
10834
 
10198
10835
  /* === recipes/toast.css === */
10199
10836
  /* @ui:component toast */
10200
- /* @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 */
10837
+ /* @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 */
10201
10838
 
10202
10839
  /* ── Container ── */
10203
10840
  [data-ui="toast"][data-part="container"] {
@@ -10246,8 +10883,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10246
10883
  max-width: 380px;
10247
10884
  width: max-content;
10248
10885
  padding: var(--space-3) var(--space-4);
10249
- background: var(--color-bg);
10250
- border: 1px solid var(--color-border);
10886
+ background: var(--panel-bg);
10887
+ border: var(--border-width) solid var(--color-border);
10251
10888
  border-radius: var(--radius-lg);
10252
10889
  box-shadow: var(--shadow-lg);
10253
10890
  pointer-events: auto;
@@ -10257,6 +10894,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10257
10894
  transform var(--duration-normal) var(--ease-out);
10258
10895
  }
10259
10896
 
10897
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
10898
+ [data-ui="toast"] [data-part="toast"] {
10899
+ -webkit-backdrop-filter: var(--surface-backdrop);
10900
+ backdrop-filter: var(--surface-backdrop);
10901
+ }
10902
+ }
10903
+
10260
10904
  /* ── State: Entering ── */
10261
10905
  [data-ui="toast"][data-variant="top-right"] [data-part="toast"][data-state="entering"],
10262
10906
  [data-ui="toast"][data-variant="top-left"] [data-part="toast"][data-state="entering"] {
@@ -10296,7 +10940,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10296
10940
 
10297
10941
  /* ── Tone Variants ── */
10298
10942
  [data-ui="toast"] [data-part="toast"][data-variant="success"] {
10299
- border-inline-start: 3px solid var(--color-success, oklch(0.55 0.18 145));
10943
+ border-inline-start: var(--border-width-lg) solid var(--color-success, oklch(0.55 0.18 145));
10300
10944
  }
10301
10945
 
10302
10946
  [data-ui="toast"] [data-part="toast"][data-variant="success"] [data-part="icon"] {
@@ -10304,7 +10948,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10304
10948
  }
10305
10949
 
10306
10950
  [data-ui="toast"] [data-part="toast"][data-variant="error"] {
10307
- border-inline-start: 3px solid var(--color-destructive, oklch(0.55 0.22 25));
10951
+ border-inline-start: var(--border-width-lg) solid var(--color-destructive, oklch(0.55 0.22 25));
10308
10952
  }
10309
10953
 
10310
10954
  [data-ui="toast"] [data-part="toast"][data-variant="error"] [data-part="icon"] {
@@ -10312,7 +10956,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10312
10956
  }
10313
10957
 
10314
10958
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] {
10315
- border-inline-start: 3px solid var(--color-warning, oklch(0.7 0.18 85));
10959
+ border-inline-start: var(--border-width-lg) solid var(--color-warning, oklch(0.7 0.18 85));
10316
10960
  }
10317
10961
 
10318
10962
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] [data-part="icon"] {
@@ -10334,7 +10978,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10334
10978
  /* ── Message ── */
10335
10979
  [data-ui="toast"] [data-part="message"] {
10336
10980
  flex: 1;
10337
- font-family: var(--font-sans, system-ui, sans-serif);
10981
+ font-family: var(--font-ui);
10338
10982
  font-size: var(--text-sm);
10339
10983
  font-weight: var(--weight-medium);
10340
10984
  color: var(--color-fg);
@@ -10345,11 +10989,11 @@ div[data-ui="separator"][data-style="thick"]::after {
10345
10989
  [data-ui="toast"] [data-part="action"] {
10346
10990
  flex-shrink: 0;
10347
10991
  padding: var(--space-1, 0.25rem) var(--space-2);
10348
- border: 1px solid var(--color-border);
10992
+ border: var(--border-width) solid var(--color-border);
10349
10993
  border-radius: var(--radius-md, 0.375rem);
10350
10994
  background: transparent;
10351
10995
  color: var(--color-fg);
10352
- font-family: var(--font-sans, system-ui, sans-serif);
10996
+ font-family: var(--font-ui);
10353
10997
  font-size: var(--text-xs, 0.75rem);
10354
10998
  font-weight: var(--weight-medium);
10355
10999
  cursor: pointer;
@@ -10362,8 +11006,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10362
11006
  }
10363
11007
 
10364
11008
  [data-ui="toast"] [data-part="action"]:focus-visible {
10365
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10366
- outline-offset: 2px;
11009
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11010
+ outline-offset: var(--focus-ring-offset);
10367
11011
  }
10368
11012
 
10369
11013
  /* ── Close Button ── */
@@ -10389,8 +11033,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10389
11033
  }
10390
11034
 
10391
11035
  [data-ui="toast"] [data-part="close"]:focus-visible {
10392
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10393
- outline-offset: 2px;
11036
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11037
+ outline-offset: var(--focus-ring-offset);
10394
11038
  }
10395
11039
 
10396
11040
  /* ── Motion ── */
@@ -10403,14 +11047,14 @@ div[data-ui="separator"][data-style="thick"]::after {
10403
11047
 
10404
11048
  /* === recipes/toggle-group.css === */
10405
11049
  /* @ui:component toggle-group */
10406
- /* @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 */
11050
+ /* @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 */
10407
11051
 
10408
11052
  /* ── Root: a segmented row of toggle buttons ── */
10409
11053
  [data-ui="toggle-group"] {
10410
11054
  display: inline-flex;
10411
11055
  gap: var(--space-1);
10412
11056
  padding: var(--space-1);
10413
- border: 1px solid var(--color-border);
11057
+ border: var(--border-width) solid var(--color-border);
10414
11058
  border-radius: var(--radius-md);
10415
11059
  background: var(--color-bg);
10416
11060
  }
@@ -10425,7 +11069,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10425
11069
  border-radius: var(--radius-md);
10426
11070
  background: transparent;
10427
11071
  color: var(--color-fg-muted);
10428
- font-family: var(--toggle-group-font, var(--font-sans));
11072
+ font-family: var(--toggle-group-font, var(--font-ui));
10429
11073
  font-size: var(--text-sm);
10430
11074
  font-weight: var(--weight-medium);
10431
11075
  line-height: 1;
@@ -10466,13 +11110,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10466
11110
 
10467
11111
  /* ── Keyboard focus ring on the item (focus lives on the hidden control) ── */
10468
11112
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:focus-visible) {
10469
- outline: 2px solid var(--color-ring);
10470
- outline-offset: 2px;
11113
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11114
+ outline-offset: var(--focus-ring-offset);
10471
11115
  }
10472
11116
 
10473
11117
  /* ── Disabled control ── */
10474
11118
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:disabled) {
10475
- opacity: 0.5;
11119
+ opacity: var(--disabled-opacity);
10476
11120
  cursor: not-allowed;
10477
11121
  }
10478
11122
 
@@ -10485,7 +11129,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10485
11129
 
10486
11130
  /* === recipes/tooltip.css === */
10487
11131
  /* @ui:component tooltip */
10488
- /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default */
11132
+ /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default font-ui surface-backdrop */
10489
11133
 
10490
11134
  /* ── Root ── */
10491
11135
  [data-ui="tooltip"] {
@@ -10506,7 +11150,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10506
11150
  color: var(--color-bg);
10507
11151
  border-radius: var(--radius-md);
10508
11152
  padding: var(--space-1h, 0.375rem) var(--space-2);
10509
- font-family: var(--font-sans, system-ui, sans-serif);
11153
+ font-family: var(--font-ui);
10510
11154
  font-size: var(--text-xs, 0.75rem);
10511
11155
  line-height: 1.4;
10512
11156
  white-space: nowrap;
@@ -10517,6 +11161,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10517
11161
  transform var(--duration-fast) var(--ease-default);
10518
11162
  }
10519
11163
 
11164
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
11165
+ [data-ui="tooltip"] [data-part="content"] {
11166
+ -webkit-backdrop-filter: var(--surface-backdrop);
11167
+ backdrop-filter: var(--surface-backdrop);
11168
+ }
11169
+ }
11170
+
10520
11171
  /* Default position (top) when no variant is specified */
10521
11172
  [data-ui="tooltip"]:not([data-variant]) [data-part="content"] {
10522
11173
  bottom: 100%;
@@ -10632,7 +11283,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10632
11283
 
10633
11284
  /* === recipes/tree-view.css === */
10634
11285
  /* @ui:component tree-view */
10635
- /* @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 */
11286
+ /* @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 */
10636
11287
 
10637
11288
  [data-ui="tree-view"],
10638
11289
  [data-ui="tree-view"] [data-part="group"] {
@@ -10645,7 +11296,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10645
11296
  inline-size: 100%;
10646
11297
  padding: var(--space-1);
10647
11298
  color: var(--color-fg);
10648
- font-family: var(--font-sans);
11299
+ font-family: var(--font-ui);
10649
11300
  font-size: var(--text-sm);
10650
11301
  }
10651
11302
 
@@ -10673,8 +11324,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10673
11324
  }
10674
11325
 
10675
11326
  [data-ui="tree-view"] [data-part="item"]:focus-visible > [data-part="label"] {
10676
- outline: var(--space-px) solid var(--color-ring);
10677
- outline-offset: var(--space-px);
11327
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11328
+ outline-offset: var(--focus-ring-offset);
10678
11329
  }
10679
11330
 
10680
11331
  [data-ui="tree-view"] [data-part="item"][aria-selected="true"] > [data-part="label"] {
@@ -10713,7 +11364,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10713
11364
 
10714
11365
  /* === patterns/auth-form.css === */
10715
11366
  /* @ui:component auth-form */
10716
- /* @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 */
11367
+ /* @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 */
10717
11368
 
10718
11369
  /* ── Root Container ── */
10719
11370
  [data-ui="auth-form"] {
@@ -10721,7 +11372,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10721
11372
  align-items: center;
10722
11373
  justify-content: center;
10723
11374
  width: 100%;
10724
- font-family: var(--font-sans);
11375
+ font-family: var(--font-body);
10725
11376
  }
10726
11377
 
10727
11378
  /* Mobile-first (task 0.8-09): on a phone the card IS the page — edge to edge,
@@ -10753,9 +11404,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10753
11404
 
10754
11405
  [data-ui="auth-form"] [data-part="title"] {
10755
11406
  margin: 0;
11407
+ font-family: var(--font-heading);
10756
11408
  font-size: var(--text-xl);
10757
- font-weight: var(--weight-bold);
10758
- line-height: var(--leading-tight);
11409
+ font-weight: var(--heading-weight);
11410
+ letter-spacing: var(--heading-tracking);
11411
+ text-transform: var(--heading-transform);
11412
+ font-variant-caps: var(--heading-caps);
11413
+ line-height: var(--heading-leading);
10759
11414
  color: var(--color-fg);
10760
11415
  }
10761
11416
 
@@ -10772,7 +11427,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10772
11427
  margin: var(--space-4) var(--space-6) 0;
10773
11428
  padding: var(--space-3);
10774
11429
  background: var(--color-destructive-subtle);
10775
- border: 1px solid var(--color-destructive);
11430
+ border: var(--border-width) solid var(--color-destructive);
10776
11431
  border-radius: var(--radius-lg);
10777
11432
  color: var(--color-destructive);
10778
11433
  font-size: var(--text-sm);
@@ -10850,13 +11505,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10850
11505
  }
10851
11506
 
10852
11507
  [data-ui="auth-form"] [data-part="footer"] a:hover {
10853
- text-decoration: underline;
11508
+ text-decoration-line: var(--link-decoration);
10854
11509
  color: var(--color-primary-hover);
10855
11510
  }
10856
11511
 
10857
11512
  [data-ui="auth-form"] [data-part="footer"] a:focus-visible {
10858
- outline: 2px solid var(--color-ring);
10859
- outline-offset: 2px;
11513
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11514
+ outline-offset: var(--focus-ring-offset);
10860
11515
  border-radius: var(--radius-sm, 0.25rem);
10861
11516
  }
10862
11517
 
@@ -10984,8 +11639,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10984
11639
  max-width: var(--auth-form-max-width, 400px);
10985
11640
  border-radius: var(--card-radius, var(--radius-lg));
10986
11641
  box-shadow: var(--card-shadow, var(--shadow-sm));
10987
- border-inline-start: 1px solid var(--card-border, var(--color-border));
10988
- border-inline-end: 1px solid var(--card-border, var(--color-border));
11642
+ border-inline-start: var(--border-width) solid var(--card-border, var(--color-border));
11643
+ border-inline-end: var(--border-width) solid var(--card-border, var(--color-border));
10989
11644
  }
10990
11645
  }
10991
11646
 
@@ -11000,7 +11655,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11000
11655
 
11001
11656
  /* === patterns/crud-table.css === */
11002
11657
  /* @ui:component crud-table */
11003
- /* @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 */
11658
+ /* @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 */
11004
11659
 
11005
11660
  /* ── Root ── */
11006
11661
  [data-ui="crud-table"] {
@@ -11008,7 +11663,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11008
11663
  flex-direction: column;
11009
11664
  gap: var(--space-4);
11010
11665
  width: 100%;
11011
- font-family: var(--font-sans, system-ui, sans-serif);
11666
+ font-family: var(--font-body);
11012
11667
  }
11013
11668
 
11014
11669
  /* ── Toolbar ── */
@@ -11066,7 +11721,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11066
11721
  gap: var(--space-3);
11067
11722
  padding: var(--space-3) var(--space-4);
11068
11723
  background: var(--color-bg-subtle);
11069
- border: 1px solid var(--color-border);
11724
+ border: var(--border-width) solid var(--color-border);
11070
11725
  border-radius: var(--radius-md);
11071
11726
  }
11072
11727
 
@@ -11081,7 +11736,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11081
11736
  [data-ui="crud-table"] [data-part="table-wrapper"] {
11082
11737
  width: 100%;
11083
11738
  overflow-x: auto;
11084
- border: 1px solid var(--color-border);
11739
+ border: var(--border-width) solid var(--color-border);
11085
11740
  border-radius: var(--radius-lg);
11086
11741
  background: var(--color-bg);
11087
11742
  }
@@ -11111,7 +11766,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11111
11766
  padding: var(--space-8) var(--space-4);
11112
11767
  text-align: center;
11113
11768
  min-height: 240px;
11114
- border: 1px dashed var(--color-border);
11769
+ border: var(--border-width) dashed var(--color-border);
11115
11770
  border-radius: var(--radius-lg);
11116
11771
  background: var(--color-bg);
11117
11772
  }
@@ -11224,7 +11879,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11224
11879
 
11225
11880
  /* === patterns/dashboard-shell.css === */
11226
11881
  /* @ui:component dashboard-shell */
11227
- /* @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 */
11882
+ /* @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 */
11228
11883
 
11229
11884
  /* ── Shell Grid Layout ──
11230
11885
  Mobile-first (task 0.8-09): the base is the PHONE shell — one column, header
@@ -11249,7 +11904,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11249
11904
  "footer";
11250
11905
  min-height: 100vh;
11251
11906
  background: var(--color-bg);
11252
- font-family: var(--font-sans);
11907
+ font-family: var(--font-body);
11253
11908
  color: var(--color-fg);
11254
11909
  }
11255
11910
 
@@ -11273,7 +11928,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11273
11928
  gap: var(--space-2);
11274
11929
  padding: var(--space-4);
11275
11930
  background: var(--color-bg-subtle);
11276
- border-inline-end: 1px solid var(--color-border);
11931
+ border-inline-end: var(--border-width) solid var(--color-border);
11277
11932
  overflow-y: auto;
11278
11933
  position: fixed;
11279
11934
  top: 0;
@@ -11293,7 +11948,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11293
11948
 
11294
11949
  [data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"] {
11295
11950
  border-inline-end: none;
11296
- border-inline-start: 1px solid var(--color-border);
11951
+ border-inline-start: var(--border-width) solid var(--color-border);
11297
11952
  inset-inline-start: auto;
11298
11953
  inset-inline-end: 0;
11299
11954
  transform: translateX(100%);
@@ -11368,7 +12023,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11368
12023
  gap: var(--space-3);
11369
12024
  padding: var(--space-2) var(--space-3);
11370
12025
  border-radius: var(--radius-md);
11371
- font-family: var(--font-sans);
12026
+ font-family: var(--font-ui);
11372
12027
  font-size: var(--text-sm);
11373
12028
  font-weight: var(--weight-medium);
11374
12029
  line-height: var(--leading-normal);
@@ -11387,8 +12042,8 @@ div[data-ui="separator"][data-style="thick"]::after {
11387
12042
  }
11388
12043
 
11389
12044
  [data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"]:focus-visible {
11390
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
11391
- outline-offset: -2px;
12045
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
12046
+ outline-offset: calc(-1 * var(--focus-ring-offset));
11392
12047
  }
11393
12048
 
11394
12049
  /* ── Nav Item Active ── */
@@ -11435,7 +12090,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11435
12090
  gap: var(--space-2);
11436
12091
  padding: 0 var(--space-3);
11437
12092
  background: var(--color-bg);
11438
- border-bottom: 1px solid var(--color-border);
12093
+ border-bottom: var(--border-width) solid var(--color-border);
11439
12094
  position: sticky;
11440
12095
  top: 0;
11441
12096
  z-index: var(--z-sticky);
@@ -11516,7 +12171,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11516
12171
  align-items: center;
11517
12172
  gap: var(--space-3);
11518
12173
  padding: var(--space-4) var(--space-6);
11519
- border-top: 1px solid var(--color-border);
12174
+ border-top: var(--border-width) solid var(--color-border);
11520
12175
  font-size: var(--text-xs);
11521
12176
  color: var(--color-fg-muted);
11522
12177
  }
@@ -11599,7 +12254,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11599
12254
 
11600
12255
  /* === patterns/document.css === */
11601
12256
  /* @ui:component document */
11602
- /* @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 */
12257
+ /* @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 */
11603
12258
 
11604
12259
  /* ── Page Rules ── */
11605
12260
  @page {
@@ -11639,14 +12294,17 @@ div[data-ui="separator"][data-style="thick"]::after {
11639
12294
  max-width: var(--doc-max-width);
11640
12295
  margin: var(--space-4) auto;
11641
12296
  padding: var(--space-6) var(--space-4);
11642
- background: var(--color-bg, #fff);
12297
+ background-color: var(--color-bg, #fff);
12298
+ background-image: var(--texture-page);
11643
12299
  color: var(--color-fg);
11644
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
12300
+ font-family: var(--doc-font, var(--font-body));
11645
12301
  font-size: var(--doc-font-size);
11646
12302
  line-height: var(--doc-line-height);
11647
- box-shadow: var(--shadow-lg,
11648
- 0 10px 15px -3px rgba(0, 0, 0, 0.1),
11649
- 0 4px 6px -4px rgba(0, 0, 0, 0.1));
12303
+ /* The fallback here used to spell out two rgba() layers, which is a shadow
12304
+ colour no theme could reach. --shadow-lg is always defined by the token
12305
+ layer, and it now carries --shadow-color, so the fallback is gone rather
12306
+ than re-tokenised. */
12307
+ box-shadow: var(--shadow-lg);
11650
12308
  border-radius: 0;
11651
12309
  position: relative;
11652
12310
  }
@@ -11662,7 +12320,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11662
12320
  [data-ui="document"] > [data-part="header"] {
11663
12321
  margin-block-end: var(--doc-section-gap);
11664
12322
  padding-block-end: var(--doc-component-gap);
11665
- border-block-end: 1px solid var(--color-border);
12323
+ border-block-end: var(--border-width) solid var(--color-border);
11666
12324
  }
11667
12325
 
11668
12326
  /* ── Body ── */
@@ -11672,13 +12330,25 @@ div[data-ui="separator"][data-style="thick"]::after {
11672
12330
  gap: var(--doc-section-gap);
11673
12331
  }
11674
12332
 
12333
+ /* ── Headings ──
12334
+ The document's own heading face and weight (1.1A-21): a print theme sets
12335
+ --doc-heading-font / --doc-heading-weight to give its titles a voice apart
12336
+ from the body copy (document-serif's Times titles over Georgia text). Both
12337
+ default to the page's heading role in tokens/document.css, and each falls
12338
+ back to what a heading rendered before the tokens had a reader. A heading
12339
+ that carries its own data-weight keeps it — that is the author asking. */
12340
+ [data-ui="document"] :is(h1, h2, h3, h4, h5, h6) {
12341
+ font-family: var(--doc-heading-font, var(--font-body));
12342
+ font-weight: var(--doc-heading-weight, var(--weight-bold));
12343
+ }
12344
+
11675
12345
  /* ── Running footer ──
11676
12346
  footer remains a non-breaking selector alias for pre-1.1.0 documents. */
11677
12347
  [data-ui="document"] > [data-part="doc-footer"],
11678
12348
  [data-ui="document"] > [data-part="footer"] {
11679
12349
  margin-block-start: var(--doc-section-gap);
11680
12350
  padding-block-start: var(--doc-component-gap);
11681
- border-block-start: 1px solid var(--color-border);
12351
+ border-block-start: var(--border-width) solid var(--color-border);
11682
12352
  font-size: var(--doc-legal-size);
11683
12353
  color: var(--doc-legal-color);
11684
12354
  }
@@ -11716,7 +12386,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11716
12386
 
11717
12387
  /* ── Variant: Report ── */
11718
12388
  [data-ui="document"][data-variant="report"] {
11719
- font-family: var(--font-serif, Georgia, "Times New Roman", serif);
12389
+ /* A report is serif-set by definition. It re-points the document's own font
12390
+ ROLE rather than its `font-family`, so every doc primitive nested inside it
12391
+ (key-value, callout, signature — all of which read --doc-font) follows the
12392
+ report into serif instead of staying sans inside a serif page. `report` is
12393
+ the author asking for serif; a theme that wants its own document face
12394
+ declares --doc-font at :root, which this variant deliberately outranks. */
12395
+ --doc-font: Georgia, 'Times New Roman', serif;
11720
12396
  line-height: 1.6;
11721
12397
  }
11722
12398
 
@@ -11811,7 +12487,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11811
12487
  z-index: var(--z-raised);
11812
12488
  margin-block-end: 0;
11813
12489
  padding-block-end: var(--doc-running-gap);
11814
- border-block-end: 1px solid var(--doc-print-border-color);
12490
+ border-block-end: var(--border-width) solid var(--doc-print-border-color);
11815
12491
  background: var(--doc-bg);
11816
12492
  transform: translateZ(0);
11817
12493
  }
@@ -11827,7 +12503,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11827
12503
  z-index: var(--z-raised);
11828
12504
  margin-block-start: 0;
11829
12505
  padding-block-start: var(--doc-running-gap);
11830
- border-block-start: 1px solid var(--doc-print-border-color);
12506
+ border-block-start: var(--border-width) solid var(--doc-print-border-color);
11831
12507
  background: var(--doc-bg);
11832
12508
  transform: translateZ(0);
11833
12509
  }
@@ -11856,7 +12532,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11856
12532
 
11857
12533
  /* === patterns/empty-state.css === */
11858
12534
  /* @ui:component empty-state */
11859
- /* @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 */
12535
+ /* @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 */
11860
12536
 
11861
12537
  /* ── Root ── */
11862
12538
  [data-ui="empty-state"] {
@@ -11867,7 +12543,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11867
12543
  text-align: center;
11868
12544
  padding: var(--space-8) var(--space-6);
11869
12545
  gap: var(--space-3);
11870
- font-family: var(--font-sans, system-ui, sans-serif);
12546
+ font-family: var(--font-body);
11871
12547
  }
11872
12548
 
11873
12549
  /* ── Icon ── */
@@ -11890,10 +12566,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11890
12566
 
11891
12567
  /* ── Title ── */
11892
12568
  [data-ui="empty-state"] [data-part="title"] {
11893
- font-family: var(--font-sans, system-ui, sans-serif);
12569
+ font-family: var(--font-heading);
11894
12570
  font-size: var(--text-lg);
11895
12571
  font-weight: var(--weight-semibold);
11896
- line-height: var(--leading-tight);
12572
+ letter-spacing: var(--heading-tracking);
12573
+ text-transform: var(--heading-transform);
12574
+ font-variant-caps: var(--heading-caps);
12575
+ line-height: var(--heading-leading);
11897
12576
  color: var(--color-fg);
11898
12577
  margin: 0;
11899
12578
  }
@@ -11991,7 +12670,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11991
12670
 
11992
12671
  /* === patterns/feature-grid.css === */
11993
12672
  /* @ui:component feature-grid */
11994
- /* @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 */
12673
+ /* @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 */
11995
12674
 
11996
12675
  /* ── Root ──
11997
12676
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -12001,7 +12680,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12001
12680
  gap: var(--space-4);
12002
12681
  padding-block: var(--space-12);
12003
12682
  padding-inline: var(--space-4);
12004
- font-family: var(--font-sans, system-ui, sans-serif);
12683
+ font-family: var(--font-body);
12005
12684
  color: var(--color-fg);
12006
12685
  background: var(--color-bg);
12007
12686
  }
@@ -12143,7 +12822,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12143
12822
  max-inline-size: var(--measure-narrow);
12144
12823
  margin-inline: auto;
12145
12824
  padding-block: var(--space-8);
12146
- font-family: var(--font-sans);
12825
+ font-family: var(--font-body);
12147
12826
  }
12148
12827
 
12149
12828
  :where(form[l-data]:not([data-ui]) > h1) {
@@ -12163,7 +12842,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12163
12842
 
12164
12843
  /* === patterns/hero.css === */
12165
12844
  /* @ui:component hero */
12166
- /* @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 */
12845
+ /* @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 */
12167
12846
 
12168
12847
  /* ── Root ──
12169
12848
  A one-column grid by default; the layout variants only change how that grid
@@ -12177,9 +12856,10 @@ div[data-ui="separator"][data-style="thick"]::after {
12177
12856
  gap: var(--space-4);
12178
12857
  padding-block: var(--space-12);
12179
12858
  padding-inline: var(--space-4);
12180
- font-family: var(--font-sans, system-ui, sans-serif);
12859
+ font-family: var(--font-body);
12181
12860
  color: var(--color-fg);
12182
- background: var(--color-bg);
12861
+ background-color: var(--color-bg);
12862
+ background-image: var(--texture-surface);
12183
12863
  }
12184
12864
 
12185
12865
  /* ── Eyebrow ── */
@@ -12191,9 +12871,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12191
12871
  /* ── Headline ── */
12192
12872
  [data-ui="hero"] [data-part="headline"] {
12193
12873
  margin: 0;
12874
+ font-family: var(--font-heading);
12194
12875
  font-size: var(--text-3xl);
12195
- font-weight: var(--weight-bold);
12196
- line-height: var(--leading-tight);
12876
+ font-weight: var(--heading-weight);
12877
+ letter-spacing: var(--heading-tracking);
12878
+ text-transform: var(--heading-transform);
12879
+ font-variant-caps: var(--heading-caps);
12880
+ line-height: var(--heading-leading);
12197
12881
  color: var(--color-fg);
12198
12882
  text-wrap: balance;
12199
12883
  }
@@ -12312,7 +12996,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12312
12996
 
12313
12997
  /* === patterns/inbox.css === */
12314
12998
  /* @ui:component inbox */
12315
- /* @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 */
12999
+ /* @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 */
12316
13000
 
12317
13001
  /* ── Root ──
12318
13002
  ONE pane, because that is what a phone has room for. Each pane's `data-state`
@@ -12332,7 +13016,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12332
13016
  overflow: hidden;
12333
13017
  border: var(--space-px, 1px) solid var(--color-border);
12334
13018
  border-radius: var(--radius-lg);
12335
- font-family: var(--font-sans, system-ui, sans-serif);
13019
+ font-family: var(--font-body);
12336
13020
  color: var(--color-fg);
12337
13021
  background: var(--color-bg);
12338
13022
  }
@@ -12424,8 +13108,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12424
13108
  }
12425
13109
 
12426
13110
  [data-ui="inbox"] [data-part="item"]:focus-visible {
12427
- outline: 2px solid var(--color-ring);
12428
- outline-offset: 2px;
13111
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13112
+ outline-offset: var(--focus-ring-offset);
12429
13113
  }
12430
13114
 
12431
13115
  [data-ui="inbox"] [data-part="item"][data-state="selected"] {
@@ -12584,7 +13268,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12584
13268
 
12585
13269
  /* === patterns/pricing.css === */
12586
13270
  /* @ui:component pricing */
12587
- /* @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 */
13271
+ /* @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 */
12588
13272
 
12589
13273
  /* ── Root ──
12590
13274
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -12594,7 +13278,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12594
13278
  gap: var(--space-4);
12595
13279
  padding-block: var(--space-12);
12596
13280
  padding-inline: var(--space-4);
12597
- font-family: var(--font-sans, system-ui, sans-serif);
13281
+ font-family: var(--font-body);
12598
13282
  color: var(--color-fg);
12599
13283
  background: var(--color-bg);
12600
13284
  }
@@ -12644,9 +13328,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12644
13328
 
12645
13329
  [data-ui="pricing"] [data-part="tier"] [data-part="title"] {
12646
13330
  margin: 0;
13331
+ font-family: var(--font-heading);
12647
13332
  font-size: var(--text-lg);
12648
13333
  font-weight: var(--weight-semibold);
12649
- line-height: var(--leading-tight);
13334
+ letter-spacing: var(--heading-tracking);
13335
+ text-transform: var(--heading-transform);
13336
+ font-variant-caps: var(--heading-caps);
13337
+ line-height: var(--heading-leading);
12650
13338
  }
12651
13339
 
12652
13340
  [data-ui="pricing"] [data-part="tier"] [data-part="header"] [data-part="description"] {
@@ -12707,7 +13395,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12707
13395
  [data-ui="pricing"] [data-part="tier"][data-state="featured"] {
12708
13396
  border-color: var(--color-primary);
12709
13397
  box-shadow: var(--shadow-md);
12710
- outline: var(--space-px, 1px) solid var(--color-primary);
13398
+ outline: var(--border-width-strong) solid var(--color-primary);
12711
13399
  }
12712
13400
 
12713
13401
  /* ── Footnote ── */
@@ -12752,14 +13440,14 @@ div[data-ui="separator"][data-style="thick"]::after {
12752
13440
 
12753
13441
  /* === patterns/search-results.css === */
12754
13442
  /* @ui:component search-results */
12755
- /* @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 */
13443
+ /* @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 */
12756
13444
 
12757
13445
  /* ── Root ── */
12758
13446
  [data-ui="search-results"] {
12759
13447
  display: flex;
12760
13448
  flex-direction: column;
12761
13449
  gap: var(--space-4);
12762
- font-family: var(--font-sans, system-ui, sans-serif);
13450
+ font-family: var(--font-body);
12763
13451
  }
12764
13452
 
12765
13453
  /* ── Search Input ── */
@@ -12787,7 +13475,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12787
13475
  justify-content: space-between;
12788
13476
  gap: var(--space-4);
12789
13477
  padding-bottom: var(--space-2);
12790
- border-bottom: 1px solid var(--color-border);
13478
+ border-bottom: var(--border-width) solid var(--color-border);
12791
13479
  }
12792
13480
 
12793
13481
  [data-ui="search-results"] [data-part="results-count"] {
@@ -12822,7 +13510,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12822
13510
  flex-direction: column;
12823
13511
  gap: var(--space-2);
12824
13512
  padding: var(--space-4);
12825
- border: 1px solid var(--color-border);
13513
+ border: var(--border-width) solid var(--color-border);
12826
13514
  border-radius: var(--radius-md);
12827
13515
  background: var(--color-bg);
12828
13516
  transition: background var(--duration-fast) var(--ease-default),
@@ -12881,7 +13569,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12881
13569
  display: flex;
12882
13570
  justify-content: center;
12883
13571
  padding-top: var(--space-4);
12884
- border-top: 1px solid var(--color-border);
13572
+ border-top: var(--border-width) solid var(--color-border);
12885
13573
  }
12886
13574
 
12887
13575
  /* ── Loading ── */
@@ -12921,7 +13609,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12921
13609
 
12922
13610
  /* ── Error State ── */
12923
13611
  [data-ui="search-results"][data-state="error"] [data-part="results-list"] {
12924
- border: 1px solid var(--color-border);
13612
+ border: var(--border-width) solid var(--color-border);
12925
13613
  border-radius: var(--radius-md);
12926
13614
  padding: var(--space-6);
12927
13615
  text-align: center;
@@ -12930,8 +13618,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12930
13618
 
12931
13619
  /* ── Focus management ── */
12932
13620
  [data-ui="search-results"] [data-part="result-item"]:focus-visible {
12933
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
12934
- outline-offset: 2px;
13621
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13622
+ outline-offset: var(--focus-ring-offset);
12935
13623
  }
12936
13624
 
12937
13625
  /* ── Motion ── */
@@ -12947,7 +13635,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12947
13635
 
12948
13636
  /* === patterns/settings-page.css === */
12949
13637
  /* @ui:component settings-page */
12950
- /* @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 */
13638
+ /* @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 */
12951
13639
 
12952
13640
  /* ── Root ── */
12953
13641
  [data-ui="settings-page"] {
@@ -12957,7 +13645,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12957
13645
  width: 100%;
12958
13646
  max-width: 768px;
12959
13647
  margin-inline: auto;
12960
- font-family: var(--font-sans, system-ui, sans-serif);
13648
+ font-family: var(--font-body);
12961
13649
  color: var(--color-fg);
12962
13650
  }
12963
13651
 
@@ -12971,9 +13659,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12971
13659
  /* ── Title ── */
12972
13660
  [data-ui="settings-page"] [data-part="title"] {
12973
13661
  margin: 0;
13662
+ font-family: var(--font-heading);
12974
13663
  font-size: var(--text-xl, 1.25rem);
12975
13664
  font-weight: var(--weight-semibold, 600);
12976
- line-height: var(--leading-tight);
13665
+ letter-spacing: var(--heading-tracking);
13666
+ text-transform: var(--heading-transform);
13667
+ font-variant-caps: var(--heading-caps);
13668
+ line-height: var(--heading-leading);
12977
13669
  color: var(--color-fg);
12978
13670
  }
12979
13671
 
@@ -13037,7 +13729,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13037
13729
  gap: var(--space-3, 0.75rem);
13038
13730
  padding: var(--space-4);
13039
13731
  background: var(--color-bg);
13040
- border-top: 1px solid var(--color-border);
13732
+ border-top: var(--border-width) solid var(--color-border);
13041
13733
  border-radius: var(--radius-lg);
13042
13734
  box-shadow: var(--shadow-md);
13043
13735
  position: sticky;
@@ -13101,7 +13793,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13101
13793
  flex-direction: row;
13102
13794
  flex-wrap: wrap;
13103
13795
  border-inline-end: none;
13104
- border-bottom: 1px solid var(--color-border);
13796
+ border-bottom: var(--border-width) solid var(--color-border);
13105
13797
  padding-inline-end: 0;
13106
13798
  position: static;
13107
13799
  }
@@ -13120,7 +13812,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13120
13812
  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="list"] {
13121
13813
  flex-direction: column;
13122
13814
  border-bottom: none;
13123
- border-inline-end: 1px solid var(--color-border);
13815
+ border-inline-end: var(--border-width) solid var(--color-border);
13124
13816
  padding-inline-end: var(--space-4);
13125
13817
  position: sticky;
13126
13818
  top: var(--space-4);
@@ -13138,7 +13830,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13138
13830
  justify-content: flex-start;
13139
13831
  text-align: start;
13140
13832
  border-bottom: none;
13141
- border-inline-start: 2px solid transparent;
13833
+ border-inline-start: var(--border-width-strong) solid transparent;
13142
13834
  margin-bottom: 0;
13143
13835
  margin-inline-end: -1px;
13144
13836
  padding: var(--space-2) var(--space-3);
@@ -13172,7 +13864,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13172
13864
 
13173
13865
  /* === patterns/site-footer.css === */
13174
13866
  /* @ui:component site-footer */
13175
- /* @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 */
13867
+ /* @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 */
13176
13868
 
13177
13869
  /* ── Root ──
13178
13870
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -13182,11 +13874,11 @@ div[data-ui="separator"][data-style="thick"]::after {
13182
13874
  gap: var(--space-8);
13183
13875
  padding-block: var(--space-10);
13184
13876
  padding-inline: var(--space-4);
13185
- font-family: var(--font-sans, system-ui, sans-serif);
13877
+ font-family: var(--font-body);
13186
13878
  font-size: var(--text-sm);
13187
13879
  color: var(--color-fg-muted);
13188
13880
  background: var(--color-bg-subtle);
13189
- border-block-start: 1px solid var(--color-border);
13881
+ border-block-start: var(--border-width) solid var(--color-border);
13190
13882
  }
13191
13883
 
13192
13884
  /* ── Brand ── */
@@ -13318,7 +14010,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13318
14010
 
13319
14011
  /* === patterns/stats-dashboard.css === */
13320
14012
  /* @ui:component stats-dashboard */
13321
- /* @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 */
14013
+ /* @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 */
13322
14014
 
13323
14015
  /* ── Root ──
13324
14016
  A reporting page: title block, KPI row, then the panel region. The KPI row
@@ -13331,7 +14023,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13331
14023
  gap: var(--space-3);
13332
14024
  padding-block: var(--space-8);
13333
14025
  padding-inline: var(--space-4);
13334
- font-family: var(--font-sans, system-ui, sans-serif);
14026
+ font-family: var(--font-body);
13335
14027
  color: var(--color-fg);
13336
14028
  background: var(--color-bg);
13337
14029
  }
@@ -13405,9 +14097,13 @@ div[data-ui="separator"][data-style="thick"]::after {
13405
14097
 
13406
14098
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="title"] {
13407
14099
  margin: 0;
14100
+ font-family: var(--font-heading);
13408
14101
  font-size: var(--text-lg);
13409
14102
  font-weight: var(--weight-semibold);
13410
- line-height: var(--leading-tight);
14103
+ letter-spacing: var(--heading-tracking);
14104
+ text-transform: var(--heading-transform);
14105
+ font-variant-caps: var(--heading-caps);
14106
+ line-height: var(--heading-leading);
13411
14107
  }
13412
14108
 
13413
14109
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="header"] [data-part="description"] {
@@ -13498,7 +14194,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13498
14194
  gap: var(--space-6);
13499
14195
  max-inline-size: var(--measure-narrow);
13500
14196
  margin-inline: auto;
13501
- font-family: var(--font-sans);
14197
+ font-family: var(--font-body);
13502
14198
  }
13503
14199
 
13504
14200
  [data-ui="wizard"] [data-part="heading"] {