@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
@@ -24,7 +24,7 @@
24
24
  "timestamp": {
25
25
  "type": "string",
26
26
  "optional": true,
27
- "description": "Inline timestamp painted after the name on the primary line, in `label.sm` / `sys.color.outline` — one tonal step further than the name. Reach for it on Feed Post; omit on Feed Ad."
27
+ "description": "Inline timestamp painted after the name on the primary line, in `label.sm` / `sys.color.border.boldest` — one tonal step further than the name. Reach for it on Feed Post; omit on Feed Ad."
28
28
  },
29
29
  "followAction": {
30
30
  "type": "boolean",
@@ -78,26 +78,26 @@
78
78
  },
79
79
  "name": {
80
80
  "required": true,
81
- "description": "Entity name. `sys.typo.label.sm` (12 / Semibold) / `sys.color.onSurface`. Renders as `<a>` when `nameHref` is set, `<span>` otherwise. Single line; truncates with ellipsis.",
81
+ "description": "Entity name. `sys.typo.label.sm` (12 / Semibold) / `sys.color.text.default`. Renders as `<a>` when `nameHref` is set, `<span>` otherwise. Single line; truncates with ellipsis.",
82
82
  "accepts": [
83
83
  "text"
84
84
  ]
85
85
  },
86
86
  "timestamp": {
87
87
  "required": false,
88
- "description": "Inline timestamp after the name. `sys.typo.label.sm` (12 / Semibold) / `sys.color.outline` — one tonal step further than the name so the timestamp recedes.",
88
+ "description": "Inline timestamp after the name. `sys.typo.label.sm` (12 / Semibold) / `sys.color.border.boldest` — one tonal step further than the name so the timestamp recedes.",
89
89
  "accepts": [
90
90
  "text"
91
91
  ]
92
92
  },
93
93
  "followAction": {
94
94
  "required": false,
95
- "description": "Inline follow toggle at the primary line's trailing edge. Bare text affordance (no chrome) — `sys.color.primary` at rest, `sys.color.onSurfaceVariant` when active. A `·` separator precedes it.",
95
+ "description": "Inline follow toggle at the primary line's trailing edge. Bare text affordance (no chrome) — `sys.color.background.primary` at rest, `sys.color.text.subtle` when active. A `·` separator precedes it.",
96
96
  "intrinsic": true
97
97
  },
98
98
  "subtitle": {
99
99
  "required": false,
100
- "description": "Secondary line plain text. `sys.typo.label.sm` / `sys.color.onSurfaceVariant`. Mutually exclusive with `meta`.",
100
+ "description": "Secondary line plain text. `sys.typo.label.sm` / `sys.color.text.subtle`. Mutually exclusive with `meta`.",
101
101
  "accepts": [
102
102
  "text"
103
103
  ]
@@ -121,14 +121,14 @@
121
121
  "containerAlign": "center",
122
122
  "avatarSize": 32,
123
123
  "nameTypo": "sys.typo.label.sm",
124
- "nameColor": "sys.color.onSurface",
124
+ "nameColor": "sys.color.text.default",
125
125
  "timestampTypo": "sys.typo.label.sm",
126
- "timestampColor": "sys.color.outline",
126
+ "timestampColor": "sys.color.border.boldest",
127
127
  "subtitleTypo": "sys.typo.label.sm",
128
- "subtitleColor": "sys.color.onSurfaceVariant",
128
+ "subtitleColor": "sys.color.text.subtle",
129
129
  "metaTypo": "sys.typo.label.sm",
130
- "metaColor": "sys.color.onSurfaceVariant",
131
- "dotColor": "sys.color.outline",
130
+ "metaColor": "sys.color.text.subtle",
131
+ "dotColor": "sys.color.border.boldest",
132
132
  "dotLineHeight": "1",
133
133
  "dotLineHeightNote": "The middot separator (`·`) inherits the surrounding text's font-size but uses `line-height: 1` so its line-box never exceeds the glyph's font-size — keeps the row's text-line tight even when the inherited line-height would otherwise allow extra vertical space around the middot.",
134
134
  "primaryRowGap": "sys.layout.inline.md",
@@ -20,9 +20,7 @@ import { NavCard } from '@teamblind-chorus/ui';
20
20
  <NavCard label="Cell label here" href="#" />
21
21
  ```
22
22
 
23
- ## Use cases
24
-
25
- ### Nav (with trailing chevron)
23
+ ## Nav
26
24
 
27
25
  `variant="nav"` auto-renders the right-pointing chevron — the explicit drill-in form. Reach for it when the card routes into another surface (settings detail, picker, sub-flow).
28
26
 
@@ -34,7 +32,7 @@ import { NavCard } from '@teamblind-chorus/ui';
34
32
  <NavCard variant="nav" label="Cell label here" href="#" />
35
33
  ```
36
34
 
37
- ### With supporting text
35
+ ## Supporting text
38
36
 
39
37
  Two-line variant — primary label on top, supporting metadata below at `onSurfaceVariant`. Works with either variant; pair with `nav` when the drill-in is metadata-bearing.
40
38
 
@@ -51,7 +49,7 @@ import { NavCard } from '@teamblind-chorus/ui';
51
49
  />
52
50
  ```
53
51
 
54
- ### With leading icon
52
+ ## Leading icon
55
53
 
56
54
  A leading 16 × 16 glyph at the inline padding edge. The icon vertically centres on the row's parent block — same `align-items: center` axis as the label column and trailing slot, so the glyph sits on the same midline as the label (one-line) or label + supportingText block (two-line).
57
55
 
@@ -69,7 +67,7 @@ import { BellIcon } from '@teamblind-chorus/ui/icons';
69
67
  />
70
68
  ```
71
69
 
72
- ### With leading thumbnail
70
+ ## Leading thumbnail
73
71
 
74
72
  A leading 32-rung [Thumbnail](../thumbnail/thumbnail.md) — used when the drill target is an entity (channel, person, brand) rather than a chrome action. The thumbnail block-centres on the row's vertical midline, same as an icon leading.
75
73
 
@@ -87,24 +85,7 @@ import { NavCard, Thumbnail } from '@teamblind-chorus/ui';
87
85
  />
88
86
  ```
89
87
 
90
- ### Group
91
-
92
- Multiple NavCards stacked vertically as a `NavCardGroup` — each card stays its own outlined affordance, separated by `sys.layout.stack.xs` (8px) gap. Use when several drill-in cards share a section but should read as discrete cards (vs a List drill-in rail — `text` rows with `nav: true` — where rows tile flush with hairline dividers).
93
-
94
- ```preview
95
- nav-card/group
96
- ---
97
- import { NavCard, NavCardGroup } from '@teamblind-chorus/ui';
98
- import { BellIcon, BookmarkIcon, ProfileIcon } from '@teamblind-chorus/ui/icons';
99
-
100
- <NavCardGroup aria-label="Account">
101
- <NavCard variant="nav" label="Profile" supportingText="Display name, avatar, bio" leading={<ProfileIcon size={16} />} href="#" />
102
- <NavCard variant="nav" label="Saved posts" supportingText="47 posts across 9 channels" leading={<BookmarkIcon size={16} />} href="#" />
103
- <NavCard variant="nav" label="Notifications" leading={<BellIcon size={16} />} href="#" />
104
- </NavCardGroup>
105
- ```
106
-
107
- ### Surface (opaque tier on a non-`surface` host)
88
+ ## Surface
108
89
 
109
90
  `appearance="surface"` paints the card with its own `sys.color.surface` fill so it reads as an opaque tier. Reach for it when the card sits on a transparent / non-`surface` host (coloured hero, tonal band, BottomSheet content slot) and the default transparent fill would let the card blend in.
110
91
 
@@ -129,9 +110,26 @@ import { BellIcon, BookmarkIcon, ProfileIcon } from '@teamblind-chorus/ui/icons'
129
110
  </div>
130
111
  ```
131
112
 
113
+ ## Group
114
+
115
+ Multiple NavCards stacked vertically as a `NavCardGroup` — each card stays its own outlined affordance, separated by `sys.layout.stack.xs` (8px) gap. Use when several drill-in cards share a section but should read as discrete cards (vs a List drill-in rail — `text` rows with `nav: true` — where rows tile flush with hairline dividers).
116
+
117
+ ```preview
118
+ nav-card/group
119
+ ---
120
+ import { NavCard, NavCardGroup } from '@teamblind-chorus/ui';
121
+ import { BellIcon, BookmarkIcon, ProfileIcon } from '@teamblind-chorus/ui/icons';
122
+
123
+ <NavCardGroup aria-label="Account">
124
+ <NavCard variant="nav" label="Profile" supportingText="Display name, avatar, bio" leading={<ProfileIcon size={16} />} href="#" />
125
+ <NavCard variant="nav" label="Saved posts" supportingText="47 posts across 9 channels" leading={<BookmarkIcon size={16} />} href="#" />
126
+ <NavCard variant="nav" label="Notifications" leading={<BellIcon size={16} />} href="#" />
127
+ </NavCardGroup>
128
+ ```
129
+
132
130
  ## Slots
133
131
 
134
- - **container** — outlined rounded box. `surface` fill, `radius.md` corners, hairline `outlineVariant` stroke painted as inset box-shadow (never `border:`).
132
+ - **container** — outlined rounded box. `surface` fill, `radius.md` corners, hairline `border.default` stroke painted as inset box-shadow (never `border:`).
135
133
  - **leading** *(optional)* — 16px icon (`currentColor`) or 32-rung [Thumbnail](../thumbnail/thumbnail.md). Block-centred on the row's vertical midline — same contract for icon and thumbnail. Omitted by default; label flushes to the inline padding edge.
136
134
  - **labelCol** — vertical column holding label and (optional) supportingText. `min-width: 0` so both lines truncate.
137
135
  - **label** — primary card text. 14px / Regular / `onSurface`. Single line; truncates.
@@ -142,7 +140,7 @@ import { BellIcon, BookmarkIcon, ProfileIcon } from '@teamblind-chorus/ui/icons'
142
140
 
143
141
  | Slot | Token bindings |
144
142
  |----------------|----------------|
145
- | container | `surface` fill, `radius.md` corners, hairline `outlineVariant` inset box-shadow, `48px` min-height, `8px` block / `16px` inline padding |
143
+ | container | `surface` fill, `radius.md` corners, hairline `border.default` inset box-shadow, `48px` min-height, `8px` block / `16px` inline padding |
146
144
  | leading | 16 × 16 (`sys.icon.md`) glyph in `currentColor` or 32 × 32 [Thumbnail](../thumbnail/thumbnail.md). Block-centred on the row's vertical midline (same contract for icon and thumbnail). `sys.layout.inline.md` (8px) gap to label column |
147
145
  | labelCol | Flex column, `min-width: 0`, no inter-line margin (line-height carries the rhythm) |
148
146
  | label | `sys.typo.body.sm` (14 / Regular) / `onSurface` |
@@ -172,7 +170,7 @@ A single rung. Min-height 48 (touch-target floor); consumers cannot shrink or gr
172
170
 
173
171
  ## Focus indicator
174
172
 
175
- Outward 3-layer ring painted on the container's outer edge via an `::after` overlay (rest stroke sits on `::before`). Trigger: `:focus-visible`. NavCard sits as its own bounded surface with margin to siblings, so an outward ring reads cleanly — see [Focus ring composition](../../DESIGN.md#focus-ring-composition).
173
+ Outward single ring painted on the container's outer edge via an `::after` overlay (rest stroke sits on `::before`). Trigger: `:focus-visible`. NavCard sits as its own bounded surface with margin to siblings, so an outward ring reads cleanly — see [Focus ring composition](../../DESIGN.md#focus-ring-composition).
176
174
 
177
175
  ## Behavior
178
176
 
@@ -2,7 +2,7 @@
2
2
  "$schema": "../../spec.schema.json",
3
3
  "name": "NavCard",
4
4
  "family": "nav-card",
5
- "description": "Outlined, rounded single-row card. Single label (optional supporting line) over a `surface`-toned box with a hairline `outlineVariant` inset-shadow stroke and `radius.md` corners. Two variants select the trailing affordance: `default` ships no trailing icon (bare labelled card — settings entry, scope tile, informational drill-target), `nav` auto-renders the right-pointing chevron for explicit drill-in semantics. Whole card is the click target — keyboard focus, hover overlay, and tap commit all sit on the card. Reach for it when one row needs to read as its own discrete affordance rather than as one entry in a [List](../list/list.md) drill-in stack (`text` rows with `nav: true`).",
5
+ "description": "Outlined, rounded single-row card. Single label (optional supporting line) over a `surface`-toned box with a hairline `border.default` inset-shadow stroke and `radius.md` corners. Two variants select the trailing affordance: `default` ships no trailing icon (bare labelled card — settings entry, scope tile, informational drill-target), `nav` auto-renders the right-pointing chevron for explicit drill-in semantics. Whole card is the click target — keyboard focus, hover overlay, and tap commit all sit on the card. Reach for it when one row needs to read as its own discrete affordance rather than as one entry in a [List](../list/list.md) drill-in stack (`text` rows with `nav: true`).",
6
6
  "element": "button",
7
7
  "props": {
8
8
  "variant": {
@@ -35,7 +35,7 @@
35
35
  "type": "enum",
36
36
  "values": ["default", "surface"],
37
37
  "default": "default",
38
- "description": "Container fill. `default` is transparent — the card's identity is the outlined chrome (hairline + radius + label + chevron) and the host surface tone reads through. `surface` paints `sys.color.surface` so the card reads as its own opaque tier; reach for it when the card sits on a transparent / non-`surface` host (between bare-surface sections, on a tonal band the card needs to break out of)."
38
+ "description": "Container fill. `default` is transparent — the card's identity is the outlined chrome (hairline + radius + label + chevron) and the host surface tone reads through. `surface` paints `sys.color.surface.default` so the card reads as its own opaque tier; reach for it when the card sits on a transparent / non-`surface` host (between bare-surface sections, on a tonal band the card needs to break out of)."
39
39
  },
40
40
  "href": {
41
41
  "type": "string",
@@ -60,7 +60,7 @@
60
60
  "slots": {
61
61
  "container": {
62
62
  "required": true,
63
- "description": "Outlined rounded box. Transparent fill by default (host tone reads through) — `surface` fill via `appearance=\"surface\"`. `radius.md` corners, hairline `outlineVariant` stroke painted as inset box-shadow (never `border:`). Whole container is the interactive target.",
63
+ "description": "Outlined rounded box. Transparent fill by default (host tone reads through) — `surface` fill via `appearance=\"surface\"`. `radius.md` corners, hairline `border.default` stroke painted as inset box-shadow (never `border:`). Whole container is the interactive target.",
64
64
  "intrinsic": true
65
65
  },
66
66
  "leading": {
@@ -95,17 +95,17 @@
95
95
  "paddingBlock": "sys.layout.container.xs",
96
96
  "paddingInline": "sys.layout.container.md",
97
97
  "outlineWidth": "sys.borderWidth.hairline",
98
- "outlineColor": "sys.color.outlineVariant",
98
+ "outlineColor": "sys.color.border.default",
99
99
  "leadingGap": "sys.layout.inline.md",
100
100
  "trailingGap": "sys.layout.inline.md",
101
101
  "leadingIconSize": "sys.icon.md",
102
102
  "labelTypo": "sys.typo.body.sm",
103
- "labelColor": "sys.color.onSurface",
103
+ "labelColor": "sys.color.text.default",
104
104
  "supportingTypo": "sys.typo.label.sm",
105
- "supportingColor": "sys.color.onSurfaceVariant",
105
+ "supportingColor": "sys.color.text.subtle",
106
106
  "supportingOffset": "0",
107
107
  "trailingIconSize": "sys.icon.md",
108
- "trailingIconColor": "sys.color.onSurfaceVariant",
108
+ "trailingIconColor": "sys.color.text.subtle",
109
109
  "groupGap": "sys.layout.stack.xs"
110
110
  },
111
111
  "appearances": {
@@ -114,7 +114,7 @@
114
114
  "note": "No fill — the host surface tone reads through. The canonical NavCard: its identity is the outlined chrome (hairline + radius + label + chevron), not a fill. Hover / pressed paint as label-tone overlays mixed on the transparent base so the host tone keeps reading through underneath the state paint."
115
115
  },
116
116
  "surface": {
117
- "background": "sys.color.surface",
117
+ "background": "sys.color.surface.default",
118
118
  "note": "Opaque `surface` fill. Reach for it when the card sits on a transparent / non-`surface` host (a `surfaceContainerLow` tonal band, a coloured hero, a BottomSheet's content slot) and should read as its own opaque tier rather than blending into the host. Outline, label, chevron, and state overlays are unchanged."
119
119
  }
120
120
  },
@@ -130,26 +130,26 @@
130
130
  "focusRing": {
131
131
  "composition": "outward",
132
132
  "layer": "::after overlay — position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
133
- "innerCounterRing": { "width": "sys.borderWidth.hairline", "color": "sys.color.focusInset" },
134
- "outerRing": { "width": "sys.borderWidth.thin", "color": "sys.color.focus" }
133
+ "innerCounterRing": { "width": "sys.borderWidth.hairline", "color": "sys.color.border.focused" },
134
+ "outerRing": { "width": "sys.borderWidth.thin", "color": "sys.color.border.focused" }
135
135
  },
136
- "note": "Keyboard-focus (:focus-visible) visual — a three-layer outward ring on the card's outer edge, with no state-overlay tint (the ring alone carries focus here). Mirrors the `focusIndicator` block for spec-only renderers. Composes over the lifecycle state the card is in."
136
+ "note": "Keyboard-focus (:focus-visible) visual — a single outward ring on the card's outer edge, with no state-overlay tint (the ring alone carries focus here). Mirrors the `focusIndicator` block for spec-only renderers. Composes over the lifecycle state the card is in."
137
137
  },
138
138
  "disabled": {
139
- "containerOpacity": "sys.state.disabled",
140
- "pointerEvents": "none"
139
+ "text": "sys.color.text.disabled",
140
+ "icon": "sys.color.icon.disabled",
141
+ "pointerEvents": "none",
142
+ "note": "Explicit disabled (no opacity): card text to text.disabled, icons to icon.disabled. Border stays border.default."
141
143
  }
142
144
  },
143
145
  "focusIndicator": {
144
- "description": "Keyboard-focus visual painted as a three-layer ring on the card's outer edge. Composes over whichever lifecycle state the card is in.",
146
+ "description": "Keyboard-focus visual painted as a single ring on the card's outer edge. Composes over whichever lifecycle state the card is in.",
145
147
  "composition": "outward",
146
148
  "compositionReason": "NavCard sits as its own bounded surface with margin to siblings; an outward ring reads cleanly without colliding with a neighbouring row's stroke.",
147
149
  "ring": {
148
- "outerWidth": "sys.borderWidth.thin",
149
- "outerColor": "sys.color.focus",
150
- "insetWidth": "sys.borderWidth.hairline",
151
- "insetColor": "sys.color.focusInset",
152
- "implementation": "outset box-shadow on the container's `::after` overlay; the rest stroke stays painted on `::before` so the two layers don't fight."
150
+ "width": "sys.borderWidth.hairline",
151
+ "color": "sys.color.border.focused",
152
+ "implementation": "outset box-shadow on the container's `::after` overlay; the rest stroke stays painted on `::before` so the rest stroke and focus ring don't fight."
153
153
  },
154
154
  "trigger": ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
155
155
  },
@@ -33,9 +33,7 @@ import { NavList } from '@teamblind-chorus/ui';
33
33
  />
34
34
  ```
35
35
 
36
- ## Use cases
37
-
38
- ### With header action
36
+ ## Header action
39
37
 
40
38
  Extends the header with a trailing `accent` Text Button when the screen has a broader index page or "Manage" route.
41
39
 
@@ -48,11 +46,7 @@ import { NavList } from '@teamblind-chorus/ui';
48
46
  label="Settings"
49
47
  headerAction={{ label: 'Manage', href: '/settings/manage' }}
50
48
  items={[
51
- { value: 'account', label: 'Account', href: '/settings/account' },
52
- { value: 'notifications',label: 'Notifications', href: '/settings/notifications' },
53
- { value: 'privacy', label: 'Privacy', href: '/settings/privacy' },
54
- { value: 'appearance', label: 'Appearance', href: '/settings/appearance' },
55
- { value: 'language', label: 'Language', href: '/settings/language' },
49
+ { value: 'account', label: 'Account', href: '/settings/account' },
56
50
  ]}
57
51
  />
58
52
  ```
@@ -55,17 +55,17 @@
55
55
  }
56
56
  },
57
57
  "sizing": {
58
- "containerFill": "sys.color.surface",
58
+ "containerFill": "sys.color.surface.default",
59
59
  "containerPaddingBlock": "sys.layout.container.lg",
60
60
  "containerPaddingInline": "sys.layout.container.md",
61
61
  "headerToListGap": "sys.layout.stack.md",
62
62
  "labelTypo": "sys.typo.heading.md",
63
- "labelColor": "sys.color.onSurface",
63
+ "labelColor": "sys.color.text.default",
64
64
  "headerActionRendersAs": "Button variant='text' size='xsmall' appearance='accent' — link-affordance accent rule.",
65
65
  "rowComposition": "list/entry label-only row (no thumbnail) — label.md primary, optional label.sm description line, family-default min-height (ref.space.600 = 48), leading column collapsed (0 leading-to-text gap), trailing slot filled with a default Icon Button (variant='icon', size='medium', icon=<ChevronRightIcon />).",
66
66
  "rowInlinePaddingNote": "Each row keeps the list/entry native sys.layout.container.md inline padding (the tap target reaches the surface edge) and adds margin-inline: calc(-1 * sys.layout.container.md) so the visible label lines up with the section's content rail (aligned with the header label at 16 from the surface).",
67
67
  "dividerWidth": "sys.borderWidth.hairline",
68
- "dividerColor": "sys.color.outlineVariant",
68
+ "dividerColor": "sys.color.border.default",
69
69
  "dividerInset": "list/entry default — 16 / 16 inset from both row edges. Label-only rows always take the default inset regardless of `size` (no avatar column to anchor against)."
70
70
  },
71
71
  "rowProps": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 🇰🇷 한국어: [`i18n/ko/schema/components/navigation-bar/main.md`](../../../i18n/ko/schema/components/navigation-bar/main.md)
4
4
 
5
- The landing-screen top bar — anchored to a tab root (feed, inbox, profile). A leading menu glyph plus left-aligned page name sit at the start; **up to four** trailing icon actions (conventionally search, chat, profile) sit at the end. Title carries the system's largest page-level rung (`typo.heading.lg`, 24/Semibold). The same row also serves a **drill-in (content-detail) screen** — pass `onBack` instead of `onMenuClick` and the leading glyph swaps to a back chevron, with the trailing cluster carrying up to four actions (see [Use cases](#use-cases)).
5
+ The landing-screen top bar — anchored to a tab root (feed, inbox, profile). A leading menu glyph plus left-aligned page name sit at the start; **up to four** trailing icon actions (conventionally search, chat, profile) sit at the end. Title carries the system's largest page-level rung (`typo.heading.lg`, 24/Semibold). The same row also serves a **drill-in (content-detail) screen** — pass `onBack` instead of `onMenuClick` and the leading glyph swaps to a back chevron, with the trailing cluster carrying up to four actions (see [Drill-in](#drill-in)).
6
6
 
7
7
  **Reach for this when** the screen is a tab root and needs the menu drawer plus a small set of global affordances, **or** when it's a content-detail drill-in (a post / article reached from a feed) needing back navigation plus a share-and-save cluster. **Skip when** you need a centred title with a single action (use [Sub](./sub.md)) or are on a dedicated search page (use [Search](./search.md)).
8
8
 
@@ -36,9 +36,7 @@ import { SearchIcon, ChatIcon, ProfileIcon } from '@teamblind-chorus/ui/icons';
36
36
  />
37
37
  ```
38
38
 
39
- ## Use cases
40
-
41
- ### With a text title in place of the logotype
39
+ ## Text title
42
40
 
43
41
  Names the screen in words. Plain text at `typo.heading.lg` (24/Semibold) `onSurface`; same 24-tall rhythm as the logotype, ellipsis on narrow.
44
42
 
@@ -60,7 +58,7 @@ import { SearchIcon, ChatIcon, ProfileIcon } from '@teamblind-chorus/ui/icons';
60
58
  />
61
59
  ```
62
60
 
63
- ### With one trailing action
61
+ ## Single action
64
62
 
65
63
  Single trailing affordance — e.g. search on an Inbox screen.
66
64
 
@@ -79,7 +77,7 @@ import { SearchIcon } from '@teamblind-chorus/ui/icons';
79
77
  />
80
78
  ```
81
79
 
82
- ### Drill-in detail screen (back chevron)
80
+ ## Drill-in
83
81
 
84
82
  A content-detail screen reached from a feed / list (a post, an article, a saved item). Pass `onBack` — the leading glyph becomes a back chevron — and the trailing cluster carries up to four actions (share / notify / bookmark / more). Same row, same 56-tall geometry; only the entry point differs.
85
83
 
@@ -108,7 +106,7 @@ import { ShareIcon, BellOffIcon, BookmarkIcon, EllipsisHorizontalIcon } from '@t
108
106
  />
109
107
  ```
110
108
 
111
- ### Drill-in with a text title and a smaller cluster
109
+ ## Drill-in text title
112
110
 
113
111
  Names the source — the channel or author the post belongs to. The cluster is `1..4` actions; drop to just the essentials (share + more) when the screen has fewer affordances.
114
112
 
@@ -129,7 +127,7 @@ import { ShareIcon, EllipsisHorizontalIcon } from '@teamblind-chorus/ui/icons';
129
127
  />
130
128
  ```
131
129
 
132
- ### Truncation (safety net)
130
+ ## Truncation
133
131
 
134
132
  Long page name truncates with ellipsis. Author concise titles (*Home*, *Inbox*) so the bar never resorts to ellipsis.
135
133
 
@@ -162,9 +160,9 @@ import { SearchIcon, ChatIcon, ProfileIcon } from '@teamblind-chorus/ui/icons';
162
160
  | Slot | Container | Color |
163
161
  |-----------------------|--------------------|------------------------------------------|
164
162
  | **Bar container** | `sys.color.surface` fill, 8px block / 16px inline padding, no border, no shadow at rest. | — |
165
- | **Leading icon** | Transparent capsule, 24px glyph centred. | `sys.color.onSurface` |
166
- | **Title** | Brand logotype `<img>` at 24px tall (width auto) by default; plain-text fallback at `heading.lg`. Not interactive. | `sys.color.onSurface` (text fallback) |
167
- | **Trailing icon(s)** | Transparent capsule, 24px glyph centred. Capsules sit flush, no inter-icon gap. | `sys.color.onSurface` |
163
+ | **Leading icon** | Transparent capsule, 24px glyph centred. | `sys.color.text.default` |
164
+ | **Title** | Brand logotype `<img>` at 24px tall (width auto) by default; plain-text fallback at `heading.lg`. Not interactive. | `sys.color.text.default` (text fallback) |
165
+ | **Trailing icon(s)** | Transparent capsule, 24px glyph centred. Capsules sit flush, no inter-icon gap. | `sys.color.text.default` |
168
166
 
169
167
  ## Sizes
170
168
 
@@ -80,13 +80,13 @@
80
80
  "trailingIconSize": "sys.icon.lg"
81
81
  },
82
82
  "appearance": {
83
- "containerFill": "sys.color.surface",
84
- "leadingIconColor": "sys.color.onSurface",
85
- "titleColor": "sys.color.onSurface",
86
- "trailingIconColor": "sys.color.onSurface"
83
+ "containerFill": "sys.color.surface.default",
84
+ "leadingIconColor": "sys.color.icon.default",
85
+ "titleColor": "sys.color.text.default",
86
+ "trailingIconColor": "sys.color.icon.default"
87
87
  },
88
88
  "states": {
89
- "note": "Bar itself has no interactive state. Icon slots carry the standard Icon Button state recipe — default / hovered (sys.state.hover overlay) / pressed (sys.state.pressed overlay) / disabled / focused (three-layer focus ring). Title carries no states."
89
+ "note": "Bar itself has no interactive state. Icon slots carry the standard Icon Button state recipe — default / hovered (sys.state.hover overlay) / pressed (sys.state.pressed overlay) / disabled / focused (single focus ring). Title carries no states."
90
90
  },
91
91
  "focusIndicator": {
92
92
  "description": "The bar itself isn't a focus target. Its action slots (leading menu, trailing icons) inherit each control's own focus composition — Icon Button → Outward — so the ring belongs to whichever capsule the keyboard lands on. See the contained sub-components for the visual contract.",
@@ -100,7 +100,7 @@
100
100
  "trailingIconCeiling": "Three is the conventional ceiling on a tab root; the drill-in (content-detail) action cluster uses up to four (share / notify / bookmark / more). A fifth belongs in the `more` (•••) overflow — the component slices to four."
101
101
  },
102
102
  "forbidden": [
103
- "brand color on the title / wordmark — header chrome stays on sys.color.surface; the wordmark paints sys.color.onSurface",
103
+ "brand color on the title / wordmark — header chrome stays on sys.color.surface.default; the wordmark paints sys.color.text.default",
104
104
  "more than four trailing actions — the action cluster caps at four; a fifth belongs in the `more` overflow",
105
105
  "leading glyph other than the menu (tab root) or back chevron (drill-in, via onBack) — never an arbitrary custom glyph",
106
106
  "centred title — the Main title is left-aligned next to the leading glyph (a centred title is the `sub` variant)",
@@ -20,9 +20,7 @@ import { NavigationBar } from '@teamblind-chorus/ui';
20
20
  <NavigationBar variant="search" placeholder="Search by keyword" onBack={() => {}} />
21
21
  ```
22
22
 
23
- ## Use cases
24
-
25
- ### With value (clear visible)
23
+ ## Value
26
24
 
27
25
  A non-empty value swaps placeholder for `onSurface` text and reveals the trailing clear (*×*) at the medium 32 × 32 capsule — smaller than the leading back-arrow so it never out-shouts the input. Clicking clear wipes the value, returns focus, and the trailing column collapses; the input's leading edge stays pixel-stable.
28
26
 
@@ -42,7 +40,7 @@ import { NavigationBar } from '@teamblind-chorus/ui';
42
40
  ## Slots
43
41
 
44
42
  - **leading** *(required)* — 24px back-arrow as the canonical [Icon Button](../button/icon.md) capsule (40 × 40 transparent, 24px glyph).
45
- - **input** *(required)* — single-line *bare* text input filling the leftover middle column. Bare means no border, no background, no inset stroke — not a [Search](../form-field/search.md) field. Value in `sys.color.onSurface`, placeholder in `sys.color.outline` (`typo.body.md`, 16/Regular). Caret follows the [system caret rule](../../DESIGN.md#caret).
43
+ - **input** *(required)* — single-line *bare* text input filling the leftover middle column. Bare means no border, no background, no inset stroke — not a [Search](../form-field/search.md) field. Value in `sys.color.text.default`, placeholder in `sys.color.border.boldest` (`typo.body.md`, 16/Regular). Caret follows the [system caret rule](../../DESIGN.md#caret).
46
44
  - **trailing** *(conditional)* — clear (*×*) [Icon Button](../button/icon.md) hosting `XCircleFillIcon`. Always Icon Button's `medium` size (32 × 32 capsule, 16px glyph) so it never over-claims weight against the bare input. Rendered only when value is non-empty; wipes value and returns focus.
47
45
 
48
46
  ## Anatomy
@@ -51,10 +49,10 @@ Three-column grid (leading / input / trailing) — side columns size to content,
51
49
 
52
50
  | Slot | Container | Color |
53
51
  |-----------------------|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
54
- | **Bar container** | `sys.color.surface` fill, 8px block / 16px inline padding, no shadow at rest, **1px bottom divider in `sys.color.outlineVariant`** painted as inset `box-shadow`. | — |
55
- | **Leading** | Transparent Icon Button capsule (8 padding around 24px glyph). | `sys.color.onSurface` |
56
- | **Input** | Bare text — no border, no background, no inset stroke. | Value: `sys.color.onSurface`. Placeholder: `sys.color.outline`. Caret: `sys.color.primary`. |
57
- | **Trailing (clear)** | Transparent Icon Button **medium** capsule (32 × 32, 16px glyph). | `sys.color.onSurface` |
52
+ | **Bar container** | `sys.color.surface` fill, 8px block / 16px inline padding, no shadow at rest, **1px bottom divider in `sys.color.border.default`** painted as inset `box-shadow`. | — |
53
+ | **Leading** | Transparent Icon Button capsule (8 padding around 24px glyph). | `sys.color.text.default` |
54
+ | **Input** | Bare text — no border, no background, no inset stroke. | Value: `sys.color.text.default`. Placeholder: `sys.color.border.boldest`. Caret: `sys.color.background.primary`. |
55
+ | **Trailing (clear)** | Transparent Icon Button **medium** capsule (32 × 32, 16px glyph). | `sys.color.text.default` |
58
56
 
59
57
  The 1px bottom divider (unique to Search) keeps the bare input from bleeding into the results list below; painted as inset `box-shadow` so it never participates in layout.
60
58
 
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "input": {
67
67
  "required": true,
68
- "description": "Single-line bare text input that fills the leftover middle column. Bare = no `border`, no `background`, no inset stroke — it is *not* a [Search bar](../form-field/search.md) field. Renders the value in `sys.color.onSurface` when present; renders the placeholder in `sys.color.outline` when empty. `body.md` (16/Regular). The bar carries the visible search affordance via the placeholder and the page context; the field itself has no chrome of its own.",
68
+ "description": "Single-line bare text input that fills the leftover middle column. Bare = no `border`, no `background`, no inset stroke — it is *not* a [Search bar](../form-field/search.md) field. Renders the value in `sys.color.text.default` when present; renders the placeholder in `sys.color.border.boldest` when empty. `body.md` (16/Regular). The bar carries the visible search affordance via the placeholder and the page context; the field itself has no chrome of its own.",
69
69
  "accepts": [
70
70
  "text"
71
71
  ]
@@ -91,20 +91,20 @@
91
91
  "trailingIconSize": "sys.icon.md"
92
92
  },
93
93
  "appearance": {
94
- "containerFill": "sys.color.surface",
95
- "containerBottomDivider": "sys.color.outlineVariant",
96
- "leadingColor": "sys.color.onSurface",
97
- "inputText": "sys.color.onSurface",
98
- "inputPlaceholder": "sys.color.outline",
99
- "inputCaret": "sys.color.onSurface",
100
- "trailingColor": "sys.color.onSurface"
94
+ "containerFill": "sys.color.surface.default",
95
+ "containerBottomDivider": "sys.color.border.default",
96
+ "leadingColor": "sys.color.text.default",
97
+ "inputText": "sys.color.text.default",
98
+ "inputPlaceholder": "sys.color.border.boldest",
99
+ "inputCaret": "sys.color.text.default",
100
+ "trailingColor": "sys.color.text.default"
101
101
  },
102
102
  "layout": {
103
103
  "grid": "Three-column grid: leading / input / trailing. Side columns size to content (auto); the input column takes the leftover space (`minmax(0, 1fr)`). Same shape as Page's grid — only the centre slot's contents differ (a bare input instead of a centred title). When the trailing column collapses (value empty → clear hidden), the input column expands to consume the freed space; the field never reflows its leading edge.",
104
104
  "noTitleSlot": "There is no separate title slot; the input fills the role the Page bar would give the title. Adding a title above or beside the input would compete with the placeholder for the search affordance and break the bar's 56 footprint."
105
105
  },
106
106
  "states": {
107
- "note": "The bar carries no interactive state of its own. The leading and trailing slots inherit Icon Button's recipe (default / hovered / pressed / focused — overlays + three-layer focus ring). The Search bar deliberately omits a `disabled` state: the only screen a `navigation-bar/search` ever lives on is the search results page itself, and a non-typable search bar on that page reduces the surface to a dead chrome strip with no escape affordance beyond the back-arrow. If search must be gated (offline / throttled / paused indexing), gate the *trigger* on the prior screen instead and never route into this bar. The input slot follows the bare-text-field shape — no border, no fill, no rest-vs-active stroke; only the caret and the placeholder→value colour swap signal interaction. See `inputStates` for the input-only details.",
107
+ "note": "The bar carries no interactive state of its own. The leading and trailing slots inherit Icon Button's recipe (default / hovered / pressed / focused — overlays + single focus ring). The Search bar deliberately omits a `disabled` state: the only screen a `navigation-bar/search` ever lives on is the search results page itself, and a non-typable search bar on that page reduces the surface to a dead chrome strip with no escape affordance beyond the back-arrow. If search must be gated (offline / throttled / paused indexing), gate the *trigger* on the prior screen instead and never route into this bar. The input slot follows the bare-text-field shape — no border, no fill, no rest-vs-active stroke; only the caret and the placeholder→value colour swap signal interaction. See `inputStates` for the input-only details.",
108
108
  "inputStates": {
109
109
  "default": {
110
110
  "caret": "hidden",
@@ -25,9 +25,7 @@ import { NavigationBar, Button } from '@teamblind-chorus/ui';
25
25
  />
26
26
  ```
27
27
 
28
- ## Use cases
29
-
30
- ### With icon trailing
28
+ ## Icon trailing
31
29
 
32
30
  The trailing slot carries a single icon.
33
31
 
@@ -44,7 +42,7 @@ import { NavigationBar } from '@teamblind-chorus/ui';
44
42
  />
45
43
  ```
46
44
 
47
- ### With text button trailing
45
+ ## Text Button trailing
48
46
 
49
47
  The trailing slot carries a [Text Button](../button/text.md) — *Skip* or *Done*. Reads as inline 16/Semibold `primary` type at rest.
50
48
 
@@ -61,7 +59,7 @@ import { NavigationBar } from '@teamblind-chorus/ui';
61
59
  />
62
60
  ```
63
61
 
64
- ### Text button pair (composer)
62
+ ## Text Button pair
65
63
 
66
64
  Modal composer bars carry a [Text Button](../button/text.md) on **both** sides — leading `default` appearance for the dismissing *Cancel*, trailing `accent` for the committing *Post* — and **omit the page title**: the pair says everything, and the centre cell keeps a non-heading placeholder so both buttons hold their edge columns. The accent side is the single CTA of the bar; never paint both sides accent, and never swap the sides (commit always trails).
67
65
 
@@ -77,7 +75,7 @@ import { Button, NavigationBar } from '@teamblind-chorus/ui';
77
75
  />
78
76
  ```
79
77
 
80
- ### External page (close-only)
78
+ ## External page
81
79
 
82
80
  External content visited in-app (embedded webview, in-app browser). Leading drops — no flow to step back; trailing is a single close (×) [Icon Button](../button/icon.md).
83
81
 
@@ -93,7 +91,7 @@ import { NavigationBar } from '@teamblind-chorus/ui';
93
91
  />
94
92
  ```
95
93
 
96
- ### Title only
94
+ ## Title only
97
95
 
98
96
  Both side slots empty — for non-dismissible sub-pages (forced confirmation, terms gate).
99
97
 
@@ -108,7 +106,7 @@ import { NavigationBar } from '@teamblind-chorus/ui';
108
106
  />
109
107
  ```
110
108
 
111
- ### Overlay (on hero / cover image)
109
+ ## Overlay
112
110
 
113
111
  `appearance="overlay"` paints a transparent container with fixed-white icons and title — the bar floats over a hero / cover image (canonical host: [Profile header](../profile-header/profile-header.md)). The image beneath provides contrast; theme tokens don't apply. The bar still pays its own `env(safe-area-inset-top)` so the status-bar zone reads cleanly. Staged here via [ProfileHeader](../profile-header/profile-header.md) so the preview matches a real-world consumer.
114
112
 
@@ -137,9 +135,9 @@ import { ProfileHeader } from '@teamblind-chorus/ui';
137
135
  | Slot | Container | Color |
138
136
  |-----------------------|--------------------|------------------------------------------|
139
137
  | **Bar container** | `sys.color.surface` fill, 8px block / 16px inline padding, no border, no shadow at rest. | — |
140
- | **Leading** | Transparent icon capsule (8 padding around 24px glyph). | `sys.color.onSurface` |
141
- | **Title** | Plain text, centred horizontally — not interactive. | `sys.color.onSurface` |
142
- | **Trailing** | Transparent icon capsule, [Toolbar Button](../button/toolbar.md), or [Text Button](../button/text.md). | `sys.color.onSurface` (icon / Toolbar) or `sys.color.primary` (Text Button) |
138
+ | **Leading** | Transparent icon capsule (8 padding around 24px glyph). | `sys.color.text.default` |
139
+ | **Title** | Plain text, centred horizontally — not interactive. | `sys.color.text.default` |
140
+ | **Trailing** | Transparent icon capsule, [Toolbar Button](../button/toolbar.md), or [Text Button](../button/text.md). | `sys.color.text.default` (icon / Toolbar) or `sys.color.background.primary` (Text Button) |
143
141
 
144
142
  ## Sizes
145
143
 
@@ -17,7 +17,7 @@
17
17
  "overlay"
18
18
  ],
19
19
  "default": "surface",
20
- "description": "Container fill and foreground tone. `surface` (default) — opaque `sys.color.surface` fill, `onSurface` icons and title; the canonical page-chrome treatment. `overlay` — transparent container with **fixed white** icons (`ref.palette.white.1000`), used when the bar floats over a hero/cover image (e.g. inside [Profile header](../profile-header/profile-header.md)). In `overlay`, the title slot is intentionally muted — pass `title=\"\"` (empty string) when the host already carries page identity below the bar."
20
+ "description": "Container fill and foreground tone. `surface` (default) — opaque `sys.color.surface.default` fill, `onSurface` icons and title; the canonical page-chrome treatment. `overlay` — transparent container with **fixed white** icons (`ref.palette.white.1000`), used when the bar floats over a hero/cover image (e.g. inside [Profile header](../profile-header/profile-header.md)). In `overlay`, the title slot is intentionally muted — pass `title=\"\"` (empty string) when the host already carries page identity below the bar."
21
21
  },
22
22
  "title": {
23
23
  "type": "string",
@@ -74,11 +74,11 @@
74
74
  },
75
75
  "appearances": {
76
76
  "surface": {
77
- "containerFill": "sys.color.surface",
78
- "leadingColor": "sys.color.onSurface",
79
- "titleColor": "sys.color.onSurface",
80
- "trailingColor": "sys.color.onSurface",
81
- "trailingTextButtonColor": "sys.color.primary",
77
+ "containerFill": "sys.color.surface.default",
78
+ "leadingColor": "sys.color.text.default",
79
+ "titleColor": "sys.color.text.default",
80
+ "trailingColor": "sys.color.text.default",
81
+ "trailingTextButtonColor": "sys.color.text.link",
82
82
  "default": true,
83
83
  "note": "Canonical page chrome — opaque surface fill with onSurface foreground."
84
84
  },
@@ -96,7 +96,7 @@
96
96
  "titleCentring": "Title is anchored to the bar's geometric horizontal centre — measured against the page component container, not against the side slots. A 40px back arrow paired with a 80px primary Toolbar Button still leaves the title perfectly centred; the side slots anchor at the start / end of their respective halves and never displace the title. The action always stays intact; title truncation (ellipsis) kicks in if the natural width exceeds what the bar can give it."
97
97
  },
98
98
  "states": {
99
- "note": "Bar itself has no interactive state. Side slots inherit the state recipe of whichever control they host (Icon Button / Toolbar Button / Text Button) — default / hovered / pressed / disabled / focused via the standard overlays + three-layer focus ring. Title carries no states."
99
+ "note": "Bar itself has no interactive state. Side slots inherit the state recipe of whichever control they host (Icon Button / Toolbar Button / Text Button) — default / hovered / pressed / disabled / focused via the standard overlays + single focus ring. Title carries no states."
100
100
  },
101
101
  "focusIndicator": {
102
102
  "description": "The bar itself isn't a focus target. Its action slots inherit each control's own focus composition — Icon Button → Outward, Toolbar Button → Outward, Text Button → Outward — so the ring belongs to whichever control the keyboard lands on. See the contained sub-components for the visual contract.",
@@ -2,7 +2,7 @@
2
2
  "$schema": "../../family.schema.json",
3
3
  "family": "pagination",
4
4
  "name": "Pagination",
5
- "description": "Decorative dot-position indicator for one-page-at-a-time pagers. An inline element (`span` / inline-flex) sized to its dots — one 6px dot per page; the active dot paints `sys.color.onSurface`, the rest paint `sys.color.outlineVariant`. Presentational only (`aria-hidden`) — the host pager owns horizontal placement (the carousels center it), scroll position, active-index tracking, and keyboard reach; tapping a dot does not navigate. Renders nothing below two pages. Single appearance, single rung. Single-spec family.",
5
+ "description": "Decorative dot-position indicator for one-page-at-a-time pagers. An inline element (`span` / inline-flex) sized to its dots — one 6px dot per page; the active dot paints `sys.color.text.default`, the rest paint `sys.color.border.default`. Presentational only (`aria-hidden`) — the host pager owns horizontal placement (the carousels center it), scroll position, active-index tracking, and keyboard reach; tapping a dot does not navigate. Renders nothing below two pages. Single appearance, single rung. Single-spec family.",
6
6
  "useCases": [
7
7
  "carousel page position (PostCarousel / ProfileCarousel)",
8
8
  "swipeable media gallery position",