@signal9/era-ui 10.0.0 → 11.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 (262) hide show
  1. package/dist/ai/actions/actions.svelte +1 -1
  2. package/dist/ai/artifact/artifact-actions.svelte +1 -1
  3. package/dist/ai/artifact/artifact-close.svelte +1 -1
  4. package/dist/ai/artifact/artifact-content.svelte +1 -1
  5. package/dist/ai/artifact/artifact-header.svelte +1 -1
  6. package/dist/ai/artifact/artifact.svelte +1 -4
  7. package/dist/ai/chain-of-thought/chain-of-thought-step.svelte +3 -3
  8. package/dist/ai/chain-of-thought/chain-of-thought.svelte +1 -1
  9. package/dist/ai/checkpoint.svelte +2 -2
  10. package/dist/ai/confirmation/confirmation-actions.svelte +1 -1
  11. package/dist/ai/confirmation/confirmation-args.svelte +4 -4
  12. package/dist/ai/confirmation/confirmation.svelte +5 -8
  13. package/dist/ai/context/context.svelte +3 -3
  14. package/dist/ai/conversation/conversation-content.svelte +1 -4
  15. package/dist/ai/conversation/conversation-empty-state.svelte +1 -1
  16. package/dist/ai/conversation/conversation-scroll-button.svelte +3 -3
  17. package/dist/ai/conversations/conversations-group.svelte +2 -2
  18. package/dist/ai/conversations/conversations-item.svelte +8 -8
  19. package/dist/ai/conversations/conversations-root.svelte +2 -2
  20. package/dist/ai/error-panel/error-panel.svelte +7 -7
  21. package/dist/ai/image.svelte +1 -1
  22. package/dist/ai/index.js +1 -1
  23. package/dist/ai/inline-citation/inline-citation.svelte +5 -5
  24. package/dist/ai/loader.svelte +1 -4
  25. package/dist/ai/message/message-branch-selector.svelte +3 -3
  26. package/dist/ai/message/message-branch.svelte +1 -1
  27. package/dist/ai/message/message-content.svelte +1 -1
  28. package/dist/ai/message/message-toolbar.svelte +1 -1
  29. package/dist/ai/message/message-usage.svelte +5 -7
  30. package/dist/ai/message/message.svelte +1 -1
  31. package/dist/ai/model-selector/model-selector.svelte +2 -2
  32. package/dist/ai/open-in-chat/open-in-chat.svelte +2 -2
  33. package/dist/ai/plan/plan-content.svelte +1 -1
  34. package/dist/ai/plan/plan-header.svelte +2 -2
  35. package/dist/ai/plan/plan.svelte +1 -4
  36. package/dist/ai/prompt-input/prompt-input-add-attachments.svelte +1 -1
  37. package/dist/ai/prompt-input/prompt-input-attachments.svelte +5 -5
  38. package/dist/ai/prompt-input/prompt-input-submit.svelte +2 -2
  39. package/dist/ai/prompt-input/prompt-input-textarea.svelte +2 -2
  40. package/dist/ai/prompt-input/prompt-input-toolbar.svelte +1 -1
  41. package/dist/ai/prompt-input/prompt-input.svelte +1 -1
  42. package/dist/ai/queue/queue-item.svelte +1 -1
  43. package/dist/ai/queue/queue.svelte +1 -1
  44. package/dist/ai/reasoning/reasoning-trigger.svelte +1 -1
  45. package/dist/ai/response/response.svelte +1 -1
  46. package/dist/ai/run-status/run-status.svelte +7 -11
  47. package/dist/ai/runtime-feed/runtime-feed-item.svelte +1 -4
  48. package/dist/ai/runtime-feed/runtime-feed-root.svelte +1 -1
  49. package/dist/ai/sources/source.svelte +2 -2
  50. package/dist/ai/sources/sources-trigger.svelte +1 -1
  51. package/dist/ai/structured-value/structured-value.svelte +4 -4
  52. package/dist/ai/suggestion/suggestion.svelte +1 -1
  53. package/dist/ai/suggestion/suggestions.svelte +1 -1
  54. package/dist/ai/swarm/swarm-agent.svelte +3 -3
  55. package/dist/ai/swarm/swarm-artifact.svelte +2 -2
  56. package/dist/ai/swarm/swarm-barrier.svelte +3 -3
  57. package/dist/ai/swarm/swarm-barriers.svelte +1 -4
  58. package/dist/ai/swarm/swarm-counts.svelte +2 -2
  59. package/dist/ai/swarm/swarm-footer.svelte +4 -3
  60. package/dist/ai/swarm/swarm-grid.svelte +2 -2
  61. package/dist/ai/swarm/swarm-header.svelte +2 -2
  62. package/dist/ai/swarm/swarm-node.svelte +7 -9
  63. package/dist/ai/swarm/swarm-role.svelte +6 -3
  64. package/dist/ai/swarm/swarm-root.svelte +1 -4
  65. package/dist/ai/swarm/swarm-sandbox.svelte +4 -7
  66. package/dist/ai/swarm/swarm-tree.svelte +2 -2
  67. package/dist/ai/task/task-content.svelte +1 -4
  68. package/dist/ai/task/task-trigger.svelte +1 -1
  69. package/dist/ai/tool/tool-chip.svelte +3 -3
  70. package/dist/ai/tool/tool-chips.svelte +3 -3
  71. package/dist/ai/tool/tool-exec.svelte +4 -4
  72. package/dist/ai/tool/tool-header.svelte +1 -1
  73. package/dist/ai/web-preview/web-preview.svelte +4 -9
  74. package/dist/ai/workflow/canvas.svelte +1 -1
  75. package/dist/ai/workflow/node.svelte +3 -3
  76. package/dist/apps/index.d.ts +3 -3
  77. package/dist/apps/index.js +3 -3
  78. package/dist/apps/llm-shell/llm-shell.svelte +4 -4
  79. package/dist/apps/notes/editor/slash-menu.svelte +2 -4
  80. package/dist/apps/notes/notes.svelte +8 -8
  81. package/dist/dev/audit/audits/anonymous-text.d.ts +2 -0
  82. package/dist/dev/audit/audits/anonymous-text.js +73 -0
  83. package/dist/dev/audit/audits/even-container-padding.js +2 -2
  84. package/dist/dev/audit/audits/index.d.ts +2 -1
  85. package/dist/dev/audit/audits/index.js +3 -1
  86. package/dist/dev/audit/audits/single-glyph-square.js +2 -2
  87. package/dist/dev/audit/types.d.ts +1 -1
  88. package/dist/dev/audit-overlay.svelte +7 -7
  89. package/dist/docs/css-utilities.d.ts +31 -0
  90. package/dist/docs/css-utilities.js +142 -8
  91. package/dist/docs/llms-txt.js +2 -2
  92. package/dist/docs/notes.md +3 -3
  93. package/dist/docs/quickstart.md +5 -5
  94. package/dist/era-ui.css +1 -1
  95. package/dist/generated-docs/llms-full.txt +455 -110
  96. package/dist/generated-docs/llms.txt +29 -14
  97. package/dist/generated-docs/manifest.json +382 -55
  98. package/dist/generated-docs/notes.md +3 -3
  99. package/dist/generated-docs/utilities.json +359 -45
  100. package/dist/generated-docs/utilities.md +423 -93
  101. package/dist/os/notification-center.svelte +11 -17
  102. package/dist/os/pane-manager.svelte.d.ts +1 -1
  103. package/dist/os/pane.svelte +4 -6
  104. package/dist/os/taskbar.svelte +13 -18
  105. package/dist/os/toast.svelte +6 -11
  106. package/dist/os/toaster.svelte +1 -1
  107. package/dist/styles/density.css +0 -2
  108. package/dist/styles/index.css +160 -84
  109. package/dist/ui/accordion/accordion-content.svelte +1 -1
  110. package/dist/ui/accordion/accordion-trigger.svelte +2 -2
  111. package/dist/ui/alert-dialog/alert-dialog-content.svelte +2 -2
  112. package/dist/ui/alert-dialog/alert-dialog-overlay.svelte +1 -1
  113. package/dist/ui/aspect-ratio/aspect-ratio.svelte +1 -5
  114. package/dist/ui/avatar/avatar-fallback.svelte +1 -1
  115. package/dist/ui/avatar/avatar-root.svelte +1 -1
  116. package/dist/ui/badge/badge.svelte +1 -1
  117. package/dist/ui/badge/badge.svelte.d.ts +1 -1
  118. package/dist/ui/bar/bar.svelte +8 -8
  119. package/dist/ui/bar/bar.svelte.d.ts +16 -16
  120. package/dist/ui/button/button.svelte +13 -2
  121. package/dist/ui/button/variants.d.ts +4 -4
  122. package/dist/ui/button/variants.js +18 -18
  123. package/dist/ui/button-group/button-group.svelte +2 -2
  124. package/dist/ui/calendar/calendar-day.svelte +1 -1
  125. package/dist/ui/calendar/calendar-grid-row.svelte +1 -1
  126. package/dist/ui/calendar/calendar-grid.svelte +1 -1
  127. package/dist/ui/calendar/calendar-head-cell.svelte +1 -1
  128. package/dist/ui/calendar/calendar-header.svelte +1 -1
  129. package/dist/ui/calendar/calendar-next-button.svelte +1 -1
  130. package/dist/ui/calendar/calendar-prev-button.svelte +1 -1
  131. package/dist/ui/calendar/calendar-root.svelte +1 -1
  132. package/dist/ui/card/card.svelte +10 -10
  133. package/dist/ui/card/card.svelte.d.ts +16 -16
  134. package/dist/ui/checkbox/checkbox-group.svelte +1 -1
  135. package/dist/ui/checkbox/checkbox.svelte +1 -1
  136. package/dist/ui/chip/chip.svelte +15 -7
  137. package/dist/ui/chip/chip.svelte.d.ts +7 -7
  138. package/dist/ui/code-block/code-block.svelte +3 -9
  139. package/dist/ui/collapsible/collapsible-trigger.svelte +1 -1
  140. package/dist/ui/combobox/combobox-content.svelte +1 -1
  141. package/dist/ui/combobox/combobox-empty.svelte +1 -6
  142. package/dist/ui/combobox/combobox-group-heading.svelte +1 -4
  143. package/dist/ui/combobox/combobox-input.svelte +1 -1
  144. package/dist/ui/combobox/combobox-item.svelte +1 -1
  145. package/dist/ui/combobox/combobox-trigger.svelte +2 -2
  146. package/dist/ui/command/command-group-heading.svelte +1 -4
  147. package/dist/ui/command/command-group-items.svelte +1 -5
  148. package/dist/ui/command/command-item.svelte +1 -1
  149. package/dist/ui/command/command-link-item.svelte +1 -1
  150. package/dist/ui/command/command-root.svelte +2 -2
  151. package/dist/ui/command/command-viewport.svelte +1 -1
  152. package/dist/ui/command-bar/command-bar.svelte +9 -13
  153. package/dist/ui/context-menu/context-menu-checkbox-item.svelte +1 -1
  154. package/dist/ui/context-menu/context-menu-content.svelte +2 -2
  155. package/dist/ui/context-menu/context-menu-group-heading.svelte +1 -4
  156. package/dist/ui/context-menu/context-menu-item.svelte +1 -1
  157. package/dist/ui/context-menu/context-menu-radio-item.svelte +1 -1
  158. package/dist/ui/context-menu/context-menu-sub-content.svelte +1 -1
  159. package/dist/ui/context-menu/context-menu-sub-trigger.svelte +2 -2
  160. package/dist/ui/copy-button/copy-button.svelte +2 -2
  161. package/dist/ui/cycle/cycle.svelte +2 -2
  162. package/dist/ui/date-field/date-field-segment.svelte +1 -1
  163. package/dist/ui/date-picker/date-picker-calendar.svelte +1 -1
  164. package/dist/ui/date-picker/date-picker-content.svelte +1 -4
  165. package/dist/ui/date-picker/date-picker-day.svelte +1 -1
  166. package/dist/ui/date-picker/date-picker-grid-row.svelte +1 -1
  167. package/dist/ui/date-picker/date-picker-grid.svelte +1 -1
  168. package/dist/ui/date-picker/date-picker-head-cell.svelte +1 -1
  169. package/dist/ui/date-picker/date-picker-header.svelte +1 -1
  170. package/dist/ui/date-picker/date-picker-next-button.svelte +1 -1
  171. package/dist/ui/date-picker/date-picker-prev-button.svelte +1 -1
  172. package/dist/ui/date-picker/date-picker-segment.svelte +1 -1
  173. package/dist/ui/date-picker/date-picker-trigger.svelte +2 -2
  174. package/dist/ui/date-range-field/date-range-field-segment.svelte +1 -1
  175. package/dist/ui/date-range-picker/date-range-picker-calendar.svelte +1 -1
  176. package/dist/ui/date-range-picker/date-range-picker-content.svelte +1 -4
  177. package/dist/ui/date-range-picker/date-range-picker-day.svelte +1 -1
  178. package/dist/ui/date-range-picker/date-range-picker-grid-row.svelte +1 -1
  179. package/dist/ui/date-range-picker/date-range-picker-grid.svelte +1 -5
  180. package/dist/ui/date-range-picker/date-range-picker-head-cell.svelte +1 -1
  181. package/dist/ui/date-range-picker/date-range-picker-header.svelte +1 -1
  182. package/dist/ui/date-range-picker/date-range-picker-next-button.svelte +1 -1
  183. package/dist/ui/date-range-picker/date-range-picker-prev-button.svelte +1 -1
  184. package/dist/ui/date-range-picker/date-range-picker-segment.svelte +1 -1
  185. package/dist/ui/date-range-picker/date-range-picker-trigger.svelte +2 -2
  186. package/dist/ui/dialog/dialog-content.svelte +3 -5
  187. package/dist/ui/dialog/dialog-header.svelte +1 -6
  188. package/dist/ui/dialog/dialog-overlay.svelte +1 -5
  189. package/dist/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +1 -1
  190. package/dist/ui/dropdown-menu/dropdown-menu-content.svelte +2 -2
  191. package/dist/ui/dropdown-menu/dropdown-menu-group-heading.svelte +1 -4
  192. package/dist/ui/dropdown-menu/dropdown-menu-item.svelte +1 -1
  193. package/dist/ui/dropdown-menu/dropdown-menu-radio-item.svelte +1 -1
  194. package/dist/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
  195. package/dist/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +2 -2
  196. package/dist/ui/dropdown-menu/dropdown-menu-trigger.svelte +2 -2
  197. package/dist/ui/file-upload/file-upload.svelte +2 -2
  198. package/dist/ui/index.js +1 -1
  199. package/dist/ui/input/input.svelte +2 -2
  200. package/dist/ui/input/textarea.svelte +1 -1
  201. package/dist/ui/input/variants.d.ts +18 -18
  202. package/dist/ui/input/variants.js +6 -6
  203. package/dist/ui/kv/kv.svelte +2 -3
  204. package/dist/ui/link-preview/link-preview-content.svelte +1 -1
  205. package/dist/ui/menubar/menubar-checkbox-item.svelte +1 -1
  206. package/dist/ui/menubar/menubar-content.svelte +2 -2
  207. package/dist/ui/menubar/menubar-group-heading.svelte +1 -4
  208. package/dist/ui/menubar/menubar-item.svelte +1 -1
  209. package/dist/ui/menubar/menubar-radio-item.svelte +1 -1
  210. package/dist/ui/menubar/menubar-root.svelte +1 -4
  211. package/dist/ui/menubar/menubar-sub-content.svelte +1 -1
  212. package/dist/ui/menubar/menubar-sub-trigger.svelte +2 -2
  213. package/dist/ui/menubar/menubar-trigger.svelte +1 -1
  214. package/dist/ui/meter/meter.svelte +2 -2
  215. package/dist/ui/pagination/pagination-next-button.svelte +1 -1
  216. package/dist/ui/pagination/pagination-prev-button.svelte +1 -1
  217. package/dist/ui/pagination/pagination-root.svelte +1 -1
  218. package/dist/ui/pane/pane-content.svelte +1 -1
  219. package/dist/ui/pane/pane-root.svelte +1 -1
  220. package/dist/ui/pane/pane-tab-list.svelte +1 -1
  221. package/dist/ui/pane/pane-tab-panel.svelte +1 -1
  222. package/dist/ui/pane/pane-tab.svelte +1 -1
  223. package/dist/ui/pane/pane.svelte +1 -1
  224. package/dist/ui/pin-input/pin-input-cell.svelte +1 -1
  225. package/dist/ui/popover/popover-content.svelte +1 -1
  226. package/dist/ui/popover/popover-trigger.svelte +1 -4
  227. package/dist/ui/progress/progress.svelte +2 -2
  228. package/dist/ui/radio-group/radio-group-item.svelte +2 -2
  229. package/dist/ui/radio-group/radio-group-root.svelte +1 -1
  230. package/dist/ui/rating-group/rating-group-item.svelte +1 -1
  231. package/dist/ui/rating-group/rating-group-root.svelte +1 -1
  232. package/dist/ui/scroll-area/scroll-area-scrollbar.svelte +1 -1
  233. package/dist/ui/scroll-area/scroll-area-thumb.svelte +1 -1
  234. package/dist/ui/scroll-area/scroll-area.svelte +1 -1
  235. package/dist/ui/select/select-content.svelte +7 -6
  236. package/dist/ui/select/select-group-heading.svelte +1 -4
  237. package/dist/ui/select/select-item.svelte +1 -1
  238. package/dist/ui/select/select-trigger.svelte +2 -2
  239. package/dist/ui/select/select-value.svelte +1 -1
  240. package/dist/ui/separator/separator.svelte +1 -1
  241. package/dist/ui/sheet/sheet-content.svelte +3 -3
  242. package/dist/ui/sheet/sheet-content.svelte.d.ts +4 -4
  243. package/dist/ui/skeleton/skeleton.svelte +4 -4
  244. package/dist/ui/skeleton/skeleton.svelte.d.ts +10 -10
  245. package/dist/ui/slider/slider-range.svelte +1 -1
  246. package/dist/ui/slider/slider-thumb.svelte +1 -1
  247. package/dist/ui/slider/slider-tick.svelte +1 -1
  248. package/dist/ui/step/step-content.svelte +1 -1
  249. package/dist/ui/step/step-section.svelte +1 -1
  250. package/dist/ui/step/step-summary.svelte +7 -7
  251. package/dist/ui/switch/switch.svelte +2 -2
  252. package/dist/ui/table/table-cell.svelte +1 -1
  253. package/dist/ui/table/table-head-cell.svelte +1 -1
  254. package/dist/ui/table/table-row.svelte +1 -1
  255. package/dist/ui/time-field/time-field-segment.svelte +1 -1
  256. package/dist/ui/time-range-field/time-range-field-segment.svelte +1 -1
  257. package/dist/ui/toggle-group/toggle-group-item.svelte +1 -1
  258. package/dist/ui/toggle-group/toggle-group-root.svelte +1 -1
  259. package/dist/ui/tooltip/tooltip-content.svelte +1 -1
  260. package/dist/ui/video-player/video-player.svelte +44 -47
  261. package/dist/utils/index.js +1 -1
  262. package/package.json +4 -3
@@ -4,18 +4,20 @@
4
4
 
5
5
  ## Using the library
6
6
 
7
+ This package is published to two registries under two names: `@signal9/era-ui` on npm (used throughout these docs) and `@sig-nine/era-ui` on GitHub Packages, where the scope must match the repo owner. Same code, same versions — pick the one your registry serves and keep the scope consistent.
8
+
7
9
  **One entry point per component.** There is no barrel that re-exports everything — importing a component can never drag in another one, or another one's dependencies.
8
10
 
9
11
  ```ts
10
- import { Button } from "@sig-nine/era-ui/button";
11
- import * as Select from "@sig-nine/era-ui/select";
12
- import * as Table from "@sig-nine/era-ui/table";
12
+ import { Button } from "@signal9/era-ui/button";
13
+ import * as Select from "@signal9/era-ui/select";
14
+ import * as Table from "@signal9/era-ui/table";
13
15
 
14
16
  // The root is the SYSTEM layer only: cn/tv, keybindings, the axis
15
17
  // registry, and Mode. It imports no component.
16
- import { cn, ModeProvider } from "@sig-nine/era-ui";
18
+ import { cn, ModeProvider } from "@signal9/era-ui";
17
19
 
18
- import "@sig-nine/era-ui/styles"; // source CSS, scanned by your Tailwind
20
+ import "@signal9/era-ui/styles"; // source CSS, scanned by your Tailwind
19
21
  ```
20
22
 
21
23
  The path is always the component's own kebab-case name — `/button`, `/dropdown-menu`, `/date-range-picker` — and the other layers are namespaced: `/ai` and `/ai/<part>`, `/apps/<app>`, `/os`, `/audit`.
@@ -24,7 +26,7 @@ Named exports wrap a single primitive (`Button`, `Badge`, `Chip`, `Input`, …).
24
26
 
25
27
  ### Stylesheets
26
28
 
27
- `@sig-nine/era-ui/styles` is the source CSS — import it once and your own Tailwind build scans era's components and emits only the utilities they use. `@sig-nine/era-ui/css` is the prebuilt alternative for a project without Tailwind. Three more are opt-in, each single-purpose: `/styles/video-player` (vidstack's vendor CSS, needed only with `VideoPlayer`), `/styles/prose` (document typography for a TipTap editor — put `era-notes-prose` on your editor element; `NoteEditor` imports it already), and `/styles/themes` (the raw theme tokens).
29
+ `@signal9/era-ui/styles` is the source CSS — import it once and your own Tailwind build scans era's components and emits only the utilities they use. `@signal9/era-ui/css` is the prebuilt alternative for a project without Tailwind. Three more are opt-in, each single-purpose: `/styles/video-player` (vidstack's vendor CSS, needed only with `VideoPlayer`), `/styles/prose` (document typography for a TipTap editor — put `era-notes-prose` on your editor element; `NoteEditor` imports it already), and `/styles/themes` (the raw theme tokens).
28
30
 
29
31
  ### Optional peers
30
32
 
@@ -58,20 +60,33 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
58
60
  - `era-text-trim` — vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.
59
61
  - `truncate` — single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders.
60
62
  - `era-text-trim-caps` — the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`.
61
- - `era-token-ink · era-ink-center` — the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).
63
+ - `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.
64
+ - `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.
65
+ - `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).
62
66
  - `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.
63
67
  - `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
64
68
  - `h-icon · h-pill · h-chip · h-control · h-bar` — the tier-height ladder — h-icon (icon) · h-pill (nested pill) · h-chip (standalone pill) · h-control (control) · h-bar (bar); the named form of h-(--era-h-*).
65
69
  - `min-h-icon · min-h-pill · min-h-chip · min-h-control · min-h-bar` — minimum tier height for containers that may grow — a bar that is at least lg-tier but can wrap (min-h-bar).
70
+ - `w-icon · w-pill · w-chip · w-control · w-bar` — a tier-sized WIDTH — the horizontal twin of the h-* ladder, for a rail or a column measured in tiers rather than in content.
71
+ - `min-w-icon · min-w-pill · min-w-chip · min-w-control · min-w-bar` — a minimum tier WIDTH — the floor that makes a single-glyph control render as a square rather than a skinny pill (min-w-control on an icon button, min-w-pill on a badge). These could not exist before the ladder was renamed: the old rungs were sm/md/lg, and Tailwind's container scale already owns min-w-md and min-w-lg, so the names collided and every call site had to write min-w-(--era-h-control) by hand. icon/pill/chip/control/bar collide with nothing.
66
72
  - `size-icon · size-pill · size-chip · size-control · size-bar` — a tier-sized square — size-icon is THE icon size (a Lucide glyph beside body text), size-control a square control face.
67
- - `gap-gutter · p-gutter · px-gutter · py-gutter` — the inter-element gap (sp/2) — flex/grid gap between sibling controls, and the matching gutter padding a scrollable list or rail owes its rows on all four sides (p-gutter on the rail = gap-gutter between its rows).
68
- - `p-inset-pill · p-inset-chip · p-inset-control · px-inset-pill · px-inset-chip · px-inset-control · py-inset-pill · py-inset-chip · py-inset-control` — text-symmetric content padding — (tier − text)/2, the inset that vertically centers body text in its tier; px-inset-control is a text button's side padding, p-inset-control a code block's.
69
- - `px-pill · px-chip` — pill side padding — the wider-than-vertical horizontal breathing room badge/chip text wants (glyph-advance derived, ~2× the vertical inset).
70
- - `px-field` — text-field side padding — where typed text starts in a control-tier input; the named form of px-(--era-field-px).
71
- - `p-panel · p-card` — optical padding for unbounded containers — p-panel for compact shells and menu-adjacent chrome, p-card for cards/dialogs/popovers, p-content for full content panels. Grows super-linearly with density so whitespace holds its perceived share as controls loosen.
72
- - `p-content` — A content panel always follows a section header ROW, and that row already
73
- - `p-menu` — menu-panel padding — the surface-owned inset (0 on flat, 2px on glass/bevel) that keeps row highlights inside a floating panel's frame; pairs with rounded-menu-item on the rows.
73
+ - `px-pill · px-chip · pl-pill · pr-pill · pl-chip · pr-chip` — pill side padding — the wider-than-vertical horizontal breathing room badge/chip text wants (glyph-advance derived, ~2× the vertical inset).
74
+ - `p-section` — padding for a content panel that sits UNDER a section header row — the even-padding exception, and the reason it is not called p-section: it deliberately under-pays the block start. For an evenly padded content panel use p-section, which is the plain token.
74
75
  - `duration-base` — the motion axis as an explicit transition-duration — for the rare case a utility (not the transition-* default) needs to name it; 0s at data-motion="instant", longer at "extra".
76
+ - `text-body` — Density-derived body size: `text-body` replaces text-[length:var(--era-text)]
77
+ - `leading-body` — Prose leading — `leading-body` is the pair to `text-body`, and every piece
78
+ - `rounded-icon · rounded-pill · rounded-chip · rounded-control · rounded-bar · rounded-menu-item` — Radius ladder — Tailwind's own rounded-* names now walk era's concentric
79
+ - `shadow` — Surface chrome — bare `shadow` is the resting control edge, shadow-lg the
80
+ - `shadow-sm · shadow-lg · shadow-well · shadow-pressed · shadow-highlight` — v4 marks bare `shadow` a deprecated spelling of shadow-sm, and lints
81
+ - `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
82
+ - `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
83
+ - `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.
84
+ - `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 · … (32 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.
85
+ - `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).
86
+ - `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.
87
+ - `ease-base` — Motion — bare transition utilities default to the motion axis, so
88
+ - `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, …
89
+ - `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
75
90
  - `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.
76
91
 
77
92
  Full reference (what each emits, when to use it): `/utilities.md`. Machine-readable list: `/utilities.json`.
@@ -131,7 +146,7 @@ never the `h-(--era-h-control)` var-class spelling. Everything below rides along
131
146
  with the stylesheet and needs no import:
132
147
 
133
148
  ```ts
134
- import "@sig-nine/era-ui/css";
149
+ import "@signal9/era-ui/css";
135
150
  ```
136
151
 
137
152
  ```svelte
@@ -145,7 +160,7 @@ motion):
145
160
 
146
161
  | Stock-looking class | What it resolves to |
147
162
  |---|---|
148
- | `rounded-icon/xxs/sm/md/lg` | the concentric radius ladder (collapses on `data-corners="square"`) |
163
+ | `rounded-icon/pill/chip/control/bar` | the concentric radius ladder (collapses on `data-corners="square"`) |
149
164
  | `rounded-menu-item` | menu-row radius, concentric inside a `rounded-control` panel |
150
165
  | `shadow` / `shadow-lg` | resting control edge / floating panel chrome, per surface |
151
166
  | `shadow-well` / `shadow-pressed` / `shadow-highlight` | recessed, pressed/latched, hover-material chrome |
@@ -153,10 +168,21 @@ motion):
153
168
  | `transition-*` (bare) | duration + easing default to the motion axis |
154
169
  | `ease-base` / `duration-base` | the motion axis, named explicitly |
155
170
  | `text-body` | density-derived body/control text size |
156
-
157
- Deliberate gaps: `w-*`/`min-w-*` tier names would shadow Tailwind's container
158
- scale (`min-w-md` stays 28rem), and the concentric-inset tokens are advanced
159
- enough to stay var-form — `min-w-(--era-h-control)` etc. remain the escape hatch.
171
+ | `p-gutter` / `gap-gutter` / `mt-gutter` / … | the spacing scale — EVERY spacing prefix works |
172
+
173
+ The spacing names (`gutter`, `card`, `panel`, `content`, `menu`, `field`, the
174
+ `inset-*` and concentric `*-inset-*` insets, `glyph-*`) are registered as a
175
+ Tailwind spacing scale, so every prefix derives automatically: `p-`, `px-`,
176
+ `pt-`, `mt-`, `gap-`, `gap-x-`, `inset-`, `translate-`, and the rest. The TIER
177
+ names (`icon`, `pill`, `chip`, `control`, `bar`) are heights, not spacing, so
178
+ they are registered per prefix instead — `h-`, `w-`, `min-h-`, `min-w-` and
179
+ `size-` — and the two vocabularies deliberately share no word. Putting a tier
180
+ in the spacing scale would silently make `px-control` mean 24px of padding.
181
+
182
+ The var form (`h-(--era-h-control)`) still works and is the escape hatch for a
183
+ token with no registered name — `--era-sp`, the press-sink offsets, anything
184
+ a component reaches for once. `scripts/check-canonical.ts` fails the build if
185
+ source uses it where a name exists.
160
186
 
161
187
  | Utility | Use it for |
162
188
  |---|---|
@@ -166,20 +192,33 @@ enough to stay var-form — `min-w-(--era-h-control)` etc. remain the escape hat
166
192
  | `era-text-trim` | vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS. |
167
193
  | `truncate` | single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders. |
168
194
  | `era-text-trim-caps` | the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`. |
169
- | `era-token-ink` `era-ink-center` | the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies). |
195
+ | `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. |
196
+ | `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. |
197
+ | `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). |
170
198
  | `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. |
171
199
  | `era-collapse` | the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden). |
172
200
  | `h-icon` `h-pill` `h-chip` `h-control` `h-bar` | the tier-height ladder — h-icon (icon) · h-pill (nested pill) · h-chip (standalone pill) · h-control (control) · h-bar (bar); the named form of h-(--era-h-*). |
173
201
  | `min-h-icon` `min-h-pill` `min-h-chip` `min-h-control` `min-h-bar` | minimum tier height for containers that may grow — a bar that is at least lg-tier but can wrap (min-h-bar). |
202
+ | `w-icon` `w-pill` `w-chip` `w-control` `w-bar` | a tier-sized WIDTH — the horizontal twin of the h-* ladder, for a rail or a column measured in tiers rather than in content. |
203
+ | `min-w-icon` `min-w-pill` `min-w-chip` `min-w-control` `min-w-bar` | a minimum tier WIDTH — the floor that makes a single-glyph control render as a square rather than a skinny pill (min-w-control on an icon button, min-w-pill on a badge). These could not exist before the ladder was renamed: the old rungs were sm/md/lg, and Tailwind's container scale already owns min-w-md and min-w-lg, so the names collided and every call site had to write min-w-(--era-h-control) by hand. icon/pill/chip/control/bar collide with nothing. |
174
204
  | `size-icon` `size-pill` `size-chip` `size-control` `size-bar` | a tier-sized square — size-icon is THE icon size (a Lucide glyph beside body text), size-control a square control face. |
175
- | `gap-gutter` `p-gutter` `px-gutter` `py-gutter` | the inter-element gap (sp/2) — flex/grid gap between sibling controls, and the matching gutter padding a scrollable list or rail owes its rows on all four sides (p-gutter on the rail = gap-gutter between its rows). |
176
- | `p-inset-pill` `p-inset-chip` `p-inset-control` `px-inset-pill` `px-inset-chip` `px-inset-control` `py-inset-pill` `py-inset-chip` `py-inset-control` | text-symmetric content padding — (tier − text)/2, the inset that vertically centers body text in its tier; px-inset-control is a text button's side padding, p-inset-control a code block's. |
177
- | `px-pill` `px-chip` | pill side padding — the wider-than-vertical horizontal breathing room badge/chip text wants (glyph-advance derived, ~2× the vertical inset). |
178
- | `px-field` | text-field side padding — where typed text starts in a control-tier input; the named form of px-(--era-field-px). |
179
- | `p-panel` `p-card` | optical padding for unbounded containers — p-panel for compact shells and menu-adjacent chrome, p-card for cards/dialogs/popovers, p-content for full content panels. Grows super-linearly with density so whitespace holds its perceived share as controls loosen. |
180
- | `p-content` | — |
181
- | `p-menu` | menu-panel padding — the surface-owned inset (0 on flat, 2px on glass/bevel) that keeps row highlights inside a floating panel's frame; pairs with rounded-menu-item on the rows. |
205
+ | `px-pill` `px-chip` `pl-pill` `pr-pill` `pl-chip` `pr-chip` | pill side padding — the wider-than-vertical horizontal breathing room badge/chip text wants (glyph-advance derived, ~2× the vertical inset). |
206
+ | `p-section` | padding for a content panel that sits UNDER a section header row — the even-padding exception, and the reason it is not called p-section: it deliberately under-pays the block start. For an evenly padded content panel use p-section, which is the plain token. |
182
207
  | `duration-base` | the motion axis as an explicit transition-duration — for the rare case a utility (not the transition-* default) needs to name it; 0s at data-motion="instant", longer at "extra". |
208
+ | `text-body` | — |
209
+ | `leading-body` | — |
210
+ | `rounded-icon` `rounded-pill` `rounded-chip` `rounded-control` `rounded-bar` `rounded-menu-item` | — |
211
+ | `shadow` | — |
212
+ | `shadow-sm` `shadow-lg` `shadow-well` `shadow-pressed` `shadow-highlight` | — |
213
+ | `bg-well` `text-well` `border-well` `bg-elevated` `text-elevated` `border-elevated` `bg-highlight` `text-highlight` `border-highlight` `bg-overlay` `text-overlay` `border-overlay` | — |
214
+ | `p-gutter` `px-gutter` `py-gutter` `gap-gutter` `p-panel` `px-panel` `py-panel` `gap-panel` `p-card` `px-card` `py-card` `gap-card` `p-content` `px-content` `py-content` `gap-content` `p-menu` `px-menu` `py-menu` `gap-menu` `p-field` `px-field` `py-field` `gap-field` | — |
215
+ | `p-inset-pill` `px-inset-pill` `py-inset-pill` `gap-inset-pill` `p-inset-chip` `px-inset-chip` `py-inset-chip` `gap-inset-chip` `p-inset-control` `px-inset-control` `py-inset-control` `gap-inset-control` | 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. |
216
+ | `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` `p-icon-inset-control` `px-icon-inset-control` `py-icon-inset-control` `gap-icon-inset-control` `p-icon-inset-bar` `px-icon-inset-bar` `py-icon-inset-bar` `gap-icon-inset-bar` `p-pill-inset-chip` `px-pill-inset-chip` `py-pill-inset-chip` `gap-pill-inset-chip` `p-pill-inset-control` `px-pill-inset-control` `py-pill-inset-control` `gap-pill-inset-control` `p-chip-inset-control` `px-chip-inset-control` `py-chip-inset-control` `gap-chip-inset-control` `p-chip-inset-bar` `px-chip-inset-bar` `py-chip-inset-bar` `gap-chip-inset-bar` | 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. |
217
+ | `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). |
218
+ | `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. |
219
+ | `ease-base` | — |
220
+ | `bg-divider` `text-divider` `border-divider` `bg-divider-faded` `text-divider-faded` `border-divider-faded` `bg-background` `text-background` `border-background` `bg-foreground` `text-foreground` `border-foreground` `bg-1` `text-1` `border-1` `bg-2` `text-2` `border-2` `bg-3` `text-3` `border-3` `bg-4` `text-4` `border-4` `bg-5` `text-5` `border-5` `bg-6` `text-6` `border-6` `bg-7` `text-7` `border-7` `bg-8` `text-8` `border-8` `bg-9` `text-9` `border-9` `bg-10` `text-10` `border-10` `bg-11` `text-11` `border-11` `bg-12` `text-12` `border-12` `bg-border` `text-border` `border-border` `bg-surface` `text-surface` `border-surface` `bg-hover` `text-hover` `border-hover` `bg-fg` `text-fg` `border-fg` `bg-bright` `text-bright` `border-bright` `bg-muted` `text-muted` `border-muted` | — |
221
+ | `bg-fill` `text-fill` `border-fill` `bg-link` `text-link` `border-link` `bg-primary` `text-primary` `border-primary` `bg-primary-fg` `text-primary-fg` `border-primary-fg` `bg-primary-hover` `text-primary-hover` `border-primary-hover` `bg-destructive` `text-destructive` `border-destructive` `bg-destructive-fg` `text-destructive-fg` `border-destructive-fg` `bg-success` `text-success` `border-success` `bg-success-fg` `text-success-fg` `border-success-fg` `bg-warning` `text-warning` `border-warning` `bg-warning-fg` `text-warning-fg` `border-warning-fg` | — |
183
222
  | `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. |
184
223
 
185
224
  ## era-interactive
@@ -357,9 +396,47 @@ Declared in `index.css`.
357
396
  }
358
397
  ```
359
398
 
360
- ## era-token-ink · era-ink-center
399
+ ## era-ink-center
400
+
401
+ **Use it for:** on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.
402
+
403
+ The EDITABLE counterpart of era-text-trim — for native <input>s, which the
404
+ trim is forbidden on (it collapses the UA's inner editor box and slices the
405
+ glyphs; see typography/collapsed-text-trim).
406
+
407
+ Without help, a tier-height input centres its text by FONT BOX, and the ui
408
+ stacks' font box is deeply asymmetric: ascent ≈1.07em against descent
409
+ ≈0.29em. Centring that box parks the visible band (caps, x-height) ~0.115em
410
+ LOW — so a field's text sat visibly below the trimmed label beside it.
411
+
412
+ The value is OPTICAL, not the derivation's: pure x-band centring computes
413
+ to ~0.23em of padding, but pixel-measured against real Title-Case text it
414
+ over-lifts — the eye weighs the cap-to-baseline mass, which x-band
415
+ centring parks ~2px high (caps 2.75px off the top against 5.7px of air
416
+ under the baseline, measured at dense). 0.08em splits the difference
417
+ between the x-band ideal and the cap-band ideal, landing caps ~3.7px in an
418
+ 18px field with ~4.7px under the baseline — the reading where neither
419
+ band's partisans win and neither complains.
361
420
 
362
- **Use it for:** the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).
421
+ The lift is padding, not a translateY: an icon-less Input paints the field
422
+ chrome itself, and a transform would drag the field along with the ink.
423
+ padding-bottom shrinks the content box from below, and a single-line input
424
+ re-centres its line box in what remains — the ink rises by exactly half the
425
+ padding, the chrome doesn't move, and the caret and selection follow the
426
+ text. In em on purpose: the correction is a fraction of the type, so it
427
+ holds across every density and text size with one value.
428
+
429
+ Declared in `index.css`.
430
+
431
+ ```css
432
+ @utility era-ink-center {
433
+ padding-bottom: 0.08em;
434
+ }
435
+ ```
436
+
437
+ ## era-token-ink
438
+
439
+ **Use it for:** 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.
363
440
 
364
441
  TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
365
442
  count, a status, a tag. Font-independent, unlike everything it replaces.
@@ -398,9 +475,45 @@ Declared in `index.css`.
398
475
  line-height: 1;
399
476
  text-box: trim-both cap alphabetic;
400
477
  }
478
+ ```
401
479
 
402
- @utility era-ink-center {
403
- padding-bottom: 0.08em;
480
+ ## era-label-ink
481
+
482
+ **Use it for:** 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).
483
+
484
+ LABEL INK — era-token-ink's mixed-case sibling, and the general answer to
485
+ "this fixed-height control holds one line of text".
486
+
487
+ Same mechanism, same reason: `text-box-trim` needs a BLOCK box, so the row
488
+ becomes one and `align-content` (block-container alignment) does the
489
+ centring. What differs is the band and the alignment, because the content
490
+ class differs — a label is sentence case, so the x-height band is the visual
491
+ mass to centre (cap-band reads low on "System"), and it is laid out against
492
+ the row's padding rather than centred in it.
493
+
494
+ WHY IT EXISTS AT ALL: era's controls are flex, and a flex container's bare
495
+ text is an ANONYMOUS flex item — a box no selector reaches and no
496
+ non-inherited property touches. So `era-text-trim` on a flex row is inert,
497
+ contributing only its `line-height: 1`, and the ink falls back to line-box
498
+ centring by font metrics. era-token-ink already fixed that for centred
499
+ tokens; this fixes it for everything else.
500
+
501
+ THE ICON CASE IS NOT SOLVED, and cannot be from CSS: an icon beside the text
502
+ needs the box to stay flex, which re-creates the anonymous item. A component
503
+ whose children are an opaque slot therefore guards it —
504
+ `not-has-[svg]:era-label-ink` — and ink-centres the text-only case while
505
+ leaving the icon case on line-box centring. Splitting icon and label into
506
+ separate slots is what would close it; typography/inert-trim reports every
507
+ site still on the fallback.
508
+
509
+ Declared in `index.css`.
510
+
511
+ ```css
512
+ @utility era-label-ink {
513
+ display: block;
514
+ align-content: center;
515
+ line-height: 1;
516
+ text-box: trim-both ex alphabetic;
404
517
  }
405
518
  ```
406
519
 
@@ -514,6 +627,54 @@ Declared in `index.css`.
514
627
  }
515
628
  ```
516
629
 
630
+ ## w-icon · w-pill · w-chip · w-control · w-bar
631
+
632
+ **Use it for:** a tier-sized WIDTH — the horizontal twin of the h-* ladder, for a rail or a column measured in tiers rather than in content.
633
+
634
+ Declared in `index.css`.
635
+
636
+ ```css
637
+ @utility w-icon {
638
+ width: var(--era-h-icon);
639
+ }
640
+ @utility w-pill {
641
+ width: var(--era-h-pill);
642
+ }
643
+ @utility w-chip {
644
+ width: var(--era-h-chip);
645
+ }
646
+ @utility w-control {
647
+ width: var(--era-h-control);
648
+ }
649
+ @utility w-bar {
650
+ width: var(--era-h-bar);
651
+ }
652
+ ```
653
+
654
+ ## min-w-icon · min-w-pill · min-w-chip · min-w-control · min-w-bar
655
+
656
+ **Use it for:** a minimum tier WIDTH — the floor that makes a single-glyph control render as a square rather than a skinny pill (min-w-control on an icon button, min-w-pill on a badge). These could not exist before the ladder was renamed: the old rungs were sm/md/lg, and Tailwind's container scale already owns min-w-md and min-w-lg, so the names collided and every call site had to write min-w-(--era-h-control) by hand. icon/pill/chip/control/bar collide with nothing.
657
+
658
+ Declared in `index.css`.
659
+
660
+ ```css
661
+ @utility min-w-icon {
662
+ min-width: var(--era-h-icon);
663
+ }
664
+ @utility min-w-pill {
665
+ min-width: var(--era-h-pill);
666
+ }
667
+ @utility min-w-chip {
668
+ min-width: var(--era-h-chip);
669
+ }
670
+ @utility min-w-control {
671
+ min-width: var(--era-h-control);
672
+ }
673
+ @utility min-w-bar {
674
+ min-width: var(--era-h-bar);
675
+ }
676
+ ```
677
+
517
678
  ## size-icon · size-pill · size-chip · size-control · size-bar
518
679
 
519
680
  **Use it for:** a tier-sized square — size-icon is THE icon size (a Lucide glyph beside body text), size-control a square control face.
@@ -543,155 +704,339 @@ Declared in `index.css`.
543
704
  }
544
705
  ```
545
706
 
546
- ## gap-gutter · p-gutter · px-gutter · py-gutter
707
+ ## px-pill · px-chip · pl-pill · pr-pill · pl-chip · pr-chip
547
708
 
548
- **Use it for:** the inter-element gap (sp/2) — flex/grid gap between sibling controls, and the matching gutter padding a scrollable list or rail owes its rows on all four sides (p-gutter on the rail = gap-gutter between its rows).
709
+ **Use it for:** pill side padding — the wider-than-vertical horizontal breathing room badge/chip text wants (glyph-advance derived, ~2× the vertical inset).
549
710
 
550
711
  Declared in `index.css`.
551
712
 
552
713
  ```css
553
- @utility gap-gutter {
554
- gap: var(--era-gap);
714
+ @utility px-pill {
715
+ padding-inline: var(--era-pill-px);
716
+ }
717
+ @utility px-chip {
718
+ padding-inline: var(--era-chip-px);
555
719
  }
556
- @utility p-gutter {
557
- padding: var(--era-gap);
720
+ @utility pl-pill {
721
+ padding-left: var(--era-pill-px);
558
722
  }
559
- @utility px-gutter {
560
- padding-inline: var(--era-gap);
723
+ @utility pr-pill {
724
+ padding-right: var(--era-pill-px);
561
725
  }
562
- @utility py-gutter {
563
- padding-block: var(--era-gap);
726
+ @utility pl-chip {
727
+ padding-left: var(--era-chip-px);
728
+ }
729
+ @utility pr-chip {
730
+ padding-right: var(--era-chip-px);
564
731
  }
565
732
  ```
566
733
 
567
- ## p-inset-pill · p-inset-chip · p-inset-control · px-inset-pill · px-inset-chip · px-inset-control · py-inset-pill · py-inset-chip · py-inset-control
734
+ ## p-section
735
+
736
+ **Use it for:** padding for a content panel that sits UNDER a section header row — the even-padding exception, and the reason it is not called p-section: it deliberately under-pays the block start. For an evenly padded content panel use p-section, which is the plain token.
737
+
738
+ A content panel always follows a section header ROW, and that row already
739
+ contributes its own slack: the heading's text sits in an h-bar bar, so there
740
+ is (h-bar − text)/2 of empty bar under its glyphs before the panel even
741
+ starts. Padding the panel evenly on top of that spends the space twice — the
742
+ header ends up floating between the section above and the paragraph it
743
+ introduces rather than binding to it.
744
+
745
+ So the block-start pays only the REMAINDER. The target is the indent: the
746
+ space under a heading should measure the same as the space beside the text,
747
+ which is --era-pad-content. The header row already supplies (h-bar − text)/2 of
748
+ it, so the panel adds what's left, and heading-to-paragraph reads equal to
749
+ the paragraph's own inset. Subtracting one --era-gap (the previous rule) left
750
+ the header's slack unaccounted for and the heading still detached.
568
751
 
569
- **Use it for:** text-symmetric content padding — (tier − text)/2, the inset that vertically centers body text in its tier; px-inset-control is a text button's side padding, p-inset-control a code block's.
752
+ Both terms are density-derived, so the equality holds at every mode; the
753
+ max() is the floor for a hypothetical mode where the row's slack would
754
+ exceed the inset outright.
570
755
 
571
756
  Declared in `index.css`.
572
757
 
573
758
  ```css
574
- @utility p-inset-pill {
575
- padding: var(--era-inset-pill);
576
- }
577
- @utility p-inset-chip {
578
- padding: var(--era-inset-chip);
579
- }
580
- @utility p-inset-control {
581
- padding: var(--era-inset-control);
759
+ @utility p-section {
760
+ padding: var(--era-pad-content);
761
+ padding-top: max(0px, calc(var(--era-pad-content) - (var(--era-h-bar) - var(--era-text)) / 2));
582
762
  }
583
- @utility px-inset-pill {
584
- padding-inline: var(--era-inset-pill);
763
+ ```
764
+
765
+ ## duration-base
766
+
767
+ **Use it for:** the motion axis as an explicit transition-duration — for the rare case a utility (not the transition-* default) needs to name it; 0s at data-motion="instant", longer at "extra".
768
+
769
+ Declared in `index.css`.
770
+
771
+ ```css
772
+ @utility duration-base {
773
+ transition-duration: var(--era-duration);
585
774
  }
586
- @utility px-inset-chip {
587
- padding-inline: var(--era-inset-chip);
775
+ ```
776
+
777
+ ## text-body
778
+
779
+ Density-derived body size: `text-body` replaces text-[length:var(--era-text)]
780
+
781
+ Declared in `index.css`.
782
+
783
+ ```css
784
+ @theme inline {
785
+ --text-body: var(--era-text);
588
786
  }
589
- @utility px-inset-control {
590
- padding-inline: var(--era-inset-control);
787
+ ```
788
+
789
+ ## leading-body
790
+
791
+ Prose leading — `leading-body` is the pair to `text-body`, and every piece
792
+ of text in the library that can wrap to a second line carries it. Enforced
793
+ at runtime by typography/prose-leading.
794
+
795
+ Declared in `index.css`.
796
+
797
+ ```css
798
+ @theme inline {
799
+ --leading-body: var(--era-leading);
591
800
  }
592
- @utility py-inset-pill {
593
- padding-block: var(--era-inset-pill);
801
+ ```
802
+
803
+ ## rounded-icon · rounded-pill · rounded-chip · rounded-control · rounded-bar · rounded-menu-item
804
+
805
+ Radius ladder — Tailwind's own rounded-* names now walk era's concentric
806
+ ladder (rd-T = rd-xs + (h-T − h-icon)/2), ride the corners toggle, and
807
+ collapse to 0 on square. rounded-menu-item is the menu-row radius
808
+ (rd-md − panel-inset) that keeps rows concentric inside a rounded-control
809
+ panel on every surface.
810
+
811
+ Declared in `index.css`.
812
+
813
+ ```css
814
+ @theme inline {
815
+ --radius-icon: var(--era-rd-icon);
816
+ --radius-pill: var(--era-rd-pill);
817
+ --radius-chip: var(--era-rd-chip);
818
+ --radius-control: var(--era-rd-control);
819
+ --radius-bar: var(--era-rd-bar);
820
+ --radius-menu-item: var(--era-item-rd);
594
821
  }
595
- @utility py-inset-chip {
596
- padding-block: var(--era-inset-chip);
822
+ ```
823
+
824
+ ## shadow
825
+
826
+ Surface chrome — bare `shadow` is the resting control edge, shadow-lg the
827
+ floating panel, shadow-well the recessed container, shadow-pressed the
828
+ active/latched face, shadow-highlight the material half of hover feedback.
829
+ Flat renders them as none, bevel as chisels, glass as frosted rims — the
830
+ class stays the same.
831
+
832
+ Declared in `index.css`.
833
+
834
+ ```css
835
+ @theme inline {
836
+ --shadow: var(--era-shadow);
597
837
  }
598
- @utility py-inset-control {
599
- padding-block: var(--era-inset-control);
838
+ ```
839
+
840
+ ## shadow-sm · shadow-lg · shadow-well · shadow-pressed · shadow-highlight
841
+
842
+ v4 marks bare `shadow` a deprecated spelling of shadow-sm, and lints
843
+ auto-fix one to the other — alias both to the control edge so either
844
+ spelling renders era chrome.
845
+
846
+ Declared in `index.css`.
847
+
848
+ ```css
849
+ @theme inline {
850
+ --shadow-sm: var(--era-shadow);
851
+ --shadow-lg: var(--era-shadow-lg);
852
+ --shadow-well: var(--era-shadow-well);
853
+ --shadow-pressed: var(--era-shadow-pressed);
854
+ --shadow-highlight: var(--era-highlight-shadow);
600
855
  }
601
856
  ```
602
857
 
603
- ## px-pill · px-chip
858
+ ## bg-well · text-well · border-well · bg-elevated · text-elevated · border-elevated · bg-highlight · text-highlight · … (12 in all)
604
859
 
605
- **Use it for:** pill side padding — the wider-than-vertical horizontal breathing room badge/chip text wants (glyph-advance derived, ~2× the vertical inset).
860
+ Surface fills — bg-well is the surface's own resting fill (pairs with
861
+ shadow-well for recessed chrome), bg-elevated the raised tier (pairs with
862
+ shadow-lg + glass-blur for floating chrome), bg-highlight the transient
863
+ hover/focus/keyboard wash (pairs with shadow-highlight; latched states
864
+ stay on opaque bg-hover), bg-overlay the modal scrim.
606
865
 
607
866
  Declared in `index.css`.
608
867
 
609
868
  ```css
610
- @utility px-pill {
611
- padding-inline: var(--era-pill-px);
869
+ @theme inline {
870
+ --color-well: var(--era-surface-bg);
871
+ --color-elevated: var(--era-surface-bg-elevated);
872
+ --color-highlight: var(--era-highlight);
873
+ --color-overlay: var(--era-overlay-bg);
612
874
  }
613
- @utility px-chip {
614
- padding-inline: var(--era-chip-px);
875
+ ```
876
+
877
+ ## p-gutter · px-gutter · py-gutter · gap-gutter · p-panel · px-panel · py-panel · gap-panel · … (24 in all)
878
+
879
+ THE SPACING SCALE — one entry per token, from which Tailwind derives the
880
+ WHOLE directional family: p/px/py/pt/pr/pb/pl/ps/pe, every margin, gap and
881
+ gap-x/y, inset/top/right/bottom/left, translate, and the sizing prefixes.
882
+
883
+ These were hand-written `@utility` blocks, which could only ever cover the
884
+ spellings someone remembered to write: `px-gutter` existed and `mt-gutter`
885
+ did not, `p-inset-control` existed and `pl-inset-control` did not, so the
886
+ library fell back to `mt-(--era-gap)` in exactly the places the named API
887
+ was supposed to cover. One line here replaces twenty blocks and leaves no
888
+ spelling missing.
889
+
890
+ ONLY genuine spacing belongs here. The namespace is shared across
891
+ h/w/p/m/gap, so a name registered here means the same length in ALL of
892
+ them — true of a gap or an inset, false of a TIER HEIGHT. Tiers stay
893
+ hand-written per prefix below, and the two vocabularies deliberately share
894
+ no word: icon/pill/chip/control/bar are heights; gutter, card, panel,
895
+ content, menu, field and the inset-* names are spacing. Registering a tier
896
+ name here would silently make `px-control` mean 24px of side padding.
897
+
898
+ Declared in `index.css`.
899
+
900
+ ```css
901
+ @theme inline {
902
+ --spacing-gutter: var(--era-gap);
903
+ --spacing-panel: var(--era-pad-panel);
904
+ --spacing-card: var(--era-pad-card);
905
+ --spacing-content: var(--era-pad-content);
906
+ --spacing-menu: var(--era-panel-inset);
907
+ --spacing-field: var(--era-field-px);
615
908
  }
616
909
  ```
617
910
 
618
- ## px-field
911
+ ## 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)
619
912
 
620
- **Use it for:** text-field side padding — where typed text starts in a control-tier input; the named form of px-(--era-field-px).
913
+ **Use it for:** 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.
621
914
 
622
915
  Declared in `index.css`.
623
916
 
624
917
  ```css
625
- @utility px-field {
626
- padding-inline: var(--era-field-px);
918
+ @theme inline {
919
+ --spacing-inset-pill: var(--era-inset-pill);
920
+ --spacing-inset-chip: var(--era-inset-chip);
921
+ --spacing-inset-control: var(--era-inset-control);
627
922
  }
628
923
  ```
629
924
 
630
- ## p-panel · p-card
925
+ ## 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 · … (32 in all)
631
926
 
632
- **Use it for:** optical padding for unbounded containers — p-panel for compact shells and menu-adjacent chrome, p-card for cards/dialogs/popovers, p-content for full content panels. Grows super-linearly with density so whitespace holds its perceived share as controls loosen.
927
+ **Use it for:** 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.
633
928
 
634
929
  Declared in `index.css`.
635
930
 
636
931
  ```css
637
- @utility p-panel {
638
- padding: var(--era-pad-panel);
932
+ @theme inline {
933
+ --spacing-icon-inset-pill: var(--era-icon-inset-pill);
934
+ --spacing-icon-inset-chip: var(--era-icon-inset-chip);
935
+ --spacing-icon-inset-control: var(--era-icon-inset-control);
936
+ --spacing-icon-inset-bar: var(--era-icon-inset-bar);
937
+ --spacing-pill-inset-chip: var(--era-pill-inset-chip);
938
+ --spacing-pill-inset-control: var(--era-pill-inset-control);
939
+ --spacing-chip-inset-control: var(--era-chip-inset-control);
940
+ --spacing-chip-inset-bar: var(--era-chip-inset-bar);
639
941
  }
640
- @utility p-card {
641
- padding: var(--era-pad-card);
942
+ ```
943
+
944
+ ## p-glyph-icon · px-glyph-icon · py-glyph-icon · gap-glyph-icon · p-glyph-pill · px-glyph-pill · py-glyph-pill · gap-glyph-pill
945
+
946
+ **Use it for:** 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).
947
+
948
+ Declared in `index.css`.
949
+
950
+ ```css
951
+ @theme inline {
952
+ --spacing-glyph-icon: var(--era-glyph-icon);
953
+ --spacing-glyph-pill: var(--era-glyph-pill);
642
954
  }
643
955
  ```
644
956
 
645
- ## p-content
957
+ ## bg-field · text-field · border-field · bg-field-highlight · text-field-highlight · border-field-highlight
646
958
 
647
- A content panel always follows a section header ROW, and that row already
648
- contributes its own slack: the heading's text sits in an h-bar bar, so there
649
- is (h-bar − text)/2 of empty bar under its glyphs before the panel even
650
- starts. Padding the panel evenly on top of that spends the space twice — the
651
- header ends up floating between the section above and the paragraph it
652
- introduces rather than binding to it.
959
+ **Use it for:** the recessed field fill — bg-field is a text input's resting well, bg-field-highlight its focused/hovered face.
653
960
 
654
- So the block-start pays only the REMAINDER. The target is the indent: the
655
- space under a heading should measure the same as the space beside the text,
656
- which is --era-content-p. The header row already supplies (h-bar − text)/2 of
657
- it, so the panel adds what's left, and heading-to-paragraph reads equal to
658
- the paragraph's own inset. Subtracting one --era-gap (the previous rule) left
659
- the header's slack unaccounted for and the heading still detached.
961
+ Declared in `index.css`.
660
962
 
661
- Both terms are density-derived, so the equality holds at every mode; the
662
- max() is the floor for a hypothetical mode where the row's slack would
663
- exceed the inset outright.
963
+ ```css
964
+ @theme inline {
965
+ --color-field: var(--era-field-bg);
966
+ --color-field-highlight: var(--era-field-highlight);
967
+ }
968
+ ```
969
+
970
+ ## ease-base
971
+
972
+ Motion — bare transition utilities default to the motion axis, so
973
+ `transition-colors` alone is on-design (0s at instant, longer at extra).
974
+ ease-base/duration-base name the axis explicitly for overrides.
664
975
 
665
976
  Declared in `index.css`.
666
977
 
667
978
  ```css
668
- @utility p-content {
669
- padding: var(--era-content-p);
670
- padding-top: max(0px, calc(var(--era-content-p) - (var(--era-h-bar) - var(--era-text)) / 2));
979
+ @theme inline {
980
+ --default-transition-duration: var(--era-duration);
981
+ --default-transition-timing-function: var(--era-ease);
982
+ --ease-base: var(--era-ease);
671
983
  }
672
984
  ```
673
985
 
674
- ## p-menu
986
+ ## bg-divider · text-divider · border-divider · bg-divider-faded · text-divider-faded · border-divider-faded · bg-background · text-background · … (66 in all)
675
987
 
676
- **Use it for:** menu-panel padding — the surface-owned inset (0 on flat, 2px on glass/bevel) that keeps row highlights inside a floating panel's frame; pairs with rounded-menu-item on the rows.
988
+ Surface divider colors: border-divider, bg-divider-faded, …
677
989
 
678
990
  Declared in `index.css`.
679
991
 
680
992
  ```css
681
- @utility p-menu {
682
- padding: var(--era-panel-inset);
993
+ @theme inline {
994
+ --color-divider: var(--era-divider-color);
995
+ --color-divider-faded: var(--era-divider-faded);
996
+ --color-background: var(--color-1);
997
+ --color-foreground: var(--color-fg);
998
+ --color-1: var(--color-1);
999
+ --color-2: var(--color-2);
1000
+ --color-3: var(--color-3);
1001
+ --color-4: var(--color-4);
1002
+ --color-5: var(--color-5);
1003
+ --color-6: var(--color-6);
1004
+ --color-7: var(--color-7);
1005
+ --color-8: var(--color-8);
1006
+ --color-9: var(--color-9);
1007
+ --color-10: var(--color-10);
1008
+ --color-11: var(--color-11);
1009
+ --color-12: var(--color-12);
1010
+ --color-border: var(--color-border);
1011
+ --color-surface: var(--color-surface);
1012
+ --color-hover: var(--color-hover);
1013
+ --color-fg: var(--color-fg);
1014
+ --color-bright: var(--color-bright);
1015
+ --color-muted: var(--color-muted);
683
1016
  }
684
1017
  ```
685
1018
 
686
- ## duration-base
1019
+ ## bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (33 in all)
687
1020
 
688
- **Use it for:** the motion axis as an explicit transition-duration — for the rare case a utility (not the transition-* default) needs to name it; 0s at data-motion="instant", longer at "extra".
1021
+ The standing pill fill — --era-fill, the latched counterpart of the
1022
+ transient highlight. Surface-owned: a composing wash on flat/bevel, the
1023
+ opaque swatch on glass.
689
1024
 
690
1025
  Declared in `index.css`.
691
1026
 
692
1027
  ```css
693
- @utility duration-base {
694
- transition-duration: var(--era-duration);
1028
+ @theme inline {
1029
+ --color-fill: var(--era-fill);
1030
+ --color-link: var(--color-link);
1031
+ --color-primary: var(--color-primary);
1032
+ --color-primary-fg: var(--color-primary-fg);
1033
+ --color-primary-hover: var(--color-primary-hover);
1034
+ --color-destructive: var(--color-destructive);
1035
+ --color-destructive-fg: var(--color-destructive-fg);
1036
+ --color-success: var(--color-success);
1037
+ --color-success-fg: var(--color-success-fg);
1038
+ --color-warning: var(--color-warning);
1039
+ --color-warning-fg: var(--color-warning-fg);
695
1040
  }
696
1041
  ```
697
1042
 
@@ -755,13 +1100,13 @@ A complete notes app — rich-text editor, slash commands, local persistence.
755
1100
 
756
1101
  ## Usage
757
1102
 
758
- Apps ship on their own subpath and are **not** re-exported from `@sig-nine/era-ui`.
1103
+ Apps ship on their own subpath and are **not** re-exported from `@signal9/era-ui`.
759
1104
  Notes carries TipTap, and a consumer who never imports an app should never pay
760
1105
  for it.
761
1106
 
762
1107
  ```svelte
763
1108
  <script>
764
- import { Notes } from '@sig-nine/era-ui/apps';
1109
+ import { Notes } from '@signal9/era-ui/apps';
765
1110
  </script>
766
1111
 
767
1112
  <Notes />
@@ -801,7 +1146,7 @@ Persistence is one small interface, so server-backed hosting is a drop-in swap
801
1146
  `load`/`save` may be sync or async:
802
1147
 
803
1148
  ```ts
804
- import { Notes, NotesStore } from '@sig-nine/era-ui/apps';
1149
+ import { Notes, NotesStore } from '@signal9/era-ui/apps';
805
1150
 
806
1151
  const store = new NotesStore({
807
1152
  adapter: {