@faqir-ui/core 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +45 -5
  2. package/cdn.json +38 -22
  3. package/dist/faqir-core.js +89 -52
  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 +61 -54
  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 +111 -5
  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/soft.css === */
645
1033
  /* @ui:theme soft — pastel warmth, large friendly radii; consumer & health apps */
646
1034
 
@@ -713,11 +1101,29 @@
713
1101
  --radius-2xl: 2rem;
714
1102
 
715
1103
  /* ── Component Aliases (pill buttons, pillowy cards) ── */
716
- --button-radius: var(--radius-full);
717
- --badge-radius: var(--radius-full);
718
- --card-radius: var(--radius-xl);
719
- --input-radius: var(--radius-lg);
720
- --dialog-radius: var(--radius-2xl);
1104
+ --button-radius: var(--radius-full);
1105
+ --badge-radius: var(--radius-full);
1106
+ --card-radius: var(--radius-xl);
1107
+ --input-radius: var(--radius-lg);
1108
+ --dialog-radius: var(--radius-2xl);
1109
+ --checkbox-radius: var(--radius-full); /* even the tick box is round */
1110
+
1111
+ /* ── Motion: springy ──
1112
+ The easing PALETTE carries a spring (`--ease-spring`, upgraded to a real
1113
+ `linear()` curve where the browser has one); a theme with this personality
1114
+ points the DEFAULT at it, and every transition in the registry inherits the
1115
+ overshoot without a single component knowing about it. The hover lift stays
1116
+ gentle: past -2px the axis (rightly) reads `playful`, and this theme is
1117
+ calm, not bouncy. */
1118
+ --ease-default: var(--ease-spring);
1119
+ --motion-hover-lift: 0 -1px;
1120
+
1121
+ /* ── Focus: a glow, not a hairline ──
1122
+ `--focus-shadow` is drawn BEHIND the ring by reset and by all thirteen
1123
+ controls that paint their own, so one declaration haloes every focusable
1124
+ surface in the framework. The pastel subtle tint is the softest thing in
1125
+ the palette that is still visible on both cream and cocoa. */
1126
+ --focus-shadow: 0 0 0 var(--space-1) var(--color-primary-subtle);
721
1127
  }
722
1128
 
723
1129
  /* ── Dark Mode ── */
@@ -843,11 +1249,38 @@
843
1249
  padding: 0;
844
1250
  }
845
1251
 
1252
+ /* Colour scheme — the one place `data-theme` is translated into the platform's
1253
+ own scheme signal. `light-dark()` in a theme reads `color-scheme`, not
1254
+ `data-theme`, so a one-block theme [1.1A-06] resolves nothing at all without
1255
+ these three rules; declaring them here (rather than in each theme) is what
1256
+ makes the two authoring forms interchangeable. Nothing else in the registry
1257
+ declares `color-scheme`, so this is purely additive.
1258
+
1259
+ Specificity does the mapping: `:root` is (0,0,1) and each attribute selector
1260
+ is (0,1,0), so `<html data-theme="dark">` takes the dark rule over the root
1261
+ default while a bare `<html>` — and `data-theme="light"` — keeps light. The
1262
+ same rules apply to a NESTED element carrying `data-theme`, which is how a
1263
+ dark island inside a light page has always worked here. */
1264
+ :root {
1265
+ color-scheme: light;
1266
+ }
1267
+
1268
+ [data-theme="dark"] {
1269
+ color-scheme: dark;
1270
+ }
1271
+
1272
+ /* `auto` hands the choice to the OS: `light dark` means "either, system first",
1273
+ which is exactly what the `@media (prefers-color-scheme: dark)` mirror block
1274
+ does for a theme authored in the three-block form. */
1275
+ [data-theme="auto"] {
1276
+ color-scheme: light dark;
1277
+ }
1278
+
846
1279
  html {
847
1280
  -webkit-text-size-adjust: 100%;
848
1281
  -moz-tab-size: 4;
849
1282
  tab-size: 4;
850
- font-family: var(--font-sans);
1283
+ font-family: var(--font-body);
851
1284
  font-size: var(--text-base);
852
1285
  line-height: var(--leading-normal);
853
1286
  color: var(--color-fg);
@@ -858,6 +1291,11 @@ html {
858
1291
 
859
1292
  body {
860
1293
  min-height: 100dvh;
1294
+ /* The page's material. `none` by default (the initial value), so this is a
1295
+ no-op until a theme points --texture-page at one of tokens/textures.css.
1296
+ `html` keeps the background COLOUR; the texture rides on `body`, which
1297
+ covers the viewport, so the two compose instead of overwriting. */
1298
+ background-image: var(--texture-page);
861
1299
  }
862
1300
 
863
1301
  img,
@@ -927,10 +1365,32 @@ table {
927
1365
  }
928
1366
  }
929
1367
 
930
- /* Focus visible — default ring */
1368
+ /* Text selection — the decoration axis reaching the one surface no component
1369
+ owns. Until 1.1 the highlight was whatever the OS drew, which is the one part
1370
+ of a themed page that never matched the theme. Both values are tokens
1371
+ (tokens/aliases.css § Decoration), so a theme states its selection once. */
1372
+ ::selection {
1373
+ background-color: var(--selection-bg);
1374
+ color: var(--selection-fg);
1375
+ }
1376
+
1377
+ /* Focus visible — the default ring, and the only place it is spelled out.
1378
+ Every value is a token (tokens/effects.css § Focus), so a theme states its
1379
+ focus once and every element that has not drawn its own ring follows. */
931
1380
  :focus-visible {
932
- outline: 2px solid var(--color-ring);
933
- outline-offset: 2px;
1381
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1382
+ outline-offset: var(--focus-ring-offset);
1383
+ }
1384
+
1385
+ /* The glow a theme may put behind the ring, at zero specificity. `box-shadow`
1386
+ is not a property focus owns: an element's resting shadow — a card's depth,
1387
+ an author's own — lives there too, and a (0,1,0) rule here replaced it with
1388
+ `none` (the default) on every keyboard focus. Under `:where()` ANY rule that
1389
+ sets a shadow outranks this one, so it lands only on an element nothing else
1390
+ shadows, and it never takes a shadow away. The controls that draw their own
1391
+ ring read `--focus-shadow` in their own `:focus-visible` rules. */
1392
+ :where(:focus-visible) {
1393
+ box-shadow: var(--focus-shadow);
934
1394
  }
935
1395
 
936
1396
  /* Hidden but accessible */
@@ -959,7 +1419,7 @@ table {
959
1419
  /* @ui:base prose — typography defaults for long-form content */
960
1420
 
961
1421
  [data-ui="prose"] {
962
- font-family: var(--font-sans);
1422
+ font-family: var(--font-body);
963
1423
  font-size: var(--text-base);
964
1424
  line-height: var(--leading-relaxed);
965
1425
  color: var(--color-fg);
@@ -967,29 +1427,45 @@ table {
967
1427
  }
968
1428
 
969
1429
  [data-ui="prose"] h1 {
1430
+ font-family: var(--font-heading);
970
1431
  font-size: var(--text-4xl);
971
- font-weight: var(--weight-bold);
972
- line-height: var(--leading-tight);
1432
+ font-weight: var(--heading-weight);
1433
+ letter-spacing: var(--heading-tracking);
1434
+ text-transform: var(--heading-transform);
1435
+ font-variant-caps: var(--heading-caps);
1436
+ line-height: var(--heading-leading);
973
1437
  margin-block: var(--space-8) var(--space-4);
974
1438
  }
975
1439
 
976
1440
  [data-ui="prose"] h2 {
1441
+ font-family: var(--font-heading);
977
1442
  font-size: var(--text-3xl);
978
1443
  font-weight: var(--weight-semibold);
979
- line-height: var(--leading-tight);
1444
+ letter-spacing: var(--heading-tracking);
1445
+ text-transform: var(--heading-transform);
1446
+ font-variant-caps: var(--heading-caps);
1447
+ line-height: var(--heading-leading);
980
1448
  margin-block: var(--space-8) var(--space-3);
981
1449
  }
982
1450
 
983
1451
  [data-ui="prose"] h3 {
1452
+ font-family: var(--font-heading);
984
1453
  font-size: var(--text-2xl);
985
1454
  font-weight: var(--weight-semibold);
1455
+ letter-spacing: var(--heading-tracking);
1456
+ text-transform: var(--heading-transform);
1457
+ font-variant-caps: var(--heading-caps);
986
1458
  line-height: var(--leading-snug);
987
1459
  margin-block: var(--space-6) var(--space-3);
988
1460
  }
989
1461
 
990
1462
  [data-ui="prose"] h4 {
1463
+ font-family: var(--font-heading);
991
1464
  font-size: var(--text-xl);
992
1465
  font-weight: var(--weight-semibold);
1466
+ letter-spacing: var(--heading-tracking);
1467
+ text-transform: var(--heading-transform);
1468
+ font-variant-caps: var(--heading-caps);
993
1469
  line-height: var(--leading-snug);
994
1470
  margin-block: var(--space-6) var(--space-2);
995
1471
  }
@@ -1000,8 +1476,8 @@ table {
1000
1476
 
1001
1477
  [data-ui="prose"] a {
1002
1478
  color: var(--color-primary);
1003
- text-decoration: underline;
1004
- text-underline-offset: 2px;
1479
+ text-decoration-line: var(--link-decoration);
1480
+ text-underline-offset: var(--link-underline-offset);
1005
1481
  }
1006
1482
 
1007
1483
  [data-ui="prose"] a:hover {
@@ -1038,7 +1514,7 @@ table {
1038
1514
  }
1039
1515
 
1040
1516
  [data-ui="prose"] blockquote {
1041
- border-inline-start: 3px solid var(--color-border-strong);
1517
+ border-inline-start: var(--border-width-lg) solid var(--color-border-strong);
1042
1518
  padding-inline-start: var(--space-4);
1043
1519
  color: var(--color-fg-muted);
1044
1520
  margin-block: var(--space-4);
@@ -1060,9 +1536,15 @@ table {
1060
1536
  margin-block: var(--space-1);
1061
1537
  }
1062
1538
 
1539
+ /* The bullet. `currentColor` by default — the initial value — so a list looks
1540
+ exactly as it did; a theme that wants accented markers sets --marker-color. */
1541
+ [data-ui="prose"] li::marker {
1542
+ color: var(--marker-color);
1543
+ }
1544
+
1063
1545
  [data-ui="prose"] hr {
1064
1546
  border: none;
1065
- border-block-start: 1px solid var(--color-border);
1547
+ border-block-start: var(--border-width) solid var(--color-border);
1066
1548
  margin-block: var(--space-8);
1067
1549
  }
1068
1550
 
@@ -1081,12 +1563,12 @@ table {
1081
1563
  font-weight: var(--weight-semibold);
1082
1564
  text-align: start;
1083
1565
  padding: var(--space-2) var(--space-3);
1084
- border-block-end: 2px solid var(--color-border-strong);
1566
+ border-block-end: var(--border-width-strong) solid var(--color-border-strong);
1085
1567
  }
1086
1568
 
1087
1569
  [data-ui="prose"] td {
1088
1570
  padding: var(--space-2) var(--space-3);
1089
- border-block-end: 1px solid var(--color-border);
1571
+ border-block-end: var(--border-width) solid var(--color-border);
1090
1572
  }
1091
1573
 
1092
1574
  /* First child no top margin, last child no bottom margin */
@@ -1271,7 +1753,7 @@ table {
1271
1753
 
1272
1754
  /* === primitives/avatar.css === */
1273
1755
  /* @ui:component avatar */
1274
- /* @ui:tokens color-bg-muted color-fg-muted radius-full font-sans text-xs text-sm weight-medium */
1756
+ /* @ui:tokens color-bg-muted color-fg-muted radius-full font-ui text-xs text-sm weight-medium */
1275
1757
 
1276
1758
  /* ── Base ── */
1277
1759
  [data-ui="avatar"] {
@@ -1301,7 +1783,7 @@ table {
1301
1783
  height: 100%;
1302
1784
  background: var(--color-bg-muted);
1303
1785
  color: var(--color-fg-muted);
1304
- font-family: var(--font-sans);
1786
+ font-family: var(--font-ui);
1305
1787
  font-size: var(--text-sm);
1306
1788
  font-weight: var(--weight-medium);
1307
1789
  text-transform: uppercase;
@@ -1326,7 +1808,7 @@ table {
1326
1808
 
1327
1809
  /* === primitives/badge.css === */
1328
1810
  /* @ui:component badge */
1329
- /* @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 */
1811
+ /* @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 */
1330
1812
 
1331
1813
  /* ── Base ── */
1332
1814
  [data-ui="badge"] {
@@ -1336,9 +1818,10 @@ table {
1336
1818
  gap: var(--space-1);
1337
1819
  padding: 0.125rem var(--space-2);
1338
1820
  border-radius: var(--badge-radius, var(--radius-full));
1821
+ corner-shape: var(--corner-shape);
1339
1822
  background: var(--color-bg-muted);
1340
1823
  color: var(--color-fg);
1341
- font-family: var(--badge-font, var(--font-sans));
1824
+ font-family: var(--badge-font, var(--font-ui));
1342
1825
  font-size: var(--text-xs);
1343
1826
  font-weight: var(--weight-medium);
1344
1827
  line-height: 1.5;
@@ -1384,11 +1867,11 @@ table {
1384
1867
 
1385
1868
  /* === primitives/breadcrumb.css === */
1386
1869
  /* @ui:component breadcrumb */
1387
- /* @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 */
1870
+ /* @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 */
1388
1871
 
1389
1872
  /* ── Root ── */
1390
1873
  [data-ui="breadcrumb"] {
1391
- font-family: var(--breadcrumb-font, var(--font-sans));
1874
+ font-family: var(--breadcrumb-font, var(--font-ui));
1392
1875
  font-size: var(--breadcrumb-size, var(--text-sm));
1393
1876
  color: var(--color-fg-muted);
1394
1877
  }
@@ -1414,12 +1897,13 @@ table {
1414
1897
 
1415
1898
  [data-ui="breadcrumb"] [data-part="item"]:hover {
1416
1899
  color: var(--color-primary-hover);
1417
- text-decoration: underline;
1900
+ text-decoration-line: var(--link-decoration);
1418
1901
  }
1419
1902
 
1420
1903
  [data-ui="breadcrumb"] [data-part="item"]:focus-visible {
1421
- outline: 2px solid var(--color-ring);
1422
- outline-offset: 2px;
1904
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1905
+ outline-offset: var(--focus-ring-offset);
1906
+ box-shadow: var(--focus-shadow);
1423
1907
  }
1424
1908
 
1425
1909
  /* ── Separator (presentational) ── */
@@ -1459,7 +1943,7 @@ table {
1459
1943
 
1460
1944
  /* === primitives/button.css === */
1461
1945
  /* @ui:component button */
1462
- /* @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 */
1946
+ /* @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 */
1463
1947
 
1464
1948
  /* ── Base ── */
1465
1949
  [data-ui="button"] {
@@ -1469,18 +1953,21 @@ table {
1469
1953
  gap: var(--space-2);
1470
1954
  height: var(--button-height-md, 40px);
1471
1955
  padding-inline: var(--space-4);
1472
- border: 1px solid var(--color-border);
1956
+ border: var(--border-width) solid var(--color-border);
1473
1957
  border-radius: var(--button-radius, var(--radius-md));
1958
+ corner-shape: var(--corner-shape);
1474
1959
  background: var(--color-bg);
1475
1960
  color: var(--color-fg);
1476
- font-family: var(--font-sans);
1961
+ font-family: var(--font-ui);
1477
1962
  font-size: var(--text-sm);
1478
1963
  font-weight: var(--weight-medium);
1964
+ text-transform: var(--button-text-transform);
1479
1965
  line-height: 1;
1480
1966
  cursor: pointer;
1481
1967
  transition: background var(--duration-fast) var(--ease-default),
1482
1968
  border-color var(--duration-fast) var(--ease-default),
1483
1969
  color var(--duration-fast) var(--ease-default),
1970
+ translate var(--duration-fast) var(--ease-default),
1484
1971
  box-shadow var(--duration-fast) var(--ease-default);
1485
1972
  user-select: none;
1486
1973
  white-space: nowrap;
@@ -1489,11 +1976,16 @@ table {
1489
1976
 
1490
1977
  [data-ui="button"]:hover {
1491
1978
  background: var(--color-bg-muted);
1979
+ /* The hover lift. `none` by default — the initial value of `translate` — so
1980
+ this rule computes what the button computed before the token existed; a
1981
+ theme with a springy personality sets `--motion-hover-lift: 0 -1px`. */
1982
+ translate: var(--motion-hover-lift);
1492
1983
  }
1493
1984
 
1494
1985
  [data-ui="button"]:focus-visible {
1495
- outline: 2px solid var(--color-ring);
1496
- outline-offset: 2px;
1986
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1987
+ outline-offset: var(--focus-ring-offset);
1988
+ box-shadow: var(--focus-shadow);
1497
1989
  }
1498
1990
 
1499
1991
  /* ── Variants ── */
@@ -1549,7 +2041,7 @@ table {
1549
2041
  padding: 0;
1550
2042
  }
1551
2043
  [data-ui="button"][data-variant="link"]:hover {
1552
- text-decoration: underline;
2044
+ text-decoration-line: var(--link-decoration);
1553
2045
  }
1554
2046
 
1555
2047
  /* ── Sizes ── */
@@ -1568,7 +2060,7 @@ table {
1568
2060
  /* ── States ── */
1569
2061
  [data-ui="button"]:disabled,
1570
2062
  [data-ui="button"][data-state="disabled"] {
1571
- opacity: 0.5;
2063
+ opacity: var(--disabled-opacity);
1572
2064
  cursor: not-allowed;
1573
2065
  pointer-events: none;
1574
2066
  }
@@ -1583,7 +2075,7 @@ table {
1583
2075
  position: absolute;
1584
2076
  width: 1em;
1585
2077
  height: 1em;
1586
- border: 2px solid currentColor;
2078
+ border: var(--border-width-strong) solid currentColor;
1587
2079
  border-inline-end-color: transparent;
1588
2080
  border-radius: var(--radius-full);
1589
2081
  animation: faqir-spin 0.6s linear infinite;
@@ -1630,7 +2122,7 @@ table {
1630
2122
 
1631
2123
  /* === primitives/callout.css === */
1632
2124
  /* @ui:component callout */
1633
- /* @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 */
2125
+ /* @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 */
1634
2126
 
1635
2127
  /* ── Base ── */
1636
2128
  [data-ui="callout"] {
@@ -1639,7 +2131,7 @@ table {
1639
2131
  padding: var(--callout-padding-y) var(--callout-padding-x);
1640
2132
  border-radius: var(--callout-radius);
1641
2133
  border-inline-start: var(--callout-border-left-width) solid;
1642
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
2134
+ font-family: var(--doc-font, var(--font-body));
1643
2135
  font-size: var(--callout-font-size);
1644
2136
  line-height: var(--doc-line-height, 1.5);
1645
2137
  }
@@ -1670,6 +2162,7 @@ table {
1670
2162
  /* ── Title ── */
1671
2163
  [data-ui="callout"] [data-part="title"] {
1672
2164
  display: block;
2165
+ font-family: var(--font-heading);
1673
2166
  font-weight: var(--weight-semibold);
1674
2167
  margin-bottom: var(--doc-label-gap, var(--space-1, 0.25rem));
1675
2168
  }
@@ -1696,8 +2189,9 @@ table {
1696
2189
  }
1697
2190
 
1698
2191
  [data-ui="callout"] [data-part="dismiss"]:focus-visible {
1699
- outline: 2px solid var(--color-ring, var(--color-info));
1700
- outline-offset: 2px;
2192
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2193
+ outline-offset: var(--focus-ring-offset);
2194
+ box-shadow: var(--focus-shadow);
1701
2195
  opacity: 1;
1702
2196
  }
1703
2197
 
@@ -1783,17 +2277,36 @@ table {
1783
2277
 
1784
2278
  /* === primitives/card.css === */
1785
2279
  /* @ui:component card */
1786
- /* @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 */
2280
+ /* @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 */
1787
2281
 
1788
2282
  /* ── Base ── */
1789
2283
  [data-ui="card"] {
1790
2284
  display: flex;
1791
2285
  flex-direction: column;
1792
- border: 1px solid var(--card-border, var(--color-surface-1-border));
2286
+ border: var(--card-border-width) solid var(--card-border, var(--color-surface-1-border));
1793
2287
  border-radius: var(--card-radius, var(--radius-lg));
1794
- background: var(--card-bg, var(--color-surface-1));
2288
+ corner-shape: var(--corner-shape);
2289
+ /* One shorthand, two layers: the material on top, the fill beneath. The fill
2290
+ is the final layer, so `--card-bg` may be a colour OR a gradient — what 1.0
2291
+ projects set it to — and the texture (`none` by default) never clobbers it. */
2292
+ background: var(--texture-surface), var(--card-bg, var(--color-surface-1));
1795
2293
  box-shadow: var(--card-shadow, var(--shadow-sm));
1796
2294
  overflow: hidden;
2295
+ transition: translate var(--duration-fast) var(--ease-default);
2296
+ }
2297
+
2298
+ /* The hover lift, the same axis `button` reads. `none` by default (the initial
2299
+ value of `translate`), so a card sits exactly where it always sat until a
2300
+ theme says surfaces rise under the pointer. */
2301
+ [data-ui="card"]:hover {
2302
+ translate: var(--motion-hover-lift);
2303
+ }
2304
+
2305
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
2306
+ [data-ui="card"] {
2307
+ -webkit-backdrop-filter: var(--surface-backdrop);
2308
+ backdrop-filter: var(--surface-backdrop);
2309
+ }
1797
2310
  }
1798
2311
 
1799
2312
  /* ── Variants ── */
@@ -1802,7 +2315,7 @@ table {
1802
2315
  }
1803
2316
 
1804
2317
  [data-ui="card"][data-variant="filled"] {
1805
- background: var(--color-surface-2);
2318
+ background: var(--texture-surface), var(--color-surface-2);
1806
2319
  border-color: var(--color-surface-2-border);
1807
2320
  box-shadow: none;
1808
2321
  }
@@ -1817,7 +2330,7 @@ table {
1817
2330
  }
1818
2331
 
1819
2332
  [data-ui="card"] > [data-part="header"] > [data-part="title"] {
1820
- font-family: var(--font-sans);
2333
+ font-family: var(--font-heading);
1821
2334
  font-size: var(--text-lg);
1822
2335
  font-weight: var(--weight-semibold);
1823
2336
  line-height: var(--leading-tight);
@@ -1858,9 +2371,19 @@ table {
1858
2371
  padding-top: 0;
1859
2372
  }
1860
2373
 
2374
+ /* ── Motion ── */
2375
+ /* The hover lift is the only thing a card animates, and it is `none` until a
2376
+ theme states one — but the house rule is that a stylesheet which transitions
2377
+ carries its own opt-out, so a reader never has to check the token first. */
2378
+ @media (prefers-reduced-motion: reduce) {
2379
+ [data-ui="card"] {
2380
+ transition: none;
2381
+ }
2382
+ }
2383
+
1861
2384
  /* === primitives/checkbox.css === */
1862
2385
  /* @ui:component checkbox */
1863
- /* @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 */
2386
+ /* @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 */
1864
2387
 
1865
2388
  /* -- Label wrapper -- */
1866
2389
  [data-ui="checkbox-label"] {
@@ -1872,7 +2395,7 @@ table {
1872
2395
 
1873
2396
  [data-ui="checkbox-label"]:has([data-ui="checkbox"]:disabled) {
1874
2397
  cursor: not-allowed;
1875
- opacity: 0.5;
2398
+ opacity: var(--disabled-opacity);
1876
2399
  }
1877
2400
 
1878
2401
  /* -- Base -- */
@@ -1884,8 +2407,8 @@ table {
1884
2407
  width: var(--checkbox-size, 18px);
1885
2408
  height: var(--checkbox-size, 18px);
1886
2409
  flex-shrink: 0;
1887
- border: 1px solid var(--color-border);
1888
- border-radius: var(--checkbox-radius, var(--radius-sm));
2410
+ border: var(--border-width) solid var(--color-border);
2411
+ border-radius: var(--checkbox-radius);
1889
2412
  background: var(--color-bg);
1890
2413
  cursor: pointer;
1891
2414
  transition: background var(--duration-fast) var(--ease-default),
@@ -1898,8 +2421,9 @@ table {
1898
2421
  }
1899
2422
 
1900
2423
  [data-ui="checkbox"]:focus-visible {
1901
- outline: 2px solid var(--color-ring);
1902
- outline-offset: 2px;
2424
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2425
+ outline-offset: var(--focus-ring-offset);
2426
+ box-shadow: var(--focus-shadow);
1903
2427
  }
1904
2428
 
1905
2429
  /* -- Checked -- */
@@ -1990,7 +2514,7 @@ table {
1990
2514
  The mask has to opt out of the substitution to stay readable. [W3-3] */
1991
2515
  @media (forced-colors: active) {
1992
2516
  [data-ui="checkbox"] {
1993
- border: 1px solid ButtonText;
2517
+ border: var(--border-width) solid ButtonText;
1994
2518
  }
1995
2519
 
1996
2520
  [data-ui="checkbox"]:checked,
@@ -2014,7 +2538,7 @@ table {
2014
2538
 
2015
2539
  /* === primitives/chip.css === */
2016
2540
  /* @ui:component chip */
2017
- /* @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 */
2541
+ /* @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 */
2018
2542
 
2019
2543
  /* ── Base ── */
2020
2544
  [data-ui="chip"] {
@@ -2022,11 +2546,11 @@ table {
2022
2546
  align-items: center;
2023
2547
  gap: var(--space-1);
2024
2548
  padding: var(--space-1) var(--space-2);
2025
- border: 1px solid transparent;
2549
+ border: var(--border-width) solid transparent;
2026
2550
  border-radius: var(--chip-radius, var(--radius-full));
2027
2551
  background: var(--color-bg-muted);
2028
2552
  color: var(--color-fg);
2029
- font-family: var(--chip-font, var(--font-sans));
2553
+ font-family: var(--chip-font, var(--font-ui));
2030
2554
  font-size: var(--text-sm);
2031
2555
  font-weight: var(--weight-medium);
2032
2556
  line-height: 1.2;
@@ -2062,8 +2586,11 @@ table {
2062
2586
  }
2063
2587
 
2064
2588
  [data-ui="chip"] [data-part="dismiss"]:focus-visible {
2065
- outline: 2px solid var(--color-ring);
2066
- outline-offset: 1px;
2589
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2590
+ /* Half the default gap — the dismiss target is small, and the full ring
2591
+ would collide with the chip's own edge. */
2592
+ outline-offset: calc(var(--focus-ring-offset) / 2);
2593
+ box-shadow: var(--focus-shadow);
2067
2594
  }
2068
2595
 
2069
2596
  /* ── Variants ── */
@@ -2286,12 +2813,12 @@ table {
2286
2813
 
2287
2814
  /* === primitives/collapsible.css === */
2288
2815
  /* @ui:component collapsible */
2289
- /* @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 */
2816
+ /* @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 */
2290
2817
 
2291
2818
  /* ── Root — native <details>, so it opens/closes with zero JavaScript ── */
2292
2819
  [data-ui="collapsible"] {
2293
2820
  border-radius: var(--collapsible-radius, var(--radius-md));
2294
- font-family: var(--collapsible-font, var(--font-sans));
2821
+ font-family: var(--collapsible-font, var(--font-ui));
2295
2822
  color: var(--color-fg);
2296
2823
  }
2297
2824
 
@@ -2321,8 +2848,9 @@ table {
2321
2848
  }
2322
2849
 
2323
2850
  [data-ui="collapsible"] [data-part="trigger"]:focus-visible {
2324
- outline: 2px solid var(--color-ring);
2325
- outline-offset: 2px;
2851
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2852
+ outline-offset: var(--focus-ring-offset);
2853
+ box-shadow: var(--focus-shadow);
2326
2854
  }
2327
2855
 
2328
2856
  /* Chevron indicator — rotates when open, CSS-only */
@@ -2331,8 +2859,8 @@ table {
2331
2859
  flex: none;
2332
2860
  width: 0.5em;
2333
2861
  height: 0.5em;
2334
- border-inline-end: 2px solid var(--color-fg-muted);
2335
- border-block-end: 2px solid var(--color-fg-muted);
2862
+ border-inline-end: var(--border-width-strong) solid var(--color-fg-muted);
2863
+ border-block-end: var(--border-width-strong) solid var(--color-fg-muted);
2336
2864
  transform: rotate(45deg);
2337
2865
  transition: transform var(--duration-normal) var(--ease-default);
2338
2866
  }
@@ -2351,7 +2879,7 @@ table {
2351
2879
 
2352
2880
  /* ── Bordered variant ── */
2353
2881
  [data-ui="collapsible"][data-variant="bordered"] {
2354
- border: 1px solid var(--color-border);
2882
+ border: var(--border-width) solid var(--color-border);
2355
2883
  }
2356
2884
 
2357
2885
  /* ── Open/close animation via ::details-content, where supported ── */
@@ -2484,13 +3012,13 @@ table {
2484
3012
 
2485
3013
  /* === primitives/description-list.css === */
2486
3014
  /* @ui:component description-list */
2487
- /* @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 */
3015
+ /* @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 */
2488
3016
 
2489
3017
  /* ── Base ── */
2490
3018
  [data-ui="description-list"] {
2491
3019
  margin: 0;
2492
3020
  padding: 0;
2493
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3021
+ font-family: var(--doc-font, var(--font-body));
2494
3022
  }
2495
3023
 
2496
3024
  /* ── Term ── */
@@ -2546,7 +3074,7 @@ table {
2546
3074
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"],
2547
3075
  [data-ui="description-list"][data-divided]:not([data-variant]) [data-part="details"] {
2548
3076
  padding-bottom: var(--space-4);
2549
- border-bottom: 1px solid var(--color-border);
3077
+ border-bottom: var(--border-width) solid var(--color-border);
2550
3078
  }
2551
3079
 
2552
3080
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"]:last-child,
@@ -2558,7 +3086,7 @@ table {
2558
3086
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="term"],
2559
3087
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="details"] {
2560
3088
  padding-bottom: var(--space-3);
2561
- border-bottom: 1px solid var(--color-border);
3089
+ border-bottom: var(--border-width) solid var(--color-border);
2562
3090
  }
2563
3091
 
2564
3092
  /* ── Size: Small ── */
@@ -2596,7 +3124,7 @@ table {
2596
3124
 
2597
3125
  /* === primitives/empty-state.css === */
2598
3126
  /* @ui:component empty-state */
2599
- /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl */
3127
+ /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl font-heading */
2600
3128
 
2601
3129
  /* ── Base ── */
2602
3130
  [data-ui="empty-state"] {
@@ -2617,6 +3145,7 @@ table {
2617
3145
 
2618
3146
  /* ── Title ── */
2619
3147
  [data-ui="empty-state"] [data-part="title"] {
3148
+ font-family: var(--font-heading);
2620
3149
  font-size: var(--text-lg);
2621
3150
  font-weight: var(--weight-medium);
2622
3151
  color: var(--color-fg);
@@ -2664,7 +3193,7 @@ table {
2664
3193
 
2665
3194
  /* === primitives/field-group.css === */
2666
3195
  /* @ui:component field-group */
2667
- /* @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 */
3196
+ /* @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 */
2668
3197
 
2669
3198
  /* ── Base / spacing ownership ──
2670
3199
  A field-group owns only its tight, density-aware intra-field step: label →
@@ -2676,7 +3205,7 @@ table {
2676
3205
  display: flex;
2677
3206
  flex-direction: column;
2678
3207
  gap: var(--space-2);
2679
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3208
+ font-family: var(--doc-font, var(--font-body));
2680
3209
  }
2681
3210
 
2682
3211
  /* ── Label ── */
@@ -2746,7 +3275,7 @@ table {
2746
3275
  [data-ui="field-group"][data-state="invalid"] [data-ui="textarea"],
2747
3276
  [data-ui="field-group"][data-state="invalid"] [data-ui="select"] {
2748
3277
  border-color: var(--field-error-color);
2749
- box-shadow: 0 0 0 1px var(--field-error-color);
3278
+ box-shadow: 0 0 0 var(--border-width) var(--field-error-color);
2750
3279
  }
2751
3280
 
2752
3281
  /* ── State: Validating ──
@@ -2756,7 +3285,7 @@ table {
2756
3285
  [data-ui="field-group"][data-state="validating"] [data-ui="textarea"],
2757
3286
  [data-ui="field-group"][data-state="validating"] [data-ui="select"] {
2758
3287
  border-color: var(--field-validating-color);
2759
- box-shadow: 0 0 0 1px var(--field-validating-color);
3288
+ box-shadow: 0 0 0 var(--border-width) var(--field-validating-color);
2760
3289
  }
2761
3290
 
2762
3291
  /* ── State: Disabled ──
@@ -2775,8 +3304,8 @@ table {
2775
3304
  [data-ui="field-group"][data-state="valid"] [data-ui="input"],
2776
3305
  [data-ui="field-group"][data-state="valid"] [data-ui="textarea"],
2777
3306
  [data-ui="field-group"][data-state="valid"] [data-ui="select"] {
2778
- border-color: var(--color-success, oklch(0.62 0.19 145));
2779
- box-shadow: 0 0 0 1px var(--color-success, oklch(0.62 0.19 145));
3307
+ border-color: var(--color-success);
3308
+ box-shadow: 0 0 0 var(--border-width) var(--color-success);
2780
3309
  }
2781
3310
 
2782
3311
  /* ── Variant: Horizontal ── */
@@ -3081,7 +3610,7 @@ table {
3081
3610
 
3082
3611
  /* === primitives/image.css === */
3083
3612
  /* @ui:component image */
3084
- /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-sans */
3613
+ /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-body */
3085
3614
 
3086
3615
  /* ── Base ── */
3087
3616
  [data-ui="image"] {
@@ -3105,7 +3634,7 @@ table {
3105
3634
  [data-ui="image"] [data-part="caption"] {
3106
3635
  display: block;
3107
3636
  margin-top: var(--space-2);
3108
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3637
+ font-family: var(--doc-font, var(--font-body));
3109
3638
  font-size: var(--image-caption-size);
3110
3639
  color: var(--image-caption-color);
3111
3640
  line-height: 1.4;
@@ -3202,7 +3731,7 @@ table {
3202
3731
 
3203
3732
  /* === primitives/input.css === */
3204
3733
  /* @ui:component input */
3205
- /* @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 */
3734
+ /* @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 */
3206
3735
 
3207
3736
  /* ── Base ── */
3208
3737
  [data-ui="input"] {
@@ -3210,11 +3739,18 @@ table {
3210
3739
  width: 100%;
3211
3740
  height: var(--input-height, 40px);
3212
3741
  padding-inline: var(--space-3);
3213
- border: 1px solid var(--color-border);
3742
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
3743
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
3744
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
3745
+ is drawn. Identical to the shorthand at every other value of the token. */
3746
+ border-style: solid;
3747
+ border-color: var(--color-border);
3748
+ border-width: var(--input-border-width);
3214
3749
  border-radius: var(--input-radius, var(--radius-md));
3215
- background: var(--input-bg, var(--color-bg));
3750
+ corner-shape: var(--corner-shape);
3751
+ background: var(--input-fill);
3216
3752
  color: var(--color-fg);
3217
- font-family: var(--input-font, var(--font-sans));
3753
+ font-family: var(--input-font, var(--font-ui));
3218
3754
  font-size: var(--text-sm);
3219
3755
  line-height: 1;
3220
3756
  transition: border-color var(--duration-fast) var(--ease-default),
@@ -3230,8 +3766,11 @@ table {
3230
3766
  }
3231
3767
 
3232
3768
  [data-ui="input"]:focus {
3233
- outline: 2px solid var(--color-ring);
3234
- outline-offset: -1px;
3769
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
3770
+ /* The ring replaces the border rather than sitting outside it: inset by
3771
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
3772
+ outline-offset: calc(-1 * var(--input-border-width));
3773
+ box-shadow: var(--focus-shadow);
3235
3774
  border-color: transparent;
3236
3775
  }
3237
3776
 
@@ -3259,7 +3798,7 @@ table {
3259
3798
  }
3260
3799
 
3261
3800
  [data-ui="input"]:disabled {
3262
- opacity: 0.5;
3801
+ opacity: var(--disabled-opacity);
3263
3802
  cursor: not-allowed;
3264
3803
  }
3265
3804
 
@@ -3322,7 +3861,7 @@ table {
3322
3861
 
3323
3862
  /* === primitives/kbd.css === */
3324
3863
  /* @ui:component kbd */
3325
- /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs */
3864
+ /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs border-width border-width-strong */
3326
3865
 
3327
3866
  /* ── Base ── */
3328
3867
  [data-ui="kbd"] {
@@ -3332,8 +3871,8 @@ table {
3332
3871
  height: 20px;
3333
3872
  min-width: 20px;
3334
3873
  padding-inline: var(--space-1h);
3335
- border: 1px solid var(--color-border);
3336
- border-bottom-width: 2px;
3874
+ border: var(--border-width) solid var(--color-border);
3875
+ border-bottom-width: var(--border-width-strong);
3337
3876
  border-radius: var(--radius-sm);
3338
3877
  background: var(--color-bg-subtle);
3339
3878
  color: var(--color-fg);
@@ -3346,7 +3885,7 @@ table {
3346
3885
 
3347
3886
  /* === primitives/key-value.css === */
3348
3887
  /* @ui:component key-value */
3349
- /* @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 */
3888
+ /* @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 */
3350
3889
 
3351
3890
  /* ── Base ── */
3352
3891
  [data-ui="key-value"] {
@@ -3355,7 +3894,7 @@ table {
3355
3894
  gap: var(--kv-pair-gap);
3356
3895
  margin: 0;
3357
3896
  padding: 0;
3358
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3897
+ font-family: var(--doc-font, var(--font-body));
3359
3898
  }
3360
3899
 
3361
3900
  /* ── Label ── */
@@ -3485,12 +4024,12 @@ table {
3485
4024
 
3486
4025
  /* === primitives/label.css === */
3487
4026
  /* @ui:component label */
3488
- /* @ui:tokens color-fg color-fg-muted color-destructive font-sans text-xs text-sm text-base weight-medium */
4027
+ /* @ui:tokens color-fg color-fg-muted color-destructive font-ui text-xs text-sm text-base weight-medium disabled-opacity */
3489
4028
 
3490
4029
  /* ── Base ── */
3491
4030
  [data-ui="label"] {
3492
4031
  display: block;
3493
- font-family: var(--font-sans);
4032
+ font-family: var(--font-ui);
3494
4033
  font-size: var(--text-sm);
3495
4034
  font-weight: var(--weight-medium);
3496
4035
  color: var(--color-fg);
@@ -3523,21 +4062,21 @@ table {
3523
4062
 
3524
4063
  /* ── States ── */
3525
4064
  [data-ui="label"][data-state="disabled"] {
3526
- opacity: 0.5;
4065
+ opacity: var(--disabled-opacity);
3527
4066
  cursor: not-allowed;
3528
4067
  }
3529
4068
 
3530
4069
  /* === primitives/link.css === */
3531
4070
  /* @ui:component link */
3532
- /* @ui:tokens color-primary color-primary-hover color-primary-active color-fg color-fg-muted color-ring radius-sm space-1 */
4071
+ /* @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 */
3533
4072
 
3534
4073
  /* ── Base ── */
3535
4074
  [data-ui="link"] {
3536
4075
  color: var(--color-primary);
3537
4076
  font-family: inherit;
3538
- text-decoration: underline;
3539
- text-decoration-thickness: 1px;
3540
- text-underline-offset: 0.2em;
4077
+ text-decoration-line: var(--link-decoration);
4078
+ text-decoration-thickness: var(--link-thickness);
4079
+ text-underline-offset: var(--link-underline-offset);
3541
4080
  border-radius: var(--radius-sm);
3542
4081
  cursor: pointer;
3543
4082
  }
@@ -3551,8 +4090,9 @@ table {
3551
4090
  }
3552
4091
 
3553
4092
  [data-ui="link"]:focus-visible {
3554
- outline: 2px solid var(--color-ring);
3555
- outline-offset: 2px;
4093
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4094
+ outline-offset: var(--focus-ring-offset);
4095
+ box-shadow: var(--focus-shadow);
3556
4096
  }
3557
4097
 
3558
4098
  /* ── Variants ── */
@@ -3576,7 +4116,7 @@ table {
3576
4116
 
3577
4117
  /* === primitives/nav.css === */
3578
4118
  /* @ui:component nav */
3579
- /* @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 */
4119
+ /* @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 */
3580
4120
 
3581
4121
  /* ── Base ── */
3582
4122
  [data-ui="nav"] {
@@ -3626,14 +4166,14 @@ table {
3626
4166
 
3627
4167
  /* ── Underline variant ── */
3628
4168
  [data-ui="nav"][data-variant="underline"] {
3629
- border-bottom: 1px solid var(--color-border);
4169
+ border-bottom: var(--border-width) solid var(--color-border);
3630
4170
  gap: 0;
3631
4171
  }
3632
4172
 
3633
4173
  [data-ui="nav"][data-variant="underline"] [data-part="link"] {
3634
4174
  border-radius: 0;
3635
4175
  padding: var(--space-2) var(--space-4);
3636
- border-bottom: 2px solid transparent;
4176
+ border-bottom: var(--border-width-strong) solid transparent;
3637
4177
  margin-bottom: -1px;
3638
4178
  }
3639
4179
 
@@ -3689,7 +4229,7 @@ table {
3689
4229
 
3690
4230
  /* === primitives/page-break.css === */
3691
4231
  /* @ui:component page-break */
3692
- /* @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 */
4232
+ /* @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 */
3693
4233
 
3694
4234
  /* ── Base (Screen) ── */
3695
4235
  [data-ui="page-break"] {
@@ -3704,12 +4244,12 @@ table {
3704
4244
  [data-ui="page-break"]::after {
3705
4245
  content: "";
3706
4246
  flex: 1;
3707
- border-top: 1px var(--page-break-screen-style) var(--page-break-screen-color);
4247
+ border-top: var(--border-width) var(--page-break-screen-style) var(--page-break-screen-color);
3708
4248
  }
3709
4249
 
3710
4250
  /* ── Label (Screen) ── */
3711
4251
  [data-ui="page-break"] {
3712
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4252
+ font-family: var(--doc-font, var(--font-body));
3713
4253
  font-size: var(--page-break-screen-label-size);
3714
4254
  color: var(--page-break-screen-label-color);
3715
4255
  letter-spacing: 0.05em;
@@ -3751,7 +4291,7 @@ table {
3751
4291
 
3752
4292
  /* === primitives/progress.css === */
3753
4293
  /* @ui:component progress */
3754
- /* @ui:tokens color-primary color-bg-muted color-success color-warning color-destructive radius-full radius-md space-1 duration-normal ease-default */
4294
+ /* @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 */
3755
4295
 
3756
4296
  /* ── Base ── */
3757
4297
  [data-ui="progress"] {
@@ -3826,7 +4366,7 @@ table {
3826
4366
  substitution and paints `Highlight`; the track keeps a visible boundary. [W3-3] */
3827
4367
  @media (forced-colors: active) {
3828
4368
  [data-ui="progress"] [data-part="track"] {
3829
- border: 1px solid ButtonText;
4369
+ border: var(--border-width) solid ButtonText;
3830
4370
  }
3831
4371
 
3832
4372
  [data-ui="progress"] [data-part="fill"],
@@ -3840,7 +4380,7 @@ table {
3840
4380
 
3841
4381
  /* === primitives/radio.css === */
3842
4382
  /* @ui:component radio */
3843
- /* @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 */
4383
+ /* @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 */
3844
4384
 
3845
4385
  /* -- Radio group -- */
3846
4386
  [data-ui="radio-group"] {
@@ -3862,7 +4402,7 @@ table {
3862
4402
 
3863
4403
  [data-ui="radio-label"]:has([data-ui="radio"]:disabled) {
3864
4404
  cursor: not-allowed;
3865
- opacity: 0.5;
4405
+ opacity: var(--disabled-opacity);
3866
4406
  }
3867
4407
 
3868
4408
  /* -- Base -- */
@@ -3874,7 +4414,7 @@ table {
3874
4414
  width: var(--radio-size, 18px);
3875
4415
  height: var(--radio-size, 18px);
3876
4416
  flex-shrink: 0;
3877
- border: 1px solid var(--color-border);
4417
+ border: var(--border-width) solid var(--color-border);
3878
4418
  border-radius: var(--radius-full);
3879
4419
  background: var(--color-bg);
3880
4420
  cursor: pointer;
@@ -3888,8 +4428,9 @@ table {
3888
4428
  }
3889
4429
 
3890
4430
  [data-ui="radio"]:focus-visible {
3891
- outline: 2px solid var(--color-ring);
3892
- outline-offset: 2px;
4431
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4432
+ outline-offset: var(--focus-ring-offset);
4433
+ box-shadow: var(--focus-shadow);
3893
4434
  }
3894
4435
 
3895
4436
  /* -- Checked -- */
@@ -3942,7 +4483,7 @@ table {
3942
4483
  inside a `--color-primary` circle, and the OS collapses both to one colour. [W3-3] */
3943
4484
  @media (forced-colors: active) {
3944
4485
  [data-ui="radio"] {
3945
- border: 1px solid ButtonText;
4486
+ border: var(--border-width) solid ButtonText;
3946
4487
  }
3947
4488
 
3948
4489
  [data-ui="radio"]:checked {
@@ -3962,7 +4503,7 @@ table {
3962
4503
 
3963
4504
  /* === primitives/select.css === */
3964
4505
  /* @ui:component select */
3965
- /* @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 */
4506
+ /* @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 */
3966
4507
 
3967
4508
  /* -- Base -- */
3968
4509
  [data-ui="select"] {
@@ -3971,11 +4512,17 @@ table {
3971
4512
  height: var(--select-height, 40px);
3972
4513
  padding-inline: var(--space-3);
3973
4514
  padding-inline-end: var(--space-8, 2rem);
3974
- border: 1px solid var(--color-border);
4515
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
4516
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
4517
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
4518
+ is drawn. Identical to the shorthand at every other value of the token. */
4519
+ border-style: solid;
4520
+ border-color: var(--color-border);
4521
+ border-width: var(--input-border-width);
3975
4522
  border-radius: var(--select-radius, var(--radius-md));
3976
- background: var(--select-bg, var(--color-bg));
4523
+ background: var(--select-bg, var(--input-fill));
3977
4524
  color: var(--color-fg);
3978
- font-family: var(--select-font, var(--font-sans));
4525
+ font-family: var(--select-font, var(--font-ui));
3979
4526
  font-size: var(--text-sm);
3980
4527
  line-height: 1;
3981
4528
  cursor: pointer;
@@ -4005,8 +4552,11 @@ table {
4005
4552
  }
4006
4553
 
4007
4554
  [data-ui="select"]:focus {
4008
- outline: 2px solid var(--color-ring);
4009
- outline-offset: -1px;
4555
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4556
+ /* The ring replaces the border rather than sitting outside it: inset by
4557
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
4558
+ outline-offset: calc(-1 * var(--input-border-width));
4559
+ box-shadow: var(--focus-shadow);
4010
4560
  border-color: transparent;
4011
4561
  }
4012
4562
 
@@ -4039,7 +4589,7 @@ table {
4039
4589
  }
4040
4590
 
4041
4591
  [data-ui="select"]:disabled {
4042
- opacity: 0.5;
4592
+ opacity: var(--disabled-opacity);
4043
4593
  cursor: not-allowed;
4044
4594
  }
4045
4595
 
@@ -4052,12 +4602,12 @@ table {
4052
4602
 
4053
4603
  /* === primitives/separator.css === */
4054
4604
  /* @ui:component separator */
4055
- /* @ui:tokens color-border space-4 text-xs color-fg-muted font-sans */
4605
+ /* @ui:tokens color-border space-4 text-xs color-fg-muted font-ui border-width-strong divider-width divider-style */
4056
4606
 
4057
4607
  /* ── Base (horizontal) ── */
4058
4608
  [data-ui="separator"] {
4059
4609
  border: none;
4060
- border-top: 1px solid var(--color-border);
4610
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
4061
4611
  margin: 0;
4062
4612
  width: 100%;
4063
4613
  }
@@ -4065,7 +4615,7 @@ table {
4065
4615
  /* ── Vertical ── */
4066
4616
  [data-ui="separator"][data-variant="vertical"] {
4067
4617
  border-top: none;
4068
- border-inline-start: 1px solid var(--color-border);
4618
+ border-inline-start: var(--divider-width) var(--divider-style) var(--color-border);
4069
4619
  width: auto;
4070
4620
  height: 100%;
4071
4621
  align-self: stretch;
@@ -4083,11 +4633,11 @@ div[data-ui="separator"]::before,
4083
4633
  div[data-ui="separator"]::after {
4084
4634
  content: "";
4085
4635
  flex: 1;
4086
- border-top: 1px solid var(--color-border);
4636
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
4087
4637
  }
4088
4638
 
4089
4639
  [data-ui="separator"] [data-part="label"] {
4090
- font-family: var(--font-sans);
4640
+ font-family: var(--font-ui);
4091
4641
  font-size: var(--text-xs);
4092
4642
  color: var(--color-fg-muted);
4093
4643
  white-space: nowrap;
@@ -4125,17 +4675,17 @@ div[data-ui="separator"][data-style="dotted"]::after {
4125
4675
 
4126
4676
  /* ── Style: Thick ── */
4127
4677
  [data-ui="separator"][data-style="thick"] {
4128
- border-top-width: 2px;
4678
+ border-top-width: var(--border-width-strong);
4129
4679
  }
4130
4680
 
4131
4681
  [data-ui="separator"][data-style="thick"][data-variant="vertical"] {
4132
4682
  border-top-width: 0;
4133
- border-inline-start-width: 2px;
4683
+ border-inline-start-width: var(--border-width-strong);
4134
4684
  }
4135
4685
 
4136
4686
  div[data-ui="separator"][data-style="thick"]::before,
4137
4687
  div[data-ui="separator"][data-style="thick"]::after {
4138
- border-top-width: 2px;
4688
+ border-top-width: var(--border-width-strong);
4139
4689
  }
4140
4690
 
4141
4691
  /* ── Vertical Sizes ── */
@@ -4153,20 +4703,20 @@ div[data-ui="separator"][data-style="thick"]::after {
4153
4703
 
4154
4704
  /* === primitives/signature.css === */
4155
4705
  /* @ui:component signature */
4156
- /* @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 */
4706
+ /* @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 */
4157
4707
 
4158
4708
  /* ── Base ── */
4159
4709
  [data-ui="signature"] {
4160
4710
  display: flex;
4161
4711
  flex-direction: column;
4162
4712
  gap: var(--space-2);
4163
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4713
+ font-family: var(--doc-font, var(--font-body));
4164
4714
  margin-top: var(--doc-signature-gap);
4165
4715
  }
4166
4716
 
4167
4717
  /* ── Line ── */
4168
4718
  [data-ui="signature"] [data-part="line"] {
4169
- border-top: 1px solid var(--doc-signature-line-color);
4719
+ border-top: var(--border-width) solid var(--doc-signature-line-color);
4170
4720
  min-height: 1px;
4171
4721
  }
4172
4722
 
@@ -4269,14 +4819,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4269
4819
 
4270
4820
  /* === primitives/spinner.css === */
4271
4821
  /* @ui:component spinner */
4272
- /* @ui:tokens color-border color-primary radius-full duration-normal ease-default */
4822
+ /* @ui:tokens color-border color-primary radius-full duration-normal ease-default border-width-strong border-width-lg */
4273
4823
 
4274
4824
  /* ── Base ── */
4275
4825
  [data-ui="spinner"] {
4276
4826
  display: inline-block;
4277
4827
  width: 24px;
4278
4828
  height: 24px;
4279
- border: 2px solid var(--color-border);
4829
+ border: var(--border-width-strong) solid var(--color-border);
4280
4830
  border-top-color: var(--color-primary);
4281
4831
  border-radius: var(--radius-full);
4282
4832
  animation: faqir-spin 0.75s linear infinite;
@@ -4292,13 +4842,13 @@ div[data-ui="separator"][data-style="thick"]::after {
4292
4842
  [data-ui="spinner"][data-size="lg"] {
4293
4843
  width: 32px;
4294
4844
  height: 32px;
4295
- border-width: 3px;
4845
+ border-width: var(--border-width-lg);
4296
4846
  }
4297
4847
 
4298
4848
  [data-ui="spinner"][data-size="xl"] {
4299
4849
  width: 48px;
4300
4850
  height: 48px;
4301
- border-width: 3px;
4851
+ border-width: var(--border-width-lg);
4302
4852
  }
4303
4853
 
4304
4854
  /* ── Motion ── */
@@ -4880,14 +5430,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4880
5430
 
4881
5431
  /* === primitives/stat.css === */
4882
5432
  /* @ui:component stat */
4883
- /* @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 */
5433
+ /* @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 */
4884
5434
 
4885
5435
  /* ── Base ── */
4886
5436
  [data-ui="stat"] {
4887
5437
  display: flex;
4888
5438
  flex-direction: column;
4889
5439
  gap: var(--space-1);
4890
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
5440
+ font-family: var(--doc-font, var(--font-body));
4891
5441
  }
4892
5442
 
4893
5443
  /* ── Label ── */
@@ -4901,6 +5451,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4901
5451
 
4902
5452
  /* ── Value ── */
4903
5453
  [data-ui="stat"] [data-part="value"] {
5454
+ font-family: var(--font-heading);
4904
5455
  font-size: var(--stat-value-size);
4905
5456
  font-weight: var(--stat-value-weight);
4906
5457
  color: var(--color-fg);
@@ -4959,10 +5510,10 @@ div[data-ui="separator"][data-style="thick"]::after {
4959
5510
  /* ── Variant: Card ── */
4960
5511
  [data-ui="stat"][data-variant="card"] {
4961
5512
  padding: var(--space-4);
4962
- border: 1px solid var(--color-border);
5513
+ border: var(--border-width) solid var(--color-border);
4963
5514
  border-radius: var(--radius-md, 0.375rem);
4964
5515
  background: var(--color-bg);
4965
- box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.05));
5516
+ box-shadow: var(--shadow-sm);
4966
5517
  }
4967
5518
 
4968
5519
  /* ── Value + Change Inline ── */
@@ -4974,7 +5525,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4974
5525
  @media print {
4975
5526
  [data-ui="stat"][data-variant="card"] {
4976
5527
  box-shadow: none;
4977
- border: 1px solid var(--doc-print-border-color, var(--color-border, #ccc));
5528
+ border: var(--border-width) solid var(--doc-print-border-color, var(--color-border, #ccc));
4978
5529
  }
4979
5530
 
4980
5531
  [data-ui="stat"] {
@@ -4984,7 +5535,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4984
5535
 
4985
5536
  /* === primitives/stepper.css === */
4986
5537
  /* @ui:component stepper */
4987
- /* @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 */
5538
+ /* @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 */
4988
5539
 
4989
5540
  /* ── Base ── */
4990
5541
  [data-ui="stepper"] {
@@ -5063,7 +5614,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5063
5614
  The tight phone metrics are the base; the roomier ones arrive at `sm`. */
5064
5615
  [data-ui="stepper"] [data-part="connector"] {
5065
5616
  flex: 1;
5066
- height: 2px;
5617
+ height: var(--border-width-strong);
5067
5618
  background: var(--color-border);
5068
5619
  margin: 0 var(--space-1);
5069
5620
  min-width: var(--space-2);
@@ -5131,18 +5682,20 @@ div[data-ui="separator"][data-style="thick"]::after {
5131
5682
 
5132
5683
  /* === primitives/surface.css === */
5133
5684
  /* @ui:component surface */
5134
- /* @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 */
5685
+ /* @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 */
5135
5686
 
5136
5687
  /* ── Base ── */
5137
5688
  [data-ui="surface"] {
5138
- background: var(--color-surface-1);
5689
+ background-color: var(--color-surface-1);
5690
+ background-image: var(--texture-surface);
5139
5691
  border-radius: var(--radius-lg);
5140
- border: 1px solid var(--color-surface-1-border);
5692
+ corner-shape: var(--corner-shape);
5693
+ border: var(--border-width) solid var(--color-surface-1-border);
5141
5694
  }
5142
5695
 
5143
5696
  /* ── Elevation Variants ── */
5144
5697
  [data-ui="surface"][data-variant="flat"] {
5145
- background: var(--color-bg);
5698
+ background-color: var(--color-bg);
5146
5699
  border: none;
5147
5700
  box-shadow: none;
5148
5701
  }
@@ -5152,11 +5705,22 @@ div[data-ui="separator"][data-style="thick"]::after {
5152
5705
  }
5153
5706
 
5154
5707
  [data-ui="surface"][data-variant="overlay"] {
5155
- background: var(--color-surface-2);
5708
+ background-color: var(--color-surface-2);
5156
5709
  box-shadow: var(--shadow-lg);
5157
5710
  border-color: var(--color-surface-2-border);
5158
5711
  }
5159
5712
 
5713
+ /* An overlay is the one surface variant that floats over other content, so it
5714
+ is the one that can be frosted. Guarded exactly as themes/glass.css guards
5715
+ its own: a browser without backdrop-filter renders the solid surface above
5716
+ and never sees this rule. */
5717
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
5718
+ [data-ui="surface"][data-variant="overlay"] {
5719
+ -webkit-backdrop-filter: var(--surface-backdrop);
5720
+ backdrop-filter: var(--surface-backdrop);
5721
+ }
5722
+ }
5723
+
5160
5724
  /* ── Padding Sizes ── */
5161
5725
  [data-ui="surface"][data-size="sm"] {
5162
5726
  padding: var(--space-3);
@@ -5212,7 +5776,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5212
5776
 
5213
5777
  /* === primitives/switch.css === */
5214
5778
  /* @ui:component switch */
5215
- /* @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 */
5779
+ /* @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 */
5216
5780
 
5217
5781
  /* -- Label wrapper -- */
5218
5782
  [data-ui="switch-label"] {
@@ -5224,7 +5788,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5224
5788
 
5225
5789
  [data-ui="switch-label"]:has([data-ui="switch"]:disabled) {
5226
5790
  cursor: not-allowed;
5227
- opacity: 0.5;
5791
+ opacity: var(--disabled-opacity);
5228
5792
  }
5229
5793
 
5230
5794
  /* -- Base (track) -- */
@@ -5252,8 +5816,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5252
5816
  width: var(--switch-width, 44px);
5253
5817
  height: var(--switch-height, 24px);
5254
5818
  padding: var(--space-0h, 2px);
5255
- border: 1px solid var(--color-border);
5256
- border-radius: var(--radius-full);
5819
+ border: var(--border-width) solid var(--color-border);
5820
+ border-radius: var(--switch-radius);
5257
5821
  background: var(--switch-bg, var(--color-bg-muted));
5258
5822
  cursor: pointer;
5259
5823
  position: relative;
@@ -5263,8 +5827,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5263
5827
  }
5264
5828
 
5265
5829
  [data-ui="switch"]:focus-visible {
5266
- outline: 2px solid var(--color-ring);
5267
- outline-offset: 2px;
5830
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
5831
+ outline-offset: var(--focus-ring-offset);
5832
+ box-shadow: var(--focus-shadow);
5268
5833
  }
5269
5834
 
5270
5835
  /* -- Thumb (pseudo-element for <input>, child for custom markup) -- */
@@ -5273,7 +5838,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5273
5838
  display: block;
5274
5839
  width: var(--switch-thumb, 18px);
5275
5840
  height: var(--switch-thumb, 18px);
5276
- border-radius: var(--radius-full);
5841
+ border-radius: var(--switch-radius);
5277
5842
  background: var(--color-primary-fg);
5278
5843
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5279
5844
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5285,7 +5850,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5285
5850
  display: block;
5286
5851
  width: var(--switch-thumb, 18px);
5287
5852
  height: var(--switch-thumb, 18px);
5288
- border-radius: var(--radius-full);
5853
+ border-radius: var(--switch-radius);
5289
5854
  background: var(--color-primary-fg);
5290
5855
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5291
5856
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5367,7 +5932,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5367
5932
  the track's border is always visible, and ON fills it with `Highlight`. [W3-3] */
5368
5933
  @media (forced-colors: active) {
5369
5934
  [data-ui="switch"] {
5370
- border: 1px solid ButtonText;
5935
+ border: var(--border-width) solid ButtonText;
5371
5936
  background: ButtonFace;
5372
5937
  }
5373
5938
 
@@ -5524,25 +6089,31 @@ div[data-ui="separator"][data-style="thick"]::after {
5524
6089
 
5525
6090
  /* === primitives/text.css === */
5526
6091
  /* @ui:component text */
5527
- /* @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 */
6092
+ /* @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 */
5528
6093
 
5529
6094
  /* ── Heading ── */
5530
6095
  [data-ui="heading"] {
5531
- font-family: var(--font-sans);
5532
- font-weight: var(--weight-bold);
6096
+ font-family: var(--font-heading);
6097
+ font-weight: var(--heading-weight);
5533
6098
  color: var(--color-fg);
5534
- line-height: var(--leading-tight);
5535
- letter-spacing: -0.01em;
6099
+ line-height: var(--heading-leading);
6100
+ text-transform: var(--heading-transform);
6101
+ font-variant-caps: var(--heading-caps);
6102
+ /* The optical tightening a large heading needs, PLUS whatever tracking the
6103
+ theme's voice asks for on top of it — so a theme that wants wide-tracked
6104
+ headings sets --heading-tracking once and every size follows, instead of
6105
+ each size having to re-derive its own number. */
6106
+ letter-spacing: calc(-0.01em + var(--heading-tracking));
5536
6107
  }
5537
6108
 
5538
6109
  [data-ui="heading"][data-size="1"] {
5539
6110
  font-size: var(--text-4xl);
5540
- letter-spacing: -0.02em;
6111
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5541
6112
  }
5542
6113
 
5543
6114
  [data-ui="heading"][data-size="2"] {
5544
6115
  font-size: var(--text-3xl);
5545
- letter-spacing: -0.02em;
6116
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5546
6117
  }
5547
6118
 
5548
6119
  [data-ui="heading"][data-size="3"] {
@@ -5566,7 +6137,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5566
6137
 
5567
6138
  /* ── Text ── */
5568
6139
  [data-ui="text"] {
5569
- font-family: var(--font-sans);
6140
+ font-family: var(--font-body);
5570
6141
  color: var(--color-fg);
5571
6142
  }
5572
6143
 
@@ -5644,7 +6215,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5644
6215
 
5645
6216
  /* === primitives/textarea.css === */
5646
6217
  /* @ui:component textarea */
5647
- /* @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 */
6218
+ /* @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 */
5648
6219
 
5649
6220
  /* -- Base -- */
5650
6221
  [data-ui="textarea"] {
@@ -5652,11 +6223,17 @@ div[data-ui="separator"][data-style="thick"]::after {
5652
6223
  width: 100%;
5653
6224
  min-height: var(--textarea-min-height, 80px);
5654
6225
  padding: var(--space-2) var(--space-3);
5655
- border: 1px solid var(--color-border);
6226
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
6227
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
6228
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
6229
+ is drawn. Identical to the shorthand at every other value of the token. */
6230
+ border-style: solid;
6231
+ border-color: var(--color-border);
6232
+ border-width: var(--input-border-width);
5656
6233
  border-radius: var(--textarea-radius, var(--radius-md));
5657
- background: var(--textarea-bg, var(--color-bg));
6234
+ background: var(--textarea-bg, var(--input-fill));
5658
6235
  color: var(--color-fg);
5659
- font-family: var(--textarea-font, var(--font-sans));
6236
+ font-family: var(--textarea-font, var(--font-ui));
5660
6237
  font-size: var(--text-sm);
5661
6238
  line-height: 1.5;
5662
6239
  resize: vertical;
@@ -5673,8 +6250,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5673
6250
  }
5674
6251
 
5675
6252
  [data-ui="textarea"]:focus {
5676
- outline: 2px solid var(--color-ring);
5677
- outline-offset: -1px;
6253
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6254
+ /* The ring replaces the border rather than sitting outside it: inset by
6255
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
6256
+ outline-offset: calc(-1 * var(--input-border-width));
6257
+ box-shadow: var(--focus-shadow);
5678
6258
  border-color: transparent;
5679
6259
  }
5680
6260
 
@@ -5702,7 +6282,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5702
6282
  }
5703
6283
 
5704
6284
  [data-ui="textarea"]:disabled {
5705
- opacity: 0.5;
6285
+ opacity: var(--disabled-opacity);
5706
6286
  cursor: not-allowed;
5707
6287
  resize: none;
5708
6288
  }
@@ -5716,7 +6296,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5716
6296
 
5717
6297
  /* === primitives/toggle.css === */
5718
6298
  /* @ui:component toggle */
5719
- /* @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 */
6299
+ /* @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 */
5720
6300
 
5721
6301
  /* ── Base (off / unpressed) ── */
5722
6302
  [data-ui="toggle"] {
@@ -5725,11 +6305,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5725
6305
  justify-content: center;
5726
6306
  gap: var(--space-1h);
5727
6307
  padding: var(--toggle-pad-y, var(--space-1h)) var(--toggle-pad-x, var(--space-3));
5728
- border: 1px solid var(--color-border);
6308
+ border: var(--border-width) solid var(--color-border);
5729
6309
  border-radius: var(--toggle-radius, var(--radius-md));
5730
6310
  background: var(--color-bg);
5731
6311
  color: var(--color-fg-muted);
5732
- font-family: var(--toggle-font, var(--font-sans));
6312
+ font-family: var(--toggle-font, var(--font-ui));
5733
6313
  font-size: var(--text-sm);
5734
6314
  font-weight: var(--weight-medium);
5735
6315
  line-height: 1;
@@ -5746,8 +6326,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5746
6326
  }
5747
6327
 
5748
6328
  [data-ui="toggle"]:focus-visible {
5749
- outline: 2px solid var(--color-ring);
5750
- outline-offset: 2px;
6329
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6330
+ outline-offset: var(--focus-ring-offset);
6331
+ box-shadow: var(--focus-shadow);
5751
6332
  }
5752
6333
 
5753
6334
  /* ── Pressed / on — styled entirely off aria-pressed, no JS ── */
@@ -5764,7 +6345,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5764
6345
 
5765
6346
  /* ── Disabled ── */
5766
6347
  [data-ui="toggle"]:disabled {
5767
- opacity: 0.5;
6348
+ opacity: var(--disabled-opacity);
5768
6349
  cursor: not-allowed;
5769
6350
  }
5770
6351
 
@@ -5788,7 +6369,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5788
6369
 
5789
6370
  /* === primitives/watermark.css === */
5790
6371
  /* @ui:component watermark */
5791
- /* @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 */
6372
+ /* @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 */
5792
6373
 
5793
6374
  [data-ui="watermark"] {
5794
6375
  position: fixed;
@@ -5807,7 +6388,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5807
6388
 
5808
6389
  [data-ui="watermark"] > [data-part="mark"] {
5809
6390
  color: var(--color-fg-muted);
5810
- font-family: var(--doc-font, var(--font-sans));
6391
+ font-family: var(--doc-font, var(--font-body));
5811
6392
  font-size: var(--text-4xl);
5812
6393
  font-weight: var(--weight-bold);
5813
6394
  line-height: var(--leading-tight);
@@ -5865,7 +6446,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5865
6446
 
5866
6447
  /* === recipes/accordion.css === */
5867
6448
  /* @ui:component accordion */
5868
- /* @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 */
6449
+ /* @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 */
5869
6450
 
5870
6451
  /* ── Root ── */
5871
6452
  [data-ui="accordion"] {
@@ -5874,7 +6455,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5874
6455
 
5875
6456
  /* ── Item ── */
5876
6457
  [data-ui="accordion"] [data-part="item"] {
5877
- border-bottom: 1px solid var(--color-border);
6458
+ border-bottom: var(--border-width) solid var(--color-border);
5878
6459
  }
5879
6460
 
5880
6461
  [data-ui="accordion"] [data-part="item"]:last-child {
@@ -5891,7 +6472,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5891
6472
  border: none;
5892
6473
  background: transparent;
5893
6474
  color: var(--color-fg);
5894
- font-family: var(--font-sans, system-ui, sans-serif);
6475
+ font-family: var(--font-ui);
5895
6476
  font-size: var(--text-base);
5896
6477
  font-weight: var(--weight-medium);
5897
6478
  text-align: start;
@@ -5905,8 +6486,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5905
6486
  }
5906
6487
 
5907
6488
  [data-ui="accordion"] [data-part="trigger"]:focus-visible {
5908
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
5909
- outline-offset: -2px;
6489
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6490
+ outline-offset: calc(-1 * var(--focus-ring-offset));
5910
6491
  border-radius: var(--radius-sm, 0.25rem);
5911
6492
  }
5912
6493
 
@@ -5938,13 +6519,13 @@ div[data-ui="separator"][data-style="thick"]::after {
5938
6519
 
5939
6520
  /* ── Bordered Variant ── */
5940
6521
  [data-ui="accordion"][data-bordered="true"] {
5941
- border: 1px solid var(--color-border);
6522
+ border: var(--border-width) solid var(--color-border);
5942
6523
  border-radius: var(--radius-lg);
5943
6524
  overflow: hidden;
5944
6525
  }
5945
6526
 
5946
6527
  [data-ui="accordion"][data-bordered="true"] [data-part="item"] {
5947
- border-bottom: 1px solid var(--color-border);
6528
+ border-bottom: var(--border-width) solid var(--color-border);
5948
6529
  }
5949
6530
 
5950
6531
  [data-ui="accordion"][data-bordered="true"] [data-part="item"]:last-child {
@@ -5961,7 +6542,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5961
6542
 
5962
6543
  /* === recipes/alert-dialog.css === */
5963
6544
  /* @ui:component alert-dialog */
5964
- /* @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 */
6545
+ /* @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 */
5965
6546
 
5966
6547
  /* ── Root ── */
5967
6548
  [data-ui="alert-dialog"] {
@@ -5997,7 +6578,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5997
6578
  max-height: 85vh;
5998
6579
  overflow-y: auto;
5999
6580
  background: var(--color-bg);
6000
- border: 1px solid var(--color-border);
6581
+ border: var(--border-width) solid var(--color-border);
6001
6582
  border-radius: var(--alert-dialog-radius, var(--radius-xl));
6002
6583
  box-shadow: var(--alert-dialog-shadow, var(--shadow-xl));
6003
6584
  opacity: 0;
@@ -6043,6 +6624,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6043
6624
  /* ── Title ── */
6044
6625
  [data-ui="alert-dialog"] [data-part="title"] {
6045
6626
  margin: 0;
6627
+ font-family: var(--font-heading);
6046
6628
  font-size: var(--text-lg, 1.125rem);
6047
6629
  font-weight: var(--weight-semibold, 600);
6048
6630
  color: var(--color-fg);
@@ -6082,7 +6664,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6082
6664
 
6083
6665
  /* === recipes/barcode.css === */
6084
6666
  /* @ui:component barcode */
6085
- /* @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 */
6667
+ /* @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 */
6086
6668
 
6087
6669
  [data-ui="barcode"] {
6088
6670
  display: inline-flex;
@@ -6109,7 +6691,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6109
6691
 
6110
6692
  [data-ui="barcode"] > [data-part="caption"] {
6111
6693
  color: var(--doc-legal-color, var(--color-fg-muted));
6112
- font-family: var(--font-mono, var(--doc-font, var(--font-sans)));
6694
+ font-family: var(--font-mono, var(--doc-font, var(--font-body)));
6113
6695
  font-size: var(--doc-legal-size);
6114
6696
  line-height: var(--leading-normal);
6115
6697
  text-align: center;
@@ -6129,7 +6711,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6129
6711
 
6130
6712
  /* === recipes/calendar.css === */
6131
6713
  /* @ui:component calendar */
6132
- /* @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 */
6714
+ /* @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 */
6133
6715
 
6134
6716
  /* ── Root ── */
6135
6717
  [data-ui="calendar"] {
@@ -6162,7 +6744,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6162
6744
  width: 28px;
6163
6745
  height: 28px;
6164
6746
  padding: 0;
6165
- border: 1px solid var(--color-border);
6747
+ border: var(--border-width) solid var(--color-border);
6166
6748
  border-radius: var(--radius-md);
6167
6749
  background: var(--color-bg);
6168
6750
  color: var(--color-fg);
@@ -6178,13 +6760,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6178
6760
 
6179
6761
  [data-ui="calendar"] [data-part="nav-prev"]:focus-visible,
6180
6762
  [data-ui="calendar"] [data-part="nav-next"]:focus-visible {
6181
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6182
- outline-offset: 2px;
6763
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6764
+ outline-offset: var(--focus-ring-offset);
6183
6765
  }
6184
6766
 
6185
6767
  [data-ui="calendar"] [data-part="nav-prev"]:disabled,
6186
6768
  [data-ui="calendar"] [data-part="nav-next"]:disabled {
6187
- opacity: 0.4;
6769
+ /* Dimmer than a disabled control — 0.4 at the 0.5 default — and it follows a
6770
+ theme's `--disabled-opacity` like every other disabled dim (1.1A-27). */
6771
+ opacity: calc(var(--disabled-opacity) * 0.8);
6188
6772
  cursor: not-allowed;
6189
6773
  }
6190
6774
 
@@ -6219,11 +6803,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6219
6803
  width: 36px;
6220
6804
  height: 36px;
6221
6805
  padding: 0;
6222
- border: 1px solid transparent;
6806
+ border: var(--border-width) solid transparent;
6223
6807
  border-radius: var(--radius-full);
6224
6808
  background: transparent;
6225
6809
  color: var(--color-fg);
6226
- font-family: var(--font-sans, system-ui, sans-serif);
6810
+ font-family: var(--font-ui);
6227
6811
  font-size: var(--text-sm);
6228
6812
  cursor: pointer;
6229
6813
  transition: background var(--duration-fast) var(--ease-default),
@@ -6236,8 +6820,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6236
6820
  }
6237
6821
 
6238
6822
  [data-ui="calendar"] [data-part="day"]:focus-visible {
6239
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6240
- outline-offset: 2px;
6823
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6824
+ outline-offset: var(--focus-ring-offset);
6241
6825
  }
6242
6826
 
6243
6827
  /* ── Today ── */
@@ -6272,7 +6856,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6272
6856
  /* ── Disabled days (aria-disabled keeps them focusable; :disabled for hard-disabled) ── */
6273
6857
  [data-ui="calendar"] [data-part="day"][aria-disabled="true"],
6274
6858
  [data-ui="calendar"] [data-part="day"]:disabled {
6275
- opacity: 0.5;
6859
+ opacity: var(--disabled-opacity);
6276
6860
  cursor: not-allowed;
6277
6861
  text-decoration: line-through;
6278
6862
  }
@@ -6336,7 +6920,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6336
6920
 
6337
6921
  /* === recipes/carousel.css === */
6338
6922
  /* @ui:component carousel */
6339
- /* @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 */
6923
+ /* @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 */
6340
6924
 
6341
6925
  /* The sliding is CSS, not JavaScript: the viewport is a scroll-snap strip and
6342
6926
  every slide is a snap target. Everything below works with no controller
@@ -6350,7 +6934,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6350
6934
  inline-size: 100%;
6351
6935
  min-inline-size: 0;
6352
6936
  max-inline-size: 100%;
6353
- font-family: var(--carousel-font, var(--font-sans));
6937
+ font-family: var(--carousel-font, var(--font-ui));
6354
6938
  }
6355
6939
 
6356
6940
  /* ── Viewport: the scroll-snap strip ── */
@@ -6376,8 +6960,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6376
6960
  }
6377
6961
 
6378
6962
  [data-ui="carousel"] [data-part="viewport"]:focus-visible {
6379
- outline: 2px solid var(--color-ring);
6380
- outline-offset: 2px;
6963
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6964
+ outline-offset: var(--focus-ring-offset);
6381
6965
  }
6382
6966
 
6383
6967
  /* ── Slide: one full-width snap target ── */
@@ -6385,7 +6969,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6385
6969
  flex: 0 0 var(--carousel-slide-size, 100%);
6386
6970
  min-inline-size: 0;
6387
6971
  padding: var(--space-4);
6388
- border: 1px solid var(--color-border);
6972
+ border: var(--border-width) solid var(--color-border);
6389
6973
  border-radius: var(--radius-lg);
6390
6974
  background: var(--color-bg);
6391
6975
  color: var(--color-fg);
@@ -6414,7 +6998,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6414
6998
  min-inline-size: 2rem;
6415
6999
  min-block-size: 2rem;
6416
7000
  padding: var(--space-1) var(--space-2);
6417
- border: 1px solid var(--color-border);
7001
+ border: var(--border-width) solid var(--color-border);
6418
7002
  border-radius: var(--radius-md);
6419
7003
  background: var(--color-bg);
6420
7004
  color: var(--color-fg);
@@ -6433,14 +7017,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6433
7017
  [data-ui="carousel"] [data-part="prev"]:focus-visible,
6434
7018
  [data-ui="carousel"] [data-part="next"]:focus-visible,
6435
7019
  [data-ui="carousel"] [data-part="dot"]:focus-visible {
6436
- outline: 2px solid var(--color-ring);
6437
- outline-offset: 2px;
7020
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7021
+ outline-offset: var(--focus-ring-offset);
6438
7022
  }
6439
7023
 
6440
7024
  /* Boundary contract "stop" — the controller disables the end button. */
6441
7025
  [data-ui="carousel"] [data-part="prev"]:disabled,
6442
7026
  [data-ui="carousel"] [data-part="next"]:disabled {
6443
- opacity: 0.4;
7027
+ /* 0.4 at the 0.5 default, and a theme's `--disabled-opacity` moves it (1.1A-27). */
7028
+ opacity: calc(var(--disabled-opacity) * 0.8);
6444
7029
  cursor: not-allowed;
6445
7030
  }
6446
7031
 
@@ -6449,7 +7034,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6449
7034
  inline-size: 0.625rem;
6450
7035
  block-size: 0.625rem;
6451
7036
  padding: 0;
6452
- border: 1px solid var(--color-border);
7037
+ border: var(--border-width) solid var(--color-border);
6453
7038
  border-radius: 50%;
6454
7039
  background: var(--color-bg-muted);
6455
7040
  cursor: pointer;
@@ -6485,7 +7070,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6485
7070
 
6486
7071
  /* === recipes/combobox.css === */
6487
7072
  /* @ui:component combobox */
6488
- /* @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 */
7073
+ /* @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 */
6489
7074
 
6490
7075
  /* ── Root ── */
6491
7076
  [data-ui="combobox"] {
@@ -6499,11 +7084,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6499
7084
  display: block;
6500
7085
  width: 100%;
6501
7086
  padding: var(--space-2) var(--space-3);
6502
- border: 1px solid var(--color-border);
7087
+ border: var(--border-width) solid var(--color-border);
6503
7088
  border-radius: var(--radius-md);
6504
7089
  background: var(--color-bg);
6505
7090
  color: var(--color-fg);
6506
- font-family: var(--font-sans, system-ui, sans-serif);
7091
+ font-family: var(--font-ui);
6507
7092
  font-size: var(--text-sm);
6508
7093
  line-height: 1.5;
6509
7094
  outline: none;
@@ -6516,8 +7101,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6516
7101
  }
6517
7102
 
6518
7103
  [data-ui="combobox"] [data-part="input"]:focus {
6519
- border-color: var(--color-ring, oklch(0.55 0.22 264));
6520
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
7104
+ border-color: var(--focus-ring-color);
7105
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
6521
7106
  }
6522
7107
 
6523
7108
  /* ── Listbox ── */
@@ -6529,7 +7114,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6529
7114
  z-index: var(--z-dropdown);
6530
7115
  margin-top: var(--space-1);
6531
7116
  padding: var(--space-1);
6532
- border: 1px solid var(--color-border);
7117
+ border: var(--border-width) solid var(--color-border);
6533
7118
  border-radius: var(--radius-lg);
6534
7119
  background: var(--color-bg);
6535
7120
  box-shadow: var(--shadow-md);
@@ -6614,7 +7199,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6614
7199
 
6615
7200
  /* === recipes/command-palette.css === */
6616
7201
  /* @ui:component command-palette */
6617
- /* @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 */
7202
+ /* @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 */
6618
7203
 
6619
7204
  /* ── Root ── */
6620
7205
  [data-ui="command-palette"] {
@@ -6647,7 +7232,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6647
7232
  display: flex;
6648
7233
  flex-direction: column;
6649
7234
  background: var(--color-bg);
6650
- border: 1px solid var(--color-border);
7235
+ border: var(--border-width) solid var(--color-border);
6651
7236
  border-radius: var(--radius-xl);
6652
7237
  box-shadow: var(--shadow-xl);
6653
7238
  overflow: hidden;
@@ -6679,7 +7264,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6679
7264
  display: flex;
6680
7265
  align-items: center;
6681
7266
  padding: var(--space-3) var(--space-4);
6682
- border-bottom: 1px solid var(--color-border);
7267
+ border-bottom: var(--border-width) solid var(--color-border);
6683
7268
  }
6684
7269
 
6685
7270
  /* ── Search Input ── */
@@ -6689,7 +7274,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6689
7274
  border: none;
6690
7275
  background: transparent;
6691
7276
  color: var(--color-fg);
6692
- font-family: var(--font-sans, system-ui, sans-serif);
7277
+ font-family: var(--font-ui);
6693
7278
  font-size: var(--text-base);
6694
7279
  outline: none;
6695
7280
  }
@@ -6773,7 +7358,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6773
7358
  align-items: center;
6774
7359
  gap: var(--space-1, 0.25rem);
6775
7360
  padding: var(--space-1, 0.25rem) var(--space-2);
6776
- border: 1px solid var(--color-border);
7361
+ border: var(--border-width) solid var(--color-border);
6777
7362
  border-radius: var(--radius-sm, 0.25rem);
6778
7363
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
6779
7364
  color: var(--color-fg-muted);
@@ -6802,7 +7387,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6802
7387
 
6803
7388
  /* === recipes/context-menu.css === */
6804
7389
  /* @ui:component context-menu */
6805
- /* @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 */
7390
+ /* @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 */
6806
7391
 
6807
7392
  [data-ui="context-menu"] {
6808
7393
  position: relative;
@@ -6815,12 +7400,12 @@ div[data-ui="separator"][data-style="thick"]::after {
6815
7400
  border-radius: var(--radius-lg);
6816
7401
  background: var(--color-bg-muted);
6817
7402
  color: var(--color-fg);
6818
- font-family: var(--font-sans, system-ui, sans-serif);
7403
+ font-family: var(--font-ui);
6819
7404
  }
6820
7405
 
6821
7406
  [data-ui="context-menu"] [data-part="target"]:focus-visible {
6822
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6823
- outline-offset: var(--space-1);
7407
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7408
+ outline-offset: var(--focus-ring-offset);
6824
7409
  }
6825
7410
 
6826
7411
  [data-ui="context-menu"] [data-part="menu"] {
@@ -6852,7 +7437,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6852
7437
  border-radius: var(--radius-md);
6853
7438
  background: transparent;
6854
7439
  color: var(--color-fg);
6855
- font-family: var(--font-sans, system-ui, sans-serif);
7440
+ font-family: var(--font-ui);
6856
7441
  font-size: var(--text-sm);
6857
7442
  font-weight: var(--weight-medium);
6858
7443
  text-align: start;
@@ -6876,15 +7461,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6876
7461
  focus additionally draws the ring, inset so it does not overlap the item
6877
7462
  above. [W3-3] */
6878
7463
  [data-ui="context-menu"] [data-part="item"]:focus-visible {
6879
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6880
- outline-offset: calc(var(--space-px) * -2);
7464
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7465
+ outline-offset: calc(-1 * var(--focus-ring-offset));
6881
7466
  }
6882
7467
 
6883
7468
  [data-ui="context-menu"] [data-part="item"]:disabled,
6884
7469
  [data-ui="context-menu"] [data-part="item"][aria-disabled="true"] {
6885
7470
  color: var(--color-fg-muted);
6886
7471
  cursor: not-allowed;
6887
- opacity: 0.5;
7472
+ opacity: var(--disabled-opacity);
6888
7473
  }
6889
7474
 
6890
7475
  [data-ui="context-menu"] [data-part="separator"] {
@@ -6903,7 +7488,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6903
7488
 
6904
7489
  /* === recipes/date-picker.css === */
6905
7490
  /* @ui:component date-picker */
6906
- /* @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 */
7491
+ /* @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 */
6907
7492
  /* The month grid inside the popup is the `calendar` recipe — see calendar.css */
6908
7493
 
6909
7494
  /* ── Root ── */
@@ -6924,11 +7509,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6924
7509
  width: 100%;
6925
7510
  padding: var(--space-2, 0.5rem) var(--space-3);
6926
7511
  padding-inline-end: var(--space-8, 2.5rem);
6927
- border: 1px solid var(--color-border);
7512
+ border: var(--border-width) solid var(--color-border);
6928
7513
  border-radius: var(--radius-md);
6929
7514
  background: var(--color-bg);
6930
7515
  color: var(--color-fg);
6931
- font-family: var(--font-sans, system-ui, sans-serif);
7516
+ font-family: var(--font-ui);
6932
7517
  font-size: var(--text-sm);
6933
7518
  line-height: 1.5;
6934
7519
  cursor: pointer;
@@ -6940,8 +7525,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6940
7525
  }
6941
7526
 
6942
7527
  [data-ui="date-picker"] [data-part="input"]:focus-visible {
6943
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6944
- outline-offset: 2px;
7528
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7529
+ outline-offset: var(--focus-ring-offset);
6945
7530
  border-color: var(--color-primary);
6946
7531
  }
6947
7532
 
@@ -6964,7 +7549,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6964
7549
  z-index: var(--z-dropdown);
6965
7550
  margin-top: var(--space-1);
6966
7551
  padding: var(--space-3);
6967
- border: 1px solid var(--color-border);
7552
+ border: var(--border-width) solid var(--color-border);
6968
7553
  border-radius: var(--radius-lg);
6969
7554
  background: var(--color-bg);
6970
7555
  box-shadow: var(--shadow-lg);
@@ -7003,7 +7588,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7003
7588
 
7004
7589
  /* === recipes/dialog.css === */
7005
7590
  /* @ui:component dialog */
7006
- /* @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 */
7591
+ /* @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 */
7007
7592
 
7008
7593
  /* ── Root ── */
7009
7594
  [data-ui="dialog"] {
@@ -7038,15 +7623,23 @@ div[data-ui="separator"][data-style="thick"]::after {
7038
7623
  width: 90%;
7039
7624
  max-height: 85vh;
7040
7625
  overflow-y: auto;
7041
- background: var(--color-bg);
7042
- border: 1px solid var(--color-border);
7626
+ background: var(--panel-bg);
7627
+ border: var(--border-width) solid var(--color-border);
7043
7628
  border-radius: var(--dialog-radius, var(--radius-xl));
7629
+ corner-shape: var(--corner-shape);
7044
7630
  box-shadow: var(--dialog-shadow, var(--shadow-xl));
7045
7631
  opacity: 0;
7046
7632
  transition: opacity var(--duration-normal) var(--ease-out),
7047
7633
  transform var(--duration-normal) var(--ease-out);
7048
7634
  }
7049
7635
 
7636
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7637
+ [data-ui="dialog"] [data-part="panel"] {
7638
+ -webkit-backdrop-filter: var(--surface-backdrop);
7639
+ backdrop-filter: var(--surface-backdrop);
7640
+ }
7641
+ }
7642
+
7050
7643
  [data-ui="dialog"][data-state="open"] [data-part="panel"] {
7051
7644
  opacity: 1;
7052
7645
  transform: translate(-50%, -50%) scale(1);
@@ -7095,6 +7688,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7095
7688
  /* ── Title ── */
7096
7689
  [data-ui="dialog"] [data-part="title"] {
7097
7690
  margin: 0;
7691
+ font-family: var(--font-heading);
7098
7692
  font-size: var(--text-lg, 1.125rem);
7099
7693
  font-weight: var(--weight-semibold, 600);
7100
7694
  color: var(--color-fg);
@@ -7129,8 +7723,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7129
7723
  }
7130
7724
 
7131
7725
  [data-ui="dialog"] [data-part="close"]:not([data-ui]):focus-visible {
7132
- outline: 2px solid var(--color-ring);
7133
- outline-offset: 2px;
7726
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7727
+ outline-offset: var(--focus-ring-offset);
7134
7728
  }
7135
7729
 
7136
7730
  /* ── Description ── */
@@ -7166,7 +7760,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7166
7760
 
7167
7761
  /* === recipes/drawer.css === */
7168
7762
  /* @ui:component drawer */
7169
- /* @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 */
7763
+ /* @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 */
7170
7764
 
7171
7765
  /* ── Root ── */
7172
7766
  [data-ui="drawer"] {
@@ -7201,17 +7795,24 @@ div[data-ui="separator"][data-style="thick"]::after {
7201
7795
  flex-direction: column;
7202
7796
  width: var(--drawer-width, 400px);
7203
7797
  max-width: 100vw;
7204
- background: var(--color-bg);
7798
+ background: var(--panel-bg);
7205
7799
  border: none;
7206
7800
  box-shadow: var(--drawer-shadow, var(--shadow-xl));
7207
7801
  transition: transform var(--duration-slow) var(--ease-out);
7208
7802
  }
7209
7803
 
7804
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7805
+ [data-ui="drawer"] [data-part="panel"] {
7806
+ -webkit-backdrop-filter: var(--surface-backdrop);
7807
+ backdrop-filter: var(--surface-backdrop);
7808
+ }
7809
+ }
7810
+
7210
7811
  /* ── Side Variants ── */
7211
7812
  [data-ui="drawer"] [data-part="panel"][data-variant="left"] {
7212
7813
  inset-inline-start: 0;
7213
7814
  inset-inline-end: auto;
7214
- border-inline-end: 1px solid var(--color-border);
7815
+ border-inline-end: var(--border-width) solid var(--color-border);
7215
7816
  border-radius: 0 var(--radius-none, 0) var(--radius-none, 0) 0;
7216
7817
  transform: translateX(-100%);
7217
7818
  }
@@ -7219,7 +7820,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7219
7820
  [data-ui="drawer"] [data-part="panel"][data-variant="right"] {
7220
7821
  inset-inline-end: 0;
7221
7822
  inset-inline-start: auto;
7222
- border-inline-start: 1px solid var(--color-border);
7823
+ border-inline-start: var(--border-width) solid var(--color-border);
7223
7824
  border-radius: var(--radius-none, 0) 0 0 var(--radius-none, 0);
7224
7825
  transform: translateX(100%);
7225
7826
  }
@@ -7273,6 +7874,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7273
7874
  /* ── Title ── */
7274
7875
  [data-ui="drawer"] [data-part="title"] {
7275
7876
  margin: 0;
7877
+ font-family: var(--font-heading);
7276
7878
  font-size: var(--text-lg, 1.125rem);
7277
7879
  font-weight: var(--weight-semibold, 600);
7278
7880
  color: var(--color-fg);
@@ -7307,8 +7909,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7307
7909
  }
7308
7910
 
7309
7911
  [data-ui="drawer"] [data-part="close"]:not([data-ui]):focus-visible {
7310
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7311
- outline-offset: 2px;
7912
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7913
+ outline-offset: var(--focus-ring-offset);
7312
7914
  }
7313
7915
 
7314
7916
  /* ── Body ── */
@@ -7327,7 +7929,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7327
7929
  gap: var(--space-3, 0.75rem);
7328
7930
  padding: var(--space-6);
7329
7931
  padding-top: var(--space-4);
7330
- border-top: 1px solid var(--color-border);
7932
+ border-top: var(--border-width) solid var(--color-border);
7331
7933
  flex-shrink: 0;
7332
7934
  }
7333
7935
 
@@ -7341,7 +7943,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7341
7943
 
7342
7944
  /* === recipes/dropdown.css === */
7343
7945
  /* @ui:component dropdown */
7344
- /* @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 */
7946
+ /* @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 */
7345
7947
 
7346
7948
  /* ── Root ── */
7347
7949
  [data-ui="dropdown"] {
@@ -7355,11 +7957,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7355
7957
  align-items: center;
7356
7958
  gap: var(--space-2);
7357
7959
  padding: var(--space-2) var(--space-3);
7358
- border: 1px solid var(--color-border);
7960
+ border: var(--border-width) solid var(--color-border);
7359
7961
  border-radius: var(--radius-md);
7360
7962
  background: var(--color-bg);
7361
7963
  color: var(--color-fg);
7362
- font-family: var(--font-sans, system-ui, sans-serif);
7964
+ font-family: var(--font-ui);
7363
7965
  font-size: var(--text-sm);
7364
7966
  font-weight: var(--weight-medium);
7365
7967
  cursor: pointer;
@@ -7373,8 +7975,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7373
7975
  }
7374
7976
 
7375
7977
  [data-ui="dropdown"] [data-part="trigger"]:focus-visible {
7376
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7377
- outline-offset: 2px;
7978
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7979
+ outline-offset: var(--focus-ring-offset);
7378
7980
  }
7379
7981
 
7380
7982
  /* ── Menu ── */
@@ -7386,9 +7988,9 @@ div[data-ui="separator"][data-style="thick"]::after {
7386
7988
  min-width: 180px;
7387
7989
  margin-top: var(--space-1);
7388
7990
  padding: var(--space-1);
7389
- border: 1px solid var(--color-border);
7991
+ border: var(--border-width) solid var(--color-border);
7390
7992
  border-radius: var(--radius-lg);
7391
- background: var(--color-bg);
7993
+ background: var(--panel-bg);
7392
7994
  box-shadow: var(--shadow-md);
7393
7995
  opacity: 0;
7394
7996
  transform: translateY(-4px);
@@ -7396,6 +7998,13 @@ div[data-ui="separator"][data-style="thick"]::after {
7396
7998
  transform var(--duration-fast) var(--ease-out);
7397
7999
  }
7398
8000
 
8001
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
8002
+ [data-ui="dropdown"] [data-part="menu"] {
8003
+ -webkit-backdrop-filter: var(--surface-backdrop);
8004
+ backdrop-filter: var(--surface-backdrop);
8005
+ }
8006
+ }
8007
+
7399
8008
  [data-ui="dropdown"][data-state="open"] [data-part="menu"] {
7400
8009
  opacity: 1;
7401
8010
  transform: translateY(0);
@@ -7418,7 +8027,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7418
8027
  border-radius: var(--radius-md);
7419
8028
  background: transparent;
7420
8029
  color: var(--color-fg);
7421
- font-family: var(--font-sans, system-ui, sans-serif);
8030
+ font-family: var(--font-ui);
7422
8031
  font-size: var(--text-sm);
7423
8032
  text-align: start;
7424
8033
  cursor: pointer;
@@ -7440,12 +8049,12 @@ div[data-ui="separator"][data-style="thick"]::after {
7440
8049
  focus additionally draws the ring, inset so it does not overlap the item
7441
8050
  above. [W3-3] */
7442
8051
  [data-ui="dropdown"] [data-part="item"]:focus-visible {
7443
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7444
- outline-offset: -2px;
8052
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8053
+ outline-offset: calc(-1 * var(--focus-ring-offset));
7445
8054
  }
7446
8055
 
7447
8056
  [data-ui="dropdown"] [data-part="item"]:disabled {
7448
- opacity: 0.5;
8057
+ opacity: var(--disabled-opacity);
7449
8058
  cursor: not-allowed;
7450
8059
  pointer-events: none;
7451
8060
  }
@@ -7498,14 +8107,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7498
8107
 
7499
8108
  /* === recipes/file-upload.css === */
7500
8109
  /* @ui:component file-upload */
7501
- /* @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 */
8110
+ /* @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 */
7502
8111
 
7503
8112
  [data-ui="file-upload"] {
7504
8113
  display: grid;
7505
8114
  gap: var(--space-4);
7506
8115
  inline-size: 100%;
7507
8116
  color: var(--color-fg);
7508
- font-family: var(--font-sans);
8117
+ font-family: var(--font-ui);
7509
8118
  }
7510
8119
 
7511
8120
  [data-ui="file-upload"] [data-part="dropzone"] {
@@ -7540,14 +8149,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7540
8149
  }
7541
8150
 
7542
8151
  [data-ui="file-upload"]:has([data-part="input"]:focus-visible) [data-part="dropzone"] {
7543
- outline: var(--space-px) solid var(--color-ring);
7544
- outline-offset: var(--space-1);
8152
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8153
+ outline-offset: var(--focus-ring-offset);
7545
8154
  }
7546
8155
 
7547
8156
  [data-ui="file-upload"][data-state="dragging"] [data-part="dropzone"] {
7548
8157
  border-color: var(--color-primary);
7549
8158
  background: var(--color-primary-subtle);
7550
- box-shadow: 0 0 0 var(--space-px) var(--color-primary);
8159
+ box-shadow: 0 0 0 var(--border-width) var(--color-primary);
7551
8160
  }
7552
8161
 
7553
8162
  [data-ui="file-upload"] [data-part="prompt"] {
@@ -7621,8 +8230,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7621
8230
  }
7622
8231
 
7623
8232
  [data-ui="file-upload"] [data-part="remove"]:focus-visible {
7624
- outline: var(--space-px) solid var(--color-ring);
7625
- outline-offset: var(--space-1);
8233
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8234
+ outline-offset: var(--focus-ring-offset);
7626
8235
  }
7627
8236
 
7628
8237
  [data-ui="file-upload"] [data-part="empty"] {
@@ -7644,7 +8253,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7644
8253
  }
7645
8254
 
7646
8255
  [data-ui="file-upload"][data-disabled] {
7647
- opacity: 0.5;
8256
+ opacity: var(--disabled-opacity);
7648
8257
  }
7649
8258
 
7650
8259
  [data-ui="file-upload"][data-disabled] [data-part="dropzone"],
@@ -7660,7 +8269,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7660
8269
 
7661
8270
  /* === recipes/input-otp.css === */
7662
8271
  /* @ui:component input-otp */
7663
- /* @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 */
8272
+ /* @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 */
7664
8273
 
7665
8274
  /* ── Root ── */
7666
8275
  [data-ui="input-otp"] {
@@ -7675,7 +8284,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7675
8284
  gutter. The transparent input is `inset: 0`, so it follows the box the
7676
8285
  segments settle into however many rows that takes. */
7677
8286
  max-inline-size: 100%;
7678
- font-family: var(--font-sans, system-ui, sans-serif);
8287
+ font-family: var(--font-ui);
7679
8288
  }
7680
8289
 
7681
8290
  /* ── Real input ──
@@ -7720,14 +8329,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7720
8329
  justify-content: center;
7721
8330
  inline-size: var(--input-otp-segment-size);
7722
8331
  block-size: var(--input-otp-segment-size);
7723
- border: 1px solid var(--color-border);
8332
+ border: var(--border-width) solid var(--color-border);
7724
8333
  border-radius: var(--radius-md);
7725
8334
  background: var(--color-bg);
7726
8335
  color: var(--color-fg);
7727
8336
  font-size: var(--text-lg, 1.125rem);
7728
8337
  font-variant-numeric: tabular-nums;
7729
8338
  line-height: 1;
7730
- transition: border-color var(--duration-fast, 120ms) var(--ease-default, ease),
8339
+ transition: border-color var(--duration-fast) var(--ease-default),
7731
8340
  box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
7732
8341
  }
7733
8342
 
@@ -7739,7 +8348,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7739
8348
  /* Active (caret / selected) segment while focused */
7740
8349
  [data-ui="input-otp"] [data-part="segment"][data-active] {
7741
8350
  border-color: var(--color-ring);
7742
- box-shadow: 0 0 0 1px var(--color-ring);
8351
+ box-shadow: 0 0 0 var(--border-width) var(--color-ring);
7743
8352
  }
7744
8353
 
7745
8354
  /* Blinking caret in the next-to-fill empty slot */
@@ -7787,7 +8396,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7787
8396
 
7788
8397
  /* ── Disabled ── */
7789
8398
  [data-ui="input-otp"][data-disabled] {
7790
- opacity: 0.5;
8399
+ opacity: var(--disabled-opacity);
7791
8400
  cursor: not-allowed;
7792
8401
  }
7793
8402
  [data-ui="input-otp"][data-disabled] [data-part="input"] {
@@ -7811,7 +8420,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7811
8420
 
7812
8421
  /* === recipes/menubar.css === */
7813
8422
  /* @ui:component menubar */
7814
- /* @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 */
8423
+ /* @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 */
7815
8424
 
7816
8425
  [data-ui="menubar"] {
7817
8426
  position: relative;
@@ -7829,7 +8438,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7829
8438
  border-radius: var(--radius-lg);
7830
8439
  background: var(--color-bg);
7831
8440
  color: var(--color-fg);
7832
- font-family: var(--font-sans);
8441
+ font-family: var(--font-ui);
7833
8442
  }
7834
8443
 
7835
8444
  [data-ui="menubar"] [data-part="group"] {
@@ -7871,7 +8480,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7871
8480
 
7872
8481
  [data-ui="menubar"] [data-part="trigger"]:focus-visible,
7873
8482
  [data-ui="menubar"] [data-part="item"]:focus-visible {
7874
- box-shadow: 0 0 0 calc(var(--space-px) * 2) var(--color-ring);
8483
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
7875
8484
  }
7876
8485
 
7877
8486
  [data-ui="menubar"] [data-part="submenu"] {
@@ -7906,7 +8515,10 @@ div[data-ui="separator"][data-style="thick"]::after {
7906
8515
  [data-ui="menubar"] [role="menuitem"][aria-disabled="true"] {
7907
8516
  color: var(--color-fg-muted);
7908
8517
  cursor: not-allowed;
7909
- opacity: 0.6;
8518
+ /* 0.6 at the 0.5 default — lighter than a control, since the muted colour
8519
+ already carries half the signal — and a theme's `--disabled-opacity` moves
8520
+ it (1.1A-27). */
8521
+ opacity: calc(var(--disabled-opacity) * 1.2);
7910
8522
  }
7911
8523
 
7912
8524
  [data-ui="menubar"] [data-part="separator"] {
@@ -7938,7 +8550,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7938
8550
 
7939
8551
  /* === recipes/pagination.css === */
7940
8552
  /* @ui:component pagination */
7941
- /* @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 */
8553
+ /* @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 */
7942
8554
 
7943
8555
  /* ── Root ── */
7944
8556
  [data-ui="pagination"] {
@@ -7974,11 +8586,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7974
8586
  min-width: 36px;
7975
8587
  height: 36px;
7976
8588
  padding: 0 var(--space-2);
7977
- border: 1px solid var(--color-border);
8589
+ border: var(--border-width) solid var(--color-border);
7978
8590
  border-radius: var(--radius-md);
7979
8591
  background: var(--color-bg);
7980
8592
  color: var(--color-fg);
7981
- font-family: var(--font-sans, system-ui, sans-serif);
8593
+ font-family: var(--font-ui);
7982
8594
  font-size: var(--text-sm);
7983
8595
  font-weight: var(--weight-medium);
7984
8596
  cursor: pointer;
@@ -7999,8 +8611,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7999
8611
  [data-ui="pagination"] [data-part="page"]:focus-visible,
8000
8612
  [data-ui="pagination"] [data-part="prev"]:focus-visible,
8001
8613
  [data-ui="pagination"] [data-part="next"]:focus-visible {
8002
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8003
- outline-offset: 2px;
8614
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8615
+ outline-offset: var(--focus-ring-offset);
8004
8616
  }
8005
8617
 
8006
8618
  /* ── Active page ── */
@@ -8024,7 +8636,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8024
8636
  /* ── Disabled ── */
8025
8637
  [data-ui="pagination"] [data-part="prev"]:disabled,
8026
8638
  [data-ui="pagination"] [data-part="next"]:disabled {
8027
- opacity: 0.5;
8639
+ opacity: var(--disabled-opacity);
8028
8640
  cursor: not-allowed;
8029
8641
  pointer-events: none;
8030
8642
  }
@@ -8094,7 +8706,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8094
8706
 
8095
8707
  /* === recipes/popover.css === */
8096
8708
  /* @ui:component popover */
8097
- /* @ui:tokens color-bg color-fg color-border shadow-md radius-lg space-3 space-4 z-dropdown duration-fast ease-default */
8709
+ /* @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 */
8098
8710
 
8099
8711
  /* ── Root ── */
8100
8712
  [data-ui="popover"] {
@@ -8108,11 +8720,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8108
8720
  align-items: center;
8109
8721
  gap: var(--space-2, 0.5rem);
8110
8722
  padding: var(--space-2, 0.5rem) var(--space-3);
8111
- border: 1px solid var(--color-border);
8723
+ border: var(--border-width) solid var(--color-border);
8112
8724
  border-radius: var(--radius-md, 0.375rem);
8113
8725
  background: var(--color-bg);
8114
8726
  color: var(--color-fg);
8115
- font-family: var(--font-sans, system-ui, sans-serif);
8727
+ font-family: var(--font-ui);
8116
8728
  font-size: var(--text-sm, 0.875rem);
8117
8729
  font-weight: var(--weight-medium, 500);
8118
8730
  cursor: pointer;
@@ -8126,8 +8738,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8126
8738
  }
8127
8739
 
8128
8740
  [data-ui="popover"] [data-part="trigger"]:focus-visible {
8129
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8130
- outline-offset: 2px;
8741
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8742
+ outline-offset: var(--focus-ring-offset);
8131
8743
  }
8132
8744
 
8133
8745
  /* ── Content ── */
@@ -8136,9 +8748,9 @@ div[data-ui="separator"][data-style="thick"]::after {
8136
8748
  z-index: var(--z-dropdown);
8137
8749
  min-width: 200px;
8138
8750
  padding: var(--space-4);
8139
- border: 1px solid var(--color-border);
8751
+ border: var(--border-width) solid var(--color-border);
8140
8752
  border-radius: var(--radius-lg);
8141
- background: var(--color-bg);
8753
+ background: var(--panel-bg);
8142
8754
  color: var(--color-fg);
8143
8755
  box-shadow: var(--shadow-md);
8144
8756
  opacity: 0;
@@ -8147,6 +8759,13 @@ div[data-ui="separator"][data-style="thick"]::after {
8147
8759
  transform var(--duration-fast) var(--ease-default);
8148
8760
  }
8149
8761
 
8762
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
8763
+ [data-ui="popover"] [data-part="content"] {
8764
+ -webkit-backdrop-filter: var(--surface-backdrop);
8765
+ backdrop-filter: var(--surface-backdrop);
8766
+ }
8767
+ }
8768
+
8150
8769
  [data-ui="popover"][data-state="open"] [data-part="content"] {
8151
8770
  opacity: 1;
8152
8771
  transform: scale(1);
@@ -8234,8 +8853,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8234
8853
  position: absolute;
8235
8854
  width: 8px;
8236
8855
  height: 8px;
8237
- background: var(--color-bg);
8238
- border: 1px solid var(--color-border);
8856
+ background: var(--panel-bg);
8857
+ border: var(--border-width) solid var(--color-border);
8239
8858
  transform: rotate(45deg);
8240
8859
  }
8241
8860
 
@@ -8336,8 +8955,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8336
8955
  }
8337
8956
 
8338
8957
  [data-ui="popover"] [data-part="close"]:focus-visible {
8339
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8340
- outline-offset: 2px;
8958
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8959
+ outline-offset: var(--focus-ring-offset);
8341
8960
  }
8342
8961
 
8343
8962
  /* ── Motion ── */
@@ -8350,7 +8969,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8350
8969
 
8351
8970
  /* === recipes/qr-code.css === */
8352
8971
  /* @ui:component qr-code */
8353
- /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-sans space-2 */
8972
+ /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-body space-2 */
8354
8973
 
8355
8974
  /* ── Base ── */
8356
8975
  [data-ui="qr-code"] {
@@ -8368,7 +8987,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8368
8987
 
8369
8988
  /* ── Caption ── */
8370
8989
  [data-ui="qr-code"] [data-part="caption"] {
8371
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
8990
+ font-family: var(--doc-font, var(--font-body));
8372
8991
  font-size: var(--doc-legal-size, var(--text-xs));
8373
8992
  color: var(--doc-legal-color, var(--color-fg-muted));
8374
8993
  text-align: center;
@@ -8409,7 +9028,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8409
9028
 
8410
9029
  /* === recipes/select-custom.css === */
8411
9030
  /* @ui:component select-custom */
8412
- /* @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 */
9031
+ /* @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 */
8413
9032
 
8414
9033
  /* ── Root ── */
8415
9034
  [data-ui="select-custom"] {
@@ -8426,11 +9045,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8426
9045
  width: 100%;
8427
9046
  min-width: 180px;
8428
9047
  padding: var(--space-2) var(--space-3);
8429
- border: 1px solid var(--color-border);
9048
+ border: var(--border-width) solid var(--color-border);
8430
9049
  border-radius: var(--radius-md);
8431
9050
  background: var(--color-bg);
8432
9051
  color: var(--color-fg);
8433
- font-family: var(--font-sans, system-ui, sans-serif);
9052
+ font-family: var(--font-ui);
8434
9053
  font-size: var(--text-sm);
8435
9054
  cursor: pointer;
8436
9055
  white-space: nowrap;
@@ -8443,8 +9062,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8443
9062
  }
8444
9063
 
8445
9064
  [data-ui="select-custom"] [data-part="trigger"]:focus-visible {
8446
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8447
- outline-offset: 2px;
9065
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9066
+ outline-offset: var(--focus-ring-offset);
8448
9067
  }
8449
9068
 
8450
9069
  /* ── Value ── */
@@ -8480,7 +9099,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8480
9099
  z-index: var(--z-dropdown);
8481
9100
  margin-top: var(--space-1);
8482
9101
  padding: var(--space-1);
8483
- border: 1px solid var(--color-border);
9102
+ border: var(--border-width) solid var(--color-border);
8484
9103
  border-radius: var(--radius-lg);
8485
9104
  background: var(--color-bg);
8486
9105
  box-shadow: var(--shadow-md);
@@ -8504,11 +9123,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8504
9123
  padding: var(--space-2) var(--space-3);
8505
9124
  margin-bottom: var(--space-1);
8506
9125
  border: none;
8507
- border-bottom: 1px solid var(--color-border);
9126
+ border-bottom: var(--border-width) solid var(--color-border);
8508
9127
  border-radius: 0;
8509
9128
  background: transparent;
8510
9129
  color: var(--color-fg);
8511
- font-family: var(--font-sans, system-ui, sans-serif);
9130
+ font-family: var(--font-ui);
8512
9131
  font-size: var(--text-sm);
8513
9132
  outline: none;
8514
9133
  }
@@ -8602,7 +9221,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8602
9221
 
8603
9222
  /* === recipes/sheet.css === */
8604
9223
  /* @ui:component sheet */
8605
- /* @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 */
9224
+ /* @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 */
8606
9225
 
8607
9226
  /* ── Root ── */
8608
9227
  [data-ui="sheet"] {
@@ -8633,11 +9252,18 @@ div[data-ui="separator"][data-style="thick"]::after {
8633
9252
  z-index: var(--z-modal);
8634
9253
  display: flex;
8635
9254
  flex-direction: column;
8636
- background: var(--color-bg);
9255
+ background: var(--panel-bg);
8637
9256
  box-shadow: var(--shadow-xl);
8638
9257
  transition: transform var(--duration-slow) var(--ease-out);
8639
9258
  }
8640
9259
 
9260
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
9261
+ [data-ui="sheet"] [data-part="panel"] {
9262
+ -webkit-backdrop-filter: var(--surface-backdrop);
9263
+ backdrop-filter: var(--surface-backdrop);
9264
+ }
9265
+ }
9266
+
8641
9267
  /* ── Side: Bottom ── */
8642
9268
  [data-ui="sheet"] [data-part="panel"][data-variant="bottom"] {
8643
9269
  bottom: 0;
@@ -8665,7 +9291,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8665
9291
  bottom: 0;
8666
9292
  max-width: 100vw;
8667
9293
  border-radius: 0 var(--radius-xl) var(--radius-xl) 0;
8668
- border-inline-end: 1px solid var(--color-border);
9294
+ border-inline-end: var(--border-width) solid var(--color-border);
8669
9295
  transform: translateX(-100%);
8670
9296
  }
8671
9297
 
@@ -8676,7 +9302,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8676
9302
  bottom: 0;
8677
9303
  max-width: 100vw;
8678
9304
  border-radius: var(--radius-xl) 0 0 var(--radius-xl);
8679
- border-inline-start: 1px solid var(--color-border);
9305
+ border-inline-start: var(--border-width) solid var(--color-border);
8680
9306
  transform: translateX(100%);
8681
9307
  }
8682
9308
 
@@ -8753,6 +9379,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8753
9379
  /* ── Title ── */
8754
9380
  [data-ui="sheet"] [data-part="title"] {
8755
9381
  margin: 0;
9382
+ font-family: var(--font-heading);
8756
9383
  font-size: var(--text-lg, 1.125rem);
8757
9384
  font-weight: var(--weight-semibold, 600);
8758
9385
  color: var(--color-fg);
@@ -8787,8 +9414,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8787
9414
  }
8788
9415
 
8789
9416
  [data-ui="sheet"] [data-part="close"]:not([data-ui]):focus-visible {
8790
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8791
- outline-offset: 2px;
9417
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9418
+ outline-offset: var(--focus-ring-offset);
8792
9419
  }
8793
9420
 
8794
9421
  /* ── Body ── */
@@ -8809,7 +9436,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8809
9436
 
8810
9437
  /* === recipes/sidebar.css === */
8811
9438
  /* @ui:component sidebar */
8812
- /* @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 */
9439
+ /* @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 */
8813
9440
 
8814
9441
  /* ── Root ──
8815
9442
  The root owns the layout column from `md` up; the panel is the visual surface.
@@ -8853,7 +9480,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8853
9480
  flex-direction: column;
8854
9481
  gap: var(--space-2);
8855
9482
  background: var(--sidebar-bg);
8856
- border-inline-end: 1px solid var(--color-border);
9483
+ border-inline-end: var(--border-width) solid var(--color-border);
8857
9484
  border-start-end-radius: var(--radius-lg, 0.5rem);
8858
9485
  border-end-end-radius: var(--radius-lg, 0.5rem);
8859
9486
  box-shadow: var(--shadow-xl);
@@ -8934,8 +9561,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8934
9561
  }
8935
9562
 
8936
9563
  [data-ui="sidebar"] [data-part="trigger"]:focus-visible {
8937
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8938
- outline-offset: 2px;
9564
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9565
+ outline-offset: var(--focus-ring-offset);
8939
9566
  }
8940
9567
 
8941
9568
  /* ── Navigation ── */
@@ -8971,8 +9598,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8971
9598
  }
8972
9599
 
8973
9600
  [data-ui="sidebar"] [data-part="item"]:focus-visible {
8974
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8975
- outline-offset: -2px;
9601
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9602
+ outline-offset: calc(-1 * var(--focus-ring-offset));
8976
9603
  }
8977
9604
 
8978
9605
  [data-ui="sidebar"] [data-part="item"][aria-current="page"] {
@@ -8999,7 +9626,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8999
9626
  [data-ui="sidebar"] [data-part="footer"] {
9000
9627
  flex-shrink: 0;
9001
9628
  padding: var(--space-3) var(--space-4);
9002
- border-block-start: 1px solid var(--color-border);
9629
+ border-block-start: var(--border-width) solid var(--color-border);
9003
9630
  }
9004
9631
 
9005
9632
  /* ── Rail (icons only) ── */
@@ -9092,7 +9719,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9092
9719
 
9093
9720
  /* === recipes/slider.css === */
9094
9721
  /* @ui:component slider */
9095
- /* @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 */
9722
+ /* @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 */
9096
9723
 
9097
9724
  /* ── Root ── */
9098
9725
  [data-ui="slider"] {
@@ -9142,28 +9769,28 @@ div[data-ui="separator"][data-style="thick"]::after {
9142
9769
  value in both LTR and RTL (translateX is physical, so -50% always recentres). */
9143
9770
  transform: translate(-50%, -50%);
9144
9771
  background: var(--color-bg, white);
9145
- border: 2px solid var(--color-primary);
9772
+ border: var(--border-width-strong) solid var(--color-primary);
9146
9773
  border-radius: var(--radius-full, 9999px);
9147
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1));
9774
+ box-shadow: var(--shadow-sm);
9148
9775
  cursor: grab;
9149
9776
  touch-action: none;
9150
- transition: box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
9777
+ transition: box-shadow var(--duration-fast) var(--ease-default);
9151
9778
  }
9152
9779
 
9153
9780
  [data-ui="slider"] [data-part="thumb"]:hover {
9154
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9155
- 0 0 0 4px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9781
+ box-shadow: var(--shadow-sm),
9782
+ 0 0 0 4px var(--color-primary-subtle);
9156
9783
  }
9157
9784
 
9158
9785
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
9159
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9160
- outline-offset: 2px;
9786
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9787
+ outline-offset: var(--focus-ring-offset);
9161
9788
  }
9162
9789
 
9163
9790
  [data-ui="slider"] [data-part="thumb"][data-state="dragging"] {
9164
9791
  cursor: grabbing;
9165
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9166
- 0 0 0 5px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9792
+ box-shadow: var(--shadow-sm),
9793
+ 0 0 0 5px var(--color-primary-subtle);
9167
9794
  }
9168
9795
 
9169
9796
  /* ── Value output ── */
@@ -9171,7 +9798,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9171
9798
  flex: 0 0 auto;
9172
9799
  min-inline-size: 3ch;
9173
9800
  color: var(--color-fg-muted);
9174
- font-family: var(--font-sans, system-ui, sans-serif);
9801
+ font-family: var(--font-ui);
9175
9802
  font-size: var(--text-sm);
9176
9803
  font-variant-numeric: tabular-nums;
9177
9804
  text-align: end;
@@ -9190,7 +9817,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9190
9817
 
9191
9818
  /* ── Disabled ── */
9192
9819
  [data-ui="slider"][data-disabled] {
9193
- opacity: 0.5;
9820
+ opacity: var(--disabled-opacity);
9194
9821
  cursor: not-allowed;
9195
9822
  pointer-events: none;
9196
9823
  }
@@ -9208,7 +9835,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9208
9835
  the substitution so the control still reads as "this much, up to here". [W3-3] */
9209
9836
  @media (forced-colors: active) {
9210
9837
  [data-ui="slider"] [data-part="track"] {
9211
- border: 1px solid ButtonText;
9838
+ border: var(--border-width) solid ButtonText;
9212
9839
  }
9213
9840
 
9214
9841
  [data-ui="slider"] [data-part="range"] {
@@ -9219,7 +9846,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9219
9846
  [data-ui="slider"] [data-part="thumb"] {
9220
9847
  forced-color-adjust: none;
9221
9848
  background: ButtonText;
9222
- border: 1px solid ButtonFace;
9849
+ border: var(--border-width) solid ButtonFace;
9223
9850
  }
9224
9851
 
9225
9852
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
@@ -9229,7 +9856,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9229
9856
 
9230
9857
  /* === recipes/table.css === */
9231
9858
  /* @ui:component table */
9232
- /* @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 */
9859
+ /* @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 */
9233
9860
 
9234
9861
  /* ── Root ── */
9235
9862
  [data-ui="table"] {
@@ -9255,7 +9882,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9255
9882
  width: 100%;
9256
9883
  border-collapse: separate;
9257
9884
  border-spacing: 0;
9258
- font-family: var(--font-sans, system-ui, sans-serif);
9885
+ font-family: var(--font-body);
9259
9886
  }
9260
9887
 
9261
9888
  /* Once any column is resized the layout freezes so widths are exact. */
@@ -9277,7 +9904,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9277
9904
  font-weight: var(--weight-semibold);
9278
9905
  color: var(--color-fg-muted);
9279
9906
  background: var(--color-bg);
9280
- border-bottom: 2px solid var(--color-border);
9907
+ border-bottom: var(--border-width-strong) solid var(--color-border);
9281
9908
  white-space: nowrap;
9282
9909
  user-select: none;
9283
9910
  }
@@ -9335,8 +9962,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9335
9962
  /* Keyboard focus on cells (sortable headers + navigable grids). */
9336
9963
  [data-ui="table"] [data-part="th"]:focus-visible,
9337
9964
  [data-ui="table"] [data-part="td"]:focus-visible {
9338
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9339
- outline-offset: -2px;
9965
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9966
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9340
9967
  }
9341
9968
 
9342
9969
  /* ── Data Cell ── */
@@ -9344,7 +9971,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9344
9971
  padding: var(--space-3) var(--space-4);
9345
9972
  font-size: var(--text-sm);
9346
9973
  color: var(--color-fg);
9347
- border-bottom: 1px solid var(--color-border);
9974
+ border-bottom: var(--border-width) solid var(--color-border);
9348
9975
  background: var(--color-bg);
9349
9976
  transition: background var(--duration-fast) var(--ease-default);
9350
9977
  }
@@ -9373,31 +10000,31 @@ div[data-ui="separator"][data-style="thick"]::after {
9373
10000
  Static fallback via nth-child; once the controller stamps data-stripe on the
9374
10001
  visible rows (so hidden rows never break the pattern), the stamped rules win. */
9375
10002
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"]:not([data-stripe]):nth-child(even):not([data-selected]) [data-part="td"] {
9376
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
10003
+ background: var(--stripe-bg);
9377
10004
  }
9378
10005
 
9379
10006
  [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"] {
9380
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
10007
+ background: var(--stripe-bg);
9381
10008
  }
9382
10009
 
9383
10010
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]) [data-part="td"] {
9384
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
10011
+ background: var(--stripe-bg);
9385
10012
  }
9386
10013
 
9387
10014
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]):hover [data-part="td"] {
9388
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
10015
+ background: var(--stripe-bg);
9389
10016
  }
9390
10017
 
9391
10018
  /* ── Bordered Variant ── */
9392
10019
  [data-ui="table"][data-variant="bordered"] [data-part="table"] {
9393
- border: 1px solid var(--color-border);
10020
+ border: var(--border-width) solid var(--color-border);
9394
10021
  border-radius: var(--radius-md, 0.375rem);
9395
10022
  overflow: hidden;
9396
10023
  }
9397
10024
 
9398
10025
  [data-ui="table"][data-variant="bordered"] [data-part="th"],
9399
10026
  [data-ui="table"][data-variant="bordered"] [data-part="td"] {
9400
- border: 1px solid var(--color-border);
10027
+ border: var(--border-width) solid var(--color-border);
9401
10028
  }
9402
10029
 
9403
10030
  /* ── Size: Small ── */
@@ -9425,7 +10052,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9425
10052
  /* ── Footer ── */
9426
10053
  [data-ui="table"] [data-part="tfoot"] [data-part="td"] {
9427
10054
  font-weight: var(--doc-table-footer-weight, var(--weight-semibold));
9428
- border-top: 2px solid var(--color-border);
10055
+ border-top: var(--border-width-strong) solid var(--color-border);
9429
10056
  border-bottom: none;
9430
10057
  background: var(--doc-table-footer-bg, var(--color-bg-subtle, oklch(0.97 0.004 260)));
9431
10058
  }
@@ -9551,7 +10178,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9551
10178
  [data-ui="table"] [data-part="filter-row"] [data-part="th"] {
9552
10179
  padding: var(--space-1) var(--space-2);
9553
10180
  background: var(--color-bg);
9554
- border-bottom: 1px solid var(--color-border);
10181
+ border-bottom: var(--border-width) solid var(--color-border);
9555
10182
  }
9556
10183
 
9557
10184
  [data-ui="table"] [data-part="filter-input"],
@@ -9563,14 +10190,14 @@ div[data-ui="separator"][data-style="thick"]::after {
9563
10190
  font-size: var(--text-xs);
9564
10191
  color: var(--color-fg);
9565
10192
  background: var(--color-bg);
9566
- border: 1px solid var(--color-border);
10193
+ border: var(--border-width) solid var(--color-border);
9567
10194
  border-radius: var(--radius-sm);
9568
10195
  }
9569
10196
 
9570
10197
  [data-ui="table"] [data-part="filter-input"]:focus,
9571
10198
  [data-ui="table"] [data-part="filter"]:focus {
9572
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9573
- outline-offset: -1px;
10199
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10200
+ outline-offset: calc(-1 * var(--border-width));
9574
10201
  border-color: var(--color-primary);
9575
10202
  }
9576
10203
 
@@ -9591,7 +10218,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9591
10218
  text-align: inherit;
9592
10219
  color: var(--color-fg);
9593
10220
  background: var(--color-bg);
9594
- border: 1px solid var(--color-primary);
10221
+ border: var(--border-width) solid var(--color-primary);
9595
10222
  border-radius: var(--radius-sm);
9596
10223
  outline: none;
9597
10224
  }
@@ -9644,11 +10271,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9644
10271
  }
9645
10272
 
9646
10273
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="before"] [data-part="td"] {
9647
- border-block-start: 2px solid var(--color-primary);
10274
+ border-block-start: var(--border-width-strong) solid var(--color-primary);
9648
10275
  }
9649
10276
 
9650
10277
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="after"] [data-part="td"] {
9651
- border-block-end: 2px solid var(--color-primary);
10278
+ border-block-end: var(--border-width-strong) solid var(--color-primary);
9652
10279
  }
9653
10280
 
9654
10281
  [data-ui="table"] [data-part="th"][data-dragging] {
@@ -9656,11 +10283,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9656
10283
  }
9657
10284
 
9658
10285
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="before"] {
9659
- border-inline-start: 2px solid var(--color-primary);
10286
+ border-inline-start: var(--border-width-strong) solid var(--color-primary);
9660
10287
  }
9661
10288
 
9662
10289
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="after"] {
9663
- border-inline-end: 2px solid var(--color-primary);
10290
+ border-inline-end: var(--border-width-strong) solid var(--color-primary);
9664
10291
  }
9665
10292
 
9666
10293
  /* ── Column Resize Handles (injected by the controller) ── */
@@ -9733,11 +10360,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9733
10360
  }
9734
10361
 
9735
10362
  [data-ui="table"] [data-pin="start"][data-pin-edge] {
9736
- border-inline-end: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10363
+ border-inline-end: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9737
10364
  }
9738
10365
 
9739
10366
  [data-ui="table"] [data-pin="end"][data-pin-edge] {
9740
- border-inline-start: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10367
+ border-inline-start: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9741
10368
  }
9742
10369
 
9743
10370
  /* ── Column Visibility ── */
@@ -9809,7 +10436,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9809
10436
  [data-ui="table"][data-stacked] [data-part="tfoot"] [data-part="tr"] {
9810
10437
  display: block;
9811
10438
  margin-block-end: var(--space-3);
9812
- border: 1px solid var(--color-border);
10439
+ border: var(--border-width) solid var(--color-border);
9813
10440
  border-radius: var(--radius-md);
9814
10441
  background: var(--color-bg);
9815
10442
  overflow: hidden;
@@ -9823,7 +10450,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9823
10450
  gap: var(--space-4);
9824
10451
  text-align: end;
9825
10452
  border-bottom: none;
9826
- border-block-end: 1px solid var(--color-border);
10453
+ border-block-end: var(--border-width) solid var(--color-border);
9827
10454
  }
9828
10455
 
9829
10456
  [data-ui="table"][data-stacked] [data-part="tr"] [data-part="td"]:last-child,
@@ -9920,7 +10547,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9920
10547
 
9921
10548
  /* === recipes/tabs.css === */
9922
10549
  /* @ui:component tabs */
9923
- /* @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 */
10550
+ /* @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 */
9924
10551
 
9925
10552
  /* ── Root ── */
9926
10553
  [data-ui="tabs"] {
@@ -9949,7 +10576,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9949
10576
  border: none;
9950
10577
  background: transparent;
9951
10578
  color: var(--color-fg-muted);
9952
- font-family: var(--font-sans, system-ui, sans-serif);
10579
+ font-family: var(--font-ui);
9953
10580
  font-size: var(--text-sm);
9954
10581
  font-weight: var(--weight-medium);
9955
10582
  cursor: pointer;
@@ -9964,8 +10591,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9964
10591
  }
9965
10592
 
9966
10593
  [data-ui="tabs"] [data-part="trigger"]:focus-visible {
9967
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9968
- outline-offset: -2px;
10594
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10595
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9969
10596
  border-radius: var(--radius-md);
9970
10597
  }
9971
10598
 
@@ -9975,12 +10602,12 @@ div[data-ui="separator"][data-style="thick"]::after {
9975
10602
 
9976
10603
  /* ── Underline Variant ── */
9977
10604
  [data-ui="tabs"][data-variant="underline"] [data-part="list"] {
9978
- border-bottom: 1px solid var(--color-border);
10605
+ border-bottom: var(--border-width) solid var(--color-border);
9979
10606
  gap: 0;
9980
10607
  }
9981
10608
 
9982
10609
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"] {
9983
- border-bottom: 2px solid transparent;
10610
+ border-bottom: var(--border-width-strong) solid transparent;
9984
10611
  margin-bottom: -1px;
9985
10612
  border-radius: 0;
9986
10613
  }
@@ -10012,17 +10639,17 @@ div[data-ui="separator"][data-style="thick"]::after {
10012
10639
  [data-ui="tabs"][data-variant="pill"] [data-part="trigger"][aria-selected="true"] {
10013
10640
  background: var(--color-bg);
10014
10641
  color: var(--color-fg);
10015
- box-shadow: var(--shadow-xs, 0 1px 2px oklch(0 0 0 / 0.04));
10642
+ box-shadow: var(--shadow-xs);
10016
10643
  }
10017
10644
 
10018
10645
  /* ── Enclosed Variant ── */
10019
10646
  [data-ui="tabs"][data-variant="enclosed"] [data-part="list"] {
10020
- border-bottom: 1px solid var(--color-border);
10647
+ border-bottom: var(--border-width) solid var(--color-border);
10021
10648
  gap: 0;
10022
10649
  }
10023
10650
 
10024
10651
  [data-ui="tabs"][data-variant="enclosed"] [data-part="trigger"] {
10025
- border: 1px solid transparent;
10652
+ border: var(--border-width) solid transparent;
10026
10653
  border-bottom: none;
10027
10654
  border-radius: var(--radius-md) var(--radius-md) 0 0;
10028
10655
  margin-bottom: -1px;
@@ -10067,8 +10694,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10067
10694
  @media (forced-colors: active) {
10068
10695
  [data-ui="tabs"] [data-part="trigger"][aria-selected="true"] {
10069
10696
  /* An outline the OS preserves, on every variant. */
10070
- outline: 2px solid Highlight;
10071
- outline-offset: -2px;
10697
+ outline: var(--border-width-strong) solid Highlight;
10698
+ outline-offset: calc(-1 * var(--border-width-strong));
10072
10699
  }
10073
10700
 
10074
10701
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"][aria-selected="true"] {
@@ -10083,7 +10710,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10083
10710
 
10084
10711
  /* === recipes/tag-input.css === */
10085
10712
  /* @ui:component tag-input */
10086
- /* @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 */
10713
+ /* @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 */
10087
10714
 
10088
10715
  /* NOTE: the tags themselves are `data-ui="chip"` elements — their styling comes
10089
10716
  entirely from chip.css. This file styles only the field wrapper, the tag row,
@@ -10104,7 +10731,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10104
10731
  gap: var(--space-1h);
10105
10732
  width: 100%;
10106
10733
  padding: var(--space-1h) var(--space-2);
10107
- border: 1px solid var(--color-border);
10734
+ border: var(--border-width) solid var(--color-border);
10108
10735
  border-radius: var(--radius-md);
10109
10736
  background: var(--color-bg);
10110
10737
  list-style: none;
@@ -10113,8 +10740,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10113
10740
  }
10114
10741
 
10115
10742
  [data-ui="tag-input"] [data-part="taglist"]:focus-within {
10116
- border-color: var(--color-ring, oklch(0.55 0.22 264));
10117
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
10743
+ border-color: var(--focus-ring-color);
10744
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
10118
10745
  }
10119
10746
 
10120
10747
  /* ── Text input: borderless, grows to fill the remaining row space ── */
@@ -10125,7 +10752,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10125
10752
  border: none;
10126
10753
  background: transparent;
10127
10754
  color: var(--color-fg);
10128
- font-family: var(--font-sans, system-ui, sans-serif);
10755
+ font-family: var(--font-ui);
10129
10756
  font-size: var(--text-sm);
10130
10757
  line-height: 1.5;
10131
10758
  outline: none;
@@ -10144,7 +10771,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10144
10771
  z-index: var(--z-dropdown);
10145
10772
  margin-top: var(--space-1);
10146
10773
  padding: var(--space-1);
10147
- border: 1px solid var(--color-border);
10774
+ border: var(--border-width) solid var(--color-border);
10148
10775
  border-radius: var(--radius-lg);
10149
10776
  background: var(--color-bg);
10150
10777
  box-shadow: var(--shadow-md);
@@ -10191,7 +10818,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10191
10818
 
10192
10819
  /* === recipes/toast.css === */
10193
10820
  /* @ui:component toast */
10194
- /* @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 */
10821
+ /* @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 */
10195
10822
 
10196
10823
  /* ── Container ── */
10197
10824
  [data-ui="toast"][data-part="container"] {
@@ -10240,8 +10867,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10240
10867
  max-width: 380px;
10241
10868
  width: max-content;
10242
10869
  padding: var(--space-3) var(--space-4);
10243
- background: var(--color-bg);
10244
- border: 1px solid var(--color-border);
10870
+ background: var(--panel-bg);
10871
+ border: var(--border-width) solid var(--color-border);
10245
10872
  border-radius: var(--radius-lg);
10246
10873
  box-shadow: var(--shadow-lg);
10247
10874
  pointer-events: auto;
@@ -10251,6 +10878,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10251
10878
  transform var(--duration-normal) var(--ease-out);
10252
10879
  }
10253
10880
 
10881
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
10882
+ [data-ui="toast"] [data-part="toast"] {
10883
+ -webkit-backdrop-filter: var(--surface-backdrop);
10884
+ backdrop-filter: var(--surface-backdrop);
10885
+ }
10886
+ }
10887
+
10254
10888
  /* ── State: Entering ── */
10255
10889
  [data-ui="toast"][data-variant="top-right"] [data-part="toast"][data-state="entering"],
10256
10890
  [data-ui="toast"][data-variant="top-left"] [data-part="toast"][data-state="entering"] {
@@ -10290,7 +10924,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10290
10924
 
10291
10925
  /* ── Tone Variants ── */
10292
10926
  [data-ui="toast"] [data-part="toast"][data-variant="success"] {
10293
- border-inline-start: 3px solid var(--color-success, oklch(0.55 0.18 145));
10927
+ border-inline-start: var(--border-width-lg) solid var(--color-success, oklch(0.55 0.18 145));
10294
10928
  }
10295
10929
 
10296
10930
  [data-ui="toast"] [data-part="toast"][data-variant="success"] [data-part="icon"] {
@@ -10298,7 +10932,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10298
10932
  }
10299
10933
 
10300
10934
  [data-ui="toast"] [data-part="toast"][data-variant="error"] {
10301
- border-inline-start: 3px solid var(--color-destructive, oklch(0.55 0.22 25));
10935
+ border-inline-start: var(--border-width-lg) solid var(--color-destructive, oklch(0.55 0.22 25));
10302
10936
  }
10303
10937
 
10304
10938
  [data-ui="toast"] [data-part="toast"][data-variant="error"] [data-part="icon"] {
@@ -10306,7 +10940,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10306
10940
  }
10307
10941
 
10308
10942
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] {
10309
- border-inline-start: 3px solid var(--color-warning, oklch(0.7 0.18 85));
10943
+ border-inline-start: var(--border-width-lg) solid var(--color-warning, oklch(0.7 0.18 85));
10310
10944
  }
10311
10945
 
10312
10946
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] [data-part="icon"] {
@@ -10328,7 +10962,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10328
10962
  /* ── Message ── */
10329
10963
  [data-ui="toast"] [data-part="message"] {
10330
10964
  flex: 1;
10331
- font-family: var(--font-sans, system-ui, sans-serif);
10965
+ font-family: var(--font-ui);
10332
10966
  font-size: var(--text-sm);
10333
10967
  font-weight: var(--weight-medium);
10334
10968
  color: var(--color-fg);
@@ -10339,11 +10973,11 @@ div[data-ui="separator"][data-style="thick"]::after {
10339
10973
  [data-ui="toast"] [data-part="action"] {
10340
10974
  flex-shrink: 0;
10341
10975
  padding: var(--space-1, 0.25rem) var(--space-2);
10342
- border: 1px solid var(--color-border);
10976
+ border: var(--border-width) solid var(--color-border);
10343
10977
  border-radius: var(--radius-md, 0.375rem);
10344
10978
  background: transparent;
10345
10979
  color: var(--color-fg);
10346
- font-family: var(--font-sans, system-ui, sans-serif);
10980
+ font-family: var(--font-ui);
10347
10981
  font-size: var(--text-xs, 0.75rem);
10348
10982
  font-weight: var(--weight-medium);
10349
10983
  cursor: pointer;
@@ -10356,8 +10990,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10356
10990
  }
10357
10991
 
10358
10992
  [data-ui="toast"] [data-part="action"]:focus-visible {
10359
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10360
- outline-offset: 2px;
10993
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10994
+ outline-offset: var(--focus-ring-offset);
10361
10995
  }
10362
10996
 
10363
10997
  /* ── Close Button ── */
@@ -10383,8 +11017,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10383
11017
  }
10384
11018
 
10385
11019
  [data-ui="toast"] [data-part="close"]:focus-visible {
10386
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10387
- outline-offset: 2px;
11020
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11021
+ outline-offset: var(--focus-ring-offset);
10388
11022
  }
10389
11023
 
10390
11024
  /* ── Motion ── */
@@ -10397,14 +11031,14 @@ div[data-ui="separator"][data-style="thick"]::after {
10397
11031
 
10398
11032
  /* === recipes/toggle-group.css === */
10399
11033
  /* @ui:component toggle-group */
10400
- /* @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 */
11034
+ /* @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 */
10401
11035
 
10402
11036
  /* ── Root: a segmented row of toggle buttons ── */
10403
11037
  [data-ui="toggle-group"] {
10404
11038
  display: inline-flex;
10405
11039
  gap: var(--space-1);
10406
11040
  padding: var(--space-1);
10407
- border: 1px solid var(--color-border);
11041
+ border: var(--border-width) solid var(--color-border);
10408
11042
  border-radius: var(--radius-md);
10409
11043
  background: var(--color-bg);
10410
11044
  }
@@ -10419,7 +11053,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10419
11053
  border-radius: var(--radius-md);
10420
11054
  background: transparent;
10421
11055
  color: var(--color-fg-muted);
10422
- font-family: var(--toggle-group-font, var(--font-sans));
11056
+ font-family: var(--toggle-group-font, var(--font-ui));
10423
11057
  font-size: var(--text-sm);
10424
11058
  font-weight: var(--weight-medium);
10425
11059
  line-height: 1;
@@ -10460,13 +11094,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10460
11094
 
10461
11095
  /* ── Keyboard focus ring on the item (focus lives on the hidden control) ── */
10462
11096
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:focus-visible) {
10463
- outline: 2px solid var(--color-ring);
10464
- outline-offset: 2px;
11097
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11098
+ outline-offset: var(--focus-ring-offset);
10465
11099
  }
10466
11100
 
10467
11101
  /* ── Disabled control ── */
10468
11102
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:disabled) {
10469
- opacity: 0.5;
11103
+ opacity: var(--disabled-opacity);
10470
11104
  cursor: not-allowed;
10471
11105
  }
10472
11106
 
@@ -10479,7 +11113,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10479
11113
 
10480
11114
  /* === recipes/tooltip.css === */
10481
11115
  /* @ui:component tooltip */
10482
- /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default */
11116
+ /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default font-ui surface-backdrop */
10483
11117
 
10484
11118
  /* ── Root ── */
10485
11119
  [data-ui="tooltip"] {
@@ -10500,7 +11134,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10500
11134
  color: var(--color-bg);
10501
11135
  border-radius: var(--radius-md);
10502
11136
  padding: var(--space-1h, 0.375rem) var(--space-2);
10503
- font-family: var(--font-sans, system-ui, sans-serif);
11137
+ font-family: var(--font-ui);
10504
11138
  font-size: var(--text-xs, 0.75rem);
10505
11139
  line-height: 1.4;
10506
11140
  white-space: nowrap;
@@ -10511,6 +11145,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10511
11145
  transform var(--duration-fast) var(--ease-default);
10512
11146
  }
10513
11147
 
11148
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
11149
+ [data-ui="tooltip"] [data-part="content"] {
11150
+ -webkit-backdrop-filter: var(--surface-backdrop);
11151
+ backdrop-filter: var(--surface-backdrop);
11152
+ }
11153
+ }
11154
+
10514
11155
  /* Default position (top) when no variant is specified */
10515
11156
  [data-ui="tooltip"]:not([data-variant]) [data-part="content"] {
10516
11157
  bottom: 100%;
@@ -10626,7 +11267,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10626
11267
 
10627
11268
  /* === recipes/tree-view.css === */
10628
11269
  /* @ui:component tree-view */
10629
- /* @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 */
11270
+ /* @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 */
10630
11271
 
10631
11272
  [data-ui="tree-view"],
10632
11273
  [data-ui="tree-view"] [data-part="group"] {
@@ -10639,7 +11280,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10639
11280
  inline-size: 100%;
10640
11281
  padding: var(--space-1);
10641
11282
  color: var(--color-fg);
10642
- font-family: var(--font-sans);
11283
+ font-family: var(--font-ui);
10643
11284
  font-size: var(--text-sm);
10644
11285
  }
10645
11286
 
@@ -10667,8 +11308,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10667
11308
  }
10668
11309
 
10669
11310
  [data-ui="tree-view"] [data-part="item"]:focus-visible > [data-part="label"] {
10670
- outline: var(--space-px) solid var(--color-ring);
10671
- outline-offset: var(--space-px);
11311
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11312
+ outline-offset: var(--focus-ring-offset);
10672
11313
  }
10673
11314
 
10674
11315
  [data-ui="tree-view"] [data-part="item"][aria-selected="true"] > [data-part="label"] {
@@ -10707,7 +11348,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10707
11348
 
10708
11349
  /* === patterns/auth-form.css === */
10709
11350
  /* @ui:component auth-form */
10710
- /* @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 */
11351
+ /* @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 */
10711
11352
 
10712
11353
  /* ── Root Container ── */
10713
11354
  [data-ui="auth-form"] {
@@ -10715,7 +11356,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10715
11356
  align-items: center;
10716
11357
  justify-content: center;
10717
11358
  width: 100%;
10718
- font-family: var(--font-sans);
11359
+ font-family: var(--font-body);
10719
11360
  }
10720
11361
 
10721
11362
  /* Mobile-first (task 0.8-09): on a phone the card IS the page — edge to edge,
@@ -10747,9 +11388,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10747
11388
 
10748
11389
  [data-ui="auth-form"] [data-part="title"] {
10749
11390
  margin: 0;
11391
+ font-family: var(--font-heading);
10750
11392
  font-size: var(--text-xl);
10751
- font-weight: var(--weight-bold);
10752
- line-height: var(--leading-tight);
11393
+ font-weight: var(--heading-weight);
11394
+ letter-spacing: var(--heading-tracking);
11395
+ text-transform: var(--heading-transform);
11396
+ font-variant-caps: var(--heading-caps);
11397
+ line-height: var(--heading-leading);
10753
11398
  color: var(--color-fg);
10754
11399
  }
10755
11400
 
@@ -10766,7 +11411,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10766
11411
  margin: var(--space-4) var(--space-6) 0;
10767
11412
  padding: var(--space-3);
10768
11413
  background: var(--color-destructive-subtle);
10769
- border: 1px solid var(--color-destructive);
11414
+ border: var(--border-width) solid var(--color-destructive);
10770
11415
  border-radius: var(--radius-lg);
10771
11416
  color: var(--color-destructive);
10772
11417
  font-size: var(--text-sm);
@@ -10844,13 +11489,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10844
11489
  }
10845
11490
 
10846
11491
  [data-ui="auth-form"] [data-part="footer"] a:hover {
10847
- text-decoration: underline;
11492
+ text-decoration-line: var(--link-decoration);
10848
11493
  color: var(--color-primary-hover);
10849
11494
  }
10850
11495
 
10851
11496
  [data-ui="auth-form"] [data-part="footer"] a:focus-visible {
10852
- outline: 2px solid var(--color-ring);
10853
- outline-offset: 2px;
11497
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11498
+ outline-offset: var(--focus-ring-offset);
10854
11499
  border-radius: var(--radius-sm, 0.25rem);
10855
11500
  }
10856
11501
 
@@ -10978,8 +11623,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10978
11623
  max-width: var(--auth-form-max-width, 400px);
10979
11624
  border-radius: var(--card-radius, var(--radius-lg));
10980
11625
  box-shadow: var(--card-shadow, var(--shadow-sm));
10981
- border-inline-start: 1px solid var(--card-border, var(--color-border));
10982
- border-inline-end: 1px solid var(--card-border, var(--color-border));
11626
+ border-inline-start: var(--border-width) solid var(--card-border, var(--color-border));
11627
+ border-inline-end: var(--border-width) solid var(--card-border, var(--color-border));
10983
11628
  }
10984
11629
  }
10985
11630
 
@@ -10994,7 +11639,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10994
11639
 
10995
11640
  /* === patterns/crud-table.css === */
10996
11641
  /* @ui:component crud-table */
10997
- /* @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 */
11642
+ /* @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 */
10998
11643
 
10999
11644
  /* ── Root ── */
11000
11645
  [data-ui="crud-table"] {
@@ -11002,7 +11647,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11002
11647
  flex-direction: column;
11003
11648
  gap: var(--space-4);
11004
11649
  width: 100%;
11005
- font-family: var(--font-sans, system-ui, sans-serif);
11650
+ font-family: var(--font-body);
11006
11651
  }
11007
11652
 
11008
11653
  /* ── Toolbar ── */
@@ -11060,7 +11705,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11060
11705
  gap: var(--space-3);
11061
11706
  padding: var(--space-3) var(--space-4);
11062
11707
  background: var(--color-bg-subtle);
11063
- border: 1px solid var(--color-border);
11708
+ border: var(--border-width) solid var(--color-border);
11064
11709
  border-radius: var(--radius-md);
11065
11710
  }
11066
11711
 
@@ -11075,7 +11720,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11075
11720
  [data-ui="crud-table"] [data-part="table-wrapper"] {
11076
11721
  width: 100%;
11077
11722
  overflow-x: auto;
11078
- border: 1px solid var(--color-border);
11723
+ border: var(--border-width) solid var(--color-border);
11079
11724
  border-radius: var(--radius-lg);
11080
11725
  background: var(--color-bg);
11081
11726
  }
@@ -11105,7 +11750,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11105
11750
  padding: var(--space-8) var(--space-4);
11106
11751
  text-align: center;
11107
11752
  min-height: 240px;
11108
- border: 1px dashed var(--color-border);
11753
+ border: var(--border-width) dashed var(--color-border);
11109
11754
  border-radius: var(--radius-lg);
11110
11755
  background: var(--color-bg);
11111
11756
  }
@@ -11218,7 +11863,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11218
11863
 
11219
11864
  /* === patterns/dashboard-shell.css === */
11220
11865
  /* @ui:component dashboard-shell */
11221
- /* @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 */
11866
+ /* @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 */
11222
11867
 
11223
11868
  /* ── Shell Grid Layout ──
11224
11869
  Mobile-first (task 0.8-09): the base is the PHONE shell — one column, header
@@ -11243,7 +11888,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11243
11888
  "footer";
11244
11889
  min-height: 100vh;
11245
11890
  background: var(--color-bg);
11246
- font-family: var(--font-sans);
11891
+ font-family: var(--font-body);
11247
11892
  color: var(--color-fg);
11248
11893
  }
11249
11894
 
@@ -11267,7 +11912,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11267
11912
  gap: var(--space-2);
11268
11913
  padding: var(--space-4);
11269
11914
  background: var(--color-bg-subtle);
11270
- border-inline-end: 1px solid var(--color-border);
11915
+ border-inline-end: var(--border-width) solid var(--color-border);
11271
11916
  overflow-y: auto;
11272
11917
  position: fixed;
11273
11918
  top: 0;
@@ -11287,7 +11932,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11287
11932
 
11288
11933
  [data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"] {
11289
11934
  border-inline-end: none;
11290
- border-inline-start: 1px solid var(--color-border);
11935
+ border-inline-start: var(--border-width) solid var(--color-border);
11291
11936
  inset-inline-start: auto;
11292
11937
  inset-inline-end: 0;
11293
11938
  transform: translateX(100%);
@@ -11362,7 +12007,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11362
12007
  gap: var(--space-3);
11363
12008
  padding: var(--space-2) var(--space-3);
11364
12009
  border-radius: var(--radius-md);
11365
- font-family: var(--font-sans);
12010
+ font-family: var(--font-ui);
11366
12011
  font-size: var(--text-sm);
11367
12012
  font-weight: var(--weight-medium);
11368
12013
  line-height: var(--leading-normal);
@@ -11381,8 +12026,8 @@ div[data-ui="separator"][data-style="thick"]::after {
11381
12026
  }
11382
12027
 
11383
12028
  [data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"]:focus-visible {
11384
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
11385
- outline-offset: -2px;
12029
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
12030
+ outline-offset: calc(-1 * var(--focus-ring-offset));
11386
12031
  }
11387
12032
 
11388
12033
  /* ── Nav Item Active ── */
@@ -11429,7 +12074,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11429
12074
  gap: var(--space-2);
11430
12075
  padding: 0 var(--space-3);
11431
12076
  background: var(--color-bg);
11432
- border-bottom: 1px solid var(--color-border);
12077
+ border-bottom: var(--border-width) solid var(--color-border);
11433
12078
  position: sticky;
11434
12079
  top: 0;
11435
12080
  z-index: var(--z-sticky);
@@ -11510,7 +12155,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11510
12155
  align-items: center;
11511
12156
  gap: var(--space-3);
11512
12157
  padding: var(--space-4) var(--space-6);
11513
- border-top: 1px solid var(--color-border);
12158
+ border-top: var(--border-width) solid var(--color-border);
11514
12159
  font-size: var(--text-xs);
11515
12160
  color: var(--color-fg-muted);
11516
12161
  }
@@ -11593,7 +12238,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11593
12238
 
11594
12239
  /* === patterns/document.css === */
11595
12240
  /* @ui:component document */
11596
- /* @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 */
12241
+ /* @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 */
11597
12242
 
11598
12243
  /* ── Page Rules ── */
11599
12244
  @page {
@@ -11633,14 +12278,17 @@ div[data-ui="separator"][data-style="thick"]::after {
11633
12278
  max-width: var(--doc-max-width);
11634
12279
  margin: var(--space-4) auto;
11635
12280
  padding: var(--space-6) var(--space-4);
11636
- background: var(--color-bg, #fff);
12281
+ background-color: var(--color-bg, #fff);
12282
+ background-image: var(--texture-page);
11637
12283
  color: var(--color-fg);
11638
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
12284
+ font-family: var(--doc-font, var(--font-body));
11639
12285
  font-size: var(--doc-font-size);
11640
12286
  line-height: var(--doc-line-height);
11641
- box-shadow: var(--shadow-lg,
11642
- 0 10px 15px -3px rgba(0, 0, 0, 0.1),
11643
- 0 4px 6px -4px rgba(0, 0, 0, 0.1));
12287
+ /* The fallback here used to spell out two rgba() layers, which is a shadow
12288
+ colour no theme could reach. --shadow-lg is always defined by the token
12289
+ layer, and it now carries --shadow-color, so the fallback is gone rather
12290
+ than re-tokenised. */
12291
+ box-shadow: var(--shadow-lg);
11644
12292
  border-radius: 0;
11645
12293
  position: relative;
11646
12294
  }
@@ -11656,7 +12304,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11656
12304
  [data-ui="document"] > [data-part="header"] {
11657
12305
  margin-block-end: var(--doc-section-gap);
11658
12306
  padding-block-end: var(--doc-component-gap);
11659
- border-block-end: 1px solid var(--color-border);
12307
+ border-block-end: var(--border-width) solid var(--color-border);
11660
12308
  }
11661
12309
 
11662
12310
  /* ── Body ── */
@@ -11666,13 +12314,25 @@ div[data-ui="separator"][data-style="thick"]::after {
11666
12314
  gap: var(--doc-section-gap);
11667
12315
  }
11668
12316
 
12317
+ /* ── Headings ──
12318
+ The document's own heading face and weight (1.1A-21): a print theme sets
12319
+ --doc-heading-font / --doc-heading-weight to give its titles a voice apart
12320
+ from the body copy (document-serif's Times titles over Georgia text). Both
12321
+ default to the page's heading role in tokens/document.css, and each falls
12322
+ back to what a heading rendered before the tokens had a reader. A heading
12323
+ that carries its own data-weight keeps it — that is the author asking. */
12324
+ [data-ui="document"] :is(h1, h2, h3, h4, h5, h6) {
12325
+ font-family: var(--doc-heading-font, var(--font-body));
12326
+ font-weight: var(--doc-heading-weight, var(--weight-bold));
12327
+ }
12328
+
11669
12329
  /* ── Running footer ──
11670
12330
  footer remains a non-breaking selector alias for pre-1.1.0 documents. */
11671
12331
  [data-ui="document"] > [data-part="doc-footer"],
11672
12332
  [data-ui="document"] > [data-part="footer"] {
11673
12333
  margin-block-start: var(--doc-section-gap);
11674
12334
  padding-block-start: var(--doc-component-gap);
11675
- border-block-start: 1px solid var(--color-border);
12335
+ border-block-start: var(--border-width) solid var(--color-border);
11676
12336
  font-size: var(--doc-legal-size);
11677
12337
  color: var(--doc-legal-color);
11678
12338
  }
@@ -11710,7 +12370,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11710
12370
 
11711
12371
  /* ── Variant: Report ── */
11712
12372
  [data-ui="document"][data-variant="report"] {
11713
- font-family: var(--font-serif, Georgia, "Times New Roman", serif);
12373
+ /* A report is serif-set by definition. It re-points the document's own font
12374
+ ROLE rather than its `font-family`, so every doc primitive nested inside it
12375
+ (key-value, callout, signature — all of which read --doc-font) follows the
12376
+ report into serif instead of staying sans inside a serif page. `report` is
12377
+ the author asking for serif; a theme that wants its own document face
12378
+ declares --doc-font at :root, which this variant deliberately outranks. */
12379
+ --doc-font: Georgia, 'Times New Roman', serif;
11714
12380
  line-height: 1.6;
11715
12381
  }
11716
12382
 
@@ -11805,7 +12471,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11805
12471
  z-index: var(--z-raised);
11806
12472
  margin-block-end: 0;
11807
12473
  padding-block-end: var(--doc-running-gap);
11808
- border-block-end: 1px solid var(--doc-print-border-color);
12474
+ border-block-end: var(--border-width) solid var(--doc-print-border-color);
11809
12475
  background: var(--doc-bg);
11810
12476
  transform: translateZ(0);
11811
12477
  }
@@ -11821,7 +12487,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11821
12487
  z-index: var(--z-raised);
11822
12488
  margin-block-start: 0;
11823
12489
  padding-block-start: var(--doc-running-gap);
11824
- border-block-start: 1px solid var(--doc-print-border-color);
12490
+ border-block-start: var(--border-width) solid var(--doc-print-border-color);
11825
12491
  background: var(--doc-bg);
11826
12492
  transform: translateZ(0);
11827
12493
  }
@@ -11850,7 +12516,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11850
12516
 
11851
12517
  /* === patterns/empty-state.css === */
11852
12518
  /* @ui:component empty-state */
11853
- /* @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 */
12519
+ /* @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 */
11854
12520
 
11855
12521
  /* ── Root ── */
11856
12522
  [data-ui="empty-state"] {
@@ -11861,7 +12527,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11861
12527
  text-align: center;
11862
12528
  padding: var(--space-8) var(--space-6);
11863
12529
  gap: var(--space-3);
11864
- font-family: var(--font-sans, system-ui, sans-serif);
12530
+ font-family: var(--font-body);
11865
12531
  }
11866
12532
 
11867
12533
  /* ── Icon ── */
@@ -11884,10 +12550,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11884
12550
 
11885
12551
  /* ── Title ── */
11886
12552
  [data-ui="empty-state"] [data-part="title"] {
11887
- font-family: var(--font-sans, system-ui, sans-serif);
12553
+ font-family: var(--font-heading);
11888
12554
  font-size: var(--text-lg);
11889
12555
  font-weight: var(--weight-semibold);
11890
- line-height: var(--leading-tight);
12556
+ letter-spacing: var(--heading-tracking);
12557
+ text-transform: var(--heading-transform);
12558
+ font-variant-caps: var(--heading-caps);
12559
+ line-height: var(--heading-leading);
11891
12560
  color: var(--color-fg);
11892
12561
  margin: 0;
11893
12562
  }
@@ -11985,7 +12654,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11985
12654
 
11986
12655
  /* === patterns/feature-grid.css === */
11987
12656
  /* @ui:component feature-grid */
11988
- /* @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 */
12657
+ /* @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 */
11989
12658
 
11990
12659
  /* ── Root ──
11991
12660
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -11995,7 +12664,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11995
12664
  gap: var(--space-4);
11996
12665
  padding-block: var(--space-12);
11997
12666
  padding-inline: var(--space-4);
11998
- font-family: var(--font-sans, system-ui, sans-serif);
12667
+ font-family: var(--font-body);
11999
12668
  color: var(--color-fg);
12000
12669
  background: var(--color-bg);
12001
12670
  }
@@ -12137,7 +12806,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12137
12806
  max-inline-size: var(--measure-narrow);
12138
12807
  margin-inline: auto;
12139
12808
  padding-block: var(--space-8);
12140
- font-family: var(--font-sans);
12809
+ font-family: var(--font-body);
12141
12810
  }
12142
12811
 
12143
12812
  :where(form[l-data]:not([data-ui]) > h1) {
@@ -12157,7 +12826,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12157
12826
 
12158
12827
  /* === patterns/hero.css === */
12159
12828
  /* @ui:component hero */
12160
- /* @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 */
12829
+ /* @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 */
12161
12830
 
12162
12831
  /* ── Root ──
12163
12832
  A one-column grid by default; the layout variants only change how that grid
@@ -12171,9 +12840,10 @@ div[data-ui="separator"][data-style="thick"]::after {
12171
12840
  gap: var(--space-4);
12172
12841
  padding-block: var(--space-12);
12173
12842
  padding-inline: var(--space-4);
12174
- font-family: var(--font-sans, system-ui, sans-serif);
12843
+ font-family: var(--font-body);
12175
12844
  color: var(--color-fg);
12176
- background: var(--color-bg);
12845
+ background-color: var(--color-bg);
12846
+ background-image: var(--texture-surface);
12177
12847
  }
12178
12848
 
12179
12849
  /* ── Eyebrow ── */
@@ -12185,9 +12855,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12185
12855
  /* ── Headline ── */
12186
12856
  [data-ui="hero"] [data-part="headline"] {
12187
12857
  margin: 0;
12858
+ font-family: var(--font-heading);
12188
12859
  font-size: var(--text-3xl);
12189
- font-weight: var(--weight-bold);
12190
- line-height: var(--leading-tight);
12860
+ font-weight: var(--heading-weight);
12861
+ letter-spacing: var(--heading-tracking);
12862
+ text-transform: var(--heading-transform);
12863
+ font-variant-caps: var(--heading-caps);
12864
+ line-height: var(--heading-leading);
12191
12865
  color: var(--color-fg);
12192
12866
  text-wrap: balance;
12193
12867
  }
@@ -12306,7 +12980,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12306
12980
 
12307
12981
  /* === patterns/inbox.css === */
12308
12982
  /* @ui:component inbox */
12309
- /* @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 */
12983
+ /* @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 */
12310
12984
 
12311
12985
  /* ── Root ──
12312
12986
  ONE pane, because that is what a phone has room for. Each pane's `data-state`
@@ -12326,7 +13000,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12326
13000
  overflow: hidden;
12327
13001
  border: var(--space-px, 1px) solid var(--color-border);
12328
13002
  border-radius: var(--radius-lg);
12329
- font-family: var(--font-sans, system-ui, sans-serif);
13003
+ font-family: var(--font-body);
12330
13004
  color: var(--color-fg);
12331
13005
  background: var(--color-bg);
12332
13006
  }
@@ -12418,8 +13092,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12418
13092
  }
12419
13093
 
12420
13094
  [data-ui="inbox"] [data-part="item"]:focus-visible {
12421
- outline: 2px solid var(--color-ring);
12422
- outline-offset: 2px;
13095
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13096
+ outline-offset: var(--focus-ring-offset);
12423
13097
  }
12424
13098
 
12425
13099
  [data-ui="inbox"] [data-part="item"][data-state="selected"] {
@@ -12578,7 +13252,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12578
13252
 
12579
13253
  /* === patterns/pricing.css === */
12580
13254
  /* @ui:component pricing */
12581
- /* @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 */
13255
+ /* @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 */
12582
13256
 
12583
13257
  /* ── Root ──
12584
13258
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -12588,7 +13262,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12588
13262
  gap: var(--space-4);
12589
13263
  padding-block: var(--space-12);
12590
13264
  padding-inline: var(--space-4);
12591
- font-family: var(--font-sans, system-ui, sans-serif);
13265
+ font-family: var(--font-body);
12592
13266
  color: var(--color-fg);
12593
13267
  background: var(--color-bg);
12594
13268
  }
@@ -12638,9 +13312,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12638
13312
 
12639
13313
  [data-ui="pricing"] [data-part="tier"] [data-part="title"] {
12640
13314
  margin: 0;
13315
+ font-family: var(--font-heading);
12641
13316
  font-size: var(--text-lg);
12642
13317
  font-weight: var(--weight-semibold);
12643
- line-height: var(--leading-tight);
13318
+ letter-spacing: var(--heading-tracking);
13319
+ text-transform: var(--heading-transform);
13320
+ font-variant-caps: var(--heading-caps);
13321
+ line-height: var(--heading-leading);
12644
13322
  }
12645
13323
 
12646
13324
  [data-ui="pricing"] [data-part="tier"] [data-part="header"] [data-part="description"] {
@@ -12701,7 +13379,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12701
13379
  [data-ui="pricing"] [data-part="tier"][data-state="featured"] {
12702
13380
  border-color: var(--color-primary);
12703
13381
  box-shadow: var(--shadow-md);
12704
- outline: var(--space-px, 1px) solid var(--color-primary);
13382
+ outline: var(--border-width-strong) solid var(--color-primary);
12705
13383
  }
12706
13384
 
12707
13385
  /* ── Footnote ── */
@@ -12746,14 +13424,14 @@ div[data-ui="separator"][data-style="thick"]::after {
12746
13424
 
12747
13425
  /* === patterns/search-results.css === */
12748
13426
  /* @ui:component search-results */
12749
- /* @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 */
13427
+ /* @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 */
12750
13428
 
12751
13429
  /* ── Root ── */
12752
13430
  [data-ui="search-results"] {
12753
13431
  display: flex;
12754
13432
  flex-direction: column;
12755
13433
  gap: var(--space-4);
12756
- font-family: var(--font-sans, system-ui, sans-serif);
13434
+ font-family: var(--font-body);
12757
13435
  }
12758
13436
 
12759
13437
  /* ── Search Input ── */
@@ -12781,7 +13459,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12781
13459
  justify-content: space-between;
12782
13460
  gap: var(--space-4);
12783
13461
  padding-bottom: var(--space-2);
12784
- border-bottom: 1px solid var(--color-border);
13462
+ border-bottom: var(--border-width) solid var(--color-border);
12785
13463
  }
12786
13464
 
12787
13465
  [data-ui="search-results"] [data-part="results-count"] {
@@ -12816,7 +13494,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12816
13494
  flex-direction: column;
12817
13495
  gap: var(--space-2);
12818
13496
  padding: var(--space-4);
12819
- border: 1px solid var(--color-border);
13497
+ border: var(--border-width) solid var(--color-border);
12820
13498
  border-radius: var(--radius-md);
12821
13499
  background: var(--color-bg);
12822
13500
  transition: background var(--duration-fast) var(--ease-default),
@@ -12875,7 +13553,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12875
13553
  display: flex;
12876
13554
  justify-content: center;
12877
13555
  padding-top: var(--space-4);
12878
- border-top: 1px solid var(--color-border);
13556
+ border-top: var(--border-width) solid var(--color-border);
12879
13557
  }
12880
13558
 
12881
13559
  /* ── Loading ── */
@@ -12915,7 +13593,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12915
13593
 
12916
13594
  /* ── Error State ── */
12917
13595
  [data-ui="search-results"][data-state="error"] [data-part="results-list"] {
12918
- border: 1px solid var(--color-border);
13596
+ border: var(--border-width) solid var(--color-border);
12919
13597
  border-radius: var(--radius-md);
12920
13598
  padding: var(--space-6);
12921
13599
  text-align: center;
@@ -12924,8 +13602,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12924
13602
 
12925
13603
  /* ── Focus management ── */
12926
13604
  [data-ui="search-results"] [data-part="result-item"]:focus-visible {
12927
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
12928
- outline-offset: 2px;
13605
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13606
+ outline-offset: var(--focus-ring-offset);
12929
13607
  }
12930
13608
 
12931
13609
  /* ── Motion ── */
@@ -12941,7 +13619,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12941
13619
 
12942
13620
  /* === patterns/settings-page.css === */
12943
13621
  /* @ui:component settings-page */
12944
- /* @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 */
13622
+ /* @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 */
12945
13623
 
12946
13624
  /* ── Root ── */
12947
13625
  [data-ui="settings-page"] {
@@ -12951,7 +13629,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12951
13629
  width: 100%;
12952
13630
  max-width: 768px;
12953
13631
  margin-inline: auto;
12954
- font-family: var(--font-sans, system-ui, sans-serif);
13632
+ font-family: var(--font-body);
12955
13633
  color: var(--color-fg);
12956
13634
  }
12957
13635
 
@@ -12965,9 +13643,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12965
13643
  /* ── Title ── */
12966
13644
  [data-ui="settings-page"] [data-part="title"] {
12967
13645
  margin: 0;
13646
+ font-family: var(--font-heading);
12968
13647
  font-size: var(--text-xl, 1.25rem);
12969
13648
  font-weight: var(--weight-semibold, 600);
12970
- line-height: var(--leading-tight);
13649
+ letter-spacing: var(--heading-tracking);
13650
+ text-transform: var(--heading-transform);
13651
+ font-variant-caps: var(--heading-caps);
13652
+ line-height: var(--heading-leading);
12971
13653
  color: var(--color-fg);
12972
13654
  }
12973
13655
 
@@ -13031,7 +13713,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13031
13713
  gap: var(--space-3, 0.75rem);
13032
13714
  padding: var(--space-4);
13033
13715
  background: var(--color-bg);
13034
- border-top: 1px solid var(--color-border);
13716
+ border-top: var(--border-width) solid var(--color-border);
13035
13717
  border-radius: var(--radius-lg);
13036
13718
  box-shadow: var(--shadow-md);
13037
13719
  position: sticky;
@@ -13095,7 +13777,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13095
13777
  flex-direction: row;
13096
13778
  flex-wrap: wrap;
13097
13779
  border-inline-end: none;
13098
- border-bottom: 1px solid var(--color-border);
13780
+ border-bottom: var(--border-width) solid var(--color-border);
13099
13781
  padding-inline-end: 0;
13100
13782
  position: static;
13101
13783
  }
@@ -13114,7 +13796,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13114
13796
  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="list"] {
13115
13797
  flex-direction: column;
13116
13798
  border-bottom: none;
13117
- border-inline-end: 1px solid var(--color-border);
13799
+ border-inline-end: var(--border-width) solid var(--color-border);
13118
13800
  padding-inline-end: var(--space-4);
13119
13801
  position: sticky;
13120
13802
  top: var(--space-4);
@@ -13132,7 +13814,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13132
13814
  justify-content: flex-start;
13133
13815
  text-align: start;
13134
13816
  border-bottom: none;
13135
- border-inline-start: 2px solid transparent;
13817
+ border-inline-start: var(--border-width-strong) solid transparent;
13136
13818
  margin-bottom: 0;
13137
13819
  margin-inline-end: -1px;
13138
13820
  padding: var(--space-2) var(--space-3);
@@ -13166,7 +13848,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13166
13848
 
13167
13849
  /* === patterns/site-footer.css === */
13168
13850
  /* @ui:component site-footer */
13169
- /* @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 */
13851
+ /* @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 */
13170
13852
 
13171
13853
  /* ── Root ──
13172
13854
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -13176,11 +13858,11 @@ div[data-ui="separator"][data-style="thick"]::after {
13176
13858
  gap: var(--space-8);
13177
13859
  padding-block: var(--space-10);
13178
13860
  padding-inline: var(--space-4);
13179
- font-family: var(--font-sans, system-ui, sans-serif);
13861
+ font-family: var(--font-body);
13180
13862
  font-size: var(--text-sm);
13181
13863
  color: var(--color-fg-muted);
13182
13864
  background: var(--color-bg-subtle);
13183
- border-block-start: 1px solid var(--color-border);
13865
+ border-block-start: var(--border-width) solid var(--color-border);
13184
13866
  }
13185
13867
 
13186
13868
  /* ── Brand ── */
@@ -13312,7 +13994,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13312
13994
 
13313
13995
  /* === patterns/stats-dashboard.css === */
13314
13996
  /* @ui:component stats-dashboard */
13315
- /* @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 */
13997
+ /* @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 */
13316
13998
 
13317
13999
  /* ── Root ──
13318
14000
  A reporting page: title block, KPI row, then the panel region. The KPI row
@@ -13325,7 +14007,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13325
14007
  gap: var(--space-3);
13326
14008
  padding-block: var(--space-8);
13327
14009
  padding-inline: var(--space-4);
13328
- font-family: var(--font-sans, system-ui, sans-serif);
14010
+ font-family: var(--font-body);
13329
14011
  color: var(--color-fg);
13330
14012
  background: var(--color-bg);
13331
14013
  }
@@ -13399,9 +14081,13 @@ div[data-ui="separator"][data-style="thick"]::after {
13399
14081
 
13400
14082
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="title"] {
13401
14083
  margin: 0;
14084
+ font-family: var(--font-heading);
13402
14085
  font-size: var(--text-lg);
13403
14086
  font-weight: var(--weight-semibold);
13404
- line-height: var(--leading-tight);
14087
+ letter-spacing: var(--heading-tracking);
14088
+ text-transform: var(--heading-transform);
14089
+ font-variant-caps: var(--heading-caps);
14090
+ line-height: var(--heading-leading);
13405
14091
  }
13406
14092
 
13407
14093
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="header"] [data-part="description"] {
@@ -13492,7 +14178,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13492
14178
  gap: var(--space-6);
13493
14179
  max-inline-size: var(--measure-narrow);
13494
14180
  margin-inline: auto;
13495
- font-family: var(--font-sans);
14181
+ font-family: var(--font-body);
13496
14182
  }
13497
14183
 
13498
14184
  [data-ui="wizard"] [data-part="heading"] {