@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.cjs CHANGED
@@ -7,11 +7,11 @@ var reactDom = require('react-dom');
7
7
  // ../../schema/components/badge/update.spec.json
8
8
  var update_spec_default = {
9
9
  appearance: {
10
- background: "sys.color.brand",
11
- label: "sys.color.onBrand",
10
+ background: "sys.color.text.brand",
11
+ label: "sys.color.text.onFill",
12
12
  radius: "sys.radius.full",
13
13
  dotOutline: {
14
- color: "sys.color.surface",
14
+ color: "sys.color.surface.default",
15
15
  width: "sys.borderWidth.thin",
16
16
  rendering: "box-shadow",
17
17
  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."
@@ -30,7 +30,7 @@ var update_spec_default = {
30
30
  minWidth: "ref.space.200",
31
31
  paddingBlock: "0",
32
32
  paddingInline: "sys.layout.container.2xs",
33
- labelTypo: "sys.typo.caption"
33
+ labelTypo: "sys.typo.label.xs"
34
34
  },
35
35
  "dot-md": {
36
36
  minHeight: "ref.space.100",
@@ -54,15 +54,15 @@ var update_spec_default = {
54
54
  var role_spec_default = {
55
55
  appearances: {
56
56
  default: {
57
- background: "sys.color.primaryContainer",
58
- label: "sys.color.onPrimaryContainer",
57
+ background: "sys.color.background.selected",
58
+ label: "sys.color.text.link",
59
59
  radius: "sys.radius.full",
60
60
  default: true,
61
61
  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."
62
62
  },
63
63
  inverse: {
64
- background: "sys.color.inverseSurface",
65
- label: "sys.color.inverseOnSurface",
64
+ background: "sys.color.background.inverse",
65
+ label: "sys.color.text.inverse",
66
66
  radius: "sys.radius.full",
67
67
  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."
68
68
  }
@@ -73,7 +73,7 @@ var role_spec_default = {
73
73
  minWidth: "ref.space.200",
74
74
  paddingBlock: "ref.space.25",
75
75
  paddingInline: "ref.space.75",
76
- labelTypo: "sys.typo.caption",
76
+ labelTypo: "sys.typo.label.xs",
77
77
  labelLineHeight: "1.2",
78
78
  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."
79
79
  }
@@ -329,27 +329,27 @@ var standard_spec_default = {
329
329
  },
330
330
  appearances: {
331
331
  primary: {
332
- background: "sys.color.primary",
332
+ background: "sys.color.background.primary",
333
333
  border: null,
334
- label: "sys.color.onPrimary"
334
+ label: "sys.color.text.onFill"
335
335
  },
336
336
  secondary: {
337
- background: "sys.color.secondaryContainer",
337
+ background: "sys.color.background.neutral",
338
338
  border: null,
339
- label: "sys.color.onSecondaryContainer"
339
+ label: "sys.color.text.default"
340
340
  },
341
341
  outlined: {
342
342
  background: "transparent",
343
343
  border: {
344
344
  width: "sys.borderWidth.hairline",
345
- color: "sys.color.primary"
345
+ color: "sys.color.text.link"
346
346
  },
347
- label: "sys.color.primary"
347
+ label: "sys.color.text.link"
348
348
  },
349
349
  tertiary: {
350
350
  background: "transparent",
351
351
  border: null,
352
- label: "sys.color.onSurfaceVariant"
352
+ label: "sys.color.text.subtle"
353
353
  }
354
354
  },
355
355
  states: {
@@ -371,10 +371,7 @@ var standard_spec_default = {
371
371
  opacity: "sys.state.focus"
372
372
  },
373
373
  ring: {
374
- outerWidth: "sys.borderWidth.thin",
375
- outerColor: "sys.color.focus",
376
- insetWidth: "sys.borderWidth.hairline",
377
- insetColor: "sys.color.focusInset"
374
+ color: "sys.color.border.focused"
378
375
  }}};
379
376
  function sizeStyle(size) {
380
377
  const s2 = standard_spec_default.sizes[size] ?? standard_spec_default.sizes[standard_spec_default.props.size.default];
@@ -404,10 +401,7 @@ function stateStyle() {
404
401
  "--button-standard-overlay-pressed": tokenToCss(standard_spec_default.states.pressed.overlay.opacity),
405
402
  "--button-standard-overlay-focus": tokenToCss(standard_spec_default.focusIndicator.overlay.opacity),
406
403
  "--button-standard-disabled-opacity": tokenToCss(standard_spec_default.states.disabled.containerOpacity),
407
- "--button-standard-focus-outer-width": tokenToCss(standard_spec_default.focusIndicator.ring.outerWidth),
408
- "--button-standard-focus-outer-color": tokenToCss(standard_spec_default.focusIndicator.ring.outerColor),
409
- "--button-standard-focus-inset-width": tokenToCss(standard_spec_default.focusIndicator.ring.insetWidth),
410
- "--button-standard-focus-inset-color": tokenToCss(standard_spec_default.focusIndicator.ring.insetColor)
404
+ "--button-standard-focus-outer-color": tokenToCss(standard_spec_default.focusIndicator.ring.color)
411
405
  };
412
406
  }
413
407
  var FORCEABLE_STATES = /* @__PURE__ */ new Set(["hovered", "pressed", "focused"]);
@@ -475,12 +469,12 @@ var fab_spec_default = {
475
469
  },
476
470
  appearances: {
477
471
  primary: {
478
- background: "sys.color.brand",
479
- label: "sys.color.onBrand"
472
+ background: "sys.color.text.brand",
473
+ label: "sys.color.text.onFill"
480
474
  },
481
475
  secondary: {
482
- background: "sys.color.surfaceContainerHigh",
483
- label: "sys.color.onSurface"
476
+ background: "sys.color.surface.default",
477
+ label: "sys.color.text.default"
484
478
  }
485
479
  },
486
480
  states: {
@@ -499,10 +493,7 @@ var fab_spec_default = {
499
493
  opacity: "sys.state.focus"
500
494
  },
501
495
  ring: {
502
- outerWidth: "sys.borderWidth.thin",
503
- outerColor: "sys.color.focus",
504
- insetWidth: "sys.borderWidth.hairline",
505
- insetColor: "sys.color.focusInset"
496
+ color: "sys.color.border.focused"
506
497
  }}};
507
498
  var FORCEABLE_STATES2 = /* @__PURE__ */ new Set(["hovered", "pressed", "focused"]);
508
499
  function appearanceStyle3(appearance) {
@@ -523,10 +514,7 @@ var sizingStyle2 = () => ({
523
514
  "--button-fab-overlay-hover": tokenToCss(fab_spec_default.states.hovered.overlay.opacity),
524
515
  "--button-fab-overlay-pressed": tokenToCss(fab_spec_default.states.pressed.overlay.opacity),
525
516
  "--button-fab-overlay-focus": tokenToCss(fab_spec_default.focusIndicator.overlay.opacity),
526
- "--button-fab-focus-outer-width": tokenToCss(fab_spec_default.focusIndicator.ring.outerWidth),
527
- "--button-fab-focus-outer-color": tokenToCss(fab_spec_default.focusIndicator.ring.outerColor),
528
- "--button-fab-focus-inset-width": tokenToCss(fab_spec_default.focusIndicator.ring.insetWidth),
529
- "--button-fab-focus-inset-color": tokenToCss(fab_spec_default.focusIndicator.ring.insetColor),
517
+ "--button-fab-focus-outer-color": tokenToCss(fab_spec_default.focusIndicator.ring.color),
530
518
  ...typoStyles(fab_spec_default.sizing.labelTypo)
531
519
  });
532
520
  function ButtonFab({
@@ -1564,16 +1552,16 @@ var filter_spec_default = {
1564
1552
  selectionStates: {
1565
1553
  unselected: {
1566
1554
  background: "transparent",
1567
- label: "sys.color.onSurface",
1555
+ label: "sys.color.text.default",
1568
1556
  border: {
1569
1557
  width: "sys.borderWidth.hairline",
1570
- color: "sys.color.outlineVariant"
1558
+ color: "sys.color.border.default"
1571
1559
  },
1572
1560
  note: "Transparent fill so the chip adopts whatever surface sits behind it (page, raised card, sheet) without pinning to a fixed neutral step."
1573
1561
  },
1574
1562
  selected: {
1575
- background: "sys.color.inverseSurface",
1576
- label: "sys.color.inverseOnSurface",
1563
+ background: "sys.color.background.inverse",
1564
+ label: "sys.color.text.inverse",
1577
1565
  border: null
1578
1566
  }
1579
1567
  },
@@ -1603,35 +1591,39 @@ var filter_spec_default = {
1603
1591
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
1604
1592
  innerCounterRing: {
1605
1593
  width: "sys.borderWidth.hairline",
1606
- color: "sys.color.focusInset"
1594
+ color: "sys.color.border.focused"
1607
1595
  },
1608
1596
  outerRing: {
1609
1597
  width: "sys.borderWidth.thin",
1610
- color: "sys.color.focus"
1598
+ color: "sys.color.border.focused"
1611
1599
  }
1612
1600
  },
1613
1601
  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."
1614
1602
  },
1615
1603
  disabled: {
1616
1604
  overlay: null,
1617
- containerOpacity: "sys.state.disabled",
1605
+ background: "sys.color.background.disabled",
1606
+ label: "sys.color.text.disabled",
1607
+ border: {
1608
+ width: "sys.borderWidth.hairline",
1609
+ color: "sys.color.border.bold"
1610
+ },
1618
1611
  suppressFocusRing: true,
1619
- cursor: "not-allowed"
1612
+ cursor: "not-allowed",
1613
+ 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."
1620
1614
  }
1621
1615
  },
1622
1616
  focusIndicator: {
1623
1617
  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.",
1624
1618
  composition: "outward",
1625
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
1619
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
1626
1620
  overlay: {
1627
1621
  color: "label",
1628
1622
  opacity: "sys.state.focus"
1629
1623
  },
1630
1624
  ring: {
1631
- outerWidth: "sys.borderWidth.thin",
1632
- outerColor: "sys.color.focus",
1633
- insetWidth: "sys.borderWidth.hairline",
1634
- insetColor: "sys.color.focusInset"
1625
+ width: "sys.borderWidth.hairline",
1626
+ color: "sys.color.border.focused"
1635
1627
  },
1636
1628
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
1637
1629
  },
@@ -1649,7 +1641,7 @@ var tag_spec_default = {
1649
1641
  name: "Chip",
1650
1642
  family: "chip",
1651
1643
  subcomponent: "tag",
1652
- 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.",
1644
+ 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.",
1653
1645
  element: "span",
1654
1646
  props: {
1655
1647
  variant: {
@@ -1690,15 +1682,15 @@ var tag_spec_default = {
1690
1682
  },
1691
1683
  appearances: {
1692
1684
  default: {
1693
- background: "sys.color.scrimSubtle",
1694
- label: "sys.color.onSurface",
1685
+ background: "sys.color.background.neutral",
1686
+ label: "sys.color.text.default",
1695
1687
  border: null,
1696
1688
  default: true,
1697
- 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."
1689
+ 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."
1698
1690
  },
1699
1691
  accent: {
1700
- background: "sys.color.primaryContainer",
1701
- label: "sys.color.primary",
1692
+ background: "sys.color.background.selected",
1693
+ label: "sys.color.text.link",
1702
1694
  border: null,
1703
1695
  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."
1704
1696
  }
@@ -1729,35 +1721,39 @@ var tag_spec_default = {
1729
1721
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
1730
1722
  innerCounterRing: {
1731
1723
  width: "sys.borderWidth.hairline",
1732
- color: "sys.color.focusInset"
1724
+ color: "sys.color.border.focused"
1733
1725
  },
1734
1726
  outerRing: {
1735
1727
  width: "sys.borderWidth.thin",
1736
- color: "sys.color.focus"
1728
+ color: "sys.color.border.focused"
1737
1729
  }
1738
1730
  },
1739
1731
  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."
1740
1732
  },
1741
1733
  disabled: {
1742
1734
  overlay: null,
1743
- containerOpacity: "sys.state.disabled",
1735
+ background: "sys.color.background.disabled",
1736
+ label: "sys.color.text.disabled",
1737
+ border: {
1738
+ width: "sys.borderWidth.hairline",
1739
+ color: "sys.color.border.bold"
1740
+ },
1744
1741
  suppressFocusRing: true,
1745
- cursor: "not-allowed"
1742
+ cursor: "not-allowed",
1743
+ 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."
1746
1744
  }
1747
1745
  },
1748
1746
  focusIndicator: {
1749
1747
  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.",
1750
1748
  composition: "outward",
1751
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
1749
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
1752
1750
  overlay: {
1753
1751
  color: "label",
1754
1752
  opacity: "sys.state.focus"
1755
1753
  },
1756
1754
  ring: {
1757
- outerWidth: "sys.borderWidth.thin",
1758
- outerColor: "sys.color.focus",
1759
- insetWidth: "sys.borderWidth.hairline",
1760
- insetColor: "sys.color.focusInset"
1755
+ width: "sys.borderWidth.hairline",
1756
+ color: "sys.color.border.focused"
1761
1757
  },
1762
1758
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
1763
1759
  },
@@ -1834,16 +1830,16 @@ var toggle_spec_default = {
1834
1830
  },
1835
1831
  selectionStates: {
1836
1832
  unselected: {
1837
- background: "sys.color.primary",
1838
- label: "sys.color.onPrimary",
1833
+ background: "sys.color.background.primary",
1834
+ label: "sys.color.text.onFill",
1839
1835
  border: null
1840
1836
  },
1841
1837
  selected: {
1842
1838
  background: "transparent",
1843
- label: "sys.color.onSurface",
1839
+ label: "sys.color.text.default",
1844
1840
  border: {
1845
1841
  width: "sys.borderWidth.hairline",
1846
- color: "sys.color.outlineVariant"
1842
+ color: "sys.color.border.default"
1847
1843
  }
1848
1844
  }
1849
1845
  },
@@ -1873,11 +1869,11 @@ var toggle_spec_default = {
1873
1869
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
1874
1870
  innerCounterRing: {
1875
1871
  width: "sys.borderWidth.hairline",
1876
- color: "sys.color.focusInset"
1872
+ color: "sys.color.border.focused"
1877
1873
  },
1878
1874
  outerRing: {
1879
1875
  width: "sys.borderWidth.thin",
1880
- color: "sys.color.focus"
1876
+ color: "sys.color.border.focused"
1881
1877
  }
1882
1878
  },
1883
1879
  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."
@@ -1892,21 +1888,19 @@ var toggle_spec_default = {
1892
1888
  focusIndicator: {
1893
1889
  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.",
1894
1890
  composition: "outward",
1895
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
1891
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
1896
1892
  overlay: {
1897
1893
  color: "label",
1898
1894
  opacity: "sys.state.focus"
1899
1895
  },
1900
1896
  ring: {
1901
- outerWidth: "sys.borderWidth.thin",
1902
- outerColor: "sys.color.focus",
1903
- insetWidth: "sys.borderWidth.hairline",
1904
- insetColor: "sys.color.focusInset"
1897
+ width: "sys.borderWidth.hairline",
1898
+ color: "sys.color.border.focused"
1905
1899
  },
1906
1900
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
1907
1901
  },
1908
1902
  forbidden: [
1909
- "active state painted with sys.color.primary fill \u2014 active is transparent + hairline outline (the active state recedes, not asserts)",
1903
+ "active state painted with sys.color.background.primary fill \u2014 active is transparent + hairline outline (the active state recedes, not asserts)",
1910
1904
  "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",
1911
1905
  "rest state without an explicit `active={false}` \u2014 toggle is a binary contract, never tristate",
1912
1906
  "manual width override that breaks the full-card stretch when used inside ProfileCarousel.followAction"
@@ -1953,10 +1947,7 @@ function sizingStyle3(spec) {
1953
1947
  "--chip-overlay-pressed": tokenToCss(spec.states.pressed.overlay.opacity),
1954
1948
  "--chip-overlay-focus": tokenToCss(spec.focusIndicator.overlay.opacity),
1955
1949
  "--chip-disabled-opacity": tokenToCss(spec.states.disabled.containerOpacity),
1956
- "--chip-focus-outer-width": tokenToCss(spec.focusIndicator.ring.outerWidth),
1957
- "--chip-focus-outer-color": tokenToCss(spec.focusIndicator.ring.outerColor),
1958
- "--chip-focus-inset-width": tokenToCss(spec.focusIndicator.ring.insetWidth),
1959
- "--chip-focus-inset-color": tokenToCss(spec.focusIndicator.ring.insetColor),
1950
+ "--chip-focus-outer-color": tokenToCss(spec.focusIndicator.ring.color),
1960
1951
  ...typoStyles(spec.sizing.labelTypo)
1961
1952
  };
1962
1953
  }
@@ -2032,14 +2023,14 @@ function ButtonToolbar({ appearance = "default", className, style, ...rest }) {
2032
2023
  let pairStyle = null;
2033
2024
  if (appearance === "accent") {
2034
2025
  pairStyle = {
2035
- "--chip-bg": "var(--sys-color-primary)",
2036
- "--chip-label": "var(--sys-color-onPrimary)",
2026
+ "--chip-bg": "var(--sys-color-background-primary)",
2027
+ "--chip-label": "var(--sys-color-text-onFill)",
2037
2028
  "--chip-border-color": "transparent"
2038
2029
  };
2039
2030
  } else if (appearance === "inverse") {
2040
2031
  pairStyle = {
2041
- "--chip-bg": "var(--sys-color-inverseSurface)",
2042
- "--chip-label": "var(--sys-color-inverseOnSurface)",
2032
+ "--chip-bg": "var(--sys-color-background-inverse)",
2033
+ "--chip-label": "var(--sys-color-text-inverse)",
2043
2034
  "--chip-border-color": "transparent"
2044
2035
  };
2045
2036
  }
@@ -2948,12 +2939,12 @@ function Divider({
2948
2939
  var empty_state_spec_default = {
2949
2940
  sizing: {
2950
2941
  illustrationSize: "ref.space.600",
2951
- illustrationColor: "sys.color.onSurfaceVariant",
2942
+ illustrationColor: "sys.color.text.subtle",
2952
2943
  illustrationGap: "sys.layout.stack.sm",
2953
2944
  headlineTypo: "sys.typo.heading.sm",
2954
- headlineColor: "sys.color.onSurface",
2945
+ headlineColor: "sys.color.text.default",
2955
2946
  bodyTypo: "sys.typo.body.sm",
2956
- bodyColor: "sys.color.onSurfaceVariant",
2947
+ bodyColor: "sys.color.text.subtle",
2957
2948
  bodyGap: "sys.layout.stack.2xs",
2958
2949
  actionGap: "sys.layout.stack.md"
2959
2950
  }};
@@ -3043,17 +3034,17 @@ var underline_spec_default = {
3043
3034
  slotGap: "sys.layout.inline.sm",
3044
3035
  indicatorHeight: "sys.borderWidth.thin",
3045
3036
  dividerWidth: "sys.borderWidth.hairline",
3046
- dividerColor: "sys.color.outlineVariant",
3037
+ dividerColor: "sys.color.border.default",
3047
3038
  labelTypo: "sys.typo.label.md",
3048
3039
  iconSize: "sys.icon.md",
3049
3040
  fadeWidth: "ref.space.600"
3050
3041
  },
3051
3042
  selectionStates: {
3052
3043
  unselected: {
3053
- label: "sys.color.outline"},
3044
+ label: "sys.color.text.subtle"},
3054
3045
  selected: {
3055
- label: "sys.color.onSurface",
3056
- indicator: "sys.color.onSurface"
3046
+ label: "sys.color.text.default",
3047
+ indicator: "sys.color.border.selected"
3057
3048
  }
3058
3049
  },
3059
3050
  states: {
@@ -3068,17 +3059,14 @@ var underline_spec_default = {
3068
3059
  }
3069
3060
  },
3070
3061
  disabled: {
3071
- containerOpacity: "sys.state.disabled"}
3062
+ }
3072
3063
  },
3073
3064
  focusIndicator: {
3074
3065
  overlay: {
3075
3066
  opacity: "sys.state.focus"
3076
3067
  },
3077
3068
  ring: {
3078
- outerWidth: "sys.borderWidth.thin",
3079
- outerColor: "sys.color.focus",
3080
- insetWidth: "sys.borderWidth.hairline",
3081
- insetColor: "sys.color.focusInset"}}};
3069
+ color: "sys.color.border.focused"}}};
3082
3070
  function useSlidingIndicator(containerRef, indicatorRef, value) {
3083
3071
  react.useLayoutEffect(() => {
3084
3072
  const container = containerRef.current;
@@ -3159,10 +3147,7 @@ function TabsUnderline({ className, style, children, ...rest }) {
3159
3147
  "--tabs-overlay-pressed": tokenToCss(underline_spec_default.states.pressed.overlay.opacity),
3160
3148
  "--tabs-overlay-focus": tokenToCss(underline_spec_default.focusIndicator.overlay.opacity),
3161
3149
  "--tabs-disabled-opacity": tokenToCss(underline_spec_default.states.disabled.containerOpacity),
3162
- "--tabs-focus-outer-width": tokenToCss(underline_spec_default.focusIndicator.ring.outerWidth),
3163
- "--tabs-focus-outer-color": tokenToCss(underline_spec_default.focusIndicator.ring.outerColor),
3164
- "--tabs-focus-inset-width": tokenToCss(underline_spec_default.focusIndicator.ring.insetWidth),
3165
- "--tabs-focus-inset-color": tokenToCss(underline_spec_default.focusIndicator.ring.insetColor),
3150
+ "--tabs-focus-outer-color": tokenToCss(underline_spec_default.focusIndicator.ring.color),
3166
3151
  ...typoStyles(s2.labelTypo),
3167
3152
  ...style
3168
3153
  };
@@ -3898,9 +3883,9 @@ function Card({ item, innerRef, index }) {
3898
3883
  }
3899
3884
  var MAX_CARDS2 = 5;
3900
3885
  var METRIC_KINDS = {
3901
- star: { Icon: StarFillIcon, tone: "var(--sys-color-icon-yellow)" },
3902
- pulse: { Icon: PulseFillIcon, tone: "var(--sys-color-success)" },
3903
- heart: { Icon: HeartFillIcon, tone: "var(--sys-color-icon-red)" }
3886
+ star: { Icon: StarFillIcon, tone: "var(--sys-color-icon-accent-yellow-default)" },
3887
+ pulse: { Icon: PulseFillIcon, tone: "var(--sys-color-icon-success)" },
3888
+ heart: { Icon: HeartFillIcon, tone: "var(--sys-color-icon-accent-red-default)" }
3904
3889
  };
3905
3890
  var PLACEHOLDER_IMAGE = "/placeholder.png";
3906
3891
  function ProfileCarousel({
@@ -4454,7 +4439,7 @@ var input_spec_default = {
4454
4439
  helper: {
4455
4440
  type: "node",
4456
4441
  optional: true,
4457
- 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."
4442
+ 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."
4458
4443
  },
4459
4444
  maxLength: {
4460
4445
  type: "number",
@@ -4474,7 +4459,7 @@ var input_spec_default = {
4474
4459
  },
4475
4460
  label: {
4476
4461
  required: false,
4477
- description: "Visible label above the box. `sys.typo.label.md`, `sys.color.onSurface`. Associated with the input via `htmlFor`.",
4462
+ description: "Visible label above the box. `sys.typo.label.md`, `sys.color.text.default`. Associated with the input via `htmlFor`.",
4478
4463
  accepts: [
4479
4464
  "text"
4480
4465
  ]
@@ -4498,14 +4483,14 @@ var input_spec_default = {
4498
4483
  },
4499
4484
  helper: {
4500
4485
  required: false,
4501
- 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.",
4486
+ 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.",
4502
4487
  accepts: [
4503
4488
  "text"
4504
4489
  ]
4505
4490
  },
4506
4491
  count: {
4507
4492
  required: false,
4508
- 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"`.',
4493
+ 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"`.',
4509
4494
  accepts: [
4510
4495
  "text"
4511
4496
  ]
@@ -4518,7 +4503,7 @@ var input_spec_default = {
4518
4503
  slotGap: "sys.layout.inline.md",
4519
4504
  radius: "sys.radius.md",
4520
4505
  borderWidth: "sys.borderWidth.hairline",
4521
- activeStrokeWeight: "sys.borderWidth.thin",
4506
+ activeStrokeWeight: "sys.borderWidth.hairline",
4522
4507
  groupGap: "sys.layout.stack.xs",
4523
4508
  labelTypo: "sys.typo.label.md",
4524
4509
  helperTypo: "sys.typo.body.sm",
@@ -4528,28 +4513,28 @@ var input_spec_default = {
4528
4513
  iconSize: "sys.icon.md"
4529
4514
  },
4530
4515
  groupColors: {
4531
- label: "sys.color.onSurface",
4532
- helper: "sys.color.onSurfaceVariant",
4533
- helperError: "sys.color.error",
4534
- count: "sys.color.onSurfaceVariant",
4535
- countCurrent: "sys.color.onSurface"
4516
+ label: "sys.color.text.default",
4517
+ helper: "sys.color.text.subtle",
4518
+ helperError: "sys.color.text.danger",
4519
+ count: "sys.color.text.subtle",
4520
+ countCurrent: "sys.color.text.default"
4536
4521
  },
4537
4522
  appearances: {
4538
4523
  default: {
4539
4524
  background: "transparent",
4540
- text: "sys.color.onSurface",
4541
- placeholder: "sys.color.outline",
4542
- borderRest: "sys.color.outlineVariant",
4543
- borderHover: "sys.color.outline",
4544
- borderActive: "sys.color.onSurface"
4525
+ text: "sys.color.text.default",
4526
+ placeholder: "sys.color.border.boldest",
4527
+ borderRest: "sys.color.border.default",
4528
+ borderHover: "sys.color.border.boldest",
4529
+ borderActive: "sys.color.border.focused"
4545
4530
  },
4546
4531
  error: {
4547
- background: "sys.color.errorContainer",
4548
- text: "sys.color.onErrorContainer",
4549
- placeholder: "sys.color.onErrorContainer",
4550
- borderRest: "sys.color.error",
4551
- borderHover: "sys.color.error",
4552
- borderActive: "sys.color.error"
4532
+ background: "sys.color.background.danger",
4533
+ text: "sys.color.text.danger",
4534
+ placeholder: "sys.color.text.danger",
4535
+ borderRest: "sys.color.border.danger",
4536
+ borderHover: "sys.color.border.danger",
4537
+ borderActive: "sys.color.border.danger"
4553
4538
  }
4554
4539
  },
4555
4540
  states: {
@@ -4579,33 +4564,34 @@ var input_spec_default = {
4579
4564
  focusRing: {
4580
4565
  composition: "outward",
4581
4566
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
4582
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
4583
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
4567
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
4568
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
4584
4569
  },
4585
- 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)."
4570
+ 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)."
4586
4571
  },
4587
4572
  disabled: {
4588
4573
  overlay: null,
4589
- background: "sys.color.surfaceContainerLow",
4590
- containerOpacity: "sys.state.disabled",
4574
+ background: "sys.color.background.disabled",
4575
+ text: "sys.color.text.disabled",
4576
+ placeholder: "sys.color.text.disabled",
4577
+ border: "sys.color.border.bold",
4591
4578
  suppressClear: true,
4592
4579
  suppressFocusRing: true,
4593
- cursor: "not-allowed"
4580
+ cursor: "not-allowed",
4581
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
4594
4582
  }
4595
4583
  },
4596
4584
  focusIndicator: {
4597
4585
  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.",
4598
4586
  composition: "outward",
4599
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
4587
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
4600
4588
  overlay: {
4601
4589
  color: "label",
4602
4590
  opacity: "sys.state.focus"
4603
4591
  },
4604
4592
  ring: {
4605
- outerWidth: "sys.borderWidth.thin",
4606
- outerColor: "sys.color.focus",
4607
- insetWidth: "sys.borderWidth.hairline",
4608
- insetColor: "sys.color.focusInset"
4593
+ width: "sys.borderWidth.hairline",
4594
+ color: "sys.color.border.focused"
4609
4595
  },
4610
4596
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
4611
4597
  },
@@ -4618,7 +4604,7 @@ var input_spec_default = {
4618
4604
  },
4619
4605
  forbidden: [
4620
4606
  "raw <input> styled with Tailwind / inline color \u2014 the input is wrapped in the chorus-field chrome that owns the stroke",
4621
- "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",
4607
+ "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",
4622
4608
  "stroke painted via `border:` \u2014 stroke is an inset box-shadow on the field",
4623
4609
  "helper text rendered outside the helperText slot"
4624
4610
  ]
@@ -4663,7 +4649,7 @@ var textarea_spec_default = {
4663
4649
  helper: {
4664
4650
  type: "node",
4665
4651
  optional: true,
4666
- 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."
4652
+ 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."
4667
4653
  },
4668
4654
  maxLength: {
4669
4655
  type: "number",
@@ -4688,7 +4674,7 @@ var textarea_spec_default = {
4688
4674
  },
4689
4675
  label: {
4690
4676
  required: false,
4691
- description: "Visible label above the box. `sys.typo.label.md`, `sys.color.onSurface`. Associated with the textarea via `htmlFor`.",
4677
+ description: "Visible label above the box. `sys.typo.label.md`, `sys.color.text.default`. Associated with the textarea via `htmlFor`.",
4692
4678
  accepts: ["text"]
4693
4679
  },
4694
4680
  container: {
@@ -4719,7 +4705,7 @@ var textarea_spec_default = {
4719
4705
  slotGap: "sys.layout.inline.md",
4720
4706
  radius: "sys.radius.md",
4721
4707
  borderWidth: "sys.borderWidth.hairline",
4722
- activeStrokeWeight: "sys.borderWidth.thin",
4708
+ activeStrokeWeight: "sys.borderWidth.hairline",
4723
4709
  groupGap: "sys.layout.stack.xs",
4724
4710
  labelTypo: "sys.typo.label.md",
4725
4711
  helperTypo: "sys.typo.body.sm",
@@ -4731,28 +4717,28 @@ var textarea_spec_default = {
4731
4717
  resize: "vertical"
4732
4718
  },
4733
4719
  groupColors: {
4734
- label: "sys.color.onSurface",
4735
- helper: "sys.color.onSurfaceVariant",
4736
- helperError: "sys.color.error",
4737
- count: "sys.color.onSurfaceVariant",
4738
- countCurrent: "sys.color.onSurface"
4720
+ label: "sys.color.text.default",
4721
+ helper: "sys.color.text.subtle",
4722
+ helperError: "sys.color.text.danger",
4723
+ count: "sys.color.text.subtle",
4724
+ countCurrent: "sys.color.text.default"
4739
4725
  },
4740
4726
  appearances: {
4741
4727
  default: {
4742
4728
  background: "transparent",
4743
- text: "sys.color.onSurface",
4744
- placeholder: "sys.color.outline",
4745
- borderRest: "sys.color.outlineVariant",
4746
- borderHover: "sys.color.outline",
4747
- borderActive: "sys.color.onSurface"
4729
+ text: "sys.color.text.default",
4730
+ placeholder: "sys.color.border.boldest",
4731
+ borderRest: "sys.color.border.default",
4732
+ borderHover: "sys.color.border.boldest",
4733
+ borderActive: "sys.color.border.focused"
4748
4734
  },
4749
4735
  error: {
4750
- background: "sys.color.errorContainer",
4751
- text: "sys.color.onErrorContainer",
4752
- placeholder: "sys.color.onErrorContainer",
4753
- borderRest: "sys.color.error",
4754
- borderHover: "sys.color.error",
4755
- borderActive: "sys.color.error"
4736
+ background: "sys.color.background.danger",
4737
+ text: "sys.color.text.danger",
4738
+ placeholder: "sys.color.text.danger",
4739
+ borderRest: "sys.color.border.danger",
4740
+ borderHover: "sys.color.border.danger",
4741
+ borderActive: "sys.color.border.danger"
4756
4742
  }
4757
4743
  },
4758
4744
  states: {
@@ -4772,32 +4758,33 @@ var textarea_spec_default = {
4772
4758
  focusRing: {
4773
4759
  composition: "outward",
4774
4760
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
4775
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
4776
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
4761
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
4762
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
4777
4763
  },
4778
- 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."
4764
+ 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."
4779
4765
  },
4780
4766
  disabled: {
4781
4767
  overlay: null,
4782
- background: "sys.color.surfaceContainerLow",
4783
- containerOpacity: "sys.state.disabled",
4768
+ background: "sys.color.background.disabled",
4769
+ text: "sys.color.text.disabled",
4770
+ placeholder: "sys.color.text.disabled",
4771
+ border: "sys.color.border.bold",
4784
4772
  suppressFocusRing: true,
4785
- cursor: "not-allowed"
4773
+ cursor: "not-allowed",
4774
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
4786
4775
  }
4787
4776
  },
4788
4777
  focusIndicator: {
4789
- description: "Same outward 3-layer ring as input.focusIndicator.",
4778
+ description: "Same outward single ring as input.focusIndicator.",
4790
4779
  composition: "outward",
4791
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
4780
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
4792
4781
  overlay: {
4793
4782
  color: "label",
4794
4783
  opacity: "sys.state.focus"
4795
4784
  },
4796
4785
  ring: {
4797
- outerWidth: "sys.borderWidth.thin",
4798
- outerColor: "sys.color.focus",
4799
- insetWidth: "sys.borderWidth.hairline",
4800
- insetColor: "sys.color.focusInset"
4786
+ width: "sys.borderWidth.hairline",
4787
+ color: "sys.color.border.focused"
4801
4788
  },
4802
4789
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
4803
4790
  },
@@ -4854,7 +4841,7 @@ var search_spec_default = {
4854
4841
  },
4855
4842
  leading: {
4856
4843
  required: true,
4857
- 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.",
4844
+ 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.",
4858
4845
  intrinsic: true
4859
4846
  },
4860
4847
  input: {
@@ -4877,18 +4864,18 @@ var search_spec_default = {
4877
4864
  slotGap: "sys.layout.inline.md",
4878
4865
  radius: "sys.radius.full",
4879
4866
  borderWidth: "sys.borderWidth.hairline",
4880
- activeStrokeWeight: "sys.borderWidth.thin",
4867
+ activeStrokeWeight: "sys.borderWidth.hairline",
4881
4868
  textTypo: "sys.typo.body.md",
4882
4869
  iconSize: "sys.icon.md"
4883
4870
  },
4884
4871
  appearances: {
4885
4872
  default: {
4886
4873
  background: "transparent",
4887
- text: "sys.color.onSurface",
4888
- placeholder: "sys.color.outline",
4889
- borderRest: "sys.color.outlineVariant",
4890
- borderHover: "sys.color.outline",
4891
- borderActive: "sys.color.onSurface"
4874
+ text: "sys.color.text.default",
4875
+ placeholder: "sys.color.border.boldest",
4876
+ borderRest: "sys.color.border.default",
4877
+ borderHover: "sys.color.border.boldest",
4878
+ borderActive: "sys.color.border.focused"
4892
4879
  }
4893
4880
  },
4894
4881
  states: {
@@ -4918,33 +4905,34 @@ var search_spec_default = {
4918
4905
  focusRing: {
4919
4906
  composition: "outward",
4920
4907
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
4921
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
4922
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
4908
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
4909
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
4923
4910
  },
4924
- 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)."
4911
+ 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)."
4925
4912
  },
4926
4913
  disabled: {
4927
4914
  overlay: null,
4928
- background: "sys.color.surfaceContainerLow",
4929
- containerOpacity: "sys.state.disabled",
4915
+ background: "sys.color.background.disabled",
4916
+ text: "sys.color.text.disabled",
4917
+ placeholder: "sys.color.text.disabled",
4918
+ border: "sys.color.border.bold",
4930
4919
  suppressClear: true,
4931
4920
  suppressFocusRing: true,
4932
- cursor: "not-allowed"
4921
+ cursor: "not-allowed",
4922
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
4933
4923
  }
4934
4924
  },
4935
4925
  focusIndicator: {
4936
4926
  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.",
4937
4927
  composition: "outward",
4938
- compositionReason: "Action affordance with breathing room around it; the 3px outward extent is reserved by the surrounding layout.",
4928
+ compositionReason: "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
4939
4929
  overlay: {
4940
4930
  color: "label",
4941
4931
  opacity: "sys.state.focus"
4942
4932
  },
4943
4933
  ring: {
4944
- outerWidth: "sys.borderWidth.thin",
4945
- outerColor: "sys.color.focus",
4946
- insetWidth: "sys.borderWidth.hairline",
4947
- insetColor: "sys.color.focusInset"
4934
+ width: "sys.borderWidth.hairline",
4935
+ color: "sys.color.border.focused"
4948
4936
  },
4949
4937
  trigger: ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
4950
4938
  },
@@ -5000,7 +4988,7 @@ var select_spec_default = {
5000
4988
  leadingIcon: {
5001
4989
  type: "node",
5002
4990
  optional: true,
5003
- 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."
4991
+ 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."
5004
4992
  },
5005
4993
  onOpen: {
5006
4994
  type: "function",
@@ -5057,7 +5045,7 @@ var select_spec_default = {
5057
5045
  slotGap: "sys.layout.inline.md",
5058
5046
  radius: "sys.radius.md",
5059
5047
  borderWidth: "sys.borderWidth.hairline",
5060
- activeStrokeWeight: "sys.borderWidth.thin",
5048
+ activeStrokeWeight: "sys.borderWidth.hairline",
5061
5049
  groupGap: "sys.layout.stack.xs",
5062
5050
  labelTypo: "sys.typo.label.md",
5063
5051
  helperTypo: "sys.typo.body.sm",
@@ -5067,28 +5055,28 @@ var select_spec_default = {
5067
5055
  iconSize: "sys.icon.md"
5068
5056
  },
5069
5057
  groupColors: {
5070
- label: "sys.color.onSurface",
5071
- helper: "sys.color.onSurfaceVariant",
5072
- helperError: "sys.color.error",
5073
- count: "sys.color.onSurfaceVariant",
5074
- countCurrent: "sys.color.onSurface"
5058
+ label: "sys.color.text.default",
5059
+ helper: "sys.color.text.subtle",
5060
+ helperError: "sys.color.text.danger",
5061
+ count: "sys.color.text.subtle",
5062
+ countCurrent: "sys.color.text.default"
5075
5063
  },
5076
5064
  appearances: {
5077
5065
  default: {
5078
5066
  background: "transparent",
5079
- text: "sys.color.onSurface",
5080
- placeholder: "sys.color.outline",
5081
- borderRest: "sys.color.outlineVariant",
5082
- borderHover: "sys.color.outline",
5083
- borderActive: "sys.color.onSurface"
5067
+ text: "sys.color.text.default",
5068
+ placeholder: "sys.color.border.boldest",
5069
+ borderRest: "sys.color.border.default",
5070
+ borderHover: "sys.color.border.boldest",
5071
+ borderActive: "sys.color.border.focused"
5084
5072
  },
5085
5073
  error: {
5086
- background: "sys.color.errorContainer",
5087
- text: "sys.color.onErrorContainer",
5088
- placeholder: "sys.color.onErrorContainer",
5089
- borderRest: "sys.color.error",
5090
- borderHover: "sys.color.error",
5091
- borderActive: "sys.color.error"
5074
+ background: "sys.color.background.danger",
5075
+ text: "sys.color.text.danger",
5076
+ placeholder: "sys.color.text.danger",
5077
+ borderRest: "sys.color.border.danger",
5078
+ borderHover: "sys.color.border.danger",
5079
+ borderActive: "sys.color.border.danger"
5092
5080
  }
5093
5081
  },
5094
5082
  states: {
@@ -5115,21 +5103,24 @@ var select_spec_default = {
5115
5103
  focusRing: {
5116
5104
  composition: "outward",
5117
5105
  layer: "::after overlay \u2014 position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
5118
- innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.focusInset" },
5119
- outerRing: { width: "sys.borderWidth.thin", color: "sys.color.focus" }
5106
+ innerCounterRing: { width: "sys.borderWidth.hairline", color: "sys.color.border.focused" },
5107
+ outerRing: { width: "sys.borderWidth.thin", color: "sys.color.border.focused" }
5120
5108
  },
5121
- 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)."
5109
+ 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)."
5122
5110
  },
5123
5111
  disabled: {
5124
5112
  overlay: null,
5125
- background: "sys.color.surfaceContainerLow",
5126
- containerOpacity: "sys.state.disabled",
5113
+ background: "sys.color.background.disabled",
5114
+ text: "sys.color.text.disabled",
5115
+ placeholder: "sys.color.text.disabled",
5116
+ border: "sys.color.border.bold",
5127
5117
  suppressFocusRing: true,
5128
- cursor: "not-allowed"
5118
+ cursor: "not-allowed",
5119
+ note: "Explicit disabled (no opacity): neutral disabled fill + bold border + disabled text/placeholder."
5129
5120
  }
5130
5121
  },
5131
5122
  focusIndicator: {
5132
- description: "Same keyboard-focus indicator as Input \u2014 outward two-layer ring composed over the active stroke.",
5123
+ description: "Same keyboard-focus indicator as Input \u2014 outward single ring composed over the active stroke.",
5133
5124
  composition: "outward",
5134
5125
  compositionReason: "Action affordance with breathing room around it.",
5135
5126
  overlay: {
@@ -5137,10 +5128,8 @@ var select_spec_default = {
5137
5128
  opacity: "sys.state.focus"
5138
5129
  },
5139
5130
  ring: {
5140
- outerWidth: "sys.borderWidth.thin",
5141
- outerColor: "sys.color.focus",
5142
- insetWidth: "sys.borderWidth.hairline",
5143
- insetColor: "sys.color.focusInset"
5131
+ width: "sys.borderWidth.hairline",
5132
+ color: "sys.color.border.focused"
5144
5133
  },
5145
5134
  trigger: ":focus-visible"
5146
5135
  },
@@ -5215,17 +5204,17 @@ function FormFieldBox({
5215
5204
  "--field-group-gap": tokenToCss(spec.sizing.groupGap),
5216
5205
  "--field-bg": tokenToCss(app.background),
5217
5206
  "--field-bg-disabled": tokenToCss(spec.states.disabled.background),
5218
- "--field-text": tokenToCss(app.text),
5219
- "--field-placeholder": tokenToCss(app.placeholder),
5220
- "--field-border": tokenToCss(app.borderRest),
5207
+ // Disabled swaps text / placeholder / border to the explicit disabled
5208
+ // tokens (no opacity) — the field box paints them via these vars.
5209
+ "--field-text": tokenToCss(isDisabled ? spec.states.disabled.text : app.text),
5210
+ "--field-placeholder": tokenToCss(
5211
+ isDisabled ? spec.states.disabled.placeholder : app.placeholder
5212
+ ),
5213
+ "--field-border": tokenToCss(isDisabled ? spec.states.disabled.border : app.borderRest),
5221
5214
  "--field-border-hover": tokenToCss(app.borderHover),
5222
5215
  "--field-border-active": tokenToCss(app.borderActive),
5223
5216
  "--field-overlay-pressed": tokenToCss(spec.states.pressed.overlay.opacity),
5224
- "--field-disabled-opacity": tokenToCss(spec.states.disabled.containerOpacity),
5225
- "--field-focus-outer-width": tokenToCss(spec.focusIndicator.ring.outerWidth),
5226
- "--field-focus-outer-color": tokenToCss(spec.focusIndicator.ring.outerColor),
5227
- "--field-focus-inset-width": tokenToCss(spec.focusIndicator.ring.insetWidth),
5228
- "--field-focus-inset-color": tokenToCss(spec.focusIndicator.ring.insetColor),
5217
+ "--field-focus-outer-color": tokenToCss(spec.focusIndicator.ring.color),
5229
5218
  ...typoStyles(spec.sizing.textTypo)
5230
5219
  };
5231
5220
  const handleChange = (event) => {
@@ -5817,7 +5806,7 @@ var sub_spec_default = {
5817
5806
  appearance: {
5818
5807
  containerFill: "transparent",
5819
5808
  labelTypo: "sys.typo.label.md",
5820
- labelColor: "sys.color.onSurfaceVariant",
5809
+ labelColor: "sys.color.text.subtle",
5821
5810
  paddingInline: "sys.layout.container.md",
5822
5811
  paddingBlockStart: "sys.layout.stack.lg",
5823
5812
  paddingBlockEnd: "sys.layout.stack.xs",