@momoi-labs/kiso 0.10.0 → 0.11.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.
@@ -21,7 +21,7 @@ specified separately and must still run before destruction.
21
21
  | Page framing | [PageHeader](../components/page-header.md) | Title ("New connection", "Edit connection"); optional cancel secondary action |
22
22
  | Fields | [FormField](../components/form-field.md) | Each field = [Label](../components/label.md) + control ([Input](../components/input.md), [Textarea](../components/textarea.md), [Select](../components/select.md), [Checkbox](../components/checkbox.md), …) + optional [HelperText](../components/helper-text.md) + [ValidationMessage](../components/validation-message.md) |
23
23
  | Grouping | [Card](../components/card.md) or section headings | Related field groups (connection, credentials, advanced) |
24
- | Primary actions | [Button](../components/button.md) | Save / Create (primary); Cancel (secondary/ghost) |
24
+ | Primary actions | [FormActions](../components/form-actions.md) + [Button](../components/button.md) | Save / Create (primary); Cancel (secondary/ghost) |
25
25
  | Overlays | [Modal / Dialog](../components/modal-dialog.md) or [Drawer](../components/drawer.md) | Compact create/edit; Drawer preferred on small viewports for the same task |
26
26
  | Inline errors | [ValidationMessage](../components/validation-message.md) on FormField | Field-level recovery; page [Alert](../components/alert.md) is for non-field failures |
27
27
  | Form / load errors | [Alert](../components/alert.md) | Submit or load failures that are not field-local (what / why / now) |
@@ -36,6 +36,19 @@ invalid fields and ValidationMessage use `--color-danger`, focus
36
36
  `--color-focus`, destructive Buttons use `--color-danger` per the Button
37
37
  contract.
38
38
 
39
+ ## Form actions
40
+
41
+ Every explicit-submit form composes [Form](../components/form.md) and
42
+ [FormActions](../components/form-actions.md). Place one primary submit action
43
+ and any secondary actions after the fields. Use sticky actions when the form
44
+ extends beyond the page or panel viewport. Follow the FormActions contract for
45
+ scroll ownership, optional messages, and responsive layout.
46
+
47
+ The product owns dirty tracking, validation, submission, and navigation.
48
+ Discard restores the last saved values; Cancel leaves the task. Keep entries
49
+ on failure. Announce feedback in the message region, not around the buttons.
50
+ Immediate preferences and automatic filters do not require FormActions.
51
+
39
52
  ## Flow
40
53
 
41
54
  ### Create
@@ -87,7 +100,7 @@ Full-page create/edit:
87
100
 
88
101
  ```text
89
102
  ┌──────────────────────────────────────────────────────────────────────┐
90
- │ PageHeader: Edit connection [Cancel] [Save] │
103
+ │ PageHeader: Edit connection │
91
104
  ├──────────────────────────────────────────────────────────────────────┤
92
105
  │ Alert (only if submit/load error — what / why / now) │
93
106
  │ │
@@ -15,13 +15,13 @@ immediate vs deferred persistence, and unambiguous save feedback.
15
15
 
16
16
  | Region | Compose with | Role |
17
17
  | --- | --- | --- |
18
- | Page framing | [PageHeader](../components/page-header.md) | "Settings" or section title; optional save actions when the page uses explicit save |
18
+ | Page framing | [PageHeader](../components/page-header.md) | "Settings" or section title; section context; submit actions belong in FormActions |
19
19
  | Section nav | [Tabs](../components/tabs.md) or Sidebar sub-nav [Link](../components/link.md)s | Split General / Notifications / API, etc. |
20
20
  | Groups | [Card](../components/card.md) | One settings group per Card |
21
21
  | Text / choice fields | [FormField](../components/form-field.md) | [Label](../components/label.md) + [Input](../components/input.md) / [Select](../components/select.md) / [Textarea](../components/textarea.md) + [HelperText](../components/helper-text.md) + [ValidationMessage](../components/validation-message.md) |
22
22
  | Repeated values with their own options | [ChipInput](../components/chip-input.md) | One field for a list a person types, such as dependencies or scopes, instead of a form section per entry |
23
23
  | Booleans | [Switch](../components/switch.md) (immediate) or [Checkbox](../components/checkbox.md) inside FormField (part of a saved form) | Switch for single immediate preferences; Checkbox when the value submits with Save |
24
- | Actions | [Button](../components/button.md) | Save (primary), Reset/Cancel (secondary) for explicit-save sections |
24
+ | Actions | [FormActions](../components/form-actions.md) + [Button](../components/button.md) | Save (primary), Reset/Cancel (secondary) for explicit-save sections |
25
25
  | Feedback | [Toast](../components/toast.md), [Alert](../components/alert.md), [ValidationMessage](../components/validation-message.md) | Saved confirmation; section errors; field errors |
26
26
  | Shell | [Application shell](application-shell.md) | Authenticated framing |
27
27
 
@@ -50,8 +50,27 @@ Three points bind here rather than there:
50
50
  ```text
51
51
  Card: Appearance
52
52
  Theme [ ▣ ][ ☀ ][ ☾ ]
53
+ Accent [ ● ][ ● ][ ● ][ ● ]
53
54
  ```
54
55
 
56
+ The accent is the second row of the same card, with
57
+ [AccentSelector](../components/accent-selector.md). It follows the same three
58
+ points: `violet` is the default, the choice is local and instant, and it
59
+ persists under `kiso-accent` outside the section's Save button.
60
+
61
+ ## Form actions
62
+
63
+ Every explicit-submit form composes [Form](../components/form.md) and
64
+ [FormActions](../components/form-actions.md). Place one primary submit action
65
+ and any secondary actions after the fields. Use sticky actions when the form
66
+ extends beyond the page or panel viewport. Follow the FormActions contract for
67
+ scroll ownership, optional messages, and responsive layout.
68
+
69
+ The product owns dirty tracking, validation, submission, and navigation.
70
+ Discard restores the last saved values; Cancel leaves the task. Keep entries
71
+ on failure. Announce feedback in the message region, not around the buttons.
72
+ Immediate preferences and automatic filters do not require FormActions.
73
+
55
74
  ## Flow
56
75
 
57
76
  ### Explicit save (default for multi-field sections)
@@ -157,10 +157,68 @@ dark because `dark.500` misses the 3:1 non-text and large-text gates on
157
157
  `dark.800` and `dark.700`; they share a step on dark exactly as they share
158
158
  `neutral.500` on light.
159
159
 
160
+ ## Accents
161
+
162
+ The accent is a second axis over the same custom properties, orthogonal to the
163
+ theme. Five accents ship: `violet` (the default), `terracotta`, `teal`,
164
+ `cobalt`, and `nocturne`. The first four are hue turns: each is a primitive
165
+ ramp (`color.violet.*`, `color.terracotta.*`, and so on) with the same
166
+ lightness per step, so every role keeps the contrast it was gated at.
167
+ `color.accent.*` is the *active* ramp: an alias layer that points at violet by
168
+ default.
169
+
170
+ `nocturne` is different in kind. It is the marketing site's palette: the
171
+ violet ramp and ink over cool slate neutrals (hue 278) instead of the warm
172
+ ones. It is the one accent that restates the neutral roles, surfaces, text,
173
+ borders, and neutral fills alike, because the slate is the palette, not a
174
+ tint on it. A hue accent nested inside a nocturne container keeps the slate
175
+ and changes only the accent. Its surface, text, and accent values are the
176
+ site's own, gated like every other accent; the roles the site never named are
177
+ Kiso's lightness in the slate hue.
178
+
179
+ An accent is chosen with `data-accent` on `<html>`, or on any container:
180
+
181
+ ```html
182
+ <html data-accent="teal">
183
+ ```
184
+
185
+ No attribute means violet. The build emits one `[data-accent="<name>"]` block
186
+ per accent from the `accent.<name>` group in `tokens/tokens.json`. That block
187
+ restates only the roles that follow the hue:
188
+
189
+ - the active ramp, `--color-accent-50` to `--color-accent-950` and
190
+ `--color-accent-base`, remapped to the named ramp. `link`, `focus`, `ring`,
191
+ `accent`, and the light-theme tints alias the ramp, so they follow without
192
+ being restated;
193
+ - the raw-hex dark fills: `primary`, `primary-hover`, `primary-foreground`,
194
+ `accent-surface`, `accent-surface-hover`, and `selected`.
195
+
196
+ The neutral roles are not restated. The warm grey carries the interface under
197
+ every hue accent, and only the accent changes: a teal product and a violet
198
+ product share the same canvas, text, and borders. Tinting the neutrals toward
199
+ the hue was tried and rejected; at any visible strength it reads as a filter
200
+ over the screen rather than as a colour choice.
201
+
202
+ Values inside the block still use `light-dark()`, so accent and theme compose
203
+ without a cross product: five accents and two themes are five blocks, not
204
+ ten. Nesting resets cleanly: a `data-accent="violet"` container inside a
205
+ teal page is violet again.
206
+
207
+ Chart series do not follow the accent. `chart-1` is pinned to the violet ink
208
+ because a terracotta, teal, or cobalt series collapses into the warning, success,
209
+ or info series; see [Categorical chart colors](#categorical-chart-colors).
210
+ Status roles do not follow it either. Red, amber, and green were rejected as
211
+ accents for the same reason: a primary button in the danger hue reads as
212
+ destructive.
213
+
214
+ Applications own the choice and its persistence, exactly as with the theme.
215
+ Use [AccentSelector](components/accent-selector.md) for the control.
216
+
160
217
  ## AA gate
161
218
 
162
219
  `scripts/check-contrast.mjs` is the build-time AA gate. In both dark and light
163
- themes it resolves the semantic aliases and checks:
220
+ themes, for the default and for every accent, it resolves the semantic aliases
221
+ and checks:
164
222
 
165
223
  - `foreground`, `muted-foreground`, `link`, `accent`, `success`, `warning`,
166
224
  `danger`, and `info` at **4.5:1** or better against `background`, `surface`,
@@ -315,8 +373,10 @@ tokens to the same version.
315
373
  ## Categorical chart colors
316
374
 
317
375
  Issue #93 adds `--color-chart-1` through `--color-chart-5` for series identity.
318
- The roles derive from accent.base, status.success, status.warning, status.info,
319
- and status.danger, in that order. Their meaning inside a chart is categorical,
376
+ The roles derive from violet.base, status.success, status.warning, status.info,
377
+ and status.danger, in that order. `chart-1` is the violet ink under every
378
+ accent, not the active accent: a series must stay distinguishable from the
379
+ status series whatever the product's accent is. Their meaning inside a chart is categorical,
320
380
  never health or severity. Existing status roles keep their meaning elsewhere.
321
381
 
322
382
  Each slot meets 3:1 on background, surface, and elevated-surface in both
@@ -335,5 +395,5 @@ Keep the canonical slot order in stacks; changing adjacency needs review.
335
395
 
336
396
  The calculation uses [Oklab](https://bottosson.github.io/posts/oklab/) and
337
397
  [Machado's simulation model](https://pubmed.ncbi.nlm.nih.gov/19834201/).
338
- Run `node scripts/check-chart-palette.mjs` for both themes. Numbered labels,
398
+ Run `node scripts/check-chart-palette.mjs` for both themes and every accent. Numbered labels,
339
399
  highlighting, and tables remain required even when these checks pass.
package/kiso/ui.css CHANGED
@@ -298,6 +298,36 @@ a:hover, .link:hover { text-decoration: underline; }
298
298
  /* ===========================================================================
299
299
  Form controls
300
300
  =========================================================================== */
301
+ /* Forms own composition; consumers own values, validation and submission. */
302
+ .form { display: flex; flex-direction: column; min-inline-size: 0; min-block-size: 100%; }
303
+ .form-body { display: grid; gap: var(--spacing-xl); padding: var(--spacing-lg); min-inline-size: 0; }
304
+ fieldset.form-body { border: 0; margin: 0; }
305
+ .form-actions {
306
+ display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-md) var(--spacing-lg);
307
+ margin-block-start: auto;
308
+ padding: var(--spacing-md) var(--spacing-lg);
309
+ border-block-start: 1px solid var(--color-border);
310
+ background: var(--color-card);
311
+ color: var(--color-card-foreground);
312
+ border-end-start-radius: inherit; border-end-end-radius: inherit;
313
+ }
314
+ .form-actions[data-sticky="true"] { position: sticky; inset-block-end: 0; z-index: 1; }
315
+ .form-actions[data-tone="warning"] {
316
+ background: linear-gradient(var(--color-warning-surface), var(--color-warning-surface)), var(--color-card);
317
+ border-block-start-color: var(--color-warning-border);
318
+ }
319
+ .form-actions[data-tone="danger"] {
320
+ background: linear-gradient(var(--color-danger-surface), var(--color-danger-surface)), var(--color-card);
321
+ border-block-start-color: var(--color-danger-border);
322
+ }
323
+ .form-actions-message { flex: 1 1 12rem; min-inline-size: 0; overflow-wrap: anywhere; font-size: var(--type-size-label); }
324
+ /* Keep the live region mounted and available to assistive technology. */
325
+ .form-actions-message:empty { flex: 0 0 0; }
326
+ .form-actions-message strong { font-weight: var(--type-weight-semibold); }
327
+ .form-actions-buttons { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--spacing-sm); margin-inline-start: auto; }
328
+ .form-scroll { min-block-size: 0; overflow: auto; scroll-padding-block-end: calc(var(--spacing-4xl) * 2); }
329
+ .form :is(input, textarea, select, button, [tabindex]) { scroll-margin-block: var(--spacing-lg) calc(var(--spacing-4xl) * 2); }
330
+
301
331
  .field { display: grid; gap: var(--spacing-xs); }
302
332
  .field > label, .label {
303
333
  font-size: var(--type-size-label);
@@ -593,6 +623,12 @@ a:hover, .link:hover { text-decoration: underline; }
593
623
  }
594
624
  .stat-foot { font-size: var(--type-size-label); color: var(--color-muted-foreground); margin-block-start: var(--spacing-sm); }
595
625
  .stat-delta { display: inline-flex; align-items: center; gap: var(--spacing-xs); font-size: var(--type-size-metadata); font-weight: var(--type-weight-medium); }
626
+ /* The delta keeps the outline treatment: only text and frame take the status
627
+ colour. Declared after .badge-outline so the variant wins the cascade. */
628
+ .stat-delta.info { color: var(--color-info); border-color: var(--color-info-border); }
629
+ .stat-delta.success { color: var(--color-success); border-color: var(--color-success-border); }
630
+ .stat-delta.warning { color: var(--color-warning); border-color: var(--color-warning-border); }
631
+ .stat-delta.danger { color: var(--color-danger); border-color: var(--color-danger-border); }
596
632
 
597
633
  /* ===========================================================================
598
634
  Table
@@ -1185,7 +1221,7 @@ pre::after {
1185
1221
  .time-range-presets small { color: var(--color-muted-foreground); font-weight: var(--type-weight-regular); }
1186
1222
  .meter[data-slot="progress"] .meter-track > span { background: var(--color-chart-1); }
1187
1223
  .dashboard-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--spacing-lg); }
1188
- .dashboard-panel { grid-column: span var(--dashboard-span, 6); min-width: 0; }
1224
+ .dashboard-panel { grid-column: span var(--dashboard-span, 6); min-width: 0; display: grid; } /* the panel is a grid so its single child stretches to the row */
1189
1225
  @media (max-width: 1024px) {
1190
1226
  .dashboard-panel { grid-column: span 6; }
1191
1227
  .dashboard-panel[data-span="12"] { grid-column: span 12; }
@@ -1198,6 +1234,52 @@ pre::after {
1198
1234
  .disclosure > summary { min-height: var(--size-touch-min); display: list-item; align-content: center; }
1199
1235
  }
1200
1236
 
1237
+ /* StepList and StepBar, issue #98. A run's steps, walked by a machine and
1238
+ read by a person. The rail is the progress: each connector takes the state
1239
+ of the step below it, so the line fills as the run advances. Running is the
1240
+ success colour because it is alive; neutral is what is not happening. */
1241
+ .step-list { list-style: none; margin: 0; padding: 0; display: grid; }
1242
+ .step { display: grid; grid-template-columns: var(--spacing-xl) minmax(0, 1fr); column-gap: var(--spacing-sm); }
1243
+ .step-rail { position: relative; display: grid; justify-items: center; }
1244
+ .step-rail::before { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 3px; translate: -50% 0; background: var(--color-secondary); }
1245
+ .step:first-child .step-rail::before { top: 12px; }
1246
+ .step:last-child .step-rail::before { bottom: auto; height: 12px; }
1247
+ .step[data-state="done"] .step-rail::before, .step[data-state="skipped"] .step-rail::before { background: var(--color-success); }
1248
+ .step[data-state="running"] .step-rail::before { background: linear-gradient(var(--color-success) 0 12px, var(--color-secondary) 12px 100%); }
1249
+ .step[data-state="failed"] .step-rail::before { background: linear-gradient(var(--color-success) 0 12px, var(--color-danger) 12px 100%); }
1250
+ .step-mark { position: relative; z-index: 1; width: 12px; height: 12px; margin-top: 6px; border-radius: var(--radius-full); background: var(--color-card); border: 3px solid var(--color-border-strong); }
1251
+ .step[data-state="done"] .step-mark { background: var(--color-success); border-color: var(--color-success); }
1252
+ .step[data-state="skipped"] .step-mark { border-color: var(--color-success); }
1253
+ .step[data-state="running"] .step-mark { border-color: var(--color-success); box-shadow: 0 0 0 4px var(--color-success-surface); animation: step-pulse 1.4s var(--motion-easing-standard) infinite; }
1254
+ .step[data-state="failed"] .step-mark { background: var(--color-danger); border-color: var(--color-danger); }
1255
+ /* 12px dot plus 6px of glow fits the 24px rail column, which a Pane clips at its edge. */
1256
+ @keyframes step-pulse { 50% { box-shadow: 0 0 0 6px transparent; } }
1257
+ .step-body { min-width: 0; padding-bottom: var(--spacing-sm); }
1258
+ .step-row { display: flex; justify-content: space-between; align-items: baseline; gap: var(--spacing-md); width: 100%; min-height: 24px; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: start; }
1259
+ button.step-row { cursor: pointer; }
1260
+ button.step-row:hover .step-label { text-decoration: underline; text-underline-offset: var(--spacing-2xs); }
1261
+ button.step-row:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; border-radius: var(--radius-sm); }
1262
+ .step-label { font-size: var(--type-size-label); font-weight: var(--type-weight-medium); }
1263
+ .step[data-state="pending"] .step-label, .step[data-state="skipped"] .step-label { color: var(--color-muted-foreground); font-weight: var(--type-weight-regular); }
1264
+ .step[data-state="running"] .step-label, .step[data-state="failed"] .step-label { font-weight: var(--type-weight-semibold); }
1265
+ .step[data-state="failed"] .step-label { color: var(--color-danger); }
1266
+ .step-row[aria-pressed="true"] .step-label { text-decoration: underline; text-underline-offset: var(--spacing-2xs); }
1267
+ .step-meta { font-family: var(--font-mono); font-size: var(--type-size-label); color: var(--color-muted-foreground); white-space: nowrap; font-variant-numeric: tabular-nums; }
1268
+ .step-detail { margin-top: var(--spacing-sm); }
1269
+ @media (pointer: coarse) {
1270
+ button.step-row { min-height: var(--size-touch-min); }
1271
+ }
1272
+ @media (prefers-reduced-motion: reduce) {
1273
+ .step[data-state="running"] .step-mark { animation: none; }
1274
+ }
1275
+
1276
+ .step-bar { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--spacing-2xs); height: var(--spacing-xs); min-width: 0; }
1277
+ .step-bar > span { border-radius: var(--radius-xs); background: var(--color-secondary); }
1278
+ .step-bar > span[data-state="done"] { background: var(--color-success); }
1279
+ .step-bar > span[data-state="running"] { background: linear-gradient(90deg, var(--color-success) 0 var(--step-progress, 100%), var(--color-success-surface) var(--step-progress, 100%) 100%); }
1280
+ .step-bar > span[data-state="skipped"] { background: repeating-linear-gradient(45deg, var(--color-success) 0 2px, transparent 2px 5px); }
1281
+ .step-bar > span[data-state="failed"] { background: var(--color-danger); }
1282
+
1201
1283
  /* Chart presentation options. Exact values remain available in every layout. */
1202
1284
  .chart-body, .chart-plots { min-width: 0; }
1203
1285
  .framed-chart[data-legend="sidebar"] .chart-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(140px, 180px); gap: var(--spacing-lg); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momoi-labs/kiso",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Kiso design-system contracts and generated design tokens",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,21 +15,6 @@
15
15
  --color-neutral-800: #26252b;
16
16
  --color-neutral-900: #1b1a1e;
17
17
  --color-neutral-950: #131217;
18
- --color-accent-50: #f7f4ff;
19
- --color-accent-200: #ede8fd;
20
- --color-accent-300: #ded5fb;
21
- --color-accent-400: #c4b4f5;
22
- --color-accent-500: #a690ea;
23
- --color-accent-600: #7d68d1;
24
- --color-accent-700: #6552b8;
25
- --color-accent-800: #46309e;
26
- --color-accent-900: #2e2170;
27
- --color-accent-950: #211741;
28
- --color-accent-base: light-dark(#5b3fc4, #a793f4);
29
- --color-status-success: light-dark(#0c6b43, #5bd295);
30
- --color-status-warning: light-dark(#7a5000, #efc05b);
31
- --color-status-danger: light-dark(#ad2f29, #f5807f);
32
- --color-status-info: light-dark(#15559e, #75c4fa);
33
18
  --color-dark-50: #f8f6f3;
34
19
  --color-dark-100: #eeece9;
35
20
  --color-dark-200: #d9d7d3;
@@ -42,6 +27,65 @@
42
27
  --color-dark-800: #2d2b28;
43
28
  --color-dark-900: #211f1c;
44
29
  --color-dark-950: #151411;
30
+ --color-violet-50: #f7f4ff;
31
+ --color-violet-200: #ede8fd;
32
+ --color-violet-300: #ded5fb;
33
+ --color-violet-400: #c4b4f5;
34
+ --color-violet-500: #a690ea;
35
+ --color-violet-600: #7d68d1;
36
+ --color-violet-700: #6552b8;
37
+ --color-violet-800: #46309e;
38
+ --color-violet-900: #2e2170;
39
+ --color-violet-950: #211741;
40
+ --color-violet-base: light-dark(#5b3fc4, #a793f4);
41
+ --color-terracotta-50: #fef4ef;
42
+ --color-terracotta-200: #fde6db;
43
+ --color-terracotta-300: #f9d2be;
44
+ --color-terracotta-400: #f1ae8c;
45
+ --color-terracotta-500: #e28655;
46
+ --color-terracotta-600: #c3590b;
47
+ --color-terracotta-700: #a44700;
48
+ --color-terracotta-800: #783100;
49
+ --color-terracotta-900: #561f00;
50
+ --color-terracotta-950: #3b1100;
51
+ --color-terracotta-base: light-dark(#974000, #ef8c56);
52
+ --color-teal-50: #ecfaf7;
53
+ --color-teal-200: #d7f2ee;
54
+ --color-teal-300: #b6e7e0;
55
+ --color-teal-400: #75d3c7;
56
+ --color-teal-500: #08baab;
57
+ --color-teal-600: #009084;
58
+ --color-teal-700: #00776d;
59
+ --color-teal-800: #00564e;
60
+ --color-teal-900: #003c36;
61
+ --color-teal-950: #002723;
62
+ --color-teal-base: light-dark(#006d64, #05c3b4);
63
+ --color-cobalt-50: #f1f7ff;
64
+ --color-cobalt-200: #e1edfe;
65
+ --color-cobalt-300: #c7ddfe;
66
+ --color-cobalt-400: #9bc2fb;
67
+ --color-cobalt-500: #6ca2f1;
68
+ --color-cobalt-600: #3b7bd7;
69
+ --color-cobalt-700: #2463bd;
70
+ --color-cobalt-800: #00449b;
71
+ --color-cobalt-900: #002d72;
72
+ --color-cobalt-950: #051f43;
73
+ --color-cobalt-base: light-dark(#0057c1, #71aafe);
74
+ --color-accent-50: var(--color-violet-50);
75
+ --color-accent-200: var(--color-violet-200);
76
+ --color-accent-300: var(--color-violet-300);
77
+ --color-accent-400: var(--color-violet-400);
78
+ --color-accent-500: var(--color-violet-500);
79
+ --color-accent-600: var(--color-violet-600);
80
+ --color-accent-700: var(--color-violet-700);
81
+ --color-accent-800: var(--color-violet-800);
82
+ --color-accent-900: var(--color-violet-900);
83
+ --color-accent-950: var(--color-violet-950);
84
+ --color-accent-base: var(--color-violet-base);
85
+ --color-status-success: light-dark(#0c6b43, #5bd295);
86
+ --color-status-warning: light-dark(#7a5000, #efc05b);
87
+ --color-status-danger: light-dark(#ad2f29, #f5807f);
88
+ --color-status-info: light-dark(#15559e, #75c4fa);
45
89
  --color-background: light-dark(var(--color-neutral-200), var(--color-dark-900));
46
90
  --color-surface: light-dark(var(--color-neutral-100), var(--color-dark-800));
47
91
  --color-elevated-surface: light-dark(var(--color-white), var(--color-dark-700));
@@ -96,7 +140,7 @@
96
140
  --color-warning-on-dark: #efc05b;
97
141
  --color-danger-on-dark: #f5807f;
98
142
  --color-info-on-dark: #75c4fa;
99
- --color-chart-1: var(--color-accent-base);
143
+ --color-chart-1: var(--color-violet-base);
100
144
  --color-chart-2: var(--color-status-success);
101
145
  --color-chart-3: var(--color-status-warning);
102
146
  --color-chart-4: var(--color-status-info);
@@ -212,6 +256,125 @@
212
256
  color-scheme: dark;
213
257
  }
214
258
 
259
+ [data-accent="violet"] {
260
+ --color-accent-50: var(--color-violet-50);
261
+ --color-accent-200: var(--color-violet-200);
262
+ --color-accent-300: var(--color-violet-300);
263
+ --color-accent-400: var(--color-violet-400);
264
+ --color-accent-500: var(--color-violet-500);
265
+ --color-accent-600: var(--color-violet-600);
266
+ --color-accent-700: var(--color-violet-700);
267
+ --color-accent-800: var(--color-violet-800);
268
+ --color-accent-900: var(--color-violet-900);
269
+ --color-accent-950: var(--color-violet-950);
270
+ --color-accent-base: var(--color-violet-base);
271
+ --color-primary: light-dark(var(--color-violet-base), #684bb5);
272
+ --color-primary-hover: light-dark(var(--color-violet-800), #795dc9);
273
+ --color-primary-foreground: light-dark(var(--color-white), #f7f5fe);
274
+ --color-accent-surface: light-dark(var(--color-violet-50), #2d2843);
275
+ --color-accent-surface-hover: light-dark(var(--color-violet-200), #3a3356);
276
+ --color-selected: light-dark(var(--color-violet-300), #49406d);
277
+ }
278
+
279
+ [data-accent="terracotta"] {
280
+ --color-accent-50: var(--color-terracotta-50);
281
+ --color-accent-200: var(--color-terracotta-200);
282
+ --color-accent-300: var(--color-terracotta-300);
283
+ --color-accent-400: var(--color-terracotta-400);
284
+ --color-accent-500: var(--color-terracotta-500);
285
+ --color-accent-600: var(--color-terracotta-600);
286
+ --color-accent-700: var(--color-terracotta-700);
287
+ --color-accent-800: var(--color-terracotta-800);
288
+ --color-accent-900: var(--color-terracotta-900);
289
+ --color-accent-950: var(--color-terracotta-950);
290
+ --color-accent-base: var(--color-terracotta-base);
291
+ --color-primary: light-dark(var(--color-terracotta-base), #9f4400);
292
+ --color-primary-hover: light-dark(var(--color-terracotta-800), #b95100);
293
+ --color-primary-foreground: light-dark(var(--color-white), #fef4f0);
294
+ --color-accent-surface: light-dark(var(--color-terracotta-50), #402516);
295
+ --color-accent-surface-hover: light-dark(var(--color-terracotta-200), #532f1c);
296
+ --color-selected: light-dark(var(--color-terracotta-300), #683a22);
297
+ }
298
+
299
+ [data-accent="teal"] {
300
+ --color-accent-50: var(--color-teal-50);
301
+ --color-accent-200: var(--color-teal-200);
302
+ --color-accent-300: var(--color-teal-300);
303
+ --color-accent-400: var(--color-teal-400);
304
+ --color-accent-500: var(--color-teal-500);
305
+ --color-accent-600: var(--color-teal-600);
306
+ --color-accent-700: var(--color-teal-700);
307
+ --color-accent-800: var(--color-teal-800);
308
+ --color-accent-900: var(--color-teal-900);
309
+ --color-accent-950: var(--color-teal-950);
310
+ --color-accent-base: var(--color-teal-base);
311
+ --color-primary: light-dark(var(--color-teal-base), #00736a);
312
+ --color-primary-hover: light-dark(var(--color-teal-800), #00877c);
313
+ --color-primary-foreground: light-dark(var(--color-white), #eef9f7);
314
+ --color-accent-surface: light-dark(var(--color-teal-50), #053430);
315
+ --color-accent-surface-hover: light-dark(var(--color-teal-200), #00433d);
316
+ --color-selected: light-dark(var(--color-teal-300), #00544d);
317
+ }
318
+
319
+ [data-accent="cobalt"] {
320
+ --color-accent-50: var(--color-cobalt-50);
321
+ --color-accent-200: var(--color-cobalt-200);
322
+ --color-accent-300: var(--color-cobalt-300);
323
+ --color-accent-400: var(--color-cobalt-400);
324
+ --color-accent-500: var(--color-cobalt-500);
325
+ --color-accent-600: var(--color-cobalt-600);
326
+ --color-accent-700: var(--color-cobalt-700);
327
+ --color-accent-800: var(--color-cobalt-800);
328
+ --color-accent-900: var(--color-cobalt-900);
329
+ --color-accent-950: var(--color-cobalt-950);
330
+ --color-accent-base: var(--color-cobalt-base);
331
+ --color-primary: light-dark(var(--color-cobalt-base), #1c5fbc);
332
+ --color-primary-hover: light-dark(var(--color-cobalt-800), #2f72d0);
333
+ --color-primary-foreground: light-dark(var(--color-white), #f2f7ff);
334
+ --color-accent-surface: light-dark(var(--color-cobalt-50), #1d2d45);
335
+ --color-accent-surface-hover: light-dark(var(--color-cobalt-200), #253a59);
336
+ --color-selected: light-dark(var(--color-cobalt-300), #2d4870);
337
+ }
338
+
339
+ [data-accent="nocturne"] {
340
+ --color-accent-50: var(--color-violet-50);
341
+ --color-accent-200: var(--color-violet-200);
342
+ --color-accent-300: var(--color-violet-300);
343
+ --color-accent-400: var(--color-violet-400);
344
+ --color-accent-500: var(--color-violet-500);
345
+ --color-accent-600: var(--color-violet-600);
346
+ --color-accent-700: var(--color-violet-700);
347
+ --color-accent-800: var(--color-violet-800);
348
+ --color-accent-900: var(--color-violet-900);
349
+ --color-accent-950: var(--color-violet-950);
350
+ --color-accent-base: light-dark(#5348ab, #b4a9e6);
351
+ --color-primary: light-dark(#5f52ba, #6d5fc2);
352
+ --color-primary-hover: light-dark(var(--color-violet-800), #7e71d6);
353
+ --color-primary-foreground: light-dark(var(--color-white), #f7f5fe);
354
+ --color-accent-surface: light-dark(var(--color-violet-50), #2a2944);
355
+ --color-accent-surface-hover: light-dark(var(--color-violet-200), #373457);
356
+ --color-selected: light-dark(#ddd8f5, #372f6b);
357
+ --color-focus: light-dark(#5f52ba, #9184d9);
358
+ --color-background: light-dark(#f2f3f8, #161826);
359
+ --color-surface: light-dark(#ffffff, #232532);
360
+ --color-elevated-surface: light-dark(#ffffff, #292b31);
361
+ --color-muted: light-dark(#ebe7f0, #292b31);
362
+ --color-sidebar: light-dark(#ffffff, #0d0e1b);
363
+ --color-card: var(--color-surface);
364
+ --color-popover: var(--color-elevated-surface);
365
+ --color-foreground: light-dark(#1b1c24, #e9e9ed);
366
+ --color-muted-foreground: light-dark(#4d4954, #9a9aa6);
367
+ --color-subtle-foreground: light-dark(#6a6572, #74747f);
368
+ --color-border: light-dark(#ded9e4, #3f424d);
369
+ --color-border-strong: light-dark(#84858d, #8f919f);
370
+ --color-secondary: light-dark(#dadce5, #363743);
371
+ --color-secondary-hover: light-dark(#b1b2bb, #454752);
372
+ --color-disabled: light-dark(#b1b2bb, #454752);
373
+ --color-disabled-surface: light-dark(#f1f2f8, #292b35);
374
+ --color-skeleton: light-dark(#dadce5, #363743);
375
+ --color-hatch: light-dark(#dadce5, #363743);
376
+ }
377
+
215
378
  @media (prefers-reduced-motion: reduce) {
216
379
  :root {
217
380
  --motion-duration-fast: 0s;