@momoi-labs/kiso 0.1.0 → 0.3.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.
package/kiso/ui.css ADDED
@@ -0,0 +1,971 @@
1
+ /* ===========================================================================
2
+ Kiso v2 — component layer (prototype)
3
+ Every value here resolves to a token in tokens.css. No raw hex, no raw px
4
+ for anything a token covers.
5
+ =========================================================================== */
6
+
7
+ @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap");
8
+
9
+ *, *::before, *::after { box-sizing: border-box; }
10
+
11
+ html { -webkit-text-size-adjust: 100%; }
12
+
13
+ body {
14
+ margin: 0;
15
+ min-height: 100vh;
16
+ background: var(--color-background);
17
+ color: var(--color-foreground);
18
+ font-family: var(--font-body);
19
+ font-size: var(--type-size-body);
20
+ font-weight: var(--type-weight-regular);
21
+ line-height: var(--type-line-height-normal);
22
+ letter-spacing: var(--type-letter-spacing-normal);
23
+ -webkit-font-smoothing: antialiased;
24
+ font-feature-settings: "cv11", "ss01";
25
+ font-variant-numeric: tabular-nums;
26
+ }
27
+
28
+ ::selection { background: light-dark(var(--color-accent-200), var(--color-accent-800)); color: light-dark(var(--color-accent-900), var(--color-accent-50)); }
29
+
30
+ /* Focus: one ring, everywhere, violet. This is the accent's main job now. */
31
+ :focus-visible {
32
+ outline: 2px solid var(--color-ring);
33
+ outline-offset: 2px;
34
+ border-radius: var(--radius-sm);
35
+ }
36
+ :focus:not(:focus-visible) { outline: none; }
37
+
38
+ /* --- typography roles ---------------------------------------------------- */
39
+ h1, h2, h3, h4, p, figure { margin: 0; }
40
+
41
+ .t-display {
42
+ font-family: var(--font-heading);
43
+ font-size: var(--type-size-display);
44
+ font-weight: var(--type-weight-semibold);
45
+ line-height: var(--type-line-height-tight);
46
+ letter-spacing: var(--type-letter-spacing-display);
47
+ }
48
+ .t-h1 {
49
+ font-family: var(--font-heading);
50
+ font-size: var(--type-size-h1);
51
+ font-weight: var(--type-weight-semibold);
52
+ line-height: var(--type-line-height-tight);
53
+ letter-spacing: var(--type-letter-spacing-heading);
54
+ }
55
+ .t-h2 {
56
+ font-family: var(--font-heading);
57
+ font-size: var(--type-size-h2);
58
+ font-weight: var(--type-weight-semibold);
59
+ line-height: var(--type-line-height-snug);
60
+ letter-spacing: var(--type-letter-spacing-heading);
61
+ }
62
+ .t-h3 {
63
+ font-family: var(--font-heading);
64
+ font-size: var(--type-size-h3);
65
+ font-weight: var(--type-weight-semibold);
66
+ line-height: var(--type-line-height-snug);
67
+ letter-spacing: var(--type-letter-spacing-heading);
68
+ }
69
+ .t-body { font-size: var(--type-size-body); }
70
+ .t-label { font-size: var(--type-size-label); font-weight: var(--type-weight-medium); }
71
+ .t-metadata { font-size: var(--type-size-metadata); line-height: var(--type-line-height-normal); }
72
+ .t-caps {
73
+ font-size: var(--type-size-metadata);
74
+ font-weight: var(--type-weight-semibold);
75
+ letter-spacing: var(--type-letter-spacing-caps);
76
+ text-transform: uppercase;
77
+ color: var(--color-subtle-foreground);
78
+ }
79
+ .t-mono, .mono, code, pre, kbd {
80
+ font-family: var(--font-mono);
81
+ font-size: 0.925em;
82
+ font-variant-ligatures: none;
83
+ }
84
+ .t-numeric {
85
+ font-variant-numeric: tabular-nums;
86
+ font-feature-settings: "tnum";
87
+ }
88
+
89
+ .muted { color: var(--color-muted-foreground); }
90
+ .subtle { color: var(--color-subtle-foreground); }
91
+ .fg { color: var(--color-foreground); }
92
+ .success { color: var(--color-success); }
93
+ .warning { color: var(--color-warning); }
94
+ .danger { color: var(--color-danger); }
95
+ .info { color: var(--color-info); }
96
+ .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
97
+ .hidden { display: none !important; }
98
+
99
+ a, .link {
100
+ color: var(--color-link);
101
+ text-decoration: none;
102
+ text-underline-offset: 3px;
103
+ text-decoration-thickness: 1px;
104
+ }
105
+ a:hover, .link:hover { text-decoration: underline; }
106
+
107
+ /* --- layout helpers ------------------------------------------------------ */
108
+ .stack { display: grid; gap: var(--spacing-lg); }
109
+ .stack-sm{ display: grid; gap: var(--spacing-sm); }
110
+ .stack-xs{ display: grid; gap: var(--spacing-xs); }
111
+ .row { display: flex; align-items: center; gap: var(--spacing-sm); }
112
+ .row-md { display: flex; align-items: center; gap: var(--spacing-md); }
113
+ .row-wrap{ display: flex; align-items: center; gap: var(--spacing-sm); flex-wrap: wrap; }
114
+ .between { display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-md); }
115
+ .grow { flex: 1; min-width: 0; }
116
+ .separator { height: 1px; background: var(--color-border); border: 0; margin: 0; }
117
+ .separator-v { width: 1px; align-self: stretch; background: var(--color-border); }
118
+ /* A configuration row: name on the left, control flushed right. One rule, so a
119
+ settings row cannot drift between screens. Inline padding is left to the
120
+ container — inside a Card the row aligns with the body, and the sidebar
121
+ footer below re-adds the nav item's inset so labels line up. */
122
+ .settings-row { display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-md); padding-block: var(--spacing-xs); }
123
+
124
+ .icon { width: var(--size-icon-md); height: var(--size-icon-md); flex: none; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
125
+ .icon-sm { width: var(--size-icon-sm); height: var(--size-icon-sm); }
126
+ .icon-lg { width: var(--size-icon-lg); height: var(--size-icon-lg); }
127
+
128
+ /* ===========================================================================
129
+ Button
130
+ =========================================================================== */
131
+ .btn {
132
+ --btn-height: var(--size-control-md);
133
+ --btn-padding-x: var(--spacing-md);
134
+ display: inline-flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ gap: var(--spacing-sm);
138
+ height: var(--btn-height);
139
+ padding-inline: var(--btn-padding-x);
140
+ border: 1px solid transparent;
141
+ border-radius: var(--radius-md);
142
+ background: transparent;
143
+ color: var(--color-foreground);
144
+ font-family: var(--font-body);
145
+ font-size: var(--type-size-body);
146
+ font-weight: var(--type-weight-medium);
147
+ line-height: 1;
148
+ white-space: nowrap;
149
+ cursor: pointer;
150
+ user-select: none;
151
+ text-decoration: none;
152
+ transition:
153
+ background var(--motion-duration-fast) var(--motion-easing-standard),
154
+ border-color var(--motion-duration-fast) var(--motion-easing-standard),
155
+ color var(--motion-duration-fast) var(--motion-easing-standard);
156
+ }
157
+ .btn:disabled, .btn[aria-disabled="true"] {
158
+ cursor: not-allowed;
159
+ opacity: 0.5;
160
+ pointer-events: none;
161
+ }
162
+ .btn:hover { text-decoration: none; }
163
+
164
+ .btn-primary {
165
+ background: var(--color-primary);
166
+ color: var(--color-primary-foreground);
167
+ box-shadow: var(--shadow-xs);
168
+ }
169
+ .btn-primary:hover { background: var(--color-primary-hover); }
170
+
171
+ .btn-secondary {
172
+ background: var(--color-secondary);
173
+ color: var(--color-secondary-foreground);
174
+ }
175
+ .btn-secondary:hover { background: var(--color-secondary-hover); }
176
+
177
+ .btn-outline {
178
+ background: var(--color-card);
179
+ border-color: var(--color-input);
180
+ color: var(--color-foreground);
181
+ box-shadow: var(--shadow-xs);
182
+ }
183
+ .btn-outline:hover { background: var(--color-accent-surface); }
184
+
185
+ .btn-ghost { color: var(--color-muted-foreground); }
186
+ .btn-ghost:hover { background: var(--color-accent-surface-hover); color: var(--color-foreground); }
187
+
188
+ .btn-danger {
189
+ background: var(--color-danger);
190
+ color: var(--color-danger-foreground);
191
+ box-shadow: var(--shadow-xs);
192
+ }
193
+ .btn-danger:hover { filter: brightness(0.93); }
194
+
195
+ .btn-danger-ghost { color: var(--color-danger); }
196
+ .btn-danger-ghost:hover { background: var(--color-danger-surface); }
197
+
198
+ .btn-link { color: var(--color-link); padding-inline: 0; height: auto; }
199
+ .btn-link:hover { text-decoration: underline; }
200
+
201
+ .btn-xs { --btn-height: var(--size-control-xs); --btn-padding-x: var(--spacing-sm); font-size: var(--type-size-label); border-radius: var(--radius-sm); }
202
+ .btn-sm { --btn-height: var(--size-control-sm); --btn-padding-x: var(--spacing-md); font-size: var(--type-size-label); }
203
+ .btn-lg { --btn-height: var(--size-control-lg); --btn-padding-x: var(--spacing-lg); }
204
+
205
+ .btn-icon { --btn-padding-x: 0; width: var(--btn-height); }
206
+ .btn-block { width: 100%; }
207
+
208
+ /* Loading: the label stays in flow so the button never resizes. */
209
+ .btn[data-loading="true"] { position: relative; color: transparent; pointer-events: none; }
210
+ .btn[data-loading="true"]::after {
211
+ content: "";
212
+ position: absolute;
213
+ width: var(--size-icon-md); height: var(--size-icon-md);
214
+ border: 2px solid currentColor;
215
+ border-radius: var(--radius-full);
216
+ border-top-color: transparent;
217
+ animation: spin 600ms linear infinite;
218
+ }
219
+ .btn-primary[data-loading="true"]::after { border-color: var(--color-primary-foreground); border-top-color: transparent; }
220
+ @keyframes spin { to { transform: rotate(360deg); } }
221
+
222
+ /* Button group / segmented control */
223
+ .btn-group { display: inline-flex; }
224
+ .btn-group .btn { border-radius: 0; border-color: var(--color-input); background: var(--color-card); }
225
+ .btn-group .btn:first-child { border-start-start-radius: var(--radius-md); border-end-start-radius: var(--radius-md); }
226
+ .btn-group .btn:last-child { border-start-end-radius: var(--radius-md); border-end-end-radius: var(--radius-md); }
227
+ .btn-group .btn + .btn { margin-inline-start: -1px; }
228
+ .btn-group .btn:hover { background: var(--color-accent-surface); }
229
+ .btn-group .btn[aria-pressed="true"] { background: var(--color-secondary); z-index: 1; }
230
+
231
+ .segmented {
232
+ display: inline-flex;
233
+ gap: var(--spacing-2xs);
234
+ padding: var(--spacing-2xs);
235
+ background: var(--color-muted);
236
+ border: 1px solid var(--color-border);
237
+ border-radius: var(--radius-lg);
238
+ }
239
+ .segmented button {
240
+ height: var(--size-control-sm);
241
+ padding-inline: var(--spacing-md);
242
+ border: 0;
243
+ border-radius: var(--radius-md);
244
+ background: transparent;
245
+ color: var(--color-muted-foreground);
246
+ font: inherit;
247
+ font-size: var(--type-size-label);
248
+ font-weight: var(--type-weight-medium);
249
+ cursor: pointer;
250
+ transition: background var(--motion-duration-fast) var(--motion-easing-standard);
251
+ }
252
+ .segmented button:hover { color: var(--color-foreground); }
253
+ .segmented button[aria-selected="true"] {
254
+ background: var(--color-card);
255
+ color: var(--color-foreground);
256
+ box-shadow: var(--shadow-xs);
257
+ }
258
+
259
+ /* ===========================================================================
260
+ Badge / pill / status
261
+ =========================================================================== */
262
+ .badge {
263
+ display: inline-flex;
264
+ align-items: center;
265
+ gap: var(--spacing-xs);
266
+ height: 20px;
267
+ padding-inline: var(--spacing-sm);
268
+ border: 1px solid transparent;
269
+ border-radius: var(--radius-sm);
270
+ font-size: var(--type-size-metadata);
271
+ font-weight: var(--type-weight-medium);
272
+ line-height: 1;
273
+ white-space: nowrap;
274
+ }
275
+ .badge-solid { background: var(--color-primary); color: var(--color-primary-foreground); }
276
+ .badge-neutral { background: var(--color-secondary); color: var(--color-secondary-foreground); }
277
+ .badge-outline { border-color: var(--color-border-strong); color: var(--color-muted-foreground); }
278
+ .badge-success { background: var(--color-success-surface); border-color: var(--color-success-border); color: var(--color-success); }
279
+ .badge-warning { background: var(--color-warning-surface); border-color: var(--color-warning-border); color: var(--color-warning); }
280
+ .badge-danger { background: var(--color-danger-surface); border-color: var(--color-danger-border); color: var(--color-danger); }
281
+ .badge-info { background: var(--color-info-surface); border-color: var(--color-info-border); color: var(--color-info); }
282
+ .badge-pill { border-radius: var(--radius-full); padding-inline: var(--spacing-md); }
283
+ .badge-count { min-width: 20px; justify-content: center; padding-inline: var(--spacing-xs); border-radius: var(--radius-full); }
284
+ .badge .mono { font-size: inherit; }
285
+
286
+ .dot { width: 6px; height: 6px; border-radius: var(--radius-full); background: currentColor; flex: none; }
287
+ .dot-lg { width: 8px; height: 8px; }
288
+ .dot-pulse { position: relative; }
289
+ .dot-pulse::after {
290
+ content: ""; position: absolute; inset: -3px;
291
+ border-radius: var(--radius-full);
292
+ background: currentColor; opacity: 0.25;
293
+ animation: pulse 2s var(--motion-easing-standard) infinite;
294
+ }
295
+ @keyframes pulse { 0%,100% { transform: scale(1); opacity: .25 } 50% { transform: scale(1.4); opacity: 0 } }
296
+
297
+ /* ===========================================================================
298
+ Form controls
299
+ =========================================================================== */
300
+ .field { display: grid; gap: var(--spacing-xs); }
301
+ .field > label, .label {
302
+ font-size: var(--type-size-label);
303
+ font-weight: var(--type-weight-medium);
304
+ color: var(--color-foreground);
305
+ letter-spacing: var(--type-letter-spacing-label);
306
+ }
307
+ .field-hint { font-size: var(--type-size-label); color: var(--color-muted-foreground); }
308
+ .field-error { font-size: var(--type-size-label); color: var(--color-danger); display: flex; align-items: center; gap: var(--spacing-xs); }
309
+ .field-required { color: var(--color-danger); }
310
+
311
+ .input, .select, .textarea {
312
+ width: 100%;
313
+ min-width: 0;
314
+ height: var(--size-control-md);
315
+ padding-inline: var(--spacing-md);
316
+ border: 1px solid var(--color-input);
317
+ border-radius: var(--radius-md);
318
+ background: var(--color-card);
319
+ color: var(--color-foreground);
320
+ font-family: var(--font-body);
321
+ font-size: var(--type-size-body);
322
+ line-height: 1;
323
+ box-shadow: var(--shadow-xs);
324
+ transition: border-color var(--motion-duration-fast) var(--motion-easing-standard);
325
+ }
326
+ .textarea { height: auto; min-height: 76px; padding-block: var(--spacing-sm); line-height: var(--type-line-height-normal); resize: vertical; }
327
+ .input::placeholder, .textarea::placeholder { color: var(--color-subtle-foreground); }
328
+ .input:hover, .select:hover, .textarea:hover { border-color: var(--color-border-strong); }
329
+ .input:disabled, .select:disabled, .textarea:disabled {
330
+ background: var(--color-disabled-surface);
331
+ color: var(--color-disabled);
332
+ cursor: not-allowed;
333
+ }
334
+ .input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--color-danger); }
335
+ .input[aria-invalid="true"]:focus-visible { outline-color: var(--color-danger); }
336
+ .input-sm { height: var(--size-control-sm); font-size: var(--type-size-label); }
337
+ .input.mono, .textarea.mono { font-size: var(--type-size-label); }
338
+
339
+ .select {
340
+ appearance: none;
341
+ padding-inline-end: var(--spacing-2xl);
342
+ /* neutral-500 sits between both themes, so the chevron needs no fork */
343
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238a857f' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
344
+ background-repeat: no-repeat;
345
+ background-position: right var(--spacing-md) center;
346
+ background-size: var(--size-icon-md);
347
+ }
348
+
349
+ /* input with a leading icon or a trailing affix */
350
+ .input-group { position: relative; display: flex; align-items: center; }
351
+ .input-group .icon {
352
+ position: absolute;
353
+ inset-inline-start: var(--spacing-md);
354
+ color: var(--color-subtle-foreground);
355
+ pointer-events: none;
356
+ }
357
+ .input-group .icon ~ .input { padding-inline-start: calc(var(--spacing-md) * 2 + var(--size-icon-md)); }
358
+ .input-group .affix {
359
+ position: absolute;
360
+ inset-inline-end: var(--spacing-sm);
361
+ display: flex; align-items: center; gap: var(--spacing-xs);
362
+ }
363
+
364
+ /* checkbox / radio */
365
+ .check {
366
+ display: inline-flex;
367
+ align-items: flex-start;
368
+ gap: var(--spacing-sm);
369
+ cursor: pointer;
370
+ font-size: var(--type-size-body);
371
+ }
372
+ .check input[type="checkbox"], .check input[type="radio"] {
373
+ appearance: none;
374
+ margin: 0;
375
+ width: var(--size-icon-md);
376
+ height: var(--size-icon-md);
377
+ flex: none;
378
+ margin-block-start: 3px;
379
+ border: 1px solid var(--color-input);
380
+ border-radius: var(--radius-xs);
381
+ background: var(--color-card);
382
+ cursor: pointer;
383
+ transition: background var(--motion-duration-fast) var(--motion-easing-standard);
384
+ }
385
+ .check input[type="radio"] { border-radius: var(--radius-full); }
386
+ .check input:checked {
387
+ background: var(--color-primary);
388
+ border-color: var(--color-primary);
389
+ }
390
+ /* The tick is a mask painted with `primary-foreground`, so it inverts with
391
+ the fill through a token. Two per-theme data URIs used to do this job and
392
+ they could not follow `color-scheme` when the theme is left to the OS. */
393
+ .check input[type="checkbox"] { display: inline-grid; place-content: center; }
394
+ .check input[type="checkbox"]::after {
395
+ content: "";
396
+ width: 10px; height: 10px;
397
+ background: var(--color-primary-foreground);
398
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-6.5'/%3E%3C/svg%3E") center / contain no-repeat;
399
+ scale: 0;
400
+ transition: scale var(--motion-duration-fast) var(--motion-easing-standard);
401
+ }
402
+ .check input[type="checkbox"]:checked::after { scale: 1; }
403
+ .check input[type="radio"]:checked {
404
+ box-shadow: inset 0 0 0 3px var(--color-card);
405
+ }
406
+ .check input:disabled { background: var(--color-disabled-surface); border-color: var(--color-border); cursor: not-allowed; }
407
+ .check-text { display: grid; gap: var(--spacing-2xs); }
408
+
409
+ /* switch */
410
+ .switch { display: inline-flex; align-items: center; gap: var(--spacing-sm); cursor: pointer; }
411
+ .switch input {
412
+ appearance: none;
413
+ margin: 0;
414
+ position: relative;
415
+ width: 32px; height: 18px; flex: none;
416
+ border-radius: var(--radius-full);
417
+ background: var(--color-border-strong);
418
+ cursor: pointer;
419
+ transition: background var(--motion-duration-fast) var(--motion-easing-standard);
420
+ }
421
+ .switch input::after {
422
+ content: "";
423
+ position: absolute;
424
+ top: 2px; inset-inline-start: 2px;
425
+ width: 14px; height: 14px;
426
+ border-radius: var(--radius-full);
427
+ background: var(--color-white);
428
+ box-shadow: var(--shadow-xs);
429
+ transition: translate var(--motion-duration-fast) var(--motion-easing-standard);
430
+ }
431
+ .switch input:checked { background: var(--color-primary); }
432
+ .switch input:checked::after { translate: 14px 0; background: var(--color-primary-foreground); }
433
+ .switch input:disabled { opacity: .5; cursor: not-allowed; }
434
+
435
+ /* range */
436
+ .range { -webkit-appearance: none; appearance: none; width: 100%; height: 4px; border-radius: var(--radius-full); background: var(--color-secondary); }
437
+ .range::-webkit-slider-thumb {
438
+ -webkit-appearance: none;
439
+ width: var(--size-icon-md); height: var(--size-icon-md);
440
+ border-radius: var(--radius-full);
441
+ background: var(--color-card);
442
+ border: 1px solid var(--color-border-strong);
443
+ box-shadow: var(--shadow-sm);
444
+ cursor: grab;
445
+ }
446
+
447
+ /* ===========================================================================
448
+ Card
449
+ =========================================================================== */
450
+ .card {
451
+ position: relative;
452
+ background: var(--color-card);
453
+ color: var(--color-card-foreground);
454
+ border: 1px solid var(--color-border);
455
+ border-radius: var(--radius-surface);
456
+ box-shadow: var(--shadow-xs);
457
+ }
458
+ .card-header { padding: var(--spacing-lg) var(--spacing-lg) 0; display: grid; gap: var(--spacing-2xs); }
459
+ .card-body { padding: var(--spacing-lg); display: grid; gap: var(--spacing-md); }
460
+ .card-footer {
461
+ padding: var(--spacing-md) var(--spacing-lg);
462
+ border-top: 1px solid var(--color-border);
463
+ display: flex; align-items: center; justify-content: flex-end; gap: var(--spacing-sm);
464
+ background: var(--color-muted);
465
+ border-end-start-radius: var(--radius-surface);
466
+ border-end-end-radius: var(--radius-surface);
467
+ }
468
+ .card-header + .card-body { padding-block-start: var(--spacing-md); }
469
+ .card-interactive { cursor: pointer; transition: border-color var(--motion-duration-fast) var(--motion-easing-standard); }
470
+ .card-interactive:hover { border-color: var(--color-border-strong); box-shadow: var(--shadow-sm); }
471
+
472
+ /* stat / KPI tile */
473
+ .stat { display: grid; gap: var(--spacing-2xs); padding: var(--spacing-lg); }
474
+ .stat-label { font-size: var(--type-size-label); color: var(--color-muted-foreground); font-weight: var(--type-weight-regular); }
475
+ .stat-value {
476
+ font-size: var(--type-size-display);
477
+ font-weight: var(--type-weight-semibold);
478
+ line-height: var(--type-line-height-tight);
479
+ letter-spacing: var(--type-letter-spacing-display);
480
+ font-variant-numeric: tabular-nums;
481
+ }
482
+ .stat-foot { font-size: var(--type-size-label); color: var(--color-muted-foreground); margin-block-start: var(--spacing-sm); }
483
+ .stat-delta { display: inline-flex; align-items: center; gap: var(--spacing-xs); font-size: var(--type-size-metadata); font-weight: var(--type-weight-medium); }
484
+
485
+ /* ===========================================================================
486
+ Table
487
+ =========================================================================== */
488
+ .table-wrap {
489
+ position: relative;
490
+ border: 1px solid var(--color-border);
491
+ border-radius: var(--radius-surface);
492
+ background: var(--color-card);
493
+ }
494
+ /* Scrolling moves to the inner element so the corner marks, which sit just
495
+ outside the frame, are not clipped away. */
496
+ .table-wrap > .table-scroll { overflow: auto; border-radius: inherit; }
497
+ table.table { width: 100%; border-collapse: collapse; font-size: var(--type-size-body); }
498
+ .table thead th {
499
+ position: sticky; top: 0; z-index: 1;
500
+ background: var(--color-muted);
501
+ padding: var(--spacing-sm) var(--spacing-md);
502
+ border-bottom: 1px solid var(--color-border);
503
+ text-align: start;
504
+ font-size: var(--type-size-label);
505
+ font-weight: var(--type-weight-medium);
506
+ color: var(--color-muted-foreground);
507
+ white-space: nowrap;
508
+ }
509
+ .table tbody td {
510
+ padding: var(--spacing-sm) var(--spacing-md);
511
+ border-bottom: 1px solid var(--color-border);
512
+ vertical-align: middle;
513
+ height: var(--size-control-lg);
514
+ }
515
+ .table tbody tr:last-child td { border-bottom: 0; }
516
+ .table tbody tr:hover { background: var(--color-accent-surface); }
517
+ .table tbody tr[aria-selected="true"] { background: var(--color-selected); }
518
+ .table .num { text-align: end; font-variant-numeric: tabular-nums; }
519
+ .table .col-tight { width: 1%; white-space: nowrap; }
520
+ .th-sort { display: inline-flex; align-items: center; gap: var(--spacing-xs); cursor: pointer; background: none; border: 0; font: inherit; color: inherit; padding: 0; }
521
+ .table-toolbar { display: flex; align-items: center; gap: var(--spacing-sm); padding: var(--spacing-md); border-bottom: 1px solid var(--color-border); }
522
+ .table-footer { display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-md); padding: var(--spacing-sm) var(--spacing-md); border-top: 1px solid var(--color-border); font-size: var(--type-size-label); color: var(--color-muted-foreground); }
523
+
524
+ /* ===========================================================================
525
+ Tabs
526
+ =========================================================================== */
527
+ .tabs { display: flex; gap: var(--spacing-lg); border-bottom: 1px solid var(--color-border); }
528
+ .tabs button {
529
+ position: relative;
530
+ height: var(--size-control-lg);
531
+ padding: 0;
532
+ border: 0; background: none;
533
+ font: inherit;
534
+ font-size: var(--type-size-body);
535
+ font-weight: var(--type-weight-medium);
536
+ color: var(--color-muted-foreground);
537
+ cursor: pointer;
538
+ }
539
+ .tabs button:hover { color: var(--color-foreground); }
540
+ .tabs button[aria-selected="true"] { color: var(--color-foreground); }
541
+ .tabs button[aria-selected="true"]::after {
542
+ content: ""; position: absolute; inset-inline: 0; bottom: -1px; height: 2px;
543
+ background: var(--color-primary);
544
+ border-radius: var(--radius-full);
545
+ }
546
+
547
+ /* ===========================================================================
548
+ Alert / callout
549
+ =========================================================================== */
550
+ .alert {
551
+ display: flex;
552
+ gap: var(--spacing-md);
553
+ padding: var(--spacing-md);
554
+ border: 1px solid var(--color-border);
555
+ border-radius: var(--radius-lg);
556
+ background: var(--color-card);
557
+ font-size: var(--type-size-body);
558
+ }
559
+ .alert .icon { margin-block-start: 2px; }
560
+ .alert-title { font-weight: var(--type-weight-medium); }
561
+ .alert-body { color: var(--color-muted-foreground); font-size: var(--type-size-label); }
562
+ .alert-info { background: var(--color-info-surface); border-color: var(--color-info-border); }
563
+ .alert-info > .icon { color: var(--color-info); }
564
+ .alert-success { background: var(--color-success-surface); border-color: var(--color-success-border); }
565
+ .alert-success > .icon { color: var(--color-success); }
566
+ .alert-warning { background: var(--color-warning-surface); border-color: var(--color-warning-border); }
567
+ .alert-warning > .icon { color: var(--color-warning); }
568
+ .alert-danger { background: var(--color-danger-surface); border-color: var(--color-danger-border); }
569
+ .alert-danger > .icon { color: var(--color-danger); }
570
+
571
+ /* ===========================================================================
572
+ Dialog / drawer / overlay
573
+ =========================================================================== */
574
+ .overlay {
575
+ position: fixed; inset: 0; z-index: 50;
576
+ display: grid; place-items: center;
577
+ padding: var(--spacing-lg);
578
+ background: var(--color-overlay);
579
+ backdrop-filter: blur(2px);
580
+ }
581
+ .dialog {
582
+ position: relative;
583
+ width: 100%; max-width: 440px;
584
+ background: var(--color-popover);
585
+ color: var(--color-popover-foreground);
586
+ border: 1px solid var(--color-border);
587
+ border-radius: var(--radius-surface);
588
+ box-shadow: var(--shadow-lg);
589
+ animation: dialog-in var(--motion-duration-normal) var(--motion-easing-standard);
590
+ }
591
+ @keyframes dialog-in { from { opacity: 0; translate: 0 8px; scale: .98 } }
592
+ .dialog-header { padding: var(--spacing-lg) var(--spacing-lg) 0; display: grid; gap: var(--spacing-2xs); }
593
+ .dialog-body { padding: var(--spacing-lg); display: grid; gap: var(--spacing-lg); }
594
+ .dialog-header + .dialog-body { padding-block-start: var(--spacing-md); }
595
+ .dialog-footer { padding: var(--spacing-md) var(--spacing-lg); border-top: 1px solid var(--color-border); display: flex; justify-content: flex-end; gap: var(--spacing-sm); background: var(--color-muted); border-end-start-radius: var(--radius-surface); border-end-end-radius: var(--radius-surface); }
596
+
597
+ /* ===========================================================================
598
+ Menu / popover / tooltip / command palette
599
+ =========================================================================== */
600
+ .menu {
601
+ min-width: 200px;
602
+ padding: var(--spacing-xs);
603
+ background: var(--color-popover);
604
+ border: 1px solid var(--color-border);
605
+ border-radius: var(--radius-lg);
606
+ box-shadow: var(--shadow-lg);
607
+ }
608
+ .menu-item {
609
+ display: flex; align-items: center; gap: var(--spacing-sm);
610
+ width: 100%;
611
+ height: var(--size-control-sm);
612
+ padding-inline: var(--spacing-sm);
613
+ border: 0; border-radius: var(--radius-md);
614
+ background: none; color: var(--color-foreground);
615
+ font: inherit; font-size: var(--type-size-body);
616
+ text-align: start; text-decoration: none;
617
+ cursor: pointer;
618
+ }
619
+ .menu-item:hover { background: var(--color-accent-surface-hover); }
620
+ .menu-item .icon { color: var(--color-muted-foreground); }
621
+ .menu-item.is-danger { color: var(--color-danger); }
622
+ .menu-item.is-danger:hover { background: var(--color-danger-surface); }
623
+ .menu-item .kbd { margin-inline-start: auto; }
624
+ .menu-label { padding: var(--spacing-sm) var(--spacing-sm) var(--spacing-xs); }
625
+ .menu-separator { height: 1px; background: var(--color-border); margin: var(--spacing-xs) calc(var(--spacing-xs) * -1); }
626
+
627
+ .kbd, kbd {
628
+ display: inline-flex; align-items: center; justify-content: center;
629
+ min-width: 18px; height: 18px;
630
+ padding-inline: var(--spacing-xs);
631
+ border: 1px solid var(--color-border);
632
+ border-bottom-width: 2px;
633
+ border-radius: var(--radius-xs);
634
+ background: var(--color-muted);
635
+ color: var(--color-muted-foreground);
636
+ font-family: var(--font-mono);
637
+ font-size: var(--type-size-metadata);
638
+ line-height: 1;
639
+ }
640
+
641
+ .tooltip {
642
+ display: inline-block;
643
+ padding: var(--spacing-xs) var(--spacing-sm);
644
+ border-radius: var(--radius-md);
645
+ background: var(--color-primary);
646
+ color: var(--color-primary-foreground);
647
+ font-size: var(--type-size-label);
648
+ line-height: var(--type-line-height-tight);
649
+ box-shadow: var(--shadow-md);
650
+ }
651
+
652
+ .palette {
653
+ width: 100%; max-width: 560px;
654
+ background: var(--color-popover);
655
+ border: 1px solid var(--color-border);
656
+ border-radius: var(--radius-surface);
657
+ box-shadow: var(--shadow-lg);
658
+ overflow: hidden;
659
+ }
660
+ .palette-input {
661
+ display: flex; align-items: center; gap: var(--spacing-sm);
662
+ padding: var(--spacing-md) var(--spacing-lg);
663
+ border-bottom: 1px solid var(--color-border);
664
+ }
665
+ .palette-input input { flex: 1; border: 0; background: none; color: inherit; font: inherit; outline: none; }
666
+ .palette-list { padding: var(--spacing-xs); max-height: 280px; overflow-y: auto; }
667
+ .palette-list .menu-item[aria-selected="true"] { background: var(--color-selected); color: var(--color-selected-foreground); }
668
+
669
+ /* ===========================================================================
670
+ Toast
671
+ =========================================================================== */
672
+ .toast-region { position: fixed; inset-block-end: var(--spacing-lg); inset-inline-end: var(--spacing-lg); z-index: 60; display: grid; gap: var(--spacing-sm); }
673
+ .toast {
674
+ display: flex; align-items: flex-start; gap: var(--spacing-md);
675
+ width: 340px;
676
+ padding: var(--spacing-md);
677
+ background: var(--color-popover);
678
+ border: 1px solid var(--color-border);
679
+ border-radius: var(--radius-lg);
680
+ box-shadow: var(--shadow-lg);
681
+ animation: toast-in var(--motion-duration-normal) var(--motion-easing-standard);
682
+ }
683
+ @keyframes toast-in { from { opacity: 0; translate: 0 12px } }
684
+
685
+ /* ===========================================================================
686
+ Feedback: spinner, progress, skeleton, empty state
687
+ =========================================================================== */
688
+ .spinner {
689
+ width: var(--size-icon-md); height: var(--size-icon-md);
690
+ border: 2px solid var(--color-border-strong);
691
+ border-top-color: var(--color-foreground);
692
+ border-radius: var(--radius-full);
693
+ animation: spin 600ms linear infinite;
694
+ }
695
+ .spinner-lg { width: var(--size-icon-lg); height: var(--size-icon-lg); }
696
+
697
+ .progress { height: 6px; border-radius: var(--radius-full); background: var(--color-secondary); overflow: hidden; }
698
+ .progress > span { display: block; height: 100%; border-radius: inherit; background: var(--color-primary); }
699
+ .progress-accent > span { background: var(--color-accent-600); }
700
+
701
+ .skeleton { border-radius: var(--radius-md); background: var(--color-skeleton); animation: shimmer 1.4s ease-in-out infinite; }
702
+ @keyframes shimmer { 50% { opacity: .55 } }
703
+
704
+ .empty {
705
+ display: grid; justify-items: center; gap: var(--spacing-sm);
706
+ padding: var(--spacing-4xl) var(--spacing-xl);
707
+ text-align: center;
708
+ }
709
+ .empty-icon {
710
+ display: grid; place-items: center;
711
+ width: var(--size-control-lg); height: var(--size-control-lg);
712
+ border: 1px solid var(--color-border);
713
+ border-radius: var(--radius-lg);
714
+ background: var(--color-muted);
715
+ color: var(--color-muted-foreground);
716
+ margin-block-end: var(--spacing-xs);
717
+ }
718
+ .empty p { color: var(--color-muted-foreground); font-size: var(--type-size-label); max-width: 42ch; }
719
+
720
+ /* ===========================================================================
721
+ Navigation: breadcrumb, pagination, sidebar, header
722
+ =========================================================================== */
723
+ .breadcrumb { display: flex; align-items: center; gap: var(--spacing-sm); font-size: var(--type-size-label); color: var(--color-muted-foreground); }
724
+ .breadcrumb a { color: var(--color-muted-foreground); }
725
+ .breadcrumb a:hover { color: var(--color-foreground); text-decoration: none; }
726
+ .breadcrumb [aria-current="page"] { color: var(--color-foreground); font-weight: var(--type-weight-medium); }
727
+ .breadcrumb .sep { color: var(--color-border-strong); }
728
+
729
+ .pagination { display: flex; align-items: center; gap: var(--spacing-xs); }
730
+ .pagination .btn[aria-current="page"] { background: var(--color-secondary); }
731
+
732
+ .app-shell { display: grid; grid-template-columns: var(--size-sidebar) minmax(0, 1fr); min-height: 100vh; }
733
+ .sidebar {
734
+ display: flex; flex-direction: column;
735
+ min-width: 0;
736
+ position: sticky; top: 0;
737
+ height: 100vh;
738
+ background: var(--color-sidebar);
739
+ border-inline-end: 1px solid var(--color-sidebar-border);
740
+ }
741
+ .sidebar-header { padding: var(--spacing-md); display: grid; gap: var(--spacing-md); }
742
+ .sidebar-body { flex: 1; overflow-y: auto; padding: 0 var(--spacing-sm) var(--spacing-sm); display: grid; gap: var(--spacing-lg); align-content: start; }
743
+ .sidebar-footer { padding: var(--spacing-sm); border-top: 1px solid var(--color-sidebar-border); display: grid; gap: var(--spacing-2xs); }
744
+ .sidebar-footer .settings-row { padding-inline: var(--spacing-sm); } /* match .nav-item's inset */
745
+ .nav-group { display: grid; gap: var(--spacing-2xs); }
746
+ .nav-group > .t-caps { padding-inline: var(--spacing-sm); margin-block-end: var(--spacing-2xs); }
747
+ .nav-item {
748
+ display: flex; align-items: center; gap: var(--spacing-sm);
749
+ height: var(--size-control-sm);
750
+ padding-inline: var(--spacing-sm);
751
+ border: 0; border-radius: var(--radius-md);
752
+ background: none;
753
+ color: var(--color-muted-foreground);
754
+ font: inherit; font-size: var(--type-size-body);
755
+ text-align: start; text-decoration: none;
756
+ cursor: pointer;
757
+ width: 100%;
758
+ }
759
+ .nav-item .icon { color: var(--color-subtle-foreground); }
760
+ .nav-item:hover { background: var(--color-accent-surface-hover); color: var(--color-foreground); text-decoration: none; }
761
+ .nav-item[aria-current="page"], .nav-item.active {
762
+ background: var(--color-selected);
763
+ box-shadow: inset 2px 0 0 var(--color-primary);
764
+ color: var(--color-selected-foreground);
765
+ font-weight: var(--type-weight-medium);
766
+ }
767
+ .nav-item[aria-current="page"] .icon, .nav-item.active .icon { color: currentColor; }
768
+ .nav-item .badge { margin-inline-start: auto; }
769
+
770
+ .brand { display: flex; align-items: center; gap: var(--spacing-sm); min-width: 0; }
771
+ .brand-mark {
772
+ display: grid; place-items: center;
773
+ width: var(--size-control-sm); height: var(--size-control-sm);
774
+ flex: none;
775
+ border-radius: var(--radius-lg);
776
+ background: var(--color-primary);
777
+ color: var(--color-primary-foreground);
778
+ font-weight: var(--type-weight-bold);
779
+ font-size: var(--type-size-label);
780
+ }
781
+
782
+ .topbar {
783
+ display: flex; align-items: center; gap: var(--spacing-md);
784
+ height: var(--size-control-lg);
785
+ min-height: 52px;
786
+ padding-inline: var(--spacing-lg);
787
+ border-bottom: 1px solid var(--color-border);
788
+ background: var(--color-background);
789
+ position: sticky; top: 0; z-index: 20;
790
+ }
791
+
792
+ .avatar {
793
+ display: grid; place-items: center;
794
+ width: var(--size-control-sm); height: var(--size-control-sm);
795
+ flex: none;
796
+ border-radius: var(--radius-full);
797
+ background: var(--color-secondary);
798
+ color: var(--color-secondary-foreground);
799
+ font-size: var(--type-size-metadata);
800
+ font-weight: var(--type-weight-medium);
801
+ }
802
+
803
+ .page { padding: var(--spacing-xl); display: grid; gap: var(--spacing-xl); align-content: start; max-width: var(--size-content-max); }
804
+ .page-header { display: grid; gap: var(--spacing-2xs); }
805
+
806
+ /* ===========================================================================
807
+ Developer-oriented surfaces (Kiso: developer-oriented-interfaces pattern)
808
+ =========================================================================== */
809
+ code {
810
+ padding: 1px var(--spacing-xs);
811
+ border-radius: var(--radius-xs);
812
+ background: var(--color-muted);
813
+ border: 1px solid var(--color-border);
814
+ }
815
+ pre {
816
+ position: relative;
817
+ margin: 0;
818
+ padding: var(--spacing-md);
819
+ border: 1px solid var(--color-border);
820
+ border-radius: var(--radius-surface);
821
+ background: var(--color-muted);
822
+ overflow-x: auto;
823
+ font-size: var(--type-size-label);
824
+ line-height: var(--type-line-height-relaxed);
825
+ }
826
+ pre code { padding: 0; background: none; border: 0; }
827
+
828
+ .kv { display: grid; grid-template-columns: minmax(96px, auto) minmax(0, 1fr); gap: var(--spacing-sm) var(--spacing-lg); font-size: var(--type-size-body); }
829
+ .kv dt { color: var(--color-muted-foreground); font-size: var(--type-size-label); }
830
+ .kv dd { margin: 0; font-family: var(--font-mono); font-size: var(--type-size-label); overflow-wrap: anywhere; }
831
+
832
+ .logview {
833
+ position: relative;
834
+ background: var(--color-neutral-950);
835
+ color: var(--color-neutral-300);
836
+ border: 1px solid var(--color-border);
837
+ border-radius: var(--radius-surface);
838
+ padding: var(--spacing-md);
839
+ font-family: var(--font-mono);
840
+ font-size: var(--type-size-label);
841
+ line-height: var(--type-line-height-relaxed);
842
+ overflow: auto;
843
+ }
844
+ .logview .log-time { color: var(--color-neutral-600); margin-inline-end: var(--spacing-sm); }
845
+ .logview .log-warn { color: var(--color-warning-on-dark); }
846
+ .logview .log-error{ color: var(--color-danger-on-dark); }
847
+ .logview .log-info { color: var(--color-info-on-dark); }
848
+
849
+ /* Sparkline / bar chart placeholders, neutral-only per the brand rules. */
850
+ .bars { display: flex; align-items: flex-end; gap: 3px; height: 40px; }
851
+ .bars i { flex: 1; background: var(--color-border-strong); border-radius: var(--radius-xs); }
852
+ .bars i.on { background: var(--color-primary); }
853
+
854
+ /* ===========================================================================
855
+ Touch targets: the 44px rule applies to coarse pointers only.
856
+ This is the whole reason the desktop UI can be 36px.
857
+ =========================================================================== */
858
+ @media (pointer: coarse) {
859
+ .btn, .input, .select, .nav-item, .menu-item {
860
+ min-height: var(--size-touch-min);
861
+ }
862
+ .btn-icon { min-width: var(--size-touch-min); }
863
+ }
864
+
865
+ @media (max-width: 1023px) {
866
+ .app-shell { grid-template-columns: 1fr; }
867
+ .sidebar { display: none; }
868
+ }
869
+
870
+
871
+ /* ===========================================================================
872
+ Corner marks — the "blueprint" corner treatment
873
+ ---------------------------------------------------------------------------
874
+ An open registration mark on each corner: two 1px ticks, each lying along
875
+ the frame line it extends and stopping `--corner-mark-gap` short of it, so
876
+ the mark points at the corner without touching it.
877
+
878
+ Deliberately two ticks and not four. A full cross puts its other two arms
879
+ directly on top of the panel border, where they are invisible — the mark
880
+ read as a bracket anyway. Dropping them halves the paint and makes the
881
+ hollow centre explicit instead of accidental.
882
+
883
+ Eight 1px gradient bars on one pseudo-element. No markup, no images, and
884
+ `--corner-mark: 0` removes them entirely.
885
+ =========================================================================== */
886
+ .card::after,
887
+ .dialog::after,
888
+ .table-wrap::after,
889
+ .logview::after,
890
+ .marked::after,
891
+ pre::after {
892
+ content: "";
893
+ position: absolute;
894
+ /* Reach far enough out that a tick clears the frame by the gap. */
895
+ inset: calc(-1 * (var(--corner-mark-tick) + var(--corner-mark-gap)));
896
+ pointer-events: none;
897
+ opacity: var(--corner-mark);
898
+ background-repeat: no-repeat;
899
+ background-image:
900
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
901
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
902
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
903
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
904
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
905
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
906
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
907
+ linear-gradient(var(--color-corner-mark), var(--color-corner-mark));
908
+ background-size:
909
+ var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick),
910
+ var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick),
911
+ var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick),
912
+ var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick);
913
+ /* The offset lands each tick exactly on the 1px frame line it extends. */
914
+ background-position:
915
+ left 0 top calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
916
+ left calc(var(--corner-mark-tick) + var(--corner-mark-gap)) top 0,
917
+ right 0 top calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
918
+ right calc(var(--corner-mark-tick) + var(--corner-mark-gap)) top 0,
919
+ left 0 bottom calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
920
+ left calc(var(--corner-mark-tick) + var(--corner-mark-gap)) bottom 0,
921
+ right 0 bottom calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
922
+ right calc(var(--corner-mark-tick) + var(--corner-mark-gap)) bottom 0;
923
+ }
924
+ .marked { position: relative; }
925
+
926
+ /* ===========================================================================
927
+ Hatch — "this region is not data"
928
+ ---------------------------------------------------------------------------
929
+ Companion to the corner marks. Three sanctioned uses, and no others:
930
+ .hatch on an empty state nothing here yet
931
+ .hatch on a chrome band this strip is title/controls, not content
932
+ .hatch on an unavailable pane the data does not exist right now
933
+
934
+ The stripe colour is one step off the surface it sits on, so text stays
935
+ legible on top of it. Do not raise the contrast to make it "read better" —
936
+ if it is loud enough to notice while reading, it is in the wrong place.
937
+ =========================================================================== */
938
+ .hatch {
939
+ background-image: repeating-linear-gradient(
940
+ var(--hatch-angle),
941
+ var(--color-hatch) 0,
942
+ var(--color-hatch) var(--hatch-line),
943
+ transparent var(--hatch-line),
944
+ transparent var(--hatch-period)
945
+ );
946
+ }
947
+ /* An empty region *is* the message, so empty states are the primary use. */
948
+ .empty.hatch { background-color: var(--color-card); }
949
+
950
+ /* A chrome band inside a panel — title, breadcrumb, controls. */
951
+ .band {
952
+ padding: var(--spacing-lg);
953
+ border-bottom: 1px solid var(--color-border);
954
+ }
955
+ .band > * { position: relative; }
956
+
957
+ /* ===========================================================================
958
+ Split pane (list-detail with a resizable divider)
959
+ =========================================================================== */
960
+ .split { display: flex; min-width: 0; }
961
+ .split > .pane { min-width: 0; overflow: auto; }
962
+ .splitter { flex: none; width: 1px; background: var(--color-border); cursor: col-resize; position: relative; }
963
+ .splitter::after { content: ""; position: absolute; inset-block: 0; inset-inline: -3px; }
964
+ .splitter:hover, .splitter.dragging { background: var(--color-ring); }
965
+
966
+ /* Chart frame: neutral only, gridlines at border strength. */
967
+ .chart { width: 100%; height: 200px; display: block; overflow: visible; color: var(--color-primary); }
968
+ .chart .grid { stroke: var(--color-border); stroke-width: 1; }
969
+ .chart .line { fill: none; stroke: var(--color-primary); stroke-width: 1.5; }
970
+ .chart .area { fill: url(#chart-fill); }
971
+ .chart-axis { display: flex; justify-content: space-between; font-size: var(--type-size-metadata); color: var(--color-subtle-foreground); margin-block-start: var(--spacing-sm); }