@teamblind-chorus/ui 1.2.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 (141) 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 +4 -4
  6. package/agents/components/avatar-rail/avatar-rail.md +2 -4
  7. package/agents/components/avatar-rail/avatar-rail.spec.json +10 -14
  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.md +16 -18
  13. package/agents/components/banner/banner.spec.json +14 -14
  14. package/agents/components/bottom-sheet/bottom-sheet.md +4 -6
  15. package/agents/components/bottom-sheet/bottom-sheet.spec.json +5 -5
  16. package/agents/components/bubble/bubble.md +8 -10
  17. package/agents/components/bubble/bubble.spec.json +11 -11
  18. package/agents/components/button/button.md +1 -1
  19. package/agents/components/button/check.md +9 -11
  20. package/agents/components/button/check.spec.json +8 -10
  21. package/agents/components/button/fab.md +7 -9
  22. package/agents/components/button/fab.spec.json +10 -12
  23. package/agents/components/button/group.spec.json +4 -4
  24. package/agents/components/button/icon.md +21 -23
  25. package/agents/components/button/icon.spec.json +12 -14
  26. package/agents/components/button/standard.md +40 -42
  27. package/agents/components/button/standard.spec.json +20 -22
  28. package/agents/components/button/text.md +21 -23
  29. package/agents/components/button/text.spec.json +13 -15
  30. package/agents/components/button/toggle.md +7 -9
  31. package/agents/components/button/toggle.spec.json +10 -12
  32. package/agents/components/button/toolbar.md +24 -26
  33. package/agents/components/button/toolbar.spec.json +10 -12
  34. package/agents/components/carousel/carousel.md +1 -1
  35. package/agents/components/carousel/post.md +15 -21
  36. package/agents/components/carousel/post.spec.json +17 -17
  37. package/agents/components/carousel/profile.md +9 -45
  38. package/agents/components/carousel/profile.spec.json +17 -17
  39. package/agents/components/chip/chip.md +1 -1
  40. package/agents/components/chip/filter.md +22 -24
  41. package/agents/components/chip/filter.spec.json +17 -13
  42. package/agents/components/chip/tag.md +22 -24
  43. package/agents/components/chip/tag.spec.json +19 -15
  44. package/agents/components/dialog/dialog.md +1 -3
  45. package/agents/components/dialog/dialog.spec.json +3 -3
  46. package/agents/components/directory-list/directory-list.md +1 -3
  47. package/agents/components/directory-list/directory-list.spec.json +2 -2
  48. package/agents/components/divider/divider.family.json +1 -1
  49. package/agents/components/divider/divider.md +12 -14
  50. package/agents/components/divider/divider.spec.json +8 -8
  51. package/agents/components/empty-state/empty-state.md +9 -9
  52. package/agents/components/empty-state/empty-state.spec.json +14 -14
  53. package/agents/components/feed/ad.md +2 -4
  54. package/agents/components/feed/ad.spec.json +10 -10
  55. package/agents/components/feed/post.md +41 -43
  56. package/agents/components/feed/post.spec.json +35 -39
  57. package/agents/components/form-field/form-field.md +1 -1
  58. package/agents/components/form-field/input.md +32 -34
  59. package/agents/components/form-field/input.spec.json +34 -33
  60. package/agents/components/form-field/search.md +2 -4
  61. package/agents/components/form-field/search.spec.json +19 -18
  62. package/agents/components/form-field/select.md +18 -20
  63. package/agents/components/form-field/select.spec.json +30 -29
  64. package/agents/components/form-field/textarea.md +3 -5
  65. package/agents/components/form-field/textarea.spec.json +32 -31
  66. package/agents/components/header/main.md +4 -6
  67. package/agents/components/header/main.spec.json +3 -3
  68. package/agents/components/header/sub.md +6 -8
  69. package/agents/components/header/sub.spec.json +3 -3
  70. package/agents/components/list/accordion.md +34 -45
  71. package/agents/components/list/accordion.spec.json +20 -20
  72. package/agents/components/list/entry.md +59 -81
  73. package/agents/components/list/entry.spec.json +20 -23
  74. package/agents/components/list/list.md +2 -2
  75. package/agents/components/list/radio.md +13 -20
  76. package/agents/components/list/radio.spec.json +16 -20
  77. package/agents/components/list/standard.md +50 -72
  78. package/agents/components/list/standard.spec.json +18 -21
  79. package/agents/components/metadata/compact.md +4 -6
  80. package/agents/components/metadata/compact.spec.json +6 -6
  81. package/agents/components/metadata/metadata.md +1 -1
  82. package/agents/components/metadata/standard.md +12 -14
  83. package/agents/components/metadata/standard.spec.json +10 -10
  84. package/agents/components/nav-card/nav-card.md +25 -27
  85. package/agents/components/nav-card/nav-card.spec.json +19 -19
  86. package/agents/components/nav-list/nav-list.md +2 -8
  87. package/agents/components/nav-list/nav-list.spec.json +3 -3
  88. package/agents/components/navigation-bar/main.md +9 -11
  89. package/agents/components/navigation-bar/main.spec.json +6 -6
  90. package/agents/components/navigation-bar/search.md +6 -8
  91. package/agents/components/navigation-bar/search.spec.json +9 -9
  92. package/agents/components/navigation-bar/sub.md +9 -11
  93. package/agents/components/navigation-bar/sub.spec.json +7 -7
  94. package/agents/components/pagination/pagination.family.json +1 -1
  95. package/agents/components/pagination/pagination.md +3 -3
  96. package/agents/components/pagination/pagination.spec.json +5 -5
  97. package/agents/components/profile-header/profile-header.md +9 -11
  98. package/agents/components/profile-header/profile-header.spec.json +9 -9
  99. package/agents/components/progress/progress.family.json +1 -1
  100. package/agents/components/progress/progress.md +5 -5
  101. package/agents/components/progress/progress.spec.json +8 -8
  102. package/agents/components/side-sheet/side-sheet.md +11 -13
  103. package/agents/components/side-sheet/side-sheet.spec.json +3 -3
  104. package/agents/components/skeleton/skeleton.md +7 -9
  105. package/agents/components/skeleton/skeleton.spec.json +5 -5
  106. package/agents/components/spinner/spinner.family.json +1 -1
  107. package/agents/components/spinner/spinner.md +8 -10
  108. package/agents/components/spinner/spinner.spec.json +9 -9
  109. package/agents/components/status-tag/status-tag.md +7 -9
  110. package/agents/components/status-tag/status-tag.spec.json +5 -5
  111. package/agents/components/suggestion-list/suggestion-list.md +3 -7
  112. package/agents/components/suggestion-list/suggestion-list.spec.json +8 -12
  113. package/agents/components/switch/switch.md +12 -14
  114. package/agents/components/switch/switch.spec.json +17 -18
  115. package/agents/components/tab-bar/tab-bar.md +9 -11
  116. package/agents/components/tab-bar/tab-bar.spec.json +25 -27
  117. package/agents/components/tabs/rounded.md +6 -8
  118. package/agents/components/tabs/rounded.spec.json +17 -15
  119. package/agents/components/tabs/segmented.md +4 -6
  120. package/agents/components/tabs/segmented.spec.json +4 -8
  121. package/agents/components/tabs/underline.md +9 -11
  122. package/agents/components/tabs/underline.spec.json +14 -16
  123. package/agents/components/thumbnail/thumbnail.md +5 -7
  124. package/agents/components/thumbnail/thumbnail.spec.json +8 -8
  125. package/agents/components/toast/toast.md +5 -7
  126. package/agents/components/toast/toast.spec.json +3 -3
  127. package/agents/components/tooltip/tooltip.md +6 -8
  128. package/agents/components/tooltip/tooltip.spec.json +4 -4
  129. package/agents/tokens.usage.json +71 -226
  130. package/dist/index.cjs +212 -223
  131. package/dist/index.cjs.map +1 -1
  132. package/dist/index.d.cts +16 -16
  133. package/dist/index.d.ts +16 -16
  134. package/dist/index.js +212 -223
  135. package/dist/index.js.map +1 -1
  136. package/dist/styles.css +386 -387
  137. package/eslint/rules.js +7 -7
  138. package/package.json +2 -3
  139. package/agents/anti-patterns.md +0 -533
  140. package/agents/compose.md +0 -240
  141. package/agents/images.md +0 -66
package/dist/index.js CHANGED
@@ -5,11 +5,11 @@ import { createPortal } from 'react-dom';
5
5
  // ../../schema/components/badge/update.spec.json
6
6
  var update_spec_default = {
7
7
  appearance: {
8
- background: "sys.color.brand",
9
- label: "sys.color.onBrand",
8
+ background: "sys.color.text.brand",
9
+ label: "sys.color.text.onFill",
10
10
  radius: "sys.radius.full",
11
11
  dotOutline: {
12
- color: "sys.color.surface",
12
+ color: "sys.color.surface.default",
13
13
  width: "sys.borderWidth.thin",
14
14
  rendering: "box-shadow",
15
15
  note: "Update Dot rungs paint a 2px `surface`-color outline as a `box-shadow` so the dot stays a discrete chip on any host (image, icon, row) without enlarging its bounding box. The outline carves the dot out of whatever sits beside it; without it the brand fill blends into surrounding fills with similar luminance."
@@ -28,7 +28,7 @@ var update_spec_default = {
28
28
  minWidth: "ref.space.200",
29
29
  paddingBlock: "0",
30
30
  paddingInline: "sys.layout.container.2xs",
31
- labelTypo: "sys.typo.caption"
31
+ labelTypo: "sys.typo.label.xs"
32
32
  },
33
33
  "dot-md": {
34
34
  minHeight: "ref.space.100",
@@ -52,15 +52,15 @@ var update_spec_default = {
52
52
  var role_spec_default = {
53
53
  appearances: {
54
54
  default: {
55
- background: "sys.color.primaryContainer",
56
- label: "sys.color.onPrimaryContainer",
55
+ background: "sys.color.background.selected",
56
+ label: "sys.color.text.link",
57
57
  radius: "sys.radius.full",
58
58
  default: true,
59
59
  note: "Tonal informational pair \u2014 pale primary container fill with the deep primary-container label. Theme-aware sys tokens, so no separate dark binding. Never the brand pair: brand is reserved for the Update sub's activity marker, and a brand-filled role mark would read as an alert, not an identity."
60
60
  },
61
61
  inverse: {
62
- background: "sys.color.inverseSurface",
63
- label: "sys.color.inverseOnSurface",
62
+ background: "sys.color.background.inverse",
63
+ label: "sys.color.text.inverse",
64
64
  radius: "sys.radius.full",
65
65
  note: "Inverse pair \u2014 the strongest mark in the row: near-black pill with light label (theme-aware; flips in dark mode). Reserved for the PRO mark on paid professional users. Same geometry as default; only the fill pair changes."
66
66
  }
@@ -71,7 +71,7 @@ var role_spec_default = {
71
71
  minWidth: "ref.space.200",
72
72
  paddingBlock: "ref.space.25",
73
73
  paddingInline: "ref.space.75",
74
- labelTypo: "sys.typo.caption",
74
+ labelTypo: "sys.typo.label.xs",
75
75
  labelLineHeight: "1.2",
76
76
  note: "Single 16-rung (`ref.space.200`) \u2014 sized to ride inline beside `caption`/`label` metadata text without stretching the row. 2 \xD7 6 padding (`ref.space.25` \xD7 `ref.space.75`); the reference steps bind raw where `sys.*` exposes no step, in lockstep with the Update sub's rungs. Label line-height is the structural `1.2` (same device as StatusTag): 10px \xD7 1.2 + 2 \xD7 2px padding = exactly 16px \u2014 `caption`'s 15px running-text line would push the pill to 19."
77
77
  }
@@ -327,27 +327,27 @@ var standard_spec_default = {
327
327
  },
328
328
  appearances: {
329
329
  primary: {
330
- background: "sys.color.primary",
330
+ background: "sys.color.background.primary",
331
331
  border: null,
332
- label: "sys.color.onPrimary"
332
+ label: "sys.color.text.onFill"
333
333
  },
334
334
  secondary: {
335
- background: "sys.color.secondaryContainer",
335
+ background: "sys.color.background.neutral",
336
336
  border: null,
337
- label: "sys.color.onSecondaryContainer"
337
+ label: "sys.color.text.default"
338
338
  },
339
339
  outlined: {
340
340
  background: "transparent",
341
341
  border: {
342
342
  width: "sys.borderWidth.hairline",
343
- color: "sys.color.primary"
343
+ color: "sys.color.text.link"
344
344
  },
345
- label: "sys.color.primary"
345
+ label: "sys.color.text.link"
346
346
  },
347
347
  tertiary: {
348
348
  background: "transparent",
349
349
  border: null,
350
- label: "sys.color.onSurfaceVariant"
350
+ label: "sys.color.text.subtle"
351
351
  }
352
352
  },
353
353
  states: {
@@ -369,10 +369,7 @@ var standard_spec_default = {
369
369
  opacity: "sys.state.focus"
370
370
  },
371
371
  ring: {
372
- outerWidth: "sys.borderWidth.thin",
373
- outerColor: "sys.color.focus",
374
- insetWidth: "sys.borderWidth.hairline",
375
- insetColor: "sys.color.focusInset"
372
+ color: "sys.color.border.focused"
376
373
  }}};
377
374
  function sizeStyle(size) {
378
375
  const s2 = standard_spec_default.sizes[size] ?? standard_spec_default.sizes[standard_spec_default.props.size.default];
@@ -402,10 +399,7 @@ function stateStyle() {
402
399
  "--button-standard-overlay-pressed": tokenToCss(standard_spec_default.states.pressed.overlay.opacity),
403
400
  "--button-standard-overlay-focus": tokenToCss(standard_spec_default.focusIndicator.overlay.opacity),
404
401
  "--button-standard-disabled-opacity": tokenToCss(standard_spec_default.states.disabled.containerOpacity),
405
- "--button-standard-focus-outer-width": tokenToCss(standard_spec_default.focusIndicator.ring.outerWidth),
406
- "--button-standard-focus-outer-color": tokenToCss(standard_spec_default.focusIndicator.ring.outerColor),
407
- "--button-standard-focus-inset-width": tokenToCss(standard_spec_default.focusIndicator.ring.insetWidth),
408
- "--button-standard-focus-inset-color": tokenToCss(standard_spec_default.focusIndicator.ring.insetColor)
402
+ "--button-standard-focus-outer-color": tokenToCss(standard_spec_default.focusIndicator.ring.color)
409
403
  };
410
404
  }
411
405
  var FORCEABLE_STATES = /* @__PURE__ */ new Set(["hovered", "pressed", "focused"]);
@@ -473,12 +467,12 @@ var fab_spec_default = {
473
467
  },
474
468
  appearances: {
475
469
  primary: {
476
- background: "sys.color.brand",
477
- label: "sys.color.onBrand"
470
+ background: "sys.color.text.brand",
471
+ label: "sys.color.text.onFill"
478
472
  },
479
473
  secondary: {
480
- background: "sys.color.surfaceContainerHigh",
481
- label: "sys.color.onSurface"
474
+ background: "sys.color.surface.default",
475
+ label: "sys.color.text.default"
482
476
  }
483
477
  },
484
478
  states: {
@@ -497,10 +491,7 @@ var fab_spec_default = {
497
491
  opacity: "sys.state.focus"
498
492
  },
499
493
  ring: {
500
- outerWidth: "sys.borderWidth.thin",
501
- outerColor: "sys.color.focus",
502
- insetWidth: "sys.borderWidth.hairline",
503
- insetColor: "sys.color.focusInset"
494
+ color: "sys.color.border.focused"
504
495
  }}};
505
496
  var FORCEABLE_STATES2 = /* @__PURE__ */ new Set(["hovered", "pressed", "focused"]);
506
497
  function appearanceStyle3(appearance) {
@@ -521,10 +512,7 @@ var sizingStyle2 = () => ({
521
512
  "--button-fab-overlay-hover": tokenToCss(fab_spec_default.states.hovered.overlay.opacity),
522
513
  "--button-fab-overlay-pressed": tokenToCss(fab_spec_default.states.pressed.overlay.opacity),
523
514
  "--button-fab-overlay-focus": tokenToCss(fab_spec_default.focusIndicator.overlay.opacity),
524
- "--button-fab-focus-outer-width": tokenToCss(fab_spec_default.focusIndicator.ring.outerWidth),
525
- "--button-fab-focus-outer-color": tokenToCss(fab_spec_default.focusIndicator.ring.outerColor),
526
- "--button-fab-focus-inset-width": tokenToCss(fab_spec_default.focusIndicator.ring.insetWidth),
527
- "--button-fab-focus-inset-color": tokenToCss(fab_spec_default.focusIndicator.ring.insetColor),
515
+ "--button-fab-focus-outer-color": tokenToCss(fab_spec_default.focusIndicator.ring.color),
528
516
  ...typoStyles(fab_spec_default.sizing.labelTypo)
529
517
  });
530
518
  function ButtonFab({
@@ -1562,16 +1550,16 @@ var filter_spec_default = {
1562
1550
  selectionStates: {
1563
1551
  unselected: {
1564
1552
  background: "transparent",
1565
- label: "sys.color.onSurface",
1553
+ label: "sys.color.text.default",
1566
1554
  border: {
1567
1555
  width: "sys.borderWidth.hairline",
1568
- color: "sys.color.outlineVariant"
1556
+ color: "sys.color.border.default"
1569
1557
  },
1570
1558
  note: "Transparent fill so the chip adopts whatever surface sits behind it (page, raised card, sheet) without pinning to a fixed neutral step."
1571
1559
  },
1572
1560
  selected: {
1573
- background: "sys.color.inverseSurface",
1574
- label: "sys.color.inverseOnSurface",
1561
+ background: "sys.color.background.inverse",
1562
+ label: "sys.color.text.inverse",
1575
1563
  border: null
1576
1564
  }
1577
1565
  },
@@ -1601,35 +1589,39 @@ var filter_spec_default = {
1601
1589
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
1602
1590
  innerCounterRing: {
1603
1591
  width: "sys.borderWidth.hairline",
1604
- color: "sys.color.focusInset"
1592
+ color: "sys.color.border.focused"
1605
1593
  },
1606
1594
  outerRing: {
1607
1595
  width: "sys.borderWidth.thin",
1608
- color: "sys.color.focus"
1596
+ color: "sys.color.border.focused"
1609
1597
  }
1610
1598
  },
1611
1599
  note: "Keyboard-focus (:focus-visible) visual. Mirrors the `focusIndicator` block (the external-reader contract); kept here so spec-only renderers see focus in the states map. Composes over the lifecycle state the chip is in; never via plain mouse click."
1612
1600
  },
1613
1601
  disabled: {
1614
1602
  overlay: null,
1615
- containerOpacity: "sys.state.disabled",
1603
+ background: "sys.color.background.disabled",
1604
+ label: "sys.color.text.disabled",
1605
+ border: {
1606
+ width: "sys.borderWidth.hairline",
1607
+ color: "sys.color.border.bold"
1608
+ },
1616
1609
  suppressFocusRing: true,
1617
- cursor: "not-allowed"
1610
+ cursor: "not-allowed",
1611
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border so the shape reads on any surface, plus disabled label. Overrides the rest/selected appearance."
1618
1612
  }
1619
1613
  },
1620
1614
  focusIndicator: {
1621
1615
  description: "Keyboard-focus visual \u2014 an accessibility indicator, not a lifecycle state. Composes over whichever lifecycle state the chip is in. The `states.focused` block above is kept for JSX runtime consumers; this block is the parallel external-reader contract.",
1622
1616
  composition: "outward",
1623
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
1617
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
1624
1618
  overlay: {
1625
1619
  color: "label",
1626
1620
  opacity: "sys.state.focus"
1627
1621
  },
1628
1622
  ring: {
1629
- outerWidth: "sys.borderWidth.thin",
1630
- outerColor: "sys.color.focus",
1631
- insetWidth: "sys.borderWidth.hairline",
1632
- insetColor: "sys.color.focusInset"
1623
+ width: "sys.borderWidth.hairline",
1624
+ color: "sys.color.border.focused"
1633
1625
  },
1634
1626
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
1635
1627
  },
@@ -1647,7 +1639,7 @@ var tag_spec_default = {
1647
1639
  name: "Chip",
1648
1640
  family: "chip",
1649
1641
  subcomponent: "tag",
1650
- description: "Informational chip. Square-cornered metadata label. Passive (or dismissable via trailing \xD7). No leading icon. Two appearances: `default` paints the translucent `sys.color.scrimSubtle` scrim (~8% inverse-tone overlay \u2014 black in light, white in dark) so the tag adopts whatever surface sits behind it; `accent` paints a tonal pale-primary container (`sys.color.primaryContainer`) with primary label for tags that need to pop against the surface.",
1642
+ description: "Informational chip. Square-cornered metadata label. Passive (or dismissable via trailing \xD7). No leading icon. Two appearances: `default` paints the translucent `sys.color.background.neutral` scrim (~8% inverse-tone overlay \u2014 black in light, white in dark) so the tag adopts whatever surface sits behind it; `accent` paints a tonal pale-primary container (`sys.color.background.selected`) with primary label for tags that need to pop against the surface.",
1651
1643
  element: "span",
1652
1644
  props: {
1653
1645
  variant: {
@@ -1688,15 +1680,15 @@ var tag_spec_default = {
1688
1680
  },
1689
1681
  appearances: {
1690
1682
  default: {
1691
- background: "sys.color.scrimSubtle",
1692
- label: "sys.color.onSurface",
1683
+ background: "sys.color.background.neutral",
1684
+ label: "sys.color.text.default",
1693
1685
  border: null,
1694
1686
  default: true,
1695
- note: "Background is the translucent inverse-tone scrim (`sys.color.scrimSubtle` \u2014 black 8% in light mode, white 8% in dark) so the tag harmonises with whatever surface sits behind it \u2014 body, raised card, BottomSheet \u2014 instead of pinning to a fixed neutral step. Same Banner-style fill used by Progress track, StatusTag neutral, and Skeleton; sys-color is theme-aware so a single token resolves correctly in both modes."
1687
+ note: "Background is the translucent inverse-tone scrim (`sys.color.background.neutral` \u2014 black 8% in light mode, white 8% in dark) so the tag harmonises with whatever surface sits behind it \u2014 body, raised card, BottomSheet \u2014 instead of pinning to a fixed neutral step. Same Banner-style fill used by Progress track, StatusTag neutral, and Skeleton; sys-color is theme-aware so a single token resolves correctly in both modes."
1696
1688
  },
1697
1689
  accent: {
1698
- background: "sys.color.primaryContainer",
1699
- label: "sys.color.primary",
1690
+ background: "sys.color.background.selected",
1691
+ label: "sys.color.text.link",
1700
1692
  border: null,
1701
1693
  note: "Tonal accent: pale primary container background with primary label. Sys-color tokens are theme-aware, so no separate dark binding is needed \u2014 the resolved tokens pick the right values per theme. Use for tags that should pop against the surface (e.g. Popular Tags in compose, highlighted hashtags) where the default overlay is too quiet."
1702
1694
  }
@@ -1727,35 +1719,39 @@ var tag_spec_default = {
1727
1719
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
1728
1720
  innerCounterRing: {
1729
1721
  width: "sys.borderWidth.hairline",
1730
- color: "sys.color.focusInset"
1722
+ color: "sys.color.border.focused"
1731
1723
  },
1732
1724
  outerRing: {
1733
1725
  width: "sys.borderWidth.thin",
1734
- color: "sys.color.focus"
1726
+ color: "sys.color.border.focused"
1735
1727
  }
1736
1728
  },
1737
1729
  note: "Keyboard-focus (:focus-visible) visual. Mirrors the `focusIndicator` block (the external-reader contract); kept here so spec-only renderers see focus in the states map. Composes over the lifecycle state the chip is in; never via plain mouse click."
1738
1730
  },
1739
1731
  disabled: {
1740
1732
  overlay: null,
1741
- containerOpacity: "sys.state.disabled",
1733
+ background: "sys.color.background.disabled",
1734
+ label: "sys.color.text.disabled",
1735
+ border: {
1736
+ width: "sys.borderWidth.hairline",
1737
+ color: "sys.color.border.bold"
1738
+ },
1742
1739
  suppressFocusRing: true,
1743
- cursor: "not-allowed"
1740
+ cursor: "not-allowed",
1741
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border so the shape reads on any surface, plus disabled label. Overrides the rest/selected appearance."
1744
1742
  }
1745
1743
  },
1746
1744
  focusIndicator: {
1747
1745
  description: "Keyboard-focus visual \u2014 an accessibility indicator, not a lifecycle state. Composes over whichever lifecycle state the chip is in. Applies only when the chip is interactive (a dismiss trailingIcon is present). The `states.focused` block above is kept for JSX runtime consumers; this block is the parallel external-reader contract.",
1748
1746
  composition: "outward",
1749
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
1747
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
1750
1748
  overlay: {
1751
1749
  color: "label",
1752
1750
  opacity: "sys.state.focus"
1753
1751
  },
1754
1752
  ring: {
1755
- outerWidth: "sys.borderWidth.thin",
1756
- outerColor: "sys.color.focus",
1757
- insetWidth: "sys.borderWidth.hairline",
1758
- insetColor: "sys.color.focusInset"
1753
+ width: "sys.borderWidth.hairline",
1754
+ color: "sys.color.border.focused"
1759
1755
  },
1760
1756
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
1761
1757
  },
@@ -1832,16 +1828,16 @@ var toggle_spec_default = {
1832
1828
  },
1833
1829
  selectionStates: {
1834
1830
  unselected: {
1835
- background: "sys.color.primary",
1836
- label: "sys.color.onPrimary",
1831
+ background: "sys.color.background.primary",
1832
+ label: "sys.color.text.onFill",
1837
1833
  border: null
1838
1834
  },
1839
1835
  selected: {
1840
1836
  background: "transparent",
1841
- label: "sys.color.onSurface",
1837
+ label: "sys.color.text.default",
1842
1838
  border: {
1843
1839
  width: "sys.borderWidth.hairline",
1844
- color: "sys.color.outlineVariant"
1840
+ color: "sys.color.border.default"
1845
1841
  }
1846
1842
  }
1847
1843
  },
@@ -1871,11 +1867,11 @@ var toggle_spec_default = {
1871
1867
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
1872
1868
  innerCounterRing: {
1873
1869
  width: "sys.borderWidth.hairline",
1874
- color: "sys.color.focusInset"
1870
+ color: "sys.color.border.focused"
1875
1871
  },
1876
1872
  outerRing: {
1877
1873
  width: "sys.borderWidth.thin",
1878
- color: "sys.color.focus"
1874
+ color: "sys.color.border.focused"
1879
1875
  }
1880
1876
  },
1881
1877
  note: "Keyboard-focus (:focus-visible) visual. Mirrors the `focusIndicator` block (the external-reader contract); kept here so spec-only renderers see focus in the states map. Composes over the lifecycle state the button is in; never via plain mouse click."
@@ -1890,21 +1886,19 @@ var toggle_spec_default = {
1890
1886
  focusIndicator: {
1891
1887
  description: "Keyboard-focus visual \u2014 an accessibility indicator, not a lifecycle state. Composes over whichever lifecycle state the button is in. The `states.focused` block above is kept for JSX runtime consumers; this block is the parallel external-reader contract.",
1892
1888
  composition: "outward",
1893
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
1889
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
1894
1890
  overlay: {
1895
1891
  color: "label",
1896
1892
  opacity: "sys.state.focus"
1897
1893
  },
1898
1894
  ring: {
1899
- outerWidth: "sys.borderWidth.thin",
1900
- outerColor: "sys.color.focus",
1901
- insetWidth: "sys.borderWidth.hairline",
1902
- insetColor: "sys.color.focusInset"
1895
+ width: "sys.borderWidth.hairline",
1896
+ color: "sys.color.border.focused"
1903
1897
  },
1904
1898
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
1905
1899
  },
1906
1900
  forbidden: [
1907
- "active state painted with sys.color.primary fill \u2014 active is transparent + hairline outline (the active state recedes, not asserts)",
1901
+ "active state painted with sys.color.background.primary fill \u2014 active is transparent + hairline outline (the active state recedes, not asserts)",
1908
1902
  "active state painted with any opaque surface fill (surface, surfaceContainer, surfaceContainerHigh) \u2014 the committed form is transparent so the host surface shows through; do not re-bind to a tier'd fill",
1909
1903
  "rest state without an explicit `active={false}` \u2014 toggle is a binary contract, never tristate",
1910
1904
  "manual width override that breaks the full-card stretch when used inside ProfileCarousel.followAction"
@@ -1951,10 +1945,7 @@ function sizingStyle3(spec) {
1951
1945
  "--chip-overlay-pressed": tokenToCss(spec.states.pressed.overlay.opacity),
1952
1946
  "--chip-overlay-focus": tokenToCss(spec.focusIndicator.overlay.opacity),
1953
1947
  "--chip-disabled-opacity": tokenToCss(spec.states.disabled.containerOpacity),
1954
- "--chip-focus-outer-width": tokenToCss(spec.focusIndicator.ring.outerWidth),
1955
- "--chip-focus-outer-color": tokenToCss(spec.focusIndicator.ring.outerColor),
1956
- "--chip-focus-inset-width": tokenToCss(spec.focusIndicator.ring.insetWidth),
1957
- "--chip-focus-inset-color": tokenToCss(spec.focusIndicator.ring.insetColor),
1948
+ "--chip-focus-outer-color": tokenToCss(spec.focusIndicator.ring.color),
1958
1949
  ...typoStyles(spec.sizing.labelTypo)
1959
1950
  };
1960
1951
  }
@@ -2030,14 +2021,14 @@ function ButtonToolbar({ appearance = "default", className, style, ...rest }) {
2030
2021
  let pairStyle = null;
2031
2022
  if (appearance === "accent") {
2032
2023
  pairStyle = {
2033
- "--chip-bg": "var(--sys-color-primary)",
2034
- "--chip-label": "var(--sys-color-onPrimary)",
2024
+ "--chip-bg": "var(--sys-color-background-primary)",
2025
+ "--chip-label": "var(--sys-color-text-onFill)",
2035
2026
  "--chip-border-color": "transparent"
2036
2027
  };
2037
2028
  } else if (appearance === "inverse") {
2038
2029
  pairStyle = {
2039
- "--chip-bg": "var(--sys-color-inverseSurface)",
2040
- "--chip-label": "var(--sys-color-inverseOnSurface)",
2030
+ "--chip-bg": "var(--sys-color-background-inverse)",
2031
+ "--chip-label": "var(--sys-color-text-inverse)",
2041
2032
  "--chip-border-color": "transparent"
2042
2033
  };
2043
2034
  }
@@ -2946,12 +2937,12 @@ function Divider({
2946
2937
  var empty_state_spec_default = {
2947
2938
  sizing: {
2948
2939
  illustrationSize: "ref.space.600",
2949
- illustrationColor: "sys.color.onSurfaceVariant",
2940
+ illustrationColor: "sys.color.text.subtle",
2950
2941
  illustrationGap: "sys.layout.stack.sm",
2951
2942
  headlineTypo: "sys.typo.heading.sm",
2952
- headlineColor: "sys.color.onSurface",
2943
+ headlineColor: "sys.color.text.default",
2953
2944
  bodyTypo: "sys.typo.body.sm",
2954
- bodyColor: "sys.color.onSurfaceVariant",
2945
+ bodyColor: "sys.color.text.subtle",
2955
2946
  bodyGap: "sys.layout.stack.2xs",
2956
2947
  actionGap: "sys.layout.stack.md"
2957
2948
  }};
@@ -3041,17 +3032,17 @@ var underline_spec_default = {
3041
3032
  slotGap: "sys.layout.inline.sm",
3042
3033
  indicatorHeight: "sys.borderWidth.thin",
3043
3034
  dividerWidth: "sys.borderWidth.hairline",
3044
- dividerColor: "sys.color.outlineVariant",
3035
+ dividerColor: "sys.color.border.default",
3045
3036
  labelTypo: "sys.typo.label.md",
3046
3037
  iconSize: "sys.icon.md",
3047
3038
  fadeWidth: "ref.space.600"
3048
3039
  },
3049
3040
  selectionStates: {
3050
3041
  unselected: {
3051
- label: "sys.color.outline"},
3042
+ label: "sys.color.text.subtle"},
3052
3043
  selected: {
3053
- label: "sys.color.onSurface",
3054
- indicator: "sys.color.onSurface"
3044
+ label: "sys.color.text.default",
3045
+ indicator: "sys.color.border.selected"
3055
3046
  }
3056
3047
  },
3057
3048
  states: {
@@ -3066,17 +3057,14 @@ var underline_spec_default = {
3066
3057
  }
3067
3058
  },
3068
3059
  disabled: {
3069
- containerOpacity: "sys.state.disabled"}
3060
+ }
3070
3061
  },
3071
3062
  focusIndicator: {
3072
3063
  overlay: {
3073
3064
  opacity: "sys.state.focus"
3074
3065
  },
3075
3066
  ring: {
3076
- outerWidth: "sys.borderWidth.thin",
3077
- outerColor: "sys.color.focus",
3078
- insetWidth: "sys.borderWidth.hairline",
3079
- insetColor: "sys.color.focusInset"}}};
3067
+ color: "sys.color.border.focused"}}};
3080
3068
  function useSlidingIndicator(containerRef, indicatorRef, value) {
3081
3069
  useLayoutEffect(() => {
3082
3070
  const container = containerRef.current;
@@ -3157,10 +3145,7 @@ function TabsUnderline({ className, style, children, ...rest }) {
3157
3145
  "--tabs-overlay-pressed": tokenToCss(underline_spec_default.states.pressed.overlay.opacity),
3158
3146
  "--tabs-overlay-focus": tokenToCss(underline_spec_default.focusIndicator.overlay.opacity),
3159
3147
  "--tabs-disabled-opacity": tokenToCss(underline_spec_default.states.disabled.containerOpacity),
3160
- "--tabs-focus-outer-width": tokenToCss(underline_spec_default.focusIndicator.ring.outerWidth),
3161
- "--tabs-focus-outer-color": tokenToCss(underline_spec_default.focusIndicator.ring.outerColor),
3162
- "--tabs-focus-inset-width": tokenToCss(underline_spec_default.focusIndicator.ring.insetWidth),
3163
- "--tabs-focus-inset-color": tokenToCss(underline_spec_default.focusIndicator.ring.insetColor),
3148
+ "--tabs-focus-outer-color": tokenToCss(underline_spec_default.focusIndicator.ring.color),
3164
3149
  ...typoStyles(s2.labelTypo),
3165
3150
  ...style
3166
3151
  };
@@ -3896,9 +3881,9 @@ function Card({ item, innerRef, index }) {
3896
3881
  }
3897
3882
  var MAX_CARDS2 = 5;
3898
3883
  var METRIC_KINDS = {
3899
- star: { Icon: StarFillIcon, tone: "var(--sys-color-icon-yellow)" },
3900
- pulse: { Icon: PulseFillIcon, tone: "var(--sys-color-success)" },
3901
- heart: { Icon: HeartFillIcon, tone: "var(--sys-color-icon-red)" }
3884
+ star: { Icon: StarFillIcon, tone: "var(--sys-color-icon-accent-yellow-default)" },
3885
+ pulse: { Icon: PulseFillIcon, tone: "var(--sys-color-icon-success)" },
3886
+ heart: { Icon: HeartFillIcon, tone: "var(--sys-color-icon-accent-red-default)" }
3902
3887
  };
3903
3888
  var PLACEHOLDER_IMAGE = "/placeholder.png";
3904
3889
  function ProfileCarousel({
@@ -4452,7 +4437,7 @@ var input_spec_default = {
4452
4437
  helper: {
4453
4438
  type: "node",
4454
4439
  optional: true,
4455
- description: "Assistive text rendered below the field box, left-aligned. **Optional on every appearance** \u2014 omit the prop to render the field without an assistive rung; the box and label keep their footprint. On the `error` appearance the helper re-tones to `sys.color.error` so the message reads as the error caption; an error field may still be shown without a helper, in which case only the field box re-tones. Mutually exclusive with `maxLength` \u2014 if both are given, the character count is shown and `helper` is ignored."
4440
+ description: "Assistive text rendered below the field box, left-aligned. **Optional on every appearance** \u2014 omit the prop to render the field without an assistive rung; the box and label keep their footprint. On the `error` appearance the helper re-tones to `sys.color.text.danger` so the message reads as the error caption; an error field may still be shown without a helper, in which case only the field box re-tones. Mutually exclusive with `maxLength` \u2014 if both are given, the character count is shown and `helper` is ignored."
4456
4441
  },
4457
4442
  maxLength: {
4458
4443
  type: "number",
@@ -4472,7 +4457,7 @@ var input_spec_default = {
4472
4457
  },
4473
4458
  label: {
4474
4459
  required: false,
4475
- description: "Visible label above the box. `sys.typo.label.md`, `sys.color.onSurface`. Associated with the input via `htmlFor`.",
4460
+ description: "Visible label above the box. `sys.typo.label.md`, `sys.color.text.default`. Associated with the input via `htmlFor`.",
4476
4461
  accepts: [
4477
4462
  "text"
4478
4463
  ]
@@ -4496,14 +4481,14 @@ var input_spec_default = {
4496
4481
  },
4497
4482
  helper: {
4498
4483
  required: false,
4499
- description: "Assistive text below the box, left-aligned. `sys.typo.body.sm`, `sys.color.onSurfaceVariant`; on the `error` appearance the colour re-tones to `sys.color.error` so the message reads as the error caption. Referenced by the input's `aria-describedby`. Not rendered when a `maxLength` count is present, and intentionally omittable on every appearance (including `error`) \u2014 pass nothing and the field renders without an assistive rung.",
4484
+ description: "Assistive text below the box, left-aligned. `sys.typo.body.sm`, `sys.color.text.subtle`; on the `error` appearance the colour re-tones to `sys.color.text.danger` so the message reads as the error caption. Referenced by the input's `aria-describedby`. Not rendered when a `maxLength` count is present, and intentionally omittable on every appearance (including `error`) \u2014 pass nothing and the field renders without an assistive rung.",
4500
4485
  accepts: [
4501
4486
  "text"
4502
4487
  ]
4503
4488
  },
4504
4489
  count: {
4505
4490
  required: false,
4506
- description: '`current/max` character count below the box, right-aligned, present when `maxLength` is set. `sys.typo.body.sm`, `sys.color.onSurfaceVariant`; the current-count number is `sys.typo.label.md` weight in `sys.color.onSurface`. Referenced by the input\'s `aria-describedby`; updates `aria-live="polite"`.',
4491
+ description: '`current/max` character count below the box, right-aligned, present when `maxLength` is set. `sys.typo.body.sm`, `sys.color.text.subtle`; the current-count number is `sys.typo.label.md` weight in `sys.color.text.default`. Referenced by the input\'s `aria-describedby`; updates `aria-live="polite"`.',
4507
4492
  accepts: [
4508
4493
  "text"
4509
4494
  ]
@@ -4516,7 +4501,7 @@ var input_spec_default = {
4516
4501
  slotGap: "sys.layout.inline.md",
4517
4502
  radius: "sys.radius.md",
4518
4503
  borderWidth: "sys.borderWidth.hairline",
4519
- activeStrokeWeight: "sys.borderWidth.thin",
4504
+ activeStrokeWeight: "sys.borderWidth.hairline",
4520
4505
  groupGap: "sys.layout.stack.xs",
4521
4506
  labelTypo: "sys.typo.label.md",
4522
4507
  helperTypo: "sys.typo.body.sm",
@@ -4526,28 +4511,28 @@ var input_spec_default = {
4526
4511
  iconSize: "sys.icon.md"
4527
4512
  },
4528
4513
  groupColors: {
4529
- label: "sys.color.onSurface",
4530
- helper: "sys.color.onSurfaceVariant",
4531
- helperError: "sys.color.error",
4532
- count: "sys.color.onSurfaceVariant",
4533
- countCurrent: "sys.color.onSurface"
4514
+ label: "sys.color.text.default",
4515
+ helper: "sys.color.text.subtle",
4516
+ helperError: "sys.color.text.danger",
4517
+ count: "sys.color.text.subtle",
4518
+ countCurrent: "sys.color.text.default"
4534
4519
  },
4535
4520
  appearances: {
4536
4521
  default: {
4537
4522
  background: "transparent",
4538
- text: "sys.color.onSurface",
4539
- placeholder: "sys.color.outline",
4540
- borderRest: "sys.color.outlineVariant",
4541
- borderHover: "sys.color.outline",
4542
- borderActive: "sys.color.onSurface"
4523
+ text: "sys.color.text.default",
4524
+ placeholder: "sys.color.border.boldest",
4525
+ borderRest: "sys.color.border.default",
4526
+ borderHover: "sys.color.border.boldest",
4527
+ borderActive: "sys.color.border.focused"
4543
4528
  },
4544
4529
  error: {
4545
- background: "sys.color.errorContainer",
4546
- text: "sys.color.onErrorContainer",
4547
- placeholder: "sys.color.onErrorContainer",
4548
- borderRest: "sys.color.error",
4549
- borderHover: "sys.color.error",
4550
- borderActive: "sys.color.error"
4530
+ background: "sys.color.background.danger",
4531
+ text: "sys.color.text.danger",
4532
+ placeholder: "sys.color.text.danger",
4533
+ borderRest: "sys.color.border.danger",
4534
+ borderHover: "sys.color.border.danger",
4535
+ borderActive: "sys.color.border.danger"
4551
4536
  }
4552
4537
  },
4553
4538
  states: {
@@ -4577,33 +4562,34 @@ var input_spec_default = {
4577
4562
  focusRing: {
4578
4563
  composition: "outward",
4579
4564
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
4580
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
4581
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
4565
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
4566
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
4582
4567
  },
4583
- note: "This IS the field's keyboard/input-focus state \u2014 `active` (caret visible, input engaged) and `:focus-visible` coincide for a text field, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. The stroke steps from its rest `hairline` (1px) to `activeStrokeWeight` (2px) and re-tones to `borderActive` \u2014 but it is an inset `box-shadow`, not a `border`, so the box model is untouched: the field's footprint, caret, and text position are pixel-stable as it goes active. Nothing reflows. The clear button is shown only in this state (and only when the value is non-empty)."
4568
+ note: "This IS the field's keyboard/input-focus state \u2014 `active` (caret visible, input engaged) and `:focus-visible` coincide for a text field, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. The stroke stays at `hairline` (1px) and re-tones to `borderActive` on active (no thickening) \u2014 but it is an inset `box-shadow`, not a `border`, so the box model is untouched: the field's footprint, caret, and text position are pixel-stable as it goes active. Nothing reflows. The clear button is shown only in this state (and only when the value is non-empty)."
4584
4569
  },
4585
4570
  disabled: {
4586
4571
  overlay: null,
4587
- background: "sys.color.surfaceContainerLow",
4588
- containerOpacity: "sys.state.disabled",
4572
+ background: "sys.color.background.disabled",
4573
+ text: "sys.color.text.disabled",
4574
+ placeholder: "sys.color.text.disabled",
4575
+ border: "sys.color.border.bold",
4589
4576
  suppressClear: true,
4590
4577
  suppressFocusRing: true,
4591
- cursor: "not-allowed"
4578
+ cursor: "not-allowed",
4579
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
4592
4580
  }
4593
4581
  },
4594
4582
  focusIndicator: {
4595
4583
  description: "Keyboard-focus visual \u2014 an accessibility indicator, not a lifecycle state. Composes over whichever lifecycle state the field is in (most commonly `active` since focus implies the caret is in the box). The `states.focused` block above is kept for JSX runtime consumers; this block is the parallel external-reader contract.",
4596
4584
  composition: "outward",
4597
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
4585
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
4598
4586
  overlay: {
4599
4587
  color: "label",
4600
4588
  opacity: "sys.state.focus"
4601
4589
  },
4602
4590
  ring: {
4603
- outerWidth: "sys.borderWidth.thin",
4604
- outerColor: "sys.color.focus",
4605
- insetWidth: "sys.borderWidth.hairline",
4606
- insetColor: "sys.color.focusInset"
4591
+ width: "sys.borderWidth.hairline",
4592
+ color: "sys.color.border.focused"
4607
4593
  },
4608
4594
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
4609
4595
  },
@@ -4616,7 +4602,7 @@ var input_spec_default = {
4616
4602
  },
4617
4603
  forbidden: [
4618
4604
  "raw <input> styled with Tailwind / inline color \u2014 the input is wrapped in the chorus-field chrome that owns the stroke",
4619
- "active-state stroke painted with sys.color.primary / a container tier \u2014 the active stroke is sys.color.onSurface (default appearance) or sys.color.error (error appearance), never primary or a container tier",
4605
+ "active-state stroke painted with sys.color.background.primary / a container tier \u2014 the active stroke is sys.color.text.default (default appearance) or sys.color.text.danger (error appearance), never primary or a container tier",
4620
4606
  "stroke painted via `border:` \u2014 stroke is an inset box-shadow on the field",
4621
4607
  "helper text rendered outside the helperText slot"
4622
4608
  ]
@@ -4661,7 +4647,7 @@ var textarea_spec_default = {
4661
4647
  helper: {
4662
4648
  type: "node",
4663
4649
  optional: true,
4664
- description: "Assistive text rendered below the field box, left-aligned. Same rules as [input.helper](./input.md): mutually exclusive with `maxLength`, optional on every appearance, re-tones to `sys.color.error` on the error appearance."
4650
+ description: "Assistive text rendered below the field box, left-aligned. Same rules as [input.helper](./input.md): mutually exclusive with `maxLength`, optional on every appearance, re-tones to `sys.color.text.danger` on the error appearance."
4665
4651
  },
4666
4652
  maxLength: {
4667
4653
  type: "number",
@@ -4686,7 +4672,7 @@ var textarea_spec_default = {
4686
4672
  },
4687
4673
  label: {
4688
4674
  required: false,
4689
- description: "Visible label above the box. `sys.typo.label.md`, `sys.color.onSurface`. Associated with the textarea via `htmlFor`.",
4675
+ description: "Visible label above the box. `sys.typo.label.md`, `sys.color.text.default`. Associated with the textarea via `htmlFor`.",
4690
4676
  accepts: ["text"]
4691
4677
  },
4692
4678
  container: {
@@ -4717,7 +4703,7 @@ var textarea_spec_default = {
4717
4703
  slotGap: "sys.layout.inline.md",
4718
4704
  radius: "sys.radius.md",
4719
4705
  borderWidth: "sys.borderWidth.hairline",
4720
- activeStrokeWeight: "sys.borderWidth.thin",
4706
+ activeStrokeWeight: "sys.borderWidth.hairline",
4721
4707
  groupGap: "sys.layout.stack.xs",
4722
4708
  labelTypo: "sys.typo.label.md",
4723
4709
  helperTypo: "sys.typo.body.sm",
@@ -4729,28 +4715,28 @@ var textarea_spec_default = {
4729
4715
  resize: "vertical"
4730
4716
  },
4731
4717
  groupColors: {
4732
- label: "sys.color.onSurface",
4733
- helper: "sys.color.onSurfaceVariant",
4734
- helperError: "sys.color.error",
4735
- count: "sys.color.onSurfaceVariant",
4736
- countCurrent: "sys.color.onSurface"
4718
+ label: "sys.color.text.default",
4719
+ helper: "sys.color.text.subtle",
4720
+ helperError: "sys.color.text.danger",
4721
+ count: "sys.color.text.subtle",
4722
+ countCurrent: "sys.color.text.default"
4737
4723
  },
4738
4724
  appearances: {
4739
4725
  default: {
4740
4726
  background: "transparent",
4741
- text: "sys.color.onSurface",
4742
- placeholder: "sys.color.outline",
4743
- borderRest: "sys.color.outlineVariant",
4744
- borderHover: "sys.color.outline",
4745
- borderActive: "sys.color.onSurface"
4727
+ text: "sys.color.text.default",
4728
+ placeholder: "sys.color.border.boldest",
4729
+ borderRest: "sys.color.border.default",
4730
+ borderHover: "sys.color.border.boldest",
4731
+ borderActive: "sys.color.border.focused"
4746
4732
  },
4747
4733
  error: {
4748
- background: "sys.color.errorContainer",
4749
- text: "sys.color.onErrorContainer",
4750
- placeholder: "sys.color.onErrorContainer",
4751
- borderRest: "sys.color.error",
4752
- borderHover: "sys.color.error",
4753
- borderActive: "sys.color.error"
4734
+ background: "sys.color.background.danger",
4735
+ text: "sys.color.text.danger",
4736
+ placeholder: "sys.color.text.danger",
4737
+ borderRest: "sys.color.border.danger",
4738
+ borderHover: "sys.color.border.danger",
4739
+ borderActive: "sys.color.border.danger"
4754
4740
  }
4755
4741
  },
4756
4742
  states: {
@@ -4770,32 +4756,33 @@ var textarea_spec_default = {
4770
4756
  focusRing: {
4771
4757
  composition: "outward",
4772
4758
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
4773
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
4774
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
4759
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
4760
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
4775
4761
  },
4776
- note: "This IS the field's keyboard/input-focus state \u2014 `active` (caret visible, input engaged) and `:focus-visible` coincide for a text field, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. Stroke steps from `hairline` (1px) to `activeStrokeWeight` (2px) as an inset box-shadow \u2014 same pixel-stable contract as input."
4762
+ note: "This IS the field's keyboard/input-focus state \u2014 `active` (caret visible, input engaged) and `:focus-visible` coincide for a text field, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. Stroke stays at `hairline` (1px), re-toning to `borderActive` as an inset box-shadow (no thickening) \u2014 same pixel-stable contract as input."
4777
4763
  },
4778
4764
  disabled: {
4779
4765
  overlay: null,
4780
- background: "sys.color.surfaceContainerLow",
4781
- containerOpacity: "sys.state.disabled",
4766
+ background: "sys.color.background.disabled",
4767
+ text: "sys.color.text.disabled",
4768
+ placeholder: "sys.color.text.disabled",
4769
+ border: "sys.color.border.bold",
4782
4770
  suppressFocusRing: true,
4783
- cursor: "not-allowed"
4771
+ cursor: "not-allowed",
4772
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
4784
4773
  }
4785
4774
  },
4786
4775
  focusIndicator: {
4787
- description: "Same outward 3-layer ring as input.focusIndicator.",
4776
+ description: "Same outward single ring as input.focusIndicator.",
4788
4777
  composition: "outward",
4789
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
4778
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
4790
4779
  overlay: {
4791
4780
  color: "label",
4792
4781
  opacity: "sys.state.focus"
4793
4782
  },
4794
4783
  ring: {
4795
- outerWidth: "sys.borderWidth.thin",
4796
- outerColor: "sys.color.focus",
4797
- insetWidth: "sys.borderWidth.hairline",
4798
- insetColor: "sys.color.focusInset"
4784
+ width: "sys.borderWidth.hairline",
4785
+ color: "sys.color.border.focused"
4799
4786
  },
4800
4787
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
4801
4788
  },
@@ -4852,7 +4839,7 @@ var search_spec_default = {
4852
4839
  },
4853
4840
  leading: {
4854
4841
  required: true,
4855
- description: "The leading `SearchIcon` glyph pinned at the box's inner-left edge. Inherits the field's text colour (`sys.color.onSurface`); decorative \u2014 not a real button, has `aria-hidden`. 16px (`sys.icon.md`), matching the clear button's footprint so the two affixes balance.",
4842
+ description: "The leading `SearchIcon` glyph pinned at the box's inner-left edge. Inherits the field's text colour (`sys.color.text.default`); decorative \u2014 not a real button, has `aria-hidden`. 16px (`sys.icon.md`), matching the clear button's footprint so the two affixes balance.",
4856
4843
  intrinsic: true
4857
4844
  },
4858
4845
  input: {
@@ -4875,18 +4862,18 @@ var search_spec_default = {
4875
4862
  slotGap: "sys.layout.inline.md",
4876
4863
  radius: "sys.radius.full",
4877
4864
  borderWidth: "sys.borderWidth.hairline",
4878
- activeStrokeWeight: "sys.borderWidth.thin",
4865
+ activeStrokeWeight: "sys.borderWidth.hairline",
4879
4866
  textTypo: "sys.typo.body.md",
4880
4867
  iconSize: "sys.icon.md"
4881
4868
  },
4882
4869
  appearances: {
4883
4870
  default: {
4884
4871
  background: "transparent",
4885
- text: "sys.color.onSurface",
4886
- placeholder: "sys.color.outline",
4887
- borderRest: "sys.color.outlineVariant",
4888
- borderHover: "sys.color.outline",
4889
- borderActive: "sys.color.onSurface"
4872
+ text: "sys.color.text.default",
4873
+ placeholder: "sys.color.border.boldest",
4874
+ borderRest: "sys.color.border.default",
4875
+ borderHover: "sys.color.border.boldest",
4876
+ borderActive: "sys.color.border.focused"
4890
4877
  }
4891
4878
  },
4892
4879
  states: {
@@ -4916,33 +4903,34 @@ var search_spec_default = {
4916
4903
  focusRing: {
4917
4904
  composition: "outward",
4918
4905
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
4919
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
4920
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
4906
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
4907
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
4921
4908
  },
4922
- note: "This IS the field's keyboard/input-focus state \u2014 `active` (caret visible, input engaged) and `:focus-visible` coincide for a text field, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. The stroke steps from its rest `hairline` (1px) to `activeStrokeWeight` (2px) and re-tones to `borderActive` \u2014 but it is an inset `box-shadow`, not a `border`, so the box model is untouched: the field's footprint, caret, and text position are pixel-stable as it goes active. Nothing reflows. The clear button is shown only in this state (and only when the value is non-empty)."
4909
+ note: "This IS the field's keyboard/input-focus state \u2014 `active` (caret visible, input engaged) and `:focus-visible` coincide for a text field, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. The stroke stays at `hairline` (1px) and re-tones to `borderActive` on active (no thickening) \u2014 but it is an inset `box-shadow`, not a `border`, so the box model is untouched: the field's footprint, caret, and text position are pixel-stable as it goes active. Nothing reflows. The clear button is shown only in this state (and only when the value is non-empty)."
4923
4910
  },
4924
4911
  disabled: {
4925
4912
  overlay: null,
4926
- background: "sys.color.surfaceContainerLow",
4927
- containerOpacity: "sys.state.disabled",
4913
+ background: "sys.color.background.disabled",
4914
+ text: "sys.color.text.disabled",
4915
+ placeholder: "sys.color.text.disabled",
4916
+ border: "sys.color.border.bold",
4928
4917
  suppressClear: true,
4929
4918
  suppressFocusRing: true,
4930
- cursor: "not-allowed"
4919
+ cursor: "not-allowed",
4920
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
4931
4921
  }
4932
4922
  },
4933
4923
  focusIndicator: {
4934
4924
  description: "Keyboard-focus visual \u2014 an accessibility indicator, not a lifecycle state. Composes over whichever lifecycle state the field is in. The `states.focused` block above is kept for JSX runtime consumers; this block is the parallel external-reader contract.",
4935
4925
  composition: "outward",
4936
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
4926
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
4937
4927
  overlay: {
4938
4928
  color: "label",
4939
4929
  opacity: "sys.state.focus"
4940
4930
  },
4941
4931
  ring: {
4942
- outerWidth: "sys.borderWidth.thin",
4943
- outerColor: "sys.color.focus",
4944
- insetWidth: "sys.borderWidth.hairline",
4945
- insetColor: "sys.color.focusInset"
4932
+ width: "sys.borderWidth.hairline",
4933
+ color: "sys.color.border.focused"
4946
4934
  },
4947
4935
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
4948
4936
  },
@@ -4998,7 +4986,7 @@ var select_spec_default = {
4998
4986
  leadingIcon: {
4999
4987
  type: "node",
5000
4988
  optional: true,
5001
- description: "Optional 16px (`sys.icon.md`) decorative glyph pinned at the inner-left edge of the field. Tracks the field's active text colour (`sys.color.onSurface` on the default appearance, `sys.color.onErrorContainer` on `error`) so the glyph reads as part of the typed content."
4989
+ description: "Optional 16px (`sys.icon.md`) decorative glyph pinned at the inner-left edge of the field. Tracks the field's active text colour (`sys.color.text.default` on the default appearance, `sys.color.text.danger` on `error`) so the glyph reads as part of the typed content."
5002
4990
  },
5003
4991
  onOpen: {
5004
4992
  type: "function",
@@ -5055,7 +5043,7 @@ var select_spec_default = {
5055
5043
  slotGap: "sys.layout.inline.md",
5056
5044
  radius: "sys.radius.md",
5057
5045
  borderWidth: "sys.borderWidth.hairline",
5058
- activeStrokeWeight: "sys.borderWidth.thin",
5046
+ activeStrokeWeight: "sys.borderWidth.hairline",
5059
5047
  groupGap: "sys.layout.stack.xs",
5060
5048
  labelTypo: "sys.typo.label.md",
5061
5049
  helperTypo: "sys.typo.body.sm",
@@ -5065,28 +5053,28 @@ var select_spec_default = {
5065
5053
  iconSize: "sys.icon.md"
5066
5054
  },
5067
5055
  groupColors: {
5068
- label: "sys.color.onSurface",
5069
- helper: "sys.color.onSurfaceVariant",
5070
- helperError: "sys.color.error",
5071
- count: "sys.color.onSurfaceVariant",
5072
- countCurrent: "sys.color.onSurface"
5056
+ label: "sys.color.text.default",
5057
+ helper: "sys.color.text.subtle",
5058
+ helperError: "sys.color.text.danger",
5059
+ count: "sys.color.text.subtle",
5060
+ countCurrent: "sys.color.text.default"
5073
5061
  },
5074
5062
  appearances: {
5075
5063
  default: {
5076
5064
  background: "transparent",
5077
- text: "sys.color.onSurface",
5078
- placeholder: "sys.color.outline",
5079
- borderRest: "sys.color.outlineVariant",
5080
- borderHover: "sys.color.outline",
5081
- borderActive: "sys.color.onSurface"
5065
+ text: "sys.color.text.default",
5066
+ placeholder: "sys.color.border.boldest",
5067
+ borderRest: "sys.color.border.default",
5068
+ borderHover: "sys.color.border.boldest",
5069
+ borderActive: "sys.color.border.focused"
5082
5070
  },
5083
5071
  error: {
5084
- background: "sys.color.errorContainer",
5085
- text: "sys.color.onErrorContainer",
5086
- placeholder: "sys.color.onErrorContainer",
5087
- borderRest: "sys.color.error",
5088
- borderHover: "sys.color.error",
5089
- borderActive: "sys.color.error"
5072
+ background: "sys.color.background.danger",
5073
+ text: "sys.color.text.danger",
5074
+ placeholder: "sys.color.text.danger",
5075
+ borderRest: "sys.color.border.danger",
5076
+ borderHover: "sys.color.border.danger",
5077
+ borderActive: "sys.color.border.danger"
5090
5078
  }
5091
5079
  },
5092
5080
  states: {
@@ -5113,21 +5101,24 @@ var select_spec_default = {
5113
5101
  focusRing: {
5114
5102
  composition: "outward",
5115
5103
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
5116
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
5117
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
5104
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
5105
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
5118
5106
  },
5119
- note: "This IS the trigger's keyboard-focus / open state \u2014 `:focus-visible` and the engaged (open) state coincide for the select trigger, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. The stroke re-tones to `borderActive` at `activeStrokeWeight` (2px) as an inset box-shadow, pixel-stable (no reflow)."
5107
+ note: "This IS the trigger's keyboard-focus / open state \u2014 `:focus-visible` and the engaged (open) state coincide for the select trigger, so there is no separate `focused` state; the focus ring described here (and in the parallel `focusIndicator` block) is the focus affordance. The stroke re-tones to `borderActive` at `activeStrokeWeight` (1px, = rest) as an inset box-shadow, pixel-stable (no reflow)."
5120
5108
  },
5121
5109
  disabled: {
5122
5110
  overlay: null,
5123
- background: "sys.color.surfaceContainerLow",
5124
- containerOpacity: "sys.state.disabled",
5111
+ background: "sys.color.background.disabled",
5112
+ text: "sys.color.text.disabled",
5113
+ placeholder: "sys.color.text.disabled",
5114
+ border: "sys.color.border.bold",
5125
5115
  suppressFocusRing: true,
5126
- cursor: "not-allowed"
5116
+ cursor: "not-allowed",
5117
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
5127
5118
  }
5128
5119
  },
5129
5120
  focusIndicator: {
5130
- description: "Same keyboard-focus indicator as Input \u2014 outward two-layer ring composed over the active stroke.",
5121
+ description: "Same keyboard-focus indicator as Input \u2014 outward single ring composed over the active stroke.",
5131
5122
  composition: "outward",
5132
5123
  compositionReason: "Action affordance with breathing room around it.",
5133
5124
  overlay: {
@@ -5135,10 +5126,8 @@ var select_spec_default = {
5135
5126
  opacity: "sys.state.focus"
5136
5127
  },
5137
5128
  ring: {
5138
- outerWidth: "sys.borderWidth.thin",
5139
- outerColor: "sys.color.focus",
5140
- insetWidth: "sys.borderWidth.hairline",
5141
- insetColor: "sys.color.focusInset"
5129
+ width: "sys.borderWidth.hairline",
5130
+ color: "sys.color.border.focused"
5142
5131
  },
5143
5132
  trigger: ":focus-visible"
5144
5133
  },
@@ -5213,17 +5202,17 @@ function FormFieldBox({
5213
5202
  "--field-group-gap": tokenToCss(spec.sizing.groupGap),
5214
5203
  "--field-bg": tokenToCss(app.background),
5215
5204
  "--field-bg-disabled": tokenToCss(spec.states.disabled.background),
5216
- "--field-text": tokenToCss(app.text),
5217
- "--field-placeholder": tokenToCss(app.placeholder),
5218
- "--field-border": tokenToCss(app.borderRest),
5205
+ // Disabled swaps text / placeholder / border to the explicit disabled
5206
+ // tokens (no opacity) — the field box paints them via these vars.
5207
+ "--field-text": tokenToCss(isDisabled ? spec.states.disabled.text : app.text),
5208
+ "--field-placeholder": tokenToCss(
5209
+ isDisabled ? spec.states.disabled.placeholder : app.placeholder
5210
+ ),
5211
+ "--field-border": tokenToCss(isDisabled ? spec.states.disabled.border : app.borderRest),
5219
5212
  "--field-border-hover": tokenToCss(app.borderHover),
5220
5213
  "--field-border-active": tokenToCss(app.borderActive),
5221
5214
  "--field-overlay-pressed": tokenToCss(spec.states.pressed.overlay.opacity),
5222
- "--field-disabled-opacity": tokenToCss(spec.states.disabled.containerOpacity),
5223
- "--field-focus-outer-width": tokenToCss(spec.focusIndicator.ring.outerWidth),
5224
- "--field-focus-outer-color": tokenToCss(spec.focusIndicator.ring.outerColor),
5225
- "--field-focus-inset-width": tokenToCss(spec.focusIndicator.ring.insetWidth),
5226
- "--field-focus-inset-color": tokenToCss(spec.focusIndicator.ring.insetColor),
5215
+ "--field-focus-outer-color": tokenToCss(spec.focusIndicator.ring.color),
5227
5216
  ...typoStyles(spec.sizing.textTypo)
5228
5217
  };
5229
5218
  const handleChange = (event) => {
@@ -5815,7 +5804,7 @@ var sub_spec_default = {
5815
5804
  appearance: {
5816
5805
  containerFill: "transparent",
5817
5806
  labelTypo: "sys.typo.label.md",
5818
- labelColor: "sys.color.onSurfaceVariant",
5807
+ labelColor: "sys.color.text.subtle",
5819
5808
  paddingInline: "sys.layout.container.md",
5820
5809
  paddingBlockStart: "sys.layout.stack.lg",
5821
5810
  paddingBlockEnd: "sys.layout.stack.xs",