@teamblind-chorus/ui 1.1.0 → 2.0.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 (148) hide show
  1. package/README.md +3 -3
  2. package/agents/AGENTS.md +6 -6
  3. package/agents/DESIGN.md +245 -244
  4. package/agents/LOVABLE.md +40 -11
  5. package/agents/catalog.md +10 -8
  6. package/agents/components/avatar-rail/avatar-rail.md +2 -4
  7. package/agents/components/avatar-rail/avatar-rail.spec.json +27 -12
  8. package/agents/components/badge/role.md +7 -9
  9. package/agents/components/badge/role.spec.json +6 -6
  10. package/agents/components/badge/update.md +6 -8
  11. package/agents/components/badge/update.spec.json +5 -5
  12. package/agents/components/banner/banner.family.json +3 -1
  13. package/agents/components/banner/banner.md +66 -15
  14. package/agents/components/banner/banner.spec.json +37 -14
  15. package/agents/components/bottom-sheet/bottom-sheet.md +4 -6
  16. package/agents/components/bottom-sheet/bottom-sheet.spec.json +5 -5
  17. package/agents/components/bubble/bubble.md +8 -10
  18. package/agents/components/bubble/bubble.spec.json +11 -11
  19. package/agents/components/button/button.md +1 -1
  20. package/agents/components/button/check.md +9 -11
  21. package/agents/components/button/check.spec.json +25 -8
  22. package/agents/components/button/fab.md +7 -9
  23. package/agents/components/button/fab.spec.json +27 -10
  24. package/agents/components/button/group.spec.json +4 -4
  25. package/agents/components/button/icon.md +21 -23
  26. package/agents/components/button/icon.spec.json +29 -12
  27. package/agents/components/button/standard.md +40 -42
  28. package/agents/components/button/standard.spec.json +37 -20
  29. package/agents/components/button/text.md +21 -23
  30. package/agents/components/button/text.spec.json +30 -13
  31. package/agents/components/button/toggle.md +7 -9
  32. package/agents/components/button/toggle.spec.json +27 -10
  33. package/agents/components/button/toolbar.md +24 -26
  34. package/agents/components/button/toolbar.spec.json +10 -12
  35. package/agents/components/carousel/carousel.md +1 -1
  36. package/agents/components/carousel/post.md +15 -21
  37. package/agents/components/carousel/post.spec.json +17 -17
  38. package/agents/components/carousel/profile.md +9 -45
  39. package/agents/components/carousel/profile.spec.json +17 -17
  40. package/agents/components/chip/chip.md +1 -1
  41. package/agents/components/chip/filter.md +22 -24
  42. package/agents/components/chip/filter.spec.json +34 -11
  43. package/agents/components/chip/tag.md +22 -24
  44. package/agents/components/chip/tag.spec.json +36 -13
  45. package/agents/components/dialog/dialog.md +1 -3
  46. package/agents/components/dialog/dialog.spec.json +3 -3
  47. package/agents/components/directory-list/directory-list.md +1 -3
  48. package/agents/components/directory-list/directory-list.spec.json +2 -2
  49. package/agents/components/divider/divider.family.json +1 -1
  50. package/agents/components/divider/divider.md +12 -14
  51. package/agents/components/divider/divider.spec.json +8 -8
  52. package/agents/components/empty-state/empty-state.family.json +28 -0
  53. package/agents/components/empty-state/empty-state.md +69 -0
  54. package/agents/components/empty-state/empty-state.spec.json +87 -0
  55. package/agents/components/feed/ad.md +2 -4
  56. package/agents/components/feed/ad.spec.json +10 -10
  57. package/agents/components/feed/post.md +41 -43
  58. package/agents/components/feed/post.spec.json +35 -39
  59. package/agents/components/form-field/form-field.md +1 -1
  60. package/agents/components/form-field/input.md +32 -34
  61. package/agents/components/form-field/input.spec.json +39 -31
  62. package/agents/components/form-field/search.md +2 -4
  63. package/agents/components/form-field/search.spec.json +24 -16
  64. package/agents/components/form-field/select.md +18 -20
  65. package/agents/components/form-field/select.spec.json +36 -27
  66. package/agents/components/form-field/textarea.md +3 -5
  67. package/agents/components/form-field/textarea.spec.json +37 -29
  68. package/agents/components/header/main.md +4 -6
  69. package/agents/components/header/main.spec.json +3 -3
  70. package/agents/components/header/sub.md +6 -8
  71. package/agents/components/header/sub.spec.json +3 -3
  72. package/agents/components/list/accordion.md +34 -45
  73. package/agents/components/list/accordion.spec.json +26 -17
  74. package/agents/components/list/entry.md +59 -81
  75. package/agents/components/list/entry.spec.json +37 -21
  76. package/agents/components/list/list.md +2 -2
  77. package/agents/components/list/radio.md +13 -20
  78. package/agents/components/list/radio.spec.json +33 -18
  79. package/agents/components/list/standard.md +88 -64
  80. package/agents/components/list/standard.spec.json +52 -20
  81. package/agents/components/metadata/compact.md +4 -6
  82. package/agents/components/metadata/compact.spec.json +6 -6
  83. package/agents/components/metadata/metadata.md +1 -1
  84. package/agents/components/metadata/standard.md +12 -14
  85. package/agents/components/metadata/standard.spec.json +10 -10
  86. package/agents/components/nav-card/nav-card.md +25 -27
  87. package/agents/components/nav-card/nav-card.spec.json +25 -16
  88. package/agents/components/nav-list/nav-list.md +2 -8
  89. package/agents/components/nav-list/nav-list.spec.json +3 -3
  90. package/agents/components/navigation-bar/main.md +9 -11
  91. package/agents/components/navigation-bar/main.spec.json +6 -6
  92. package/agents/components/navigation-bar/search.md +6 -8
  93. package/agents/components/navigation-bar/search.spec.json +9 -9
  94. package/agents/components/navigation-bar/sub.md +9 -11
  95. package/agents/components/navigation-bar/sub.spec.json +7 -7
  96. package/agents/components/page-shell/page-shell.family.json +1 -1
  97. package/agents/components/page-shell/page-shell.md +33 -0
  98. package/agents/components/page-shell/page-shell.spec.json +85 -0
  99. package/agents/components/pagination/pagination.family.json +1 -1
  100. package/agents/components/pagination/pagination.md +3 -3
  101. package/agents/components/pagination/pagination.spec.json +5 -5
  102. package/agents/components/profile-header/profile-header.md +9 -11
  103. package/agents/components/profile-header/profile-header.spec.json +9 -9
  104. package/agents/components/progress/progress.family.json +1 -1
  105. package/agents/components/progress/progress.md +5 -5
  106. package/agents/components/progress/progress.spec.json +8 -8
  107. package/agents/components/side-sheet/side-sheet.md +11 -13
  108. package/agents/components/side-sheet/side-sheet.spec.json +3 -3
  109. package/agents/components/skeleton/skeleton.md +7 -9
  110. package/agents/components/skeleton/skeleton.spec.json +5 -5
  111. package/agents/components/spinner/spinner.family.json +27 -0
  112. package/agents/components/spinner/spinner.md +96 -0
  113. package/agents/components/spinner/spinner.spec.json +82 -0
  114. package/agents/components/status-tag/status-tag.md +7 -9
  115. package/agents/components/status-tag/status-tag.spec.json +5 -5
  116. package/agents/components/suggestion-list/suggestion-list.md +3 -7
  117. package/agents/components/suggestion-list/suggestion-list.spec.json +8 -12
  118. package/agents/components/switch/switch.md +12 -14
  119. package/agents/components/switch/switch.spec.json +23 -15
  120. package/agents/components/tab-bar/tab-bar.md +9 -11
  121. package/agents/components/tab-bar/tab-bar.spec.json +37 -23
  122. package/agents/components/tabs/rounded.md +6 -8
  123. package/agents/components/tabs/rounded.spec.json +34 -13
  124. package/agents/components/tabs/segmented.md +4 -6
  125. package/agents/components/tabs/segmented.spec.json +4 -8
  126. package/agents/components/tabs/underline.md +9 -11
  127. package/agents/components/tabs/underline.spec.json +31 -14
  128. package/agents/components/thumbnail/thumbnail.md +5 -7
  129. package/agents/components/thumbnail/thumbnail.spec.json +8 -8
  130. package/agents/components/toast/toast.md +5 -7
  131. package/agents/components/toast/toast.spec.json +3 -3
  132. package/agents/components/tooltip/tooltip.md +6 -8
  133. package/agents/components/tooltip/tooltip.spec.json +4 -4
  134. package/agents/manifest.json +8 -6
  135. package/agents/tokens.usage.json +71 -226
  136. package/agents/usage.json +12 -0
  137. package/dist/index.cjs +531 -262
  138. package/dist/index.cjs.map +1 -1
  139. package/dist/index.d.cts +57 -13
  140. package/dist/index.d.ts +57 -13
  141. package/dist/index.js +530 -263
  142. package/dist/index.js.map +1 -1
  143. package/dist/styles.css +560 -379
  144. package/eslint/rules.js +7 -7
  145. package/package.json +2 -3
  146. package/agents/anti-patterns.md +0 -533
  147. package/agents/compose.md +0 -240
  148. package/agents/images.md +0 -66
package/dist/styles.css CHANGED
@@ -160,10 +160,9 @@ textarea {
160
160
  `box-shadow` on the button itself. Because the pseudo-element is
161
161
  `position: absolute`, the ring is out of flow: it contributes nothing
162
162
  to layout, so neither the button, a button group's gap, nor any
163
- sibling shifts when focus arrives. The two-layer composition is
164
- DESIGN.md's canonical recipe, painted *outward* via stacked box-shadows
165
- (1px `focusInset` counter-ring at 0→1px, then the 2px `focus` stroke
166
- visible at 1→3px). Sits at `z-index: 2`, above the state-overlay
163
+ sibling shifts when focus arrives. The single-ring composition is
164
+ DESIGN.md's canonical recipe, painted *outward* as a 1px
165
+ `border.focused` box-shadow. Sits at `z-index: 2`, above the state-overlay
167
166
  `::before` (z-index 0) and the label / icon (z-index 1). */
168
167
  .chorus-button--standard::after {
169
168
  content: '';
@@ -178,9 +177,7 @@ textarea {
178
177
 
179
178
  .chorus-button--standard:focus-visible::after,
180
179
  .chorus-button--standard[data-force-state="focused"]::after {
181
- box-shadow:
182
- 0 0 0 var(--button-standard-focus-inset-width) var(--button-standard-focus-inset-color),
183
- 0 0 0 calc(var(--button-standard-focus-outer-width) + var(--button-standard-focus-inset-width)) var(--button-standard-focus-outer-color);
180
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--button-standard-focus-outer-color);
184
181
  }
185
182
 
186
183
  .chorus-button--standard:disabled::after { box-shadow: none; }
@@ -252,7 +249,7 @@ textarea {
252
249
  .chorus-button-group__label {
253
250
  text-align: center;
254
251
  margin-bottom: var(--sys-layout-stack-md);
255
- color: var(--sys-color-onSurfaceVariant);
252
+ color: var(--sys-color-text-subtle);
256
253
  font-size: var(--sys-typo-body-md-size);
257
254
  font-weight: var(--sys-typo-body-md-weight);
258
255
  line-height: var(--sys-typo-body-md-line);
@@ -260,7 +257,7 @@ textarea {
260
257
  }
261
258
 
262
259
  .chorus-button-group__label strong {
263
- color: var(--sys-color-onSurface);
260
+ color: var(--sys-color-text-default);
264
261
  }
265
262
 
266
263
  /* Docked footer bar — full-bleed surface pinned to the bottom of the app.
@@ -269,7 +266,7 @@ textarea {
269
266
  passing behind reads as a separate region. Renders in flow — PageShell
270
267
  owns the pin, so the bar must NOT set position: sticky/fixed itself. */
271
268
  .chorus-button-group--docked {
272
- background: var(--sys-color-surface);
269
+ background: var(--sys-color-surface-default);
273
270
  padding: var(--sys-layout-container-md);
274
271
  box-shadow: var(--sys-elevation-sheet);
275
272
  }
@@ -329,7 +326,7 @@ textarea {
329
326
  /* Focus ring — dedicated overlay layer (`::after`), so it never affects
330
327
  layout (the FAB's footprint is fixed; nothing reflows on focus) and
331
328
  never collides with the FAB's own `box-shadow` (the floating
332
- elevation, which stays untouched underneath). Canonical two-layer
329
+ elevation, which stays untouched underneath). Canonical single-ring
333
330
  composition, painted outward; `z-index: 2`, above the overlay
334
331
  `::before` (z-index 0) and the label / icon (z-index 1). */
335
332
  .chorus-button--fab::after {
@@ -345,9 +342,7 @@ textarea {
345
342
 
346
343
  .chorus-button--fab:focus-visible::after,
347
344
  .chorus-button--fab[data-force-state="focused"]::after {
348
- box-shadow:
349
- 0 0 0 var(--button-fab-focus-inset-width) var(--button-fab-focus-inset-color),
350
- 0 0 0 calc(var(--button-fab-focus-outer-width) + var(--button-fab-focus-inset-width)) var(--button-fab-focus-outer-color);
345
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--button-fab-focus-outer-color);
351
346
  }
352
347
 
353
348
  .chorus-button--fab__icon,
@@ -393,11 +388,7 @@ textarea {
393
388
  --chip-overlay-hover: var(--sys-state-hover);
394
389
  --chip-overlay-pressed: var(--sys-state-pressed);
395
390
  --chip-overlay-focus: var(--sys-state-focus);
396
- --chip-disabled-opacity: var(--sys-state-disabled);
397
- --chip-focus-outer-width: var(--sys-borderWidth-thin);
398
- --chip-focus-outer-color: var(--sys-color-focus);
399
- --chip-focus-inset-width: var(--sys-borderWidth-hairline);
400
- --chip-focus-inset-color: var(--sys-color-focusInset);
391
+ --chip-focus-outer-color: var(--sys-color-border-focused);
401
392
  font-size: var(--sys-typo-label-sm-size);
402
393
  font-weight: var(--sys-typo-label-sm-weight);
403
394
  line-height: var(--sys-typo-label-sm-line);
@@ -431,8 +422,8 @@ textarea {
431
422
 
432
423
  .chorus-chip--filter {
433
424
  --chip-bg: transparent;
434
- --chip-label: var(--sys-color-onSurface);
435
- --chip-border-color: var(--sys-color-outlineVariant);
425
+ --chip-label: var(--sys-color-text-default);
426
+ --chip-border-color: var(--sys-color-border-default);
436
427
  /* 32 capsule — anatomy rung, resolved via ref.space. */
437
428
  --chip-min-height: var(--ref-space-400);
438
429
  --chip-padding-block: var(--sys-layout-container-2xs);
@@ -441,8 +432,8 @@ textarea {
441
432
  }
442
433
 
443
434
  .chorus-chip--filter.is-selected {
444
- --chip-bg: var(--sys-color-inverseSurface);
445
- --chip-label: var(--sys-color-inverseOnSurface);
435
+ --chip-bg: var(--sys-color-background-inverse);
436
+ --chip-label: var(--sys-color-text-inverse);
446
437
  --chip-border-color: transparent;
447
438
  }
448
439
 
@@ -455,8 +446,8 @@ textarea {
455
446
  so the recipe falls out of the same chip CSS without a per-state
456
447
  override. */
457
448
  .chorus-chip--filter.chorus-button--toolbar--accent {
458
- --chip-bg: var(--sys-color-primary);
459
- --chip-label: var(--sys-color-onPrimary);
449
+ --chip-bg: var(--sys-color-background-primary);
450
+ --chip-label: var(--sys-color-text-onFill);
460
451
  --chip-border-color: transparent;
461
452
  }
462
453
 
@@ -466,8 +457,8 @@ textarea {
466
457
  cluster so the button reads against `inverseSurface` containers
467
458
  without a per-host tweak. */
468
459
  .chorus-chip--filter.chorus-button--toolbar--inverse {
469
- --chip-bg: var(--sys-color-inverseSurface);
470
- --chip-label: var(--sys-color-inverseOnSurface);
460
+ --chip-bg: var(--sys-color-background-inverse);
461
+ --chip-label: var(--sys-color-text-inverse);
471
462
  --chip-border-color: transparent;
472
463
  }
473
464
 
@@ -477,8 +468,8 @@ textarea {
477
468
  (transparent while inactive), so the chip never changes width when it
478
469
  toggles. */
479
470
  .chorus-chip--toggle {
480
- --chip-bg: var(--sys-color-primary);
481
- --chip-label: var(--sys-color-onPrimary);
471
+ --chip-bg: var(--sys-color-background-primary);
472
+ --chip-label: var(--sys-color-text-onFill);
482
473
  --chip-border-color: transparent;
483
474
  /* 32 capsule — same geometry as Filter, anatomy rung. */
484
475
  --chip-min-height: var(--ref-space-400);
@@ -488,21 +479,18 @@ textarea {
488
479
  }
489
480
 
490
481
  .chorus-chip--toggle.is-selected {
491
- --chip-bg: var(--sys-color-surfaceContainerHigh);
492
- --chip-label: var(--sys-color-onSurface);
493
- --chip-border-color: var(--sys-color-outlineVariant);
482
+ --chip-bg: var(--sys-color-background-neutral);
483
+ --chip-label: var(--sys-color-text-default);
484
+ --chip-border-color: var(--sys-color-border-default);
494
485
  }
495
486
 
496
487
  .chorus-chip--tag {
497
- /* Translucent overlay (`sys.color.scrimSubtle` black 8% in light,
498
- white 8% in dark) rather than a tonal container role, so the tag
499
- adopts whatever surface sits behind it — body, raised card, sheet —
500
- by tinting one step darker (light mode) or lighter (dark mode)
501
- instead of pinning to a fixed neutral step that can collide with
502
- the surface ladder. Same Banner-style scrim used by Progress
503
- track, StatusTag neutral, and Skeleton. */
504
- --chip-bg: var(--sys-color-scrimSubtle);
505
- --chip-label: var(--sys-color-onSurface);
488
+ /* Solid `background.neutral` fill (the role that replaced the old ~8%
489
+ scrim) a fixed light-gray pill in light, a mid-gray in dark. Same
490
+ neutral fill as Banner default, Progress track, StatusTag neutral,
491
+ and Skeleton, so the quiet-neutral family reads as one. */
492
+ --chip-bg: var(--sys-color-background-neutral);
493
+ --chip-label: var(--sys-color-text-default);
506
494
  --chip-border-color: transparent;
507
495
  /* 24 capsule — Tag rung, anatomy via ref.space. */
508
496
  --chip-min-height: var(--ref-space-300);
@@ -516,8 +504,8 @@ textarea {
516
504
  block. Inline `--chip-bg` is also skipped by the JSX (the appearance
517
505
  has no `backgroundDark` field) so this class wins cleanly. */
518
506
  .chorus-chip--tag.chorus-chip--tag--accent {
519
- --chip-bg: var(--sys-color-primaryContainer);
520
- --chip-label: var(--sys-color-primary);
507
+ --chip-bg: var(--sys-color-background-selected);
508
+ --chip-label: var(--sys-color-text-accent-blue);
521
509
  }
522
510
 
523
511
  /* Icon-only Compact — when the chip carries no label slot, shrink the
@@ -559,7 +547,7 @@ span.chorus-chip {
559
547
 
560
548
  /* Focus ring — dedicated overlay layer (`::after`), `position: absolute`
561
549
  so it's out of flow: a focused chip never widens, and a chip group's
562
- 4px gap never shifts. Canonical two-layer composition, painted outward;
550
+ 4px gap never shifts. Canonical single-ring composition, painted outward;
563
551
  `z-index: 2`, above the overlay `::before` (z-index 0) and the label /
564
552
  icon (z-index 1). Inside a Tabs row the ring is re-anchored *inward*
565
553
  (the row is a scroller — see the Segmented override below). */
@@ -576,9 +564,7 @@ span.chorus-chip {
576
564
 
577
565
  .chorus-chip:focus-visible::after,
578
566
  .chorus-chip[data-force-state="focused"]::after {
579
- box-shadow:
580
- 0 0 0 var(--chip-focus-inset-width) var(--chip-focus-inset-color),
581
- 0 0 0 calc(var(--chip-focus-outer-width) + var(--chip-focus-inset-width)) var(--chip-focus-outer-color);
567
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--chip-focus-outer-color);
582
568
  }
583
569
 
584
570
  .chorus-chip:disabled::after { box-shadow: none; }
@@ -607,7 +593,12 @@ span.chorus-chip {
607
593
  }
608
594
 
609
595
  .chorus-chip:disabled {
610
- opacity: var(--chip-disabled-opacity);
596
+ /* Explicit disabled (no opacity): neutral disabled pill — overrides the
597
+ variant's --chip-bg / --chip-label / --chip-border-color on source
598
+ order (this rule sits after every appearance block above). */
599
+ --chip-bg: var(--sys-color-background-disabled);
600
+ --chip-label: var(--sys-color-text-disabled);
601
+ --chip-border-color: var(--sys-color-border-bold);
611
602
  cursor: not-allowed;
612
603
  }
613
604
 
@@ -649,7 +640,7 @@ span.chorus-chip {
649
640
  width: var(--badge-min-width);
650
641
  height: var(--badge-min-height);
651
642
  padding: 0;
652
- box-shadow: 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-surface);
643
+ box-shadow: 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-surface-default);
653
644
  }
654
645
 
655
646
  /* ============================================================
@@ -749,7 +740,11 @@ span.chorus-chip {
749
740
  }
750
741
 
751
742
  .chorus-tab:disabled {
752
- opacity: var(--tabs-disabled-opacity);
743
+ /* Explicit disabled (no opacity): label + icon re-tone to text.disabled
744
+ (icon rides currentColor); overrides the selected/unselected label
745
+ color on specificity. A disabled tab is never selected, so no
746
+ indicator paints. */
747
+ color: var(--sys-color-text-disabled);
753
748
  cursor: not-allowed;
754
749
  outline: none;
755
750
  box-shadow: none;
@@ -889,10 +884,9 @@ span.chorus-chip {
889
884
  • Clip-safe — the Tabs row is a horizontal scroller (`overflow-x:
890
885
  auto`, which coerces `overflow-y: auto`), so an *outward* ring is
891
886
  sliced off at the row's top / bottom edge. The ring is drawn
892
- *inside* the tab via stacked inset box-shadows, so nothing clips it.
893
- • Layer-safe — an `outline` painted over the tab box covers the inset
894
- counter-ring; here the two layers (2px `focus` stroke over a 1px
895
- `focusInset` counter-ring) are explicit and both visible.
887
+ *inside* the tab via an inset box-shadow, so nothing clips it.
888
+ • Layer-safe — the ring is a single 1px `border.focused` inset
889
+ box-shadow on the `::after`, explicit and always visible.
896
890
  Sits at `z-index: 2`, above the state-overlay `::before` (z-index 0)
897
891
  and the label / icon (z-index 1). The tab's own `::before` already
898
892
  owns the focus *overlay* tint; this `::after` owns the *ring*. */
@@ -909,9 +903,7 @@ span.chorus-chip {
909
903
 
910
904
  .chorus-tab--underline:focus-visible::after,
911
905
  .chorus-tab--underline[data-force-state="focused"]::after {
912
- box-shadow:
913
- inset 0 0 0 var(--tabs-focus-outer-width) var(--tabs-focus-outer-color),
914
- inset 0 0 0 calc(var(--tabs-focus-outer-width) + var(--tabs-focus-inset-width)) var(--tabs-focus-inset-color);
906
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--tabs-focus-outer-color);
915
907
  }
916
908
 
917
909
  /* ----- Segmented ----- */
@@ -951,9 +943,7 @@ span.chorus-chip {
951
943
  from outward to inset here.) */
952
944
  .chorus-tabs--segmented .chorus-chip:focus-visible::after,
953
945
  .chorus-tabs--segmented .chorus-chip[data-force-state="focused"]::after {
954
- box-shadow:
955
- inset 0 0 0 var(--chip-focus-outer-width) var(--chip-focus-outer-color),
956
- inset 0 0 0 calc(var(--chip-focus-outer-width) + var(--chip-focus-inset-width)) var(--chip-focus-inset-color);
946
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--chip-focus-outer-color);
957
947
  }
958
948
 
959
949
  /* ----- Rounded (chip-delegated) -----
@@ -998,7 +988,7 @@ span.chorus-chip {
998
988
  font-size: var(--sys-typo-label-sm-size);
999
989
  font-weight: var(--sys-typo-label-sm-weight);
1000
990
  line-height: var(--sys-typo-label-sm-line);
1001
- color: var(--sys-color-onSurface);
991
+ color: var(--sys-color-text-default);
1002
992
  text-decoration: none;
1003
993
  white-space: nowrap;
1004
994
  overflow: hidden;
@@ -1007,7 +997,7 @@ span.chorus-chip {
1007
997
  }
1008
998
  a.chorus-metadata__name:hover { text-decoration: underline; }
1009
999
  a.chorus-metadata__name:focus-visible {
1010
- outline: var(--sys-borderWidth-hairline) solid var(--sys-color-focus);
1000
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
1011
1001
  outline-offset: var(--sys-layout-inline-xs);
1012
1002
  border-radius: var(--sys-radius-xs);
1013
1003
  }
@@ -1017,7 +1007,7 @@ a.chorus-metadata__name:focus-visible {
1017
1007
  font-weight: var(--sys-typo-label-sm-weight);
1018
1008
  line-height: var(--sys-typo-label-sm-line);
1019
1009
  /* One tonal step further than name — timestamp recedes. */
1020
- color: var(--sys-color-outline);
1010
+ color: var(--sys-color-border-boldest);
1021
1011
  }
1022
1012
 
1023
1013
  /* Middot separator. The bullet glyph (U+00B7) is naturally tall — its
@@ -1029,7 +1019,7 @@ a.chorus-metadata__name:focus-visible {
1029
1019
  the line-box to that font-size so the dot's vertical extent never
1030
1020
  exceeds the text height. */
1031
1021
  .chorus-metadata__dot {
1032
- color: var(--sys-color-outline);
1022
+ color: var(--sys-color-border-boldest);
1033
1023
  font-size: var(--sys-typo-label-sm-size);
1034
1024
  line-height: 1;
1035
1025
  }
@@ -1044,15 +1034,15 @@ a.chorus-metadata__name:focus-visible {
1044
1034
  font-size: var(--sys-typo-label-sm-size);
1045
1035
  font-weight: var(--sys-typo-label-sm-weight);
1046
1036
  line-height: var(--sys-typo-label-sm-line);
1047
- color: var(--sys-color-primary);
1037
+ color: var(--sys-color-text-link);
1048
1038
  }
1049
1039
 
1050
1040
  .chorus-metadata__follow[aria-pressed="true"] {
1051
- color: var(--sys-color-onSurfaceVariant);
1041
+ color: var(--sys-color-text-subtle);
1052
1042
  }
1053
1043
 
1054
1044
  .chorus-metadata__follow:focus-visible {
1055
- outline: var(--sys-borderWidth-hairline) solid var(--sys-color-focus);
1045
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
1056
1046
  outline-offset: var(--sys-layout-inline-xs);
1057
1047
  border-radius: var(--sys-radius-xs);
1058
1048
  }
@@ -1061,7 +1051,7 @@ a.chorus-metadata__name:focus-visible {
1061
1051
  font-size: var(--sys-typo-label-sm-size);
1062
1052
  font-weight: var(--sys-typo-label-sm-weight);
1063
1053
  line-height: var(--sys-typo-label-sm-line);
1064
- color: var(--sys-color-onSurfaceVariant);
1054
+ color: var(--sys-color-text-subtle);
1065
1055
  white-space: nowrap;
1066
1056
  overflow: hidden;
1067
1057
  text-overflow: ellipsis;
@@ -1074,7 +1064,7 @@ a.chorus-metadata__name:focus-visible {
1074
1064
  font-size: var(--sys-typo-label-sm-size);
1075
1065
  font-weight: var(--sys-typo-label-sm-weight);
1076
1066
  line-height: var(--sys-typo-label-sm-line);
1077
- color: var(--sys-color-onSurfaceVariant);
1067
+ color: var(--sys-color-text-subtle);
1078
1068
  min-width: 0;
1079
1069
  }
1080
1070
 
@@ -1088,7 +1078,7 @@ a.chorus-metadata__name:focus-visible {
1088
1078
  }
1089
1079
  .chorus-metadata__meta-link:hover { text-decoration: underline; }
1090
1080
  .chorus-metadata__meta-link:focus-visible {
1091
- outline: var(--sys-borderWidth-hairline) solid var(--sys-color-focus);
1081
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
1092
1082
  outline-offset: var(--sys-layout-inline-xs);
1093
1083
  border-radius: var(--sys-radius-xs);
1094
1084
  }
@@ -1148,8 +1138,8 @@ a.chorus-metadata__name:focus-visible {
1148
1138
  flex-direction: column;
1149
1139
  gap: var(--sys-layout-stack-md);
1150
1140
  padding: var(--sys-layout-container-lg) var(--sys-layout-container-md);
1151
- background: var(--sys-color-surface);
1152
- color: var(--sys-color-onSurface);
1141
+ background: var(--sys-color-surface-default);
1142
+ color: var(--sys-color-text-default);
1153
1143
  width: 100%;
1154
1144
  /* Max-width is a layout-contract literal (matches the Feed family's
1155
1145
  "single column, mobile-first card" rule). Anatomy contract, not a
@@ -1157,9 +1147,9 @@ a.chorus-metadata__name:focus-visible {
1157
1147
  max-width: 480px;
1158
1148
  box-sizing: border-box;
1159
1149
  /* Hairline bottom divider — every Post / Ad card ends with a 1px
1160
- outlineVariant seam so consecutive cards in a stream read as one
1150
+ border.default seam so consecutive cards in a stream read as one
1161
1151
  rhythm. border-bottom is layout-safe under box-sizing: border-box. */
1162
- border-bottom: var(--sys-borderWidth-hairline) solid var(--sys-color-outlineVariant);
1152
+ border-bottom: var(--sys-borderWidth-hairline) solid var(--sys-color-border-default);
1163
1153
  }
1164
1154
 
1165
1155
  /* Clickable Post — whole-card navigation target (opt-in via `onClick`).
@@ -1172,7 +1162,7 @@ a.chorus-metadata__name:focus-visible {
1172
1162
  }
1173
1163
 
1174
1164
  .chorus-feed--clickable:focus-visible {
1175
- outline: var(--sys-borderWidth-hairline) solid var(--sys-color-focus);
1165
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
1176
1166
  outline-offset: calc(-1 * var(--sys-layout-inline-xs));
1177
1167
  }
1178
1168
 
@@ -1196,7 +1186,7 @@ a.chorus-metadata__name:focus-visible {
1196
1186
  font-weight: var(--sys-typo-label-sm-weight);
1197
1187
  line-height: var(--sys-typo-label-sm-line);
1198
1188
  letter-spacing: var(--sys-typo-label-sm-tracking);
1199
- color: var(--sys-color-brand);
1189
+ color: var(--sys-color-text-brand);
1200
1190
  text-transform: uppercase;
1201
1191
  }
1202
1192
 
@@ -1227,7 +1217,7 @@ a.chorus-metadata__name:focus-visible {
1227
1217
  font-weight: var(--sys-typo-heading-sm-weight);
1228
1218
  line-height: var(--sys-typo-heading-sm-line);
1229
1219
  letter-spacing: var(--sys-typo-heading-sm-tracking);
1230
- color: var(--sys-color-onSurface);
1220
+ color: var(--sys-color-text-default);
1231
1221
  white-space: nowrap;
1232
1222
  overflow: hidden;
1233
1223
  text-overflow: ellipsis;
@@ -1238,7 +1228,7 @@ a.chorus-metadata__name:focus-visible {
1238
1228
  font-size: var(--sys-typo-body-sm-size);
1239
1229
  font-weight: var(--sys-typo-body-sm-weight);
1240
1230
  line-height: var(--sys-typo-body-sm-line);
1241
- color: var(--sys-color-onSurfaceVariant);
1231
+ color: var(--sys-color-text-subtle);
1242
1232
  display: -webkit-box;
1243
1233
  -webkit-line-clamp: 2;
1244
1234
  -webkit-box-orient: vertical;
@@ -1254,7 +1244,7 @@ a.chorus-metadata__name:focus-visible {
1254
1244
  width: var(--ref-space-1000);
1255
1245
  height: var(--ref-space-1000);
1256
1246
  border-radius: var(--sys-radius-md);
1257
- background: var(--sys-color-surfaceContainerHigh);
1247
+ background: var(--sys-color-surface-sunken);
1258
1248
  position: relative;
1259
1249
  overflow: hidden;
1260
1250
  }
@@ -1262,7 +1252,6 @@ a.chorus-metadata__name:focus-visible {
1262
1252
  .chorus-feed__thumbnail img,
1263
1253
  .chorus-feed__thumbnail-fallback {
1264
1254
  width: 100%; height: 100%; display: block;
1265
- background: linear-gradient(135deg, var(--sys-color-placeholderImage-start) 0%, var(--sys-color-placeholderImage-end) 100%);
1266
1255
  object-fit: cover;
1267
1256
  }
1268
1257
 
@@ -1300,7 +1289,7 @@ a.chorus-metadata__name:focus-visible {
1300
1289
  /* Touch-target floor — same 48 rung used by List rows, kept as an
1301
1290
  intrinsic anatomy dimension (not a layout token). */
1302
1291
  min-height: var(--ref-space-600);
1303
- background: var(--sys-color-surfaceVariant);
1292
+ background: var(--sys-color-surface-sunken);
1304
1293
  border-radius: var(--sys-radius-md);
1305
1294
  font-size: var(--sys-typo-body-sm-size);
1306
1295
  line-height: var(--sys-typo-body-sm-line);
@@ -1311,25 +1300,25 @@ a.chorus-metadata__name:focus-visible {
1311
1300
  align-items: center;
1312
1301
  gap: var(--sys-layout-inline-sm);
1313
1302
  }
1314
- .chorus-feed__poll-glyph { color: var(--sys-color-brand); display: inline-flex; }
1315
- .chorus-feed__poll-label { color: var(--sys-color-brand); font-weight: var(--ref-fontWeight-bold); }
1303
+ .chorus-feed__poll-glyph { color: var(--sys-color-text-brand); display: inline-flex; }
1304
+ .chorus-feed__poll-label { color: var(--sys-color-text-brand); font-weight: var(--ref-fontWeight-bold); }
1316
1305
 
1317
1306
  /* Offer-evaluation tone — same chrome as the poll banner, but the
1318
- leading glyph and label paint in `sys.color.success` (resolves to
1307
+ leading glyph and label paint in `sys.color.text.success` (resolves to
1319
1308
  `ref.palette.green.500` in light, the same step in dark), so the
1320
1309
  editorial category reads as "compensation / decision support"
1321
1310
  rather than "community vote". The icon is `CompensationFillIcon`;
1322
1311
  the label is constrained to the literal "Offer" by the spec. */
1323
1312
  .chorus-feed__poll--offer .chorus-feed__poll-glyph,
1324
1313
  .chorus-feed__poll--offer .chorus-feed__poll-label {
1325
- color: var(--sys-color-success);
1314
+ color: var(--sys-color-text-success);
1326
1315
  }
1327
1316
  .chorus-feed__poll-divider {
1328
1317
  width: var(--sys-borderWidth-hairline);
1329
1318
  align-self: stretch;
1330
- background: var(--sys-color-outlineVariant);
1319
+ background: var(--sys-color-border-default);
1331
1320
  }
1332
- .chorus-feed__poll-participants { color: var(--sys-color-onSurface); }
1321
+ .chorus-feed__poll-participants { color: var(--sys-color-text-default); }
1333
1322
  .chorus-feed__poll-participants strong { font-weight: var(--ref-fontWeight-bold); }
1334
1323
 
1335
1324
  .chorus-feed__citation {
@@ -1342,7 +1331,7 @@ a.chorus-metadata__name:focus-visible {
1342
1331
  gap: 0;
1343
1332
  align-items: stretch;
1344
1333
  padding: 0;
1345
- background: var(--sys-color-surfaceContainer);
1334
+ background: var(--sys-color-surface-default);
1346
1335
  border-radius: var(--sys-radius-md);
1347
1336
  overflow: hidden;
1348
1337
  text-decoration: none;
@@ -1359,7 +1348,6 @@ a.chorus-metadata__name:focus-visible {
1359
1348
  flex: 0 0 120px;
1360
1349
  width: 120px;
1361
1350
  align-self: stretch;
1362
- background: linear-gradient(135deg, var(--sys-color-placeholderImage-start) 0%, var(--sys-color-placeholderImage-end) 100%);
1363
1351
  overflow: hidden;
1364
1352
  position: relative;
1365
1353
  }
@@ -1380,7 +1368,7 @@ a.chorus-metadata__name:focus-visible {
1380
1368
  padding: var(--sys-layout-container-sm);
1381
1369
  min-width: 0;
1382
1370
  flex: 1 1 auto;
1383
- background: var(--sys-color-surfaceVariant);
1371
+ background: var(--sys-color-surface-sunken);
1384
1372
  }
1385
1373
 
1386
1374
  /* All text inside the citation surface sits at the label.sm rung —
@@ -1394,7 +1382,7 @@ a.chorus-metadata__name:focus-visible {
1394
1382
  .chorus-feed__citation-title {
1395
1383
  font-weight: var(--sys-typo-label-sm-weight);
1396
1384
  line-height: var(--sys-typo-label-sm-line);
1397
- color: var(--sys-color-onSurface);
1385
+ color: var(--sys-color-text-default);
1398
1386
  display: -webkit-box;
1399
1387
  -webkit-line-clamp: 2;
1400
1388
  -webkit-box-orient: vertical;
@@ -1405,7 +1393,7 @@ a.chorus-metadata__name:focus-visible {
1405
1393
  display: inline-flex;
1406
1394
  align-items: center;
1407
1395
  gap: var(--sys-layout-inline-sm);
1408
- color: var(--sys-color-onSurfaceVariant);
1396
+ color: var(--sys-color-text-subtle);
1409
1397
  }
1410
1398
  /* Source mark is a 16×16 brand badge — `icon.sm` anatomy rung with
1411
1399
  `radius.sm` (4px) so it reads as a chip-adjacent badge, not a tag. */
@@ -1413,8 +1401,8 @@ a.chorus-metadata__name:focus-visible {
1413
1401
  width: var(--sys-icon-md); height: var(--sys-icon-md);
1414
1402
  flex: 0 0 var(--sys-icon-md);
1415
1403
  border-radius: var(--sys-radius-sm);
1416
- background: var(--sys-color-onSurface);
1417
- color: var(--sys-color-surface);
1404
+ background: var(--sys-color-icon-default);
1405
+ color: var(--sys-color-surface-default);
1418
1406
  display: inline-flex; align-items: center; justify-content: center;
1419
1407
  overflow: hidden;
1420
1408
  }
@@ -1424,7 +1412,7 @@ a.chorus-metadata__name:focus-visible {
1424
1412
  .chorus-feed__mention {
1425
1413
  font-style: italic;
1426
1414
  font-size: var(--sys-typo-body-sm-size);
1427
- color: var(--sys-color-primary);
1415
+ color: var(--sys-color-text-mention);
1428
1416
  text-decoration: none;
1429
1417
  }
1430
1418
 
@@ -1439,14 +1427,14 @@ a.chorus-metadata__name:focus-visible {
1439
1427
  display: flex;
1440
1428
  align-items: center;
1441
1429
  gap: var(--sys-layout-inline-lg);
1442
- color: var(--sys-color-onSurfaceVariant);
1430
+ color: var(--sys-color-text-subtle);
1443
1431
  }
1444
1432
 
1445
1433
  /* Active toggle — the brand-tone variant of the Like counter. We
1446
1434
  override `--button-text-label` directly rather than reaching for
1447
1435
  Text Button's `primary` appearance because Feed's active-like
1448
- colour is `sys.color.brand` (the same role the editorial `flag`
1449
- slot rides), not the interactive `sys.color.primary`. Selector
1436
+ colour is `sys.color.text.brand` (the same role the editorial `flag`
1437
+ slot rides), not the interactive `sys.color.background.primary`. Selector
1450
1438
  doubles the class (specificity 0,2,0) so it wins against the
1451
1439
  `.chorus-button--text--appearance-default` rule that declares
1452
1440
  `--button-text-label` later in the cascade. The Heart glyph re-
@@ -1454,7 +1442,7 @@ a.chorus-metadata__name:focus-visible {
1454
1442
  and the hover / pressed / focus overlays inherit from
1455
1443
  `--button-text-label` so the state feedback stays in lockstep. */
1456
1444
  .chorus-button--text.chorus-feed__like--active {
1457
- --button-text-label: var(--sys-color-brand);
1445
+ --button-text-label: var(--sys-color-text-brand);
1458
1446
  }
1459
1447
 
1460
1448
 
@@ -1478,7 +1466,7 @@ a.chorus-metadata__name:focus-visible {
1478
1466
  font-size: var(--sys-typo-label-sm-size);
1479
1467
  font-weight: var(--sys-typo-label-sm-weight);
1480
1468
  line-height: var(--sys-typo-label-sm-line);
1481
- color: var(--sys-color-onSurfaceVariant);
1469
+ color: var(--sys-color-text-subtle);
1482
1470
  }
1483
1471
  .chorus-feed__views-icon {
1484
1472
  display: inline-flex;
@@ -1496,8 +1484,8 @@ a.chorus-metadata__name:focus-visible {
1496
1484
  flex-direction: column;
1497
1485
  gap: var(--sys-layout-stack-md);
1498
1486
  padding: var(--sys-layout-container-lg) var(--sys-layout-container-md);
1499
- background: var(--sys-color-surface);
1500
- color: var(--sys-color-onSurface);
1487
+ background: var(--sys-color-surface-default);
1488
+ color: var(--sys-color-text-default);
1501
1489
  width: 100%;
1502
1490
  /* Same column cap as Feed — FeedAd rides in the same scrolling
1503
1491
  column, so the literal mirrors Feed's anatomy contract. */
@@ -1506,7 +1494,7 @@ a.chorus-metadata__name:focus-visible {
1506
1494
  box-sizing: border-box;
1507
1495
  /* Hairline bottom divider — mirrors the Feed Post seam so an Ad
1508
1496
  drops into a Post stream without breaking the inter-card rhythm. */
1509
- border-bottom: var(--sys-borderWidth-hairline) solid var(--sys-color-outlineVariant);
1497
+ border-bottom: var(--sys-borderWidth-hairline) solid var(--sys-color-border-default);
1510
1498
  }
1511
1499
 
1512
1500
  /* FeedAd brand row is now rendered via the shared Metadata component —
@@ -1528,7 +1516,7 @@ a.chorus-metadata__name:focus-visible {
1528
1516
  justify-content: center;
1529
1517
  width: var(--ref-space-300);
1530
1518
  height: var(--ref-space-300);
1531
- color: var(--sys-color-onSurfaceVariant);
1519
+ color: var(--sys-color-text-subtle);
1532
1520
  flex: 0 0 auto;
1533
1521
  }
1534
1522
  .chorus-feed-ad__dismiss svg {
@@ -1537,7 +1525,7 @@ a.chorus-metadata__name:focus-visible {
1537
1525
  display: block;
1538
1526
  }
1539
1527
  .chorus-feed-ad__dismiss:focus-visible {
1540
- outline: var(--sys-borderWidth-hairline) solid var(--sys-color-focus);
1528
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
1541
1529
  outline-offset: var(--sys-layout-inline-xs);
1542
1530
  border-radius: var(--sys-radius-xs);
1543
1531
  }
@@ -1555,7 +1543,7 @@ a.chorus-metadata__name:focus-visible {
1555
1543
  font-weight: var(--sys-typo-heading-sm-weight);
1556
1544
  line-height: var(--sys-typo-heading-sm-line);
1557
1545
  letter-spacing: var(--sys-typo-heading-sm-tracking);
1558
- color: var(--sys-color-onSurface);
1546
+ color: var(--sys-color-text-default);
1559
1547
  white-space: nowrap;
1560
1548
  overflow: hidden;
1561
1549
  text-overflow: ellipsis;
@@ -1566,7 +1554,7 @@ a.chorus-metadata__name:focus-visible {
1566
1554
  font-size: var(--sys-typo-body-sm-size);
1567
1555
  font-weight: var(--sys-typo-body-sm-weight);
1568
1556
  line-height: var(--sys-typo-body-sm-line);
1569
- color: var(--sys-color-onSurfaceVariant);
1557
+ color: var(--sys-color-text-subtle);
1570
1558
  display: -webkit-box;
1571
1559
  -webkit-line-clamp: 2;
1572
1560
  -webkit-box-orient: vertical;
@@ -1592,7 +1580,7 @@ a.chorus-metadata__name:focus-visible {
1592
1580
  .chorus-feed-ad__media {
1593
1581
  width: 100%;
1594
1582
  aspect-ratio: 16 / 10;
1595
- background-color: var(--sys-color-surfaceContainerHigh);
1583
+ background-color: var(--sys-color-surface-sunken);
1596
1584
  background-image: var(--chorus-placeholder-image);
1597
1585
  background-size: cover;
1598
1586
  background-position: center;
@@ -1624,7 +1612,7 @@ a.chorus-metadata__name:focus-visible {
1624
1612
  schema/components/carousel/carousel.md for the contract.
1625
1613
  ============================================================ */
1626
1614
  .chorus-carousel {
1627
- background: var(--sys-color-surface);
1615
+ background: var(--sys-color-surface-default);
1628
1616
  width: 100%;
1629
1617
  box-sizing: border-box;
1630
1618
  /* Full-bleed inline (matches DirectoryList): the host pays NO inline
@@ -1676,7 +1664,7 @@ a.chorus-metadata__name:focus-visible {
1676
1664
 
1677
1665
  .chorus-header .chorus-header__label {
1678
1666
  margin: 0;
1679
- color: var(--sys-color-onSurface);
1667
+ color: var(--sys-color-text-default);
1680
1668
  font-size: var(--sys-typo-heading-md-size);
1681
1669
  line-height: var(--sys-typo-heading-md-line);
1682
1670
  font-weight: var(--sys-typo-heading-md-weight);
@@ -1699,7 +1687,7 @@ a.chorus-metadata__name:focus-visible {
1699
1687
  later in this file. The IconButton is its own tap target; the
1700
1688
  surrounding `<header>` stays non-interactive. */
1701
1689
  .chorus-button--icon.chorus-header__icon {
1702
- --button-icon-glyph-color: var(--sys-color-onSurfaceVariant);
1690
+ --button-icon-glyph-color: var(--sys-color-text-subtle);
1703
1691
  }
1704
1692
 
1705
1693
  .chorus-header__icon--chevron svg {
@@ -1801,10 +1789,10 @@ a.chorus-metadata__name:focus-visible {
1801
1789
  gap: var(--sys-layout-stack-sm);
1802
1790
  padding: var(--sys-layout-container-md);
1803
1791
  border-radius: var(--sys-radius-md);
1804
- background: var(--sys-color-surface);
1792
+ background: var(--sys-color-surface-default);
1805
1793
  /* No-layout outline — an inset hairline ring rather than a border so
1806
1794
  the card's box geometry is stable across states. */
1807
- box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-outlineVariant);
1795
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-default);
1808
1796
  text-align: left;
1809
1797
  font: inherit;
1810
1798
  color: inherit;
@@ -1842,7 +1830,7 @@ a.chorus-metadata__name:focus-visible {
1842
1830
  font-size: var(--sys-typo-label-md-size);
1843
1831
  line-height: var(--sys-typo-label-md-line);
1844
1832
  font-weight: var(--sys-typo-label-md-weight);
1845
- color: var(--sys-color-onSurface);
1833
+ color: var(--sys-color-text-default);
1846
1834
  white-space: nowrap;
1847
1835
  overflow: hidden;
1848
1836
  text-overflow: ellipsis;
@@ -1853,7 +1841,7 @@ a.chorus-metadata__name:focus-visible {
1853
1841
  font-size: var(--sys-typo-body-sm-size);
1854
1842
  line-height: var(--sys-typo-body-sm-line);
1855
1843
  font-weight: var(--sys-typo-body-sm-weight);
1856
- color: var(--sys-color-onSurfaceVariant);
1844
+ color: var(--sys-color-text-subtle);
1857
1845
  display: -webkit-box;
1858
1846
  -webkit-line-clamp: 3;
1859
1847
  -webkit-box-orient: vertical;
@@ -1863,7 +1851,7 @@ a.chorus-metadata__name:focus-visible {
1863
1851
  .chorus-post-carousel__card-mention {
1864
1852
  font-size: var(--sys-typo-body-sm-size);
1865
1853
  line-height: var(--sys-typo-body-sm-line);
1866
- color: var(--sys-color-primary);
1854
+ color: var(--sys-color-text-mention);
1867
1855
  }
1868
1856
 
1869
1857
  .chorus-post-carousel__card-footer {
@@ -1877,7 +1865,7 @@ a.chorus-metadata__name:focus-visible {
1877
1865
  font-size: var(--sys-typo-label-sm-size);
1878
1866
  line-height: var(--sys-typo-label-sm-line);
1879
1867
  font-weight: var(--sys-typo-label-sm-weight);
1880
- color: var(--sys-color-onSurfaceVariant);
1868
+ color: var(--sys-color-text-subtle);
1881
1869
  }
1882
1870
 
1883
1871
  .chorus-post-carousel__card-views {
@@ -1886,7 +1874,7 @@ a.chorus-metadata__name:focus-visible {
1886
1874
  gap: var(--sys-layout-inline-sm);
1887
1875
  font-size: var(--sys-typo-label-sm-size);
1888
1876
  line-height: var(--sys-typo-label-sm-line);
1889
- color: var(--sys-color-onSurfaceVariant);
1877
+ color: var(--sys-color-text-subtle);
1890
1878
  }
1891
1879
 
1892
1880
  .chorus-post-carousel__card-views svg {
@@ -1949,7 +1937,7 @@ a.chorus-metadata__name:focus-visible {
1949
1937
  display: flex;
1950
1938
  flex-direction: column;
1951
1939
  align-items: center;
1952
- background: var(--sys-color-surface);
1940
+ background: var(--sys-color-surface-default);
1953
1941
  border-radius: var(--sys-radius-md);
1954
1942
  overflow: hidden;
1955
1943
  padding-bottom: var(--sys-layout-container-md);
@@ -1973,7 +1961,7 @@ a.chorus-metadata__name:focus-visible {
1973
1961
  border-radius: inherit;
1974
1962
  pointer-events: none;
1975
1963
  z-index: 2;
1976
- box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-outlineVariant);
1964
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-default);
1977
1965
  }
1978
1966
 
1979
1967
  .chorus-profile-carousel__card--clickable {
@@ -1988,7 +1976,7 @@ a.chorus-metadata__name:focus-visible {
1988
1976
  paints opaquely over the background. */
1989
1977
  width: 100%;
1990
1978
  height: 88px;
1991
- background-color: var(--sys-color-surfaceContainerHigh);
1979
+ background-color: var(--sys-color-surface-sunken);
1992
1980
  background-image: var(--chorus-placeholder-image);
1993
1981
  background-size: cover;
1994
1982
  background-position: center;
@@ -2012,7 +2000,7 @@ a.chorus-metadata__name:focus-visible {
2012
2000
  /* The Thumbnail's surface halo (a 2px ring) sits on the cover band's
2013
2001
  edge so the circular avatar reads as a separate plane from the
2014
2002
  cover. */
2015
- box-shadow: 0 0 0 2px var(--sys-color-surface);
2003
+ box-shadow: 0 0 0 2px var(--sys-color-surface-default);
2016
2004
  border-radius: var(--sys-radius-full);
2017
2005
  }
2018
2006
 
@@ -2031,7 +2019,7 @@ a.chorus-metadata__name:focus-visible {
2031
2019
  font-size: var(--sys-typo-label-md-size);
2032
2020
  line-height: var(--sys-typo-label-md-line);
2033
2021
  font-weight: var(--sys-typo-label-md-weight);
2034
- color: var(--sys-color-onSurface);
2022
+ color: var(--sys-color-text-default);
2035
2023
  max-width: 100%;
2036
2024
  white-space: nowrap;
2037
2025
  overflow: hidden;
@@ -2041,7 +2029,7 @@ a.chorus-metadata__name:focus-visible {
2041
2029
  .chorus-profile-carousel__followers {
2042
2030
  font-size: var(--sys-typo-label-sm-size);
2043
2031
  line-height: var(--sys-typo-label-sm-line);
2044
- color: var(--sys-color-onSurfaceVariant);
2032
+ color: var(--sys-color-text-subtle);
2045
2033
  }
2046
2034
 
2047
2035
  /* Slot below the identity stack. Either a row of icon-value metrics or a
@@ -2083,7 +2071,7 @@ a.chorus-metadata__name:focus-visible {
2083
2071
  margin: 0;
2084
2072
  font-size: var(--sys-typo-label-sm-size);
2085
2073
  line-height: var(--sys-typo-label-sm-line);
2086
- color: var(--sys-color-onSurfaceVariant);
2074
+ color: var(--sys-color-text-subtle);
2087
2075
  text-align: center;
2088
2076
  display: -webkit-box;
2089
2077
  -webkit-line-clamp: 2;
@@ -2098,7 +2086,7 @@ a.chorus-metadata__name:focus-visible {
2098
2086
  gap: var(--sys-layout-inline-sm);
2099
2087
  font-size: var(--sys-typo-label-sm-size);
2100
2088
  line-height: var(--sys-typo-label-sm-line);
2101
- color: var(--sys-color-onSurface);
2089
+ color: var(--sys-color-text-default);
2102
2090
  }
2103
2091
 
2104
2092
  .chorus-profile-carousel__metric-icon {
@@ -2145,7 +2133,7 @@ a.chorus-metadata__name:focus-visible {
2145
2133
  .chorus-profile-header {
2146
2134
  display: flex;
2147
2135
  flex-direction: column;
2148
- background: var(--sys-color-surface);
2136
+ background: var(--sys-color-surface-default);
2149
2137
  width: 100%;
2150
2138
  }
2151
2139
 
@@ -2164,7 +2152,7 @@ a.chorus-metadata__name:focus-visible {
2164
2152
  widens / narrows, so the cover keeps the same visual mass relative
2165
2153
  to the column instead of locking to a hard pixel height. */
2166
2154
  aspect-ratio: 375 / 120;
2167
- background-color: var(--sys-color-surfaceContainerHigh);
2155
+ background-color: var(--sys-color-surface-sunken);
2168
2156
  background-image: var(--chorus-placeholder-image);
2169
2157
  background-size: cover;
2170
2158
  background-position: center;
@@ -2295,7 +2283,7 @@ a.chorus-metadata__name:focus-visible {
2295
2283
  line-height: var(--sys-typo-heading-lg-line);
2296
2284
  font-weight: var(--sys-typo-heading-lg-weight);
2297
2285
  letter-spacing: var(--sys-typo-heading-lg-tracking);
2298
- color: var(--sys-color-onSurface);
2286
+ color: var(--sys-color-text-default);
2299
2287
  white-space: nowrap;
2300
2288
  overflow: hidden;
2301
2289
  text-overflow: ellipsis;
@@ -2309,17 +2297,17 @@ a.chorus-metadata__name:focus-visible {
2309
2297
  gap: var(--sys-layout-inline-sm);
2310
2298
  font-size: var(--sys-typo-body-sm-size);
2311
2299
  line-height: var(--sys-typo-body-sm-line);
2312
- color: var(--sys-color-onSurfaceVariant);
2300
+ color: var(--sys-color-text-subtle);
2313
2301
  min-width: 0;
2314
2302
  }
2315
2303
 
2316
2304
  .chorus-profile-header__meta-icon {
2317
2305
  flex: 0 0 auto;
2318
- color: var(--sys-color-onSurfaceVariant);
2306
+ color: var(--sys-color-text-subtle);
2319
2307
  }
2320
2308
 
2321
2309
  .chorus-profile-header__meta-sep {
2322
- color: var(--sys-color-onSurfaceVariant);
2310
+ color: var(--sys-color-text-subtle);
2323
2311
  }
2324
2312
 
2325
2313
  .chorus-profile-header__meta-visibility,
@@ -2357,7 +2345,7 @@ a.chorus-metadata__name:focus-visible {
2357
2345
  Canonical hosts: ProfileHeader's avatar (the 56-rung that half-
2358
2346
  overlaps the cover) and any avatar Thumbnail that lives over imagery. */
2359
2347
  .chorus-thumbnail--outlined {
2360
- box-shadow: 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-surface);
2348
+ box-shadow: 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-surface-default);
2361
2349
  }
2362
2350
 
2363
2351
  /* Same image-area fallback contract as `.chorus-feed-ad__media` — the
@@ -2369,7 +2357,7 @@ a.chorus-metadata__name:focus-visible {
2369
2357
  width: 100%;
2370
2358
  height: 100%;
2371
2359
  border-radius: var(--sys-radius-full);
2372
- background-color: var(--sys-color-surfaceContainerHigh);
2360
+ background-color: var(--sys-color-surface-sunken);
2373
2361
  background-image: var(--chorus-placeholder-image);
2374
2362
  background-size: cover;
2375
2363
  background-position: center;
@@ -2402,11 +2390,11 @@ a.chorus-metadata__name:focus-visible {
2402
2390
  width: var(--sys-icon-md);
2403
2391
  height: var(--sys-icon-md);
2404
2392
  border-radius: var(--sys-radius-full);
2405
- background: var(--sys-color-surface);
2393
+ background: var(--sys-color-surface-default);
2406
2394
  /* Hairline halo via box-shadow so the badge does not enlarge the
2407
2395
  bounding box — the halo paints over the host image's edge without
2408
2396
  shifting the badge's `icon.sm` footprint. */
2409
- box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-surface);
2397
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-surface-default);
2410
2398
  overflow: hidden;
2411
2399
  display: inline-flex;
2412
2400
  align-items: center;
@@ -2422,12 +2410,12 @@ a.chorus-metadata__name:focus-visible {
2422
2410
  }
2423
2411
 
2424
2412
  .chorus-thumbnail__badge:empty {
2425
- background: var(--sys-color-surfaceContainerHigh);
2413
+ background: var(--sys-color-surface-sunken);
2426
2414
  }
2427
2415
 
2428
2416
  /* List — vertical row stack. The row is the interactive surface;
2429
2417
  leading and trailing slots are decorative. Inter-row divider is a
2430
- hairline `outlineVariant`, not a layout gap — the contract is
2418
+ hairline `border.default`, not a layout gap — the contract is
2431
2419
  "flush rows separated by a rule", not "rows with breathing room". */
2432
2420
  .chorus-list {
2433
2421
  display: flex;
@@ -2456,7 +2444,7 @@ a.chorus-metadata__name:focus-visible {
2456
2444
  min-height: var(--ref-space-600);
2457
2445
  box-sizing: border-box;
2458
2446
  cursor: pointer;
2459
- color: var(--sys-color-onSurface);
2447
+ color: var(--sys-color-text-default);
2460
2448
  position: relative;
2461
2449
  isolation: isolate;
2462
2450
  }
@@ -2475,7 +2463,7 @@ a.chorus-metadata__name:focus-visible {
2475
2463
  right: var(--sys-layout-container-md);
2476
2464
  bottom: 0;
2477
2465
  height: var(--sys-borderWidth-hairline);
2478
- background: var(--sys-color-outlineVariant);
2466
+ background: var(--sys-color-border-default);
2479
2467
  pointer-events: none;
2480
2468
  }
2481
2469
 
@@ -2489,11 +2477,11 @@ a.chorus-metadata__name:focus-visible {
2489
2477
  nav chevron carries no `data-nested-action`, so hovering it still lights
2490
2478
  the row (it IS the row's drill-in affordance). */
2491
2479
  .chorus-list__row:hover:not(:has([data-nested-action]:hover)) {
2492
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-hover) * 100%), transparent);
2480
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-hover) * 100%), transparent);
2493
2481
  }
2494
2482
 
2495
2483
  .chorus-list__row:active:not(:has([data-nested-action]:active)) {
2496
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-pressed) * 100%), transparent);
2484
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-pressed) * 100%), transparent);
2497
2485
  }
2498
2486
 
2499
2487
  /* Focus indicator — inward composition per DESIGN.md → Focus ring
@@ -2514,9 +2502,7 @@ a.chorus-metadata__name:focus-visible {
2514
2502
 
2515
2503
  .chorus-list__row:focus-visible::before,
2516
2504
  .chorus-list__row[data-force-state="focused"]::before {
2517
- box-shadow:
2518
- inset 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-focus),
2519
- inset 0 0 0 calc(var(--sys-borderWidth-thin) + var(--sys-borderWidth-hairline)) var(--sys-color-focusInset);
2505
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-focused);
2520
2506
  }
2521
2507
 
2522
2508
  .chorus-list__row:focus-visible {
@@ -2527,13 +2513,21 @@ a.chorus-metadata__name:focus-visible {
2527
2513
  cursor: not-allowed;
2528
2514
  }
2529
2515
 
2530
- /* Disabled dims the row *content* only applied to the row's direct
2531
- children so the inter-row divider (`::after`) and focus overlay
2532
- (`::before`) keep full opacity. Fading the whole row box would dim the
2533
- hairline divider too, which reads as an awkward gap in the otherwise
2534
- crisp rule between rows. */
2535
- .chorus-list__row.is-disabled > * {
2536
- opacity: var(--sys-state-disabled);
2516
+ /* Disabled re-tones the row *content* to the neutral disabled tokens
2517
+ text `text.disabled`, icon glyph `icon.disabled` instead of an
2518
+ opacity dim, so the inter-row divider (`::after`) and focus overlay
2519
+ (`::before`) keep full strength. Scoping the colors to the content
2520
+ leaves the hairline rule crisp, the same reason the old opacity was
2521
+ applied to the row's children rather than the whole box. */
2522
+ .chorus-list__row.is-disabled .chorus-list__label,
2523
+ .chorus-list__row.is-disabled .chorus-list__supporting,
2524
+ .chorus-list__row.is-disabled .chorus-list__trailing {
2525
+ color: var(--sys-color-text-disabled);
2526
+ }
2527
+
2528
+ .chorus-list__row.is-disabled .chorus-list__leading--icon,
2529
+ .chorus-list__row.is-disabled .chorus-list__radio {
2530
+ color: var(--sys-color-icon-disabled);
2537
2531
  }
2538
2532
 
2539
2533
  .chorus-list__leading {
@@ -2577,7 +2571,7 @@ a.chorus-metadata__name:focus-visible {
2577
2571
  .chorus-list__label {
2578
2572
  font-size: var(--sys-typo-body-md-size);
2579
2573
  line-height: var(--sys-typo-body-md-line);
2580
- color: var(--sys-color-onSurface);
2574
+ color: var(--sys-color-text-default);
2581
2575
  overflow: hidden;
2582
2576
  text-overflow: ellipsis;
2583
2577
  white-space: nowrap;
@@ -2599,7 +2593,7 @@ a.chorus-metadata__name:focus-visible {
2599
2593
  .chorus-list__supporting {
2600
2594
  font-size: var(--sys-typo-body-sm-size);
2601
2595
  line-height: var(--sys-typo-body-sm-line);
2602
- color: var(--sys-color-onSurfaceVariant);
2596
+ color: var(--sys-color-text-subtle);
2603
2597
  overflow: hidden;
2604
2598
  text-overflow: ellipsis;
2605
2599
  white-space: nowrap;
@@ -2609,12 +2603,37 @@ a.chorus-metadata__name:focus-visible {
2609
2603
  display: inline-flex;
2610
2604
  align-items: center;
2611
2605
  justify-content: center;
2612
- color: var(--sys-color-onSurfaceVariant);
2606
+ color: var(--sys-color-text-subtle);
2613
2607
  flex: 0 0 auto;
2614
2608
  /* Text group ↔ trailing action: fixed `inline.md` (8) in every variant. */
2615
2609
  margin-left: var(--sys-layout-inline-md);
2616
2610
  }
2617
2611
 
2612
+ /* Embedded-Banner row — a Standard row whose text group stacks over a
2613
+ Banner that spans the row's full content width. The row flips from a
2614
+ single horizontal line to a vertical stack: the normal leading + label
2615
+ + trailing line (`__row-main`) sits on top, the Banner `stack.xs` (8)
2616
+ below it. The stack fills the row's content box so the Banner aligns to
2617
+ the same 16px inline inset as the text group above it. The Banner owns
2618
+ its own tinted fill / radius / padding; the slot only spaces it and
2619
+ marks it a nested-action region (its controls never commit the row). */
2620
+ .chorus-list__stack {
2621
+ display: flex;
2622
+ flex-direction: column;
2623
+ gap: var(--sys-layout-stack-xs);
2624
+ flex: 1 1 auto;
2625
+ min-width: 0;
2626
+ }
2627
+
2628
+ .chorus-list__row-main {
2629
+ display: flex;
2630
+ align-items: center;
2631
+ }
2632
+
2633
+ .chorus-list__banner {
2634
+ display: block;
2635
+ }
2636
+
2618
2637
  /* Entry variant — directory-entry row with selectable leading Thumbnail
2619
2638
  (32 / 40 / 48 / 56 via `data-size="small|medium|large|xlarge"`), an
2620
2639
  identity group (label + optional inline count Badge + optional stacked
@@ -2649,7 +2668,7 @@ a.chorus-metadata__name:focus-visible {
2649
2668
  carries the meaning; the slot enforces the 24 rung regardless of the glyph's
2650
2669
  own size attribute. */
2651
2670
  .chorus-list__leading--icon {
2652
- color: var(--sys-color-onSurfaceVariant);
2671
+ color: var(--sys-color-text-subtle);
2653
2672
  }
2654
2673
 
2655
2674
  .chorus-list__leading--icon svg {
@@ -2719,7 +2738,7 @@ a.chorus-metadata__name:focus-visible {
2719
2738
  min-width: 0;
2720
2739
  }
2721
2740
 
2722
- /* Inline verified mark — paints in `sys.color.primary` (resolves to
2741
+ /* Inline verified mark — paints in `sys.color.background.primary` (resolves to
2723
2742
  `ref.palette.blue.500`). Sits to the LEFT of the label so the trust
2724
2743
  signal reads first. Centred against the label (the primary row is
2725
2744
  baseline-aligned for the label + count pairing). */
@@ -2728,7 +2747,7 @@ a.chorus-metadata__name:focus-visible {
2728
2747
  align-self: center;
2729
2748
  width: var(--sys-icon-md);
2730
2749
  height: var(--sys-icon-md);
2731
- color: var(--sys-color-primary);
2750
+ color: var(--sys-color-icon-accent-blue-default);
2732
2751
  flex: 0 0 auto;
2733
2752
  }
2734
2753
 
@@ -2741,7 +2760,7 @@ a.chorus-metadata__name:focus-visible {
2741
2760
  font-size: var(--sys-typo-label-md-size);
2742
2761
  line-height: var(--sys-typo-label-md-line);
2743
2762
  font-weight: var(--sys-typo-label-md-weight);
2744
- color: var(--sys-color-onSurface);
2763
+ color: var(--sys-color-text-default);
2745
2764
  overflow: hidden;
2746
2765
  text-overflow: ellipsis;
2747
2766
  white-space: nowrap;
@@ -2758,7 +2777,7 @@ a.chorus-metadata__name:focus-visible {
2758
2777
  .chorus-entry-row__secondary {
2759
2778
  font-size: var(--sys-typo-label-sm-size);
2760
2779
  line-height: var(--sys-typo-label-sm-line);
2761
- color: var(--sys-color-onSurface);
2780
+ color: var(--sys-color-text-default);
2762
2781
  overflow: hidden;
2763
2782
  text-overflow: ellipsis;
2764
2783
  white-space: nowrap;
@@ -2767,7 +2786,7 @@ a.chorus-metadata__name:focus-visible {
2767
2786
  .chorus-entry-row__description {
2768
2787
  font-size: var(--sys-typo-label-sm-size);
2769
2788
  line-height: var(--sys-typo-label-sm-line);
2770
- color: var(--sys-color-onSurfaceVariant);
2789
+ color: var(--sys-color-text-subtle);
2771
2790
  /* Identity-group ↔ description separator: 2px (ref.space.25). The
2772
2791
  description reads as a tight supporting layer below the identity
2773
2792
  block rather than a co-equal line. */
@@ -2784,7 +2803,7 @@ a.chorus-metadata__name:focus-visible {
2784
2803
  display: inline-flex;
2785
2804
  align-items: center;
2786
2805
  justify-content: center;
2787
- color: var(--sys-color-onSurfaceVariant);
2806
+ color: var(--sys-color-text-subtle);
2788
2807
  flex: 0 0 auto;
2789
2808
  margin-left: var(--sys-layout-inline-md);
2790
2809
  }
@@ -2825,7 +2844,7 @@ a.chorus-metadata__name:focus-visible {
2825
2844
  modifier when the card needs its own opaque tier (sitting on a
2826
2845
  transparent host or between bare-surface sections). */
2827
2846
  background: transparent;
2828
- color: var(--sys-color-onSurface);
2847
+ color: var(--sys-color-text-default);
2829
2848
  border: 0;
2830
2849
  border-radius: var(--sys-radius-md);
2831
2850
  text-align: left;
@@ -2833,7 +2852,7 @@ a.chorus-metadata__name:focus-visible {
2833
2852
  cursor: pointer;
2834
2853
  position: relative;
2835
2854
  isolation: isolate;
2836
- box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-outlineVariant);
2855
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-default);
2837
2856
  transition: background 120ms ease;
2838
2857
  }
2839
2858
 
@@ -2854,12 +2873,12 @@ a.chorus-metadata__name:focus-visible {
2854
2873
  /* Default hover/pressed — overlay mixes on a transparent base, so the
2855
2874
  host surface tone keeps reading through underneath the state paint. */
2856
2875
  .chorus-nav-card:hover {
2857
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-hover) * 100%), transparent);
2876
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-hover) * 100%), transparent);
2858
2877
  }
2859
2878
 
2860
2879
  .chorus-nav-card:active,
2861
2880
  .chorus-nav-card[data-force-state="pressed"] {
2862
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-pressed) * 100%), transparent);
2881
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-pressed) * 100%), transparent);
2863
2882
  }
2864
2883
 
2865
2884
  /* Surface appearance — paints the card with its own `surface` fill.
@@ -2869,16 +2888,16 @@ a.chorus-metadata__name:focus-visible {
2869
2888
  hairline outline + chevron + hover overlay all stay; only the
2870
2889
  container fill changes. */
2871
2890
  .chorus-nav-card--surface {
2872
- background: var(--sys-color-surface);
2891
+ background: var(--sys-color-surface-default);
2873
2892
  }
2874
2893
 
2875
2894
  .chorus-nav-card--surface:hover {
2876
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-hover) * 100%), var(--sys-color-surface));
2895
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-hover) * 100%), var(--sys-color-surface-default));
2877
2896
  }
2878
2897
 
2879
2898
  .chorus-nav-card--surface:active,
2880
2899
  .chorus-nav-card--surface[data-force-state="pressed"] {
2881
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-pressed) * 100%), var(--sys-color-surface));
2900
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-pressed) * 100%), var(--sys-color-surface-default));
2882
2901
  }
2883
2902
 
2884
2903
  /* Outward focus ring — paints OUTSIDE the card's outline so it never
@@ -2901,14 +2920,15 @@ a.chorus-metadata__name:focus-visible {
2901
2920
 
2902
2921
  .chorus-nav-card:focus-visible::after,
2903
2922
  .chorus-nav-card[data-force-state="focused"]::after {
2904
- box-shadow:
2905
- 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-focus),
2906
- 0 0 0 calc(var(--sys-borderWidth-thin) + var(--sys-borderWidth-hairline)) var(--sys-color-focusInset);
2923
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-focused);
2907
2924
  }
2908
2925
 
2909
2926
  .chorus-nav-card[data-disabled="true"],
2910
2927
  .chorus-nav-card:disabled {
2911
- opacity: var(--sys-state-disabled);
2928
+ /* Explicit disabled (no opacity): content re-tones to text.disabled via
2929
+ the card's inherited color (label / supporting / leading glyph all
2930
+ ride it). */
2931
+ color: var(--sys-color-text-disabled);
2912
2932
  cursor: not-allowed;
2913
2933
  }
2914
2934
 
@@ -2934,7 +2954,7 @@ a.chorus-metadata__name:focus-visible {
2934
2954
  font-size: var(--sys-typo-body-sm-size);
2935
2955
  line-height: var(--sys-typo-body-sm-line);
2936
2956
  font-weight: var(--sys-typo-body-sm-weight);
2937
- color: var(--sys-color-onSurface);
2957
+ color: var(--sys-color-text-default);
2938
2958
  overflow: hidden;
2939
2959
  text-overflow: ellipsis;
2940
2960
  white-space: nowrap;
@@ -2943,7 +2963,7 @@ a.chorus-metadata__name:focus-visible {
2943
2963
  .chorus-nav-card__supporting {
2944
2964
  font-size: var(--sys-typo-label-sm-size);
2945
2965
  line-height: var(--sys-typo-label-sm-line);
2946
- color: var(--sys-color-onSurfaceVariant);
2966
+ color: var(--sys-color-text-subtle);
2947
2967
  overflow: hidden;
2948
2968
  text-overflow: ellipsis;
2949
2969
  white-space: nowrap;
@@ -2953,7 +2973,7 @@ a.chorus-metadata__name:focus-visible {
2953
2973
  display: inline-flex;
2954
2974
  align-items: center;
2955
2975
  justify-content: center;
2956
- color: var(--sys-color-onSurfaceVariant);
2976
+ color: var(--sys-color-text-subtle);
2957
2977
  flex: 0 0 auto;
2958
2978
  }
2959
2979
 
@@ -2976,7 +2996,7 @@ a.chorus-metadata__name:focus-visible {
2976
2996
  display: inline-flex;
2977
2997
  align-items: center;
2978
2998
  justify-content: center;
2979
- color: var(--sys-color-onSurface);
2999
+ color: var(--sys-color-icon-default);
2980
3000
  transition: color 120ms ease;
2981
3001
  }
2982
3002
 
@@ -2993,7 +3013,7 @@ a.chorus-metadata__name:focus-visible {
2993
3013
  anchored to the rail's right edge regardless of how far the user
2994
3014
  scrolls the avatars. */
2995
3015
  .chorus-avatar-rail {
2996
- background: var(--sys-color-surface);
3016
+ background: var(--sys-color-surface-default);
2997
3017
  width: 100%;
2998
3018
  box-sizing: border-box;
2999
3019
  padding: var(--sys-layout-container-sm) var(--sys-layout-container-md);
@@ -3068,7 +3088,7 @@ a.chorus-metadata__name:focus-visible {
3068
3088
  }
3069
3089
 
3070
3090
  .chorus-avatar-rail__item:focus-visible {
3071
- outline: var(--sys-borderWidth-hairline) solid var(--sys-color-focus);
3091
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
3072
3092
  outline-offset: var(--sys-layout-inline-xs);
3073
3093
  }
3074
3094
 
@@ -3086,7 +3106,7 @@ a.chorus-metadata__name:focus-visible {
3086
3106
  width: calc(48px + 2 * var(--sys-layout-inline-sm));
3087
3107
  font-size: var(--sys-typo-label-sm-size);
3088
3108
  line-height: var(--sys-typo-label-sm-line);
3089
- color: var(--sys-color-onSurface);
3109
+ color: var(--sys-color-text-default);
3090
3110
  text-align: center;
3091
3111
  overflow: hidden;
3092
3112
  text-overflow: ellipsis;
@@ -3119,7 +3139,7 @@ a.chorus-metadata__name:focus-visible {
3119
3139
  label), toggle at one inline.xl (16) before the next page's leading avatar,
3120
3140
  and that next avatar peeks 8 (inline.md) past the surface's right edge. */
3121
3141
  .chorus-suggestion-list {
3122
- background: var(--sys-color-surface);
3142
+ background: var(--sys-color-surface-default);
3123
3143
  width: 100%;
3124
3144
  box-sizing: border-box;
3125
3145
  padding-block: var(--sys-layout-container-lg);
@@ -3257,7 +3277,7 @@ a.chorus-metadata__name:focus-visible {
3257
3277
  ============================================================ */
3258
3278
  .chorus-directory-list,
3259
3279
  .chorus-nav-list {
3260
- background: var(--sys-color-surface);
3280
+ background: var(--sys-color-surface-default);
3261
3281
  width: 100%;
3262
3282
  box-sizing: border-box;
3263
3283
  /* Full-bleed column — the host pays NO inline padding. Its Header and
@@ -3278,6 +3298,65 @@ a.chorus-metadata__name:focus-visible {
3278
3298
  rule already excludes `[data-divider="false"]`, so no extra CSS
3279
3299
  is needed to hide it here. */
3280
3300
 
3301
+ /* ============================================================
3302
+ EmptyState — centered no-data composition. Painted inside the
3303
+ surface that would otherwise hold the data: an optional monochrome
3304
+ illustration, a required headline, optional body copy, and an
3305
+ optional primary-Button CTA. Ships no surface fill of its own —
3306
+ the host supplies the surface tier and the bounding box; EmptyState
3307
+ only centers its column inside it. Inter-slot rhythm follows the
3308
+ stack tokens (illustration→headline 12, headline→body 4, body→CTA
3309
+ 16). Distinct from Skeleton (an in-flight loading placeholder).
3310
+ ============================================================ */
3311
+ .chorus-empty-state {
3312
+ display: flex;
3313
+ flex-direction: column;
3314
+ align-items: center;
3315
+ text-align: center;
3316
+ }
3317
+
3318
+ /* Optional illustration — a glyph / illustration sized to a 48-box
3319
+ (larger than `sys.icon.lg`, realizing the 'icon.xl or larger' intent
3320
+ since no `sys.icon.xl` rung exists), painted monochrome in
3321
+ `onSurfaceVariant` via `currentColor` so it reads as quiet chrome,
3322
+ not a brand moment. 12 below it to the headline. */
3323
+ .chorus-empty-state__illustration {
3324
+ display: inline-flex;
3325
+ align-items: center;
3326
+ justify-content: center;
3327
+ width: var(--empty-state-illustration-size);
3328
+ height: var(--empty-state-illustration-size);
3329
+ margin-bottom: var(--empty-state-illustration-gap);
3330
+ color: var(--empty-state-illustration-color);
3331
+ }
3332
+
3333
+ .chorus-empty-state__illustration img,
3334
+ .chorus-empty-state__illustration svg {
3335
+ width: var(--empty-state-illustration-size);
3336
+ height: var(--empty-state-illustration-size);
3337
+ display: block;
3338
+ color: currentColor;
3339
+ }
3340
+
3341
+ /* Required headline — heading.sm in `onSurface`. Typography vars are
3342
+ emitted inline by the React file (typoStyles). */
3343
+ .chorus-empty-state__headline {
3344
+ margin: 0;
3345
+ color: var(--empty-state-headline-color);
3346
+ }
3347
+
3348
+ /* Optional body — body.sm in `onSurfaceVariant`, 4 below the headline. */
3349
+ .chorus-empty-state__body {
3350
+ margin: 0;
3351
+ margin-top: var(--empty-state-body-gap);
3352
+ color: var(--empty-state-body-color);
3353
+ }
3354
+
3355
+ /* Optional CTA — a default-size primary Button, 16 below the body. */
3356
+ .chorus-empty-state__action {
3357
+ margin-top: var(--empty-state-action-gap);
3358
+ }
3359
+
3281
3360
  /* ============================================================
3282
3361
  Banner — in-body explanation block (info / neutral)
3283
3362
  ============================================================ */
@@ -3290,9 +3369,9 @@ a.chorus-metadata__name:focus-visible {
3290
3369
  }
3291
3370
 
3292
3371
  .chorus-banner--accent {
3293
- background: var(--sys-color-primaryContainer);
3294
- color: var(--sys-color-onPrimaryContainer);
3295
- --banner-outline-color: color-mix(in srgb, var(--sys-color-primary) 40%, transparent);
3372
+ background: var(--sys-color-background-selected);
3373
+ color: var(--sys-color-text-link);
3374
+ --banner-outline-color: color-mix(in srgb, var(--sys-color-border-primary) 40%, transparent);
3296
3375
  }
3297
3376
 
3298
3377
  /* Destructive — error-tinted banner. Reach for it when the aside is a
@@ -3301,30 +3380,26 @@ a.chorus-metadata__name:focus-visible {
3301
3380
  shadcn `<Alert variant="destructive">` shape for Lovable-generated
3302
3381
  screens. */
3303
3382
  .chorus-banner--destructive {
3304
- background: var(--sys-color-errorContainer);
3305
- color: var(--sys-color-onErrorContainer);
3306
- --banner-outline-color: color-mix(in srgb, var(--sys-color-error) 40%, transparent);
3307
- }
3308
-
3309
- /* Default uses `sys.color.scrimSubtle` (~8% inverse-tone overlay —
3310
- black in light, white in dark) rather than a tonal container role,
3311
- so the banner stays harmonious on any underlying surface body,
3312
- raised card, BottomSheet, Dialog by tinting one step darker
3313
- (light mode) or lighter (dark mode) instead of pinning to a fixed
3314
- neutral step that can collide with the surface ladder. Same scrim
3315
- used by Chip / Tag default, Progress track, StatusTag neutral, and
3316
- Skeleton. */
3383
+ background: var(--sys-color-background-danger);
3384
+ color: var(--sys-color-text-danger);
3385
+ --banner-outline-color: color-mix(in srgb, var(--sys-color-border-danger) 40%, transparent);
3386
+ }
3387
+
3388
+ /* Default uses the solid `background.neutral` fill (the role that
3389
+ replaced the old ~8% scrim) a fixed light-gray step in light, a
3390
+ mid-gray in dark. Same neutral fill as Chip / Tag default, Progress
3391
+ track, StatusTag neutral, and Skeleton, so they read as one family. */
3317
3392
  .chorus-banner--default {
3318
- background: var(--sys-color-scrimSubtle);
3319
- color: var(--sys-color-onSurface);
3320
- --banner-outline-color: var(--sys-color-outlineVariant);
3393
+ background: var(--sys-color-background-neutral);
3394
+ color: var(--sys-color-text-default);
3395
+ --banner-outline-color: var(--sys-color-border-default);
3321
3396
  }
3322
3397
 
3323
3398
  /* Optional outline — a hairline inset stroke toned to the appearance's
3324
3399
  color family (each appearance block above sets
3325
3400
  `--banner-outline-color`), kept deliberately faint so the edge reads
3326
3401
  as a soft boundary of the same tint, not a frame: the subtle gray
3327
- hairline (`sys.color.outlineVariant`) on default's gray-tinted
3402
+ hairline (`sys.color.border.default`) on default's gray-tinted
3328
3403
  scrim; `primary` / `error` at 40% over transparent (the Skeleton
3329
3404
  fill recipe) on accent / destructive. Painted as an inset
3330
3405
  box-shadow, never a `border`, so toggling it can't change the
@@ -3414,7 +3489,22 @@ a.chorus-metadata__name:focus-visible {
3414
3489
  }
3415
3490
 
3416
3491
  .chorus-banner--default .chorus-banner__action {
3417
- color: var(--sys-color-primary);
3492
+ color: var(--sys-color-text-link);
3493
+ }
3494
+
3495
+ /* neutral-body — keeps the `accent` fill but lays the Default
3496
+ appearance's neutral foreground over it: title + body re-tone to
3497
+ `onSurface` (quiet, high-legibility body copy) while the action
3498
+ steps to `primary`, exactly as on `default`. The accent tint still
3499
+ pulls the eye; the text just stops shouting in the primary family.
3500
+ Only meaningful combined with `--accent` (default is already
3501
+ `onSurface`; destructive must carry the warning tone through copy). */
3502
+ .chorus-banner--accent.chorus-banner--neutral-body {
3503
+ color: var(--sys-color-text-default);
3504
+ }
3505
+
3506
+ .chorus-banner--accent.chorus-banner--neutral-body .chorus-banner__action {
3507
+ color: var(--sys-color-text-link);
3418
3508
  }
3419
3509
 
3420
3510
  /* Trailing icon slot — a 16 × 16 glyph (`sys.icon.md`) at the trailing
@@ -3439,19 +3529,34 @@ a.chorus-metadata__name:focus-visible {
3439
3529
  color: currentColor;
3440
3530
  }
3441
3531
 
3532
+ /* Trailing action slot — hosts an inline Text Button (`<Button
3533
+ variant="text">`) at the trailing edge, vertically centered against
3534
+ the whole block (`align-self: center` overrides the container's
3535
+ flex-start) and footprint-preserving (`flex: 0 0 auto`). The Button
3536
+ owns its own size + appearance per the button/text spec; by default
3537
+ pick the appearance whose color family matches the banner fill
3538
+ (accent → accent, default → default, destructive → destructive
3539
+ flavor) so the commit reads as part of the tinted block. Unlike the
3540
+ trailing icon it is a real interactive control, so it is not
3541
+ aria-hidden. The Text Button's optical-alignment margin lets its
3542
+ visible label sit flush against the container's trailing padding. */
3543
+ .chorus-banner__trailing-action {
3544
+ flex: 0 0 auto;
3545
+ align-self: center;
3546
+ display: inline-flex;
3547
+ }
3548
+
3442
3549
  /* ============================================================
3443
3550
  Divider — section-break band between adjacent regions that
3444
3551
  don't share an enclosing container. Single full-bleed block
3445
- painted with `sys.color.scrimSubtle` (~8% inverse-tone
3446
- overlayblack in light mode, white in dark) at a fixed
3447
- `sys.layout.stack.xs` (8) block thickness — the 1× rung of
3448
- the base-unit ladder. The translucent fill stays visible on
3449
- every host surface tier (surface, surfaceContainerHigh,
3450
- hero, …) without colliding with a fixed neutral step
3451
- same scrim tier as Banner default, Chip / Tag default,
3452
- Progress track, StatusTag neutral, and Skeleton. Resets
3453
- every browser `<hr>` default (margin, border, background-
3454
- image) so only the scrimSubtle band paints.
3552
+ painted with `sys.color.border.default` (the hairline
3553
+ separator role a faint gray in light, a subtle dark step in
3554
+ dark) at a fixed `sys.layout.stack.xs` (8) block thickness —
3555
+ the 1× rung of the base-unit ladder. Reads as a separator
3556
+ tier rather than a fill (unlike Banner / Chip / Tag default,
3557
+ which take the solid `background.neutral`). Resets every
3558
+ browser `<hr>` default (margin, border, background-image) so
3559
+ only the divider band paints.
3455
3560
  ============================================================ */
3456
3561
  .chorus-divider {
3457
3562
  display: block;
@@ -3461,7 +3566,7 @@ a.chorus-metadata__name:focus-visible {
3461
3566
  padding: 0;
3462
3567
  border: none;
3463
3568
  border-radius: 0;
3464
- background: var(--sys-color-scrimSubtle);
3569
+ background: var(--sys-color-border-default);
3465
3570
  background-image: none;
3466
3571
  flex-shrink: 0;
3467
3572
  }
@@ -3504,8 +3609,8 @@ a.chorus-metadata__name:focus-visible {
3504
3609
  box-sizing: border-box;
3505
3610
  display: flex;
3506
3611
  flex-direction: column;
3507
- background: var(--sys-color-surface);
3508
- color: var(--sys-color-onSurface);
3612
+ background: var(--sys-color-surface-default);
3613
+ color: var(--sys-color-text-default);
3509
3614
  box-shadow: var(--sys-elevation-sheet);
3510
3615
  }
3511
3616
 
@@ -3557,7 +3662,7 @@ a.chorus-metadata__name:focus-visible {
3557
3662
  .chorus-side-sheet__footer {
3558
3663
  flex: 0 0 auto;
3559
3664
  padding: var(--sys-layout-container-md);
3560
- border-top: var(--sys-borderWidth-hairline) solid var(--sys-color-outlineVariant);
3665
+ border-top: var(--sys-borderWidth-hairline) solid var(--sys-color-border-default);
3561
3666
  display: flex;
3562
3667
  align-items: center;
3563
3668
  justify-content: flex-start;
@@ -3603,8 +3708,8 @@ a.chorus-metadata__name:focus-visible {
3603
3708
  max-height: 90vh;
3604
3709
  display: flex;
3605
3710
  flex-direction: column;
3606
- background: var(--sys-color-surfaceContainerHigh);
3607
- color: var(--sys-color-onSurface);
3711
+ background: var(--sys-color-surface-default);
3712
+ color: var(--sys-color-text-default);
3608
3713
  border-top-left-radius: var(--sys-radius-xl);
3609
3714
  border-top-right-radius: var(--sys-radius-xl);
3610
3715
  box-shadow: var(--sys-elevation-sheet);
@@ -3622,7 +3727,7 @@ a.chorus-metadata__name:focus-visible {
3622
3727
  height: var(--ref-space-50);
3623
3728
  margin: var(--sys-layout-container-xs) auto;
3624
3729
  border-radius: var(--sys-radius-full);
3625
- background: color-mix(in srgb, var(--sys-color-onSurfaceVariant) 40%, transparent);
3730
+ background: color-mix(in srgb, var(--sys-color-text-subtle) 40%, transparent);
3626
3731
  }
3627
3732
 
3628
3733
  .chorus-bottom-sheet__content {
@@ -3640,7 +3745,7 @@ a.chorus-metadata__name:focus-visible {
3640
3745
  line-height: var(--sys-typo-heading-lg-line);
3641
3746
  font-weight: var(--sys-typo-heading-lg-weight);
3642
3747
  letter-spacing: var(--sys-typo-heading-lg-tracking);
3643
- color: var(--sys-color-onSurface);
3748
+ color: var(--sys-color-text-default);
3644
3749
  }
3645
3750
 
3646
3751
  /* Nested-step title row — when the sheet drives a drill-in, an Icon
@@ -3659,7 +3764,7 @@ a.chorus-metadata__name:focus-visible {
3659
3764
  font-size: var(--sys-typo-body-md-size);
3660
3765
  line-height: var(--sys-typo-body-md-line);
3661
3766
  font-weight: var(--sys-typo-body-md-weight);
3662
- color: var(--sys-color-onSurfaceVariant);
3767
+ color: var(--sys-color-text-subtle);
3663
3768
  }
3664
3769
 
3665
3770
  .chorus-bottom-sheet__actions {
@@ -3668,7 +3773,7 @@ a.chorus-metadata__name:focus-visible {
3668
3773
  flex-direction: column;
3669
3774
  gap: var(--sys-layout-stack-xs);
3670
3775
  padding: var(--sys-layout-container-md);
3671
- background: var(--sys-color-surfaceContainerHigh);
3776
+ background: var(--sys-color-surface-default);
3672
3777
  transition: box-shadow 120ms ease-out;
3673
3778
  }
3674
3779
 
@@ -3713,8 +3818,8 @@ a.chorus-metadata__name:focus-visible {
3713
3818
  align-items: stretch;
3714
3819
  text-align: start;
3715
3820
  padding: var(--sys-layout-container-lg);
3716
- background: var(--sys-color-surfaceContainerHigh);
3717
- color: var(--sys-color-onSurface);
3821
+ background: var(--sys-color-surface-default);
3822
+ color: var(--sys-color-text-default);
3718
3823
  border-radius: var(--sys-radius-xl);
3719
3824
  box-shadow: var(--sys-elevation-overlay);
3720
3825
  }
@@ -3730,7 +3835,7 @@ a.chorus-metadata__name:focus-visible {
3730
3835
  line-height: var(--sys-typo-heading-sm-line);
3731
3836
  font-weight: var(--sys-typo-heading-sm-weight);
3732
3837
  letter-spacing: var(--sys-typo-heading-sm-tracking);
3733
- color: var(--sys-color-onSurface);
3838
+ color: var(--sys-color-text-default);
3734
3839
  }
3735
3840
 
3736
3841
  .chorus-dialog__image {
@@ -3746,7 +3851,7 @@ a.chorus-metadata__name:focus-visible {
3746
3851
  font-size: var(--sys-typo-body-sm-size);
3747
3852
  line-height: var(--sys-typo-body-sm-line);
3748
3853
  font-weight: var(--sys-typo-body-sm-weight);
3749
- color: var(--sys-color-onSurfaceVariant);
3854
+ color: var(--sys-color-text-subtle);
3750
3855
  }
3751
3856
 
3752
3857
  .chorus-dialog__actions {
@@ -3854,7 +3959,7 @@ a.chorus-metadata__name:focus-visible {
3854
3959
 
3855
3960
  /* Accessibility focus ring — a dedicated overlay layer (`::after`),
3856
3961
  `position: absolute` so it never affects layout: a focused field never
3857
- widens and never nudges a sibling. Canonical two-layer composition,
3962
+ widens and never nudges a sibling. Canonical single-ring composition,
3858
3963
  painted outward from the field's edge; sits at `z-index: 2`, above the
3859
3964
  state-overlay `::before` (z-index 0) and the input / clear slots
3860
3965
  (z-index 1). `inset: 0` because the field has no `border` — the padding
@@ -3872,14 +3977,15 @@ a.chorus-metadata__name:focus-visible {
3872
3977
  }
3873
3978
 
3874
3979
  .chorus-field[data-force-state="focused"]::after {
3875
- box-shadow:
3876
- 0 0 0 var(--field-focus-inset-width) var(--field-focus-inset-color),
3877
- 0 0 0 calc(var(--field-focus-outer-width) + var(--field-focus-inset-width)) var(--field-focus-outer-color);
3980
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--field-focus-outer-color);
3878
3981
  }
3879
3982
 
3880
3983
  .chorus-field.is-disabled {
3984
+ /* Explicit disabled (no opacity): neutral disabled fill + bold border
3985
+ + disabled text. The component swaps `--field-text` / `--field-border`
3986
+ to the disabled tokens when disabled (see FormField.jsx), so the held
3987
+ rest stroke and typed text re-tone without a dim. */
3881
3988
  background: var(--field-bg-disabled);
3882
- opacity: var(--field-disabled-opacity);
3883
3989
  cursor: not-allowed;
3884
3990
  /* Hold the rest stroke even if the disabled field is hovered. */
3885
3991
  box-shadow: inset 0 0 0 var(--field-border-width) var(--field-border);
@@ -4005,7 +4111,7 @@ a.chorus-metadata__name:focus-visible {
4005
4111
  padding: 0;
4006
4112
  border: none;
4007
4113
  background: transparent;
4008
- color: var(--sys-color-onSurfaceVariant);
4114
+ color: var(--sys-color-text-subtle);
4009
4115
  border-radius: var(--sys-radius-full);
4010
4116
  cursor: pointer;
4011
4117
  }
@@ -4027,7 +4133,7 @@ a.chorus-metadata__name:focus-visible {
4027
4133
  }
4028
4134
 
4029
4135
  /* Focus ring — dedicated overlay layer (`::after`), `position: absolute`
4030
- so it never affects the field's layout. Canonical two-layer ring,
4136
+ so it never affects the field's layout. Canonical single-ring,
4031
4137
  outward; `z-index: 2`, above the 16px glyph. */
4032
4138
  .chorus-field__clear::after {
4033
4139
  content: '';
@@ -4041,9 +4147,7 @@ a.chorus-metadata__name:focus-visible {
4041
4147
  }
4042
4148
 
4043
4149
  .chorus-field__clear:focus-visible::after {
4044
- box-shadow:
4045
- 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-focusInset),
4046
- 0 0 0 calc(var(--sys-borderWidth-thin) + var(--sys-borderWidth-hairline)) var(--sys-color-focus);
4150
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-focused);
4047
4151
  }
4048
4152
 
4049
4153
  /* ============================================================
@@ -4074,7 +4178,7 @@ a.chorus-metadata__name:focus-visible {
4074
4178
  font-weight: var(--sys-typo-label-md-weight);
4075
4179
  line-height: var(--sys-typo-label-md-line);
4076
4180
  letter-spacing: var(--sys-typo-label-md-tracking);
4077
- color: var(--sys-color-onSurface);
4181
+ color: var(--sys-color-text-default);
4078
4182
  }
4079
4183
 
4080
4184
  .chorus-field-group__helper {
@@ -4082,7 +4186,7 @@ a.chorus-metadata__name:focus-visible {
4082
4186
  font-weight: var(--sys-typo-body-sm-weight);
4083
4187
  line-height: var(--sys-typo-body-sm-line);
4084
4188
  letter-spacing: var(--sys-typo-body-sm-tracking);
4085
- color: var(--sys-color-onSurfaceVariant);
4189
+ color: var(--sys-color-text-subtle);
4086
4190
  }
4087
4191
 
4088
4192
  .chorus-field-group__count {
@@ -4091,14 +4195,14 @@ a.chorus-metadata__name:focus-visible {
4091
4195
  font-weight: var(--sys-typo-body-sm-weight);
4092
4196
  line-height: var(--sys-typo-body-sm-line);
4093
4197
  letter-spacing: var(--sys-typo-body-sm-tracking);
4094
- color: var(--sys-color-onSurfaceVariant);
4198
+ color: var(--sys-color-text-subtle);
4095
4199
  }
4096
4200
 
4097
4201
  /* Current-count number — same body.sm size, label.md weight so the
4098
4202
  live count reads bolder than the `/max` suffix. */
4099
4203
  .chorus-field-group__count-current {
4100
4204
  font-weight: var(--sys-typo-label-md-weight);
4101
- color: var(--sys-color-onSurface);
4205
+ color: var(--sys-color-text-default);
4102
4206
  }
4103
4207
 
4104
4208
  /* Error appearance — re-tone the helper / count so the bottom rung
@@ -4106,16 +4210,15 @@ a.chorus-metadata__name:focus-visible {
4106
4210
  .chorus-field-group--error .chorus-field-group__helper,
4107
4211
  .chorus-field-group--error .chorus-field-group__count,
4108
4212
  .chorus-field-group--error .chorus-field-group__count-current {
4109
- color: var(--sys-color-error);
4213
+ color: var(--sys-color-text-danger);
4110
4214
  }
4111
4215
 
4112
- /* Disabled — dim the label / helper / count to match the 40% the box
4113
- already applies to itself. Box and group bits use the same
4114
- `--field-disabled-opacity` independently (no compounding). */
4216
+ /* Disabled — re-tone the label / helper / count to `text.disabled` to
4217
+ match the field box's explicit disabled treatment (no opacity). */
4115
4218
  .chorus-field-group.is-disabled .chorus-field-group__label,
4116
4219
  .chorus-field-group.is-disabled .chorus-field-group__helper,
4117
4220
  .chorus-field-group.is-disabled .chorus-field-group__count {
4118
- opacity: var(--field-disabled-opacity);
4221
+ color: var(--sys-color-text-disabled);
4119
4222
  }
4120
4223
 
4121
4224
  /* Trailing slot — symmetric to `.chorus-field__leading`. Hosts the
@@ -4130,7 +4233,7 @@ a.chorus-metadata__name:focus-visible {
4130
4233
  justify-content: center;
4131
4234
  width: var(--field-icon-size);
4132
4235
  height: var(--field-icon-size);
4133
- color: var(--sys-color-onSurfaceVariant);
4236
+ color: var(--sys-color-text-subtle);
4134
4237
  }
4135
4238
 
4136
4239
  .chorus-field--error .chorus-field__trailing {
@@ -4273,8 +4376,8 @@ a.chorus-metadata__name:focus-visible {
4273
4376
  calc(env(safe-area-inset-top, 0px) + var(--sys-layout-container-xs))
4274
4377
  var(--sys-layout-container-md)
4275
4378
  var(--sys-layout-container-xs);
4276
- background: var(--sys-color-surface);
4277
- color: var(--sys-color-onSurface);
4379
+ background: var(--sys-color-surface-default);
4380
+ color: var(--sys-color-text-default);
4278
4381
  }
4279
4382
 
4280
4383
  /* Main row layout (leading slot + flex-grown left title + trailing action
@@ -4295,7 +4398,7 @@ a.chorus-metadata__name:focus-visible {
4295
4398
  line-height: var(--sys-typo-heading-lg-line);
4296
4399
  font-weight: var(--sys-typo-heading-lg-weight);
4297
4400
  letter-spacing: var(--sys-typo-heading-lg-tracking);
4298
- color: var(--sys-color-onSurface);
4401
+ color: var(--sys-color-text-default);
4299
4402
  overflow: hidden;
4300
4403
  text-overflow: ellipsis;
4301
4404
  white-space: nowrap;
@@ -4329,7 +4432,7 @@ a.chorus-metadata__name:focus-visible {
4329
4432
  line-height: var(--sys-typo-heading-sm-line);
4330
4433
  font-weight: var(--sys-typo-heading-sm-weight);
4331
4434
  letter-spacing: var(--sys-typo-heading-sm-tracking);
4332
- color: var(--sys-color-onSurface);
4435
+ color: var(--sys-color-text-default);
4333
4436
  overflow: hidden;
4334
4437
  text-overflow: ellipsis;
4335
4438
  white-space: nowrap;
@@ -4407,7 +4510,7 @@ a.chorus-metadata__name:focus-visible {
4407
4510
  the row or shifts the input's caret position. Unique to Search; the
4408
4511
  bare input has no chrome of its own and the divider terminates the
4409
4512
  bar against the results list below. */
4410
- box-shadow: inset 0 -1px 0 var(--sys-color-outlineVariant);
4513
+ box-shadow: inset 0 -1px 0 var(--sys-color-border-default);
4411
4514
  }
4412
4515
 
4413
4516
  .chorus-navigation-bar--search .chorus-navigation-bar__slot--leading {
@@ -4419,9 +4522,9 @@ a.chorus-metadata__name:focus-visible {
4419
4522
  }
4420
4523
 
4421
4524
  /* Bare input — no border / background / inset stroke. Type rung body.md
4422
- (16/Regular). Caret picks up `sys.color.primary` so the active state
4525
+ (16/Regular). Caret picks up `sys.color.background.primary` so the active state
4423
4526
  reads against the surface fill. Placeholder picks up `sys.color.outline`;
4424
- value text picks up `sys.color.onSurface`. */
4527
+ value text picks up `sys.color.text.default`. */
4425
4528
  .chorus-navigation-bar__search-input {
4426
4529
  box-sizing: border-box;
4427
4530
  width: 100%;
@@ -4430,8 +4533,8 @@ a.chorus-metadata__name:focus-visible {
4430
4533
  padding: 0;
4431
4534
  border: 0;
4432
4535
  background: transparent;
4433
- color: var(--sys-color-onSurface);
4434
- caret-color: var(--sys-color-onSurface);
4536
+ color: var(--sys-color-text-default);
4537
+ caret-color: var(--sys-color-text-default);
4435
4538
  font-family: inherit;
4436
4539
  font-size: var(--sys-typo-body-md-size);
4437
4540
  line-height: var(--sys-typo-body-md-line);
@@ -4443,7 +4546,7 @@ a.chorus-metadata__name:focus-visible {
4443
4546
  }
4444
4547
 
4445
4548
  .chorus-navigation-bar__search-input::placeholder {
4446
- color: var(--sys-color-outline);
4549
+ color: var(--sys-color-border-boldest);
4447
4550
  opacity: 1;
4448
4551
  }
4449
4552
 
@@ -4469,8 +4572,8 @@ a.chorus-metadata__name:focus-visible {
4469
4572
  40 × 40 footprint falls out of `8 (padding) + 24 (glyph) + 8` and
4470
4573
  re-flows automatically if the icon token changes. Transparent at
4471
4574
  rest; hover / pressed paint `sys.state.*` overlays of `onSurface`;
4472
- focus composes the standard three-layer ring (`sys.color.focus`
4473
- outside `sys.color.focusInset`). */
4575
+ focus composes the standard three-layer ring (`sys.color.border.focused`
4576
+ outside `sys.color.border.focused`). */
4474
4577
  .chorus-button--icon {
4475
4578
  box-sizing: border-box;
4476
4579
  display: inline-flex;
@@ -4492,7 +4595,7 @@ a.chorus-metadata__name:focus-visible {
4492
4595
  /* Per-appearance plumbing — the glyph colour drives the hover /
4493
4596
  pressed / focus overlays (they `color-mix` from this var), so
4494
4597
  each appearance only declares one token. */
4495
- --button-icon-glyph-color: var(--sys-color-onSurface);
4598
+ --button-icon-glyph-color: var(--sys-color-icon-default);
4496
4599
  color: var(--button-icon-glyph-color);
4497
4600
  border-radius: var(--sys-radius-full);
4498
4601
  cursor: pointer;
@@ -4509,8 +4612,8 @@ a.chorus-metadata__name:focus-visible {
4509
4612
  /* Appearance modifiers — only the glyph colour token changes. Hover /
4510
4613
  pressed / focus overlays mix from `--button-icon-glyph-color`, so
4511
4614
  the recipe falls out without per-appearance overlay rules. */
4512
- .chorus-button--icon--appearance-default { --button-icon-glyph-color: var(--sys-color-onSurface); }
4513
- .chorus-button--icon--appearance-inverse { --button-icon-glyph-color: var(--sys-color-inverseOnSurface); }
4615
+ .chorus-button--icon--appearance-default { --button-icon-glyph-color: var(--sys-color-icon-default); }
4616
+ .chorus-button--icon--appearance-inverse { --button-icon-glyph-color: var(--sys-color-text-inverse); }
4514
4617
 
4515
4618
  .chorus-button--icon:hover,
4516
4619
  .chorus-button--icon[data-force-state="hovered"] {
@@ -4524,9 +4627,8 @@ a.chorus-metadata__name:focus-visible {
4524
4627
 
4525
4628
  .chorus-button--icon:focus-visible,
4526
4629
  .chorus-button--icon[data-force-state="focused"] {
4527
- outline: var(--sys-borderWidth-thin) solid var(--sys-color-focus);
4528
- outline-offset: calc(-1 * var(--sys-borderWidth-thin));
4529
- box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-focusInset);
4630
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
4631
+ outline-offset: calc(-1 * var(--sys-borderWidth-hairline));
4530
4632
  }
4531
4633
 
4532
4634
  .chorus-button--icon[data-force-state="focused"] {
@@ -4568,7 +4670,7 @@ a.chorus-metadata__name:focus-visible {
4568
4670
  density. Renders as <a> when `href` is given, <button> otherwise. */
4569
4671
  .chorus-button--text {
4570
4672
  /* Per-size plumbing — appearance + size modifiers override these. */
4571
- --button-text-label: var(--sys-color-onSurfaceVariant);
4673
+ --button-text-label: var(--sys-color-text-subtle);
4572
4674
  --button-text-min-height: var(--ref-space-500);
4573
4675
  --button-text-padding-block: var(--sys-layout-container-xs);
4574
4676
  --button-text-padding-inline: var(--sys-layout-container-xs);
@@ -4620,10 +4722,10 @@ a.chorus-metadata__name:focus-visible {
4620
4722
  `inverse` swaps the label to the inverse cluster so a Text Button
4621
4723
  inside a Toast / coach-mark / snackbar reads against the host's
4622
4724
  `inverseSurface` fill without a per-host tweak. */
4623
- .chorus-button--text--appearance-default { --button-text-label: var(--sys-color-onSurfaceVariant); }
4624
- .chorus-button--text--appearance-accent { --button-text-label: var(--sys-color-primary); }
4625
- .chorus-button--text--appearance-onPrimary { --button-text-label: var(--sys-color-onPrimary); }
4626
- .chorus-button--text--appearance-inverse { --button-text-label: var(--sys-color-inverseOnSurface); }
4725
+ .chorus-button--text--appearance-default { --button-text-label: var(--sys-color-text-subtle); }
4726
+ .chorus-button--text--appearance-accent { --button-text-label: var(--sys-color-text-accent-blue); }
4727
+ .chorus-button--text--appearance-onPrimary { --button-text-label: var(--sys-color-text-onFill); }
4728
+ .chorus-button--text--appearance-inverse { --button-text-label: var(--sys-color-text-inverse); }
4627
4729
 
4628
4730
  /* Size modifiers — pair min-height + padding + typo + icon footprint. */
4629
4731
  .chorus-button--text--size-medium {
@@ -4693,9 +4795,8 @@ a.chorus-metadata__name:focus-visible {
4693
4795
 
4694
4796
  .chorus-button--text:focus-visible,
4695
4797
  .chorus-button--text[data-force-state="focused"] {
4696
- outline: var(--sys-borderWidth-thin) solid var(--sys-color-focus);
4697
- outline-offset: calc(-1 * var(--sys-borderWidth-thin));
4698
- box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-focusInset);
4798
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
4799
+ outline-offset: calc(-1 * var(--sys-borderWidth-hairline));
4699
4800
  }
4700
4801
 
4701
4802
  .chorus-button--text[data-force-state="focused"] {
@@ -4719,7 +4820,7 @@ a.chorus-metadata__name:focus-visible {
4719
4820
  layout edges. */
4720
4821
  .chorus-button--check {
4721
4822
  /* Per-size plumbing. */
4722
- --button-check-label: var(--sys-color-onSurfaceVariant);
4823
+ --button-check-label: var(--sys-color-text-subtle);
4723
4824
  --button-check-min-height: var(--ref-space-500);
4724
4825
  --button-check-padding-block: var(--sys-layout-container-xs);
4725
4826
  --button-check-padding-inline: var(--sys-layout-container-xs);
@@ -4756,9 +4857,18 @@ a.chorus-metadata__name:focus-visible {
4756
4857
  transition: background 120ms ease;
4757
4858
  }
4758
4859
 
4759
- .chorus-button--check--appearance-default { --button-check-label: var(--sys-color-onSurfaceVariant); }
4760
- .chorus-button--check--appearance-accent { --button-check-label: var(--sys-color-primary); }
4761
- .chorus-button--check--appearance-inverse { --button-check-label: var(--sys-color-inverseOnSurface); }
4860
+ .chorus-button--check--appearance-default { --button-check-label: var(--sys-color-text-subtle); }
4861
+ .chorus-button--check--appearance-accent { --button-check-label: var(--sys-color-text-accent-blue); }
4862
+ .chorus-button--check--appearance-inverse { --button-check-label: var(--sys-color-text-inverse); }
4863
+
4864
+ /* Standard checkbox glyph paints in `icon.default` — the selection-control
4865
+ family's neutral glyph tone (selection is shown by the outline↔fill glyph
4866
+ swap, not color), while the label keeps its quieter `text.subtle`. The
4867
+ accent / inverse appearances intentionally tint the glyph with their label
4868
+ color via `currentColor`, so this only re-tones the default appearance. */
4869
+ .chorus-button--check--appearance-default .chorus-button--check__checkbox {
4870
+ color: var(--sys-color-icon-default);
4871
+ }
4762
4872
 
4763
4873
  /* Two sizes — the checkbox footprint is the size differentiator, not the
4764
4874
  label. Both rungs share `sys.typo.label.sm` (12-rank); medium pairs it
@@ -4830,9 +4940,8 @@ a.chorus-metadata__name:focus-visible {
4830
4940
 
4831
4941
  .chorus-button--check:focus-visible,
4832
4942
  .chorus-button--check[data-force-state="focused"] {
4833
- outline: var(--sys-borderWidth-thin) solid var(--sys-color-focus);
4834
- outline-offset: calc(-1 * var(--sys-borderWidth-thin));
4835
- box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-focusInset);
4943
+ outline: var(--sys-borderWidth-hairline) solid var(--sys-color-border-focused);
4944
+ outline-offset: calc(-1 * var(--sys-borderWidth-hairline));
4836
4945
  }
4837
4946
 
4838
4947
  .chorus-button--check[data-force-state="focused"] {
@@ -4874,13 +4983,13 @@ a.chorus-metadata__name:focus-visible {
4874
4983
  its original 56-tall footprint. Inline padding stays 0 — tab
4875
4984
  items are equal-width and span the full row. */
4876
4985
  padding: 0 0 env(safe-area-inset-bottom, 0px);
4877
- background: var(--sys-color-surface);
4878
- color: var(--sys-color-onSurface);
4986
+ background: var(--sys-color-surface-default);
4987
+ color: var(--sys-color-text-default);
4879
4988
  /* Top hairline divider — separates the bar from the scrolling content
4880
4989
  above it without introducing a layout border that could nudge the
4881
4990
  56-tall row off-pixel. Painted as an inset shadow so the bar's flex
4882
4991
  geometry is untouched. */
4883
- box-shadow: inset 0 var(--sys-borderWidth-hairline) 0 0 var(--sys-color-outlineVariant);
4992
+ box-shadow: inset 0 var(--sys-borderWidth-hairline) 0 0 var(--sys-color-border-default);
4884
4993
  }
4885
4994
 
4886
4995
  .chorus-tab-bar__item {
@@ -4908,14 +5017,14 @@ a.chorus-metadata__name:focus-visible {
4908
5017
  margin: 0;
4909
5018
  font: inherit;
4910
5019
  text-decoration: none;
4911
- color: var(--sys-color-onSurfaceVariant);
5020
+ color: var(--sys-color-text-subtle);
4912
5021
  cursor: pointer;
4913
5022
  -webkit-tap-highlight-color: transparent;
4914
5023
  }
4915
5024
 
4916
5025
  .chorus-tab-bar__item[aria-current="page"].is-active,
4917
5026
  .chorus-tab-bar__item.is-active {
4918
- color: var(--sys-color-onSurface);
5027
+ color: var(--sys-color-text-default);
4919
5028
  }
4920
5029
 
4921
5030
  .chorus-tab-bar__icon {
@@ -4954,27 +5063,25 @@ a.chorus-metadata__name:focus-visible {
4954
5063
 
4955
5064
  .chorus-tab-bar__item:hover::before,
4956
5065
  .chorus-tab-bar__item[data-force-state="hovered"]::before {
4957
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-hover) * 100%), transparent);
5066
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-hover) * 100%), transparent);
4958
5067
  }
4959
5068
 
4960
5069
  .chorus-tab-bar__item:active::before,
4961
5070
  .chorus-tab-bar__item[data-force-state="pressed"]::before {
4962
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-pressed) * 100%), transparent);
5071
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-pressed) * 100%), transparent);
4963
5072
  }
4964
5073
 
4965
5074
  .chorus-tab-bar__item[data-force-state="focused"]::before {
4966
- background: color-mix(in srgb, var(--sys-color-onSurface) calc(var(--sys-state-focus) * 100%), transparent);
5075
+ background: color-mix(in srgb, var(--sys-color-text-default) calc(var(--sys-state-focus) * 100%), transparent);
4967
5076
  }
4968
5077
 
4969
5078
  /* Focus ring — three-layer composition rings the item flush at the
4970
5079
  slot edge. We can't ring outward (adjacent items are flush under
4971
5080
  `flex: 1 1 0`, so an outward stroke would overlap its neighbour),
4972
- so the standard composition is painted as `inset` shadows on the
4973
- ::after that covers the slot exactly. Layering reads from the slot
4974
- edge inward: `focus` (the 2px outer stroke) sits at the edge, then
4975
- `focusInset` (the 1px counter-ring) sits just inside — **focus
4976
- outer, inset inner**, never reversed. The ring is constrained
4977
- strictly inside the slot's bounding box. */
5081
+ so the standard composition is painted as an `inset` shadow on the
5082
+ ::after that covers the slot exactly: a single 1px `border.focused`
5083
+ ring at the slot edge, constrained strictly inside the slot's
5084
+ bounding box. */
4978
5085
  .chorus-tab-bar__item::after {
4979
5086
  content: '';
4980
5087
  position: absolute;
@@ -4988,9 +5095,7 @@ a.chorus-metadata__name:focus-visible {
4988
5095
 
4989
5096
  .chorus-tab-bar__item:focus-visible::after,
4990
5097
  .chorus-tab-bar__item[data-force-state="focused"]::after {
4991
- box-shadow:
4992
- inset 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-focus),
4993
- inset 0 0 0 calc(var(--sys-borderWidth-thin) + var(--sys-borderWidth-hairline)) var(--sys-color-focusInset);
5098
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-focused);
4994
5099
  }
4995
5100
 
4996
5101
  /* Label fills the item's slot up to its natural text width and
@@ -5002,10 +5107,10 @@ a.chorus-metadata__name:focus-visible {
5002
5107
  .chorus-tab-bar__label {
5003
5108
  max-width: 100%;
5004
5109
  font-family: var(--sys-typo-fontFamily-sans);
5005
- font-size: var(--sys-typo-caption-size);
5006
- line-height: var(--sys-typo-caption-line);
5007
- font-weight: var(--sys-typo-caption-weight);
5008
- letter-spacing: var(--sys-typo-caption-tracking);
5110
+ font-size: var(--sys-typo-label-xs-size);
5111
+ line-height: var(--sys-typo-label-xs-line);
5112
+ font-weight: var(--sys-typo-label-xs-weight);
5113
+ letter-spacing: var(--sys-typo-label-xs-tracking);
5009
5114
  color: currentColor;
5010
5115
  text-align: center;
5011
5116
  white-space: nowrap;
@@ -5016,7 +5121,7 @@ a.chorus-metadata__name:focus-visible {
5016
5121
  }
5017
5122
 
5018
5123
  /* Primary appearance — the "Create" / "Compose" commit affordance.
5019
- Paints the glyph in `sys.color.brand` (the editorial/brand accent
5124
+ Paints the glyph in `sys.color.text.brand` (the editorial/brand accent
5020
5125
  the system reserves for commit affordances that should read as the
5021
5126
  product's voice, not a generic call-to-action). Pair with a
5022
5127
  filled-tile icon (AddSquareFillIcon / ComposeFillIcon) so the
@@ -5027,11 +5132,11 @@ a.chorus-metadata__name:focus-visible {
5027
5132
  standard icon footprint so the row's optical alignment is
5028
5133
  unaffected. */
5029
5134
  .chorus-tab-bar__item--primary {
5030
- color: var(--sys-color-onSurfaceVariant);
5135
+ color: var(--sys-color-text-subtle);
5031
5136
  }
5032
5137
 
5033
5138
  .chorus-tab-bar__item--primary .chorus-tab-bar__icon {
5034
- color: var(--sys-color-brand);
5139
+ color: var(--sys-color-text-brand);
5035
5140
  }
5036
5141
 
5037
5142
  .chorus-tab-bar__item:focus-visible {
@@ -5040,7 +5145,9 @@ a.chorus-metadata__name:focus-visible {
5040
5145
 
5041
5146
  .chorus-tab-bar__item:disabled,
5042
5147
  .chorus-tab-bar__item[aria-disabled="true"] {
5043
- opacity: var(--sys-state-disabled);
5148
+ /* Explicit disabled (no opacity): item re-tones to text.disabled; icon
5149
+ and label ride currentColor so both follow. */
5150
+ color: var(--sys-color-text-disabled);
5044
5151
  cursor: not-allowed;
5045
5152
  pointer-events: none;
5046
5153
  }
@@ -5066,8 +5173,8 @@ a.chorus-metadata__name:focus-visible {
5066
5173
  max-width: min(400px, calc(100vw - 2 * var(--sys-layout-container-xs)));
5067
5174
  padding: var(--sys-layout-container-xs) var(--sys-layout-container-md);
5068
5175
  border-radius: var(--sys-radius-md);
5069
- background: var(--sys-color-inverseSurface);
5070
- color: var(--sys-color-inverseOnSurface);
5176
+ background: var(--sys-color-background-inverse);
5177
+ color: var(--sys-color-text-inverse);
5071
5178
  box-shadow: var(--sys-elevation-overlay);
5072
5179
  }
5073
5180
 
@@ -5149,16 +5256,16 @@ a.chorus-metadata__name:focus-visible {
5149
5256
  Pair the action button with `appearance="onPrimary"` (also
5150
5257
  theme-stable). */
5151
5258
  .chorus-tooltip--appearance-default {
5152
- background: var(--sys-color-primary);
5153
- color: var(--sys-color-onPrimary);
5259
+ background: var(--sys-color-background-primary);
5260
+ color: var(--sys-color-text-onFill);
5154
5261
  }
5155
5262
 
5156
5263
  /* Inverse — dark-cluster bubble for primary-heavy screens. Pair the
5157
5264
  action button with `appearance="inverse"` so the label flips with
5158
5265
  the host fill. */
5159
5266
  .chorus-tooltip--appearance-inverse {
5160
- background: var(--sys-color-inverseSurface);
5161
- color: var(--sys-color-inverseOnSurface);
5267
+ background: var(--sys-color-background-inverse);
5268
+ color: var(--sys-color-text-inverse);
5162
5269
  }
5163
5270
 
5164
5271
  .chorus-tooltip__body {
@@ -5256,8 +5363,8 @@ a.chorus-metadata__name:focus-visible {
5256
5363
  }
5257
5364
 
5258
5365
  .chorus-bubble {
5259
- --bubble-fill: var(--sys-color-primary);
5260
- --bubble-ink: var(--sys-color-onPrimary);
5366
+ --bubble-fill: var(--sys-color-background-primary);
5367
+ --bubble-ink: var(--sys-color-text-onFill);
5261
5368
 
5262
5369
  position: relative;
5263
5370
  display: inline-flex;
@@ -5277,10 +5384,10 @@ a.chorus-metadata__name:focus-visible {
5277
5384
  border-radius: var(--sys-radius-full);
5278
5385
  background: var(--bubble-fill);
5279
5386
  color: var(--bubble-ink);
5280
- font-size: var(--sys-typo-caption-size);
5281
- font-weight: var(--sys-typo-caption-weight);
5282
- line-height: var(--sys-typo-caption-line);
5283
- letter-spacing: var(--sys-typo-caption-tracking);
5387
+ font-size: var(--sys-typo-label-xs-size);
5388
+ font-weight: var(--sys-typo-label-xs-weight);
5389
+ line-height: var(--sys-typo-label-xs-line);
5390
+ letter-spacing: var(--sys-typo-label-xs-tracking);
5284
5391
  }
5285
5392
 
5286
5393
  /* Single-line body. `min-width: 0` is the standard flex-truncation
@@ -5345,7 +5452,7 @@ a.chorus-metadata__name:focus-visible {
5345
5452
  /* One 6px dot per page in an inline.sm row. An inline element —
5346
5453
  inline-flex, intrinsic width (no stretch, no self-centering); the
5347
5454
  host owns horizontal placement. Active dot paints `onSurface`, the
5348
- rest `outlineVariant`. Non-interactive (`aria-hidden` on the root) —
5455
+ rest `border.default`. Non-interactive (`aria-hidden` on the root) —
5349
5456
  the host pager owns the active index and keyboard reach.
5350
5457
  See schema/components/pagination/pagination.md. */
5351
5458
 
@@ -5359,23 +5466,22 @@ a.chorus-metadata__name:focus-visible {
5359
5466
  width: var(--ref-space-75);
5360
5467
  height: var(--ref-space-75);
5361
5468
  border-radius: var(--sys-radius-full);
5362
- background: var(--sys-color-outlineVariant);
5469
+ background: var(--sys-color-border-default);
5363
5470
  display: block;
5364
5471
  }
5365
5472
 
5366
5473
  .chorus-pagination__dot--active {
5367
- background: var(--sys-color-onSurface);
5474
+ background: var(--sys-color-text-default);
5368
5475
  }
5369
5476
 
5370
5477
  /* ============================================================
5371
5478
  Progress — linear progress bar (determinate)
5372
5479
  ============================================================ */
5373
- /* Single visual rung — 8px tall, radius.full. Track paints with
5374
- `sys.color.scrimSubtle` (the Banner-style inverse-tone scrim black
5375
- 8% in light, white 8% in dark) so the bar reads cleanly on any host
5376
- surface tier rather than colliding with a fixed surface-container
5377
- step. Indicator paints in `inverseSurface` so the filled segment
5378
- always contrasts against the bare-track scrim regardless of theme.
5480
+ /* Single visual rung — 8px tall, radius.full. Track paints with the
5481
+ solid `background.neutral` fill (the role that replaced the old
5482
+ Banner-style ~8% scrim) a light-gray track in light, a mid-gray in
5483
+ dark. Indicator paints in `inverseSurface` so the filled segment
5484
+ always contrasts against the bare track regardless of theme.
5379
5485
  The indicator's `translateX` parks at `-100 + percent`% so the
5380
5486
  trailing edge sits at the value's ratio; transitions over 200ms so
5381
5487
  jumps animate. */
@@ -5386,7 +5492,7 @@ a.chorus-metadata__name:focus-visible {
5386
5492
  width: 100%;
5387
5493
  height: var(--sys-layout-container-xs);
5388
5494
  overflow: hidden;
5389
- background: var(--sys-color-scrimSubtle);
5495
+ background: var(--sys-color-background-neutral);
5390
5496
  border-radius: var(--sys-radius-full);
5391
5497
  flex: 1 1 auto;
5392
5498
  }
@@ -5396,7 +5502,7 @@ a.chorus-metadata__name:focus-visible {
5396
5502
  position: absolute;
5397
5503
  inset: 0;
5398
5504
  width: 100%;
5399
- background: var(--sys-color-inverseSurface);
5505
+ background: var(--sys-color-background-inverse);
5400
5506
  border-radius: inherit;
5401
5507
  transform: translateX(-100%);
5402
5508
  transition: transform 200ms ease-out;
@@ -5433,32 +5539,30 @@ a.chorus-metadata__name:focus-visible {
5433
5539
  }
5434
5540
 
5435
5541
  /* Neutral — the quiet informational default. Background paints with
5436
- `sys.color.scrimSubtle` a translucent inverse-tone scrim (~8%
5437
- black light, ~8% white dark) so the pill stays a faint overlay on
5438
- the host surface rather than picking up the same tone as a
5439
- surface-* container. Same Banner-style fill used by Chip / Tag
5440
- default, Progress track, and Skeleton. Foreground stays bound to
5441
- `onSurfaceVariant` so legibility tracks the active palette
5442
- automatically. */
5542
+ the solid `background.neutral` fill (the role that replaced the old
5543
+ ~8% scrim) a light-gray pill in light, a mid-gray in dark. Same
5544
+ neutral fill used by Banner / Chip / Tag default, Progress track,
5545
+ and Skeleton. Foreground stays bound to `text.subtle` so legibility
5546
+ tracks the active palette automatically. */
5443
5547
  .chorus-status-tag--neutral {
5444
- background: var(--sys-color-scrimSubtle);
5445
- color: var(--sys-color-onSurfaceVariant);
5548
+ background: var(--sys-color-background-neutral);
5549
+ color: var(--sys-color-text-subtle);
5446
5550
  }
5447
5551
 
5448
5552
  .chorus-status-tag--error {
5449
- background: var(--sys-color-errorContainer);
5450
- color: var(--sys-color-onErrorContainer);
5553
+ background: var(--sys-color-background-danger);
5554
+ color: var(--sys-color-text-danger);
5451
5555
  }
5452
5556
 
5453
5557
  /* ============================================================
5454
5558
  Skeleton — tonal loading placeholder with opacity pulse
5455
5559
  ============================================================ */
5456
- /* Translucent inverse-tone scrim (`sys.color.scrimSubtle` black 8%
5457
- in light mode, white 8% in dark) painted with a slow opacity pulse
5458
- (0.5 → 1 → 0.5, 1.6s `ease-in-out`). The same Banner-style fill used
5459
- by Chip / Tag default, Progress track, and StatusTag neutral stays
5460
- visible on every host surface tier without colliding with a fixed
5461
- neutral step. Three shapes select the default footprint and corner
5560
+ /* Solid `background.neutral` fill (the role that replaced the old ~8%
5561
+ scrim) a light-gray placeholder in light, a mid-gray in dark
5562
+ painted with a slow opacity pulse (0.5 → 1 → 0.5, 1.6s
5563
+ `ease-in-out`). The same neutral fill used by Banner / Chip / Tag
5564
+ default, Progress track, and StatusTag neutral. Three shapes select
5565
+ the default footprint and corner
5462
5566
  radius. The pulse animates `opacity` only — no gradient sweep — so
5463
5567
  the placeholder reads as anonymous chrome and degrades cleanly under
5464
5568
  `prefers-reduced-motion: reduce`. */
@@ -5469,7 +5573,7 @@ a.chorus-metadata__name:focus-visible {
5469
5573
 
5470
5574
  .chorus-skeleton {
5471
5575
  display: block;
5472
- background: var(--sys-color-scrimSubtle);
5576
+ background: var(--sys-color-background-neutral);
5473
5577
  animation: chorus-skeleton-pulse 1.6s ease-in-out infinite;
5474
5578
  }
5475
5579
 
@@ -5505,24 +5609,90 @@ a.chorus-metadata__name:focus-visible {
5505
5609
  }
5506
5610
  }
5507
5611
 
5612
+ /* ============================================================
5613
+ Spinner — indeterminate rotating-arc loading indicator
5614
+ ============================================================ */
5615
+ /* A rotating ring for short, progress-unknown waits (< ~1s) on a
5616
+ neutral host surface. The arc paints `background.primary` as the
5617
+ foreground motion over a solid `background.neutral` track ring (the
5618
+ role that replaced the old ~8% scrim) so the rotation reads clearly.
5619
+ The ring is drawn with a conic gradient masked to an annulus — no
5620
+ `border:` (per the no-layout-strokes rule). Diameter rides the
5621
+ icon.* ladder via the `--spinner-diameter` plumbing var (sys.icon.lg
5622
+ medium / sys.icon.md small). Rotation modulates position, not
5623
+ luminance, and is suppressed under `prefers-reduced-motion: reduce`,
5624
+ leaving the full ring static as a quiet loading mark. */
5625
+ @keyframes chorus-spinner-rotate {
5626
+ to { transform: rotate(360deg); }
5627
+ }
5628
+
5629
+ .chorus-spinner {
5630
+ display: inline-flex;
5631
+ align-items: center;
5632
+ gap: var(--spinner-gap);
5633
+ }
5634
+
5635
+ .chorus-spinner__arc {
5636
+ display: block;
5637
+ flex: none;
5638
+ width: var(--spinner-diameter);
5639
+ height: var(--spinner-diameter);
5640
+ border-radius: var(--sys-radius-full);
5641
+ /* Foreground arc sweeps from primary to transparent over the track. */
5642
+ background:
5643
+ conic-gradient(var(--sys-color-background-primary), color-mix(in srgb, var(--sys-color-background-primary) 0%, transparent) 75%, color-mix(in srgb, var(--sys-color-background-primary) 0%, transparent));
5644
+ /* Annulus mask: punch out the centre so it reads as a ring, 2px thick.
5645
+ The mask fill is alpha-only — the opaque keep-region of the mask is
5646
+ not a design color, so it is not a token binding. */
5647
+ /* chorus-token-exempt */
5648
+ -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
5649
+ /* chorus-token-exempt */
5650
+ mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
5651
+ animation: chorus-spinner-rotate 0.8s linear infinite;
5652
+ }
5653
+
5654
+ /* Faint full track ring under the rotating arc, painted via box-shadow
5655
+ inset so the bare ring stays visible on any surface tier. */
5656
+ .chorus-spinner__arc::before {
5657
+ content: '';
5658
+ position: absolute;
5659
+ inset: 0;
5660
+ border-radius: inherit;
5661
+ box-shadow: inset 0 0 0 2px var(--sys-color-background-neutral);
5662
+ }
5663
+
5664
+ .chorus-spinner__arc {
5665
+ position: relative;
5666
+ }
5667
+
5668
+ .chorus-spinner__label {
5669
+ color: var(--sys-color-text-subtle);
5670
+ }
5671
+
5672
+ @media (prefers-reduced-motion: reduce) {
5673
+ .chorus-spinner__arc {
5674
+ animation: none;
5675
+ }
5676
+ }
5677
+
5508
5678
  /* ============================================================
5509
5679
  Switch — binary active/inactive pill with translating thumb
5510
5680
  ============================================================ */
5511
- /* 52 × 32 pill track + 28 × 28 thumb. Inactive paints a `scrimSubtle`
5512
- track (inverse-tone ~8% tint) with a hairline outline and a fixed-white
5681
+ /* 52 × 32 pill track + 28 × 28 thumb. Inactive paints a solid
5682
+ `background.neutral` track with a hairline outline and a fixed-white
5513
5683
  thumb; active paints `primary` track with no outline. Thumb translates 20px between
5514
5684
  the two ends. Whole track is the click target — the thumb is
5515
5685
  decorative. Outward focus ring matches Switch's "stands inline with
5516
5686
  whitespace around it" placement; the rest stroke stays a no-layout
5517
5687
  inset box-shadow. */
5518
5688
  .chorus-switch {
5519
- /* Inactive (resting) — `scrimSubtle` track (inverse-tone ~8% tint:
5520
- black in light, white in dark) so the track stays distinct on any
5521
- host surface tier, reinforced by the hairline outline, with a
5522
- fixed-white thumb that reads the same in light and dark. The active
5523
- selector below overrides for the on-state. */
5524
- --switch-track-bg: var(--sys-color-scrimSubtle);
5525
- --switch-track-outline: var(--sys-color-outlineVariant);
5689
+ /* Inactive (resting) — `icon.subtlest` track: the off state of the
5690
+ selection-control family, a mid-neutral that reads clearly on any host
5691
+ surface, reinforced by the hairline outline, with a fixed-white thumb
5692
+ that reads the same in light and dark. The active selector below
5693
+ overrides for the on-state. */
5694
+ --switch-track-bg: var(--sys-color-icon-subtlest);
5695
+ --switch-track-outline: var(--sys-color-border-default);
5526
5696
  --switch-thumb-bg: var(--ref-palette-white-1000);
5527
5697
  --switch-thumb-offset: 0px;
5528
5698
 
@@ -5561,20 +5731,20 @@ a.chorus-metadata__name:focus-visible {
5561
5731
  transform 120ms ease-out;
5562
5732
  }
5563
5733
 
5564
- /* Active — `primary` track, `onPrimary` thumb, outline disappears so the
5565
- filled track reads as one solid block. Thumb translates to the
5734
+ /* Active — `icon.accent.blue` track, `onFill` thumb, outline disappears so
5735
+ the filled track reads as one solid block. Thumb translates to the
5566
5736
  trailing end (52 - 28 - 2*2 = 20). */
5567
5737
  .chorus-switch[data-state='active'] {
5568
- --switch-track-bg: var(--sys-color-primary);
5738
+ --switch-track-bg: var(--sys-color-icon-accent-blue-default);
5569
5739
  --switch-track-outline: transparent;
5570
- --switch-thumb-bg: var(--sys-color-onPrimary);
5740
+ --switch-thumb-bg: var(--sys-color-text-onFill);
5571
5741
  --switch-thumb-offset: 20px;
5572
5742
  }
5573
5743
 
5574
5744
  .chorus-switch:hover {
5575
5745
  background: color-mix(
5576
5746
  in srgb,
5577
- var(--sys-color-onSurface) calc(var(--sys-state-hover) * 100%),
5747
+ var(--sys-color-text-default) calc(var(--sys-state-hover) * 100%),
5578
5748
  var(--switch-track-bg)
5579
5749
  );
5580
5750
  }
@@ -5583,7 +5753,7 @@ a.chorus-metadata__name:focus-visible {
5583
5753
  .chorus-switch[data-force-state='pressed'] {
5584
5754
  background: color-mix(
5585
5755
  in srgb,
5586
- var(--sys-color-onSurface) calc(var(--sys-state-pressed) * 100%),
5756
+ var(--sys-color-text-default) calc(var(--sys-state-pressed) * 100%),
5587
5757
  var(--switch-track-bg)
5588
5758
  );
5589
5759
  }
@@ -5608,14 +5778,16 @@ a.chorus-metadata__name:focus-visible {
5608
5778
 
5609
5779
  .chorus-switch:focus-visible::after,
5610
5780
  .chorus-switch[data-force-state='focused']::after {
5611
- box-shadow:
5612
- 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-focus),
5613
- 0 0 0 calc(var(--sys-borderWidth-thin) + var(--sys-borderWidth-hairline)) var(--sys-color-focusInset);
5781
+ box-shadow: 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-focused);
5614
5782
  }
5615
5783
 
5616
5784
  .chorus-switch:disabled,
5617
5785
  .chorus-switch[data-disabled='true'] {
5618
- opacity: var(--sys-state-disabled);
5786
+ /* Explicit disabled (no opacity): the track re-tones to the neutral
5787
+ disabled fill with a bold edge, overriding the active/inactive track
5788
+ set above — this rule wins on source order. Thumb stays put. */
5789
+ --switch-track-bg: var(--sys-color-icon-disabled);
5790
+ --switch-track-outline: var(--sys-color-border-bold);
5619
5791
  cursor: not-allowed;
5620
5792
  pointer-events: none;
5621
5793
  }
@@ -5624,7 +5796,7 @@ a.chorus-metadata__name:focus-visible {
5624
5796
  Accordion — stack of expandable rows with rotating chevron
5625
5797
  ============================================================ */
5626
5798
  /* Edge-to-edge (`full-bleed`) family. Rows tile flush with a hairline
5627
- `outlineVariant` divider inset 16px (`layout.container.md`) on BOTH
5799
+ `border.default` divider inset 16px (`layout.container.md`) on BOTH
5628
5800
  the leading and trailing edges so the rule reads as separating row
5629
5801
  *content*, not the container. Composes the divider on a dedicated
5630
5802
  `::after` overlay rather than a `border:` / full-bleed box-shadow so
@@ -5649,7 +5821,7 @@ a.chorus-metadata__name:focus-visible {
5649
5821
  right: var(--sys-layout-container-md);
5650
5822
  bottom: 0;
5651
5823
  height: var(--sys-borderWidth-hairline);
5652
- background: var(--sys-color-outlineVariant);
5824
+ background: var(--sys-color-border-default);
5653
5825
  pointer-events: none;
5654
5826
  }
5655
5827
 
@@ -5663,7 +5835,7 @@ a.chorus-metadata__name:focus-visible {
5663
5835
  padding: var(--sys-layout-container-xs) var(--sys-layout-container-md);
5664
5836
  border: 0;
5665
5837
  background: transparent;
5666
- color: var(--sys-color-onSurface);
5838
+ color: var(--sys-color-text-default);
5667
5839
  text-align: left;
5668
5840
  cursor: pointer;
5669
5841
  position: relative;
@@ -5681,7 +5853,7 @@ a.chorus-metadata__name:focus-visible {
5681
5853
  line-height: var(--sys-typo-body-md-line);
5682
5854
  font-weight: var(--sys-typo-body-md-weight);
5683
5855
  letter-spacing: var(--sys-typo-body-md-tracking);
5684
- color: var(--sys-color-onSurface);
5856
+ color: var(--sys-color-text-default);
5685
5857
  }
5686
5858
 
5687
5859
  .chorus-accordion__chevron {
@@ -5691,7 +5863,7 @@ a.chorus-metadata__name:focus-visible {
5691
5863
  justify-content: center;
5692
5864
  width: var(--sys-icon-md);
5693
5865
  height: var(--sys-icon-md);
5694
- color: var(--sys-color-onSurfaceVariant);
5866
+ color: var(--sys-color-text-subtle);
5695
5867
  transition: transform 120ms ease-out;
5696
5868
  }
5697
5869
 
@@ -5702,7 +5874,7 @@ a.chorus-metadata__name:focus-visible {
5702
5874
  .chorus-accordion__trigger:hover {
5703
5875
  background: color-mix(
5704
5876
  in srgb,
5705
- var(--sys-color-onSurface) calc(var(--sys-state-hover) * 100%),
5877
+ var(--sys-color-text-default) calc(var(--sys-state-hover) * 100%),
5706
5878
  transparent
5707
5879
  );
5708
5880
  }
@@ -5711,7 +5883,7 @@ a.chorus-metadata__name:focus-visible {
5711
5883
  .chorus-accordion__trigger[data-force-state='pressed'] {
5712
5884
  background: color-mix(
5713
5885
  in srgb,
5714
- var(--sys-color-onSurface) calc(var(--sys-state-pressed) * 100%),
5886
+ var(--sys-color-text-default) calc(var(--sys-state-pressed) * 100%),
5715
5887
  transparent
5716
5888
  );
5717
5889
  }
@@ -5735,17 +5907,26 @@ a.chorus-metadata__name:focus-visible {
5735
5907
 
5736
5908
  .chorus-accordion__trigger:focus-visible::before,
5737
5909
  .chorus-accordion__trigger[data-force-state='focused']::before {
5738
- box-shadow:
5739
- inset 0 0 0 var(--sys-borderWidth-thin) var(--sys-color-focus),
5740
- inset 0 0 0 calc(var(--sys-borderWidth-thin) + var(--sys-borderWidth-hairline)) var(--sys-color-focusInset);
5910
+ box-shadow: inset 0 0 0 var(--sys-borderWidth-hairline) var(--sys-color-border-focused);
5741
5911
  }
5742
5912
 
5743
5913
  .chorus-accordion__trigger:disabled,
5744
5914
  .chorus-accordion__item[data-disabled='true'] {
5745
- opacity: var(--sys-state-disabled);
5746
5915
  cursor: not-allowed;
5747
5916
  }
5748
5917
 
5918
+ /* Explicit disabled (no opacity): trigger label re-tones to text.disabled,
5919
+ chevron glyph to icon.disabled. */
5920
+ .chorus-accordion__trigger:disabled,
5921
+ .chorus-accordion__item[data-disabled='true'] .chorus-accordion__trigger,
5922
+ .chorus-accordion__item[data-disabled='true'] .chorus-accordion__label {
5923
+ color: var(--sys-color-text-disabled);
5924
+ }
5925
+
5926
+ .chorus-accordion__item[data-disabled='true'] .chorus-accordion__chevron {
5927
+ color: var(--sys-color-icon-disabled);
5928
+ }
5929
+
5749
5930
  .chorus-accordion__item[data-disabled='true'] .chorus-accordion__trigger {
5750
5931
  pointer-events: none;
5751
5932
  }
@@ -5766,7 +5947,7 @@ a.chorus-metadata__name:focus-visible {
5766
5947
  sub-list stretches flush to the accordion's right edge without
5767
5948
  a double-paid gutter.
5768
5949
 
5769
- Mode (b) also paints a hairline `outlineVariant` top group-divider
5950
+ Mode (b) also paints a hairline `border.default` top group-divider
5770
5951
  via a `::before` overlay (no-layout stroke — a `border-top:` on the
5771
5952
  child container would reflow the first row's box and break its
5772
5953
  inward focus ring). The 16px inline inset mirrors the inter-item
@@ -5803,7 +5984,7 @@ a.chorus-metadata__name:focus-visible {
5803
5984
  right: var(--sys-layout-container-md);
5804
5985
  top: 0;
5805
5986
  height: var(--sys-borderWidth-hairline);
5806
- background: var(--sys-color-outlineVariant);
5987
+ background: var(--sys-color-border-default);
5807
5988
  pointer-events: none;
5808
5989
  }
5809
5990
 
@@ -5845,7 +6026,7 @@ a.chorus-metadata__name:focus-visible {
5845
6026
  line-height: var(--sys-typo-body-sm-line);
5846
6027
  font-weight: var(--sys-typo-body-sm-weight);
5847
6028
  letter-spacing: var(--sys-typo-body-sm-tracking);
5848
- color: var(--sys-color-onSurfaceVariant);
6029
+ color: var(--sys-color-text-subtle);
5849
6030
  }
5850
6031
 
5851
6032
  @media (prefers-reduced-motion: reduce) {