@signal9/era-ui 32.0.0 → 33.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 (145) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/dev/audit-overlay.svelte +2 -2
  3. package/dist/era-ui.css +1 -1
  4. package/dist/generated-docs/utilities.json +99 -99
  5. package/dist/os/pane.svelte +3 -13
  6. package/dist/styles/index.css +2 -956
  7. package/dist/styles/typography.css +1 -1
  8. package/dist/styles/utilities/geometry.css +188 -0
  9. package/dist/styles/utilities/interaction.css +334 -0
  10. package/dist/styles/utilities/materials.css +39 -0
  11. package/dist/styles/utilities/public.css +391 -0
  12. package/dist/styles/utilities.css +5 -0
  13. package/dist/ui/card/card.svelte +2 -52
  14. package/dist/ui/card/card.svelte.d.ts +0 -43
  15. package/dist/ui/card/variants.d.ts +44 -0
  16. package/dist/ui/card/variants.js +20 -0
  17. package/dist/ui/context-menu/context-menu-checkbox-item.svelte +2 -4
  18. package/dist/ui/context-menu/context-menu-group-heading.svelte +2 -5
  19. package/dist/ui/context-menu/context-menu-item.svelte +2 -8
  20. package/dist/ui/context-menu/context-menu-radio-item.svelte +2 -8
  21. package/dist/ui/context-menu/context-menu-separator.svelte +2 -5
  22. package/dist/ui/context-menu/context-menu-sub-trigger.svelte +2 -8
  23. package/dist/ui/dialog/dialog-header.svelte +1 -1
  24. package/dist/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +2 -4
  25. package/dist/ui/dropdown-menu/dropdown-menu-group-heading.svelte +2 -5
  26. package/dist/ui/dropdown-menu/dropdown-menu-item.svelte +2 -8
  27. package/dist/ui/dropdown-menu/dropdown-menu-radio-item.svelte +2 -8
  28. package/dist/ui/dropdown-menu/dropdown-menu-separator.svelte +2 -5
  29. package/dist/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +2 -8
  30. package/dist/ui/menu-recipes.d.ts +6 -0
  31. package/dist/ui/menu-recipes.js +6 -0
  32. package/dist/ui/menubar/menubar-checkbox-item.svelte +2 -9
  33. package/dist/ui/menubar/menubar-group-heading.svelte +2 -5
  34. package/dist/ui/menubar/menubar-item.svelte +2 -8
  35. package/dist/ui/menubar/menubar-radio-item.svelte +2 -8
  36. package/dist/ui/menubar/menubar-separator.svelte +2 -5
  37. package/dist/ui/menubar/menubar-sub-trigger.svelte +2 -8
  38. package/dist/ui/pane/pane-close.svelte +7 -26
  39. package/dist/ui/video-player/video-player.svelte +8 -8
  40. package/package.json +48 -12
  41. package/dist/docs/badge.md +0 -18
  42. package/dist/docs/bits-ui-audit.md +0 -58
  43. package/dist/docs/button.md +0 -19
  44. package/dist/docs/chip.md +0 -20
  45. package/dist/docs/component-docs-core.d.ts +0 -8
  46. package/dist/docs/component-docs-core.js +0 -73
  47. package/dist/docs/component-docs.d.ts +0 -2
  48. package/dist/docs/component-docs.js +0 -25
  49. package/dist/docs/component-source-scanners.d.ts +0 -18
  50. package/dist/docs/component-source-scanners.js +0 -46
  51. package/dist/docs/consumer-import.d.ts +0 -65
  52. package/dist/docs/consumer-import.js +0 -70
  53. package/dist/docs/css-utilities.d.ts +0 -58
  54. package/dist/docs/css-utilities.js +0 -317
  55. package/dist/docs/extract-props.d.ts +0 -13
  56. package/dist/docs/extract-props.js +0 -324
  57. package/dist/docs/generated-docs.d.ts +0 -6
  58. package/dist/docs/generated-docs.js +0 -30
  59. package/dist/docs/index.d.ts +0 -5
  60. package/dist/docs/index.js +0 -66
  61. package/dist/docs/notes.md +0 -83
  62. package/dist/docs/scroll-area.md +0 -7
  63. package/dist/docs/separator.md +0 -20
  64. package/dist/docs/table.md +0 -35
  65. package/dist/docs/utilities.d.ts +0 -4
  66. package/dist/docs/utilities.js +0 -15
  67. package/dist/generated-docs/accordion.md +0 -57
  68. package/dist/generated-docs/alert-dialog.md +0 -91
  69. package/dist/generated-docs/aspect-ratio.md +0 -17
  70. package/dist/generated-docs/avatar.md +0 -39
  71. package/dist/generated-docs/badge.md +0 -41
  72. package/dist/generated-docs/bar.md +0 -41
  73. package/dist/generated-docs/button-group.md +0 -19
  74. package/dist/generated-docs/button.md +0 -117
  75. package/dist/generated-docs/calendar.md +0 -126
  76. package/dist/generated-docs/card.md +0 -58
  77. package/dist/generated-docs/checkbox.md +0 -42
  78. package/dist/generated-docs/chip.md +0 -61
  79. package/dist/generated-docs/code-block.md +0 -20
  80. package/dist/generated-docs/collapsible.md +0 -30
  81. package/dist/generated-docs/combobox.md +0 -74
  82. package/dist/generated-docs/command-bar.md +0 -3
  83. package/dist/generated-docs/command.md +0 -126
  84. package/dist/generated-docs/context-menu.md +0 -104
  85. package/dist/generated-docs/copy-button.md +0 -29
  86. package/dist/generated-docs/cycle.md +0 -29
  87. package/dist/generated-docs/date-field.md +0 -49
  88. package/dist/generated-docs/date-picker.md +0 -180
  89. package/dist/generated-docs/date-range-field.md +0 -50
  90. package/dist/generated-docs/date-range-picker.md +0 -180
  91. package/dist/generated-docs/dialog.md +0 -94
  92. package/dist/generated-docs/draggable.md +0 -3
  93. package/dist/generated-docs/dropdown-menu.md +0 -104
  94. package/dist/generated-docs/file-upload.md +0 -18
  95. package/dist/generated-docs/getting-started.md +0 -3
  96. package/dist/generated-docs/input.md +0 -23
  97. package/dist/generated-docs/kv.md +0 -20
  98. package/dist/generated-docs/label.md +0 -17
  99. package/dist/generated-docs/link-preview.md +0 -40
  100. package/dist/generated-docs/llm-shell.md +0 -3
  101. package/dist/generated-docs/llms-full.txt +0 -5201
  102. package/dist/generated-docs/llms.txt +0 -138
  103. package/dist/generated-docs/logo.md +0 -24
  104. package/dist/generated-docs/manifest.json +0 -1685
  105. package/dist/generated-docs/measurements.md +0 -3
  106. package/dist/generated-docs/menu.md +0 -11
  107. package/dist/generated-docs/menubar.md +0 -104
  108. package/dist/generated-docs/meter.md +0 -101
  109. package/dist/generated-docs/mode.md +0 -24
  110. package/dist/generated-docs/nav.md +0 -73
  111. package/dist/generated-docs/navigation-menu.md +0 -11
  112. package/dist/generated-docs/notes.md +0 -87
  113. package/dist/generated-docs/os.md +0 -3
  114. package/dist/generated-docs/pagination.md +0 -55
  115. package/dist/generated-docs/pane.md +0 -34
  116. package/dist/generated-docs/pin-input.md +0 -31
  117. package/dist/generated-docs/popover.md +0 -43
  118. package/dist/generated-docs/progress.md +0 -17
  119. package/dist/generated-docs/radio-group.md +0 -31
  120. package/dist/generated-docs/range-calendar.md +0 -11
  121. package/dist/generated-docs/rating-group.md +0 -31
  122. package/dist/generated-docs/scroll-area.md +0 -65
  123. package/dist/generated-docs/select.md +0 -67
  124. package/dist/generated-docs/separator.md +0 -57
  125. package/dist/generated-docs/sheet.md +0 -11
  126. package/dist/generated-docs/skeleton.md +0 -18
  127. package/dist/generated-docs/slider.md +0 -71
  128. package/dist/generated-docs/spacing.md +0 -3
  129. package/dist/generated-docs/step.md +0 -51
  130. package/dist/generated-docs/surfaces.md +0 -3
  131. package/dist/generated-docs/switch.md +0 -18
  132. package/dist/generated-docs/table.md +0 -113
  133. package/dist/generated-docs/tabs.md +0 -48
  134. package/dist/generated-docs/text.md +0 -3
  135. package/dist/generated-docs/time-field.md +0 -49
  136. package/dist/generated-docs/time-range-field.md +0 -50
  137. package/dist/generated-docs/timeline.md +0 -32
  138. package/dist/generated-docs/todo.md +0 -3
  139. package/dist/generated-docs/toggle-group.md +0 -31
  140. package/dist/generated-docs/toggle.md +0 -20
  141. package/dist/generated-docs/toolbar.md +0 -11
  142. package/dist/generated-docs/tooltip.md +0 -40
  143. package/dist/generated-docs/tree.md +0 -36
  144. package/dist/generated-docs/utilities.md +0 -1236
  145. package/dist/generated-docs/video-player.md +0 -73
@@ -0,0 +1,391 @@
1
+ /* ------------------------------------------------------------------ */
2
+ /* THE PUBLIC CLASS API */
3
+ /* */
4
+ /* Era's consumer-facing styling surface is NAMED utilities — a user */
5
+ /* of the library writes `tier-control px-gutter shadow`, never */
6
+ /* `h-(--era-h-control)`-style var classes. Where Tailwind already has a */
7
+ /* name for the concept (rounded-control, shadow, ease) era OVERLOADS it */
8
+ /* so stock-looking markup renders on-design; where it doesn't, era */
9
+ /* registers its own (h-control, px-gutter, gap-gutter, p-card). */
10
+ /* */
11
+ /* The --era-* custom properties remain the internal contract (and */
12
+ /* the escape hatch for anything without a name — e.g. min-w-* tier */
13
+ /* names are NOT registered because Tailwind's container scale */
14
+ /* already owns min-w-md/lg; use min-w-(--era-h-control) there). */
15
+ /* */
16
+ /* Everything here is a thin name over a token, so the full axis */
17
+ /* system — density, surface, corners, motion — flows through */
18
+ /* untouched. @theme inline is load-bearing: it inlines the var() */
19
+ /* reference instead of snapshotting a value, so each USE re-resolves */
20
+ /* against the element's own inherited axes. */
21
+ /* ------------------------------------------------------------------ */
22
+ @theme inline {
23
+ /* THE TYPE LADDER — the one axis that was not on the density system.
24
+ *
25
+ * era had exactly one size, `text-body`, so a heading had nowhere to go and
26
+ * consumers reached for Tailwind's fixed `text-2xl` or a bare <h1>. Both are
27
+ * rem-fixed while `--era-text` re-tiers, so heading prominence DEGRADED as
28
+ * density increased: measured in a consumer app, an <h1> against body text
29
+ * was 1.33x at dense and 1.14x at touch. The page title gets quieter the
30
+ * tighter you set the page, which is backwards, and it is the only place in
31
+ * era where a size relationship does not hold across the axis.
32
+ *
33
+ * Named by ROLE, like the tier ladder and for the same reason: size names
34
+ * invert (this library already shipped an `xxs` bigger than its `xs`), and a
35
+ * role tells you where the rung belongs. Ratios are simple fractions of the
36
+ * atom rather than a geometric scale — again like the tier ladder, whose
37
+ * rungs are sp+6, 2sp+6, 3sp, 4sp rather than a constant multiplier. They
38
+ * land on whole pixels at dense and hold their ratio at every mode.
39
+ *
40
+ * micro 5/6 10 / 11.7 / 11.7 / 11.7 an eyebrow, a legend, a tag
41
+ * body 1 12 / 14 / 14 / 14 control and UI text
42
+ * lede 5/4 15 / 17.5 the paragraph under a title
43
+ * heading 3/2 18 / 21 a section heading
44
+ * title 2 24 / 28 a page or card title
45
+ * display 3 36 / 42 a hero
46
+ *
47
+ * `micro` is not invented: the library hand-writes text-[0.625rem] ten times
48
+ * for exactly this role, and 5/6 of dense's 12px is that value.
49
+ *
50
+ * Leading and tracking ride with the size, so a rung is one class. Both
51
+ * tighten as the rung grows, which is ordinary optical setting and matters
52
+ * more here than usual — era's default stack is monospace, whose display
53
+ * sizes read loose without it.
54
+ *
55
+ * @use the type ladder — micro (eyebrow/legend) < body (controls) < lede
56
+ * (the paragraph under a title) < heading < title < display. Derived from
57
+ * --era-text, so the ratio between any two rungs holds at every density;
58
+ * leading and tracking ride with the size, so a rung is one class.
59
+ *
60
+ * body and micro deliberately carry NO line-height: `text-body` is worn by
61
+ * every control in the library, where leading is owned by era-text-trim and
62
+ * leading-none. Giving it a default would re-space every control in era.
63
+ * Use `leading-body` for running text, as before. */
64
+ --text-micro: calc(var(--era-text) * 5 / 6);
65
+ --text-micro--letter-spacing: 0.04em;
66
+ --text-lede: calc(var(--era-text) * 5 / 4);
67
+ --text-lede--line-height: 1.5;
68
+ --text-heading: calc(var(--era-text) * 3 / 2);
69
+ --text-heading--line-height: 1.3;
70
+ --text-heading--letter-spacing: -0.01em;
71
+ --text-title: calc(var(--era-text) * 2);
72
+ --text-title--line-height: 1.15;
73
+ --text-title--letter-spacing: -0.02em;
74
+ --text-display: calc(var(--era-text) * 3);
75
+ --text-display--line-height: 1.05;
76
+ --text-display--letter-spacing: -0.03em;
77
+ /* Density-derived body size: `text-body` replaces text-[length:var(--era-text)] */
78
+ --text-body: var(--era-text);
79
+ /* Prose leading — `leading-body` is the pair to `text-body`, and every piece
80
+ * of text in the library that can wrap to a second line carries it. Enforced
81
+ * at runtime by typography/prose-leading. */
82
+ --leading-body: var(--era-leading);
83
+ /* Radius ladder — Tailwind's own rounded-* names now walk era's concentric
84
+ * ladder (rd-T = rd-xs + (h-T − h-icon)/2), ride the corners toggle, and
85
+ * collapse to 0 on square. rounded-menu-item is the menu-row radius
86
+ * (rd-md − panel-inset) that keeps rows concentric inside a rounded-control
87
+ * panel on every surface. */
88
+ --radius-icon: var(--era-rd-icon);
89
+ --radius-pill: var(--era-rd-pill);
90
+ --radius-chip: var(--era-rd-chip);
91
+ --radius-control: var(--era-rd-control);
92
+ --radius-bar: var(--era-rd-bar);
93
+ --radius-menu-item: var(--era-item-rd);
94
+ /* Surface chrome — bare `shadow` is the resting control edge, shadow-lg the
95
+ * floating panel, shadow-well the recessed container, shadow-pressed the
96
+ * active/latched face, shadow-highlight the material half of hover feedback.
97
+ * Flat renders them as none, bevel as chisels, glass as frosted rims — the
98
+ * class stays the same. */
99
+ --shadow: var(--era-shadow);
100
+ /* v4 marks bare `shadow` a deprecated spelling of shadow-sm, and lints
101
+ * auto-fix one to the other — alias both to the control edge so either
102
+ * spelling renders era chrome. */
103
+ --shadow-sm: var(--era-shadow);
104
+ --shadow-lg: var(--era-shadow-lg);
105
+ --shadow-well: var(--era-shadow-well);
106
+ --shadow-pressed: var(--era-shadow-pressed);
107
+ --shadow-highlight: var(--era-highlight-shadow);
108
+ /* Surface fills — bg-well is the surface's own resting fill (pairs with
109
+ * shadow-well for recessed chrome), bg-elevated the raised tier,
110
+ * bg-highlight the transient
111
+ * hover/focus/keyboard wash (pairs with shadow-highlight; latched states
112
+ * stay on opaque bg-hover), bg-overlay the modal scrim. */
113
+ --color-well: var(--era-surface-bg);
114
+ --color-elevated: var(--era-surface-bg-elevated);
115
+ --color-highlight: var(--era-highlight);
116
+ --color-overlay: var(--era-overlay-bg);
117
+ /* THE SPACING SCALE — one entry per token, from which Tailwind derives the
118
+ * WHOLE directional family: p/px/py/pt/pr/pb/pl/ps/pe, every margin, gap and
119
+ * gap-x/y, inset/top/right/bottom/left, translate, and the sizing prefixes.
120
+ *
121
+ * These were hand-written `@utility` blocks, which could only ever cover the
122
+ * spellings someone remembered to write: `px-gutter` existed and `mt-gutter`
123
+ * did not, `p-inset-control` existed and `pl-inset-control` did not, so the
124
+ * library fell back to `mt-(--era-gap)` in exactly the places the named API
125
+ * was supposed to cover. One line here replaces twenty blocks and leaves no
126
+ * spelling missing.
127
+ *
128
+ * ONLY genuine spacing belongs here. The namespace is shared across
129
+ * h/w/p/m/gap, so a name registered here means the same length in ALL of
130
+ * them — true of a gap or an inset, false of a TIER HEIGHT. Tiers stay
131
+ * hand-written per prefix below, and the two vocabularies deliberately share
132
+ * no word: icon/pill/chip/control/bar are heights; gutter, card, panel,
133
+ * content, menu, field and the inset-* names are spacing. Registering a tier
134
+ * name here would silently make `px-control` mean 24px of side padding. */
135
+ --spacing-gutter: var(--era-gap);
136
+ --spacing-panel: var(--era-pad-panel);
137
+ --spacing-card: var(--era-pad-card);
138
+ --spacing-content: var(--era-pad-content);
139
+ --spacing-menu: var(--era-panel-inset);
140
+ --spacing-field: var(--era-field-px);
141
+ /* @use text-symmetric content padding — (tier − text)/2, the inset that
142
+ * vertically centres body text in its tier; px-inset-control is a text
143
+ * button's side padding, p-inset-control a code block's. */
144
+ --spacing-inset-pill: var(--era-inset-pill);
145
+ --spacing-inset-chip: var(--era-inset-chip);
146
+ --spacing-inset-control: var(--era-inset-control);
147
+ /* @use the concentric inset for a nested pair — (h-container − h-child)/2,
148
+ * the gap that makes a child control sit evenly inside its container, and
149
+ * the radius step that keeps their corners concentric. Named for the pair it
150
+ * joins: gap-icon-inset-control seats an icon in a control. */
151
+ --spacing-icon-inset-pill: var(--era-icon-inset-pill);
152
+ --spacing-icon-inset-chip: var(--era-icon-inset-chip);
153
+ --spacing-icon-inset-control: var(--era-icon-inset-control);
154
+ --spacing-icon-inset-bar: var(--era-icon-inset-bar);
155
+ --spacing-pill-inset-chip: var(--era-pill-inset-chip);
156
+ --spacing-pill-inset-control: var(--era-pill-inset-control);
157
+ --spacing-pill-inset-bar: var(--era-pill-inset-bar);
158
+ --spacing-chip-inset-control: var(--era-chip-inset-control);
159
+ --spacing-chip-inset-bar: var(--era-chip-inset-bar);
160
+ --spacing-control-inset-bar: var(--era-control-inset-bar);
161
+ /* @use the glyph size for a tier — the INK inside the box, not the box
162
+ * (size-glyph-pill is the dismiss × in a pill, size-pill is the pill). */
163
+ --spacing-glyph-icon: var(--era-glyph-icon);
164
+ --spacing-glyph-pill: var(--era-glyph-pill);
165
+ /* @use the recessed field fill — bg-field is a text input's resting well,
166
+ * bg-field-highlight its focused/hovered face. */
167
+ --color-field: var(--era-field-bg);
168
+ --color-field-highlight: var(--era-field-highlight);
169
+ /* @use the stacking tier for chrome that renders at the document root —
170
+ * z-chrome (taskbar) < z-drawer (slide-over) < z-overlay (every dialog,
171
+ * menu, popover and scrim) < z-toast < z-debug. A component ordering its
172
+ * OWN parts inside an isolated context keeps small integers instead; see
173
+ * styles/layers.css for why the two are different things. */
174
+ --z-index-chrome: var(--era-z-chrome);
175
+ --z-index-drawer: var(--era-z-drawer);
176
+ --z-index-overlay: var(--era-z-overlay);
177
+ --z-index-toast: var(--era-z-toast);
178
+ --z-index-debug: var(--era-z-debug);
179
+ /* Motion — bare transition utilities default to the motion axis, so
180
+ * `transition-colors` alone is on-design (0s at instant, longer at extra).
181
+ * ease-base/duration-base name the axis explicitly for overrides. */
182
+ --default-transition-duration: var(--era-duration);
183
+ --default-transition-timing-function: var(--era-ease);
184
+ --ease-base: var(--era-ease);
185
+ /* Surface divider colors: border-divider, bg-divider-faded, … */
186
+ --color-divider: var(--era-divider-color);
187
+ --color-divider-faded: var(--era-divider-faded);
188
+ --color-background: var(--color-1);
189
+ --color-foreground: var(--color-fg);
190
+ --color-1: var(--color-1);
191
+ --color-2: var(--color-2);
192
+ --color-3: var(--color-3);
193
+ --color-4: var(--color-4);
194
+ --color-5: var(--color-5);
195
+ --color-6: var(--color-6);
196
+ --color-7: var(--color-7);
197
+ --color-8: var(--color-8);
198
+ --color-9: var(--color-9);
199
+ --color-10: var(--color-10);
200
+ --color-11: var(--color-11);
201
+ --color-12: var(--color-12);
202
+ --color-border: var(--color-border);
203
+ --color-surface: var(--color-surface);
204
+ --color-hover: var(--color-hover);
205
+ --color-fg: var(--color-fg);
206
+ --color-bright: var(--color-bright);
207
+ --color-muted: var(--color-muted);
208
+ /* The standing pill fill — --era-fill, the latched counterpart of the
209
+ * transient highlight. Surface-owned: a composing wash on flat/bevel, the
210
+ * opaque swatch on glass. */
211
+ --color-fill: var(--era-fill);
212
+ --color-link: var(--color-link);
213
+ --color-primary: var(--color-primary);
214
+ --color-primary-fg: var(--color-primary-fg);
215
+ --color-primary-hover: var(--color-primary-hover);
216
+ --color-destructive: var(--color-destructive);
217
+ --color-destructive-fg: var(--color-destructive-fg);
218
+ --color-success: var(--color-success);
219
+ --color-success-fg: var(--color-success-fg);
220
+ --color-warning: var(--color-warning);
221
+ --color-warning-fg: var(--color-warning-fg);
222
+ --color-info: var(--color-info);
223
+ --color-info-fg: var(--color-info-fg);
224
+ }
225
+
226
+ /* ------------------------------------------------------------------ */
227
+ /* Named tier + spacing utilities */
228
+ /* */
229
+ /* What is left here is what the SPACING SCALE above cannot express: */
230
+ /* a tier is a HEIGHT, and the spacing namespace is shared across */
231
+ /* h/w/p/m/gap, so registering `control` there would silently make */
232
+ /* px-control mean 24px of side padding. Tier names therefore get one */
233
+ /* hand-written block per prefix that needs them, and the two */
234
+ /* vocabularies share no word. Kept terse; the ladder itself is */
235
+ /* documented in density.css and on the /spacing page. */
236
+ /* ------------------------------------------------------------------ */
237
+
238
+ /* @use the tier-height ladder — h-icon (icon) · h-pill (nested pill) · h-chip
239
+ * (standalone pill) · h-control (control) · h-bar (bar); the named form of
240
+ * h-(--era-h-*). */
241
+ @utility h-icon {
242
+ height: var(--era-h-icon);
243
+ }
244
+ @utility h-pill {
245
+ height: var(--era-h-pill);
246
+ }
247
+ @utility h-chip {
248
+ height: var(--era-h-chip);
249
+ }
250
+ @utility h-control {
251
+ height: var(--era-h-control);
252
+ }
253
+ @utility h-bar {
254
+ height: var(--era-h-bar);
255
+ }
256
+
257
+ /* @use minimum tier height for containers that may grow — a bar that is at
258
+ * least lg-tier but can wrap (min-h-bar). */
259
+ @utility min-h-icon {
260
+ min-height: var(--era-h-icon);
261
+ }
262
+ @utility min-h-pill {
263
+ min-height: var(--era-h-pill);
264
+ }
265
+ @utility min-h-chip {
266
+ min-height: var(--era-h-chip);
267
+ }
268
+ @utility min-h-control {
269
+ min-height: var(--era-h-control);
270
+ }
271
+ @utility min-h-bar {
272
+ min-height: var(--era-h-bar);
273
+ }
274
+
275
+ /* @use a tier-sized WIDTH — the horizontal twin of the h-* ladder, for a rail or
276
+ * a column measured in tiers rather than in content. */
277
+ @utility w-icon {
278
+ width: var(--era-h-icon);
279
+ }
280
+ @utility w-pill {
281
+ width: var(--era-h-pill);
282
+ }
283
+ @utility w-chip {
284
+ width: var(--era-h-chip);
285
+ }
286
+ @utility w-control {
287
+ width: var(--era-h-control);
288
+ }
289
+ @utility w-bar {
290
+ width: var(--era-h-bar);
291
+ }
292
+
293
+ /* @use a minimum tier WIDTH — the floor that makes a single-glyph control render
294
+ * as a square rather than a skinny pill (min-w-control on an icon button,
295
+ * min-w-pill on a badge). These could not exist before the ladder was renamed:
296
+ * the old rungs were sm/md/lg, and Tailwind's container scale already owns
297
+ * min-w-md and min-w-lg, so the names collided and every call site had to write
298
+ * min-w-(--era-h-control) by hand. icon/pill/chip/control/bar collide with nothing. */
299
+ @utility min-w-icon {
300
+ min-width: var(--era-h-icon);
301
+ }
302
+ @utility min-w-pill {
303
+ min-width: var(--era-h-pill);
304
+ }
305
+ @utility min-w-chip {
306
+ min-width: var(--era-h-chip);
307
+ }
308
+ @utility min-w-control {
309
+ min-width: var(--era-h-control);
310
+ }
311
+ @utility min-w-bar {
312
+ min-width: var(--era-h-bar);
313
+ }
314
+
315
+ /* @use a tier-sized square — size-icon is THE icon size (a Lucide glyph beside
316
+ * body text), size-control a square control face. */
317
+ @utility size-icon {
318
+ width: var(--era-h-icon);
319
+ height: var(--era-h-icon);
320
+ }
321
+ @utility size-pill {
322
+ width: var(--era-h-pill);
323
+ height: var(--era-h-pill);
324
+ }
325
+ @utility size-chip {
326
+ width: var(--era-h-chip);
327
+ height: var(--era-h-chip);
328
+ }
329
+ @utility size-control {
330
+ width: var(--era-h-control);
331
+ height: var(--era-h-control);
332
+ }
333
+ @utility size-bar {
334
+ width: var(--era-h-bar);
335
+ height: var(--era-h-bar);
336
+ }
337
+
338
+ /* @use pill side padding — the wider-than-vertical horizontal breathing room
339
+ * badge/chip text wants (glyph-advance derived, ~2× the vertical inset). */
340
+ @utility px-pill {
341
+ padding-inline: var(--era-pill-px);
342
+ }
343
+ @utility px-chip {
344
+ padding-inline: var(--era-chip-px);
345
+ }
346
+ @utility pl-pill {
347
+ padding-left: var(--era-pill-px);
348
+ }
349
+ @utility pr-pill {
350
+ padding-right: var(--era-pill-px);
351
+ }
352
+ @utility pl-chip {
353
+ padding-left: var(--era-chip-px);
354
+ }
355
+ @utility pr-chip {
356
+ padding-right: var(--era-chip-px);
357
+ }
358
+
359
+ /* @use padding for a content panel that sits UNDER a section header row — the
360
+ * even-padding exception, and the reason it is not called p-section: it
361
+ * deliberately under-pays the block start. For an evenly padded content panel
362
+ * use p-section, which is the plain token.
363
+ *
364
+ * A content panel always follows a section header ROW, and that row already
365
+ * contributes its own slack: the heading's text sits in an h-bar bar, so there
366
+ * is (h-bar − text)/2 of empty bar under its glyphs before the panel even
367
+ * starts. Padding the panel evenly on top of that spends the space twice — the
368
+ * header ends up floating between the section above and the paragraph it
369
+ * introduces rather than binding to it.
370
+ *
371
+ * So the block-start pays only the REMAINDER. The target is the indent: the
372
+ * space under a heading should measure the same as the space beside the text,
373
+ * which is --era-pad-content. The header row already supplies (h-bar − text)/2 of
374
+ * it, so the panel adds what's left, and heading-to-paragraph reads equal to
375
+ * the paragraph's own inset. Subtracting one --era-gap (the previous rule) left
376
+ * the header's slack unaccounted for and the heading still detached.
377
+ *
378
+ * Both terms are density-derived, so the equality holds at every mode; the
379
+ * max() is the floor for a hypothetical mode where the row's slack would
380
+ * exceed the inset outright. */
381
+ @utility p-section {
382
+ padding: var(--era-pad-content);
383
+ padding-top: max(0px, calc(var(--era-pad-content) - (var(--era-h-bar) - var(--era-text)) / 2));
384
+ }
385
+
386
+ /* @use the motion axis as an explicit transition-duration — for the rare case
387
+ * a utility (not the transition-* default) needs to name it; 0s at
388
+ * data-motion="instant", longer at "extra". */
389
+ @utility duration-base {
390
+ transition-duration: var(--era-duration);
391
+ }
@@ -0,0 +1,5 @@
1
+ /* Internal utility modules. Consumers continue to import the stable styles entrypoint. */
2
+ @import './utilities/interaction.css';
3
+ @import './utilities/materials.css';
4
+ @import './utilities/geometry.css';
5
+ @import './utilities/public.css';
@@ -1,58 +1,8 @@
1
- <script lang="ts" module>
2
- import { cn, tv } from '../../utils/index.js';
3
-
4
- export const cardVariants = tv({
5
- base: 'block w-full rounded-bar text-left text-fg',
6
- variants: {
7
- tone: {
8
- elevated: 'bg-elevated shadow-sm',
9
- surface: 'bg-well',
10
- // The recessed tier, the container-level twin of --era-field-bg. The
11
- // other two tones are RAISED (elevated) and level (surface); there was
12
- // no way to say "sunken", so anything wanting one — a tool's output
13
- // pane, an expanded chip body — hand-rolled the fill and shadow-well
14
- // pair instead of importing this.
15
- well: 'bg-field shadow-well',
16
- flat: ''
17
- },
18
- // Sectioned layout (header / body / footer with dividers) omits the
19
- // outer padding — each section pads itself so dividers run edge-to-edge.
20
- // `p-0` (not just "no class") so a <button> card drops the browser's
21
- // default button padding and lines up with the <div>/<a> variants.
22
- //
23
- // EVEN on all four sides. This carried a half-height top padding
24
- // (pt-gutter against pb-pad-md) borrowed from `p-section`, whose
25
- // asymmetry is earned: a content panel always follows a section heading
26
- // ROW, and that row's own bar already contributes slack above the text,
27
- // so padding evenly on top of it spends the space twice. A card has no
28
- // row above it — its own top edge IS the boundary — so the borrowed
29
- // rule had nothing to subtract and simply made every card top-heavy
30
- // (4px above the content against 8px below it, at dense). A consumer
31
- // reported it as "cards aren't evenly spaced", which is exactly what it
32
- // was: the even-gap law, broken by default, in the component that
33
- // bounds more consumer content than any other.
34
- sectioned: { true: 'p-0', false: 'p-card' },
35
- // A CARD YOU CAN PRESS DEPRESSES. The pressed material is on every
36
- // other era control and was missing here, so a pressable card was the
37
- // one thing in the library that lit up on hover and then did nothing
38
- // under the finger — on bevel, where the pressed face is an inverted
39
- // chisel, that is the difference between a control and a picture of
40
- // one. Inert on flat (the token is `none`) and on glass (it resolves
41
- // to the resting shadow), so only the surface that has a pressed face
42
- // shows it. Move one library-owned content layer with the face: transforming
43
- // consumer children separately would pull a card's sections apart, while no
44
- // wrapper leaves the frame depressed around stationary ink.
45
- interactive: {
46
- true: 'pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50'
47
- }
48
- },
49
- defaultVariants: { tone: 'elevated', sectioned: false, interactive: false }
50
- });
51
- </script>
52
-
53
1
  <script lang="ts">
54
2
  import type { Snippet } from 'svelte';
55
3
  import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
4
+ import { cn } from '../../utils/index.js';
5
+ import { cardVariants } from './variants.js';
56
6
 
57
7
  type CardElement = HTMLDivElement | HTMLAnchorElement | HTMLButtonElement;
58
8
 
@@ -1,46 +1,3 @@
1
- export declare const cardVariants: import("tailwind-variants").TVReturnType<{
2
- tone: {
3
- elevated: "bg-elevated shadow-sm";
4
- surface: "bg-well";
5
- well: "bg-field shadow-well";
6
- flat: "";
7
- };
8
- sectioned: {
9
- true: "p-0";
10
- false: "p-card";
11
- };
12
- interactive: {
13
- true: "pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
14
- };
15
- }, undefined, "block w-full rounded-bar text-left text-fg", {
16
- tone: {
17
- elevated: "bg-elevated shadow-sm";
18
- surface: "bg-well";
19
- well: "bg-field shadow-well";
20
- flat: "";
21
- };
22
- sectioned: {
23
- true: "p-0";
24
- false: "p-card";
25
- };
26
- interactive: {
27
- true: "pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
28
- };
29
- }, undefined, import("tailwind-variants").TVReturnTypeLike<{
30
- tone: {
31
- elevated: "bg-elevated shadow-sm";
32
- surface: "bg-well";
33
- well: "bg-field shadow-well";
34
- flat: "";
35
- };
36
- sectioned: {
37
- true: "p-0";
38
- false: "p-card";
39
- };
40
- interactive: {
41
- true: "pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
42
- };
43
- }, undefined>>;
44
1
  import type { Snippet } from 'svelte';
45
2
  import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
46
3
  type CardElement = HTMLDivElement | HTMLAnchorElement | HTMLButtonElement;
@@ -0,0 +1,44 @@
1
+ /** Card layout and interaction semantics. Surface implementations paint them. */
2
+ export declare const cardVariants: import("tailwind-variants").TVReturnType<{
3
+ tone: {
4
+ elevated: "bg-elevated shadow-sm";
5
+ surface: "bg-well";
6
+ well: "bg-field shadow-well";
7
+ flat: "";
8
+ };
9
+ sectioned: {
10
+ true: "p-0";
11
+ false: "p-card";
12
+ };
13
+ interactive: {
14
+ true: "pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
15
+ };
16
+ }, undefined, "block w-full rounded-bar text-left text-fg", {
17
+ tone: {
18
+ elevated: "bg-elevated shadow-sm";
19
+ surface: "bg-well";
20
+ well: "bg-field shadow-well";
21
+ flat: "";
22
+ };
23
+ sectioned: {
24
+ true: "p-0";
25
+ false: "p-card";
26
+ };
27
+ interactive: {
28
+ true: "pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
29
+ };
30
+ }, undefined, import("tailwind-variants").TVReturnTypeLike<{
31
+ tone: {
32
+ elevated: "bg-elevated shadow-sm";
33
+ surface: "bg-well";
34
+ well: "bg-field shadow-well";
35
+ flat: "";
36
+ };
37
+ sectioned: {
38
+ true: "p-0";
39
+ false: "p-card";
40
+ };
41
+ interactive: {
42
+ true: "pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
43
+ };
44
+ }, undefined>>;
@@ -0,0 +1,20 @@
1
+ import { tv } from '../../utils/index.js';
2
+ /** Card layout and interaction semantics. Surface implementations paint them. */
3
+ export const cardVariants = tv({
4
+ base: 'block w-full rounded-bar text-left text-fg',
5
+ variants: {
6
+ tone: {
7
+ elevated: 'bg-elevated shadow-sm',
8
+ surface: 'bg-well',
9
+ well: 'bg-field shadow-well',
10
+ flat: ''
11
+ },
12
+ // Section padding is owned per section so dividers can run edge-to-edge.
13
+ sectioned: { true: 'p-0', false: 'p-card' },
14
+ // `pressable` moves the single data-era-press-content plane on bevel.
15
+ interactive: {
16
+ true: 'pressable cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50'
17
+ }
18
+ },
19
+ defaultVariants: { tone: 'elevated', sectioned: false, interactive: false }
20
+ });
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { ContextMenu } from 'bits-ui';
3
3
  import { cn } from '../../utils/index.js';
4
+ import { menuChoiceItem } from '../menu-recipes.js';
4
5
 
5
6
  let {
6
7
  ref = $bindable(null),
@@ -13,9 +14,6 @@
13
14
  <ContextMenu.CheckboxItem
14
15
  bind:ref
15
16
  bind:checked
16
- class={cn(
17
- 'flex h-control cursor-pointer items-center rounded-menu-item px-inset-control text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-highlight data-[highlighted]:shadow-highlight',
18
- className
19
- )}
17
+ class={cn(menuChoiceItem, className)}
20
18
  {...restProps}
21
19
  />
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { ContextMenu } from 'bits-ui';
3
3
  import { cn } from '../../utils/index.js';
4
+ import { menuGroupHeading } from '../menu-recipes.js';
4
5
 
5
6
  let {
6
7
  ref = $bindable(null),
@@ -9,8 +10,4 @@
9
10
  }: ContextMenu.GroupHeadingProps = $props();
10
11
  </script>
11
12
 
12
- <ContextMenu.GroupHeading
13
- bind:ref
14
- class={cn('flex h-control items-center px-inset-control text-body text-muted', className)}
15
- {...restProps}
16
- />
13
+ <ContextMenu.GroupHeading bind:ref class={cn(menuGroupHeading, className)} {...restProps} />
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { ContextMenu } from 'bits-ui';
3
3
  import { cn, type PartProps } from '../../utils/index.js';
4
+ import { menuItem } from '../menu-recipes.js';
4
5
 
5
6
  let {
6
7
  ref = $bindable(null),
@@ -10,13 +11,6 @@
10
11
  }: PartProps<ContextMenu.ItemProps> = $props();
11
12
  </script>
12
13
 
13
- <ContextMenu.Item
14
- bind:ref
15
- class={cn(
16
- 'flex h-control cursor-pointer items-center gap-gutter rounded-menu-item px-inset-control text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-highlight data-[highlighted]:shadow-highlight',
17
- className
18
- )}
19
- {...restProps}
20
- >
14
+ <ContextMenu.Item bind:ref class={cn(menuItem, className)} {...restProps}>
21
15
  {@render children?.()}
22
16
  </ContextMenu.Item>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { ContextMenu } from 'bits-ui';
3
3
  import { cn } from '../../utils/index.js';
4
+ import { menuChoiceItem } from '../menu-recipes.js';
4
5
 
5
6
  let {
6
7
  ref = $bindable(null),
@@ -9,11 +10,4 @@
9
10
  }: ContextMenu.RadioItemProps = $props();
10
11
  </script>
11
12
 
12
- <ContextMenu.RadioItem
13
- bind:ref
14
- class={cn(
15
- 'flex h-control cursor-pointer items-center rounded-menu-item px-inset-control text-body text-fg data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[highlighted]:bg-highlight data-[highlighted]:shadow-highlight',
16
- className
17
- )}
18
- {...restProps}
19
- />
13
+ <ContextMenu.RadioItem bind:ref class={cn(menuChoiceItem, className)} {...restProps} />
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { ContextMenu } from 'bits-ui';
3
3
  import { cn } from '../../utils/index.js';
4
+ import { menuSeparator } from '../menu-recipes.js';
4
5
 
5
6
  let {
6
7
  ref = $bindable(null),
@@ -9,8 +10,4 @@
9
10
  }: ContextMenu.SeparatorProps = $props();
10
11
  </script>
11
12
 
12
- <ContextMenu.Separator
13
- bind:ref
14
- class={cn('my-[calc(var(--era-gap)/2)] h-px bg-divider-faded', className)}
15
- {...restProps}
16
- />
13
+ <ContextMenu.Separator bind:ref class={cn(menuSeparator, className)} {...restProps} />