@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,119 +978,175 @@
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/default.css === */
645
- /* @ui:theme default — light + dark mode overrides */
646
-
647
- /* ── Light Mode ── */
648
- /* Light mode otherwise inherits the semantic-token defaults from semantic.css.
649
- These overrides raise the handful of default-theme tokens that fell below the
650
- WCAG 2 AA 4.5:1 text threshold (task 0.4-24 · §12.3), each verified by the axe
651
- gate (tests/a11y). Darkening is contrast-safe: every *solid* use of these
652
- semantic colours (button, progress, stepper marker) carries light text or no
653
- text, so a deeper tone only raises its contrast. */
1033
+ /* @ui:theme default — one :root block, both schemes, via light-dark() */
1034
+
1035
+ /* Authored in the ONE-BLOCK form [1.1A-06]: each scheme-dependent token states
1036
+ `light-dark(<light>, <dark>)` once instead of being written in `:root`, again
1037
+ in `[data-theme="dark"]` and a third time in the `prefers-color-scheme`
1038
+ mirror. `base/reset.css` turns `data-theme` into the `color-scheme` the
1039
+ function reads, so the two authoring forms are interchangeable and every
1040
+ existing `data-theme` value keeps driving exactly what it drove before.
1041
+
1042
+ The light argument is the value this theme would otherwise have INHERITED
1043
+ from tokens/semantic.css; spelling it out is the price of the single block,
1044
+ because a token cannot read its own base value (`light-dark(var(--color-bg),
1045
+ …)` on `--color-bg` is a cycle). `tests/themes/light-dark.test.ts` is what
1046
+ keeps the copy honest: every light argument must equal the base value unless
1047
+ it is one of the four deliberate AA corrections below (task 0.4-24 · §12.3),
1048
+ and that list fails in both directions.
1049
+
1050
+ Darkening for AA is contrast-safe: every *solid* use of these semantic colours
1051
+ (button, progress, stepper marker) carries light text or no text, so a deeper
1052
+ tone only raises its contrast.
1053
+
1054
+ The shadow ramp is the one family still authored as blocks — see below. */
654
1055
  :root {
1056
+ /* ── Surfaces ── */
1057
+ --color-bg: light-dark(var(--palette-gray-25), var(--palette-gray-950));
1058
+ --color-bg-subtle: light-dark(var(--palette-gray-100), var(--palette-gray-900));
1059
+ --color-bg-muted: light-dark(var(--palette-gray-200), var(--palette-gray-800));
1060
+ /* Scheme-independent by construction: the elevation ramp is defined in terms
1061
+ of tokens that already carry both schemes, so it needs no second spelling. */
655
1062
  --color-surface-1: var(--color-bg-subtle);
656
1063
  --color-surface-2: var(--color-bg-muted);
657
1064
  --color-surface-1-border: var(--color-border);
658
1065
  --color-surface-2-border: var(--color-border-strong);
659
- --color-fg-muted: var(--palette-gray-600); /* AA: gray-500 was 4.31:1 on muted surfaces (avatar/tabs) */
660
- --color-fg-subtle: var(--palette-gray-500); /* AA: gray-400 was 2.61:1 (subtle text, footers, page-break) */
661
- --color-success: var(--palette-green-700); /* AA: green-500 as soft-badge/stat/stepper text was 3.19:1 */
662
- --color-warning: var(--palette-amber-800); /* AA: amber-500 as soft-badge text was 2.02:1 */
663
- }
1066
+ --color-fg: light-dark(var(--palette-gray-950), var(--palette-gray-50));
1067
+ /* AA: light gray-500 was 4.31:1 on muted surfaces (avatar/tabs); in dark,
1068
+ gray-400 is kept for subtle, so muted moves up. */
1069
+ --color-fg-muted: light-dark(var(--palette-gray-600), var(--palette-gray-300));
1070
+ /* AA: light gray-400 was 2.61:1 (subtle text, footers, page-break);
1071
+ dark gray-500 subtle text was 4.11:1 on bg. */
1072
+ --color-fg-subtle: light-dark(var(--palette-gray-500), var(--palette-gray-400));
664
1073
 
665
- /* ── Dark Mode ── */
666
- [data-theme="dark"] {
667
- --color-bg: var(--palette-gray-950);
668
- --color-bg-subtle: var(--palette-gray-900);
669
- --color-bg-muted: var(--palette-gray-800);
670
- --color-surface-1: var(--color-bg-subtle);
671
- --color-surface-2: var(--color-bg-muted);
672
- --color-surface-1-border: var(--color-border);
673
- --color-surface-2-border: var(--color-border-strong);
674
- --color-fg: var(--palette-gray-50);
675
- --color-fg-muted: var(--palette-gray-300); /* AA: gray-400 kept subtle above 4.5:1, so muted moves up */
676
- --color-fg-subtle: var(--palette-gray-400); /* AA: gray-500 subtle text was 4.11:1 on bg */
677
-
678
- --color-primary: var(--palette-indigo-400);
679
- --color-primary-hover: var(--palette-indigo-300);
680
- --color-primary-active: var(--palette-indigo-200);
681
- --color-primary-fg: var(--palette-gray-950); /* AA: dark ink on the luminous dark-mode accent — white was 3.4:1 [0.4-16] */
682
- --color-primary-subtle: oklch(0.24 0.06 264);
683
-
684
- --color-secondary: var(--palette-gray-800);
685
- --color-secondary-hover: var(--palette-gray-700);
686
- --color-secondary-fg: var(--palette-gray-100);
687
-
688
- --color-destructive: var(--palette-red-400); /* AA: luminous red so it reads as text on subtle/dark bg (badge/chip/field/stat); red-500 was 3.42:1 [0.4-24] */
689
- --color-destructive-hover: var(--palette-red-300);
690
- --color-destructive-fg: var(--palette-gray-950); /* AA: dark ink on the luminous red for solid surfaces (button) — mirrors --color-primary-fg [0.4-24] */
691
- --color-destructive-subtle: oklch(0.24 0.06 25);
692
-
693
- --color-success: var(--palette-green-400);
694
- --color-success-subtle: oklch(0.24 0.054 155);
695
- --color-warning: var(--palette-amber-400);
696
- --color-warning-subtle: oklch(0.24 0.045 75);
697
- --color-info: var(--palette-blue-400);
698
- --color-info-subtle: oklch(0.24 0.054 240);
699
-
700
- --color-border: var(--palette-gray-800);
701
- --color-border-strong: var(--palette-gray-700);
702
- --color-ring: oklch(0.65 0.20 264);
1074
+ /* ── Interactive: Primary ── */
1075
+ --color-primary: light-dark(var(--palette-indigo-500), var(--palette-indigo-400));
1076
+ --color-primary-hover: light-dark(var(--palette-indigo-600), var(--palette-indigo-300));
1077
+ --color-primary-active: light-dark(var(--palette-indigo-700), var(--palette-indigo-200));
1078
+ /* AA: dark ink on the luminous dark-mode accent — white was 3.4:1 [0.4-16] */
1079
+ --color-primary-fg: light-dark(white, var(--palette-gray-950));
1080
+ --color-primary-subtle: light-dark(var(--palette-indigo-50), oklch(0.24 0.06 264));
1081
+
1082
+ /* ── Interactive: Secondary ── */
1083
+ --color-secondary: light-dark(var(--palette-gray-100), var(--palette-gray-800));
1084
+ --color-secondary-hover: light-dark(var(--palette-gray-200), var(--palette-gray-700));
1085
+ --color-secondary-fg: light-dark(var(--palette-gray-900), var(--palette-gray-100));
1086
+
1087
+ /* ── Interactive: Destructive ── */
1088
+ /* AA: a luminous dark red so it reads as text on subtle/dark bg
1089
+ (badge/chip/field/stat); red-500 was 3.42:1 [0.4-24] */
1090
+ --color-destructive: light-dark(var(--palette-red-500), var(--palette-red-400));
1091
+ --color-destructive-hover: light-dark(var(--palette-red-600), var(--palette-red-300));
1092
+ /* AA: dark ink on the luminous red for solid surfaces (button) — mirrors
1093
+ --color-primary-fg [0.4-24] */
1094
+ --color-destructive-fg: light-dark(white, var(--palette-gray-950));
1095
+ --color-destructive-subtle: light-dark(var(--palette-red-50), oklch(0.24 0.06 25));
1096
+
1097
+ /* ── Feedback ── */
1098
+ /* AA: light green-500 as soft-badge/stat/stepper text was 3.19:1 */
1099
+ --color-success: light-dark(var(--palette-green-700), var(--palette-green-400));
1100
+ --color-success-subtle: light-dark(var(--palette-green-50), oklch(0.24 0.054 155));
1101
+ /* AA: light amber-500 as soft-badge text was 2.02:1 */
1102
+ --color-warning: light-dark(var(--palette-amber-800), var(--palette-amber-400));
1103
+ --color-warning-subtle: light-dark(var(--palette-amber-50), oklch(0.24 0.045 75));
1104
+ --color-info: light-dark(var(--palette-blue-500), var(--palette-blue-400));
1105
+ --color-info-subtle: light-dark(var(--palette-blue-50), oklch(0.24 0.054 240));
703
1106
 
1107
+ /* ── Borders ── */
1108
+ --color-border: light-dark(var(--palette-gray-200), var(--palette-gray-800));
1109
+ --color-border-strong: light-dark(var(--palette-gray-300), var(--palette-gray-700));
1110
+ --color-ring: light-dark(oklch(0.55 0.22 264), oklch(0.65 0.20 264));
1111
+ }
1112
+
1113
+ /* ── Dark Mode: the shadow ramp ── */
1114
+ /* The one family `light-dark()` cannot collapse. It is a <color> function and a
1115
+ shadow list is not a colour, so the whole value cannot be wrapped; and the
1116
+ per-layer spelling would have to pad the dark ramp with alpha-0 layers to give
1117
+ both schemes one geometry — writing a shadow where this theme says `none`,
1118
+ and restating the base light ramp (two layers per step) to do it.
1119
+ Light stays inherited from tokens/effects.css; only dark is stated.
1120
+
1121
+ Each step is cast in `--shadow-color` (1.1A-04 — bare OKLCH channels, so the
1122
+ step keeps its own alpha), which for this theme is the base layer's own
1123
+ `0 0 0`. That is the ONLY thing `default` adopts from the 1.1 families, and
1124
+ deliberately so: `default` is not a theme that resembles the token layer, it
1125
+ IS the token layer's own look, so restating a base value here would fork the
1126
+ two and let a later change to `tokens/*` silently stop reaching the reference
1127
+ theme. Every other axis `default` carries is derived from the base layer,
1128
+ which is what `tests/themes/axes.test.ts` holds equal to
1129
+ `THEME_SEED_DEFAULTS`. Casting the ramp through the channel is not a restated
1130
+ value — it is the ten literal blacks this theme used to hide from a theme
1131
+ that wants to tint them. [1.1A-15] */
1132
+ [data-theme="dark"] {
704
1133
  --shadow-xs: none;
705
- --shadow-sm: 0 1px 3px oklch(0 0 0 / 0.3);
706
- --shadow-md: 0 4px 6px oklch(0 0 0 / 0.3);
707
- --shadow-lg: 0 10px 15px oklch(0 0 0 / 0.4);
708
- --shadow-xl: 0 20px 25px oklch(0 0 0 / 0.5);
1134
+ --shadow-sm: 0 1px 3px oklch(var(--shadow-color) / 0.3);
1135
+ --shadow-md: 0 4px 6px oklch(var(--shadow-color) / 0.3);
1136
+ --shadow-lg: 0 10px 15px oklch(var(--shadow-color) / 0.4);
1137
+ --shadow-xl: 0 20px 25px oklch(var(--shadow-color) / 0.5);
709
1138
  }
710
1139
 
711
- /* ── Auto Dark Mode (system preference) ── */
712
- /* Mirror of the [data-theme="dark"] block above — keep the two in sync. */
1140
+ /* Mirror of the [data-theme="dark"] block above — keep the two in sync. The
1141
+ colours need no mirror: `[data-theme="auto"]` is `color-scheme: light dark`,
1142
+ so light-dark() already follows the system preference. */
713
1143
  @media (prefers-color-scheme: dark) {
714
1144
  [data-theme="auto"] {
715
- --color-bg: var(--palette-gray-950);
716
- --color-bg-subtle: var(--palette-gray-900);
717
- --color-bg-muted: var(--palette-gray-800);
718
- --color-surface-1: var(--color-bg-subtle);
719
- --color-surface-2: var(--color-bg-muted);
720
- --color-surface-1-border: var(--color-border);
721
- --color-surface-2-border: var(--color-border-strong);
722
- --color-fg: var(--palette-gray-50);
723
- --color-fg-muted: var(--palette-gray-300); /* AA — see [data-theme="dark"] */
724
- --color-fg-subtle: var(--palette-gray-400); /* AA — see [data-theme="dark"] */
725
-
726
- --color-primary: var(--palette-indigo-400);
727
- --color-primary-hover: var(--palette-indigo-300);
728
- --color-primary-active: var(--palette-indigo-200);
729
- --color-primary-fg: var(--palette-gray-950); /* AA: dark ink on the luminous dark-mode accent — white was 3.4:1 [0.4-16] */
730
- --color-primary-subtle: oklch(0.24 0.06 264);
731
-
732
- --color-secondary: var(--palette-gray-800);
733
- --color-secondary-hover: var(--palette-gray-700);
734
- --color-secondary-fg: var(--palette-gray-100);
735
-
736
- --color-destructive: var(--palette-red-400); /* AA — see [data-theme="dark"] [0.4-24] */
737
- --color-destructive-hover: var(--palette-red-300);
738
- --color-destructive-fg: var(--palette-gray-950); /* AA — see [data-theme="dark"] [0.4-24] */
739
- --color-destructive-subtle: oklch(0.24 0.06 25);
740
-
741
- --color-success: var(--palette-green-400);
742
- --color-success-subtle: oklch(0.24 0.054 155);
743
- --color-warning: var(--palette-amber-400);
744
- --color-warning-subtle: oklch(0.24 0.045 75);
745
- --color-info: var(--palette-blue-400);
746
- --color-info-subtle: oklch(0.24 0.054 240);
747
-
748
- --color-border: var(--palette-gray-800);
749
- --color-border-strong: var(--palette-gray-700);
750
- --color-ring: oklch(0.65 0.20 264);
751
-
752
1145
  --shadow-xs: none;
753
- --shadow-sm: 0 1px 3px oklch(0 0 0 / 0.3);
754
- --shadow-md: 0 4px 6px oklch(0 0 0 / 0.3);
755
- --shadow-lg: 0 10px 15px oklch(0 0 0 / 0.4);
756
- --shadow-xl: 0 20px 25px oklch(0 0 0 / 0.5);
1146
+ --shadow-sm: 0 1px 3px oklch(var(--shadow-color) / 0.3);
1147
+ --shadow-md: 0 4px 6px oklch(var(--shadow-color) / 0.3);
1148
+ --shadow-lg: 0 10px 15px oklch(var(--shadow-color) / 0.4);
1149
+ --shadow-xl: 0 20px 25px oklch(var(--shadow-color) / 0.5);
757
1150
  }
758
1151
  }
759
1152
 
@@ -771,11 +1164,38 @@
771
1164
  padding: 0;
772
1165
  }
773
1166
 
1167
+ /* Colour scheme — the one place `data-theme` is translated into the platform's
1168
+ own scheme signal. `light-dark()` in a theme reads `color-scheme`, not
1169
+ `data-theme`, so a one-block theme [1.1A-06] resolves nothing at all without
1170
+ these three rules; declaring them here (rather than in each theme) is what
1171
+ makes the two authoring forms interchangeable. Nothing else in the registry
1172
+ declares `color-scheme`, so this is purely additive.
1173
+
1174
+ Specificity does the mapping: `:root` is (0,0,1) and each attribute selector
1175
+ is (0,1,0), so `<html data-theme="dark">` takes the dark rule over the root
1176
+ default while a bare `<html>` — and `data-theme="light"` — keeps light. The
1177
+ same rules apply to a NESTED element carrying `data-theme`, which is how a
1178
+ dark island inside a light page has always worked here. */
1179
+ :root {
1180
+ color-scheme: light;
1181
+ }
1182
+
1183
+ [data-theme="dark"] {
1184
+ color-scheme: dark;
1185
+ }
1186
+
1187
+ /* `auto` hands the choice to the OS: `light dark` means "either, system first",
1188
+ which is exactly what the `@media (prefers-color-scheme: dark)` mirror block
1189
+ does for a theme authored in the three-block form. */
1190
+ [data-theme="auto"] {
1191
+ color-scheme: light dark;
1192
+ }
1193
+
774
1194
  html {
775
1195
  -webkit-text-size-adjust: 100%;
776
1196
  -moz-tab-size: 4;
777
1197
  tab-size: 4;
778
- font-family: var(--font-sans);
1198
+ font-family: var(--font-body);
779
1199
  font-size: var(--text-base);
780
1200
  line-height: var(--leading-normal);
781
1201
  color: var(--color-fg);
@@ -786,6 +1206,11 @@ html {
786
1206
 
787
1207
  body {
788
1208
  min-height: 100dvh;
1209
+ /* The page's material. `none` by default (the initial value), so this is a
1210
+ no-op until a theme points --texture-page at one of tokens/textures.css.
1211
+ `html` keeps the background COLOUR; the texture rides on `body`, which
1212
+ covers the viewport, so the two compose instead of overwriting. */
1213
+ background-image: var(--texture-page);
789
1214
  }
790
1215
 
791
1216
  img,
@@ -855,10 +1280,32 @@ table {
855
1280
  }
856
1281
  }
857
1282
 
858
- /* Focus visible — default ring */
1283
+ /* Text selection — the decoration axis reaching the one surface no component
1284
+ owns. Until 1.1 the highlight was whatever the OS drew, which is the one part
1285
+ of a themed page that never matched the theme. Both values are tokens
1286
+ (tokens/aliases.css § Decoration), so a theme states its selection once. */
1287
+ ::selection {
1288
+ background-color: var(--selection-bg);
1289
+ color: var(--selection-fg);
1290
+ }
1291
+
1292
+ /* Focus visible — the default ring, and the only place it is spelled out.
1293
+ Every value is a token (tokens/effects.css § Focus), so a theme states its
1294
+ focus once and every element that has not drawn its own ring follows. */
859
1295
  :focus-visible {
860
- outline: 2px solid var(--color-ring);
861
- outline-offset: 2px;
1296
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1297
+ outline-offset: var(--focus-ring-offset);
1298
+ }
1299
+
1300
+ /* The glow a theme may put behind the ring, at zero specificity. `box-shadow`
1301
+ is not a property focus owns: an element's resting shadow — a card's depth,
1302
+ an author's own — lives there too, and a (0,1,0) rule here replaced it with
1303
+ `none` (the default) on every keyboard focus. Under `:where()` ANY rule that
1304
+ sets a shadow outranks this one, so it lands only on an element nothing else
1305
+ shadows, and it never takes a shadow away. The controls that draw their own
1306
+ ring read `--focus-shadow` in their own `:focus-visible` rules. */
1307
+ :where(:focus-visible) {
1308
+ box-shadow: var(--focus-shadow);
862
1309
  }
863
1310
 
864
1311
  /* Hidden but accessible */
@@ -887,7 +1334,7 @@ table {
887
1334
  /* @ui:base prose — typography defaults for long-form content */
888
1335
 
889
1336
  [data-ui="prose"] {
890
- font-family: var(--font-sans);
1337
+ font-family: var(--font-body);
891
1338
  font-size: var(--text-base);
892
1339
  line-height: var(--leading-relaxed);
893
1340
  color: var(--color-fg);
@@ -895,29 +1342,45 @@ table {
895
1342
  }
896
1343
 
897
1344
  [data-ui="prose"] h1 {
1345
+ font-family: var(--font-heading);
898
1346
  font-size: var(--text-4xl);
899
- font-weight: var(--weight-bold);
900
- line-height: var(--leading-tight);
1347
+ font-weight: var(--heading-weight);
1348
+ letter-spacing: var(--heading-tracking);
1349
+ text-transform: var(--heading-transform);
1350
+ font-variant-caps: var(--heading-caps);
1351
+ line-height: var(--heading-leading);
901
1352
  margin-block: var(--space-8) var(--space-4);
902
1353
  }
903
1354
 
904
1355
  [data-ui="prose"] h2 {
1356
+ font-family: var(--font-heading);
905
1357
  font-size: var(--text-3xl);
906
1358
  font-weight: var(--weight-semibold);
907
- line-height: var(--leading-tight);
1359
+ letter-spacing: var(--heading-tracking);
1360
+ text-transform: var(--heading-transform);
1361
+ font-variant-caps: var(--heading-caps);
1362
+ line-height: var(--heading-leading);
908
1363
  margin-block: var(--space-8) var(--space-3);
909
1364
  }
910
1365
 
911
1366
  [data-ui="prose"] h3 {
1367
+ font-family: var(--font-heading);
912
1368
  font-size: var(--text-2xl);
913
1369
  font-weight: var(--weight-semibold);
1370
+ letter-spacing: var(--heading-tracking);
1371
+ text-transform: var(--heading-transform);
1372
+ font-variant-caps: var(--heading-caps);
914
1373
  line-height: var(--leading-snug);
915
1374
  margin-block: var(--space-6) var(--space-3);
916
1375
  }
917
1376
 
918
1377
  [data-ui="prose"] h4 {
1378
+ font-family: var(--font-heading);
919
1379
  font-size: var(--text-xl);
920
1380
  font-weight: var(--weight-semibold);
1381
+ letter-spacing: var(--heading-tracking);
1382
+ text-transform: var(--heading-transform);
1383
+ font-variant-caps: var(--heading-caps);
921
1384
  line-height: var(--leading-snug);
922
1385
  margin-block: var(--space-6) var(--space-2);
923
1386
  }
@@ -928,8 +1391,8 @@ table {
928
1391
 
929
1392
  [data-ui="prose"] a {
930
1393
  color: var(--color-primary);
931
- text-decoration: underline;
932
- text-underline-offset: 2px;
1394
+ text-decoration-line: var(--link-decoration);
1395
+ text-underline-offset: var(--link-underline-offset);
933
1396
  }
934
1397
 
935
1398
  [data-ui="prose"] a:hover {
@@ -966,7 +1429,7 @@ table {
966
1429
  }
967
1430
 
968
1431
  [data-ui="prose"] blockquote {
969
- border-inline-start: 3px solid var(--color-border-strong);
1432
+ border-inline-start: var(--border-width-lg) solid var(--color-border-strong);
970
1433
  padding-inline-start: var(--space-4);
971
1434
  color: var(--color-fg-muted);
972
1435
  margin-block: var(--space-4);
@@ -988,9 +1451,15 @@ table {
988
1451
  margin-block: var(--space-1);
989
1452
  }
990
1453
 
1454
+ /* The bullet. `currentColor` by default — the initial value — so a list looks
1455
+ exactly as it did; a theme that wants accented markers sets --marker-color. */
1456
+ [data-ui="prose"] li::marker {
1457
+ color: var(--marker-color);
1458
+ }
1459
+
991
1460
  [data-ui="prose"] hr {
992
1461
  border: none;
993
- border-block-start: 1px solid var(--color-border);
1462
+ border-block-start: var(--border-width) solid var(--color-border);
994
1463
  margin-block: var(--space-8);
995
1464
  }
996
1465
 
@@ -1009,12 +1478,12 @@ table {
1009
1478
  font-weight: var(--weight-semibold);
1010
1479
  text-align: start;
1011
1480
  padding: var(--space-2) var(--space-3);
1012
- border-block-end: 2px solid var(--color-border-strong);
1481
+ border-block-end: var(--border-width-strong) solid var(--color-border-strong);
1013
1482
  }
1014
1483
 
1015
1484
  [data-ui="prose"] td {
1016
1485
  padding: var(--space-2) var(--space-3);
1017
- border-block-end: 1px solid var(--color-border);
1486
+ border-block-end: var(--border-width) solid var(--color-border);
1018
1487
  }
1019
1488
 
1020
1489
  /* First child no top margin, last child no bottom margin */
@@ -1199,7 +1668,7 @@ table {
1199
1668
 
1200
1669
  /* === primitives/avatar.css === */
1201
1670
  /* @ui:component avatar */
1202
- /* @ui:tokens color-bg-muted color-fg-muted radius-full font-sans text-xs text-sm weight-medium */
1671
+ /* @ui:tokens color-bg-muted color-fg-muted radius-full font-ui text-xs text-sm weight-medium */
1203
1672
 
1204
1673
  /* ── Base ── */
1205
1674
  [data-ui="avatar"] {
@@ -1229,7 +1698,7 @@ table {
1229
1698
  height: 100%;
1230
1699
  background: var(--color-bg-muted);
1231
1700
  color: var(--color-fg-muted);
1232
- font-family: var(--font-sans);
1701
+ font-family: var(--font-ui);
1233
1702
  font-size: var(--text-sm);
1234
1703
  font-weight: var(--weight-medium);
1235
1704
  text-transform: uppercase;
@@ -1254,7 +1723,7 @@ table {
1254
1723
 
1255
1724
  /* === primitives/badge.css === */
1256
1725
  /* @ui:component badge */
1257
- /* @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 */
1726
+ /* @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 */
1258
1727
 
1259
1728
  /* ── Base ── */
1260
1729
  [data-ui="badge"] {
@@ -1264,9 +1733,10 @@ table {
1264
1733
  gap: var(--space-1);
1265
1734
  padding: 0.125rem var(--space-2);
1266
1735
  border-radius: var(--badge-radius, var(--radius-full));
1736
+ corner-shape: var(--corner-shape);
1267
1737
  background: var(--color-bg-muted);
1268
1738
  color: var(--color-fg);
1269
- font-family: var(--badge-font, var(--font-sans));
1739
+ font-family: var(--badge-font, var(--font-ui));
1270
1740
  font-size: var(--text-xs);
1271
1741
  font-weight: var(--weight-medium);
1272
1742
  line-height: 1.5;
@@ -1312,11 +1782,11 @@ table {
1312
1782
 
1313
1783
  /* === primitives/breadcrumb.css === */
1314
1784
  /* @ui:component breadcrumb */
1315
- /* @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 */
1785
+ /* @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 */
1316
1786
 
1317
1787
  /* ── Root ── */
1318
1788
  [data-ui="breadcrumb"] {
1319
- font-family: var(--breadcrumb-font, var(--font-sans));
1789
+ font-family: var(--breadcrumb-font, var(--font-ui));
1320
1790
  font-size: var(--breadcrumb-size, var(--text-sm));
1321
1791
  color: var(--color-fg-muted);
1322
1792
  }
@@ -1342,12 +1812,13 @@ table {
1342
1812
 
1343
1813
  [data-ui="breadcrumb"] [data-part="item"]:hover {
1344
1814
  color: var(--color-primary-hover);
1345
- text-decoration: underline;
1815
+ text-decoration-line: var(--link-decoration);
1346
1816
  }
1347
1817
 
1348
1818
  [data-ui="breadcrumb"] [data-part="item"]:focus-visible {
1349
- outline: 2px solid var(--color-ring);
1350
- outline-offset: 2px;
1819
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1820
+ outline-offset: var(--focus-ring-offset);
1821
+ box-shadow: var(--focus-shadow);
1351
1822
  }
1352
1823
 
1353
1824
  /* ── Separator (presentational) ── */
@@ -1387,7 +1858,7 @@ table {
1387
1858
 
1388
1859
  /* === primitives/button.css === */
1389
1860
  /* @ui:component button */
1390
- /* @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 */
1861
+ /* @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 */
1391
1862
 
1392
1863
  /* ── Base ── */
1393
1864
  [data-ui="button"] {
@@ -1397,18 +1868,21 @@ table {
1397
1868
  gap: var(--space-2);
1398
1869
  height: var(--button-height-md, 40px);
1399
1870
  padding-inline: var(--space-4);
1400
- border: 1px solid var(--color-border);
1871
+ border: var(--border-width) solid var(--color-border);
1401
1872
  border-radius: var(--button-radius, var(--radius-md));
1873
+ corner-shape: var(--corner-shape);
1402
1874
  background: var(--color-bg);
1403
1875
  color: var(--color-fg);
1404
- font-family: var(--font-sans);
1876
+ font-family: var(--font-ui);
1405
1877
  font-size: var(--text-sm);
1406
1878
  font-weight: var(--weight-medium);
1879
+ text-transform: var(--button-text-transform);
1407
1880
  line-height: 1;
1408
1881
  cursor: pointer;
1409
1882
  transition: background var(--duration-fast) var(--ease-default),
1410
1883
  border-color var(--duration-fast) var(--ease-default),
1411
1884
  color var(--duration-fast) var(--ease-default),
1885
+ translate var(--duration-fast) var(--ease-default),
1412
1886
  box-shadow var(--duration-fast) var(--ease-default);
1413
1887
  user-select: none;
1414
1888
  white-space: nowrap;
@@ -1417,11 +1891,16 @@ table {
1417
1891
 
1418
1892
  [data-ui="button"]:hover {
1419
1893
  background: var(--color-bg-muted);
1894
+ /* The hover lift. `none` by default — the initial value of `translate` — so
1895
+ this rule computes what the button computed before the token existed; a
1896
+ theme with a springy personality sets `--motion-hover-lift: 0 -1px`. */
1897
+ translate: var(--motion-hover-lift);
1420
1898
  }
1421
1899
 
1422
1900
  [data-ui="button"]:focus-visible {
1423
- outline: 2px solid var(--color-ring);
1424
- outline-offset: 2px;
1901
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
1902
+ outline-offset: var(--focus-ring-offset);
1903
+ box-shadow: var(--focus-shadow);
1425
1904
  }
1426
1905
 
1427
1906
  /* ── Variants ── */
@@ -1477,7 +1956,7 @@ table {
1477
1956
  padding: 0;
1478
1957
  }
1479
1958
  [data-ui="button"][data-variant="link"]:hover {
1480
- text-decoration: underline;
1959
+ text-decoration-line: var(--link-decoration);
1481
1960
  }
1482
1961
 
1483
1962
  /* ── Sizes ── */
@@ -1496,7 +1975,7 @@ table {
1496
1975
  /* ── States ── */
1497
1976
  [data-ui="button"]:disabled,
1498
1977
  [data-ui="button"][data-state="disabled"] {
1499
- opacity: 0.5;
1978
+ opacity: var(--disabled-opacity);
1500
1979
  cursor: not-allowed;
1501
1980
  pointer-events: none;
1502
1981
  }
@@ -1511,7 +1990,7 @@ table {
1511
1990
  position: absolute;
1512
1991
  width: 1em;
1513
1992
  height: 1em;
1514
- border: 2px solid currentColor;
1993
+ border: var(--border-width-strong) solid currentColor;
1515
1994
  border-inline-end-color: transparent;
1516
1995
  border-radius: var(--radius-full);
1517
1996
  animation: faqir-spin 0.6s linear infinite;
@@ -1558,7 +2037,7 @@ table {
1558
2037
 
1559
2038
  /* === primitives/callout.css === */
1560
2039
  /* @ui:component callout */
1561
- /* @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 */
2040
+ /* @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 */
1562
2041
 
1563
2042
  /* ── Base ── */
1564
2043
  [data-ui="callout"] {
@@ -1567,7 +2046,7 @@ table {
1567
2046
  padding: var(--callout-padding-y) var(--callout-padding-x);
1568
2047
  border-radius: var(--callout-radius);
1569
2048
  border-inline-start: var(--callout-border-left-width) solid;
1570
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
2049
+ font-family: var(--doc-font, var(--font-body));
1571
2050
  font-size: var(--callout-font-size);
1572
2051
  line-height: var(--doc-line-height, 1.5);
1573
2052
  }
@@ -1598,6 +2077,7 @@ table {
1598
2077
  /* ── Title ── */
1599
2078
  [data-ui="callout"] [data-part="title"] {
1600
2079
  display: block;
2080
+ font-family: var(--font-heading);
1601
2081
  font-weight: var(--weight-semibold);
1602
2082
  margin-bottom: var(--doc-label-gap, var(--space-1, 0.25rem));
1603
2083
  }
@@ -1624,8 +2104,9 @@ table {
1624
2104
  }
1625
2105
 
1626
2106
  [data-ui="callout"] [data-part="dismiss"]:focus-visible {
1627
- outline: 2px solid var(--color-ring, var(--color-info));
1628
- outline-offset: 2px;
2107
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2108
+ outline-offset: var(--focus-ring-offset);
2109
+ box-shadow: var(--focus-shadow);
1629
2110
  opacity: 1;
1630
2111
  }
1631
2112
 
@@ -1711,17 +2192,36 @@ table {
1711
2192
 
1712
2193
  /* === primitives/card.css === */
1713
2194
  /* @ui:component card */
1714
- /* @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 */
2195
+ /* @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 */
1715
2196
 
1716
2197
  /* ── Base ── */
1717
2198
  [data-ui="card"] {
1718
2199
  display: flex;
1719
2200
  flex-direction: column;
1720
- border: 1px solid var(--card-border, var(--color-surface-1-border));
2201
+ border: var(--card-border-width) solid var(--card-border, var(--color-surface-1-border));
1721
2202
  border-radius: var(--card-radius, var(--radius-lg));
1722
- background: var(--card-bg, var(--color-surface-1));
2203
+ corner-shape: var(--corner-shape);
2204
+ /* One shorthand, two layers: the material on top, the fill beneath. The fill
2205
+ is the final layer, so `--card-bg` may be a colour OR a gradient — what 1.0
2206
+ projects set it to — and the texture (`none` by default) never clobbers it. */
2207
+ background: var(--texture-surface), var(--card-bg, var(--color-surface-1));
1723
2208
  box-shadow: var(--card-shadow, var(--shadow-sm));
1724
2209
  overflow: hidden;
2210
+ transition: translate var(--duration-fast) var(--ease-default);
2211
+ }
2212
+
2213
+ /* The hover lift, the same axis `button` reads. `none` by default (the initial
2214
+ value of `translate`), so a card sits exactly where it always sat until a
2215
+ theme says surfaces rise under the pointer. */
2216
+ [data-ui="card"]:hover {
2217
+ translate: var(--motion-hover-lift);
2218
+ }
2219
+
2220
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
2221
+ [data-ui="card"] {
2222
+ -webkit-backdrop-filter: var(--surface-backdrop);
2223
+ backdrop-filter: var(--surface-backdrop);
2224
+ }
1725
2225
  }
1726
2226
 
1727
2227
  /* ── Variants ── */
@@ -1730,7 +2230,7 @@ table {
1730
2230
  }
1731
2231
 
1732
2232
  [data-ui="card"][data-variant="filled"] {
1733
- background: var(--color-surface-2);
2233
+ background: var(--texture-surface), var(--color-surface-2);
1734
2234
  border-color: var(--color-surface-2-border);
1735
2235
  box-shadow: none;
1736
2236
  }
@@ -1745,7 +2245,7 @@ table {
1745
2245
  }
1746
2246
 
1747
2247
  [data-ui="card"] > [data-part="header"] > [data-part="title"] {
1748
- font-family: var(--font-sans);
2248
+ font-family: var(--font-heading);
1749
2249
  font-size: var(--text-lg);
1750
2250
  font-weight: var(--weight-semibold);
1751
2251
  line-height: var(--leading-tight);
@@ -1786,9 +2286,19 @@ table {
1786
2286
  padding-top: 0;
1787
2287
  }
1788
2288
 
2289
+ /* ── Motion ── */
2290
+ /* The hover lift is the only thing a card animates, and it is `none` until a
2291
+ theme states one — but the house rule is that a stylesheet which transitions
2292
+ carries its own opt-out, so a reader never has to check the token first. */
2293
+ @media (prefers-reduced-motion: reduce) {
2294
+ [data-ui="card"] {
2295
+ transition: none;
2296
+ }
2297
+ }
2298
+
1789
2299
  /* === primitives/checkbox.css === */
1790
2300
  /* @ui:component checkbox */
1791
- /* @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 */
2301
+ /* @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 */
1792
2302
 
1793
2303
  /* -- Label wrapper -- */
1794
2304
  [data-ui="checkbox-label"] {
@@ -1800,7 +2310,7 @@ table {
1800
2310
 
1801
2311
  [data-ui="checkbox-label"]:has([data-ui="checkbox"]:disabled) {
1802
2312
  cursor: not-allowed;
1803
- opacity: 0.5;
2313
+ opacity: var(--disabled-opacity);
1804
2314
  }
1805
2315
 
1806
2316
  /* -- Base -- */
@@ -1812,8 +2322,8 @@ table {
1812
2322
  width: var(--checkbox-size, 18px);
1813
2323
  height: var(--checkbox-size, 18px);
1814
2324
  flex-shrink: 0;
1815
- border: 1px solid var(--color-border);
1816
- border-radius: var(--checkbox-radius, var(--radius-sm));
2325
+ border: var(--border-width) solid var(--color-border);
2326
+ border-radius: var(--checkbox-radius);
1817
2327
  background: var(--color-bg);
1818
2328
  cursor: pointer;
1819
2329
  transition: background var(--duration-fast) var(--ease-default),
@@ -1826,8 +2336,9 @@ table {
1826
2336
  }
1827
2337
 
1828
2338
  [data-ui="checkbox"]:focus-visible {
1829
- outline: 2px solid var(--color-ring);
1830
- outline-offset: 2px;
2339
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2340
+ outline-offset: var(--focus-ring-offset);
2341
+ box-shadow: var(--focus-shadow);
1831
2342
  }
1832
2343
 
1833
2344
  /* -- Checked -- */
@@ -1918,7 +2429,7 @@ table {
1918
2429
  The mask has to opt out of the substitution to stay readable. [W3-3] */
1919
2430
  @media (forced-colors: active) {
1920
2431
  [data-ui="checkbox"] {
1921
- border: 1px solid ButtonText;
2432
+ border: var(--border-width) solid ButtonText;
1922
2433
  }
1923
2434
 
1924
2435
  [data-ui="checkbox"]:checked,
@@ -1942,7 +2453,7 @@ table {
1942
2453
 
1943
2454
  /* === primitives/chip.css === */
1944
2455
  /* @ui:component chip */
1945
- /* @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 */
2456
+ /* @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 */
1946
2457
 
1947
2458
  /* ── Base ── */
1948
2459
  [data-ui="chip"] {
@@ -1950,11 +2461,11 @@ table {
1950
2461
  align-items: center;
1951
2462
  gap: var(--space-1);
1952
2463
  padding: var(--space-1) var(--space-2);
1953
- border: 1px solid transparent;
2464
+ border: var(--border-width) solid transparent;
1954
2465
  border-radius: var(--chip-radius, var(--radius-full));
1955
2466
  background: var(--color-bg-muted);
1956
2467
  color: var(--color-fg);
1957
- font-family: var(--chip-font, var(--font-sans));
2468
+ font-family: var(--chip-font, var(--font-ui));
1958
2469
  font-size: var(--text-sm);
1959
2470
  font-weight: var(--weight-medium);
1960
2471
  line-height: 1.2;
@@ -1990,8 +2501,11 @@ table {
1990
2501
  }
1991
2502
 
1992
2503
  [data-ui="chip"] [data-part="dismiss"]:focus-visible {
1993
- outline: 2px solid var(--color-ring);
1994
- outline-offset: 1px;
2504
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2505
+ /* Half the default gap — the dismiss target is small, and the full ring
2506
+ would collide with the chip's own edge. */
2507
+ outline-offset: calc(var(--focus-ring-offset) / 2);
2508
+ box-shadow: var(--focus-shadow);
1995
2509
  }
1996
2510
 
1997
2511
  /* ── Variants ── */
@@ -2214,12 +2728,12 @@ table {
2214
2728
 
2215
2729
  /* === primitives/collapsible.css === */
2216
2730
  /* @ui:component collapsible */
2217
- /* @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 */
2731
+ /* @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 */
2218
2732
 
2219
2733
  /* ── Root — native <details>, so it opens/closes with zero JavaScript ── */
2220
2734
  [data-ui="collapsible"] {
2221
2735
  border-radius: var(--collapsible-radius, var(--radius-md));
2222
- font-family: var(--collapsible-font, var(--font-sans));
2736
+ font-family: var(--collapsible-font, var(--font-ui));
2223
2737
  color: var(--color-fg);
2224
2738
  }
2225
2739
 
@@ -2249,8 +2763,9 @@ table {
2249
2763
  }
2250
2764
 
2251
2765
  [data-ui="collapsible"] [data-part="trigger"]:focus-visible {
2252
- outline: 2px solid var(--color-ring);
2253
- outline-offset: 2px;
2766
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
2767
+ outline-offset: var(--focus-ring-offset);
2768
+ box-shadow: var(--focus-shadow);
2254
2769
  }
2255
2770
 
2256
2771
  /* Chevron indicator — rotates when open, CSS-only */
@@ -2259,8 +2774,8 @@ table {
2259
2774
  flex: none;
2260
2775
  width: 0.5em;
2261
2776
  height: 0.5em;
2262
- border-inline-end: 2px solid var(--color-fg-muted);
2263
- border-block-end: 2px solid var(--color-fg-muted);
2777
+ border-inline-end: var(--border-width-strong) solid var(--color-fg-muted);
2778
+ border-block-end: var(--border-width-strong) solid var(--color-fg-muted);
2264
2779
  transform: rotate(45deg);
2265
2780
  transition: transform var(--duration-normal) var(--ease-default);
2266
2781
  }
@@ -2279,7 +2794,7 @@ table {
2279
2794
 
2280
2795
  /* ── Bordered variant ── */
2281
2796
  [data-ui="collapsible"][data-variant="bordered"] {
2282
- border: 1px solid var(--color-border);
2797
+ border: var(--border-width) solid var(--color-border);
2283
2798
  }
2284
2799
 
2285
2800
  /* ── Open/close animation via ::details-content, where supported ── */
@@ -2412,13 +2927,13 @@ table {
2412
2927
 
2413
2928
  /* === primitives/description-list.css === */
2414
2929
  /* @ui:component description-list */
2415
- /* @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 */
2930
+ /* @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 */
2416
2931
 
2417
2932
  /* ── Base ── */
2418
2933
  [data-ui="description-list"] {
2419
2934
  margin: 0;
2420
2935
  padding: 0;
2421
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
2936
+ font-family: var(--doc-font, var(--font-body));
2422
2937
  }
2423
2938
 
2424
2939
  /* ── Term ── */
@@ -2474,7 +2989,7 @@ table {
2474
2989
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"],
2475
2990
  [data-ui="description-list"][data-divided]:not([data-variant]) [data-part="details"] {
2476
2991
  padding-bottom: var(--space-4);
2477
- border-bottom: 1px solid var(--color-border);
2992
+ border-bottom: var(--border-width) solid var(--color-border);
2478
2993
  }
2479
2994
 
2480
2995
  [data-ui="description-list"][data-divided][data-variant="vertical"] [data-part="details"]:last-child,
@@ -2486,7 +3001,7 @@ table {
2486
3001
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="term"],
2487
3002
  [data-ui="description-list"][data-divided][data-variant="horizontal"] [data-part="details"] {
2488
3003
  padding-bottom: var(--space-3);
2489
- border-bottom: 1px solid var(--color-border);
3004
+ border-bottom: var(--border-width) solid var(--color-border);
2490
3005
  }
2491
3006
 
2492
3007
  /* ── Size: Small ── */
@@ -2524,7 +3039,7 @@ table {
2524
3039
 
2525
3040
  /* === primitives/empty-state.css === */
2526
3041
  /* @ui:component empty-state */
2527
- /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl */
3042
+ /* @ui:tokens color-fg-muted color-fg-subtle space-3 space-4 space-6 space-8 text-sm text-lg text-3xl font-heading */
2528
3043
 
2529
3044
  /* ── Base ── */
2530
3045
  [data-ui="empty-state"] {
@@ -2545,6 +3060,7 @@ table {
2545
3060
 
2546
3061
  /* ── Title ── */
2547
3062
  [data-ui="empty-state"] [data-part="title"] {
3063
+ font-family: var(--font-heading);
2548
3064
  font-size: var(--text-lg);
2549
3065
  font-weight: var(--weight-medium);
2550
3066
  color: var(--color-fg);
@@ -2592,7 +3108,7 @@ table {
2592
3108
 
2593
3109
  /* === primitives/field-group.css === */
2594
3110
  /* @ui:component field-group */
2595
- /* @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 */
3111
+ /* @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 */
2596
3112
 
2597
3113
  /* ── Base / spacing ownership ──
2598
3114
  A field-group owns only its tight, density-aware intra-field step: label →
@@ -2604,7 +3120,7 @@ table {
2604
3120
  display: flex;
2605
3121
  flex-direction: column;
2606
3122
  gap: var(--space-2);
2607
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3123
+ font-family: var(--doc-font, var(--font-body));
2608
3124
  }
2609
3125
 
2610
3126
  /* ── Label ── */
@@ -2674,7 +3190,7 @@ table {
2674
3190
  [data-ui="field-group"][data-state="invalid"] [data-ui="textarea"],
2675
3191
  [data-ui="field-group"][data-state="invalid"] [data-ui="select"] {
2676
3192
  border-color: var(--field-error-color);
2677
- box-shadow: 0 0 0 1px var(--field-error-color);
3193
+ box-shadow: 0 0 0 var(--border-width) var(--field-error-color);
2678
3194
  }
2679
3195
 
2680
3196
  /* ── State: Validating ──
@@ -2684,7 +3200,7 @@ table {
2684
3200
  [data-ui="field-group"][data-state="validating"] [data-ui="textarea"],
2685
3201
  [data-ui="field-group"][data-state="validating"] [data-ui="select"] {
2686
3202
  border-color: var(--field-validating-color);
2687
- box-shadow: 0 0 0 1px var(--field-validating-color);
3203
+ box-shadow: 0 0 0 var(--border-width) var(--field-validating-color);
2688
3204
  }
2689
3205
 
2690
3206
  /* ── State: Disabled ──
@@ -2703,8 +3219,8 @@ table {
2703
3219
  [data-ui="field-group"][data-state="valid"] [data-ui="input"],
2704
3220
  [data-ui="field-group"][data-state="valid"] [data-ui="textarea"],
2705
3221
  [data-ui="field-group"][data-state="valid"] [data-ui="select"] {
2706
- border-color: var(--color-success, oklch(0.62 0.19 145));
2707
- box-shadow: 0 0 0 1px var(--color-success, oklch(0.62 0.19 145));
3222
+ border-color: var(--color-success);
3223
+ box-shadow: 0 0 0 var(--border-width) var(--color-success);
2708
3224
  }
2709
3225
 
2710
3226
  /* ── Variant: Horizontal ── */
@@ -3009,7 +3525,7 @@ table {
3009
3525
 
3010
3526
  /* === primitives/image.css === */
3011
3527
  /* @ui:component image */
3012
- /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-sans */
3528
+ /* @ui:tokens image-radius image-border image-border-width image-caption-size image-caption-color color-bg-muted font-body */
3013
3529
 
3014
3530
  /* ── Base ── */
3015
3531
  [data-ui="image"] {
@@ -3033,7 +3549,7 @@ table {
3033
3549
  [data-ui="image"] [data-part="caption"] {
3034
3550
  display: block;
3035
3551
  margin-top: var(--space-2);
3036
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3552
+ font-family: var(--doc-font, var(--font-body));
3037
3553
  font-size: var(--image-caption-size);
3038
3554
  color: var(--image-caption-color);
3039
3555
  line-height: 1.4;
@@ -3130,7 +3646,7 @@ table {
3130
3646
 
3131
3647
  /* === primitives/input.css === */
3132
3648
  /* @ui:component input */
3133
- /* @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 */
3649
+ /* @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 */
3134
3650
 
3135
3651
  /* ── Base ── */
3136
3652
  [data-ui="input"] {
@@ -3138,11 +3654,18 @@ table {
3138
3654
  width: 100%;
3139
3655
  height: var(--input-height, 40px);
3140
3656
  padding-inline: var(--space-3);
3141
- border: 1px solid var(--color-border);
3657
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
3658
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
3659
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
3660
+ is drawn. Identical to the shorthand at every other value of the token. */
3661
+ border-style: solid;
3662
+ border-color: var(--color-border);
3663
+ border-width: var(--input-border-width);
3142
3664
  border-radius: var(--input-radius, var(--radius-md));
3143
- background: var(--input-bg, var(--color-bg));
3665
+ corner-shape: var(--corner-shape);
3666
+ background: var(--input-fill);
3144
3667
  color: var(--color-fg);
3145
- font-family: var(--input-font, var(--font-sans));
3668
+ font-family: var(--input-font, var(--font-ui));
3146
3669
  font-size: var(--text-sm);
3147
3670
  line-height: 1;
3148
3671
  transition: border-color var(--duration-fast) var(--ease-default),
@@ -3158,8 +3681,11 @@ table {
3158
3681
  }
3159
3682
 
3160
3683
  [data-ui="input"]:focus {
3161
- outline: 2px solid var(--color-ring);
3162
- outline-offset: -1px;
3684
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
3685
+ /* The ring replaces the border rather than sitting outside it: inset by
3686
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
3687
+ outline-offset: calc(-1 * var(--input-border-width));
3688
+ box-shadow: var(--focus-shadow);
3163
3689
  border-color: transparent;
3164
3690
  }
3165
3691
 
@@ -3187,7 +3713,7 @@ table {
3187
3713
  }
3188
3714
 
3189
3715
  [data-ui="input"]:disabled {
3190
- opacity: 0.5;
3716
+ opacity: var(--disabled-opacity);
3191
3717
  cursor: not-allowed;
3192
3718
  }
3193
3719
 
@@ -3250,7 +3776,7 @@ table {
3250
3776
 
3251
3777
  /* === primitives/kbd.css === */
3252
3778
  /* @ui:component kbd */
3253
- /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs */
3779
+ /* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs border-width border-width-strong */
3254
3780
 
3255
3781
  /* ── Base ── */
3256
3782
  [data-ui="kbd"] {
@@ -3260,8 +3786,8 @@ table {
3260
3786
  height: 20px;
3261
3787
  min-width: 20px;
3262
3788
  padding-inline: var(--space-1h);
3263
- border: 1px solid var(--color-border);
3264
- border-bottom-width: 2px;
3789
+ border: var(--border-width) solid var(--color-border);
3790
+ border-bottom-width: var(--border-width-strong);
3265
3791
  border-radius: var(--radius-sm);
3266
3792
  background: var(--color-bg-subtle);
3267
3793
  color: var(--color-fg);
@@ -3274,7 +3800,7 @@ table {
3274
3800
 
3275
3801
  /* === primitives/key-value.css === */
3276
3802
  /* @ui:component key-value */
3277
- /* @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 */
3803
+ /* @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 */
3278
3804
 
3279
3805
  /* ── Base ── */
3280
3806
  [data-ui="key-value"] {
@@ -3283,7 +3809,7 @@ table {
3283
3809
  gap: var(--kv-pair-gap);
3284
3810
  margin: 0;
3285
3811
  padding: 0;
3286
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
3812
+ font-family: var(--doc-font, var(--font-body));
3287
3813
  }
3288
3814
 
3289
3815
  /* ── Label ── */
@@ -3413,12 +3939,12 @@ table {
3413
3939
 
3414
3940
  /* === primitives/label.css === */
3415
3941
  /* @ui:component label */
3416
- /* @ui:tokens color-fg color-fg-muted color-destructive font-sans text-xs text-sm text-base weight-medium */
3942
+ /* @ui:tokens color-fg color-fg-muted color-destructive font-ui text-xs text-sm text-base weight-medium disabled-opacity */
3417
3943
 
3418
3944
  /* ── Base ── */
3419
3945
  [data-ui="label"] {
3420
3946
  display: block;
3421
- font-family: var(--font-sans);
3947
+ font-family: var(--font-ui);
3422
3948
  font-size: var(--text-sm);
3423
3949
  font-weight: var(--weight-medium);
3424
3950
  color: var(--color-fg);
@@ -3451,21 +3977,21 @@ table {
3451
3977
 
3452
3978
  /* ── States ── */
3453
3979
  [data-ui="label"][data-state="disabled"] {
3454
- opacity: 0.5;
3980
+ opacity: var(--disabled-opacity);
3455
3981
  cursor: not-allowed;
3456
3982
  }
3457
3983
 
3458
3984
  /* === primitives/link.css === */
3459
3985
  /* @ui:component link */
3460
- /* @ui:tokens color-primary color-primary-hover color-primary-active color-fg color-fg-muted color-ring radius-sm space-1 */
3986
+ /* @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 */
3461
3987
 
3462
3988
  /* ── Base ── */
3463
3989
  [data-ui="link"] {
3464
3990
  color: var(--color-primary);
3465
3991
  font-family: inherit;
3466
- text-decoration: underline;
3467
- text-decoration-thickness: 1px;
3468
- text-underline-offset: 0.2em;
3992
+ text-decoration-line: var(--link-decoration);
3993
+ text-decoration-thickness: var(--link-thickness);
3994
+ text-underline-offset: var(--link-underline-offset);
3469
3995
  border-radius: var(--radius-sm);
3470
3996
  cursor: pointer;
3471
3997
  }
@@ -3479,8 +4005,9 @@ table {
3479
4005
  }
3480
4006
 
3481
4007
  [data-ui="link"]:focus-visible {
3482
- outline: 2px solid var(--color-ring);
3483
- outline-offset: 2px;
4008
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4009
+ outline-offset: var(--focus-ring-offset);
4010
+ box-shadow: var(--focus-shadow);
3484
4011
  }
3485
4012
 
3486
4013
  /* ── Variants ── */
@@ -3504,7 +4031,7 @@ table {
3504
4031
 
3505
4032
  /* === primitives/nav.css === */
3506
4033
  /* @ui:component nav */
3507
- /* @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 */
4034
+ /* @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 */
3508
4035
 
3509
4036
  /* ── Base ── */
3510
4037
  [data-ui="nav"] {
@@ -3554,14 +4081,14 @@ table {
3554
4081
 
3555
4082
  /* ── Underline variant ── */
3556
4083
  [data-ui="nav"][data-variant="underline"] {
3557
- border-bottom: 1px solid var(--color-border);
4084
+ border-bottom: var(--border-width) solid var(--color-border);
3558
4085
  gap: 0;
3559
4086
  }
3560
4087
 
3561
4088
  [data-ui="nav"][data-variant="underline"] [data-part="link"] {
3562
4089
  border-radius: 0;
3563
4090
  padding: var(--space-2) var(--space-4);
3564
- border-bottom: 2px solid transparent;
4091
+ border-bottom: var(--border-width-strong) solid transparent;
3565
4092
  margin-bottom: -1px;
3566
4093
  }
3567
4094
 
@@ -3617,7 +4144,7 @@ table {
3617
4144
 
3618
4145
  /* === primitives/page-break.css === */
3619
4146
  /* @ui:component page-break */
3620
- /* @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 */
4147
+ /* @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 */
3621
4148
 
3622
4149
  /* ── Base (Screen) ── */
3623
4150
  [data-ui="page-break"] {
@@ -3632,12 +4159,12 @@ table {
3632
4159
  [data-ui="page-break"]::after {
3633
4160
  content: "";
3634
4161
  flex: 1;
3635
- border-top: 1px var(--page-break-screen-style) var(--page-break-screen-color);
4162
+ border-top: var(--border-width) var(--page-break-screen-style) var(--page-break-screen-color);
3636
4163
  }
3637
4164
 
3638
4165
  /* ── Label (Screen) ── */
3639
4166
  [data-ui="page-break"] {
3640
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4167
+ font-family: var(--doc-font, var(--font-body));
3641
4168
  font-size: var(--page-break-screen-label-size);
3642
4169
  color: var(--page-break-screen-label-color);
3643
4170
  letter-spacing: 0.05em;
@@ -3679,7 +4206,7 @@ table {
3679
4206
 
3680
4207
  /* === primitives/progress.css === */
3681
4208
  /* @ui:component progress */
3682
- /* @ui:tokens color-primary color-bg-muted color-success color-warning color-destructive radius-full radius-md space-1 duration-normal ease-default */
4209
+ /* @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 */
3683
4210
 
3684
4211
  /* ── Base ── */
3685
4212
  [data-ui="progress"] {
@@ -3754,7 +4281,7 @@ table {
3754
4281
  substitution and paints `Highlight`; the track keeps a visible boundary. [W3-3] */
3755
4282
  @media (forced-colors: active) {
3756
4283
  [data-ui="progress"] [data-part="track"] {
3757
- border: 1px solid ButtonText;
4284
+ border: var(--border-width) solid ButtonText;
3758
4285
  }
3759
4286
 
3760
4287
  [data-ui="progress"] [data-part="fill"],
@@ -3768,7 +4295,7 @@ table {
3768
4295
 
3769
4296
  /* === primitives/radio.css === */
3770
4297
  /* @ui:component radio */
3771
- /* @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 */
4298
+ /* @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 */
3772
4299
 
3773
4300
  /* -- Radio group -- */
3774
4301
  [data-ui="radio-group"] {
@@ -3790,7 +4317,7 @@ table {
3790
4317
 
3791
4318
  [data-ui="radio-label"]:has([data-ui="radio"]:disabled) {
3792
4319
  cursor: not-allowed;
3793
- opacity: 0.5;
4320
+ opacity: var(--disabled-opacity);
3794
4321
  }
3795
4322
 
3796
4323
  /* -- Base -- */
@@ -3802,7 +4329,7 @@ table {
3802
4329
  width: var(--radio-size, 18px);
3803
4330
  height: var(--radio-size, 18px);
3804
4331
  flex-shrink: 0;
3805
- border: 1px solid var(--color-border);
4332
+ border: var(--border-width) solid var(--color-border);
3806
4333
  border-radius: var(--radius-full);
3807
4334
  background: var(--color-bg);
3808
4335
  cursor: pointer;
@@ -3816,8 +4343,9 @@ table {
3816
4343
  }
3817
4344
 
3818
4345
  [data-ui="radio"]:focus-visible {
3819
- outline: 2px solid var(--color-ring);
3820
- outline-offset: 2px;
4346
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4347
+ outline-offset: var(--focus-ring-offset);
4348
+ box-shadow: var(--focus-shadow);
3821
4349
  }
3822
4350
 
3823
4351
  /* -- Checked -- */
@@ -3870,7 +4398,7 @@ table {
3870
4398
  inside a `--color-primary` circle, and the OS collapses both to one colour. [W3-3] */
3871
4399
  @media (forced-colors: active) {
3872
4400
  [data-ui="radio"] {
3873
- border: 1px solid ButtonText;
4401
+ border: var(--border-width) solid ButtonText;
3874
4402
  }
3875
4403
 
3876
4404
  [data-ui="radio"]:checked {
@@ -3890,7 +4418,7 @@ table {
3890
4418
 
3891
4419
  /* === primitives/select.css === */
3892
4420
  /* @ui:component select */
3893
- /* @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 */
4421
+ /* @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 */
3894
4422
 
3895
4423
  /* -- Base -- */
3896
4424
  [data-ui="select"] {
@@ -3899,11 +4427,17 @@ table {
3899
4427
  height: var(--select-height, 40px);
3900
4428
  padding-inline: var(--space-3);
3901
4429
  padding-inline-end: var(--space-8, 2rem);
3902
- border: 1px solid var(--color-border);
4430
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
4431
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
4432
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
4433
+ is drawn. Identical to the shorthand at every other value of the token. */
4434
+ border-style: solid;
4435
+ border-color: var(--color-border);
4436
+ border-width: var(--input-border-width);
3903
4437
  border-radius: var(--select-radius, var(--radius-md));
3904
- background: var(--select-bg, var(--color-bg));
4438
+ background: var(--select-bg, var(--input-fill));
3905
4439
  color: var(--color-fg);
3906
- font-family: var(--select-font, var(--font-sans));
4440
+ font-family: var(--select-font, var(--font-ui));
3907
4441
  font-size: var(--text-sm);
3908
4442
  line-height: 1;
3909
4443
  cursor: pointer;
@@ -3933,8 +4467,11 @@ table {
3933
4467
  }
3934
4468
 
3935
4469
  [data-ui="select"]:focus {
3936
- outline: 2px solid var(--color-ring);
3937
- outline-offset: -1px;
4470
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
4471
+ /* The ring replaces the border rather than sitting outside it: inset by
4472
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
4473
+ outline-offset: calc(-1 * var(--input-border-width));
4474
+ box-shadow: var(--focus-shadow);
3938
4475
  border-color: transparent;
3939
4476
  }
3940
4477
 
@@ -3967,7 +4504,7 @@ table {
3967
4504
  }
3968
4505
 
3969
4506
  [data-ui="select"]:disabled {
3970
- opacity: 0.5;
4507
+ opacity: var(--disabled-opacity);
3971
4508
  cursor: not-allowed;
3972
4509
  }
3973
4510
 
@@ -3980,12 +4517,12 @@ table {
3980
4517
 
3981
4518
  /* === primitives/separator.css === */
3982
4519
  /* @ui:component separator */
3983
- /* @ui:tokens color-border space-4 text-xs color-fg-muted font-sans */
4520
+ /* @ui:tokens color-border space-4 text-xs color-fg-muted font-ui border-width-strong divider-width divider-style */
3984
4521
 
3985
4522
  /* ── Base (horizontal) ── */
3986
4523
  [data-ui="separator"] {
3987
4524
  border: none;
3988
- border-top: 1px solid var(--color-border);
4525
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
3989
4526
  margin: 0;
3990
4527
  width: 100%;
3991
4528
  }
@@ -3993,7 +4530,7 @@ table {
3993
4530
  /* ── Vertical ── */
3994
4531
  [data-ui="separator"][data-variant="vertical"] {
3995
4532
  border-top: none;
3996
- border-inline-start: 1px solid var(--color-border);
4533
+ border-inline-start: var(--divider-width) var(--divider-style) var(--color-border);
3997
4534
  width: auto;
3998
4535
  height: 100%;
3999
4536
  align-self: stretch;
@@ -4011,11 +4548,11 @@ div[data-ui="separator"]::before,
4011
4548
  div[data-ui="separator"]::after {
4012
4549
  content: "";
4013
4550
  flex: 1;
4014
- border-top: 1px solid var(--color-border);
4551
+ border-top: var(--divider-width) var(--divider-style) var(--color-border);
4015
4552
  }
4016
4553
 
4017
4554
  [data-ui="separator"] [data-part="label"] {
4018
- font-family: var(--font-sans);
4555
+ font-family: var(--font-ui);
4019
4556
  font-size: var(--text-xs);
4020
4557
  color: var(--color-fg-muted);
4021
4558
  white-space: nowrap;
@@ -4053,17 +4590,17 @@ div[data-ui="separator"][data-style="dotted"]::after {
4053
4590
 
4054
4591
  /* ── Style: Thick ── */
4055
4592
  [data-ui="separator"][data-style="thick"] {
4056
- border-top-width: 2px;
4593
+ border-top-width: var(--border-width-strong);
4057
4594
  }
4058
4595
 
4059
4596
  [data-ui="separator"][data-style="thick"][data-variant="vertical"] {
4060
4597
  border-top-width: 0;
4061
- border-inline-start-width: 2px;
4598
+ border-inline-start-width: var(--border-width-strong);
4062
4599
  }
4063
4600
 
4064
4601
  div[data-ui="separator"][data-style="thick"]::before,
4065
4602
  div[data-ui="separator"][data-style="thick"]::after {
4066
- border-top-width: 2px;
4603
+ border-top-width: var(--border-width-strong);
4067
4604
  }
4068
4605
 
4069
4606
  /* ── Vertical Sizes ── */
@@ -4081,20 +4618,20 @@ div[data-ui="separator"][data-style="thick"]::after {
4081
4618
 
4082
4619
  /* === primitives/signature.css === */
4083
4620
  /* @ui:component signature */
4084
- /* @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 */
4621
+ /* @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 */
4085
4622
 
4086
4623
  /* ── Base ── */
4087
4624
  [data-ui="signature"] {
4088
4625
  display: flex;
4089
4626
  flex-direction: column;
4090
4627
  gap: var(--space-2);
4091
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
4628
+ font-family: var(--doc-font, var(--font-body));
4092
4629
  margin-top: var(--doc-signature-gap);
4093
4630
  }
4094
4631
 
4095
4632
  /* ── Line ── */
4096
4633
  [data-ui="signature"] [data-part="line"] {
4097
- border-top: 1px solid var(--doc-signature-line-color);
4634
+ border-top: var(--border-width) solid var(--doc-signature-line-color);
4098
4635
  min-height: 1px;
4099
4636
  }
4100
4637
 
@@ -4197,14 +4734,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4197
4734
 
4198
4735
  /* === primitives/spinner.css === */
4199
4736
  /* @ui:component spinner */
4200
- /* @ui:tokens color-border color-primary radius-full duration-normal ease-default */
4737
+ /* @ui:tokens color-border color-primary radius-full duration-normal ease-default border-width-strong border-width-lg */
4201
4738
 
4202
4739
  /* ── Base ── */
4203
4740
  [data-ui="spinner"] {
4204
4741
  display: inline-block;
4205
4742
  width: 24px;
4206
4743
  height: 24px;
4207
- border: 2px solid var(--color-border);
4744
+ border: var(--border-width-strong) solid var(--color-border);
4208
4745
  border-top-color: var(--color-primary);
4209
4746
  border-radius: var(--radius-full);
4210
4747
  animation: faqir-spin 0.75s linear infinite;
@@ -4220,13 +4757,13 @@ div[data-ui="separator"][data-style="thick"]::after {
4220
4757
  [data-ui="spinner"][data-size="lg"] {
4221
4758
  width: 32px;
4222
4759
  height: 32px;
4223
- border-width: 3px;
4760
+ border-width: var(--border-width-lg);
4224
4761
  }
4225
4762
 
4226
4763
  [data-ui="spinner"][data-size="xl"] {
4227
4764
  width: 48px;
4228
4765
  height: 48px;
4229
- border-width: 3px;
4766
+ border-width: var(--border-width-lg);
4230
4767
  }
4231
4768
 
4232
4769
  /* ── Motion ── */
@@ -4808,14 +5345,14 @@ div[data-ui="separator"][data-style="thick"]::after {
4808
5345
 
4809
5346
  /* === primitives/stat.css === */
4810
5347
  /* @ui:component stat */
4811
- /* @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 */
5348
+ /* @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 */
4812
5349
 
4813
5350
  /* ── Base ── */
4814
5351
  [data-ui="stat"] {
4815
5352
  display: flex;
4816
5353
  flex-direction: column;
4817
5354
  gap: var(--space-1);
4818
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
5355
+ font-family: var(--doc-font, var(--font-body));
4819
5356
  }
4820
5357
 
4821
5358
  /* ── Label ── */
@@ -4829,6 +5366,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4829
5366
 
4830
5367
  /* ── Value ── */
4831
5368
  [data-ui="stat"] [data-part="value"] {
5369
+ font-family: var(--font-heading);
4832
5370
  font-size: var(--stat-value-size);
4833
5371
  font-weight: var(--stat-value-weight);
4834
5372
  color: var(--color-fg);
@@ -4887,10 +5425,10 @@ div[data-ui="separator"][data-style="thick"]::after {
4887
5425
  /* ── Variant: Card ── */
4888
5426
  [data-ui="stat"][data-variant="card"] {
4889
5427
  padding: var(--space-4);
4890
- border: 1px solid var(--color-border);
5428
+ border: var(--border-width) solid var(--color-border);
4891
5429
  border-radius: var(--radius-md, 0.375rem);
4892
5430
  background: var(--color-bg);
4893
- box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.05));
5431
+ box-shadow: var(--shadow-sm);
4894
5432
  }
4895
5433
 
4896
5434
  /* ── Value + Change Inline ── */
@@ -4902,7 +5440,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4902
5440
  @media print {
4903
5441
  [data-ui="stat"][data-variant="card"] {
4904
5442
  box-shadow: none;
4905
- border: 1px solid var(--doc-print-border-color, var(--color-border, #ccc));
5443
+ border: var(--border-width) solid var(--doc-print-border-color, var(--color-border, #ccc));
4906
5444
  }
4907
5445
 
4908
5446
  [data-ui="stat"] {
@@ -4912,7 +5450,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4912
5450
 
4913
5451
  /* === primitives/stepper.css === */
4914
5452
  /* @ui:component stepper */
4915
- /* @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 */
5453
+ /* @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 */
4916
5454
 
4917
5455
  /* ── Base ── */
4918
5456
  [data-ui="stepper"] {
@@ -4991,7 +5529,7 @@ div[data-ui="separator"][data-style="thick"]::after {
4991
5529
  The tight phone metrics are the base; the roomier ones arrive at `sm`. */
4992
5530
  [data-ui="stepper"] [data-part="connector"] {
4993
5531
  flex: 1;
4994
- height: 2px;
5532
+ height: var(--border-width-strong);
4995
5533
  background: var(--color-border);
4996
5534
  margin: 0 var(--space-1);
4997
5535
  min-width: var(--space-2);
@@ -5059,18 +5597,20 @@ div[data-ui="separator"][data-style="thick"]::after {
5059
5597
 
5060
5598
  /* === primitives/surface.css === */
5061
5599
  /* @ui:component surface */
5062
- /* @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 */
5600
+ /* @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 */
5063
5601
 
5064
5602
  /* ── Base ── */
5065
5603
  [data-ui="surface"] {
5066
- background: var(--color-surface-1);
5604
+ background-color: var(--color-surface-1);
5605
+ background-image: var(--texture-surface);
5067
5606
  border-radius: var(--radius-lg);
5068
- border: 1px solid var(--color-surface-1-border);
5607
+ corner-shape: var(--corner-shape);
5608
+ border: var(--border-width) solid var(--color-surface-1-border);
5069
5609
  }
5070
5610
 
5071
5611
  /* ── Elevation Variants ── */
5072
5612
  [data-ui="surface"][data-variant="flat"] {
5073
- background: var(--color-bg);
5613
+ background-color: var(--color-bg);
5074
5614
  border: none;
5075
5615
  box-shadow: none;
5076
5616
  }
@@ -5080,11 +5620,22 @@ div[data-ui="separator"][data-style="thick"]::after {
5080
5620
  }
5081
5621
 
5082
5622
  [data-ui="surface"][data-variant="overlay"] {
5083
- background: var(--color-surface-2);
5623
+ background-color: var(--color-surface-2);
5084
5624
  box-shadow: var(--shadow-lg);
5085
5625
  border-color: var(--color-surface-2-border);
5086
5626
  }
5087
5627
 
5628
+ /* An overlay is the one surface variant that floats over other content, so it
5629
+ is the one that can be frosted. Guarded exactly as themes/glass.css guards
5630
+ its own: a browser without backdrop-filter renders the solid surface above
5631
+ and never sees this rule. */
5632
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
5633
+ [data-ui="surface"][data-variant="overlay"] {
5634
+ -webkit-backdrop-filter: var(--surface-backdrop);
5635
+ backdrop-filter: var(--surface-backdrop);
5636
+ }
5637
+ }
5638
+
5088
5639
  /* ── Padding Sizes ── */
5089
5640
  [data-ui="surface"][data-size="sm"] {
5090
5641
  padding: var(--space-3);
@@ -5140,7 +5691,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5140
5691
 
5141
5692
  /* === primitives/switch.css === */
5142
5693
  /* @ui:component switch */
5143
- /* @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 */
5694
+ /* @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 */
5144
5695
 
5145
5696
  /* -- Label wrapper -- */
5146
5697
  [data-ui="switch-label"] {
@@ -5152,7 +5703,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5152
5703
 
5153
5704
  [data-ui="switch-label"]:has([data-ui="switch"]:disabled) {
5154
5705
  cursor: not-allowed;
5155
- opacity: 0.5;
5706
+ opacity: var(--disabled-opacity);
5156
5707
  }
5157
5708
 
5158
5709
  /* -- Base (track) -- */
@@ -5180,8 +5731,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5180
5731
  width: var(--switch-width, 44px);
5181
5732
  height: var(--switch-height, 24px);
5182
5733
  padding: var(--space-0h, 2px);
5183
- border: 1px solid var(--color-border);
5184
- border-radius: var(--radius-full);
5734
+ border: var(--border-width) solid var(--color-border);
5735
+ border-radius: var(--switch-radius);
5185
5736
  background: var(--switch-bg, var(--color-bg-muted));
5186
5737
  cursor: pointer;
5187
5738
  position: relative;
@@ -5191,8 +5742,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5191
5742
  }
5192
5743
 
5193
5744
  [data-ui="switch"]:focus-visible {
5194
- outline: 2px solid var(--color-ring);
5195
- outline-offset: 2px;
5745
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
5746
+ outline-offset: var(--focus-ring-offset);
5747
+ box-shadow: var(--focus-shadow);
5196
5748
  }
5197
5749
 
5198
5750
  /* -- Thumb (pseudo-element for <input>, child for custom markup) -- */
@@ -5201,7 +5753,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5201
5753
  display: block;
5202
5754
  width: var(--switch-thumb, 18px);
5203
5755
  height: var(--switch-thumb, 18px);
5204
- border-radius: var(--radius-full);
5756
+ border-radius: var(--switch-radius);
5205
5757
  background: var(--color-primary-fg);
5206
5758
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5207
5759
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5213,7 +5765,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5213
5765
  display: block;
5214
5766
  width: var(--switch-thumb, 18px);
5215
5767
  height: var(--switch-thumb, 18px);
5216
- border-radius: var(--radius-full);
5768
+ border-radius: var(--switch-radius);
5217
5769
  background: var(--color-primary-fg);
5218
5770
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
5219
5771
  transition: transform var(--duration-fast) var(--ease-default);
@@ -5295,7 +5847,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5295
5847
  the track's border is always visible, and ON fills it with `Highlight`. [W3-3] */
5296
5848
  @media (forced-colors: active) {
5297
5849
  [data-ui="switch"] {
5298
- border: 1px solid ButtonText;
5850
+ border: var(--border-width) solid ButtonText;
5299
5851
  background: ButtonFace;
5300
5852
  }
5301
5853
 
@@ -5452,25 +6004,31 @@ div[data-ui="separator"][data-style="thick"]::after {
5452
6004
 
5453
6005
  /* === primitives/text.css === */
5454
6006
  /* @ui:component text */
5455
- /* @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 */
6007
+ /* @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 */
5456
6008
 
5457
6009
  /* ── Heading ── */
5458
6010
  [data-ui="heading"] {
5459
- font-family: var(--font-sans);
5460
- font-weight: var(--weight-bold);
6011
+ font-family: var(--font-heading);
6012
+ font-weight: var(--heading-weight);
5461
6013
  color: var(--color-fg);
5462
- line-height: var(--leading-tight);
5463
- letter-spacing: -0.01em;
6014
+ line-height: var(--heading-leading);
6015
+ text-transform: var(--heading-transform);
6016
+ font-variant-caps: var(--heading-caps);
6017
+ /* The optical tightening a large heading needs, PLUS whatever tracking the
6018
+ theme's voice asks for on top of it — so a theme that wants wide-tracked
6019
+ headings sets --heading-tracking once and every size follows, instead of
6020
+ each size having to re-derive its own number. */
6021
+ letter-spacing: calc(-0.01em + var(--heading-tracking));
5464
6022
  }
5465
6023
 
5466
6024
  [data-ui="heading"][data-size="1"] {
5467
6025
  font-size: var(--text-4xl);
5468
- letter-spacing: -0.02em;
6026
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5469
6027
  }
5470
6028
 
5471
6029
  [data-ui="heading"][data-size="2"] {
5472
6030
  font-size: var(--text-3xl);
5473
- letter-spacing: -0.02em;
6031
+ letter-spacing: calc(-0.02em + var(--heading-tracking));
5474
6032
  }
5475
6033
 
5476
6034
  [data-ui="heading"][data-size="3"] {
@@ -5494,7 +6052,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5494
6052
 
5495
6053
  /* ── Text ── */
5496
6054
  [data-ui="text"] {
5497
- font-family: var(--font-sans);
6055
+ font-family: var(--font-body);
5498
6056
  color: var(--color-fg);
5499
6057
  }
5500
6058
 
@@ -5572,7 +6130,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5572
6130
 
5573
6131
  /* === primitives/textarea.css === */
5574
6132
  /* @ui:component textarea */
5575
- /* @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 */
6133
+ /* @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 */
5576
6134
 
5577
6135
  /* -- Base -- */
5578
6136
  [data-ui="textarea"] {
@@ -5580,11 +6138,17 @@ div[data-ui="separator"][data-style="thick"]::after {
5580
6138
  width: 100%;
5581
6139
  min-height: var(--textarea-min-height, 80px);
5582
6140
  padding: var(--space-2) var(--space-3);
5583
- border: 1px solid var(--color-border);
6141
+ /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
6142
+ ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
6143
+ as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
6144
+ is drawn. Identical to the shorthand at every other value of the token. */
6145
+ border-style: solid;
6146
+ border-color: var(--color-border);
6147
+ border-width: var(--input-border-width);
5584
6148
  border-radius: var(--textarea-radius, var(--radius-md));
5585
- background: var(--textarea-bg, var(--color-bg));
6149
+ background: var(--textarea-bg, var(--input-fill));
5586
6150
  color: var(--color-fg);
5587
- font-family: var(--textarea-font, var(--font-sans));
6151
+ font-family: var(--textarea-font, var(--font-ui));
5588
6152
  font-size: var(--text-sm);
5589
6153
  line-height: 1.5;
5590
6154
  resize: vertical;
@@ -5601,8 +6165,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5601
6165
  }
5602
6166
 
5603
6167
  [data-ui="textarea"]:focus {
5604
- outline: 2px solid var(--color-ring);
5605
- outline-offset: -1px;
6168
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6169
+ /* The ring replaces the border rather than sitting outside it: inset by
6170
+ exactly the edge it covers, so a heavier shape theme stays aligned. */
6171
+ outline-offset: calc(-1 * var(--input-border-width));
6172
+ box-shadow: var(--focus-shadow);
5606
6173
  border-color: transparent;
5607
6174
  }
5608
6175
 
@@ -5630,7 +6197,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5630
6197
  }
5631
6198
 
5632
6199
  [data-ui="textarea"]:disabled {
5633
- opacity: 0.5;
6200
+ opacity: var(--disabled-opacity);
5634
6201
  cursor: not-allowed;
5635
6202
  resize: none;
5636
6203
  }
@@ -5644,7 +6211,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5644
6211
 
5645
6212
  /* === primitives/toggle.css === */
5646
6213
  /* @ui:component toggle */
5647
- /* @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 */
6214
+ /* @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 */
5648
6215
 
5649
6216
  /* ── Base (off / unpressed) ── */
5650
6217
  [data-ui="toggle"] {
@@ -5653,11 +6220,11 @@ div[data-ui="separator"][data-style="thick"]::after {
5653
6220
  justify-content: center;
5654
6221
  gap: var(--space-1h);
5655
6222
  padding: var(--toggle-pad-y, var(--space-1h)) var(--toggle-pad-x, var(--space-3));
5656
- border: 1px solid var(--color-border);
6223
+ border: var(--border-width) solid var(--color-border);
5657
6224
  border-radius: var(--toggle-radius, var(--radius-md));
5658
6225
  background: var(--color-bg);
5659
6226
  color: var(--color-fg-muted);
5660
- font-family: var(--toggle-font, var(--font-sans));
6227
+ font-family: var(--toggle-font, var(--font-ui));
5661
6228
  font-size: var(--text-sm);
5662
6229
  font-weight: var(--weight-medium);
5663
6230
  line-height: 1;
@@ -5674,8 +6241,9 @@ div[data-ui="separator"][data-style="thick"]::after {
5674
6241
  }
5675
6242
 
5676
6243
  [data-ui="toggle"]:focus-visible {
5677
- outline: 2px solid var(--color-ring);
5678
- outline-offset: 2px;
6244
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6245
+ outline-offset: var(--focus-ring-offset);
6246
+ box-shadow: var(--focus-shadow);
5679
6247
  }
5680
6248
 
5681
6249
  /* ── Pressed / on — styled entirely off aria-pressed, no JS ── */
@@ -5692,7 +6260,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5692
6260
 
5693
6261
  /* ── Disabled ── */
5694
6262
  [data-ui="toggle"]:disabled {
5695
- opacity: 0.5;
6263
+ opacity: var(--disabled-opacity);
5696
6264
  cursor: not-allowed;
5697
6265
  }
5698
6266
 
@@ -5716,7 +6284,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5716
6284
 
5717
6285
  /* === primitives/watermark.css === */
5718
6286
  /* @ui:component watermark */
5719
- /* @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 */
6287
+ /* @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 */
5720
6288
 
5721
6289
  [data-ui="watermark"] {
5722
6290
  position: fixed;
@@ -5735,7 +6303,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5735
6303
 
5736
6304
  [data-ui="watermark"] > [data-part="mark"] {
5737
6305
  color: var(--color-fg-muted);
5738
- font-family: var(--doc-font, var(--font-sans));
6306
+ font-family: var(--doc-font, var(--font-body));
5739
6307
  font-size: var(--text-4xl);
5740
6308
  font-weight: var(--weight-bold);
5741
6309
  line-height: var(--leading-tight);
@@ -5793,7 +6361,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5793
6361
 
5794
6362
  /* === recipes/accordion.css === */
5795
6363
  /* @ui:component accordion */
5796
- /* @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 */
6364
+ /* @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 */
5797
6365
 
5798
6366
  /* ── Root ── */
5799
6367
  [data-ui="accordion"] {
@@ -5802,7 +6370,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5802
6370
 
5803
6371
  /* ── Item ── */
5804
6372
  [data-ui="accordion"] [data-part="item"] {
5805
- border-bottom: 1px solid var(--color-border);
6373
+ border-bottom: var(--border-width) solid var(--color-border);
5806
6374
  }
5807
6375
 
5808
6376
  [data-ui="accordion"] [data-part="item"]:last-child {
@@ -5819,7 +6387,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5819
6387
  border: none;
5820
6388
  background: transparent;
5821
6389
  color: var(--color-fg);
5822
- font-family: var(--font-sans, system-ui, sans-serif);
6390
+ font-family: var(--font-ui);
5823
6391
  font-size: var(--text-base);
5824
6392
  font-weight: var(--weight-medium);
5825
6393
  text-align: start;
@@ -5833,8 +6401,8 @@ div[data-ui="separator"][data-style="thick"]::after {
5833
6401
  }
5834
6402
 
5835
6403
  [data-ui="accordion"] [data-part="trigger"]:focus-visible {
5836
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
5837
- outline-offset: -2px;
6404
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6405
+ outline-offset: calc(-1 * var(--focus-ring-offset));
5838
6406
  border-radius: var(--radius-sm, 0.25rem);
5839
6407
  }
5840
6408
 
@@ -5866,13 +6434,13 @@ div[data-ui="separator"][data-style="thick"]::after {
5866
6434
 
5867
6435
  /* ── Bordered Variant ── */
5868
6436
  [data-ui="accordion"][data-bordered="true"] {
5869
- border: 1px solid var(--color-border);
6437
+ border: var(--border-width) solid var(--color-border);
5870
6438
  border-radius: var(--radius-lg);
5871
6439
  overflow: hidden;
5872
6440
  }
5873
6441
 
5874
6442
  [data-ui="accordion"][data-bordered="true"] [data-part="item"] {
5875
- border-bottom: 1px solid var(--color-border);
6443
+ border-bottom: var(--border-width) solid var(--color-border);
5876
6444
  }
5877
6445
 
5878
6446
  [data-ui="accordion"][data-bordered="true"] [data-part="item"]:last-child {
@@ -5889,7 +6457,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5889
6457
 
5890
6458
  /* === recipes/alert-dialog.css === */
5891
6459
  /* @ui:component alert-dialog */
5892
- /* @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 */
6460
+ /* @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 */
5893
6461
 
5894
6462
  /* ── Root ── */
5895
6463
  [data-ui="alert-dialog"] {
@@ -5925,7 +6493,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5925
6493
  max-height: 85vh;
5926
6494
  overflow-y: auto;
5927
6495
  background: var(--color-bg);
5928
- border: 1px solid var(--color-border);
6496
+ border: var(--border-width) solid var(--color-border);
5929
6497
  border-radius: var(--alert-dialog-radius, var(--radius-xl));
5930
6498
  box-shadow: var(--alert-dialog-shadow, var(--shadow-xl));
5931
6499
  opacity: 0;
@@ -5971,6 +6539,7 @@ div[data-ui="separator"][data-style="thick"]::after {
5971
6539
  /* ── Title ── */
5972
6540
  [data-ui="alert-dialog"] [data-part="title"] {
5973
6541
  margin: 0;
6542
+ font-family: var(--font-heading);
5974
6543
  font-size: var(--text-lg, 1.125rem);
5975
6544
  font-weight: var(--weight-semibold, 600);
5976
6545
  color: var(--color-fg);
@@ -6010,7 +6579,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6010
6579
 
6011
6580
  /* === recipes/barcode.css === */
6012
6581
  /* @ui:component barcode */
6013
- /* @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 */
6582
+ /* @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 */
6014
6583
 
6015
6584
  [data-ui="barcode"] {
6016
6585
  display: inline-flex;
@@ -6037,7 +6606,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6037
6606
 
6038
6607
  [data-ui="barcode"] > [data-part="caption"] {
6039
6608
  color: var(--doc-legal-color, var(--color-fg-muted));
6040
- font-family: var(--font-mono, var(--doc-font, var(--font-sans)));
6609
+ font-family: var(--font-mono, var(--doc-font, var(--font-body)));
6041
6610
  font-size: var(--doc-legal-size);
6042
6611
  line-height: var(--leading-normal);
6043
6612
  text-align: center;
@@ -6057,7 +6626,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6057
6626
 
6058
6627
  /* === recipes/calendar.css === */
6059
6628
  /* @ui:component calendar */
6060
- /* @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 */
6629
+ /* @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 */
6061
6630
 
6062
6631
  /* ── Root ── */
6063
6632
  [data-ui="calendar"] {
@@ -6090,7 +6659,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6090
6659
  width: 28px;
6091
6660
  height: 28px;
6092
6661
  padding: 0;
6093
- border: 1px solid var(--color-border);
6662
+ border: var(--border-width) solid var(--color-border);
6094
6663
  border-radius: var(--radius-md);
6095
6664
  background: var(--color-bg);
6096
6665
  color: var(--color-fg);
@@ -6106,13 +6675,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6106
6675
 
6107
6676
  [data-ui="calendar"] [data-part="nav-prev"]:focus-visible,
6108
6677
  [data-ui="calendar"] [data-part="nav-next"]:focus-visible {
6109
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6110
- outline-offset: 2px;
6678
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6679
+ outline-offset: var(--focus-ring-offset);
6111
6680
  }
6112
6681
 
6113
6682
  [data-ui="calendar"] [data-part="nav-prev"]:disabled,
6114
6683
  [data-ui="calendar"] [data-part="nav-next"]:disabled {
6115
- opacity: 0.4;
6684
+ /* Dimmer than a disabled control — 0.4 at the 0.5 default — and it follows a
6685
+ theme's `--disabled-opacity` like every other disabled dim (1.1A-27). */
6686
+ opacity: calc(var(--disabled-opacity) * 0.8);
6116
6687
  cursor: not-allowed;
6117
6688
  }
6118
6689
 
@@ -6147,11 +6718,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6147
6718
  width: 36px;
6148
6719
  height: 36px;
6149
6720
  padding: 0;
6150
- border: 1px solid transparent;
6721
+ border: var(--border-width) solid transparent;
6151
6722
  border-radius: var(--radius-full);
6152
6723
  background: transparent;
6153
6724
  color: var(--color-fg);
6154
- font-family: var(--font-sans, system-ui, sans-serif);
6725
+ font-family: var(--font-ui);
6155
6726
  font-size: var(--text-sm);
6156
6727
  cursor: pointer;
6157
6728
  transition: background var(--duration-fast) var(--ease-default),
@@ -6164,8 +6735,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6164
6735
  }
6165
6736
 
6166
6737
  [data-ui="calendar"] [data-part="day"]:focus-visible {
6167
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6168
- outline-offset: 2px;
6738
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6739
+ outline-offset: var(--focus-ring-offset);
6169
6740
  }
6170
6741
 
6171
6742
  /* ── Today ── */
@@ -6200,7 +6771,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6200
6771
  /* ── Disabled days (aria-disabled keeps them focusable; :disabled for hard-disabled) ── */
6201
6772
  [data-ui="calendar"] [data-part="day"][aria-disabled="true"],
6202
6773
  [data-ui="calendar"] [data-part="day"]:disabled {
6203
- opacity: 0.5;
6774
+ opacity: var(--disabled-opacity);
6204
6775
  cursor: not-allowed;
6205
6776
  text-decoration: line-through;
6206
6777
  }
@@ -6264,7 +6835,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6264
6835
 
6265
6836
  /* === recipes/carousel.css === */
6266
6837
  /* @ui:component carousel */
6267
- /* @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 */
6838
+ /* @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 */
6268
6839
 
6269
6840
  /* The sliding is CSS, not JavaScript: the viewport is a scroll-snap strip and
6270
6841
  every slide is a snap target. Everything below works with no controller
@@ -6278,7 +6849,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6278
6849
  inline-size: 100%;
6279
6850
  min-inline-size: 0;
6280
6851
  max-inline-size: 100%;
6281
- font-family: var(--carousel-font, var(--font-sans));
6852
+ font-family: var(--carousel-font, var(--font-ui));
6282
6853
  }
6283
6854
 
6284
6855
  /* ── Viewport: the scroll-snap strip ── */
@@ -6304,8 +6875,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6304
6875
  }
6305
6876
 
6306
6877
  [data-ui="carousel"] [data-part="viewport"]:focus-visible {
6307
- outline: 2px solid var(--color-ring);
6308
- outline-offset: 2px;
6878
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6879
+ outline-offset: var(--focus-ring-offset);
6309
6880
  }
6310
6881
 
6311
6882
  /* ── Slide: one full-width snap target ── */
@@ -6313,7 +6884,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6313
6884
  flex: 0 0 var(--carousel-slide-size, 100%);
6314
6885
  min-inline-size: 0;
6315
6886
  padding: var(--space-4);
6316
- border: 1px solid var(--color-border);
6887
+ border: var(--border-width) solid var(--color-border);
6317
6888
  border-radius: var(--radius-lg);
6318
6889
  background: var(--color-bg);
6319
6890
  color: var(--color-fg);
@@ -6342,7 +6913,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6342
6913
  min-inline-size: 2rem;
6343
6914
  min-block-size: 2rem;
6344
6915
  padding: var(--space-1) var(--space-2);
6345
- border: 1px solid var(--color-border);
6916
+ border: var(--border-width) solid var(--color-border);
6346
6917
  border-radius: var(--radius-md);
6347
6918
  background: var(--color-bg);
6348
6919
  color: var(--color-fg);
@@ -6361,14 +6932,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6361
6932
  [data-ui="carousel"] [data-part="prev"]:focus-visible,
6362
6933
  [data-ui="carousel"] [data-part="next"]:focus-visible,
6363
6934
  [data-ui="carousel"] [data-part="dot"]:focus-visible {
6364
- outline: 2px solid var(--color-ring);
6365
- outline-offset: 2px;
6935
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
6936
+ outline-offset: var(--focus-ring-offset);
6366
6937
  }
6367
6938
 
6368
6939
  /* Boundary contract "stop" — the controller disables the end button. */
6369
6940
  [data-ui="carousel"] [data-part="prev"]:disabled,
6370
6941
  [data-ui="carousel"] [data-part="next"]:disabled {
6371
- opacity: 0.4;
6942
+ /* 0.4 at the 0.5 default, and a theme's `--disabled-opacity` moves it (1.1A-27). */
6943
+ opacity: calc(var(--disabled-opacity) * 0.8);
6372
6944
  cursor: not-allowed;
6373
6945
  }
6374
6946
 
@@ -6377,7 +6949,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6377
6949
  inline-size: 0.625rem;
6378
6950
  block-size: 0.625rem;
6379
6951
  padding: 0;
6380
- border: 1px solid var(--color-border);
6952
+ border: var(--border-width) solid var(--color-border);
6381
6953
  border-radius: 50%;
6382
6954
  background: var(--color-bg-muted);
6383
6955
  cursor: pointer;
@@ -6413,7 +6985,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6413
6985
 
6414
6986
  /* === recipes/combobox.css === */
6415
6987
  /* @ui:component combobox */
6416
- /* @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 */
6988
+ /* @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 */
6417
6989
 
6418
6990
  /* ── Root ── */
6419
6991
  [data-ui="combobox"] {
@@ -6427,11 +6999,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6427
6999
  display: block;
6428
7000
  width: 100%;
6429
7001
  padding: var(--space-2) var(--space-3);
6430
- border: 1px solid var(--color-border);
7002
+ border: var(--border-width) solid var(--color-border);
6431
7003
  border-radius: var(--radius-md);
6432
7004
  background: var(--color-bg);
6433
7005
  color: var(--color-fg);
6434
- font-family: var(--font-sans, system-ui, sans-serif);
7006
+ font-family: var(--font-ui);
6435
7007
  font-size: var(--text-sm);
6436
7008
  line-height: 1.5;
6437
7009
  outline: none;
@@ -6444,8 +7016,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6444
7016
  }
6445
7017
 
6446
7018
  [data-ui="combobox"] [data-part="input"]:focus {
6447
- border-color: var(--color-ring, oklch(0.55 0.22 264));
6448
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
7019
+ border-color: var(--focus-ring-color);
7020
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
6449
7021
  }
6450
7022
 
6451
7023
  /* ── Listbox ── */
@@ -6457,7 +7029,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6457
7029
  z-index: var(--z-dropdown);
6458
7030
  margin-top: var(--space-1);
6459
7031
  padding: var(--space-1);
6460
- border: 1px solid var(--color-border);
7032
+ border: var(--border-width) solid var(--color-border);
6461
7033
  border-radius: var(--radius-lg);
6462
7034
  background: var(--color-bg);
6463
7035
  box-shadow: var(--shadow-md);
@@ -6542,7 +7114,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6542
7114
 
6543
7115
  /* === recipes/command-palette.css === */
6544
7116
  /* @ui:component command-palette */
6545
- /* @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 */
7117
+ /* @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 */
6546
7118
 
6547
7119
  /* ── Root ── */
6548
7120
  [data-ui="command-palette"] {
@@ -6575,7 +7147,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6575
7147
  display: flex;
6576
7148
  flex-direction: column;
6577
7149
  background: var(--color-bg);
6578
- border: 1px solid var(--color-border);
7150
+ border: var(--border-width) solid var(--color-border);
6579
7151
  border-radius: var(--radius-xl);
6580
7152
  box-shadow: var(--shadow-xl);
6581
7153
  overflow: hidden;
@@ -6607,7 +7179,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6607
7179
  display: flex;
6608
7180
  align-items: center;
6609
7181
  padding: var(--space-3) var(--space-4);
6610
- border-bottom: 1px solid var(--color-border);
7182
+ border-bottom: var(--border-width) solid var(--color-border);
6611
7183
  }
6612
7184
 
6613
7185
  /* ── Search Input ── */
@@ -6617,7 +7189,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6617
7189
  border: none;
6618
7190
  background: transparent;
6619
7191
  color: var(--color-fg);
6620
- font-family: var(--font-sans, system-ui, sans-serif);
7192
+ font-family: var(--font-ui);
6621
7193
  font-size: var(--text-base);
6622
7194
  outline: none;
6623
7195
  }
@@ -6701,7 +7273,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6701
7273
  align-items: center;
6702
7274
  gap: var(--space-1, 0.25rem);
6703
7275
  padding: var(--space-1, 0.25rem) var(--space-2);
6704
- border: 1px solid var(--color-border);
7276
+ border: var(--border-width) solid var(--color-border);
6705
7277
  border-radius: var(--radius-sm, 0.25rem);
6706
7278
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
6707
7279
  color: var(--color-fg-muted);
@@ -6730,7 +7302,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6730
7302
 
6731
7303
  /* === recipes/context-menu.css === */
6732
7304
  /* @ui:component context-menu */
6733
- /* @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 */
7305
+ /* @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 */
6734
7306
 
6735
7307
  [data-ui="context-menu"] {
6736
7308
  position: relative;
@@ -6743,12 +7315,12 @@ div[data-ui="separator"][data-style="thick"]::after {
6743
7315
  border-radius: var(--radius-lg);
6744
7316
  background: var(--color-bg-muted);
6745
7317
  color: var(--color-fg);
6746
- font-family: var(--font-sans, system-ui, sans-serif);
7318
+ font-family: var(--font-ui);
6747
7319
  }
6748
7320
 
6749
7321
  [data-ui="context-menu"] [data-part="target"]:focus-visible {
6750
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6751
- outline-offset: var(--space-1);
7322
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7323
+ outline-offset: var(--focus-ring-offset);
6752
7324
  }
6753
7325
 
6754
7326
  [data-ui="context-menu"] [data-part="menu"] {
@@ -6780,7 +7352,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6780
7352
  border-radius: var(--radius-md);
6781
7353
  background: transparent;
6782
7354
  color: var(--color-fg);
6783
- font-family: var(--font-sans, system-ui, sans-serif);
7355
+ font-family: var(--font-ui);
6784
7356
  font-size: var(--text-sm);
6785
7357
  font-weight: var(--weight-medium);
6786
7358
  text-align: start;
@@ -6804,15 +7376,15 @@ div[data-ui="separator"][data-style="thick"]::after {
6804
7376
  focus additionally draws the ring, inset so it does not overlap the item
6805
7377
  above. [W3-3] */
6806
7378
  [data-ui="context-menu"] [data-part="item"]:focus-visible {
6807
- outline: calc(var(--space-px) * 2) solid var(--color-ring);
6808
- outline-offset: calc(var(--space-px) * -2);
7379
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7380
+ outline-offset: calc(-1 * var(--focus-ring-offset));
6809
7381
  }
6810
7382
 
6811
7383
  [data-ui="context-menu"] [data-part="item"]:disabled,
6812
7384
  [data-ui="context-menu"] [data-part="item"][aria-disabled="true"] {
6813
7385
  color: var(--color-fg-muted);
6814
7386
  cursor: not-allowed;
6815
- opacity: 0.5;
7387
+ opacity: var(--disabled-opacity);
6816
7388
  }
6817
7389
 
6818
7390
  [data-ui="context-menu"] [data-part="separator"] {
@@ -6831,7 +7403,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6831
7403
 
6832
7404
  /* === recipes/date-picker.css === */
6833
7405
  /* @ui:component date-picker */
6834
- /* @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 */
7406
+ /* @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 */
6835
7407
  /* The month grid inside the popup is the `calendar` recipe — see calendar.css */
6836
7408
 
6837
7409
  /* ── Root ── */
@@ -6852,11 +7424,11 @@ div[data-ui="separator"][data-style="thick"]::after {
6852
7424
  width: 100%;
6853
7425
  padding: var(--space-2, 0.5rem) var(--space-3);
6854
7426
  padding-inline-end: var(--space-8, 2.5rem);
6855
- border: 1px solid var(--color-border);
7427
+ border: var(--border-width) solid var(--color-border);
6856
7428
  border-radius: var(--radius-md);
6857
7429
  background: var(--color-bg);
6858
7430
  color: var(--color-fg);
6859
- font-family: var(--font-sans, system-ui, sans-serif);
7431
+ font-family: var(--font-ui);
6860
7432
  font-size: var(--text-sm);
6861
7433
  line-height: 1.5;
6862
7434
  cursor: pointer;
@@ -6868,8 +7440,8 @@ div[data-ui="separator"][data-style="thick"]::after {
6868
7440
  }
6869
7441
 
6870
7442
  [data-ui="date-picker"] [data-part="input"]:focus-visible {
6871
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
6872
- outline-offset: 2px;
7443
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7444
+ outline-offset: var(--focus-ring-offset);
6873
7445
  border-color: var(--color-primary);
6874
7446
  }
6875
7447
 
@@ -6892,7 +7464,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6892
7464
  z-index: var(--z-dropdown);
6893
7465
  margin-top: var(--space-1);
6894
7466
  padding: var(--space-3);
6895
- border: 1px solid var(--color-border);
7467
+ border: var(--border-width) solid var(--color-border);
6896
7468
  border-radius: var(--radius-lg);
6897
7469
  background: var(--color-bg);
6898
7470
  box-shadow: var(--shadow-lg);
@@ -6931,7 +7503,7 @@ div[data-ui="separator"][data-style="thick"]::after {
6931
7503
 
6932
7504
  /* === recipes/dialog.css === */
6933
7505
  /* @ui:component dialog */
6934
- /* @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 */
7506
+ /* @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 */
6935
7507
 
6936
7508
  /* ── Root ── */
6937
7509
  [data-ui="dialog"] {
@@ -6966,15 +7538,23 @@ div[data-ui="separator"][data-style="thick"]::after {
6966
7538
  width: 90%;
6967
7539
  max-height: 85vh;
6968
7540
  overflow-y: auto;
6969
- background: var(--color-bg);
6970
- border: 1px solid var(--color-border);
7541
+ background: var(--panel-bg);
7542
+ border: var(--border-width) solid var(--color-border);
6971
7543
  border-radius: var(--dialog-radius, var(--radius-xl));
7544
+ corner-shape: var(--corner-shape);
6972
7545
  box-shadow: var(--dialog-shadow, var(--shadow-xl));
6973
7546
  opacity: 0;
6974
7547
  transition: opacity var(--duration-normal) var(--ease-out),
6975
7548
  transform var(--duration-normal) var(--ease-out);
6976
7549
  }
6977
7550
 
7551
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7552
+ [data-ui="dialog"] [data-part="panel"] {
7553
+ -webkit-backdrop-filter: var(--surface-backdrop);
7554
+ backdrop-filter: var(--surface-backdrop);
7555
+ }
7556
+ }
7557
+
6978
7558
  [data-ui="dialog"][data-state="open"] [data-part="panel"] {
6979
7559
  opacity: 1;
6980
7560
  transform: translate(-50%, -50%) scale(1);
@@ -7023,6 +7603,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7023
7603
  /* ── Title ── */
7024
7604
  [data-ui="dialog"] [data-part="title"] {
7025
7605
  margin: 0;
7606
+ font-family: var(--font-heading);
7026
7607
  font-size: var(--text-lg, 1.125rem);
7027
7608
  font-weight: var(--weight-semibold, 600);
7028
7609
  color: var(--color-fg);
@@ -7057,8 +7638,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7057
7638
  }
7058
7639
 
7059
7640
  [data-ui="dialog"] [data-part="close"]:not([data-ui]):focus-visible {
7060
- outline: 2px solid var(--color-ring);
7061
- outline-offset: 2px;
7641
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7642
+ outline-offset: var(--focus-ring-offset);
7062
7643
  }
7063
7644
 
7064
7645
  /* ── Description ── */
@@ -7094,7 +7675,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7094
7675
 
7095
7676
  /* === recipes/drawer.css === */
7096
7677
  /* @ui:component drawer */
7097
- /* @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 */
7678
+ /* @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 */
7098
7679
 
7099
7680
  /* ── Root ── */
7100
7681
  [data-ui="drawer"] {
@@ -7129,17 +7710,24 @@ div[data-ui="separator"][data-style="thick"]::after {
7129
7710
  flex-direction: column;
7130
7711
  width: var(--drawer-width, 400px);
7131
7712
  max-width: 100vw;
7132
- background: var(--color-bg);
7713
+ background: var(--panel-bg);
7133
7714
  border: none;
7134
7715
  box-shadow: var(--drawer-shadow, var(--shadow-xl));
7135
7716
  transition: transform var(--duration-slow) var(--ease-out);
7136
7717
  }
7137
7718
 
7719
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7720
+ [data-ui="drawer"] [data-part="panel"] {
7721
+ -webkit-backdrop-filter: var(--surface-backdrop);
7722
+ backdrop-filter: var(--surface-backdrop);
7723
+ }
7724
+ }
7725
+
7138
7726
  /* ── Side Variants ── */
7139
7727
  [data-ui="drawer"] [data-part="panel"][data-variant="left"] {
7140
7728
  inset-inline-start: 0;
7141
7729
  inset-inline-end: auto;
7142
- border-inline-end: 1px solid var(--color-border);
7730
+ border-inline-end: var(--border-width) solid var(--color-border);
7143
7731
  border-radius: 0 var(--radius-none, 0) var(--radius-none, 0) 0;
7144
7732
  transform: translateX(-100%);
7145
7733
  }
@@ -7147,7 +7735,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7147
7735
  [data-ui="drawer"] [data-part="panel"][data-variant="right"] {
7148
7736
  inset-inline-end: 0;
7149
7737
  inset-inline-start: auto;
7150
- border-inline-start: 1px solid var(--color-border);
7738
+ border-inline-start: var(--border-width) solid var(--color-border);
7151
7739
  border-radius: var(--radius-none, 0) 0 0 var(--radius-none, 0);
7152
7740
  transform: translateX(100%);
7153
7741
  }
@@ -7201,6 +7789,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7201
7789
  /* ── Title ── */
7202
7790
  [data-ui="drawer"] [data-part="title"] {
7203
7791
  margin: 0;
7792
+ font-family: var(--font-heading);
7204
7793
  font-size: var(--text-lg, 1.125rem);
7205
7794
  font-weight: var(--weight-semibold, 600);
7206
7795
  color: var(--color-fg);
@@ -7235,8 +7824,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7235
7824
  }
7236
7825
 
7237
7826
  [data-ui="drawer"] [data-part="close"]:not([data-ui]):focus-visible {
7238
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7239
- outline-offset: 2px;
7827
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7828
+ outline-offset: var(--focus-ring-offset);
7240
7829
  }
7241
7830
 
7242
7831
  /* ── Body ── */
@@ -7255,7 +7844,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7255
7844
  gap: var(--space-3, 0.75rem);
7256
7845
  padding: var(--space-6);
7257
7846
  padding-top: var(--space-4);
7258
- border-top: 1px solid var(--color-border);
7847
+ border-top: var(--border-width) solid var(--color-border);
7259
7848
  flex-shrink: 0;
7260
7849
  }
7261
7850
 
@@ -7269,7 +7858,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7269
7858
 
7270
7859
  /* === recipes/dropdown.css === */
7271
7860
  /* @ui:component dropdown */
7272
- /* @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 */
7861
+ /* @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 */
7273
7862
 
7274
7863
  /* ── Root ── */
7275
7864
  [data-ui="dropdown"] {
@@ -7283,11 +7872,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7283
7872
  align-items: center;
7284
7873
  gap: var(--space-2);
7285
7874
  padding: var(--space-2) var(--space-3);
7286
- border: 1px solid var(--color-border);
7875
+ border: var(--border-width) solid var(--color-border);
7287
7876
  border-radius: var(--radius-md);
7288
7877
  background: var(--color-bg);
7289
7878
  color: var(--color-fg);
7290
- font-family: var(--font-sans, system-ui, sans-serif);
7879
+ font-family: var(--font-ui);
7291
7880
  font-size: var(--text-sm);
7292
7881
  font-weight: var(--weight-medium);
7293
7882
  cursor: pointer;
@@ -7301,8 +7890,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7301
7890
  }
7302
7891
 
7303
7892
  [data-ui="dropdown"] [data-part="trigger"]:focus-visible {
7304
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7305
- outline-offset: 2px;
7893
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7894
+ outline-offset: var(--focus-ring-offset);
7306
7895
  }
7307
7896
 
7308
7897
  /* ── Menu ── */
@@ -7314,9 +7903,9 @@ div[data-ui="separator"][data-style="thick"]::after {
7314
7903
  min-width: 180px;
7315
7904
  margin-top: var(--space-1);
7316
7905
  padding: var(--space-1);
7317
- border: 1px solid var(--color-border);
7906
+ border: var(--border-width) solid var(--color-border);
7318
7907
  border-radius: var(--radius-lg);
7319
- background: var(--color-bg);
7908
+ background: var(--panel-bg);
7320
7909
  box-shadow: var(--shadow-md);
7321
7910
  opacity: 0;
7322
7911
  transform: translateY(-4px);
@@ -7324,6 +7913,13 @@ div[data-ui="separator"][data-style="thick"]::after {
7324
7913
  transform var(--duration-fast) var(--ease-out);
7325
7914
  }
7326
7915
 
7916
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
7917
+ [data-ui="dropdown"] [data-part="menu"] {
7918
+ -webkit-backdrop-filter: var(--surface-backdrop);
7919
+ backdrop-filter: var(--surface-backdrop);
7920
+ }
7921
+ }
7922
+
7327
7923
  [data-ui="dropdown"][data-state="open"] [data-part="menu"] {
7328
7924
  opacity: 1;
7329
7925
  transform: translateY(0);
@@ -7346,7 +7942,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7346
7942
  border-radius: var(--radius-md);
7347
7943
  background: transparent;
7348
7944
  color: var(--color-fg);
7349
- font-family: var(--font-sans, system-ui, sans-serif);
7945
+ font-family: var(--font-ui);
7350
7946
  font-size: var(--text-sm);
7351
7947
  text-align: start;
7352
7948
  cursor: pointer;
@@ -7368,12 +7964,12 @@ div[data-ui="separator"][data-style="thick"]::after {
7368
7964
  focus additionally draws the ring, inset so it does not overlap the item
7369
7965
  above. [W3-3] */
7370
7966
  [data-ui="dropdown"] [data-part="item"]:focus-visible {
7371
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7372
- outline-offset: -2px;
7967
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
7968
+ outline-offset: calc(-1 * var(--focus-ring-offset));
7373
7969
  }
7374
7970
 
7375
7971
  [data-ui="dropdown"] [data-part="item"]:disabled {
7376
- opacity: 0.5;
7972
+ opacity: var(--disabled-opacity);
7377
7973
  cursor: not-allowed;
7378
7974
  pointer-events: none;
7379
7975
  }
@@ -7426,14 +8022,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7426
8022
 
7427
8023
  /* === recipes/file-upload.css === */
7428
8024
  /* @ui:component file-upload */
7429
- /* @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 */
8025
+ /* @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 */
7430
8026
 
7431
8027
  [data-ui="file-upload"] {
7432
8028
  display: grid;
7433
8029
  gap: var(--space-4);
7434
8030
  inline-size: 100%;
7435
8031
  color: var(--color-fg);
7436
- font-family: var(--font-sans);
8032
+ font-family: var(--font-ui);
7437
8033
  }
7438
8034
 
7439
8035
  [data-ui="file-upload"] [data-part="dropzone"] {
@@ -7468,14 +8064,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7468
8064
  }
7469
8065
 
7470
8066
  [data-ui="file-upload"]:has([data-part="input"]:focus-visible) [data-part="dropzone"] {
7471
- outline: var(--space-px) solid var(--color-ring);
7472
- outline-offset: var(--space-1);
8067
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8068
+ outline-offset: var(--focus-ring-offset);
7473
8069
  }
7474
8070
 
7475
8071
  [data-ui="file-upload"][data-state="dragging"] [data-part="dropzone"] {
7476
8072
  border-color: var(--color-primary);
7477
8073
  background: var(--color-primary-subtle);
7478
- box-shadow: 0 0 0 var(--space-px) var(--color-primary);
8074
+ box-shadow: 0 0 0 var(--border-width) var(--color-primary);
7479
8075
  }
7480
8076
 
7481
8077
  [data-ui="file-upload"] [data-part="prompt"] {
@@ -7549,8 +8145,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7549
8145
  }
7550
8146
 
7551
8147
  [data-ui="file-upload"] [data-part="remove"]:focus-visible {
7552
- outline: var(--space-px) solid var(--color-ring);
7553
- outline-offset: var(--space-1);
8148
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8149
+ outline-offset: var(--focus-ring-offset);
7554
8150
  }
7555
8151
 
7556
8152
  [data-ui="file-upload"] [data-part="empty"] {
@@ -7572,7 +8168,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7572
8168
  }
7573
8169
 
7574
8170
  [data-ui="file-upload"][data-disabled] {
7575
- opacity: 0.5;
8171
+ opacity: var(--disabled-opacity);
7576
8172
  }
7577
8173
 
7578
8174
  [data-ui="file-upload"][data-disabled] [data-part="dropzone"],
@@ -7588,7 +8184,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7588
8184
 
7589
8185
  /* === recipes/input-otp.css === */
7590
8186
  /* @ui:component input-otp */
7591
- /* @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 */
8187
+ /* @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 */
7592
8188
 
7593
8189
  /* ── Root ── */
7594
8190
  [data-ui="input-otp"] {
@@ -7603,7 +8199,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7603
8199
  gutter. The transparent input is `inset: 0`, so it follows the box the
7604
8200
  segments settle into however many rows that takes. */
7605
8201
  max-inline-size: 100%;
7606
- font-family: var(--font-sans, system-ui, sans-serif);
8202
+ font-family: var(--font-ui);
7607
8203
  }
7608
8204
 
7609
8205
  /* ── Real input ──
@@ -7648,14 +8244,14 @@ div[data-ui="separator"][data-style="thick"]::after {
7648
8244
  justify-content: center;
7649
8245
  inline-size: var(--input-otp-segment-size);
7650
8246
  block-size: var(--input-otp-segment-size);
7651
- border: 1px solid var(--color-border);
8247
+ border: var(--border-width) solid var(--color-border);
7652
8248
  border-radius: var(--radius-md);
7653
8249
  background: var(--color-bg);
7654
8250
  color: var(--color-fg);
7655
8251
  font-size: var(--text-lg, 1.125rem);
7656
8252
  font-variant-numeric: tabular-nums;
7657
8253
  line-height: 1;
7658
- transition: border-color var(--duration-fast, 120ms) var(--ease-default, ease),
8254
+ transition: border-color var(--duration-fast) var(--ease-default),
7659
8255
  box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
7660
8256
  }
7661
8257
 
@@ -7667,7 +8263,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7667
8263
  /* Active (caret / selected) segment while focused */
7668
8264
  [data-ui="input-otp"] [data-part="segment"][data-active] {
7669
8265
  border-color: var(--color-ring);
7670
- box-shadow: 0 0 0 1px var(--color-ring);
8266
+ box-shadow: 0 0 0 var(--border-width) var(--color-ring);
7671
8267
  }
7672
8268
 
7673
8269
  /* Blinking caret in the next-to-fill empty slot */
@@ -7715,7 +8311,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7715
8311
 
7716
8312
  /* ── Disabled ── */
7717
8313
  [data-ui="input-otp"][data-disabled] {
7718
- opacity: 0.5;
8314
+ opacity: var(--disabled-opacity);
7719
8315
  cursor: not-allowed;
7720
8316
  }
7721
8317
  [data-ui="input-otp"][data-disabled] [data-part="input"] {
@@ -7739,7 +8335,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7739
8335
 
7740
8336
  /* === recipes/menubar.css === */
7741
8337
  /* @ui:component menubar */
7742
- /* @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 */
8338
+ /* @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 */
7743
8339
 
7744
8340
  [data-ui="menubar"] {
7745
8341
  position: relative;
@@ -7757,7 +8353,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7757
8353
  border-radius: var(--radius-lg);
7758
8354
  background: var(--color-bg);
7759
8355
  color: var(--color-fg);
7760
- font-family: var(--font-sans);
8356
+ font-family: var(--font-ui);
7761
8357
  }
7762
8358
 
7763
8359
  [data-ui="menubar"] [data-part="group"] {
@@ -7799,7 +8395,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7799
8395
 
7800
8396
  [data-ui="menubar"] [data-part="trigger"]:focus-visible,
7801
8397
  [data-ui="menubar"] [data-part="item"]:focus-visible {
7802
- box-shadow: 0 0 0 calc(var(--space-px) * 2) var(--color-ring);
8398
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
7803
8399
  }
7804
8400
 
7805
8401
  [data-ui="menubar"] [data-part="submenu"] {
@@ -7834,7 +8430,10 @@ div[data-ui="separator"][data-style="thick"]::after {
7834
8430
  [data-ui="menubar"] [role="menuitem"][aria-disabled="true"] {
7835
8431
  color: var(--color-fg-muted);
7836
8432
  cursor: not-allowed;
7837
- opacity: 0.6;
8433
+ /* 0.6 at the 0.5 default — lighter than a control, since the muted colour
8434
+ already carries half the signal — and a theme's `--disabled-opacity` moves
8435
+ it (1.1A-27). */
8436
+ opacity: calc(var(--disabled-opacity) * 1.2);
7838
8437
  }
7839
8438
 
7840
8439
  [data-ui="menubar"] [data-part="separator"] {
@@ -7866,7 +8465,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7866
8465
 
7867
8466
  /* === recipes/pagination.css === */
7868
8467
  /* @ui:component pagination */
7869
- /* @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 */
8468
+ /* @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 */
7870
8469
 
7871
8470
  /* ── Root ── */
7872
8471
  [data-ui="pagination"] {
@@ -7902,11 +8501,11 @@ div[data-ui="separator"][data-style="thick"]::after {
7902
8501
  min-width: 36px;
7903
8502
  height: 36px;
7904
8503
  padding: 0 var(--space-2);
7905
- border: 1px solid var(--color-border);
8504
+ border: var(--border-width) solid var(--color-border);
7906
8505
  border-radius: var(--radius-md);
7907
8506
  background: var(--color-bg);
7908
8507
  color: var(--color-fg);
7909
- font-family: var(--font-sans, system-ui, sans-serif);
8508
+ font-family: var(--font-ui);
7910
8509
  font-size: var(--text-sm);
7911
8510
  font-weight: var(--weight-medium);
7912
8511
  cursor: pointer;
@@ -7927,8 +8526,8 @@ div[data-ui="separator"][data-style="thick"]::after {
7927
8526
  [data-ui="pagination"] [data-part="page"]:focus-visible,
7928
8527
  [data-ui="pagination"] [data-part="prev"]:focus-visible,
7929
8528
  [data-ui="pagination"] [data-part="next"]:focus-visible {
7930
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
7931
- outline-offset: 2px;
8529
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8530
+ outline-offset: var(--focus-ring-offset);
7932
8531
  }
7933
8532
 
7934
8533
  /* ── Active page ── */
@@ -7952,7 +8551,7 @@ div[data-ui="separator"][data-style="thick"]::after {
7952
8551
  /* ── Disabled ── */
7953
8552
  [data-ui="pagination"] [data-part="prev"]:disabled,
7954
8553
  [data-ui="pagination"] [data-part="next"]:disabled {
7955
- opacity: 0.5;
8554
+ opacity: var(--disabled-opacity);
7956
8555
  cursor: not-allowed;
7957
8556
  pointer-events: none;
7958
8557
  }
@@ -8022,7 +8621,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8022
8621
 
8023
8622
  /* === recipes/popover.css === */
8024
8623
  /* @ui:component popover */
8025
- /* @ui:tokens color-bg color-fg color-border shadow-md radius-lg space-3 space-4 z-dropdown duration-fast ease-default */
8624
+ /* @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 */
8026
8625
 
8027
8626
  /* ── Root ── */
8028
8627
  [data-ui="popover"] {
@@ -8036,11 +8635,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8036
8635
  align-items: center;
8037
8636
  gap: var(--space-2, 0.5rem);
8038
8637
  padding: var(--space-2, 0.5rem) var(--space-3);
8039
- border: 1px solid var(--color-border);
8638
+ border: var(--border-width) solid var(--color-border);
8040
8639
  border-radius: var(--radius-md, 0.375rem);
8041
8640
  background: var(--color-bg);
8042
8641
  color: var(--color-fg);
8043
- font-family: var(--font-sans, system-ui, sans-serif);
8642
+ font-family: var(--font-ui);
8044
8643
  font-size: var(--text-sm, 0.875rem);
8045
8644
  font-weight: var(--weight-medium, 500);
8046
8645
  cursor: pointer;
@@ -8054,8 +8653,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8054
8653
  }
8055
8654
 
8056
8655
  [data-ui="popover"] [data-part="trigger"]:focus-visible {
8057
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8058
- outline-offset: 2px;
8656
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8657
+ outline-offset: var(--focus-ring-offset);
8059
8658
  }
8060
8659
 
8061
8660
  /* ── Content ── */
@@ -8064,9 +8663,9 @@ div[data-ui="separator"][data-style="thick"]::after {
8064
8663
  z-index: var(--z-dropdown);
8065
8664
  min-width: 200px;
8066
8665
  padding: var(--space-4);
8067
- border: 1px solid var(--color-border);
8666
+ border: var(--border-width) solid var(--color-border);
8068
8667
  border-radius: var(--radius-lg);
8069
- background: var(--color-bg);
8668
+ background: var(--panel-bg);
8070
8669
  color: var(--color-fg);
8071
8670
  box-shadow: var(--shadow-md);
8072
8671
  opacity: 0;
@@ -8075,6 +8674,13 @@ div[data-ui="separator"][data-style="thick"]::after {
8075
8674
  transform var(--duration-fast) var(--ease-default);
8076
8675
  }
8077
8676
 
8677
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
8678
+ [data-ui="popover"] [data-part="content"] {
8679
+ -webkit-backdrop-filter: var(--surface-backdrop);
8680
+ backdrop-filter: var(--surface-backdrop);
8681
+ }
8682
+ }
8683
+
8078
8684
  [data-ui="popover"][data-state="open"] [data-part="content"] {
8079
8685
  opacity: 1;
8080
8686
  transform: scale(1);
@@ -8162,8 +8768,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8162
8768
  position: absolute;
8163
8769
  width: 8px;
8164
8770
  height: 8px;
8165
- background: var(--color-bg);
8166
- border: 1px solid var(--color-border);
8771
+ background: var(--panel-bg);
8772
+ border: var(--border-width) solid var(--color-border);
8167
8773
  transform: rotate(45deg);
8168
8774
  }
8169
8775
 
@@ -8264,8 +8870,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8264
8870
  }
8265
8871
 
8266
8872
  [data-ui="popover"] [data-part="close"]:focus-visible {
8267
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8268
- outline-offset: 2px;
8873
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8874
+ outline-offset: var(--focus-ring-offset);
8269
8875
  }
8270
8876
 
8271
8877
  /* ── Motion ── */
@@ -8278,7 +8884,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8278
8884
 
8279
8885
  /* === recipes/qr-code.css === */
8280
8886
  /* @ui:component qr-code */
8281
- /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-sans space-2 */
8887
+ /* @ui:tokens color-fg color-bg doc-legal-color doc-legal-size doc-font font-body space-2 */
8282
8888
 
8283
8889
  /* ── Base ── */
8284
8890
  [data-ui="qr-code"] {
@@ -8296,7 +8902,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8296
8902
 
8297
8903
  /* ── Caption ── */
8298
8904
  [data-ui="qr-code"] [data-part="caption"] {
8299
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
8905
+ font-family: var(--doc-font, var(--font-body));
8300
8906
  font-size: var(--doc-legal-size, var(--text-xs));
8301
8907
  color: var(--doc-legal-color, var(--color-fg-muted));
8302
8908
  text-align: center;
@@ -8337,7 +8943,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8337
8943
 
8338
8944
  /* === recipes/select-custom.css === */
8339
8945
  /* @ui:component select-custom */
8340
- /* @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 */
8946
+ /* @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 */
8341
8947
 
8342
8948
  /* ── Root ── */
8343
8949
  [data-ui="select-custom"] {
@@ -8354,11 +8960,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8354
8960
  width: 100%;
8355
8961
  min-width: 180px;
8356
8962
  padding: var(--space-2) var(--space-3);
8357
- border: 1px solid var(--color-border);
8963
+ border: var(--border-width) solid var(--color-border);
8358
8964
  border-radius: var(--radius-md);
8359
8965
  background: var(--color-bg);
8360
8966
  color: var(--color-fg);
8361
- font-family: var(--font-sans, system-ui, sans-serif);
8967
+ font-family: var(--font-ui);
8362
8968
  font-size: var(--text-sm);
8363
8969
  cursor: pointer;
8364
8970
  white-space: nowrap;
@@ -8371,8 +8977,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8371
8977
  }
8372
8978
 
8373
8979
  [data-ui="select-custom"] [data-part="trigger"]:focus-visible {
8374
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8375
- outline-offset: 2px;
8980
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
8981
+ outline-offset: var(--focus-ring-offset);
8376
8982
  }
8377
8983
 
8378
8984
  /* ── Value ── */
@@ -8408,7 +9014,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8408
9014
  z-index: var(--z-dropdown);
8409
9015
  margin-top: var(--space-1);
8410
9016
  padding: var(--space-1);
8411
- border: 1px solid var(--color-border);
9017
+ border: var(--border-width) solid var(--color-border);
8412
9018
  border-radius: var(--radius-lg);
8413
9019
  background: var(--color-bg);
8414
9020
  box-shadow: var(--shadow-md);
@@ -8432,11 +9038,11 @@ div[data-ui="separator"][data-style="thick"]::after {
8432
9038
  padding: var(--space-2) var(--space-3);
8433
9039
  margin-bottom: var(--space-1);
8434
9040
  border: none;
8435
- border-bottom: 1px solid var(--color-border);
9041
+ border-bottom: var(--border-width) solid var(--color-border);
8436
9042
  border-radius: 0;
8437
9043
  background: transparent;
8438
9044
  color: var(--color-fg);
8439
- font-family: var(--font-sans, system-ui, sans-serif);
9045
+ font-family: var(--font-ui);
8440
9046
  font-size: var(--text-sm);
8441
9047
  outline: none;
8442
9048
  }
@@ -8530,7 +9136,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8530
9136
 
8531
9137
  /* === recipes/sheet.css === */
8532
9138
  /* @ui:component sheet */
8533
- /* @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 */
9139
+ /* @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 */
8534
9140
 
8535
9141
  /* ── Root ── */
8536
9142
  [data-ui="sheet"] {
@@ -8561,11 +9167,18 @@ div[data-ui="separator"][data-style="thick"]::after {
8561
9167
  z-index: var(--z-modal);
8562
9168
  display: flex;
8563
9169
  flex-direction: column;
8564
- background: var(--color-bg);
9170
+ background: var(--panel-bg);
8565
9171
  box-shadow: var(--shadow-xl);
8566
9172
  transition: transform var(--duration-slow) var(--ease-out);
8567
9173
  }
8568
9174
 
9175
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
9176
+ [data-ui="sheet"] [data-part="panel"] {
9177
+ -webkit-backdrop-filter: var(--surface-backdrop);
9178
+ backdrop-filter: var(--surface-backdrop);
9179
+ }
9180
+ }
9181
+
8569
9182
  /* ── Side: Bottom ── */
8570
9183
  [data-ui="sheet"] [data-part="panel"][data-variant="bottom"] {
8571
9184
  bottom: 0;
@@ -8593,7 +9206,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8593
9206
  bottom: 0;
8594
9207
  max-width: 100vw;
8595
9208
  border-radius: 0 var(--radius-xl) var(--radius-xl) 0;
8596
- border-inline-end: 1px solid var(--color-border);
9209
+ border-inline-end: var(--border-width) solid var(--color-border);
8597
9210
  transform: translateX(-100%);
8598
9211
  }
8599
9212
 
@@ -8604,7 +9217,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8604
9217
  bottom: 0;
8605
9218
  max-width: 100vw;
8606
9219
  border-radius: var(--radius-xl) 0 0 var(--radius-xl);
8607
- border-inline-start: 1px solid var(--color-border);
9220
+ border-inline-start: var(--border-width) solid var(--color-border);
8608
9221
  transform: translateX(100%);
8609
9222
  }
8610
9223
 
@@ -8681,6 +9294,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8681
9294
  /* ── Title ── */
8682
9295
  [data-ui="sheet"] [data-part="title"] {
8683
9296
  margin: 0;
9297
+ font-family: var(--font-heading);
8684
9298
  font-size: var(--text-lg, 1.125rem);
8685
9299
  font-weight: var(--weight-semibold, 600);
8686
9300
  color: var(--color-fg);
@@ -8715,8 +9329,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8715
9329
  }
8716
9330
 
8717
9331
  [data-ui="sheet"] [data-part="close"]:not([data-ui]):focus-visible {
8718
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8719
- outline-offset: 2px;
9332
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9333
+ outline-offset: var(--focus-ring-offset);
8720
9334
  }
8721
9335
 
8722
9336
  /* ── Body ── */
@@ -8737,7 +9351,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8737
9351
 
8738
9352
  /* === recipes/sidebar.css === */
8739
9353
  /* @ui:component sidebar */
8740
- /* @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 */
9354
+ /* @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 */
8741
9355
 
8742
9356
  /* ── Root ──
8743
9357
  The root owns the layout column from `md` up; the panel is the visual surface.
@@ -8781,7 +9395,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8781
9395
  flex-direction: column;
8782
9396
  gap: var(--space-2);
8783
9397
  background: var(--sidebar-bg);
8784
- border-inline-end: 1px solid var(--color-border);
9398
+ border-inline-end: var(--border-width) solid var(--color-border);
8785
9399
  border-start-end-radius: var(--radius-lg, 0.5rem);
8786
9400
  border-end-end-radius: var(--radius-lg, 0.5rem);
8787
9401
  box-shadow: var(--shadow-xl);
@@ -8862,8 +9476,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8862
9476
  }
8863
9477
 
8864
9478
  [data-ui="sidebar"] [data-part="trigger"]:focus-visible {
8865
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8866
- outline-offset: 2px;
9479
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9480
+ outline-offset: var(--focus-ring-offset);
8867
9481
  }
8868
9482
 
8869
9483
  /* ── Navigation ── */
@@ -8899,8 +9513,8 @@ div[data-ui="separator"][data-style="thick"]::after {
8899
9513
  }
8900
9514
 
8901
9515
  [data-ui="sidebar"] [data-part="item"]:focus-visible {
8902
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
8903
- outline-offset: -2px;
9516
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9517
+ outline-offset: calc(-1 * var(--focus-ring-offset));
8904
9518
  }
8905
9519
 
8906
9520
  [data-ui="sidebar"] [data-part="item"][aria-current="page"] {
@@ -8927,7 +9541,7 @@ div[data-ui="separator"][data-style="thick"]::after {
8927
9541
  [data-ui="sidebar"] [data-part="footer"] {
8928
9542
  flex-shrink: 0;
8929
9543
  padding: var(--space-3) var(--space-4);
8930
- border-block-start: 1px solid var(--color-border);
9544
+ border-block-start: var(--border-width) solid var(--color-border);
8931
9545
  }
8932
9546
 
8933
9547
  /* ── Rail (icons only) ── */
@@ -9020,7 +9634,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9020
9634
 
9021
9635
  /* === recipes/slider.css === */
9022
9636
  /* @ui:component slider */
9023
- /* @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 */
9637
+ /* @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 */
9024
9638
 
9025
9639
  /* ── Root ── */
9026
9640
  [data-ui="slider"] {
@@ -9070,28 +9684,28 @@ div[data-ui="separator"][data-style="thick"]::after {
9070
9684
  value in both LTR and RTL (translateX is physical, so -50% always recentres). */
9071
9685
  transform: translate(-50%, -50%);
9072
9686
  background: var(--color-bg, white);
9073
- border: 2px solid var(--color-primary);
9687
+ border: var(--border-width-strong) solid var(--color-primary);
9074
9688
  border-radius: var(--radius-full, 9999px);
9075
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1));
9689
+ box-shadow: var(--shadow-sm);
9076
9690
  cursor: grab;
9077
9691
  touch-action: none;
9078
- transition: box-shadow var(--duration-fast, 120ms) var(--ease-default, ease);
9692
+ transition: box-shadow var(--duration-fast) var(--ease-default);
9079
9693
  }
9080
9694
 
9081
9695
  [data-ui="slider"] [data-part="thumb"]:hover {
9082
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9083
- 0 0 0 4px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9696
+ box-shadow: var(--shadow-sm),
9697
+ 0 0 0 4px var(--color-primary-subtle);
9084
9698
  }
9085
9699
 
9086
9700
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
9087
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9088
- outline-offset: 2px;
9701
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9702
+ outline-offset: var(--focus-ring-offset);
9089
9703
  }
9090
9704
 
9091
9705
  [data-ui="slider"] [data-part="thumb"][data-state="dragging"] {
9092
9706
  cursor: grabbing;
9093
- box-shadow: var(--shadow-sm, 0 1px 3px oklch(0 0 0 / 0.1)),
9094
- 0 0 0 5px var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
9707
+ box-shadow: var(--shadow-sm),
9708
+ 0 0 0 5px var(--color-primary-subtle);
9095
9709
  }
9096
9710
 
9097
9711
  /* ── Value output ── */
@@ -9099,7 +9713,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9099
9713
  flex: 0 0 auto;
9100
9714
  min-inline-size: 3ch;
9101
9715
  color: var(--color-fg-muted);
9102
- font-family: var(--font-sans, system-ui, sans-serif);
9716
+ font-family: var(--font-ui);
9103
9717
  font-size: var(--text-sm);
9104
9718
  font-variant-numeric: tabular-nums;
9105
9719
  text-align: end;
@@ -9118,7 +9732,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9118
9732
 
9119
9733
  /* ── Disabled ── */
9120
9734
  [data-ui="slider"][data-disabled] {
9121
- opacity: 0.5;
9735
+ opacity: var(--disabled-opacity);
9122
9736
  cursor: not-allowed;
9123
9737
  pointer-events: none;
9124
9738
  }
@@ -9136,7 +9750,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9136
9750
  the substitution so the control still reads as "this much, up to here". [W3-3] */
9137
9751
  @media (forced-colors: active) {
9138
9752
  [data-ui="slider"] [data-part="track"] {
9139
- border: 1px solid ButtonText;
9753
+ border: var(--border-width) solid ButtonText;
9140
9754
  }
9141
9755
 
9142
9756
  [data-ui="slider"] [data-part="range"] {
@@ -9147,7 +9761,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9147
9761
  [data-ui="slider"] [data-part="thumb"] {
9148
9762
  forced-color-adjust: none;
9149
9763
  background: ButtonText;
9150
- border: 1px solid ButtonFace;
9764
+ border: var(--border-width) solid ButtonFace;
9151
9765
  }
9152
9766
 
9153
9767
  [data-ui="slider"] [data-part="thumb"]:focus-visible {
@@ -9157,7 +9771,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9157
9771
 
9158
9772
  /* === recipes/table.css === */
9159
9773
  /* @ui:component table */
9160
- /* @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 */
9774
+ /* @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 */
9161
9775
 
9162
9776
  /* ── Root ── */
9163
9777
  [data-ui="table"] {
@@ -9183,7 +9797,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9183
9797
  width: 100%;
9184
9798
  border-collapse: separate;
9185
9799
  border-spacing: 0;
9186
- font-family: var(--font-sans, system-ui, sans-serif);
9800
+ font-family: var(--font-body);
9187
9801
  }
9188
9802
 
9189
9803
  /* Once any column is resized the layout freezes so widths are exact. */
@@ -9205,7 +9819,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9205
9819
  font-weight: var(--weight-semibold);
9206
9820
  color: var(--color-fg-muted);
9207
9821
  background: var(--color-bg);
9208
- border-bottom: 2px solid var(--color-border);
9822
+ border-bottom: var(--border-width-strong) solid var(--color-border);
9209
9823
  white-space: nowrap;
9210
9824
  user-select: none;
9211
9825
  }
@@ -9263,8 +9877,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9263
9877
  /* Keyboard focus on cells (sortable headers + navigable grids). */
9264
9878
  [data-ui="table"] [data-part="th"]:focus-visible,
9265
9879
  [data-ui="table"] [data-part="td"]:focus-visible {
9266
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9267
- outline-offset: -2px;
9880
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
9881
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9268
9882
  }
9269
9883
 
9270
9884
  /* ── Data Cell ── */
@@ -9272,7 +9886,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9272
9886
  padding: var(--space-3) var(--space-4);
9273
9887
  font-size: var(--text-sm);
9274
9888
  color: var(--color-fg);
9275
- border-bottom: 1px solid var(--color-border);
9889
+ border-bottom: var(--border-width) solid var(--color-border);
9276
9890
  background: var(--color-bg);
9277
9891
  transition: background var(--duration-fast) var(--ease-default);
9278
9892
  }
@@ -9301,31 +9915,31 @@ div[data-ui="separator"][data-style="thick"]::after {
9301
9915
  Static fallback via nth-child; once the controller stamps data-stripe on the
9302
9916
  visible rows (so hidden rows never break the pattern), the stamped rules win. */
9303
9917
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"]:not([data-stripe]):nth-child(even):not([data-selected]) [data-part="td"] {
9304
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
9918
+ background: var(--stripe-bg);
9305
9919
  }
9306
9920
 
9307
9921
  [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"] {
9308
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
9922
+ background: var(--stripe-bg);
9309
9923
  }
9310
9924
 
9311
9925
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]) [data-part="td"] {
9312
- background: var(--color-bg-subtle, oklch(0.97 0.004 260));
9926
+ background: var(--stripe-bg);
9313
9927
  }
9314
9928
 
9315
9929
  [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"][data-stripe="even"]:not([data-selected]):hover [data-part="td"] {
9316
- background: var(--color-bg-subtle, oklch(0.95 0.006 260));
9930
+ background: var(--stripe-bg);
9317
9931
  }
9318
9932
 
9319
9933
  /* ── Bordered Variant ── */
9320
9934
  [data-ui="table"][data-variant="bordered"] [data-part="table"] {
9321
- border: 1px solid var(--color-border);
9935
+ border: var(--border-width) solid var(--color-border);
9322
9936
  border-radius: var(--radius-md, 0.375rem);
9323
9937
  overflow: hidden;
9324
9938
  }
9325
9939
 
9326
9940
  [data-ui="table"][data-variant="bordered"] [data-part="th"],
9327
9941
  [data-ui="table"][data-variant="bordered"] [data-part="td"] {
9328
- border: 1px solid var(--color-border);
9942
+ border: var(--border-width) solid var(--color-border);
9329
9943
  }
9330
9944
 
9331
9945
  /* ── Size: Small ── */
@@ -9353,7 +9967,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9353
9967
  /* ── Footer ── */
9354
9968
  [data-ui="table"] [data-part="tfoot"] [data-part="td"] {
9355
9969
  font-weight: var(--doc-table-footer-weight, var(--weight-semibold));
9356
- border-top: 2px solid var(--color-border);
9970
+ border-top: var(--border-width-strong) solid var(--color-border);
9357
9971
  border-bottom: none;
9358
9972
  background: var(--doc-table-footer-bg, var(--color-bg-subtle, oklch(0.97 0.004 260)));
9359
9973
  }
@@ -9479,7 +10093,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9479
10093
  [data-ui="table"] [data-part="filter-row"] [data-part="th"] {
9480
10094
  padding: var(--space-1) var(--space-2);
9481
10095
  background: var(--color-bg);
9482
- border-bottom: 1px solid var(--color-border);
10096
+ border-bottom: var(--border-width) solid var(--color-border);
9483
10097
  }
9484
10098
 
9485
10099
  [data-ui="table"] [data-part="filter-input"],
@@ -9491,14 +10105,14 @@ div[data-ui="separator"][data-style="thick"]::after {
9491
10105
  font-size: var(--text-xs);
9492
10106
  color: var(--color-fg);
9493
10107
  background: var(--color-bg);
9494
- border: 1px solid var(--color-border);
10108
+ border: var(--border-width) solid var(--color-border);
9495
10109
  border-radius: var(--radius-sm);
9496
10110
  }
9497
10111
 
9498
10112
  [data-ui="table"] [data-part="filter-input"]:focus,
9499
10113
  [data-ui="table"] [data-part="filter"]:focus {
9500
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9501
- outline-offset: -1px;
10114
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10115
+ outline-offset: calc(-1 * var(--border-width));
9502
10116
  border-color: var(--color-primary);
9503
10117
  }
9504
10118
 
@@ -9519,7 +10133,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9519
10133
  text-align: inherit;
9520
10134
  color: var(--color-fg);
9521
10135
  background: var(--color-bg);
9522
- border: 1px solid var(--color-primary);
10136
+ border: var(--border-width) solid var(--color-primary);
9523
10137
  border-radius: var(--radius-sm);
9524
10138
  outline: none;
9525
10139
  }
@@ -9572,11 +10186,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9572
10186
  }
9573
10187
 
9574
10188
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="before"] [data-part="td"] {
9575
- border-block-start: 2px solid var(--color-primary);
10189
+ border-block-start: var(--border-width-strong) solid var(--color-primary);
9576
10190
  }
9577
10191
 
9578
10192
  [data-ui="table"] [data-part="tr"][data-drop-target][data-drop-pos="after"] [data-part="td"] {
9579
- border-block-end: 2px solid var(--color-primary);
10193
+ border-block-end: var(--border-width-strong) solid var(--color-primary);
9580
10194
  }
9581
10195
 
9582
10196
  [data-ui="table"] [data-part="th"][data-dragging] {
@@ -9584,11 +10198,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9584
10198
  }
9585
10199
 
9586
10200
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="before"] {
9587
- border-inline-start: 2px solid var(--color-primary);
10201
+ border-inline-start: var(--border-width-strong) solid var(--color-primary);
9588
10202
  }
9589
10203
 
9590
10204
  [data-ui="table"] [data-part="th"][data-drop-target][data-drop-pos="after"] {
9591
- border-inline-end: 2px solid var(--color-primary);
10205
+ border-inline-end: var(--border-width-strong) solid var(--color-primary);
9592
10206
  }
9593
10207
 
9594
10208
  /* ── Column Resize Handles (injected by the controller) ── */
@@ -9661,11 +10275,11 @@ div[data-ui="separator"][data-style="thick"]::after {
9661
10275
  }
9662
10276
 
9663
10277
  [data-ui="table"] [data-pin="start"][data-pin-edge] {
9664
- border-inline-end: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10278
+ border-inline-end: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9665
10279
  }
9666
10280
 
9667
10281
  [data-ui="table"] [data-pin="end"][data-pin-edge] {
9668
- border-inline-start: 1px solid var(--color-border-strong, oklch(0.85 0.006 260));
10282
+ border-inline-start: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
9669
10283
  }
9670
10284
 
9671
10285
  /* ── Column Visibility ── */
@@ -9737,7 +10351,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9737
10351
  [data-ui="table"][data-stacked] [data-part="tfoot"] [data-part="tr"] {
9738
10352
  display: block;
9739
10353
  margin-block-end: var(--space-3);
9740
- border: 1px solid var(--color-border);
10354
+ border: var(--border-width) solid var(--color-border);
9741
10355
  border-radius: var(--radius-md);
9742
10356
  background: var(--color-bg);
9743
10357
  overflow: hidden;
@@ -9751,7 +10365,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9751
10365
  gap: var(--space-4);
9752
10366
  text-align: end;
9753
10367
  border-bottom: none;
9754
- border-block-end: 1px solid var(--color-border);
10368
+ border-block-end: var(--border-width) solid var(--color-border);
9755
10369
  }
9756
10370
 
9757
10371
  [data-ui="table"][data-stacked] [data-part="tr"] [data-part="td"]:last-child,
@@ -9848,7 +10462,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9848
10462
 
9849
10463
  /* === recipes/tabs.css === */
9850
10464
  /* @ui:component tabs */
9851
- /* @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 */
10465
+ /* @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 */
9852
10466
 
9853
10467
  /* ── Root ── */
9854
10468
  [data-ui="tabs"] {
@@ -9877,7 +10491,7 @@ div[data-ui="separator"][data-style="thick"]::after {
9877
10491
  border: none;
9878
10492
  background: transparent;
9879
10493
  color: var(--color-fg-muted);
9880
- font-family: var(--font-sans, system-ui, sans-serif);
10494
+ font-family: var(--font-ui);
9881
10495
  font-size: var(--text-sm);
9882
10496
  font-weight: var(--weight-medium);
9883
10497
  cursor: pointer;
@@ -9892,8 +10506,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9892
10506
  }
9893
10507
 
9894
10508
  [data-ui="tabs"] [data-part="trigger"]:focus-visible {
9895
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
9896
- outline-offset: -2px;
10509
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10510
+ outline-offset: calc(-1 * var(--focus-ring-offset));
9897
10511
  border-radius: var(--radius-md);
9898
10512
  }
9899
10513
 
@@ -9903,12 +10517,12 @@ div[data-ui="separator"][data-style="thick"]::after {
9903
10517
 
9904
10518
  /* ── Underline Variant ── */
9905
10519
  [data-ui="tabs"][data-variant="underline"] [data-part="list"] {
9906
- border-bottom: 1px solid var(--color-border);
10520
+ border-bottom: var(--border-width) solid var(--color-border);
9907
10521
  gap: 0;
9908
10522
  }
9909
10523
 
9910
10524
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"] {
9911
- border-bottom: 2px solid transparent;
10525
+ border-bottom: var(--border-width-strong) solid transparent;
9912
10526
  margin-bottom: -1px;
9913
10527
  border-radius: 0;
9914
10528
  }
@@ -9940,17 +10554,17 @@ div[data-ui="separator"][data-style="thick"]::after {
9940
10554
  [data-ui="tabs"][data-variant="pill"] [data-part="trigger"][aria-selected="true"] {
9941
10555
  background: var(--color-bg);
9942
10556
  color: var(--color-fg);
9943
- box-shadow: var(--shadow-xs, 0 1px 2px oklch(0 0 0 / 0.04));
10557
+ box-shadow: var(--shadow-xs);
9944
10558
  }
9945
10559
 
9946
10560
  /* ── Enclosed Variant ── */
9947
10561
  [data-ui="tabs"][data-variant="enclosed"] [data-part="list"] {
9948
- border-bottom: 1px solid var(--color-border);
10562
+ border-bottom: var(--border-width) solid var(--color-border);
9949
10563
  gap: 0;
9950
10564
  }
9951
10565
 
9952
10566
  [data-ui="tabs"][data-variant="enclosed"] [data-part="trigger"] {
9953
- border: 1px solid transparent;
10567
+ border: var(--border-width) solid transparent;
9954
10568
  border-bottom: none;
9955
10569
  border-radius: var(--radius-md) var(--radius-md) 0 0;
9956
10570
  margin-bottom: -1px;
@@ -9995,8 +10609,8 @@ div[data-ui="separator"][data-style="thick"]::after {
9995
10609
  @media (forced-colors: active) {
9996
10610
  [data-ui="tabs"] [data-part="trigger"][aria-selected="true"] {
9997
10611
  /* An outline the OS preserves, on every variant. */
9998
- outline: 2px solid Highlight;
9999
- outline-offset: -2px;
10612
+ outline: var(--border-width-strong) solid Highlight;
10613
+ outline-offset: calc(-1 * var(--border-width-strong));
10000
10614
  }
10001
10615
 
10002
10616
  [data-ui="tabs"][data-variant="underline"] [data-part="trigger"][aria-selected="true"] {
@@ -10011,7 +10625,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10011
10625
 
10012
10626
  /* === recipes/tag-input.css === */
10013
10627
  /* @ui:component tag-input */
10014
- /* @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 */
10628
+ /* @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 */
10015
10629
 
10016
10630
  /* NOTE: the tags themselves are `data-ui="chip"` elements — their styling comes
10017
10631
  entirely from chip.css. This file styles only the field wrapper, the tag row,
@@ -10032,7 +10646,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10032
10646
  gap: var(--space-1h);
10033
10647
  width: 100%;
10034
10648
  padding: var(--space-1h) var(--space-2);
10035
- border: 1px solid var(--color-border);
10649
+ border: var(--border-width) solid var(--color-border);
10036
10650
  border-radius: var(--radius-md);
10037
10651
  background: var(--color-bg);
10038
10652
  list-style: none;
@@ -10041,8 +10655,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10041
10655
  }
10042
10656
 
10043
10657
  [data-ui="tag-input"] [data-part="taglist"]:focus-within {
10044
- border-color: var(--color-ring, oklch(0.55 0.22 264));
10045
- box-shadow: 0 0 0 2px var(--color-ring, oklch(0.55 0.22 264));
10658
+ border-color: var(--focus-ring-color);
10659
+ box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
10046
10660
  }
10047
10661
 
10048
10662
  /* ── Text input: borderless, grows to fill the remaining row space ── */
@@ -10053,7 +10667,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10053
10667
  border: none;
10054
10668
  background: transparent;
10055
10669
  color: var(--color-fg);
10056
- font-family: var(--font-sans, system-ui, sans-serif);
10670
+ font-family: var(--font-ui);
10057
10671
  font-size: var(--text-sm);
10058
10672
  line-height: 1.5;
10059
10673
  outline: none;
@@ -10072,7 +10686,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10072
10686
  z-index: var(--z-dropdown);
10073
10687
  margin-top: var(--space-1);
10074
10688
  padding: var(--space-1);
10075
- border: 1px solid var(--color-border);
10689
+ border: var(--border-width) solid var(--color-border);
10076
10690
  border-radius: var(--radius-lg);
10077
10691
  background: var(--color-bg);
10078
10692
  box-shadow: var(--shadow-md);
@@ -10119,7 +10733,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10119
10733
 
10120
10734
  /* === recipes/toast.css === */
10121
10735
  /* @ui:component toast */
10122
- /* @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 */
10736
+ /* @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 */
10123
10737
 
10124
10738
  /* ── Container ── */
10125
10739
  [data-ui="toast"][data-part="container"] {
@@ -10168,8 +10782,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10168
10782
  max-width: 380px;
10169
10783
  width: max-content;
10170
10784
  padding: var(--space-3) var(--space-4);
10171
- background: var(--color-bg);
10172
- border: 1px solid var(--color-border);
10785
+ background: var(--panel-bg);
10786
+ border: var(--border-width) solid var(--color-border);
10173
10787
  border-radius: var(--radius-lg);
10174
10788
  box-shadow: var(--shadow-lg);
10175
10789
  pointer-events: auto;
@@ -10179,6 +10793,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10179
10793
  transform var(--duration-normal) var(--ease-out);
10180
10794
  }
10181
10795
 
10796
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
10797
+ [data-ui="toast"] [data-part="toast"] {
10798
+ -webkit-backdrop-filter: var(--surface-backdrop);
10799
+ backdrop-filter: var(--surface-backdrop);
10800
+ }
10801
+ }
10802
+
10182
10803
  /* ── State: Entering ── */
10183
10804
  [data-ui="toast"][data-variant="top-right"] [data-part="toast"][data-state="entering"],
10184
10805
  [data-ui="toast"][data-variant="top-left"] [data-part="toast"][data-state="entering"] {
@@ -10218,7 +10839,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10218
10839
 
10219
10840
  /* ── Tone Variants ── */
10220
10841
  [data-ui="toast"] [data-part="toast"][data-variant="success"] {
10221
- border-inline-start: 3px solid var(--color-success, oklch(0.55 0.18 145));
10842
+ border-inline-start: var(--border-width-lg) solid var(--color-success, oklch(0.55 0.18 145));
10222
10843
  }
10223
10844
 
10224
10845
  [data-ui="toast"] [data-part="toast"][data-variant="success"] [data-part="icon"] {
@@ -10226,7 +10847,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10226
10847
  }
10227
10848
 
10228
10849
  [data-ui="toast"] [data-part="toast"][data-variant="error"] {
10229
- border-inline-start: 3px solid var(--color-destructive, oklch(0.55 0.22 25));
10850
+ border-inline-start: var(--border-width-lg) solid var(--color-destructive, oklch(0.55 0.22 25));
10230
10851
  }
10231
10852
 
10232
10853
  [data-ui="toast"] [data-part="toast"][data-variant="error"] [data-part="icon"] {
@@ -10234,7 +10855,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10234
10855
  }
10235
10856
 
10236
10857
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] {
10237
- border-inline-start: 3px solid var(--color-warning, oklch(0.7 0.18 85));
10858
+ border-inline-start: var(--border-width-lg) solid var(--color-warning, oklch(0.7 0.18 85));
10238
10859
  }
10239
10860
 
10240
10861
  [data-ui="toast"] [data-part="toast"][data-variant="warning"] [data-part="icon"] {
@@ -10256,7 +10877,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10256
10877
  /* ── Message ── */
10257
10878
  [data-ui="toast"] [data-part="message"] {
10258
10879
  flex: 1;
10259
- font-family: var(--font-sans, system-ui, sans-serif);
10880
+ font-family: var(--font-ui);
10260
10881
  font-size: var(--text-sm);
10261
10882
  font-weight: var(--weight-medium);
10262
10883
  color: var(--color-fg);
@@ -10267,11 +10888,11 @@ div[data-ui="separator"][data-style="thick"]::after {
10267
10888
  [data-ui="toast"] [data-part="action"] {
10268
10889
  flex-shrink: 0;
10269
10890
  padding: var(--space-1, 0.25rem) var(--space-2);
10270
- border: 1px solid var(--color-border);
10891
+ border: var(--border-width) solid var(--color-border);
10271
10892
  border-radius: var(--radius-md, 0.375rem);
10272
10893
  background: transparent;
10273
10894
  color: var(--color-fg);
10274
- font-family: var(--font-sans, system-ui, sans-serif);
10895
+ font-family: var(--font-ui);
10275
10896
  font-size: var(--text-xs, 0.75rem);
10276
10897
  font-weight: var(--weight-medium);
10277
10898
  cursor: pointer;
@@ -10284,8 +10905,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10284
10905
  }
10285
10906
 
10286
10907
  [data-ui="toast"] [data-part="action"]:focus-visible {
10287
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10288
- outline-offset: 2px;
10908
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10909
+ outline-offset: var(--focus-ring-offset);
10289
10910
  }
10290
10911
 
10291
10912
  /* ── Close Button ── */
@@ -10311,8 +10932,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10311
10932
  }
10312
10933
 
10313
10934
  [data-ui="toast"] [data-part="close"]:focus-visible {
10314
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
10315
- outline-offset: 2px;
10935
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
10936
+ outline-offset: var(--focus-ring-offset);
10316
10937
  }
10317
10938
 
10318
10939
  /* ── Motion ── */
@@ -10325,14 +10946,14 @@ div[data-ui="separator"][data-style="thick"]::after {
10325
10946
 
10326
10947
  /* === recipes/toggle-group.css === */
10327
10948
  /* @ui:component toggle-group */
10328
- /* @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 */
10949
+ /* @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 */
10329
10950
 
10330
10951
  /* ── Root: a segmented row of toggle buttons ── */
10331
10952
  [data-ui="toggle-group"] {
10332
10953
  display: inline-flex;
10333
10954
  gap: var(--space-1);
10334
10955
  padding: var(--space-1);
10335
- border: 1px solid var(--color-border);
10956
+ border: var(--border-width) solid var(--color-border);
10336
10957
  border-radius: var(--radius-md);
10337
10958
  background: var(--color-bg);
10338
10959
  }
@@ -10347,7 +10968,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10347
10968
  border-radius: var(--radius-md);
10348
10969
  background: transparent;
10349
10970
  color: var(--color-fg-muted);
10350
- font-family: var(--toggle-group-font, var(--font-sans));
10971
+ font-family: var(--toggle-group-font, var(--font-ui));
10351
10972
  font-size: var(--text-sm);
10352
10973
  font-weight: var(--weight-medium);
10353
10974
  line-height: 1;
@@ -10388,13 +11009,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10388
11009
 
10389
11010
  /* ── Keyboard focus ring on the item (focus lives on the hidden control) ── */
10390
11011
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:focus-visible) {
10391
- outline: 2px solid var(--color-ring);
10392
- outline-offset: 2px;
11012
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11013
+ outline-offset: var(--focus-ring-offset);
10393
11014
  }
10394
11015
 
10395
11016
  /* ── Disabled control ── */
10396
11017
  [data-ui="toggle-group"] [data-part="item"]:has([data-part="control"]:disabled) {
10397
- opacity: 0.5;
11018
+ opacity: var(--disabled-opacity);
10398
11019
  cursor: not-allowed;
10399
11020
  }
10400
11021
 
@@ -10407,7 +11028,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10407
11028
 
10408
11029
  /* === recipes/tooltip.css === */
10409
11030
  /* @ui:component tooltip */
10410
- /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default */
11031
+ /* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default font-ui surface-backdrop */
10411
11032
 
10412
11033
  /* ── Root ── */
10413
11034
  [data-ui="tooltip"] {
@@ -10428,7 +11049,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10428
11049
  color: var(--color-bg);
10429
11050
  border-radius: var(--radius-md);
10430
11051
  padding: var(--space-1h, 0.375rem) var(--space-2);
10431
- font-family: var(--font-sans, system-ui, sans-serif);
11052
+ font-family: var(--font-ui);
10432
11053
  font-size: var(--text-xs, 0.75rem);
10433
11054
  line-height: 1.4;
10434
11055
  white-space: nowrap;
@@ -10439,6 +11060,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10439
11060
  transform var(--duration-fast) var(--ease-default);
10440
11061
  }
10441
11062
 
11063
+ @supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
11064
+ [data-ui="tooltip"] [data-part="content"] {
11065
+ -webkit-backdrop-filter: var(--surface-backdrop);
11066
+ backdrop-filter: var(--surface-backdrop);
11067
+ }
11068
+ }
11069
+
10442
11070
  /* Default position (top) when no variant is specified */
10443
11071
  [data-ui="tooltip"]:not([data-variant]) [data-part="content"] {
10444
11072
  bottom: 100%;
@@ -10554,7 +11182,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10554
11182
 
10555
11183
  /* === recipes/tree-view.css === */
10556
11184
  /* @ui:component tree-view */
10557
- /* @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 */
11185
+ /* @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 */
10558
11186
 
10559
11187
  [data-ui="tree-view"],
10560
11188
  [data-ui="tree-view"] [data-part="group"] {
@@ -10567,7 +11195,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10567
11195
  inline-size: 100%;
10568
11196
  padding: var(--space-1);
10569
11197
  color: var(--color-fg);
10570
- font-family: var(--font-sans);
11198
+ font-family: var(--font-ui);
10571
11199
  font-size: var(--text-sm);
10572
11200
  }
10573
11201
 
@@ -10595,8 +11223,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10595
11223
  }
10596
11224
 
10597
11225
  [data-ui="tree-view"] [data-part="item"]:focus-visible > [data-part="label"] {
10598
- outline: var(--space-px) solid var(--color-ring);
10599
- outline-offset: var(--space-px);
11226
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11227
+ outline-offset: var(--focus-ring-offset);
10600
11228
  }
10601
11229
 
10602
11230
  [data-ui="tree-view"] [data-part="item"][aria-selected="true"] > [data-part="label"] {
@@ -10635,7 +11263,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10635
11263
 
10636
11264
  /* === patterns/auth-form.css === */
10637
11265
  /* @ui:component auth-form */
10638
- /* @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 */
11266
+ /* @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 */
10639
11267
 
10640
11268
  /* ── Root Container ── */
10641
11269
  [data-ui="auth-form"] {
@@ -10643,7 +11271,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10643
11271
  align-items: center;
10644
11272
  justify-content: center;
10645
11273
  width: 100%;
10646
- font-family: var(--font-sans);
11274
+ font-family: var(--font-body);
10647
11275
  }
10648
11276
 
10649
11277
  /* Mobile-first (task 0.8-09): on a phone the card IS the page — edge to edge,
@@ -10675,9 +11303,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10675
11303
 
10676
11304
  [data-ui="auth-form"] [data-part="title"] {
10677
11305
  margin: 0;
11306
+ font-family: var(--font-heading);
10678
11307
  font-size: var(--text-xl);
10679
- font-weight: var(--weight-bold);
10680
- line-height: var(--leading-tight);
11308
+ font-weight: var(--heading-weight);
11309
+ letter-spacing: var(--heading-tracking);
11310
+ text-transform: var(--heading-transform);
11311
+ font-variant-caps: var(--heading-caps);
11312
+ line-height: var(--heading-leading);
10681
11313
  color: var(--color-fg);
10682
11314
  }
10683
11315
 
@@ -10694,7 +11326,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10694
11326
  margin: var(--space-4) var(--space-6) 0;
10695
11327
  padding: var(--space-3);
10696
11328
  background: var(--color-destructive-subtle);
10697
- border: 1px solid var(--color-destructive);
11329
+ border: var(--border-width) solid var(--color-destructive);
10698
11330
  border-radius: var(--radius-lg);
10699
11331
  color: var(--color-destructive);
10700
11332
  font-size: var(--text-sm);
@@ -10772,13 +11404,13 @@ div[data-ui="separator"][data-style="thick"]::after {
10772
11404
  }
10773
11405
 
10774
11406
  [data-ui="auth-form"] [data-part="footer"] a:hover {
10775
- text-decoration: underline;
11407
+ text-decoration-line: var(--link-decoration);
10776
11408
  color: var(--color-primary-hover);
10777
11409
  }
10778
11410
 
10779
11411
  [data-ui="auth-form"] [data-part="footer"] a:focus-visible {
10780
- outline: 2px solid var(--color-ring);
10781
- outline-offset: 2px;
11412
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11413
+ outline-offset: var(--focus-ring-offset);
10782
11414
  border-radius: var(--radius-sm, 0.25rem);
10783
11415
  }
10784
11416
 
@@ -10906,8 +11538,8 @@ div[data-ui="separator"][data-style="thick"]::after {
10906
11538
  max-width: var(--auth-form-max-width, 400px);
10907
11539
  border-radius: var(--card-radius, var(--radius-lg));
10908
11540
  box-shadow: var(--card-shadow, var(--shadow-sm));
10909
- border-inline-start: 1px solid var(--card-border, var(--color-border));
10910
- border-inline-end: 1px solid var(--card-border, var(--color-border));
11541
+ border-inline-start: var(--border-width) solid var(--card-border, var(--color-border));
11542
+ border-inline-end: var(--border-width) solid var(--card-border, var(--color-border));
10911
11543
  }
10912
11544
  }
10913
11545
 
@@ -10922,7 +11554,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10922
11554
 
10923
11555
  /* === patterns/crud-table.css === */
10924
11556
  /* @ui:component crud-table */
10925
- /* @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 */
11557
+ /* @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 */
10926
11558
 
10927
11559
  /* ── Root ── */
10928
11560
  [data-ui="crud-table"] {
@@ -10930,7 +11562,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10930
11562
  flex-direction: column;
10931
11563
  gap: var(--space-4);
10932
11564
  width: 100%;
10933
- font-family: var(--font-sans, system-ui, sans-serif);
11565
+ font-family: var(--font-body);
10934
11566
  }
10935
11567
 
10936
11568
  /* ── Toolbar ── */
@@ -10988,7 +11620,7 @@ div[data-ui="separator"][data-style="thick"]::after {
10988
11620
  gap: var(--space-3);
10989
11621
  padding: var(--space-3) var(--space-4);
10990
11622
  background: var(--color-bg-subtle);
10991
- border: 1px solid var(--color-border);
11623
+ border: var(--border-width) solid var(--color-border);
10992
11624
  border-radius: var(--radius-md);
10993
11625
  }
10994
11626
 
@@ -11003,7 +11635,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11003
11635
  [data-ui="crud-table"] [data-part="table-wrapper"] {
11004
11636
  width: 100%;
11005
11637
  overflow-x: auto;
11006
- border: 1px solid var(--color-border);
11638
+ border: var(--border-width) solid var(--color-border);
11007
11639
  border-radius: var(--radius-lg);
11008
11640
  background: var(--color-bg);
11009
11641
  }
@@ -11033,7 +11665,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11033
11665
  padding: var(--space-8) var(--space-4);
11034
11666
  text-align: center;
11035
11667
  min-height: 240px;
11036
- border: 1px dashed var(--color-border);
11668
+ border: var(--border-width) dashed var(--color-border);
11037
11669
  border-radius: var(--radius-lg);
11038
11670
  background: var(--color-bg);
11039
11671
  }
@@ -11146,7 +11778,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11146
11778
 
11147
11779
  /* === patterns/dashboard-shell.css === */
11148
11780
  /* @ui:component dashboard-shell */
11149
- /* @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 */
11781
+ /* @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 */
11150
11782
 
11151
11783
  /* ── Shell Grid Layout ──
11152
11784
  Mobile-first (task 0.8-09): the base is the PHONE shell — one column, header
@@ -11171,7 +11803,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11171
11803
  "footer";
11172
11804
  min-height: 100vh;
11173
11805
  background: var(--color-bg);
11174
- font-family: var(--font-sans);
11806
+ font-family: var(--font-body);
11175
11807
  color: var(--color-fg);
11176
11808
  }
11177
11809
 
@@ -11195,7 +11827,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11195
11827
  gap: var(--space-2);
11196
11828
  padding: var(--space-4);
11197
11829
  background: var(--color-bg-subtle);
11198
- border-inline-end: 1px solid var(--color-border);
11830
+ border-inline-end: var(--border-width) solid var(--color-border);
11199
11831
  overflow-y: auto;
11200
11832
  position: fixed;
11201
11833
  top: 0;
@@ -11215,7 +11847,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11215
11847
 
11216
11848
  [data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"] {
11217
11849
  border-inline-end: none;
11218
- border-inline-start: 1px solid var(--color-border);
11850
+ border-inline-start: var(--border-width) solid var(--color-border);
11219
11851
  inset-inline-start: auto;
11220
11852
  inset-inline-end: 0;
11221
11853
  transform: translateX(100%);
@@ -11290,7 +11922,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11290
11922
  gap: var(--space-3);
11291
11923
  padding: var(--space-2) var(--space-3);
11292
11924
  border-radius: var(--radius-md);
11293
- font-family: var(--font-sans);
11925
+ font-family: var(--font-ui);
11294
11926
  font-size: var(--text-sm);
11295
11927
  font-weight: var(--weight-medium);
11296
11928
  line-height: var(--leading-normal);
@@ -11309,8 +11941,8 @@ div[data-ui="separator"][data-style="thick"]::after {
11309
11941
  }
11310
11942
 
11311
11943
  [data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"]:focus-visible {
11312
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
11313
- outline-offset: -2px;
11944
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
11945
+ outline-offset: calc(-1 * var(--focus-ring-offset));
11314
11946
  }
11315
11947
 
11316
11948
  /* ── Nav Item Active ── */
@@ -11357,7 +11989,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11357
11989
  gap: var(--space-2);
11358
11990
  padding: 0 var(--space-3);
11359
11991
  background: var(--color-bg);
11360
- border-bottom: 1px solid var(--color-border);
11992
+ border-bottom: var(--border-width) solid var(--color-border);
11361
11993
  position: sticky;
11362
11994
  top: 0;
11363
11995
  z-index: var(--z-sticky);
@@ -11438,7 +12070,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11438
12070
  align-items: center;
11439
12071
  gap: var(--space-3);
11440
12072
  padding: var(--space-4) var(--space-6);
11441
- border-top: 1px solid var(--color-border);
12073
+ border-top: var(--border-width) solid var(--color-border);
11442
12074
  font-size: var(--text-xs);
11443
12075
  color: var(--color-fg-muted);
11444
12076
  }
@@ -11521,7 +12153,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11521
12153
 
11522
12154
  /* === patterns/document.css === */
11523
12155
  /* @ui:component document */
11524
- /* @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 */
12156
+ /* @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 */
11525
12157
 
11526
12158
  /* ── Page Rules ── */
11527
12159
  @page {
@@ -11561,14 +12193,17 @@ div[data-ui="separator"][data-style="thick"]::after {
11561
12193
  max-width: var(--doc-max-width);
11562
12194
  margin: var(--space-4) auto;
11563
12195
  padding: var(--space-6) var(--space-4);
11564
- background: var(--color-bg, #fff);
12196
+ background-color: var(--color-bg, #fff);
12197
+ background-image: var(--texture-page);
11565
12198
  color: var(--color-fg);
11566
- font-family: var(--doc-font, var(--font-sans, system-ui, sans-serif));
12199
+ font-family: var(--doc-font, var(--font-body));
11567
12200
  font-size: var(--doc-font-size);
11568
12201
  line-height: var(--doc-line-height);
11569
- box-shadow: var(--shadow-lg,
11570
- 0 10px 15px -3px rgba(0, 0, 0, 0.1),
11571
- 0 4px 6px -4px rgba(0, 0, 0, 0.1));
12202
+ /* The fallback here used to spell out two rgba() layers, which is a shadow
12203
+ colour no theme could reach. --shadow-lg is always defined by the token
12204
+ layer, and it now carries --shadow-color, so the fallback is gone rather
12205
+ than re-tokenised. */
12206
+ box-shadow: var(--shadow-lg);
11572
12207
  border-radius: 0;
11573
12208
  position: relative;
11574
12209
  }
@@ -11584,7 +12219,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11584
12219
  [data-ui="document"] > [data-part="header"] {
11585
12220
  margin-block-end: var(--doc-section-gap);
11586
12221
  padding-block-end: var(--doc-component-gap);
11587
- border-block-end: 1px solid var(--color-border);
12222
+ border-block-end: var(--border-width) solid var(--color-border);
11588
12223
  }
11589
12224
 
11590
12225
  /* ── Body ── */
@@ -11594,13 +12229,25 @@ div[data-ui="separator"][data-style="thick"]::after {
11594
12229
  gap: var(--doc-section-gap);
11595
12230
  }
11596
12231
 
12232
+ /* ── Headings ──
12233
+ The document's own heading face and weight (1.1A-21): a print theme sets
12234
+ --doc-heading-font / --doc-heading-weight to give its titles a voice apart
12235
+ from the body copy (document-serif's Times titles over Georgia text). Both
12236
+ default to the page's heading role in tokens/document.css, and each falls
12237
+ back to what a heading rendered before the tokens had a reader. A heading
12238
+ that carries its own data-weight keeps it — that is the author asking. */
12239
+ [data-ui="document"] :is(h1, h2, h3, h4, h5, h6) {
12240
+ font-family: var(--doc-heading-font, var(--font-body));
12241
+ font-weight: var(--doc-heading-weight, var(--weight-bold));
12242
+ }
12243
+
11597
12244
  /* ── Running footer ──
11598
12245
  footer remains a non-breaking selector alias for pre-1.1.0 documents. */
11599
12246
  [data-ui="document"] > [data-part="doc-footer"],
11600
12247
  [data-ui="document"] > [data-part="footer"] {
11601
12248
  margin-block-start: var(--doc-section-gap);
11602
12249
  padding-block-start: var(--doc-component-gap);
11603
- border-block-start: 1px solid var(--color-border);
12250
+ border-block-start: var(--border-width) solid var(--color-border);
11604
12251
  font-size: var(--doc-legal-size);
11605
12252
  color: var(--doc-legal-color);
11606
12253
  }
@@ -11638,7 +12285,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11638
12285
 
11639
12286
  /* ── Variant: Report ── */
11640
12287
  [data-ui="document"][data-variant="report"] {
11641
- font-family: var(--font-serif, Georgia, "Times New Roman", serif);
12288
+ /* A report is serif-set by definition. It re-points the document's own font
12289
+ ROLE rather than its `font-family`, so every doc primitive nested inside it
12290
+ (key-value, callout, signature — all of which read --doc-font) follows the
12291
+ report into serif instead of staying sans inside a serif page. `report` is
12292
+ the author asking for serif; a theme that wants its own document face
12293
+ declares --doc-font at :root, which this variant deliberately outranks. */
12294
+ --doc-font: Georgia, 'Times New Roman', serif;
11642
12295
  line-height: 1.6;
11643
12296
  }
11644
12297
 
@@ -11733,7 +12386,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11733
12386
  z-index: var(--z-raised);
11734
12387
  margin-block-end: 0;
11735
12388
  padding-block-end: var(--doc-running-gap);
11736
- border-block-end: 1px solid var(--doc-print-border-color);
12389
+ border-block-end: var(--border-width) solid var(--doc-print-border-color);
11737
12390
  background: var(--doc-bg);
11738
12391
  transform: translateZ(0);
11739
12392
  }
@@ -11749,7 +12402,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11749
12402
  z-index: var(--z-raised);
11750
12403
  margin-block-start: 0;
11751
12404
  padding-block-start: var(--doc-running-gap);
11752
- border-block-start: 1px solid var(--doc-print-border-color);
12405
+ border-block-start: var(--border-width) solid var(--doc-print-border-color);
11753
12406
  background: var(--doc-bg);
11754
12407
  transform: translateZ(0);
11755
12408
  }
@@ -11778,7 +12431,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11778
12431
 
11779
12432
  /* === patterns/empty-state.css === */
11780
12433
  /* @ui:component empty-state */
11781
- /* @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 */
12434
+ /* @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 */
11782
12435
 
11783
12436
  /* ── Root ── */
11784
12437
  [data-ui="empty-state"] {
@@ -11789,7 +12442,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11789
12442
  text-align: center;
11790
12443
  padding: var(--space-8) var(--space-6);
11791
12444
  gap: var(--space-3);
11792
- font-family: var(--font-sans, system-ui, sans-serif);
12445
+ font-family: var(--font-body);
11793
12446
  }
11794
12447
 
11795
12448
  /* ── Icon ── */
@@ -11812,10 +12465,13 @@ div[data-ui="separator"][data-style="thick"]::after {
11812
12465
 
11813
12466
  /* ── Title ── */
11814
12467
  [data-ui="empty-state"] [data-part="title"] {
11815
- font-family: var(--font-sans, system-ui, sans-serif);
12468
+ font-family: var(--font-heading);
11816
12469
  font-size: var(--text-lg);
11817
12470
  font-weight: var(--weight-semibold);
11818
- line-height: var(--leading-tight);
12471
+ letter-spacing: var(--heading-tracking);
12472
+ text-transform: var(--heading-transform);
12473
+ font-variant-caps: var(--heading-caps);
12474
+ line-height: var(--heading-leading);
11819
12475
  color: var(--color-fg);
11820
12476
  margin: 0;
11821
12477
  }
@@ -11913,7 +12569,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11913
12569
 
11914
12570
  /* === patterns/feature-grid.css === */
11915
12571
  /* @ui:component feature-grid */
11916
- /* @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 */
12572
+ /* @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 */
11917
12573
 
11918
12574
  /* ── Root ──
11919
12575
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -11923,7 +12579,7 @@ div[data-ui="separator"][data-style="thick"]::after {
11923
12579
  gap: var(--space-4);
11924
12580
  padding-block: var(--space-12);
11925
12581
  padding-inline: var(--space-4);
11926
- font-family: var(--font-sans, system-ui, sans-serif);
12582
+ font-family: var(--font-body);
11927
12583
  color: var(--color-fg);
11928
12584
  background: var(--color-bg);
11929
12585
  }
@@ -12065,7 +12721,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12065
12721
  max-inline-size: var(--measure-narrow);
12066
12722
  margin-inline: auto;
12067
12723
  padding-block: var(--space-8);
12068
- font-family: var(--font-sans);
12724
+ font-family: var(--font-body);
12069
12725
  }
12070
12726
 
12071
12727
  :where(form[l-data]:not([data-ui]) > h1) {
@@ -12085,7 +12741,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12085
12741
 
12086
12742
  /* === patterns/hero.css === */
12087
12743
  /* @ui:component hero */
12088
- /* @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 */
12744
+ /* @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 */
12089
12745
 
12090
12746
  /* ── Root ──
12091
12747
  A one-column grid by default; the layout variants only change how that grid
@@ -12099,9 +12755,10 @@ div[data-ui="separator"][data-style="thick"]::after {
12099
12755
  gap: var(--space-4);
12100
12756
  padding-block: var(--space-12);
12101
12757
  padding-inline: var(--space-4);
12102
- font-family: var(--font-sans, system-ui, sans-serif);
12758
+ font-family: var(--font-body);
12103
12759
  color: var(--color-fg);
12104
- background: var(--color-bg);
12760
+ background-color: var(--color-bg);
12761
+ background-image: var(--texture-surface);
12105
12762
  }
12106
12763
 
12107
12764
  /* ── Eyebrow ── */
@@ -12113,9 +12770,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12113
12770
  /* ── Headline ── */
12114
12771
  [data-ui="hero"] [data-part="headline"] {
12115
12772
  margin: 0;
12773
+ font-family: var(--font-heading);
12116
12774
  font-size: var(--text-3xl);
12117
- font-weight: var(--weight-bold);
12118
- line-height: var(--leading-tight);
12775
+ font-weight: var(--heading-weight);
12776
+ letter-spacing: var(--heading-tracking);
12777
+ text-transform: var(--heading-transform);
12778
+ font-variant-caps: var(--heading-caps);
12779
+ line-height: var(--heading-leading);
12119
12780
  color: var(--color-fg);
12120
12781
  text-wrap: balance;
12121
12782
  }
@@ -12234,7 +12895,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12234
12895
 
12235
12896
  /* === patterns/inbox.css === */
12236
12897
  /* @ui:component inbox */
12237
- /* @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 */
12898
+ /* @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 */
12238
12899
 
12239
12900
  /* ── Root ──
12240
12901
  ONE pane, because that is what a phone has room for. Each pane's `data-state`
@@ -12254,7 +12915,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12254
12915
  overflow: hidden;
12255
12916
  border: var(--space-px, 1px) solid var(--color-border);
12256
12917
  border-radius: var(--radius-lg);
12257
- font-family: var(--font-sans, system-ui, sans-serif);
12918
+ font-family: var(--font-body);
12258
12919
  color: var(--color-fg);
12259
12920
  background: var(--color-bg);
12260
12921
  }
@@ -12346,8 +13007,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12346
13007
  }
12347
13008
 
12348
13009
  [data-ui="inbox"] [data-part="item"]:focus-visible {
12349
- outline: 2px solid var(--color-ring);
12350
- outline-offset: 2px;
13010
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13011
+ outline-offset: var(--focus-ring-offset);
12351
13012
  }
12352
13013
 
12353
13014
  [data-ui="inbox"] [data-part="item"][data-state="selected"] {
@@ -12506,7 +13167,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12506
13167
 
12507
13168
  /* === patterns/pricing.css === */
12508
13169
  /* @ui:component pricing */
12509
- /* @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 */
13170
+ /* @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 */
12510
13171
 
12511
13172
  /* ── Root ──
12512
13173
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -12516,7 +13177,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12516
13177
  gap: var(--space-4);
12517
13178
  padding-block: var(--space-12);
12518
13179
  padding-inline: var(--space-4);
12519
- font-family: var(--font-sans, system-ui, sans-serif);
13180
+ font-family: var(--font-body);
12520
13181
  color: var(--color-fg);
12521
13182
  background: var(--color-bg);
12522
13183
  }
@@ -12566,9 +13227,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12566
13227
 
12567
13228
  [data-ui="pricing"] [data-part="tier"] [data-part="title"] {
12568
13229
  margin: 0;
13230
+ font-family: var(--font-heading);
12569
13231
  font-size: var(--text-lg);
12570
13232
  font-weight: var(--weight-semibold);
12571
- line-height: var(--leading-tight);
13233
+ letter-spacing: var(--heading-tracking);
13234
+ text-transform: var(--heading-transform);
13235
+ font-variant-caps: var(--heading-caps);
13236
+ line-height: var(--heading-leading);
12572
13237
  }
12573
13238
 
12574
13239
  [data-ui="pricing"] [data-part="tier"] [data-part="header"] [data-part="description"] {
@@ -12629,7 +13294,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12629
13294
  [data-ui="pricing"] [data-part="tier"][data-state="featured"] {
12630
13295
  border-color: var(--color-primary);
12631
13296
  box-shadow: var(--shadow-md);
12632
- outline: var(--space-px, 1px) solid var(--color-primary);
13297
+ outline: var(--border-width-strong) solid var(--color-primary);
12633
13298
  }
12634
13299
 
12635
13300
  /* ── Footnote ── */
@@ -12674,14 +13339,14 @@ div[data-ui="separator"][data-style="thick"]::after {
12674
13339
 
12675
13340
  /* === patterns/search-results.css === */
12676
13341
  /* @ui:component search-results */
12677
- /* @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 */
13342
+ /* @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 */
12678
13343
 
12679
13344
  /* ── Root ── */
12680
13345
  [data-ui="search-results"] {
12681
13346
  display: flex;
12682
13347
  flex-direction: column;
12683
13348
  gap: var(--space-4);
12684
- font-family: var(--font-sans, system-ui, sans-serif);
13349
+ font-family: var(--font-body);
12685
13350
  }
12686
13351
 
12687
13352
  /* ── Search Input ── */
@@ -12709,7 +13374,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12709
13374
  justify-content: space-between;
12710
13375
  gap: var(--space-4);
12711
13376
  padding-bottom: var(--space-2);
12712
- border-bottom: 1px solid var(--color-border);
13377
+ border-bottom: var(--border-width) solid var(--color-border);
12713
13378
  }
12714
13379
 
12715
13380
  [data-ui="search-results"] [data-part="results-count"] {
@@ -12744,7 +13409,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12744
13409
  flex-direction: column;
12745
13410
  gap: var(--space-2);
12746
13411
  padding: var(--space-4);
12747
- border: 1px solid var(--color-border);
13412
+ border: var(--border-width) solid var(--color-border);
12748
13413
  border-radius: var(--radius-md);
12749
13414
  background: var(--color-bg);
12750
13415
  transition: background var(--duration-fast) var(--ease-default),
@@ -12803,7 +13468,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12803
13468
  display: flex;
12804
13469
  justify-content: center;
12805
13470
  padding-top: var(--space-4);
12806
- border-top: 1px solid var(--color-border);
13471
+ border-top: var(--border-width) solid var(--color-border);
12807
13472
  }
12808
13473
 
12809
13474
  /* ── Loading ── */
@@ -12843,7 +13508,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12843
13508
 
12844
13509
  /* ── Error State ── */
12845
13510
  [data-ui="search-results"][data-state="error"] [data-part="results-list"] {
12846
- border: 1px solid var(--color-border);
13511
+ border: var(--border-width) solid var(--color-border);
12847
13512
  border-radius: var(--radius-md);
12848
13513
  padding: var(--space-6);
12849
13514
  text-align: center;
@@ -12852,8 +13517,8 @@ div[data-ui="separator"][data-style="thick"]::after {
12852
13517
 
12853
13518
  /* ── Focus management ── */
12854
13519
  [data-ui="search-results"] [data-part="result-item"]:focus-visible {
12855
- outline: 2px solid var(--color-ring, oklch(0.55 0.22 264));
12856
- outline-offset: 2px;
13520
+ outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
13521
+ outline-offset: var(--focus-ring-offset);
12857
13522
  }
12858
13523
 
12859
13524
  /* ── Motion ── */
@@ -12869,7 +13534,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12869
13534
 
12870
13535
  /* === patterns/settings-page.css === */
12871
13536
  /* @ui:component settings-page */
12872
- /* @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 */
13537
+ /* @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 */
12873
13538
 
12874
13539
  /* ── Root ── */
12875
13540
  [data-ui="settings-page"] {
@@ -12879,7 +13544,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12879
13544
  width: 100%;
12880
13545
  max-width: 768px;
12881
13546
  margin-inline: auto;
12882
- font-family: var(--font-sans, system-ui, sans-serif);
13547
+ font-family: var(--font-body);
12883
13548
  color: var(--color-fg);
12884
13549
  }
12885
13550
 
@@ -12893,9 +13558,13 @@ div[data-ui="separator"][data-style="thick"]::after {
12893
13558
  /* ── Title ── */
12894
13559
  [data-ui="settings-page"] [data-part="title"] {
12895
13560
  margin: 0;
13561
+ font-family: var(--font-heading);
12896
13562
  font-size: var(--text-xl, 1.25rem);
12897
13563
  font-weight: var(--weight-semibold, 600);
12898
- line-height: var(--leading-tight);
13564
+ letter-spacing: var(--heading-tracking);
13565
+ text-transform: var(--heading-transform);
13566
+ font-variant-caps: var(--heading-caps);
13567
+ line-height: var(--heading-leading);
12899
13568
  color: var(--color-fg);
12900
13569
  }
12901
13570
 
@@ -12959,7 +13628,7 @@ div[data-ui="separator"][data-style="thick"]::after {
12959
13628
  gap: var(--space-3, 0.75rem);
12960
13629
  padding: var(--space-4);
12961
13630
  background: var(--color-bg);
12962
- border-top: 1px solid var(--color-border);
13631
+ border-top: var(--border-width) solid var(--color-border);
12963
13632
  border-radius: var(--radius-lg);
12964
13633
  box-shadow: var(--shadow-md);
12965
13634
  position: sticky;
@@ -13023,7 +13692,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13023
13692
  flex-direction: row;
13024
13693
  flex-wrap: wrap;
13025
13694
  border-inline-end: none;
13026
- border-bottom: 1px solid var(--color-border);
13695
+ border-bottom: var(--border-width) solid var(--color-border);
13027
13696
  padding-inline-end: 0;
13028
13697
  position: static;
13029
13698
  }
@@ -13042,7 +13711,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13042
13711
  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="list"] {
13043
13712
  flex-direction: column;
13044
13713
  border-bottom: none;
13045
- border-inline-end: 1px solid var(--color-border);
13714
+ border-inline-end: var(--border-width) solid var(--color-border);
13046
13715
  padding-inline-end: var(--space-4);
13047
13716
  position: sticky;
13048
13717
  top: var(--space-4);
@@ -13060,7 +13729,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13060
13729
  justify-content: flex-start;
13061
13730
  text-align: start;
13062
13731
  border-bottom: none;
13063
- border-inline-start: 2px solid transparent;
13732
+ border-inline-start: var(--border-width-strong) solid transparent;
13064
13733
  margin-bottom: 0;
13065
13734
  margin-inline-end: -1px;
13066
13735
  padding: var(--space-2) var(--space-3);
@@ -13094,7 +13763,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13094
13763
 
13095
13764
  /* === patterns/site-footer.css === */
13096
13765
  /* @ui:component site-footer */
13097
- /* @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 */
13766
+ /* @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 */
13098
13767
 
13099
13768
  /* ── Root ──
13100
13769
  Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
@@ -13104,11 +13773,11 @@ div[data-ui="separator"][data-style="thick"]::after {
13104
13773
  gap: var(--space-8);
13105
13774
  padding-block: var(--space-10);
13106
13775
  padding-inline: var(--space-4);
13107
- font-family: var(--font-sans, system-ui, sans-serif);
13776
+ font-family: var(--font-body);
13108
13777
  font-size: var(--text-sm);
13109
13778
  color: var(--color-fg-muted);
13110
13779
  background: var(--color-bg-subtle);
13111
- border-block-start: 1px solid var(--color-border);
13780
+ border-block-start: var(--border-width) solid var(--color-border);
13112
13781
  }
13113
13782
 
13114
13783
  /* ── Brand ── */
@@ -13240,7 +13909,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13240
13909
 
13241
13910
  /* === patterns/stats-dashboard.css === */
13242
13911
  /* @ui:component stats-dashboard */
13243
- /* @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 */
13912
+ /* @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 */
13244
13913
 
13245
13914
  /* ── Root ──
13246
13915
  A reporting page: title block, KPI row, then the panel region. The KPI row
@@ -13253,7 +13922,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13253
13922
  gap: var(--space-3);
13254
13923
  padding-block: var(--space-8);
13255
13924
  padding-inline: var(--space-4);
13256
- font-family: var(--font-sans, system-ui, sans-serif);
13925
+ font-family: var(--font-body);
13257
13926
  color: var(--color-fg);
13258
13927
  background: var(--color-bg);
13259
13928
  }
@@ -13327,9 +13996,13 @@ div[data-ui="separator"][data-style="thick"]::after {
13327
13996
 
13328
13997
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="title"] {
13329
13998
  margin: 0;
13999
+ font-family: var(--font-heading);
13330
14000
  font-size: var(--text-lg);
13331
14001
  font-weight: var(--weight-semibold);
13332
- line-height: var(--leading-tight);
14002
+ letter-spacing: var(--heading-tracking);
14003
+ text-transform: var(--heading-transform);
14004
+ font-variant-caps: var(--heading-caps);
14005
+ line-height: var(--heading-leading);
13333
14006
  }
13334
14007
 
13335
14008
  [data-ui="stats-dashboard"] [data-part="report"] [data-part="header"] [data-part="description"] {
@@ -13420,7 +14093,7 @@ div[data-ui="separator"][data-style="thick"]::after {
13420
14093
  gap: var(--space-6);
13421
14094
  max-inline-size: var(--measure-narrow);
13422
14095
  margin-inline: auto;
13423
- font-family: var(--font-sans);
14096
+ font-family: var(--font-body);
13424
14097
  }
13425
14098
 
13426
14099
  [data-ui="wizard"] [data-part="heading"] {