@signal9/era-ui 30.8.0 → 32.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 (116) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/ai/artifact/artifact.svelte +1 -1
  3. package/dist/ai/conversations/conversations-item.svelte +1 -1
  4. package/dist/ai/plan/plan-header.svelte +1 -1
  5. package/dist/ai/prompt-input/prompt-input-attachments.svelte +2 -6
  6. package/dist/ai/swarm/swarm-node.svelte +1 -1
  7. package/dist/ai/todo/todo-header.svelte +1 -1
  8. package/dist/ai/todo/todo-item.svelte +1 -1
  9. package/dist/ai/tool/tool-chip.svelte +1 -1
  10. package/dist/ai/web-preview/web-preview.svelte +2 -2
  11. package/dist/ai/workflow/node.svelte +1 -1
  12. package/dist/dev/audit/audits/wall-is-isotropic.js +1 -1
  13. package/dist/docs/css-utilities.js +9 -5
  14. package/dist/era-ui.css +1 -1
  15. package/dist/generated-docs/badge.md +1 -1
  16. package/dist/generated-docs/bar.md +22 -4
  17. package/dist/generated-docs/button.md +38 -4
  18. package/dist/generated-docs/card.md +35 -5
  19. package/dist/generated-docs/chip.md +16 -0
  20. package/dist/generated-docs/llms-full.txt +370 -70
  21. package/dist/generated-docs/llms.txt +8 -4
  22. package/dist/generated-docs/manifest.json +85 -28
  23. package/dist/generated-docs/meter.md +79 -1
  24. package/dist/generated-docs/nav.md +8 -1
  25. package/dist/generated-docs/separator.md +18 -0
  26. package/dist/generated-docs/utilities.json +68 -15
  27. package/dist/generated-docs/utilities.md +145 -50
  28. package/dist/os/notification-center.svelte +1 -1
  29. package/dist/os/taskbar.svelte +1 -1
  30. package/dist/os/toast.svelte +1 -1
  31. package/dist/styles/density.css +15 -25
  32. package/dist/styles/index.css +74 -48
  33. package/dist/styles/motion.css +1 -1
  34. package/dist/styles/prose.css +1 -1
  35. package/dist/styles/surfaces/bevel.css +16 -19
  36. package/dist/styles/surfaces/contract.css +50 -0
  37. package/dist/styles/surfaces/flat.css +27 -0
  38. package/dist/styles/surfaces/glass.css +11 -8
  39. package/dist/ui/accordion/accordion-trigger.svelte +1 -1
  40. package/dist/ui/alert-dialog/alert-dialog-content.svelte +1 -1
  41. package/dist/ui/badge/badge.svelte +8 -2
  42. package/dist/ui/badge/badge.svelte.d.ts +1 -1
  43. package/dist/ui/bar/bar.svelte +95 -26
  44. package/dist/ui/bar/bar.svelte.d.ts +71 -31
  45. package/dist/ui/button/button.svelte +6 -0
  46. package/dist/ui/button/button.svelte.d.ts +2 -0
  47. package/dist/ui/button/variants.d.ts +3 -3
  48. package/dist/ui/button/variants.js +6 -11
  49. package/dist/ui/calendar/calendar-day.svelte +1 -1
  50. package/dist/ui/card/card.svelte +23 -10
  51. package/dist/ui/card/card.svelte.d.ts +19 -7
  52. package/dist/ui/chip/chip.svelte +5 -2
  53. package/dist/ui/chip/chip.svelte.d.ts +6 -6
  54. package/dist/ui/collapsible/collapsible-trigger.svelte +1 -1
  55. package/dist/ui/combobox/combobox-content.svelte +1 -1
  56. package/dist/ui/combobox/combobox-trigger.svelte +1 -1
  57. package/dist/ui/command/command-item.svelte +1 -1
  58. package/dist/ui/command/command-link-item.svelte +1 -1
  59. package/dist/ui/command/command-root.svelte +5 -7
  60. package/dist/ui/command-bar/command-bar.svelte +3 -3
  61. package/dist/ui/context-menu/context-menu-content.svelte +1 -4
  62. package/dist/ui/context-menu/context-menu-sub-content.svelte +1 -4
  63. package/dist/ui/date-field/date-field-segment.svelte +1 -1
  64. package/dist/ui/date-picker/date-picker-content.svelte +1 -1
  65. package/dist/ui/date-picker/date-picker-day.svelte +1 -1
  66. package/dist/ui/date-picker/date-picker-segment.svelte +1 -1
  67. package/dist/ui/date-picker/date-picker-trigger.svelte +1 -1
  68. package/dist/ui/date-range-field/date-range-field-segment.svelte +1 -1
  69. package/dist/ui/date-range-picker/date-range-picker-content.svelte +1 -1
  70. package/dist/ui/date-range-picker/date-range-picker-day.svelte +1 -1
  71. package/dist/ui/date-range-picker/date-range-picker-segment.svelte +1 -1
  72. package/dist/ui/date-range-picker/date-range-picker-trigger.svelte +1 -1
  73. package/dist/ui/dialog/dialog-content.svelte +20 -2
  74. package/dist/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
  75. package/dist/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -4
  76. package/dist/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -1
  77. package/dist/ui/file-upload/file-upload.svelte +1 -1
  78. package/dist/ui/input/variants.d.ts +6 -6
  79. package/dist/ui/input/variants.js +2 -2
  80. package/dist/ui/kv/kv.svelte +1 -1
  81. package/dist/ui/link-preview/link-preview-content.svelte +1 -1
  82. package/dist/ui/menubar/menubar-content.svelte +1 -1
  83. package/dist/ui/menubar/menubar-root.svelte +1 -1
  84. package/dist/ui/menubar/menubar-sub-content.svelte +1 -4
  85. package/dist/ui/menubar/menubar-trigger.svelte +1 -1
  86. package/dist/ui/meter/meter.svelte +1 -2
  87. package/dist/ui/nav/nav-bar.svelte +9 -4
  88. package/dist/ui/nav/nav-bar.svelte.d.ts +2 -1
  89. package/dist/ui/nav/nav-item.svelte +1 -0
  90. package/dist/ui/pane/pane-root.svelte +3 -12
  91. package/dist/ui/pane/pane-tab.svelte +1 -1
  92. package/dist/ui/popover/popover-content.svelte +1 -1
  93. package/dist/ui/provider/surfaces.d.ts +1 -1
  94. package/dist/ui/provider/surfaces.js +1 -1
  95. package/dist/ui/select/select-content.svelte +1 -1
  96. package/dist/ui/select/select-trigger.svelte +1 -1
  97. package/dist/ui/sheet/sheet-content.svelte +1 -1
  98. package/dist/ui/sheet/sheet-content.svelte.d.ts +1 -1
  99. package/dist/ui/slider/slider-thumb.svelte +1 -1
  100. package/dist/ui/step/step-summary.svelte +1 -1
  101. package/dist/ui/switch/switch.svelte +3 -3
  102. package/dist/ui/time-field/time-field-segment.svelte +1 -1
  103. package/dist/ui/time-range-field/time-range-field-segment.svelte +1 -1
  104. package/dist/ui/timeline/timeline-step.svelte +1 -1
  105. package/dist/ui/toggle-group/toggle-group-item.svelte +2 -2
  106. package/dist/ui/toggle-group/toggle-group-item.svelte.d.ts +6 -6
  107. package/dist/ui/toggle-group/toggle-group-root.svelte +1 -2
  108. package/dist/ui/toggle-group/toggle-group-root.svelte.d.ts +3 -3
  109. package/dist/ui/tooltip/tooltip-content.svelte +1 -1
  110. package/dist/ui/tree/tree-item.svelte +1 -1
  111. package/dist/ui/video-player/video-player.svelte +2 -2
  112. package/dist/utils/tw-merge-config.d.ts +6 -1
  113. package/dist/utils/tw-merge-config.js +6 -2
  114. package/package.json +5 -3
  115. package/skill/SKILL.md +26 -21
  116. package/dist/styles/surfaces/base.css +0 -257
@@ -101,9 +101,13 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
101
101
  - `era-ink-center` — on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.
102
102
  - `era-token-ink` — the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.
103
103
  - `era-label-ink` — the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).
104
- - `glass-blur` — the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface="glass" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.
105
- - `rounded-row` — the radius for a row inside a container that pads it by the gutter — a nav rail, a command list, any scrolling list of controls. For a row in a menu PANEL, whose inset is the surface-owned frame rather than the gutter, use rounded-menu-item.
104
+ - `surface-backdrop` — the surface-aware backdrop treatment without choosing a fill or relief. Prefer material-popover/material-panel when the element is a complete surface.
105
+ - `material-popover` — a floating transient surface: menus, popovers, tooltips, pickers, toasts. Binds its raised fill, floating relief, and backdrop treatment atomically.
106
+ - `material-panel` — a floating persistent surface: dialogs, sheets, panes, inspectors. Binds its resting fill, floating relief, and backdrop treatment atomically.
107
+ - `pressable` — the physical press contract on a control whose direct content plane is marked data-era-press-content. The surface owns relief/travel; the component may scale travel with --era-press-scale.
108
+ - `tier-icon · tier-pill · tier-chip · tier-control · tier-bar` — BOUNDED GEOMETRY — height and radius are one decision.
106
109
  - `h-line` — the height of one line of the element's own text — a skeleton standing in for a line, a spacer that must match a line box.
110
+ - `era-track-well` — instead of `shadow-well` on a track whose value is painted by a child that covers the box — a progress/meter/slider track, a custom gauge. For a well holding ordinary content, `shadow-well` is still right.
107
111
  - `era-skeleton-pulse` — Skeleton's pulse, on the MOTION AXIS.
108
112
  - `era-shimmer` — the in-progress text treatment — put it on a "working…" / "thinking…" label while a task streams, instead of a spinner beside the text.
109
113
  - `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
@@ -124,11 +128,11 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
124
128
  - `bg-well · text-well · border-well · bg-elevated · text-elevated · border-elevated · bg-highlight · text-highlight · … (12 in all)` — Surface fills — bg-well is the surface's own resting fill (pairs with
125
129
  - `p-gutter · px-gutter · py-gutter · gap-gutter · p-panel · px-panel · py-panel · gap-panel · … (24 in all)` — THE SPACING SCALE — one entry per token, from which Tailwind derives the
126
130
  - `p-inset-pill · px-inset-pill · py-inset-pill · gap-inset-pill · p-inset-chip · px-inset-chip · py-inset-chip · gap-inset-chip · … (12 in all)` — text-symmetric content padding — (tier − text)/2, the inset that vertically centres body text in its tier; px-inset-control is a text button's side padding, p-inset-control a code block's.
127
- - `p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (36 in all)` — the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control.
131
+ - `p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (40 in all)` — the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control.
128
132
  - `p-glyph-icon · px-glyph-icon · py-glyph-icon · gap-glyph-icon · p-glyph-pill · px-glyph-pill · py-glyph-pill · gap-glyph-pill` — the glyph size for a tier — the INK inside the box, not the box (size-glyph-pill is the dismiss × in a pill, size-pill is the pill).
129
133
  - `bg-field · text-field · border-field · bg-field-highlight · text-field-highlight · border-field-highlight` — the recessed field fill — bg-field is a text input's resting well, bg-field-highlight its focused/hovered face.
130
134
  - `ease-base` — Motion — bare transition utilities default to the motion axis, so
131
135
  - `bg-divider · text-divider · border-divider · bg-divider-faded · text-divider-faded · border-divider-faded · bg-background · text-background · … (66 in all)` — Surface divider colors: border-divider, bg-divider-faded, …
132
- - `bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (33 in all)` — The standing pill fill — --era-fill, the latched counterpart of the
136
+ - `bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (39 in all)` — The standing pill fill — --era-fill, the latched counterpart of the
133
137
 
134
138
  Full reference (what each emits, when to use it): `{{ORIGIN}}/utilities.md`. Machine-readable list: `{{ORIGIN}}/utilities.json`.
@@ -52,7 +52,7 @@
52
52
  "slug": "utilities",
53
53
  "title": "Utilities",
54
54
  "summary": "The CSS classes era ships alongside the components — links, ink-centred text, shimmer, hidden scrollbars.",
55
- "tokenEstimate": 13166,
55
+ "tokenEstimate": 13846,
56
56
  "sections": [
57
57
  "Overview",
58
58
  "era-interactive",
@@ -64,9 +64,13 @@
64
64
  "era-ink-center",
65
65
  "era-token-ink",
66
66
  "era-label-ink",
67
- "glass-blur",
68
- "rounded-row",
67
+ "surface-backdrop",
68
+ "material-popover",
69
+ "material-panel",
70
+ "pressable",
71
+ "tier-icon · tier-pill · tier-chip · tier-control · tier-bar",
69
72
  "h-line",
73
+ "era-track-well",
70
74
  "era-skeleton-pulse",
71
75
  "era-shimmer",
72
76
  "era-collapse",
@@ -87,12 +91,12 @@
87
91
  "bg-well · text-well · border-well · bg-elevated · text-elevated · border-elevated · bg-highlight · text-highlight · … (12 in all)",
88
92
  "p-gutter · px-gutter · py-gutter · gap-gutter · p-panel · px-panel · py-panel · gap-panel · … (24 in all)",
89
93
  "p-inset-pill · px-inset-pill · py-inset-pill · gap-inset-pill · p-inset-chip · px-inset-chip · py-inset-chip · gap-inset-chip · … (12 in all)",
90
- "p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (36 in all)",
94
+ "p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (40 in all)",
91
95
  "p-glyph-icon · px-glyph-icon · py-glyph-icon · gap-glyph-icon · p-glyph-pill · px-glyph-pill · py-glyph-pill · gap-glyph-pill",
92
96
  "bg-field · text-field · border-field · bg-field-highlight · text-field-highlight · border-field-highlight",
93
97
  "ease-base",
94
98
  "bg-divider · text-divider · border-divider · bg-divider-faded · text-divider-faded · border-divider-faded · bg-background · text-background · … (66 in all)",
95
- "bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (33 in all)"
99
+ "bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (39 in all)"
96
100
  ],
97
101
  "file": "utilities.md"
98
102
  },
@@ -158,7 +162,7 @@
158
162
  "slug": "badge",
159
163
  "title": "Badge",
160
164
  "summary": "A small label for status or categorization.",
161
- "tokenEstimate": 279,
165
+ "tokenEstimate": 282,
162
166
  "sections": [
163
167
  "Import",
164
168
  "Props",
@@ -184,7 +188,7 @@
184
188
  "slug": "bar",
185
189
  "title": "Bar",
186
190
  "summary": "A flex container for toolbars and headers, in three heights.",
187
- "tokenEstimate": 211,
191
+ "tokenEstimate": 500,
188
192
  "sections": [
189
193
  "Import",
190
194
  "Props"
@@ -195,7 +199,7 @@
195
199
  "slug": "nav",
196
200
  "title": "Nav",
197
201
  "summary": "A navigation landmark and its items — the current one announces itself, and that announcement is what paints it.",
198
- "tokenEstimate": 825,
202
+ "tokenEstimate": 955,
199
203
  "sections": [
200
204
  "Import",
201
205
  "Nav.Bar",
@@ -207,7 +211,7 @@
207
211
  "slug": "button",
208
212
  "title": "Button",
209
213
  "summary": "A flexible button or link element.",
210
- "tokenEstimate": 1070,
214
+ "tokenEstimate": 1625,
211
215
  "sections": [
212
216
  "Import",
213
217
  "Props",
@@ -242,7 +246,7 @@
242
246
  "slug": "card",
243
247
  "title": "Card",
244
248
  "summary": "A surface container that can behave as a link or button.",
245
- "tokenEstimate": 285,
249
+ "tokenEstimate": 725,
246
250
  "sections": [
247
251
  "Import",
248
252
  "Props"
@@ -253,7 +257,7 @@
253
257
  "slug": "chip",
254
258
  "title": "Chip",
255
259
  "summary": "An interactive, optionally dismissible token.",
256
- "tokenEstimate": 329,
260
+ "tokenEstimate": 593,
257
261
  "sections": [
258
262
  "Import",
259
263
  "Props",
@@ -310,7 +314,7 @@
310
314
  "slug": "separator",
311
315
  "title": "Separator",
312
316
  "summary": "A visual divider between content.",
313
- "tokenEstimate": 218,
317
+ "tokenEstimate": 531,
314
318
  "sections": [
315
319
  "Import",
316
320
  "Props",
@@ -752,7 +756,7 @@
752
756
  "slug": "meter",
753
757
  "title": "Meter",
754
758
  "summary": "Displays a value within a known range.",
755
- "tokenEstimate": 188,
759
+ "tokenEstimate": 1469,
756
760
  "sections": [
757
761
  "Import",
758
762
  "Props"
@@ -1119,24 +1123,57 @@
1119
1123
  "css": "@utility era-label-ink {\n\tdisplay: block;\n\talign-content: center;\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
1120
1124
  },
1121
1125
  {
1122
- "name": "glass-blur",
1126
+ "name": "surface-backdrop",
1123
1127
  "names": [
1124
- "glass-blur"
1128
+ "surface-backdrop"
1125
1129
  ],
1126
1130
  "file": "index.css",
1127
- "useCase": "the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface=\"glass\" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.",
1128
- "description": "Tailwind v4 cannot resolve var() inside backdrop-blur-[], so the filter\nis a registered utility, gated to glass subtrees.\n\nIt lives HERE rather than in surfaces/glass.css, where a surface's own\nchrome would naturally sit, because glass.css is imported into a cascade\nlayer and `@utility` cannot be nested inside one. Surface-scoped RULES stay\nin their surface file; surface-scoped UTILITIES have to come out.",
1129
- "css": "@utility` cannot be nested inside one. Surface-scoped RULES stay\n * in their surface file; surface-scoped UTILITIES have to come out.\n *\n * @use the backdrop blur for a floating panel (popover, dialog, taskbar) — it\n * applies only inside a data-surface=\"glass\" subtree and is inert elsewhere,\n * so it is safe to leave on a panel that renders under every surface. */\n@utility glass-blur {\n\t[data-surface='glass'] & {\n\t\tbackdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t\t-webkit-backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t}\n}"
1131
+ "useCase": "the surface-aware backdrop treatment without choosing a fill or relief. Prefer material-popover/material-panel when the element is a complete surface.",
1132
+ "description": "",
1133
+ "css": "@utility surface-backdrop {\n\tbackdrop-filter: var(--era-backdrop-filter);\n\t-webkit-backdrop-filter: var(--era-backdrop-filter);\n}"
1134
+ },
1135
+ {
1136
+ "name": "material-popover",
1137
+ "names": [
1138
+ "material-popover"
1139
+ ],
1140
+ "file": "index.css",
1141
+ "useCase": "a floating transient surface: menus, popovers, tooltips, pickers, toasts. Binds its raised fill, floating relief, and backdrop treatment atomically.",
1142
+ "description": "",
1143
+ "css": "@utility material-popover {\n\tbackground-color: var(--era-surface-bg-elevated);\n\tbox-shadow: var(--era-shadow-lg);\n\tbackdrop-filter: var(--era-backdrop-filter);\n\t-webkit-backdrop-filter: var(--era-backdrop-filter);\n}"
1144
+ },
1145
+ {
1146
+ "name": "material-panel",
1147
+ "names": [
1148
+ "material-panel"
1149
+ ],
1150
+ "file": "index.css",
1151
+ "useCase": "a floating persistent surface: dialogs, sheets, panes, inspectors. Binds its resting fill, floating relief, and backdrop treatment atomically.",
1152
+ "description": "",
1153
+ "css": "@utility material-panel {\n\tbackground-color: var(--era-surface-bg);\n\tbox-shadow: var(--era-shadow-lg);\n\tbackdrop-filter: var(--era-backdrop-filter);\n\t-webkit-backdrop-filter: var(--era-backdrop-filter);\n}"
1154
+ },
1155
+ {
1156
+ "name": "pressable",
1157
+ "names": [
1158
+ "pressable"
1159
+ ],
1160
+ "file": "index.css",
1161
+ "useCase": "the physical press contract on a control whose direct content plane is marked data-era-press-content. The surface owns relief/travel; the component may scale travel with --era-press-scale.",
1162
+ "description": "",
1163
+ "css": "@utility pressable {\n\t&:active {\n\t\tbox-shadow: var(--era-shadow-pressed);\n\t}\n\n\t&:active > [data-era-press-content] {\n\t\ttranslate: var(--era-press-effective-x, var(--era-press-sink-x))\n\t\t\tvar(--era-press-effective-y, var(--era-press-sink-y));\n\t}\n}"
1130
1164
  },
1131
1165
  {
1132
- "name": "rounded-row",
1166
+ "name": "tier-icon",
1133
1167
  "names": [
1134
- "rounded-row"
1168
+ "tier-icon",
1169
+ "tier-pill",
1170
+ "tier-chip",
1171
+ "tier-control",
1172
+ "tier-bar"
1135
1173
  ],
1136
1174
  "file": "index.css",
1137
- "useCase": "the radius for a row inside a container that pads it by the gutter a nav rail, a command list, any scrolling list of controls. For a row in a menu PANEL, whose inset is the surface-owned frame rather than the gutter, use rounded-menu-item.",
1138
- "description": "THE ROW RADIUS — concentricity for a row that is inset, WITH its inset intact.\n\nThe law is rd_outer − rd_inner = gap. A row inside a container that pads it by\nthe gutter therefore takes the container's radius MINUS the gutter — and no\ntier radius equals that at more than one density, which is why reaching for\n`rounded-control` and hoping looks wrong: in a control-radius pane the row and\nthe pane end up with identical curvature separated by 5px of gap, two arcs at\none corner with no relationship.\n\nThe alternative — deleting the gap so equal radii become legal — is the wrong\ntrade and was briefly shipped. The ladder exists so a gap and concentric\ncorners COEXIST; spending one to buy the other gives up the thing it is for.\n\nThe calc runs on the ROW, not on the container, which is what makes it\nautomatic: `--era-container-rd` is inherited, so a container that is not\ncontrol-radius publishes its own and every row inside re-derives. era's\ncommand palette does exactly that — it is rd-bar, so its rows resolve to\nrd-bar − gap, which IS rd-control (control-inset-bar is the gutter), and the\npalette's geometry is unchanged by this.",
1139
- "css": "@utility rounded-row {\n\tborder-radius: max(0px, calc(var(--era-container-rd, var(--era-rd-control)) - var(--era-gap)));\n}"
1175
+ "description": "BOUNDED GEOMETRY — height and radius are one decision.\n\nA tier is a geometric type, not two classes a caller must remember to keep in\nsync. `tier-control` establishes h-control AND rd-control; the radius ladder\nthen guarantees rd_outer rd_inner = (h_outer h_inner)/2 for every pair.\nWidth remains the component's decision: a row stretches, a button adds\nmin-w-control, and a square control adds w-control.",
1176
+ "css": "@utility tier-icon {\n\theight: var(--era-h-icon);\n\tborder-radius: var(--era-rd-icon);\n}\n\n@utility tier-pill {\n\theight: var(--era-h-pill);\n\tborder-radius: var(--era-rd-pill);\n}\n\n@utility tier-chip {\n\theight: var(--era-h-chip);\n\tborder-radius: var(--era-rd-chip);\n}\n\n@utility tier-control {\n\theight: var(--era-h-control);\n\tborder-radius: var(--era-rd-control);\n}\n\n@utility tier-bar {\n\theight: var(--era-h-bar);\n\tborder-radius: var(--era-rd-bar);\n}"
1140
1177
  },
1141
1178
  {
1142
1179
  "name": "h-line",
@@ -1148,6 +1185,16 @@
1148
1185
  "description": "One LINE BOX tall — the height of the text this stands in for.\n\nSkeleton's `line` used h-(--era-text), which is the body FONT SIZE: never the\nheight of a rendered line (that is font-size x leading), and wrong again by\nthe ladder's ratio for any rung other than body. `1lh` resolves against the\nelement's OWN computed line-height, so putting a text-* class on the skeleton\nmakes it match that tier exactly, at every density, and it follows a leading\nchange for free.",
1149
1186
  "css": "@utility h-line {\n\theight: 1lh;\n}"
1150
1187
  },
1188
+ {
1189
+ "name": "era-track-well",
1190
+ "names": [
1191
+ "era-track-well"
1192
+ ],
1193
+ "file": "index.css",
1194
+ "useCase": "instead of `shadow-well` on a track whose value is painted by a child that covers the box — a progress/meter/slider track, a custom gauge. For a well holding ordinary content, `shadow-well` is still right.",
1195
+ "description": "A WELL THAT SURVIVES BEING FILLED.\n\n`shadow-well` is an INSET shadow, and an inset shadow belongs to the\nelement's background layer — it paints under the element's own descendants.\nThat is invisible on a well holding text (a checkbox, a code block: the\nchrome runs around the content) and wrong the moment something paints the\nwhole box. Meter, Progress and the Slider track all do exactly that: an\nopaque child, `translateX`-ed to the value. So the well survived only where\nthe track was EMPTY — a half-full meter on bevel had a chisel to the right\nof the value and none to the left, which reads as a hole with a sticker\nover it rather than a level inside a well.\n\nThe fix is painting order, not geometry: the same `--era-shadow-well` on a\npseudo-element that is the element's LAST child, so it lands above the fill.\nThe fill still spans the full box — nothing is inset, no radius is\nre-derived, and 0% and 100% keep their exact ends. The `position: relative`\nis load-bearing (the overlay resolves against this box) and `inherit` on the\nradius keeps it honest under `data-corners=\"square\"`.\n\nSurface-agnostic on purpose. It reads the same token every well reads, so\nglass's hairline rim is restored by the same line that restores bevel's\nchisel, and flat — where the token is `none` — renders exactly as before.\nReported against bevel by a consumer; it was never a bevel bug.",
1196
+ "css": "@utility era-track-well {\n\tposition: relative;\n\t&::after {\n\t\tcontent: '';\n\t\tposition: absolute;\n\t\tinset: 0;\n\t\tborder-radius: inherit;\n\t\tbox-shadow: var(--era-shadow-well);\n\t\tpointer-events: none;\n\t}\n}"
1197
+ },
1151
1198
  {
1152
1199
  "name": "era-skeleton-pulse",
1153
1200
  "names": [
@@ -1367,7 +1414,7 @@
1367
1414
  "border-overlay"
1368
1415
  ],
1369
1416
  "file": "index.css",
1370
- "description": "Surface fills — bg-well is the surface's own resting fill (pairs with\nshadow-well for recessed chrome), bg-elevated the raised tier (pairs with\nshadow-lg + glass-blur for floating chrome), bg-highlight the transient\nhover/focus/keyboard wash (pairs with shadow-highlight; latched states\nstay on opaque bg-hover), bg-overlay the modal scrim.",
1417
+ "description": "Surface fills — bg-well is the surface's own resting fill (pairs with\nshadow-well for recessed chrome), bg-elevated the raised tier,\nbg-highlight the transient\nhover/focus/keyboard wash (pairs with shadow-highlight; latched states\nstay on opaque bg-hover), bg-overlay the modal scrim.",
1371
1418
  "css": "@theme inline {\n\t--color-well: var(--era-surface-bg);\n\t--color-elevated: var(--era-surface-bg-elevated);\n\t--color-highlight: var(--era-highlight);\n\t--color-overlay: var(--era-overlay-bg);\n}"
1372
1419
  },
1373
1420
  {
@@ -1461,12 +1508,16 @@
1461
1508
  "p-chip-inset-bar",
1462
1509
  "px-chip-inset-bar",
1463
1510
  "py-chip-inset-bar",
1464
- "gap-chip-inset-bar"
1511
+ "gap-chip-inset-bar",
1512
+ "p-control-inset-bar",
1513
+ "px-control-inset-bar",
1514
+ "py-control-inset-bar",
1515
+ "gap-control-inset-bar"
1465
1516
  ],
1466
1517
  "file": "index.css",
1467
1518
  "useCase": "the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control.",
1468
1519
  "description": "",
1469
- "css": "@theme inline {\n\t--spacing-icon-inset-pill: var(--era-icon-inset-pill);\n\t--spacing-icon-inset-chip: var(--era-icon-inset-chip);\n\t--spacing-icon-inset-control: var(--era-icon-inset-control);\n\t--spacing-icon-inset-bar: var(--era-icon-inset-bar);\n\t--spacing-pill-inset-chip: var(--era-pill-inset-chip);\n\t--spacing-pill-inset-control: var(--era-pill-inset-control);\n\t--spacing-pill-inset-bar: var(--era-pill-inset-bar);\n\t--spacing-chip-inset-control: var(--era-chip-inset-control);\n\t--spacing-chip-inset-bar: var(--era-chip-inset-bar);\n}"
1520
+ "css": "@theme inline {\n\t--spacing-icon-inset-pill: var(--era-icon-inset-pill);\n\t--spacing-icon-inset-chip: var(--era-icon-inset-chip);\n\t--spacing-icon-inset-control: var(--era-icon-inset-control);\n\t--spacing-icon-inset-bar: var(--era-icon-inset-bar);\n\t--spacing-pill-inset-chip: var(--era-pill-inset-chip);\n\t--spacing-pill-inset-control: var(--era-pill-inset-control);\n\t--spacing-pill-inset-bar: var(--era-pill-inset-bar);\n\t--spacing-chip-inset-control: var(--era-chip-inset-control);\n\t--spacing-chip-inset-bar: var(--era-chip-inset-bar);\n\t--spacing-control-inset-bar: var(--era-control-inset-bar);\n}"
1470
1521
  },
1471
1522
  {
1472
1523
  "name": "p-glyph-icon",
@@ -1618,11 +1669,17 @@
1618
1669
  "border-warning",
1619
1670
  "bg-warning-fg",
1620
1671
  "text-warning-fg",
1621
- "border-warning-fg"
1672
+ "border-warning-fg",
1673
+ "bg-info",
1674
+ "text-info",
1675
+ "border-info",
1676
+ "bg-info-fg",
1677
+ "text-info-fg",
1678
+ "border-info-fg"
1622
1679
  ],
1623
1680
  "file": "index.css",
1624
1681
  "description": "The standing pill fill — --era-fill, the latched counterpart of the\ntransient highlight. Surface-owned: a composing wash on flat/bevel, the\nopaque swatch on glass.",
1625
- "css": "@theme inline {\n\t--color-fill: var(--era-fill);\n\t--color-link: var(--color-link);\n\t--color-primary: var(--color-primary);\n\t--color-primary-fg: var(--color-primary-fg);\n\t--color-primary-hover: var(--color-primary-hover);\n\t--color-destructive: var(--color-destructive);\n\t--color-destructive-fg: var(--color-destructive-fg);\n\t--color-success: var(--color-success);\n\t--color-success-fg: var(--color-success-fg);\n\t--color-warning: var(--color-warning);\n\t--color-warning-fg: var(--color-warning-fg);\n}"
1682
+ "css": "@theme inline {\n\t--color-fill: var(--era-fill);\n\t--color-link: var(--color-link);\n\t--color-primary: var(--color-primary);\n\t--color-primary-fg: var(--color-primary-fg);\n\t--color-primary-hover: var(--color-primary-hover);\n\t--color-destructive: var(--color-destructive);\n\t--color-destructive-fg: var(--color-destructive-fg);\n\t--color-success: var(--color-success);\n\t--color-success-fg: var(--color-success-fg);\n\t--color-warning: var(--color-warning);\n\t--color-warning-fg: var(--color-warning-fg);\n\t--color-info: var(--color-info);\n\t--color-info-fg: var(--color-info-fg);\n}"
1626
1683
  }
1627
1684
  ]
1628
1685
  }
@@ -14,10 +14,88 @@ Inherits all props from `Meter.RootProps`.
14
14
 
15
15
  | Prop | Type | Default | Notes |
16
16
  |------|------|---------|-------|
17
- | `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning'` | `'default'` | The band this reading falls in. Tone is the fill's colour only — the
17
+ | `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning' \| 'info'` | `'default'` | The band this reading falls in. Tone is the fill's colour only — the
18
18
  track stays neutral, because the well belongs to the control and the
19
19
  fill belongs to the value.
20
20
  Tone carries no semantics on its own: a meter in the destructive band
21
21
  still needs an accessible label saying what has run out. Pair it with
22
22
  `aria-label` / a visible label, never rely on the hue alone. |
23
+ | `threshold?` | `number` | — | A BOUNDARY INSIDE THE RANGE — in the same units as `value`, not a
24
+ percentage. A quota with a soft limit before the hard one; a plan that
25
+ includes 30 hours of the 50 it bills against; a temperature that is
26
+ fine until it is not. The bar fills against `max`, and the mark says
27
+ where the number the reader is actually deciding about sits.
28
+ WHY THE MARK HAS NO COLOUR OF ITS OWN. It has to read against both
29
+ sides of itself: over the empty track before the value reaches it, and
30
+ over the fill afterwards. One token cannot do that — a colour tuned
31
+ against the track disappears into the fill the moment the value
32
+ crosses, which is exactly what a consumer hit hand-rolling this. So
33
+ the mark is painted in the colour of the side it is NOT on: the fill's
34
+ paint while the value is short of it, the track's fill once the value
35
+ has passed. That contrast is not a new promise — it is the meter's
36
+ own. A fill that did not stand out from its track would not be a
37
+ meter, so borrowing the pair is the one choice that cannot be wrong in
38
+ a theme, a tone, or a surface era has not seen.
39
+ IT IS DECORATION, and silent on purpose. There is no `role` and
40
+ nothing to announce: a screen reader gets `value`/`min`/`max` and the
41
+ meter's own accessible name, and a boundary it cannot position adds
42
+ nothing. If the threshold is part of the reading — it usually is —
43
+ put the figure in `aria-label` and in a caption, where it is a number
44
+ rather than a position.
45
+ PASS `aria-valuetext` IF YOUR STORED UNIT IS NOT YOUR DISPLAYED ONE.
46
+ `value`, `max` and `threshold` all have to sit in one unit for this
47
+ arithmetic to work, and `aria-valuenow` is `value` verbatim — so a bar
48
+ stored in minutes and read in hours announces "2640 of 3000", a figure
49
+ the customer was never quoted. Converting the props is not available
50
+ to you (it would move the mark), which makes `aria-valuetext` the only
51
+ lever; it passes through `restProps` onto the same element. Reported
52
+ by a consumer billing minutes and quoting hours.
53
+ Outside `[min, max]` it renders NOTHING rather than clamping to an
54
+ end, because a mark pinned to the edge of the bar would claim a
55
+ boundary that is not in the range. |
56
+ | `buffer?` | `number` | — | A REGION FROM `min` THAT IS A DIFFERENT KIND OF QUANTITY — painted
57
+ under the fill, over the track, in the same units as `value`.
58
+ The media player's buffered-progress shape, and the name is borrowed
59
+ from it, but the reading is more general: some of the range is already
60
+ accounted for. A plan whose first 30 of 50 hours are included in the
61
+ monthly minimum is not "24 hours into a bill", it is "24 of 30 hours
62
+ you have already paid for" — money spent against money that will be
63
+ spent, which is a distinction the bar could not draw.
64
+ NO COLOUR OF ITS OWN, for the reason `threshold` has none: it has to
65
+ be legible over the track while never competing with the fill that
66
+ crosses it, and a token tuned for one of those is wrong for the other.
67
+ It is the fill's own paint at 30%, so it cannot be wrong in a theme,
68
+ a tone or a surface era has not seen, and it is the same 30% Slider's
69
+ `progress` has used for a seek bar's buffer since it shipped.
70
+ UNDER the fill, so it disappears as the value consumes it. That is the
71
+ reading, not a limitation: once you are past your included hours, the
72
+ included region IS spent, and `threshold` is what goes on marking
73
+ where it ended.
74
+ CLAMPED to the range rather than dropped, which is where it differs
75
+ from `threshold`. A region can be honestly truncated — a buffer past
76
+ `max` means the whole visible bar is accounted for, and painting it
77
+ all says exactly that. A point cannot: a mark pinned to the edge would
78
+ claim a boundary that is not in the range, so an out-of-range
79
+ `threshold` renders nothing instead.
80
+ Silent, like the mark. `aria-valuetext` already carries the reading,
81
+ and a second region a screen reader cannot position adds nothing.
82
+ (Slider spells its equivalent `progress` and takes a 0–1 FRACTION.
83
+ Here every positional prop is in the value's own units — `value`,
84
+ `max`, `threshold`, `buffer` — because a component that mixed the two
85
+ would be a bug generator. The names differ because on a Meter
86
+ `progress` would be a synonym for `value`.) |
87
+ | `start?` | `Snippet` | — | Captions under the two ends of the bar — what the range MEANS.
88
+ A meter states a proportion and leaves the reader to work out what of.
89
+ "0m used" on the left and "50h before approval" on the right is not
90
+ decoration, it is the reading; every consumer of a bare meter ends up
91
+ hand-rolling the same flex row underneath it, which is where this came
92
+ from. `start` is left, `end` is right, either may stand alone.
93
+ NOT ANNOUNCED. They are captions, so a screen reader gets the meter's
94
+ value and its own `aria-label`, not these. If the range needs saying
95
+ out loud, say it in the label too — the same rule `tone` carries.
96
+ THE DOM IS UNCHANGED WITHOUT THEM. With neither snippet this renders
97
+ exactly the element it always did, so `class` still lands on the track
98
+ and the geometry audits still walk the same box. Passing one wraps the
99
+ track in a column, and `class` still lands on the track. |
100
+ | `end?` | `Snippet` | — | — |
23
101
  | `ref?` | `(forwarded)` | `null` | bindable |
@@ -21,7 +21,7 @@ Inherits all props from `HTMLAttributes<HTMLElement>`.
21
21
  |------|------|---------|-------|
22
22
  | `ref?` | `HTMLElement \| null` | `null` | bindable |
23
23
  | `size?` | `'chip' \| 'control' \| 'bar'` | `'bar'` | Height tier, exactly as Bar's — the geometry is Bar's, not a second copy. |
24
- | `content?` | `'tier' \| 'pill'` | `'tier'` | Tier of the items inside, so the wall stays concentric to them. |
24
+ | `content?` | `BarContent` | | Tier of the items inside, so the wall stays concentric to them. |
25
25
  | `divider?` | `boolean` | `false` | Draw Bar's flush cap-a-panel rule beneath the bar. Off by default,
26
26
  because a nav that sits in a page already has whatever separation the
27
27
  layout gives it — and a link-variant nav in particular reads as text,
@@ -46,6 +46,13 @@ Inherits all props from `HTMLAnchorAttributes`.
46
46
  drops the chrome entirely and renders running text, for a primary nav
47
47
  that should read as links rather than a row of raised keycaps. Existing
48
48
  bars are byte-identical. |
49
+ | `currentCue?` | `'thickness' \| 'ink' \| 'none'` | `'thickness'` | WHAT MARKS THE CURRENT ITEM. `thickness` (default) is the three-state
50
+ decoration — portable across every theme and font because it is one
51
+ ink at three strengths. `ink` brightens the current item instead, and
52
+ is theme-dependent by construction: era's default themes point
53
+ --color-link at --color-bright, so its delta there is zero. `none`
54
+ silences era's cue entirely, for a consumer painting their own.
55
+ See navItemVariants above for the measurements behind each. |
49
56
  | `current?` | `boolean` | `false` | Whether this item points at the page you are on.
50
57
  There is deliberately no `active` prop beside this one. `active` would
51
58
  be a second source of truth for one fact, and the two drift the moment
@@ -15,6 +15,24 @@ Inherits all props from `Separator.RootProps`.
15
15
  | Prop | Type | Default | Notes |
16
16
  |------|------|---------|-------|
17
17
  | `variant?` | `'line' \| 'slant'` | `'line'` | Use `slant` for inline dividers in breadcrumbs, titles, and compact metadata. |
18
+ | `size?` | `keyof typeof SIZES` | — | Give a VERTICAL rule a height of its own, from the tier ladder, instead
19
+ of stretching to whatever line it lands in. Ignored when horizontal.
20
+ WHY YOU WOULD WANT IT. A stretched rule is a passenger: it has no
21
+ intrinsic height, so it measures whatever its neighbours measure and
22
+ contributes nothing back. That is right inside a Bar, whose height is
23
+ already fixed — and it is why a rule in an auto-height row cannot hold
24
+ that row's height steady. A consumer whose site header gained and lost
25
+ a qualifier between pages watched the chrome resize, and pinned a
26
+ `min-h-[calc(...)]` on the header to stop it. Sizing the rule removes
27
+ that calc: it becomes the piece that stands the row up.
28
+ (For the record, since the report named the wrong mechanism: a
29
+ stretched rule does not GROW its row. Measured in an 18px auto-height
30
+ row, adding one leaves the row at 18px and the rule resolves to 10px —
31
+ the line minus its two gutter margins. It can only ever be shorter
32
+ than the row it divides, which is the whole problem here.)
33
+ A sized rule drops the gutter margins with the stretch: the height is
34
+ now a deliberate number, and silently adding 2 x gutter to it would
35
+ make it the one element on the page you cannot reason about. |
18
36
  | `ref?` | `(forwarded)` | `null` | bindable |
19
37
 
20
38
  ## Usage
@@ -91,24 +91,57 @@
91
91
  "css": "@utility era-label-ink {\n\tdisplay: block;\n\talign-content: center;\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
92
92
  },
93
93
  {
94
- "name": "glass-blur",
94
+ "name": "surface-backdrop",
95
95
  "names": [
96
- "glass-blur"
96
+ "surface-backdrop"
97
97
  ],
98
98
  "file": "index.css",
99
- "useCase": "the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface=\"glass\" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.",
100
- "description": "Tailwind v4 cannot resolve var() inside backdrop-blur-[], so the filter\nis a registered utility, gated to glass subtrees.\n\nIt lives HERE rather than in surfaces/glass.css, where a surface's own\nchrome would naturally sit, because glass.css is imported into a cascade\nlayer and `@utility` cannot be nested inside one. Surface-scoped RULES stay\nin their surface file; surface-scoped UTILITIES have to come out.",
101
- "css": "@utility` cannot be nested inside one. Surface-scoped RULES stay\n * in their surface file; surface-scoped UTILITIES have to come out.\n *\n * @use the backdrop blur for a floating panel (popover, dialog, taskbar) — it\n * applies only inside a data-surface=\"glass\" subtree and is inert elsewhere,\n * so it is safe to leave on a panel that renders under every surface. */\n@utility glass-blur {\n\t[data-surface='glass'] & {\n\t\tbackdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t\t-webkit-backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t}\n}"
99
+ "useCase": "the surface-aware backdrop treatment without choosing a fill or relief. Prefer material-popover/material-panel when the element is a complete surface.",
100
+ "description": "",
101
+ "css": "@utility surface-backdrop {\n\tbackdrop-filter: var(--era-backdrop-filter);\n\t-webkit-backdrop-filter: var(--era-backdrop-filter);\n}"
102
+ },
103
+ {
104
+ "name": "material-popover",
105
+ "names": [
106
+ "material-popover"
107
+ ],
108
+ "file": "index.css",
109
+ "useCase": "a floating transient surface: menus, popovers, tooltips, pickers, toasts. Binds its raised fill, floating relief, and backdrop treatment atomically.",
110
+ "description": "",
111
+ "css": "@utility material-popover {\n\tbackground-color: var(--era-surface-bg-elevated);\n\tbox-shadow: var(--era-shadow-lg);\n\tbackdrop-filter: var(--era-backdrop-filter);\n\t-webkit-backdrop-filter: var(--era-backdrop-filter);\n}"
112
+ },
113
+ {
114
+ "name": "material-panel",
115
+ "names": [
116
+ "material-panel"
117
+ ],
118
+ "file": "index.css",
119
+ "useCase": "a floating persistent surface: dialogs, sheets, panes, inspectors. Binds its resting fill, floating relief, and backdrop treatment atomically.",
120
+ "description": "",
121
+ "css": "@utility material-panel {\n\tbackground-color: var(--era-surface-bg);\n\tbox-shadow: var(--era-shadow-lg);\n\tbackdrop-filter: var(--era-backdrop-filter);\n\t-webkit-backdrop-filter: var(--era-backdrop-filter);\n}"
122
+ },
123
+ {
124
+ "name": "pressable",
125
+ "names": [
126
+ "pressable"
127
+ ],
128
+ "file": "index.css",
129
+ "useCase": "the physical press contract on a control whose direct content plane is marked data-era-press-content. The surface owns relief/travel; the component may scale travel with --era-press-scale.",
130
+ "description": "",
131
+ "css": "@utility pressable {\n\t&:active {\n\t\tbox-shadow: var(--era-shadow-pressed);\n\t}\n\n\t&:active > [data-era-press-content] {\n\t\ttranslate: var(--era-press-effective-x, var(--era-press-sink-x))\n\t\t\tvar(--era-press-effective-y, var(--era-press-sink-y));\n\t}\n}"
102
132
  },
103
133
  {
104
- "name": "rounded-row",
134
+ "name": "tier-icon",
105
135
  "names": [
106
- "rounded-row"
136
+ "tier-icon",
137
+ "tier-pill",
138
+ "tier-chip",
139
+ "tier-control",
140
+ "tier-bar"
107
141
  ],
108
142
  "file": "index.css",
109
- "useCase": "the radius for a row inside a container that pads it by the gutter a nav rail, a command list, any scrolling list of controls. For a row in a menu PANEL, whose inset is the surface-owned frame rather than the gutter, use rounded-menu-item.",
110
- "description": "THE ROW RADIUS — concentricity for a row that is inset, WITH its inset intact.\n\nThe law is rd_outer − rd_inner = gap. A row inside a container that pads it by\nthe gutter therefore takes the container's radius MINUS the gutter — and no\ntier radius equals that at more than one density, which is why reaching for\n`rounded-control` and hoping looks wrong: in a control-radius pane the row and\nthe pane end up with identical curvature separated by 5px of gap, two arcs at\none corner with no relationship.\n\nThe alternative — deleting the gap so equal radii become legal — is the wrong\ntrade and was briefly shipped. The ladder exists so a gap and concentric\ncorners COEXIST; spending one to buy the other gives up the thing it is for.\n\nThe calc runs on the ROW, not on the container, which is what makes it\nautomatic: `--era-container-rd` is inherited, so a container that is not\ncontrol-radius publishes its own and every row inside re-derives. era's\ncommand palette does exactly that — it is rd-bar, so its rows resolve to\nrd-bar − gap, which IS rd-control (control-inset-bar is the gutter), and the\npalette's geometry is unchanged by this.",
111
- "css": "@utility rounded-row {\n\tborder-radius: max(0px, calc(var(--era-container-rd, var(--era-rd-control)) - var(--era-gap)));\n}"
143
+ "description": "BOUNDED GEOMETRY — height and radius are one decision.\n\nA tier is a geometric type, not two classes a caller must remember to keep in\nsync. `tier-control` establishes h-control AND rd-control; the radius ladder\nthen guarantees rd_outer rd_inner = (h_outer h_inner)/2 for every pair.\nWidth remains the component's decision: a row stretches, a button adds\nmin-w-control, and a square control adds w-control.",
144
+ "css": "@utility tier-icon {\n\theight: var(--era-h-icon);\n\tborder-radius: var(--era-rd-icon);\n}\n\n@utility tier-pill {\n\theight: var(--era-h-pill);\n\tborder-radius: var(--era-rd-pill);\n}\n\n@utility tier-chip {\n\theight: var(--era-h-chip);\n\tborder-radius: var(--era-rd-chip);\n}\n\n@utility tier-control {\n\theight: var(--era-h-control);\n\tborder-radius: var(--era-rd-control);\n}\n\n@utility tier-bar {\n\theight: var(--era-h-bar);\n\tborder-radius: var(--era-rd-bar);\n}"
112
145
  },
113
146
  {
114
147
  "name": "h-line",
@@ -120,6 +153,16 @@
120
153
  "description": "One LINE BOX tall — the height of the text this stands in for.\n\nSkeleton's `line` used h-(--era-text), which is the body FONT SIZE: never the\nheight of a rendered line (that is font-size x leading), and wrong again by\nthe ladder's ratio for any rung other than body. `1lh` resolves against the\nelement's OWN computed line-height, so putting a text-* class on the skeleton\nmakes it match that tier exactly, at every density, and it follows a leading\nchange for free.",
121
154
  "css": "@utility h-line {\n\theight: 1lh;\n}"
122
155
  },
156
+ {
157
+ "name": "era-track-well",
158
+ "names": [
159
+ "era-track-well"
160
+ ],
161
+ "file": "index.css",
162
+ "useCase": "instead of `shadow-well` on a track whose value is painted by a child that covers the box — a progress/meter/slider track, a custom gauge. For a well holding ordinary content, `shadow-well` is still right.",
163
+ "description": "A WELL THAT SURVIVES BEING FILLED.\n\n`shadow-well` is an INSET shadow, and an inset shadow belongs to the\nelement's background layer — it paints under the element's own descendants.\nThat is invisible on a well holding text (a checkbox, a code block: the\nchrome runs around the content) and wrong the moment something paints the\nwhole box. Meter, Progress and the Slider track all do exactly that: an\nopaque child, `translateX`-ed to the value. So the well survived only where\nthe track was EMPTY — a half-full meter on bevel had a chisel to the right\nof the value and none to the left, which reads as a hole with a sticker\nover it rather than a level inside a well.\n\nThe fix is painting order, not geometry: the same `--era-shadow-well` on a\npseudo-element that is the element's LAST child, so it lands above the fill.\nThe fill still spans the full box — nothing is inset, no radius is\nre-derived, and 0% and 100% keep their exact ends. The `position: relative`\nis load-bearing (the overlay resolves against this box) and `inherit` on the\nradius keeps it honest under `data-corners=\"square\"`.\n\nSurface-agnostic on purpose. It reads the same token every well reads, so\nglass's hairline rim is restored by the same line that restores bevel's\nchisel, and flat — where the token is `none` — renders exactly as before.\nReported against bevel by a consumer; it was never a bevel bug.",
164
+ "css": "@utility era-track-well {\n\tposition: relative;\n\t&::after {\n\t\tcontent: '';\n\t\tposition: absolute;\n\t\tinset: 0;\n\t\tborder-radius: inherit;\n\t\tbox-shadow: var(--era-shadow-well);\n\t\tpointer-events: none;\n\t}\n}"
165
+ },
123
166
  {
124
167
  "name": "era-skeleton-pulse",
125
168
  "names": [
@@ -339,7 +382,7 @@
339
382
  "border-overlay"
340
383
  ],
341
384
  "file": "index.css",
342
- "description": "Surface fills — bg-well is the surface's own resting fill (pairs with\nshadow-well for recessed chrome), bg-elevated the raised tier (pairs with\nshadow-lg + glass-blur for floating chrome), bg-highlight the transient\nhover/focus/keyboard wash (pairs with shadow-highlight; latched states\nstay on opaque bg-hover), bg-overlay the modal scrim.",
385
+ "description": "Surface fills — bg-well is the surface's own resting fill (pairs with\nshadow-well for recessed chrome), bg-elevated the raised tier,\nbg-highlight the transient\nhover/focus/keyboard wash (pairs with shadow-highlight; latched states\nstay on opaque bg-hover), bg-overlay the modal scrim.",
343
386
  "css": "@theme inline {\n\t--color-well: var(--era-surface-bg);\n\t--color-elevated: var(--era-surface-bg-elevated);\n\t--color-highlight: var(--era-highlight);\n\t--color-overlay: var(--era-overlay-bg);\n}"
344
387
  },
345
388
  {
@@ -433,12 +476,16 @@
433
476
  "p-chip-inset-bar",
434
477
  "px-chip-inset-bar",
435
478
  "py-chip-inset-bar",
436
- "gap-chip-inset-bar"
479
+ "gap-chip-inset-bar",
480
+ "p-control-inset-bar",
481
+ "px-control-inset-bar",
482
+ "py-control-inset-bar",
483
+ "gap-control-inset-bar"
437
484
  ],
438
485
  "file": "index.css",
439
486
  "useCase": "the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control.",
440
487
  "description": "",
441
- "css": "@theme inline {\n\t--spacing-icon-inset-pill: var(--era-icon-inset-pill);\n\t--spacing-icon-inset-chip: var(--era-icon-inset-chip);\n\t--spacing-icon-inset-control: var(--era-icon-inset-control);\n\t--spacing-icon-inset-bar: var(--era-icon-inset-bar);\n\t--spacing-pill-inset-chip: var(--era-pill-inset-chip);\n\t--spacing-pill-inset-control: var(--era-pill-inset-control);\n\t--spacing-pill-inset-bar: var(--era-pill-inset-bar);\n\t--spacing-chip-inset-control: var(--era-chip-inset-control);\n\t--spacing-chip-inset-bar: var(--era-chip-inset-bar);\n}"
488
+ "css": "@theme inline {\n\t--spacing-icon-inset-pill: var(--era-icon-inset-pill);\n\t--spacing-icon-inset-chip: var(--era-icon-inset-chip);\n\t--spacing-icon-inset-control: var(--era-icon-inset-control);\n\t--spacing-icon-inset-bar: var(--era-icon-inset-bar);\n\t--spacing-pill-inset-chip: var(--era-pill-inset-chip);\n\t--spacing-pill-inset-control: var(--era-pill-inset-control);\n\t--spacing-pill-inset-bar: var(--era-pill-inset-bar);\n\t--spacing-chip-inset-control: var(--era-chip-inset-control);\n\t--spacing-chip-inset-bar: var(--era-chip-inset-bar);\n\t--spacing-control-inset-bar: var(--era-control-inset-bar);\n}"
442
489
  },
443
490
  {
444
491
  "name": "p-glyph-icon",
@@ -590,11 +637,17 @@
590
637
  "border-warning",
591
638
  "bg-warning-fg",
592
639
  "text-warning-fg",
593
- "border-warning-fg"
640
+ "border-warning-fg",
641
+ "bg-info",
642
+ "text-info",
643
+ "border-info",
644
+ "bg-info-fg",
645
+ "text-info-fg",
646
+ "border-info-fg"
594
647
  ],
595
648
  "file": "index.css",
596
649
  "description": "The standing pill fill — --era-fill, the latched counterpart of the\ntransient highlight. Surface-owned: a composing wash on flat/bevel, the\nopaque swatch on glass.",
597
- "css": "@theme inline {\n\t--color-fill: var(--era-fill);\n\t--color-link: var(--color-link);\n\t--color-primary: var(--color-primary);\n\t--color-primary-fg: var(--color-primary-fg);\n\t--color-primary-hover: var(--color-primary-hover);\n\t--color-destructive: var(--color-destructive);\n\t--color-destructive-fg: var(--color-destructive-fg);\n\t--color-success: var(--color-success);\n\t--color-success-fg: var(--color-success-fg);\n\t--color-warning: var(--color-warning);\n\t--color-warning-fg: var(--color-warning-fg);\n}"
650
+ "css": "@theme inline {\n\t--color-fill: var(--era-fill);\n\t--color-link: var(--color-link);\n\t--color-primary: var(--color-primary);\n\t--color-primary-fg: var(--color-primary-fg);\n\t--color-primary-hover: var(--color-primary-hover);\n\t--color-destructive: var(--color-destructive);\n\t--color-destructive-fg: var(--color-destructive-fg);\n\t--color-success: var(--color-success);\n\t--color-success-fg: var(--color-success-fg);\n\t--color-warning: var(--color-warning);\n\t--color-warning-fg: var(--color-warning-fg);\n\t--color-info: var(--color-info);\n\t--color-info-fg: var(--color-info-fg);\n}"
598
651
  }
599
652
  ]
600
653
  }