@handamade/psi-mcp 0.4.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.
@@ -0,0 +1,2018 @@
1
+ {
2
+ "version": "0.4.0",
3
+ "themes": [
4
+ "light",
5
+ "dark",
6
+ "acme",
7
+ "ember"
8
+ ],
9
+ "components": [
10
+ {
11
+ "name": "Button",
12
+ "description": "",
13
+ "props": [
14
+ {
15
+ "name": "variant",
16
+ "type": "\"accent\" | \"accent-subtle\" | \"neutral\" | \"neutral-subtle\" | \"ghost\" | \"danger\" | \"danger-subtle\" | \"outline\"",
17
+ "required": false,
18
+ "default": "neutral",
19
+ "description": "Visual variant."
20
+ },
21
+ {
22
+ "name": "size",
23
+ "type": "24 | 32 | 40 | 48",
24
+ "required": false,
25
+ "default": 32,
26
+ "description": "Height in px (24 | 32 | 40 | 48)."
27
+ },
28
+ {
29
+ "name": "href",
30
+ "type": "string",
31
+ "required": false,
32
+ "default": null,
33
+ "description": "Render as an anchor with this href (D33). disabled → aria-disabled,\nno href attribute, pointer-events: none."
34
+ },
35
+ {
36
+ "name": "target",
37
+ "type": "string",
38
+ "required": false,
39
+ "default": null,
40
+ "description": "Anchor target; only used with href."
41
+ },
42
+ {
43
+ "name": "rel",
44
+ "type": "string",
45
+ "required": false,
46
+ "default": null,
47
+ "description": "Anchor rel; only used with href."
48
+ },
49
+ {
50
+ "name": "ref",
51
+ "type": "Ref<HTMLButtonElement | HTMLAnchorElement>",
52
+ "required": false,
53
+ "default": null,
54
+ "description": "Forwarded ref to the underlying element."
55
+ },
56
+ {
57
+ "name": "className",
58
+ "type": "string",
59
+ "required": false,
60
+ "default": null,
61
+ "description": "Additional CSS class name(s) merged onto the component's root element."
62
+ }
63
+ ],
64
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Button\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"accent\" \\| \"accent-subtle\" \\| \"neutral\" \\| \"neutral-subtle\" \\| \"ghost\" \\| \"danger\" \\| \"danger-subtle\" \\| \"outline\"` | neutral | no | Visual variant. |\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Height in px (24 \\| 32 \\| 40 \\| 48). |\n| `href` | `string` | — | no | Render as an anchor with this href (D33). disabled → aria-disabled, no href attribute, pointer-events: none. |\n| `target` | `string` | — | no | Anchor target; only used with href. |\n| `rel` | `string` | — | no | Anchor rel; only used with href. |\n| `ref` | `Ref<HTMLButtonElement \\| HTMLAnchorElement>` | — | no | Forwarded ref to the underlying element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Enter / Space | Activates the button. |\n| Tab | Focusable; visible focus ring via :focus-visible. |\n\nWith href it renders an <a>; disabled anchors get aria-disabled, lose the href attribute, and suppress activation (D33).\n\n## Theming\n\nOverride `--psi-button-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
65
+ },
66
+ {
67
+ "name": "IconButton",
68
+ "description": "",
69
+ "props": [
70
+ {
71
+ "name": "variant",
72
+ "type": "\"accent\" | \"neutral\" | \"ghost\" | \"danger\"",
73
+ "required": false,
74
+ "default": "neutral",
75
+ "description": "Visual variant."
76
+ },
77
+ {
78
+ "name": "size",
79
+ "type": "24 | 32 | 40 | 48",
80
+ "required": false,
81
+ "default": 32,
82
+ "description": "Square size in px (24 | 32 | 40 | 48)."
83
+ },
84
+ {
85
+ "name": "href",
86
+ "type": "string",
87
+ "required": false,
88
+ "default": null,
89
+ "description": "Render as an anchor with this href (D33). disabled → aria-disabled,\nno href attribute, pointer-events: none."
90
+ },
91
+ {
92
+ "name": "target",
93
+ "type": "string",
94
+ "required": false,
95
+ "default": null,
96
+ "description": "Anchor target; only used with href."
97
+ },
98
+ {
99
+ "name": "rel",
100
+ "type": "string",
101
+ "required": false,
102
+ "default": null,
103
+ "description": "Anchor rel; only used with href."
104
+ },
105
+ {
106
+ "name": "ref",
107
+ "type": "Ref<HTMLButtonElement | HTMLAnchorElement>",
108
+ "required": false,
109
+ "default": null,
110
+ "description": "Forwarded ref to the underlying element."
111
+ },
112
+ {
113
+ "name": "className",
114
+ "type": "string",
115
+ "required": false,
116
+ "default": null,
117
+ "description": "Additional CSS class name(s) merged onto the component's root element."
118
+ }
119
+ ],
120
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# IconButton\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"accent\" \\| \"neutral\" \\| \"ghost\" \\| \"danger\"` | neutral | no | Visual variant. |\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Square size in px (24 \\| 32 \\| 40 \\| 48). |\n| `href` | `string` | — | no | Render as an anchor with this href (D33). disabled → aria-disabled, no href attribute, pointer-events: none. |\n| `target` | `string` | — | no | Anchor target; only used with href. |\n| `rel` | `string` | — | no | Anchor rel; only used with href. |\n| `ref` | `Ref<HTMLButtonElement \\| HTMLAnchorElement>` | — | no | Forwarded ref to the underlying element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Enter / Space | Activates. |\n\nRequires an accessible name — pass aria-label. IconButton does not hide its icon for you; mark the icon aria-hidden yourself.\n\n## Theming\n\nOverride `--psi-button-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
121
+ },
122
+ {
123
+ "name": "Card",
124
+ "description": "",
125
+ "props": [
126
+ {
127
+ "name": "variant",
128
+ "type": "\"stacked\" | \"featured\"",
129
+ "required": false,
130
+ "default": "stacked",
131
+ "description": "stacked = media above body; featured = media beside body (~1.6fr/1fr), stacks under md."
132
+ },
133
+ {
134
+ "name": "media",
135
+ "type": "ReactNode",
136
+ "required": false,
137
+ "default": null,
138
+ "description": "Media slot rendered edge-to-edge (img, AspectRatio, …)."
139
+ },
140
+ {
141
+ "name": "hoverLift",
142
+ "type": "boolean",
143
+ "required": false,
144
+ "default": false,
145
+ "description": "Lift on hover: translateY(-6px) over --psi-duration-350."
146
+ },
147
+ {
148
+ "name": "ref",
149
+ "type": "Ref<HTMLDivElement>",
150
+ "required": false,
151
+ "default": null,
152
+ "description": "Forwarded ref to the root element."
153
+ },
154
+ {
155
+ "name": "className",
156
+ "type": "string",
157
+ "required": false,
158
+ "default": null,
159
+ "description": "Additional CSS class name(s) merged onto the component's root element."
160
+ }
161
+ ],
162
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Card\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"stacked\" \\| \"featured\"` | stacked | no | stacked = media above body; featured = media beside body (~1.6fr/1fr), stacks under md. |\n| `media` | `ReactNode` | — | no | Media slot rendered edge-to-edge (img, AspectRatio, …). |\n| `hoverLift` | `boolean` | false | no | Lift on hover: translateY(-6px) over --psi-duration-350. |\n| `ref` | `Ref<HTMLDivElement>` | — | no | Forwarded ref to the root element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Theming\n\nOverride `--psi-card-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
163
+ },
164
+ {
165
+ "name": "Input",
166
+ "description": "",
167
+ "props": [
168
+ {
169
+ "name": "size",
170
+ "type": "24 | 32 | 40 | 48",
171
+ "required": false,
172
+ "default": 32,
173
+ "description": "Height in px (24 | 32 | 40 | 48)."
174
+ },
175
+ {
176
+ "name": "error",
177
+ "type": "boolean",
178
+ "required": false,
179
+ "default": false,
180
+ "description": "Show error styling."
181
+ },
182
+ {
183
+ "name": "ref",
184
+ "type": "Ref<HTMLInputElement>",
185
+ "required": false,
186
+ "default": null,
187
+ "description": "Forwarded ref to the underlying `<input>` element."
188
+ },
189
+ {
190
+ "name": "className",
191
+ "type": "string",
192
+ "required": false,
193
+ "default": null,
194
+ "description": "Additional CSS class name(s) merged onto the component's root element."
195
+ }
196
+ ],
197
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Input\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Height in px (24 \\| 32 \\| 40 \\| 48). |\n| `error` | `boolean` | false | no | Show error styling. |\n| `ref` | `Ref<HTMLInputElement>` | — | no | Forwarded ref to the underlying `<input>` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Tab | Focuses the native <input>; focus ring on the field. |\n\nerror sets a red border only — pair with aria-invalid and aria-describedby pointing at your error text.\n\n## Theming\n\nOverride `--psi-input-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
198
+ },
199
+ {
200
+ "name": "Select",
201
+ "description": "",
202
+ "props": [
203
+ {
204
+ "name": "size",
205
+ "type": "24 | 32 | 40 | 48",
206
+ "required": false,
207
+ "default": 32,
208
+ "description": "Height in px (24 | 32 | 40 | 48). Replaces the native `size` attribute\n(which sets the visible option-row count on a listbox-style `<select>`)\nwith the design system's control height in pixels."
209
+ },
210
+ {
211
+ "name": "error",
212
+ "type": "boolean",
213
+ "required": false,
214
+ "default": false,
215
+ "description": "Show error styling."
216
+ },
217
+ {
218
+ "name": "ref",
219
+ "type": "Ref<HTMLSelectElement>",
220
+ "required": false,
221
+ "default": null,
222
+ "description": "Forwarded ref to the underlying `<select>` element."
223
+ },
224
+ {
225
+ "name": "className",
226
+ "type": "string",
227
+ "required": false,
228
+ "default": null,
229
+ "description": "Additional CSS class name(s) merged onto the component's root element."
230
+ }
231
+ ],
232
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Select\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `size` | `24 \\| 32 \\| 40 \\| 48` | 32 | no | Height in px (24 \\| 32 \\| 40 \\| 48). Replaces the native `size` attribute (which sets the visible option-row count on a listbox-style `<select>`) with the design system's control height in pixels. |\n| `error` | `boolean` | false | no | Show error styling. |\n| `ref` | `Ref<HTMLSelectElement>` | — | no | Forwarded ref to the underlying `<select>` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Tab | Focuses the native <select>. |\n| Arrow keys / typeahead | Native option navigation. |\n\nerror: same contract as Input.\n\n## Theming\n\nOverride `--psi-select-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
233
+ },
234
+ {
235
+ "name": "Checkbox",
236
+ "description": "",
237
+ "props": [
238
+ {
239
+ "name": "children",
240
+ "type": "ReactNode",
241
+ "required": false,
242
+ "default": null,
243
+ "description": "Label text."
244
+ },
245
+ {
246
+ "name": "ref",
247
+ "type": "Ref<HTMLInputElement>",
248
+ "required": false,
249
+ "default": null,
250
+ "description": "Forwarded ref to the underlying `<input type=\"checkbox\">` element."
251
+ },
252
+ {
253
+ "name": "className",
254
+ "type": "string",
255
+ "required": false,
256
+ "default": null,
257
+ "description": "Additional CSS class name(s) merged onto the component's root element."
258
+ }
259
+ ],
260
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Checkbox\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `children` | `ReactNode` | — | no | Label text. |\n| `ref` | `Ref<HTMLInputElement>` | — | no | Forwarded ref to the underlying `<input type=\"checkbox\">` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Space | Toggles. Native <input type=checkbox> underneath (visually hidden). |\n\n\n## Theming\n\nOverride `--psi-checkbox-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
261
+ },
262
+ {
263
+ "name": "Switch",
264
+ "description": "",
265
+ "props": [
266
+ {
267
+ "name": "children",
268
+ "type": "ReactNode",
269
+ "required": false,
270
+ "default": null,
271
+ "description": "Label text."
272
+ },
273
+ {
274
+ "name": "ref",
275
+ "type": "Ref<HTMLInputElement>",
276
+ "required": false,
277
+ "default": null,
278
+ "description": "Forwarded ref to the underlying `<input type=\"checkbox\" role=\"switch\">` element."
279
+ },
280
+ {
281
+ "name": "className",
282
+ "type": "string",
283
+ "required": false,
284
+ "default": null,
285
+ "description": "Additional CSS class name(s) merged onto the component's root element."
286
+ }
287
+ ],
288
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Switch\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `children` | `ReactNode` | — | no | Label text. |\n| `ref` | `Ref<HTMLInputElement>` | — | no | Forwarded ref to the underlying `<input type=\"checkbox\" role=\"switch\">` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Space | Toggles. Native checkbox input with role=\"switch\"; announced as a switch, not a checkbox. |\n\n\n## Theming\n\nOverride `--psi-switch-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
289
+ },
290
+ {
291
+ "name": "Tag",
292
+ "description": "",
293
+ "props": [
294
+ {
295
+ "name": "variant",
296
+ "type": "\"neutral\" | \"accent\" | \"success\" | \"warning\" | \"danger\"",
297
+ "required": false,
298
+ "default": "neutral",
299
+ "description": "Semantic color variant."
300
+ },
301
+ {
302
+ "name": "subtle",
303
+ "type": "boolean",
304
+ "required": false,
305
+ "default": false,
306
+ "description": "Use tinted background with semantic foreground."
307
+ },
308
+ {
309
+ "name": "onDismiss",
310
+ "type": "(() => void)",
311
+ "required": false,
312
+ "default": null,
313
+ "description": "When provided, renders a dismiss button that calls this handler."
314
+ },
315
+ {
316
+ "name": "ref",
317
+ "type": "Ref<HTMLSpanElement>",
318
+ "required": false,
319
+ "default": null,
320
+ "description": "Forwarded ref to the underlying `<span>` element."
321
+ },
322
+ {
323
+ "name": "className",
324
+ "type": "string",
325
+ "required": false,
326
+ "default": null,
327
+ "description": "Additional CSS class name(s) merged onto the component's root element."
328
+ }
329
+ ],
330
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Tag\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `variant` | `\"neutral\" \\| \"accent\" \\| \"success\" \\| \"warning\" \\| \"danger\"` | neutral | no | Semantic color variant. |\n| `subtle` | `boolean` | false | no | Use tinted background with semantic foreground. |\n| `onDismiss` | `(() => void)` | — | no | When provided, renders a dismiss button that calls this handler. |\n| `ref` | `Ref<HTMLSpanElement>` | — | no | Forwarded ref to the underlying `<span>` element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Enter / Space (dismiss button) | onDismiss renders a real <button>; keyboard-dismissible. |\n\nPassive label otherwise; not in the tab order without onDismiss.\n\n## Theming\n\nOverride `--psi-tag-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n## Variant guidance\n\n- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.\n- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.\n- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.\n- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.\n- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.\n- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.\n- **danger** — Destructive action. Delete, remove, disconnect.\n- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.\n- **success | warning** — Status communication (Tag only). Status badges, labels.\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
331
+ },
332
+ {
333
+ "name": "Tooltip",
334
+ "description": "",
335
+ "props": [
336
+ {
337
+ "name": "content",
338
+ "type": "ReactNode",
339
+ "required": true,
340
+ "default": null,
341
+ "description": "Tooltip content."
342
+ },
343
+ {
344
+ "name": "children",
345
+ "type": "ReactElement<Record<string, unknown>, string | JSXElementConstructor<any>>",
346
+ "required": true,
347
+ "default": null,
348
+ "description": "The trigger element (must accept ref, onMouseEnter/Leave, onFocus/Blur)."
349
+ },
350
+ {
351
+ "name": "placement",
352
+ "type": "\"top\" | \"bottom\" | \"left\" | \"right\"",
353
+ "required": false,
354
+ "default": "top",
355
+ "description": "Preferred placement."
356
+ }
357
+ ],
358
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# Tooltip\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `content` | `ReactNode` | — | yes | Tooltip content. |\n| `children` | `ReactElement<Record<string, unknown>, string \\| JSXElementConstructor<any>>` | — | yes | The trigger element (must accept ref, onMouseEnter/Leave, onFocus/Blur). |\n| `placement` | `\"top\" \\| \"bottom\" \\| \"left\" \\| \"right\"` | top | no | Preferred placement. |\n\n## Keyboard & assistive tech\n\n| Keys | Behavior |\n|---|---|\n| Tab (focus trigger) | Shows immediately on focus (no delay). |\n| Escape | Dismisses while visible (WCAG 1.4.13). |\n\nHover opens after a short delay; content is linked via aria-describedby while visible. Trigger must accept onMouseEnter/Leave and onFocus/Blur props (cloned in automatically) — no ref forwarding required.\n\n## Theming\n\nOverride `--psi-tooltip-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
359
+ },
360
+ {
361
+ "name": "NavBar",
362
+ "description": "",
363
+ "props": [
364
+ {
365
+ "name": "brand",
366
+ "type": "ReactNode",
367
+ "required": false,
368
+ "default": null,
369
+ "description": "Brand slot (wordmark / logo link), leading edge."
370
+ },
371
+ {
372
+ "name": "actions",
373
+ "type": "ReactNode",
374
+ "required": false,
375
+ "default": null,
376
+ "description": "Trailing actions slot (theme switch, CTA)."
377
+ },
378
+ {
379
+ "name": "children",
380
+ "type": "ReactNode",
381
+ "required": false,
382
+ "default": null,
383
+ "description": "Nav links."
384
+ },
385
+ {
386
+ "name": "ref",
387
+ "type": "Ref<HTMLElement>",
388
+ "required": false,
389
+ "default": null,
390
+ "description": "Forwarded ref to the header element."
391
+ },
392
+ {
393
+ "name": "className",
394
+ "type": "string",
395
+ "required": false,
396
+ "default": null,
397
+ "description": "Additional CSS class name(s) merged onto the component's root element."
398
+ }
399
+ ],
400
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# NavBar\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `brand` | `ReactNode` | — | no | Brand slot (wordmark / logo link), leading edge. |\n| `actions` | `ReactNode` | — | no | Trailing actions slot (theme switch, CTA). |\n| `children` | `ReactNode` | — | no | Nav links. |\n| `ref` | `Ref<HTMLElement>` | — | no | Forwarded ref to the header element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Theming\n\nOverride `--psi-navbar-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
401
+ },
402
+ {
403
+ "name": "AspectRatio",
404
+ "description": "",
405
+ "props": [
406
+ {
407
+ "name": "ratio",
408
+ "type": "number",
409
+ "required": true,
410
+ "default": null,
411
+ "description": "Width/height ratio, e.g. 16/10 or 4/5."
412
+ },
413
+ {
414
+ "name": "ref",
415
+ "type": "Ref<HTMLDivElement>",
416
+ "required": false,
417
+ "default": null,
418
+ "description": "Forwarded ref to the frame element."
419
+ },
420
+ {
421
+ "name": "className",
422
+ "type": "string",
423
+ "required": false,
424
+ "default": null,
425
+ "description": "Additional CSS class name(s) merged onto the component's root element."
426
+ }
427
+ ],
428
+ "doc": "<!-- Generated by emit-docs.ts — do not edit. -->\n# AspectRatio\n\n\n\n## Props\n\n| Prop | Type | Default | Required | Description |\n|---|---|---|---|---|\n| `ratio` | `number` | — | yes | Width/height ratio, e.g. 16/10 or 4/5. |\n| `ref` | `Ref<HTMLDivElement>` | — | no | Forwarded ref to the frame element. |\n| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |\n\n## Theming\n\nOverride `--psi-aspect-ratio-*` custom properties at any scope; interactive states derive automatically (L - 0.04 hover, L - 0.08 active).\n\n\n\n## Rules\n\n- One accent per visual group; everything else neutral or ghost.\n- danger only for actions with real consequences.\n- Sizes are px numbers (24|32|40|48), never S/M/L.\n- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.\n- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.\n- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).\n"
429
+ }
430
+ ],
431
+ "tokens": [
432
+ {
433
+ "name": "bgPrimary",
434
+ "formula": "slot(canvas)",
435
+ "values": {
436
+ "light": {
437
+ "oklch": {
438
+ "l": 0.95,
439
+ "c": 0.005,
440
+ "h": 250
441
+ },
442
+ "hex": "#eceff2"
443
+ },
444
+ "dark": {
445
+ "oklch": {
446
+ "l": 0.15,
447
+ "c": 0.01,
448
+ "h": 250
449
+ },
450
+ "hex": "#080c0f"
451
+ },
452
+ "acme": {
453
+ "oklch": {
454
+ "l": 0.96,
455
+ "c": 0.01,
456
+ "h": 80
457
+ },
458
+ "hex": "#f5f1ea"
459
+ },
460
+ "ember": {
461
+ "oklch": {
462
+ "l": 0.147,
463
+ "c": 0.004,
464
+ "h": 49
465
+ },
466
+ "hex": "#0c0a09"
467
+ }
468
+ }
469
+ },
470
+ {
471
+ "name": "bgSecondary",
472
+ "formula": "slot(canvas) → L delta(0.03)",
473
+ "values": {
474
+ "light": {
475
+ "oklch": {
476
+ "l": 0.98,
477
+ "c": 0.005,
478
+ "h": 250
479
+ },
480
+ "hex": "#f6f9fc"
481
+ },
482
+ "dark": {
483
+ "oklch": {
484
+ "l": 0.2,
485
+ "c": 0.015,
486
+ "h": 250
487
+ },
488
+ "hex": "#11171d"
489
+ },
490
+ "acme": {
491
+ "oklch": {
492
+ "l": 0.99,
493
+ "c": 0.0089453125,
494
+ "h": 80
495
+ },
496
+ "hex": "#fffbf5"
497
+ },
498
+ "ember": {
499
+ "oklch": {
500
+ "l": 0.16199999999999998,
501
+ "c": 0.007,
502
+ "h": 49
503
+ },
504
+ "hex": "#100d0b"
505
+ }
506
+ }
507
+ },
508
+ {
509
+ "name": "fgPrimary",
510
+ "formula": "slot(ink) → L set(0.3), C set(0.03)",
511
+ "values": {
512
+ "light": {
513
+ "oklch": {
514
+ "l": 0.3,
515
+ "c": 0.03,
516
+ "h": 250
517
+ },
518
+ "hex": "#222f3c"
519
+ },
520
+ "dark": {
521
+ "oklch": {
522
+ "l": 0.93,
523
+ "c": 0.01,
524
+ "h": 250
525
+ },
526
+ "hex": "#e3e8ee"
527
+ },
528
+ "acme": {
529
+ "oklch": {
530
+ "l": 0.3,
531
+ "c": 0.03,
532
+ "h": 30
533
+ },
534
+ "hex": "#3c2825"
535
+ },
536
+ "ember": {
537
+ "oklch": {
538
+ "l": 0.949,
539
+ "c": 0.011,
540
+ "h": 72
541
+ },
542
+ "hex": "#f3ede6"
543
+ }
544
+ }
545
+ },
546
+ {
547
+ "name": "fgSecondary",
548
+ "formula": "ref(fgPrimary) → alpha(0.7)",
549
+ "values": {
550
+ "light": {
551
+ "oklch": {
552
+ "l": 0.3,
553
+ "c": 0.03,
554
+ "h": 250,
555
+ "alpha": 0.7
556
+ },
557
+ "hex": "#222f3c"
558
+ },
559
+ "dark": {
560
+ "oklch": {
561
+ "l": 0.93,
562
+ "c": 0.01,
563
+ "h": 250,
564
+ "alpha": 0.7
565
+ },
566
+ "hex": "#e3e8ee"
567
+ },
568
+ "acme": {
569
+ "oklch": {
570
+ "l": 0.3,
571
+ "c": 0.03,
572
+ "h": 30,
573
+ "alpha": 0.7
574
+ },
575
+ "hex": "#3c2825"
576
+ },
577
+ "ember": {
578
+ "oklch": {
579
+ "l": 0.949,
580
+ "c": 0.011,
581
+ "h": 72,
582
+ "alpha": 0.7
583
+ },
584
+ "hex": "#f3ede6"
585
+ }
586
+ }
587
+ },
588
+ {
589
+ "name": "fgTertiary",
590
+ "formula": "ref(fgPrimary) → alpha(0.5)",
591
+ "values": {
592
+ "light": {
593
+ "oklch": {
594
+ "l": 0.3,
595
+ "c": 0.03,
596
+ "h": 250,
597
+ "alpha": 0.5
598
+ },
599
+ "hex": "#222f3c"
600
+ },
601
+ "dark": {
602
+ "oklch": {
603
+ "l": 0.93,
604
+ "c": 0.01,
605
+ "h": 250,
606
+ "alpha": 0.5
607
+ },
608
+ "hex": "#e3e8ee"
609
+ },
610
+ "acme": {
611
+ "oklch": {
612
+ "l": 0.3,
613
+ "c": 0.03,
614
+ "h": 30,
615
+ "alpha": 0.5
616
+ },
617
+ "hex": "#3c2825"
618
+ },
619
+ "ember": {
620
+ "oklch": {
621
+ "l": 0.949,
622
+ "c": 0.011,
623
+ "h": 72,
624
+ "alpha": 0.5
625
+ },
626
+ "hex": "#f3ede6"
627
+ }
628
+ }
629
+ },
630
+ {
631
+ "name": "fgQuaternary",
632
+ "formula": "ref(fgPrimary) → alpha(0.3)",
633
+ "values": {
634
+ "light": {
635
+ "oklch": {
636
+ "l": 0.3,
637
+ "c": 0.03,
638
+ "h": 250,
639
+ "alpha": 0.3
640
+ },
641
+ "hex": "#222f3c"
642
+ },
643
+ "dark": {
644
+ "oklch": {
645
+ "l": 0.93,
646
+ "c": 0.01,
647
+ "h": 250,
648
+ "alpha": 0.3
649
+ },
650
+ "hex": "#e3e8ee"
651
+ },
652
+ "acme": {
653
+ "oklch": {
654
+ "l": 0.3,
655
+ "c": 0.03,
656
+ "h": 30,
657
+ "alpha": 0.3
658
+ },
659
+ "hex": "#3c2825"
660
+ },
661
+ "ember": {
662
+ "oklch": {
663
+ "l": 0.949,
664
+ "c": 0.011,
665
+ "h": 72,
666
+ "alpha": 0.3
667
+ },
668
+ "hex": "#f3ede6"
669
+ }
670
+ }
671
+ },
672
+ {
673
+ "name": "fgPrimaryInverted",
674
+ "formula": "slot(canvas)",
675
+ "values": {
676
+ "light": {
677
+ "oklch": {
678
+ "l": 0.95,
679
+ "c": 0.005,
680
+ "h": 250
681
+ },
682
+ "hex": "#eceff2"
683
+ },
684
+ "dark": {
685
+ "oklch": {
686
+ "l": 0.15,
687
+ "c": 0.02,
688
+ "h": 250
689
+ },
690
+ "hex": "#050c13"
691
+ },
692
+ "acme": {
693
+ "oklch": {
694
+ "l": 0.96,
695
+ "c": 0.01,
696
+ "h": 80
697
+ },
698
+ "hex": "#f5f1ea"
699
+ },
700
+ "ember": {
701
+ "oklch": {
702
+ "l": 0.15,
703
+ "c": 0.011,
704
+ "h": 72
705
+ },
706
+ "hex": "#0e0a06"
707
+ }
708
+ }
709
+ },
710
+ {
711
+ "name": "fgStaticWhite",
712
+ "formula": "slot(canvas) → L set(1), C set(0)",
713
+ "values": {
714
+ "light": {
715
+ "oklch": {
716
+ "l": 1,
717
+ "c": 0,
718
+ "h": 250
719
+ },
720
+ "hex": "#ffffff"
721
+ },
722
+ "dark": {
723
+ "oklch": {
724
+ "l": 1,
725
+ "c": 0,
726
+ "h": 250
727
+ },
728
+ "hex": "#ffffff"
729
+ },
730
+ "acme": {
731
+ "oklch": {
732
+ "l": 1,
733
+ "c": 0,
734
+ "h": 80
735
+ },
736
+ "hex": "#ffffff"
737
+ },
738
+ "ember": {
739
+ "oklch": {
740
+ "l": 1,
741
+ "c": 0,
742
+ "h": 49
743
+ },
744
+ "hex": "#ffffff"
745
+ }
746
+ }
747
+ },
748
+ {
749
+ "name": "fgStaticBlack",
750
+ "formula": "slot(ink) → L set(0.25), C cap(0.03)",
751
+ "values": {
752
+ "light": {
753
+ "oklch": {
754
+ "l": 0.25,
755
+ "c": 0.02,
756
+ "h": 250
757
+ },
758
+ "hex": "#1a222b"
759
+ },
760
+ "dark": {
761
+ "oklch": {
762
+ "l": 0.25,
763
+ "c": 0.02,
764
+ "h": 250
765
+ },
766
+ "hex": "#1a222b"
767
+ },
768
+ "acme": {
769
+ "oklch": {
770
+ "l": 0.25,
771
+ "c": 0.015,
772
+ "h": 30
773
+ },
774
+ "hex": "#281f1d"
775
+ },
776
+ "ember": {
777
+ "oklch": {
778
+ "l": 0.25,
779
+ "c": 0.011,
780
+ "h": 72
781
+ },
782
+ "hex": "#25211c"
783
+ }
784
+ }
785
+ },
786
+ {
787
+ "name": "fgOnAccent",
788
+ "formula": "ref(fgStaticWhite)",
789
+ "values": {
790
+ "light": {
791
+ "oklch": {
792
+ "l": 1,
793
+ "c": 0,
794
+ "h": 250
795
+ },
796
+ "hex": "#ffffff"
797
+ },
798
+ "dark": {
799
+ "oklch": {
800
+ "l": 1,
801
+ "c": 0,
802
+ "h": 250
803
+ },
804
+ "hex": "#ffffff"
805
+ },
806
+ "acme": {
807
+ "oklch": {
808
+ "l": 1,
809
+ "c": 0,
810
+ "h": 80
811
+ },
812
+ "hex": "#ffffff"
813
+ },
814
+ "ember": {
815
+ "oklch": {
816
+ "l": 0.25,
817
+ "c": 0.011,
818
+ "h": 72
819
+ },
820
+ "hex": "#25211c"
821
+ }
822
+ }
823
+ },
824
+ {
825
+ "name": "fgAccent",
826
+ "formula": "slot(accent) → L set(0.48), C cap(0.23)",
827
+ "values": {
828
+ "light": {
829
+ "oklch": {
830
+ "l": 0.48,
831
+ "c": 0.195772705078125,
832
+ "h": 260
833
+ },
834
+ "hex": "#0053c9"
835
+ },
836
+ "dark": {
837
+ "oklch": {
838
+ "l": 0.75,
839
+ "c": 0.1286,
840
+ "h": 260
841
+ },
842
+ "hex": "#7daeff"
843
+ },
844
+ "acme": {
845
+ "oklch": {
846
+ "l": 0.48,
847
+ "c": 0.19250488281250003,
848
+ "h": 30
849
+ },
850
+ "hex": "#b10b00"
851
+ },
852
+ "ember": {
853
+ "oklch": {
854
+ "l": 0.75,
855
+ "c": 0.15596191406249998,
856
+ "h": 40
857
+ },
858
+ "hex": "#ff885d"
859
+ }
860
+ }
861
+ },
862
+ {
863
+ "name": "fgSuccess",
864
+ "formula": "slot(success) → L set(0.48), C cap(0.1187)",
865
+ "values": {
866
+ "light": {
867
+ "oklch": {
868
+ "l": 0.48,
869
+ "c": 0.118642041015625,
870
+ "h": 155
871
+ },
872
+ "hex": "#00703e"
873
+ },
874
+ "dark": {
875
+ "oklch": {
876
+ "l": 0.75,
877
+ "c": 0.18540771484375002,
878
+ "h": 155
879
+ },
880
+ "hex": "#00cf77"
881
+ },
882
+ "acme": {
883
+ "oklch": {
884
+ "l": 0.48,
885
+ "c": 0.108573486328125,
886
+ "h": 160
887
+ },
888
+ "hex": "#007048"
889
+ },
890
+ "ember": {
891
+ "oklch": {
892
+ "l": 0.75,
893
+ "c": 0.18540771484375002,
894
+ "h": 155
895
+ },
896
+ "hex": "#00cf77"
897
+ }
898
+ }
899
+ },
900
+ {
901
+ "name": "fgWarning",
902
+ "formula": "slot(warning) → L set(0.48), C cap(0.1013)",
903
+ "values": {
904
+ "light": {
905
+ "oklch": {
906
+ "l": 0.48,
907
+ "c": 0.101250537109375,
908
+ "h": 75
909
+ },
910
+ "hex": "#7e5400"
911
+ },
912
+ "dark": {
913
+ "oklch": {
914
+ "l": 0.75,
915
+ "c": 0.1582,
916
+ "h": 75
917
+ },
918
+ "hex": "#e79d00"
919
+ },
920
+ "acme": {
921
+ "oklch": {
922
+ "l": 0.48,
923
+ "c": 0.098351953125,
924
+ "h": 85
925
+ },
926
+ "hex": "#775800"
927
+ },
928
+ "ember": {
929
+ "oklch": {
930
+ "l": 0.75,
931
+ "c": 0.1582,
932
+ "h": 75
933
+ },
934
+ "hex": "#e79d00"
935
+ }
936
+ }
937
+ },
938
+ {
939
+ "name": "fgDanger",
940
+ "formula": "slot(danger) → L set(0.48), C cap(0.1946)",
941
+ "values": {
942
+ "light": {
943
+ "oklch": {
944
+ "l": 0.48,
945
+ "c": 0.194552490234375,
946
+ "h": 25
947
+ },
948
+ "hex": "#b1001b"
949
+ },
950
+ "dark": {
951
+ "oklch": {
952
+ "l": 0.75,
953
+ "c": 0.1505,
954
+ "h": 25
955
+ },
956
+ "hex": "#ff847d"
957
+ },
958
+ "acme": {
959
+ "oklch": {
960
+ "l": 0.48,
961
+ "c": 0.1919,
962
+ "h": 15
963
+ },
964
+ "hex": "#af0039"
965
+ },
966
+ "ember": {
967
+ "oklch": {
968
+ "l": 0.75,
969
+ "c": 0.1505,
970
+ "h": 25
971
+ },
972
+ "hex": "#ff847d"
973
+ }
974
+ }
975
+ },
976
+ {
977
+ "name": "fillNeutral1",
978
+ "formula": "slot(canvas) → L delta(0.016), C delta(-0.001)",
979
+ "values": {
980
+ "light": {
981
+ "oklch": {
982
+ "l": 0.966,
983
+ "c": 0.004,
984
+ "h": 250
985
+ },
986
+ "hex": "#f2f4f6"
987
+ },
988
+ "dark": {
989
+ "oklch": {
990
+ "l": 0.18,
991
+ "c": 0.012,
992
+ "h": 250
993
+ },
994
+ "hex": "#0e1217"
995
+ },
996
+ "acme": {
997
+ "oklch": {
998
+ "l": 0.976,
999
+ "c": 0.009000000000000001,
1000
+ "h": 80
1001
+ },
1002
+ "hex": "#faf7f0"
1003
+ },
1004
+ "ember": {
1005
+ "oklch": {
1006
+ "l": 0.18,
1007
+ "c": 0.012,
1008
+ "h": 72
1009
+ },
1010
+ "hex": "#15110c"
1011
+ }
1012
+ }
1013
+ },
1014
+ {
1015
+ "name": "fillNeutral2",
1016
+ "formula": "slot(canvas)",
1017
+ "values": {
1018
+ "light": {
1019
+ "oklch": {
1020
+ "l": 0.95,
1021
+ "c": 0.005,
1022
+ "h": 250
1023
+ },
1024
+ "hex": "#eceff2"
1025
+ },
1026
+ "dark": {
1027
+ "oklch": {
1028
+ "l": 0.2,
1029
+ "c": 0.015,
1030
+ "h": 250
1031
+ },
1032
+ "hex": "#11171d"
1033
+ },
1034
+ "acme": {
1035
+ "oklch": {
1036
+ "l": 0.96,
1037
+ "c": 0.01,
1038
+ "h": 80
1039
+ },
1040
+ "hex": "#f5f1ea"
1041
+ },
1042
+ "ember": {
1043
+ "oklch": {
1044
+ "l": 0.2,
1045
+ "c": 0.015,
1046
+ "h": 72
1047
+ },
1048
+ "hex": "#1a150f"
1049
+ }
1050
+ }
1051
+ },
1052
+ {
1053
+ "name": "fillNeutral3",
1054
+ "formula": "slot(canvas) → L delta(-0.017), C delta(0.001)",
1055
+ "values": {
1056
+ "light": {
1057
+ "oklch": {
1058
+ "l": 0.9329999999999999,
1059
+ "c": 0.006,
1060
+ "h": 250
1061
+ },
1062
+ "hex": "#e6e9ed"
1063
+ },
1064
+ "dark": {
1065
+ "oklch": {
1066
+ "l": 0.23,
1067
+ "c": 0.018,
1068
+ "h": 250
1069
+ },
1070
+ "hex": "#171e25"
1071
+ },
1072
+ "acme": {
1073
+ "oklch": {
1074
+ "l": 0.943,
1075
+ "c": 0.011,
1076
+ "h": 80
1077
+ },
1078
+ "hex": "#f0ebe4"
1079
+ },
1080
+ "ember": {
1081
+ "oklch": {
1082
+ "l": 0.23,
1083
+ "c": 0.018,
1084
+ "h": 72
1085
+ },
1086
+ "hex": "#221c14"
1087
+ }
1088
+ }
1089
+ },
1090
+ {
1091
+ "name": "fillNeutral4",
1092
+ "formula": "slot(canvas) → L delta(-0.034), C delta(0.002)",
1093
+ "values": {
1094
+ "light": {
1095
+ "oklch": {
1096
+ "l": 0.9159999999999999,
1097
+ "c": 0.007,
1098
+ "h": 250
1099
+ },
1100
+ "hex": "#e0e4e8"
1101
+ },
1102
+ "dark": {
1103
+ "oklch": {
1104
+ "l": 0.26,
1105
+ "c": 0.02,
1106
+ "h": 250
1107
+ },
1108
+ "hex": "#1d252d"
1109
+ },
1110
+ "acme": {
1111
+ "oklch": {
1112
+ "l": 0.9259999999999999,
1113
+ "c": 0.012,
1114
+ "h": 80
1115
+ },
1116
+ "hex": "#ebe6de"
1117
+ },
1118
+ "ember": {
1119
+ "oklch": {
1120
+ "l": 0.26,
1121
+ "c": 0.02,
1122
+ "h": 72
1123
+ },
1124
+ "hex": "#2a2319"
1125
+ }
1126
+ }
1127
+ },
1128
+ {
1129
+ "name": "fillNeutral5",
1130
+ "formula": "slot(canvas) → L delta(-0.032), C delta(0.003)",
1131
+ "values": {
1132
+ "light": {
1133
+ "oklch": {
1134
+ "l": 0.9179999999999999,
1135
+ "c": 0.008,
1136
+ "h": 250
1137
+ },
1138
+ "hex": "#e0e4e9"
1139
+ },
1140
+ "dark": {
1141
+ "oklch": {
1142
+ "l": 0.29,
1143
+ "c": 0.022,
1144
+ "h": 250
1145
+ },
1146
+ "hex": "#232c36"
1147
+ },
1148
+ "acme": {
1149
+ "oklch": {
1150
+ "l": 0.9279999999999999,
1151
+ "c": 0.013000000000000001,
1152
+ "h": 80
1153
+ },
1154
+ "hex": "#ece6de"
1155
+ },
1156
+ "ember": {
1157
+ "oklch": {
1158
+ "l": 0.29,
1159
+ "c": 0.022,
1160
+ "h": 72
1161
+ },
1162
+ "hex": "#322a1f"
1163
+ }
1164
+ }
1165
+ },
1166
+ {
1167
+ "name": "fillNeutral6",
1168
+ "formula": "slot(canvas) → L delta(-0.048), C delta(0.004)",
1169
+ "values": {
1170
+ "light": {
1171
+ "oklch": {
1172
+ "l": 0.9019999999999999,
1173
+ "c": 0.009000000000000001,
1174
+ "h": 250
1175
+ },
1176
+ "hex": "#dadfe4"
1177
+ },
1178
+ "dark": {
1179
+ "oklch": {
1180
+ "l": 0.32,
1181
+ "c": 0.025,
1182
+ "h": 250
1183
+ },
1184
+ "hex": "#29343f"
1185
+ },
1186
+ "acme": {
1187
+ "oklch": {
1188
+ "l": 0.9119999999999999,
1189
+ "c": 0.014,
1190
+ "h": 80
1191
+ },
1192
+ "hex": "#e7e1d8"
1193
+ },
1194
+ "ember": {
1195
+ "oklch": {
1196
+ "l": 0.32,
1197
+ "c": 0.025,
1198
+ "h": 72
1199
+ },
1200
+ "hex": "#3b3125"
1201
+ }
1202
+ }
1203
+ },
1204
+ {
1205
+ "name": "fillAccent",
1206
+ "formula": "slot(accent)",
1207
+ "values": {
1208
+ "light": {
1209
+ "oklch": {
1210
+ "l": 0.55,
1211
+ "c": 0.21,
1212
+ "h": 260
1213
+ },
1214
+ "hex": "#1368e9"
1215
+ },
1216
+ "dark": {
1217
+ "oklch": {
1218
+ "l": 0.55,
1219
+ "c": 0.21,
1220
+ "h": 260
1221
+ },
1222
+ "hex": "#1368e9"
1223
+ },
1224
+ "acme": {
1225
+ "oklch": {
1226
+ "l": 0.55,
1227
+ "c": 0.2,
1228
+ "h": 30
1229
+ },
1230
+ "hex": "#cc2a1b"
1231
+ },
1232
+ "ember": {
1233
+ "oklch": {
1234
+ "l": 0.724,
1235
+ "c": 0.1768271484375,
1236
+ "h": 40
1237
+ },
1238
+ "hex": "#ff7847"
1239
+ }
1240
+ }
1241
+ },
1242
+ {
1243
+ "name": "fillSuccess",
1244
+ "formula": "slot(success) → C cap(0.1285)",
1245
+ "values": {
1246
+ "light": {
1247
+ "oklch": {
1248
+ "l": 0.52,
1249
+ "c": 0.1285,
1250
+ "h": 155
1251
+ },
1252
+ "hex": "#007e46"
1253
+ },
1254
+ "dark": {
1255
+ "oklch": {
1256
+ "l": 0.52,
1257
+ "c": 0.1285,
1258
+ "h": 155
1259
+ },
1260
+ "hex": "#007e46"
1261
+ },
1262
+ "acme": {
1263
+ "oklch": {
1264
+ "l": 0.52,
1265
+ "c": 0.1176,
1266
+ "h": 160
1267
+ },
1268
+ "hex": "#007d51"
1269
+ },
1270
+ "ember": {
1271
+ "oklch": {
1272
+ "l": 0.52,
1273
+ "c": 0.1285,
1274
+ "h": 155
1275
+ },
1276
+ "hex": "#007e46"
1277
+ }
1278
+ }
1279
+ },
1280
+ {
1281
+ "name": "fillWarning",
1282
+ "formula": "slot(warning)",
1283
+ "values": {
1284
+ "light": {
1285
+ "oklch": {
1286
+ "l": 0.75,
1287
+ "c": 0.1582,
1288
+ "h": 75
1289
+ },
1290
+ "hex": "#e79d00"
1291
+ },
1292
+ "dark": {
1293
+ "oklch": {
1294
+ "l": 0.75,
1295
+ "c": 0.1582,
1296
+ "h": 75
1297
+ },
1298
+ "hex": "#e79d00"
1299
+ },
1300
+ "acme": {
1301
+ "oklch": {
1302
+ "l": 0.78,
1303
+ "c": 0.15,
1304
+ "h": 85
1305
+ },
1306
+ "hex": "#e3ae28"
1307
+ },
1308
+ "ember": {
1309
+ "oklch": {
1310
+ "l": 0.75,
1311
+ "c": 0.1582,
1312
+ "h": 75
1313
+ },
1314
+ "hex": "#e79d00"
1315
+ }
1316
+ }
1317
+ },
1318
+ {
1319
+ "name": "fillDanger",
1320
+ "formula": "slot(danger)",
1321
+ "values": {
1322
+ "light": {
1323
+ "oklch": {
1324
+ "l": 0.55,
1325
+ "c": 0.22,
1326
+ "h": 25
1327
+ },
1328
+ "hex": "#d40924"
1329
+ },
1330
+ "dark": {
1331
+ "oklch": {
1332
+ "l": 0.55,
1333
+ "c": 0.22,
1334
+ "h": 25
1335
+ },
1336
+ "hex": "#d40924"
1337
+ },
1338
+ "acme": {
1339
+ "oklch": {
1340
+ "l": 0.55,
1341
+ "c": 0.21986572265625,
1342
+ "h": 15
1343
+ },
1344
+ "hex": "#d20046"
1345
+ },
1346
+ "ember": {
1347
+ "oklch": {
1348
+ "l": 0.55,
1349
+ "c": 0.22,
1350
+ "h": 25
1351
+ },
1352
+ "hex": "#d40924"
1353
+ }
1354
+ }
1355
+ },
1356
+ {
1357
+ "name": "fillTintAccent",
1358
+ "formula": "ref(fgAccent) → alpha(0.12)",
1359
+ "values": {
1360
+ "light": {
1361
+ "oklch": {
1362
+ "l": 0.48,
1363
+ "c": 0.195772705078125,
1364
+ "h": 260,
1365
+ "alpha": 0.12
1366
+ },
1367
+ "hex": "#0053c9"
1368
+ },
1369
+ "dark": {
1370
+ "oklch": {
1371
+ "l": 0.75,
1372
+ "c": 0.1286,
1373
+ "h": 260,
1374
+ "alpha": 0.15
1375
+ },
1376
+ "hex": "#7daeff"
1377
+ },
1378
+ "acme": {
1379
+ "oklch": {
1380
+ "l": 0.48,
1381
+ "c": 0.19250488281250003,
1382
+ "h": 30,
1383
+ "alpha": 0.12
1384
+ },
1385
+ "hex": "#b10b00"
1386
+ },
1387
+ "ember": {
1388
+ "oklch": {
1389
+ "l": 0.75,
1390
+ "c": 0.15596191406249998,
1391
+ "h": 40,
1392
+ "alpha": 0.15
1393
+ },
1394
+ "hex": "#ff885d"
1395
+ }
1396
+ }
1397
+ },
1398
+ {
1399
+ "name": "fillTintSuccess",
1400
+ "formula": "ref(fgSuccess) → alpha(0.12)",
1401
+ "values": {
1402
+ "light": {
1403
+ "oklch": {
1404
+ "l": 0.48,
1405
+ "c": 0.118642041015625,
1406
+ "h": 155,
1407
+ "alpha": 0.12
1408
+ },
1409
+ "hex": "#00703e"
1410
+ },
1411
+ "dark": {
1412
+ "oklch": {
1413
+ "l": 0.75,
1414
+ "c": 0.18540771484375002,
1415
+ "h": 155,
1416
+ "alpha": 0.15
1417
+ },
1418
+ "hex": "#00cf77"
1419
+ },
1420
+ "acme": {
1421
+ "oklch": {
1422
+ "l": 0.48,
1423
+ "c": 0.108573486328125,
1424
+ "h": 160,
1425
+ "alpha": 0.12
1426
+ },
1427
+ "hex": "#007048"
1428
+ },
1429
+ "ember": {
1430
+ "oklch": {
1431
+ "l": 0.75,
1432
+ "c": 0.18540771484375002,
1433
+ "h": 155,
1434
+ "alpha": 0.15
1435
+ },
1436
+ "hex": "#00cf77"
1437
+ }
1438
+ }
1439
+ },
1440
+ {
1441
+ "name": "fillTintWarning",
1442
+ "formula": "ref(fgWarning) → alpha(0.12)",
1443
+ "values": {
1444
+ "light": {
1445
+ "oklch": {
1446
+ "l": 0.48,
1447
+ "c": 0.101250537109375,
1448
+ "h": 75,
1449
+ "alpha": 0.12
1450
+ },
1451
+ "hex": "#7e5400"
1452
+ },
1453
+ "dark": {
1454
+ "oklch": {
1455
+ "l": 0.75,
1456
+ "c": 0.1582,
1457
+ "h": 75,
1458
+ "alpha": 0.15
1459
+ },
1460
+ "hex": "#e79d00"
1461
+ },
1462
+ "acme": {
1463
+ "oklch": {
1464
+ "l": 0.48,
1465
+ "c": 0.098351953125,
1466
+ "h": 85,
1467
+ "alpha": 0.12
1468
+ },
1469
+ "hex": "#775800"
1470
+ },
1471
+ "ember": {
1472
+ "oklch": {
1473
+ "l": 0.75,
1474
+ "c": 0.1582,
1475
+ "h": 75,
1476
+ "alpha": 0.15
1477
+ },
1478
+ "hex": "#e79d00"
1479
+ }
1480
+ }
1481
+ },
1482
+ {
1483
+ "name": "fillTintDanger",
1484
+ "formula": "ref(fgDanger) → alpha(0.12)",
1485
+ "values": {
1486
+ "light": {
1487
+ "oklch": {
1488
+ "l": 0.48,
1489
+ "c": 0.194552490234375,
1490
+ "h": 25,
1491
+ "alpha": 0.12
1492
+ },
1493
+ "hex": "#b1001b"
1494
+ },
1495
+ "dark": {
1496
+ "oklch": {
1497
+ "l": 0.75,
1498
+ "c": 0.1505,
1499
+ "h": 25,
1500
+ "alpha": 0.15
1501
+ },
1502
+ "hex": "#ff847d"
1503
+ },
1504
+ "acme": {
1505
+ "oklch": {
1506
+ "l": 0.48,
1507
+ "c": 0.1919,
1508
+ "h": 15,
1509
+ "alpha": 0.12
1510
+ },
1511
+ "hex": "#af0039"
1512
+ },
1513
+ "ember": {
1514
+ "oklch": {
1515
+ "l": 0.75,
1516
+ "c": 0.1505,
1517
+ "h": 25,
1518
+ "alpha": 0.15
1519
+ },
1520
+ "hex": "#ff847d"
1521
+ }
1522
+ }
1523
+ },
1524
+ {
1525
+ "name": "borderFaint",
1526
+ "formula": "ref(fgPrimary) → alpha(0.08)",
1527
+ "values": {
1528
+ "light": {
1529
+ "oklch": {
1530
+ "l": 0.3,
1531
+ "c": 0.03,
1532
+ "h": 250,
1533
+ "alpha": 0.08
1534
+ },
1535
+ "hex": "#222f3c"
1536
+ },
1537
+ "dark": {
1538
+ "oklch": {
1539
+ "l": 0.93,
1540
+ "c": 0.01,
1541
+ "h": 250,
1542
+ "alpha": 0.08
1543
+ },
1544
+ "hex": "#e3e8ee"
1545
+ },
1546
+ "acme": {
1547
+ "oklch": {
1548
+ "l": 0.3,
1549
+ "c": 0.03,
1550
+ "h": 30,
1551
+ "alpha": 0.08
1552
+ },
1553
+ "hex": "#3c2825"
1554
+ },
1555
+ "ember": {
1556
+ "oklch": {
1557
+ "l": 0.949,
1558
+ "c": 0.011,
1559
+ "h": 72,
1560
+ "alpha": 0.08
1561
+ },
1562
+ "hex": "#f3ede6"
1563
+ }
1564
+ }
1565
+ },
1566
+ {
1567
+ "name": "borderNeutral",
1568
+ "formula": "ref(fgPrimary) → alpha(0.15)",
1569
+ "values": {
1570
+ "light": {
1571
+ "oklch": {
1572
+ "l": 0.3,
1573
+ "c": 0.03,
1574
+ "h": 250,
1575
+ "alpha": 0.15
1576
+ },
1577
+ "hex": "#222f3c"
1578
+ },
1579
+ "dark": {
1580
+ "oklch": {
1581
+ "l": 0.93,
1582
+ "c": 0.01,
1583
+ "h": 250,
1584
+ "alpha": 0.15
1585
+ },
1586
+ "hex": "#e3e8ee"
1587
+ },
1588
+ "acme": {
1589
+ "oklch": {
1590
+ "l": 0.3,
1591
+ "c": 0.03,
1592
+ "h": 30,
1593
+ "alpha": 0.15
1594
+ },
1595
+ "hex": "#3c2825"
1596
+ },
1597
+ "ember": {
1598
+ "oklch": {
1599
+ "l": 0.949,
1600
+ "c": 0.011,
1601
+ "h": 72,
1602
+ "alpha": 0.15
1603
+ },
1604
+ "hex": "#f3ede6"
1605
+ }
1606
+ }
1607
+ },
1608
+ {
1609
+ "name": "borderStrong",
1610
+ "formula": "ref(fgPrimary) → alpha(0.3)",
1611
+ "values": {
1612
+ "light": {
1613
+ "oklch": {
1614
+ "l": 0.3,
1615
+ "c": 0.03,
1616
+ "h": 250,
1617
+ "alpha": 0.3
1618
+ },
1619
+ "hex": "#222f3c"
1620
+ },
1621
+ "dark": {
1622
+ "oklch": {
1623
+ "l": 0.93,
1624
+ "c": 0.01,
1625
+ "h": 250,
1626
+ "alpha": 0.3
1627
+ },
1628
+ "hex": "#e3e8ee"
1629
+ },
1630
+ "acme": {
1631
+ "oklch": {
1632
+ "l": 0.3,
1633
+ "c": 0.03,
1634
+ "h": 30,
1635
+ "alpha": 0.3
1636
+ },
1637
+ "hex": "#3c2825"
1638
+ },
1639
+ "ember": {
1640
+ "oklch": {
1641
+ "l": 0.949,
1642
+ "c": 0.011,
1643
+ "h": 72,
1644
+ "alpha": 0.3
1645
+ },
1646
+ "hex": "#f3ede6"
1647
+ }
1648
+ }
1649
+ },
1650
+ {
1651
+ "name": "borderFocus",
1652
+ "formula": "ref(fgAccent)",
1653
+ "values": {
1654
+ "light": {
1655
+ "oklch": {
1656
+ "l": 0.48,
1657
+ "c": 0.195772705078125,
1658
+ "h": 260
1659
+ },
1660
+ "hex": "#0053c9"
1661
+ },
1662
+ "dark": {
1663
+ "oklch": {
1664
+ "l": 0.75,
1665
+ "c": 0.1286,
1666
+ "h": 260
1667
+ },
1668
+ "hex": "#7daeff"
1669
+ },
1670
+ "acme": {
1671
+ "oklch": {
1672
+ "l": 0.48,
1673
+ "c": 0.19250488281250003,
1674
+ "h": 30
1675
+ },
1676
+ "hex": "#b10b00"
1677
+ },
1678
+ "ember": {
1679
+ "oklch": {
1680
+ "l": 0.75,
1681
+ "c": 0.15596191406249998,
1682
+ "h": 40
1683
+ },
1684
+ "hex": "#ff885d"
1685
+ }
1686
+ }
1687
+ },
1688
+ {
1689
+ "name": "scrimSoft",
1690
+ "formula": "ref(bgPrimary) → alpha(0.25)",
1691
+ "values": {
1692
+ "light": {
1693
+ "oklch": {
1694
+ "l": 0.95,
1695
+ "c": 0.005,
1696
+ "h": 250,
1697
+ "alpha": 0.25
1698
+ },
1699
+ "hex": "#eceff2"
1700
+ },
1701
+ "dark": {
1702
+ "oklch": {
1703
+ "l": 0.15,
1704
+ "c": 0.01,
1705
+ "h": 250,
1706
+ "alpha": 0.25
1707
+ },
1708
+ "hex": "#080c0f"
1709
+ },
1710
+ "acme": {
1711
+ "oklch": {
1712
+ "l": 0.96,
1713
+ "c": 0.01,
1714
+ "h": 80,
1715
+ "alpha": 0.25
1716
+ },
1717
+ "hex": "#f5f1ea"
1718
+ },
1719
+ "ember": {
1720
+ "oklch": {
1721
+ "l": 0.147,
1722
+ "c": 0.004,
1723
+ "h": 49,
1724
+ "alpha": 0.25
1725
+ },
1726
+ "hex": "#0c0a09"
1727
+ }
1728
+ }
1729
+ },
1730
+ {
1731
+ "name": "scrimMedium",
1732
+ "formula": "ref(bgPrimary) → alpha(0.35)",
1733
+ "values": {
1734
+ "light": {
1735
+ "oklch": {
1736
+ "l": 0.95,
1737
+ "c": 0.005,
1738
+ "h": 250,
1739
+ "alpha": 0.35
1740
+ },
1741
+ "hex": "#eceff2"
1742
+ },
1743
+ "dark": {
1744
+ "oklch": {
1745
+ "l": 0.15,
1746
+ "c": 0.01,
1747
+ "h": 250,
1748
+ "alpha": 0.35
1749
+ },
1750
+ "hex": "#080c0f"
1751
+ },
1752
+ "acme": {
1753
+ "oklch": {
1754
+ "l": 0.96,
1755
+ "c": 0.01,
1756
+ "h": 80,
1757
+ "alpha": 0.35
1758
+ },
1759
+ "hex": "#f5f1ea"
1760
+ },
1761
+ "ember": {
1762
+ "oklch": {
1763
+ "l": 0.147,
1764
+ "c": 0.004,
1765
+ "h": 49,
1766
+ "alpha": 0.35
1767
+ },
1768
+ "hex": "#0c0a09"
1769
+ }
1770
+ }
1771
+ },
1772
+ {
1773
+ "name": "scrimHeavy",
1774
+ "formula": "ref(bgPrimary) → alpha(0.82)",
1775
+ "values": {
1776
+ "light": {
1777
+ "oklch": {
1778
+ "l": 0.95,
1779
+ "c": 0.005,
1780
+ "h": 250,
1781
+ "alpha": 0.82
1782
+ },
1783
+ "hex": "#eceff2"
1784
+ },
1785
+ "dark": {
1786
+ "oklch": {
1787
+ "l": 0.15,
1788
+ "c": 0.01,
1789
+ "h": 250,
1790
+ "alpha": 0.82
1791
+ },
1792
+ "hex": "#080c0f"
1793
+ },
1794
+ "acme": {
1795
+ "oklch": {
1796
+ "l": 0.96,
1797
+ "c": 0.01,
1798
+ "h": 80,
1799
+ "alpha": 0.82
1800
+ },
1801
+ "hex": "#f5f1ea"
1802
+ },
1803
+ "ember": {
1804
+ "oklch": {
1805
+ "l": 0.147,
1806
+ "c": 0.004,
1807
+ "h": 49,
1808
+ "alpha": 0.82
1809
+ },
1810
+ "hex": "#0c0a09"
1811
+ }
1812
+ }
1813
+ }
1814
+ ],
1815
+ "scales": {
1816
+ "space": [
1817
+ 0,
1818
+ 2,
1819
+ 4,
1820
+ 6,
1821
+ 8,
1822
+ 12,
1823
+ 16,
1824
+ 20,
1825
+ 24,
1826
+ 32,
1827
+ 40,
1828
+ 48,
1829
+ 64,
1830
+ 80,
1831
+ 96,
1832
+ 120,
1833
+ 144
1834
+ ],
1835
+ "size": [
1836
+ 24,
1837
+ 32,
1838
+ 40,
1839
+ 48
1840
+ ],
1841
+ "radius": [
1842
+ 4,
1843
+ 6,
1844
+ 8,
1845
+ 12
1846
+ ],
1847
+ "motion": {
1848
+ "durations": [
1849
+ 150,
1850
+ 200,
1851
+ 350,
1852
+ 450,
1853
+ 600
1854
+ ],
1855
+ "easings": {
1856
+ "standard": "ease",
1857
+ "in-out": "ease-in-out",
1858
+ "soft": "cubic-bezier(0.2, 0.6, 0.2, 1)"
1859
+ }
1860
+ },
1861
+ "layout": {
1862
+ "breakpoints": {
1863
+ "sm": 560,
1864
+ "md": 960
1865
+ },
1866
+ "container": {
1867
+ "max": 1312,
1868
+ "gutter": 40,
1869
+ "gutterNarrow": 24
1870
+ },
1871
+ "zIndex": {
1872
+ "nav": 100,
1873
+ "overlay": 1000,
1874
+ "tooltip": 1100
1875
+ }
1876
+ }
1877
+ },
1878
+ "topics": {
1879
+ "variants": [
1880
+ {
1881
+ "variant": "accent",
1882
+ "intent": "Primary action, draws attention",
1883
+ "typicalUse": "Submit, CTA, main action in a group"
1884
+ },
1885
+ {
1886
+ "variant": "accent-subtle",
1887
+ "intent": "Accent tone, lower visual weight",
1888
+ "typicalUse": "Selected state, active filter, soft CTA"
1889
+ },
1890
+ {
1891
+ "variant": "neutral",
1892
+ "intent": "Default, structurally present",
1893
+ "typicalUse": "Secondary actions, toolbar buttons"
1894
+ },
1895
+ {
1896
+ "variant": "neutral-subtle",
1897
+ "intent": "Minimal chrome",
1898
+ "typicalUse": "Inline actions, table row actions"
1899
+ },
1900
+ {
1901
+ "variant": "ghost",
1902
+ "intent": "No visible container until hover",
1903
+ "typicalUse": "Icon-only triggers, compact toolbars"
1904
+ },
1905
+ {
1906
+ "variant": "outline",
1907
+ "intent": "Bordered ghost — visible structure, no fill until hover",
1908
+ "typicalUse": "Marketing CTA, download button; hover fills accent"
1909
+ },
1910
+ {
1911
+ "variant": "danger",
1912
+ "intent": "Destructive action",
1913
+ "typicalUse": "Delete, remove, disconnect"
1914
+ },
1915
+ {
1916
+ "variant": "danger-subtle",
1917
+ "intent": "Destructive context, low urgency",
1918
+ "typicalUse": "Warning badges, soft destructive hints"
1919
+ },
1920
+ {
1921
+ "variant": "success | warning",
1922
+ "intent": "Status communication (Tag only)",
1923
+ "typicalUse": "Status badges, labels"
1924
+ }
1925
+ ],
1926
+ "rules": [
1927
+ "One accent per visual group; everything else neutral or ghost.",
1928
+ "danger only for actions with real consequences.",
1929
+ "Sizes are px numbers (24|32|40|48), never S/M/L.",
1930
+ "Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.",
1931
+ "Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.",
1932
+ "--psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono)."
1933
+ ],
1934
+ "states": {
1935
+ "hover": "L - 0.04",
1936
+ "active": "L - 0.08",
1937
+ "disabled": "element opacity 0.4 (keeps hue)",
1938
+ "focus": "2px ring var(--psi-{component}-focus-ring)"
1939
+ },
1940
+ "typographyDefaults": {
1941
+ "body": "16-24-regular",
1942
+ "compactUI": "14-20-regular",
1943
+ "heading": "24-32-medium",
1944
+ "caption": "12-16-regular"
1945
+ },
1946
+ "fonts": {
1947
+ "roles": [
1948
+ "sans",
1949
+ "serif",
1950
+ "mono",
1951
+ "display"
1952
+ ],
1953
+ "note": "Font roles are brand-level (D29). The DS ships no font files: consumers load each brand's webfonts themselves.",
1954
+ "brands": {
1955
+ "ember": {
1956
+ "archivo": "800,900 (display/sans)",
1957
+ "ibmPlexSerif": "400 (serif)",
1958
+ "ibmPlexMono": "400,500 (mono)"
1959
+ }
1960
+ },
1961
+ "scope": "Brand font stacks fully apply when data-psi-theme is on the root <html> element (the standard consumer setup). In nested subtree theming, --psi-text-*/--psi-display-* combos keep the default stacks: custom properties substitute at :root."
1962
+ },
1963
+ "motion": {
1964
+ "durations": [
1965
+ 150,
1966
+ 200,
1967
+ 350,
1968
+ 450,
1969
+ 600
1970
+ ],
1971
+ "easings": {
1972
+ "standard": "ease",
1973
+ "in-out": "ease-in-out",
1974
+ "soft": "cubic-bezier(0.2, 0.6, 0.2, 1)"
1975
+ },
1976
+ "reducedMotion": "All --psi-duration-* zero under prefers-reduced-motion (D30). Always drive transitions/animations with duration tokens; never hardcode times.",
1977
+ "recipes": {
1978
+ "pulseDown": "App-level keyframe (the DS ships none): @keyframes pulse-down { 0%,100% { transform: translateY(0); opacity: .5; } 50% { transform: translateY(6px); opacity: 1; } } — drive with var(--psi-ease-in-out)."
1979
+ }
1980
+ },
1981
+ "layout": {
1982
+ "breakpoints": {
1983
+ "sm": 560,
1984
+ "md": 960
1985
+ },
1986
+ "note": "Breakpoints are build-time constants (D31): import { breakpoints } from '@handamade/psi-tokens/types'. CSS vars cannot drive @media.",
1987
+ "container": "Use .psi-container — max-width 1312px, gutter 40px stepping to 24px under md.",
1988
+ "zIndex": {
1989
+ "nav": 100,
1990
+ "overlay": 1000,
1991
+ "tooltip": 1100
1992
+ }
1993
+ },
1994
+ "recipes": {
1995
+ "mediaTint": "Apply .psi-media-tint to media elements; the brand defines --psi-media-tint (D35). Hover/focus reveals true color over --psi-duration-450 --psi-ease-soft.",
1996
+ "sectionHeader": "SectionHeader ships as a recipe, not a component (v1.2 non-goal): baseline-aligned flex row — mono annotation (--psi-text-mono-14-20-regular, --psi-fg-accent) + h2 (.psi-display-32-32-extrabold) + optional trailing meta, border-bottom 1px var(--psi-border-faint), padding-bottom var(--psi-space-20)."
1997
+ },
1998
+ "tags": {
1999
+ "accentRule": "Tags are passive labels and do not count against 'one accent per visual group' — that rule governs interactive emphasis (buttons/CTAs). D40.",
2000
+ "badges": {
2001
+ "highlight": "accent-subtle",
2002
+ "meta": "neutral-subtle",
2003
+ "status": "success | warning | danger"
2004
+ }
2005
+ },
2006
+ "getting-started": {
2007
+ "install": "npm install @handamade/psi-tokens @handamade/psi-react",
2008
+ "cssImports": [
2009
+ "@handamade/psi-tokens/base.css",
2010
+ "@handamade/psi-tokens/<theme>.css — one per theme you use (light|dark|acme|ember)",
2011
+ "@handamade/psi-tokens/components.css",
2012
+ "@handamade/psi-tokens/utilities.css — REQUIRED: .psi-container + reduced-motion zeroing"
2013
+ ],
2014
+ "themeAttribute": "Set data-psi-theme=\"light|dark|acme|ember\" on <html> or a subtree root.",
2015
+ "rules": "Sizes are px numbers (24 | 32 | 40 | 48), never S/M/L. Variants are flat (accent, accent-subtle, neutral, neutral-subtle, ghost, danger, danger-subtle, outline); one accent per visual group (Tags exempt, D40); danger only for destructive actions. Never hardcode colors — bind var(--psi-*)."
2016
+ }
2017
+ }
2018
+ }