@momoi-labs/kiso 0.10.0 → 0.12.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/docs/components/README.md +7 -0
- package/kiso/docs/components/accent-selector.md +136 -0
- package/kiso/docs/components/card.md +11 -5
- package/kiso/docs/components/drawer.md +1 -1
- package/kiso/docs/components/form-actions.md +145 -0
- package/kiso/docs/components/form-field.md +3 -0
- package/kiso/docs/components/form.md +102 -0
- package/kiso/docs/components/modal-dialog.md +1 -1
- package/kiso/docs/components/step-bar.md +57 -0
- package/kiso/docs/components/step-list.md +86 -0
- package/kiso/docs/components/theme-selector.md +4 -2
- package/kiso/docs/components/time-range-control.md +6 -0
- package/kiso/docs/evolution.md +2 -1
- package/kiso/docs/patterns/crud.md +15 -2
- package/kiso/docs/patterns/settings.md +21 -2
- package/kiso/docs/tokens.md +100 -9
- package/kiso/ui.css +244 -39
- package/package.json +1 -1
- package/tokens/build/tokens.css +179 -16
- package/tokens/build/tokens.d.ts +184 -23
- package/tokens/build/tokens.json +160 -12
- package/tokens/build/tokens.scss +161 -13
package/kiso/docs/evolution.md
CHANGED
|
@@ -13,7 +13,7 @@ the system needs them. This is the honest roadmap for those choices.
|
|
|
13
13
|
| **Figma Tokens Studio integration** | [Epic #2](https://github.com/momoi-labs/blueprint/issues/2) kept the token pipeline focused on its committed outputs. Tokens Studio is a Figma plugin workflow built through Style Dictionary and `@tokens-studio/sd-transforms`, not a standalone emitter. | When design-to-code synchronization through Figma becomes a real team workflow rather than a hypothetical integration. |
|
|
14
14
|
| **DTCG 2025.10 Resolver module** | The multiple-context and theme Resolver considered in [epic #2](https://github.com/momoi-labs/blueprint/issues/2) is a preview draft marked “do not implement.” V1 uses an explicit, stable theme model instead. | When the Resolver module reaches stable status and Kiso has a concrete context or theme problem it would solve. |
|
|
15
15
|
| **`--shadow-lg`** | The elevation scale intentionally stops at `--shadow-sm` and `--shadow-md`; [#25](https://github.com/momoi-labs/blueprint/issues/25) fixed component references without inventing a larger elevation. | When a real overlay or hierarchy cannot be expressed clearly with `--shadow-md`. Propose the token in the source, then regenerate its outputs. |
|
|
16
|
-
| **A dedicated multi-step-flow pattern** | [#26](https://github.com/momoi-labs/blueprint/issues/26) added step indication as a Pagination variant, which satisfies the current bounded-flow need without another pattern. | When recurring
|
|
16
|
+
| **A dedicated multi-step-flow pattern** | [#26](https://github.com/momoi-labs/blueprint/issues/26) added step indication as a Pagination variant, which satisfies the current bounded-flow need without another pattern. [#98](https://github.com/momoi-labs/blueprint/issues/98) added StepList for the other case, a run a machine walks and a person reads; person-driven flows still use Pagination. | When recurring person-driven flows need behavior, composition, or guidance beyond Pagination's scope. |
|
|
17
17
|
| **Additional patterns** | The pattern set from [epic #4](https://github.com/momoi-labs/blueprint/issues/4) is an intentionally lean cut of roughly 21 recurring product structures. Speculative completeness would encode guesses. | When a real product exposes a repeated structure that the current patterns cannot express without an ad-hoc solution. |
|
|
18
18
|
| **Additional components** | The roughly 28-component cut from [epic #3](https://github.com/momoi-labs/blueprint/issues/3) covers the intended v1 product surface. Adding primitives in anticipation would enlarge the interface before their contracts are understood. | When a need recurs across products. Propose a component and its contract; do not invent one locally or copy one in unchanged. |
|
|
19
19
|
| **Heavy governance** | A two-person lab does not need a contribution bureaucracy or design-review board. For v1, the propose-don't-copy rule in [`kiso/AGENTS.md`](../AGENTS.md) is the governance mechanism, as scoped by [epic #5](https://github.com/momoi-labs/blueprint/issues/5). | When more contributors, products, or incompatible proposals make ownership and decision-making unclear. Add only the process needed to resolve an observed coordination problem. |
|
|
@@ -31,6 +31,7 @@ The growth model below is not theory. What it has produced so far:
|
|
|
31
31
|
| What | Evidence | Where |
|
|
32
32
|
| --- | --- | --- |
|
|
33
33
|
| **[ChipInput](components/chip-input.md)** | A self-hosted console had to collect a development image's dependencies: a list a person types, where every entry carries a backend, a version, and installer options. One form section per entry grew without limit and buried the list. | Added as a component contract with the segmented chip, the in-place value, and one segment per option. |
|
|
34
|
+
| **[StepList](components/step-list.md) and [StepBar](components/step-bar.md)** | The self-host console's Last run tab walks a machine through eleven lifecycle steps over several minutes and wrote its own list of steps with a state each, replacing a progress bar and a two-thousand-line log to search. An image build and the Host's own bootstrap were about to copy it. [#98](https://github.com/momoi-labs/blueprint/issues/98) records the evidence. | Added as two contracts: the list inside a Split with the step's LogView beside it, and the bar for a summary, a table cell, or a toast. |
|
|
34
35
|
| **[Sparkline](components/sparkline.md)** | The self-host console collects metrics in-process, one sample per tick on an evenly spaced window, and needed the same shape three times over: a trend cell per application row, context under a KPI value, and one series per container. [#84](https://github.com/momoi-labs/blueprint/issues/84) records the evidence. | Added as a component contract and a Recharts-based component, single series, neutral by default, primary only for the series a tile is about. |
|
|
35
36
|
|
|
36
37
|
## Growth model: grow with real products
|
|
@@ -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
|
|
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;
|
|
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)
|
package/kiso/docs/tokens.md
CHANGED
|
@@ -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
|
|
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`,
|
|
@@ -219,9 +277,9 @@ Layout sizes: `--size-sidebar` (248px) is the shell navigation column;
|
|
|
219
277
|
`--size-icon-sm` (14px), `--size-icon-md` (16px, the default), and
|
|
220
278
|
`--size-icon-lg` (20px).
|
|
221
279
|
|
|
222
|
-
## Corners
|
|
280
|
+
## Corners and appearance
|
|
223
281
|
|
|
224
|
-
Panels are square. `--radius-surface` is `0px`, and a panel's corner treatment
|
|
282
|
+
Panels are square by default. `--radius-surface` is `0px`, and a panel's corner treatment
|
|
225
283
|
is a **corner mark** instead: two 1px ticks per corner, each lying along the
|
|
226
284
|
frame line it extends and stopping `--corner-mark-gap` short of it, so the mark
|
|
227
285
|
points at the corner without touching it.
|
|
@@ -238,8 +296,8 @@ the paint and makes the hollow centre explicit rather than accidental.
|
|
|
238
296
|
|
|
239
297
|
The gap **is** the mark. Close it and this is just a thicker border.
|
|
240
298
|
|
|
241
|
-
Marks appear on
|
|
242
|
-
|
|
299
|
+
Marks appear on panels by default. Applications can select another treatment
|
|
300
|
+
with the appearance attributes below.
|
|
243
301
|
|
|
244
302
|
The remaining radii only take the bite off controls:
|
|
245
303
|
|
|
@@ -250,7 +308,38 @@ The remaining radii only take the bite off controls:
|
|
|
250
308
|
| `--radius-md` | 4px | **Buttons, inputs, menu items** — the control default. |
|
|
251
309
|
| `--radius-lg` | 5px | Segmented tracks and other control groups. |
|
|
252
310
|
| `--radius-full` | 9999px | Pills, dots, switches, avatars. |
|
|
253
|
-
| `--radius-surface` | 0px | **Panels, cards, tables, dialogs**
|
|
311
|
+
| `--radius-surface` | 0px | **Panels, cards, tables, dialogs** by default. |
|
|
312
|
+
|
|
313
|
+
### Appearance attributes
|
|
314
|
+
|
|
315
|
+
Set these attributes on `<html>` so they also reach portalled dialogs and menus.
|
|
316
|
+
They ship in `@momoi-labs/kiso/ui.css`, which React's stylesheet imports.
|
|
317
|
+
No gallery CSS or JavaScript is required.
|
|
318
|
+
|
|
319
|
+
| Attribute | Values | Default when omitted |
|
|
320
|
+
| --- | --- | --- |
|
|
321
|
+
| `data-border-style` | `square`, `soft`, `round`, `asym`, `rail`, `dash`, `bevel`, `double`, `base`, `offset` | Square panels and existing control radii |
|
|
322
|
+
| `data-corner-size` | `off`, `small`, `medium`, `large` | `medium` |
|
|
323
|
+
| `data-corner-marks` | `none`, `ticks`, `brackets`, `arcs`, `dots` | `ticks` |
|
|
324
|
+
| `data-mark-size` | `small`, `medium`, `large` | `medium` |
|
|
325
|
+
|
|
326
|
+
`data-corner-size` scales the radii selected by `data-border-style`: `off`
|
|
327
|
+
sets them to zero; `small`, `medium`, and `large` use 0.5, 1, and 1.5 times
|
|
328
|
+
that style's radii. Square panels stay square and their control radii stay
|
|
329
|
+
unchanged unless the size is `off`. Size does not hide marks; use
|
|
330
|
+
`data-corner-marks="none"` for that.
|
|
331
|
+
|
|
332
|
+
Mark sizes set `--corner-mark-tick` and `--corner-mark-gap` to 2px/1px,
|
|
333
|
+
4px/2px, or 8px/4px. Border styles override the existing radius tokens.
|
|
334
|
+
The generated token defaults remain unchanged.
|
|
335
|
+
|
|
336
|
+
```html
|
|
337
|
+
<html lang="en" data-accent="terracotta" data-border-style="soft"
|
|
338
|
+
data-corner-size="small" data-corner-marks="arcs" data-mark-size="medium">
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Keep scrolling on `.log-scroll`, `.table-scroll`, dialog bodies, and
|
|
342
|
+
`pre > code`. The outer frame owns the marks, which extend outside it.
|
|
254
343
|
|
|
255
344
|
## Hatch
|
|
256
345
|
|
|
@@ -315,8 +404,10 @@ tokens to the same version.
|
|
|
315
404
|
## Categorical chart colors
|
|
316
405
|
|
|
317
406
|
Issue #93 adds `--color-chart-1` through `--color-chart-5` for series identity.
|
|
318
|
-
The roles derive from
|
|
319
|
-
and status.danger, in that order.
|
|
407
|
+
The roles derive from violet.base, status.success, status.warning, status.info,
|
|
408
|
+
and status.danger, in that order. `chart-1` is the violet ink under every
|
|
409
|
+
accent, not the active accent: a series must stay distinguishable from the
|
|
410
|
+
status series whatever the product's accent is. Their meaning inside a chart is categorical,
|
|
320
411
|
never health or severity. Existing status roles keep their meaning elsewhere.
|
|
321
412
|
|
|
322
413
|
Each slot meets 3:1 on background, surface, and elevated-surface in both
|
|
@@ -335,5 +426,5 @@ Keep the canonical slot order in stacks; changing adjacency needs review.
|
|
|
335
426
|
|
|
336
427
|
The calculation uses [Oklab](https://bottosson.github.io/posts/oklab/) and
|
|
337
428
|
[Machado's simulation model](https://pubmed.ncbi.nlm.nih.gov/19834201/).
|
|
338
|
-
Run `node scripts/check-chart-palette.mjs` for both themes. Numbered labels,
|
|
429
|
+
Run `node scripts/check-chart-palette.mjs` for both themes and every accent. Numbered labels,
|
|
339
430
|
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
|
|
@@ -762,6 +798,7 @@ table.table { width: 100%; border-collapse: collapse; font-size: var(--type-size
|
|
|
762
798
|
}
|
|
763
799
|
|
|
764
800
|
.palette {
|
|
801
|
+
position: relative;
|
|
765
802
|
width: 100%; max-width: 560px;
|
|
766
803
|
background: var(--color-popover);
|
|
767
804
|
border: 1px solid var(--color-border);
|
|
@@ -1036,59 +1073,171 @@ pre code { display: block; overflow-x: auto; padding: 0; background: none; borde
|
|
|
1036
1073
|
}
|
|
1037
1074
|
|
|
1038
1075
|
|
|
1039
|
-
/*
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1076
|
+
/* Appearance attributes. Set these on html to include portalled content. */
|
|
1077
|
+
:root {
|
|
1078
|
+
--appearance-scale: 1;
|
|
1079
|
+
--appearance-square-scale: 1;
|
|
1080
|
+
--appearance-panel-shadow: 0 0 transparent;
|
|
1081
|
+
--appearance-panel-border: solid;
|
|
1082
|
+
}
|
|
1083
|
+
[data-corner-size="off"] { --appearance-scale: 0; --appearance-square-scale: 0; }
|
|
1084
|
+
[data-corner-size="small"] { --appearance-scale: .5; }
|
|
1085
|
+
[data-corner-size="medium"] { --appearance-scale: 1; }
|
|
1086
|
+
[data-corner-size="large"] { --appearance-scale: 1.5; }
|
|
1087
|
+
[data-border-style] {
|
|
1088
|
+
--appearance-base-radius: 8px;
|
|
1089
|
+
--appearance-control-base: 4px;
|
|
1090
|
+
--appearance-panel-border: solid;
|
|
1091
|
+
--appearance-panel-shadow: 0 0 transparent;
|
|
1092
|
+
--appearance-overlay-content: none;
|
|
1093
|
+
--appearance-footer-start: var(--radius-surface);
|
|
1094
|
+
--appearance-overlay-inset: 0;
|
|
1095
|
+
--appearance-overlay-border: 0;
|
|
1096
|
+
--appearance-overlay-radius: var(--appearance-corners);
|
|
1097
|
+
--radius-surface: calc(var(--appearance-base-radius) * var(--appearance-scale));
|
|
1098
|
+
--radius-md: calc(var(--appearance-control-base) * var(--appearance-scale));
|
|
1099
|
+
--radius-xs: calc(var(--radius-md) / 2);
|
|
1100
|
+
--radius-sm: calc(var(--radius-md) * .75);
|
|
1101
|
+
--radius-lg: calc(var(--radius-md) * 1.25);
|
|
1102
|
+
--appearance-corners: var(--radius-surface);
|
|
1103
|
+
--appearance-control-corners: var(--radius-md);
|
|
1104
|
+
}
|
|
1105
|
+
[data-border-style="square"] {
|
|
1106
|
+
--appearance-base-radius: 0px;
|
|
1107
|
+
--radius-xs: calc(2px * var(--appearance-square-scale));
|
|
1108
|
+
--radius-sm: calc(3px * var(--appearance-square-scale));
|
|
1109
|
+
--radius-md: calc(4px * var(--appearance-square-scale));
|
|
1110
|
+
--radius-lg: calc(5px * var(--appearance-square-scale));
|
|
1111
|
+
}
|
|
1112
|
+
[data-border-style="soft"] { --appearance-base-radius: 8px; }
|
|
1113
|
+
[data-border-style="round"] { --appearance-base-radius: 16px; --appearance-control-base: 8px; }
|
|
1114
|
+
[data-border-style="asym"] {
|
|
1115
|
+
--appearance-footer-start: calc(3px * var(--appearance-scale));
|
|
1116
|
+
--appearance-base-radius: 12px;
|
|
1117
|
+
--appearance-control-base: 6px;
|
|
1118
|
+
--appearance-corners: var(--radius-surface) calc(3px * var(--appearance-scale));
|
|
1119
|
+
--appearance-control-corners: var(--radius-md) calc(2px * var(--appearance-scale));
|
|
1120
|
+
}
|
|
1121
|
+
[data-border-style="rail"] { --appearance-overlay-content: ""; --appearance-base-radius: 6px; --appearance-control-base: 3px; --appearance-panel-shadow: inset 3px 0 var(--color-border-strong); }
|
|
1122
|
+
[data-border-style="dash"] { --appearance-panel-border: dashed; }
|
|
1123
|
+
[data-border-style="bevel"] { --appearance-overlay-content: ""; --appearance-panel-shadow: inset 1px 1px 1px var(--color-shadow-contact), inset -1px -1px var(--color-border-strong); }
|
|
1124
|
+
[data-border-style="double"] { --appearance-overlay-content: ""; --appearance-overlay-inset: 3px; --appearance-overlay-border: 1px solid var(--color-border); --appearance-overlay-radius: max(0px, calc(var(--radius-surface) - 3px)); }
|
|
1125
|
+
[data-border-style="base"] { --appearance-overlay-content: "";
|
|
1126
|
+
/* Match the outer frame so the thick base covers its bottom hairline. */
|
|
1127
|
+
--appearance-overlay-inset: -1px;
|
|
1128
|
+
--appearance-panel-shadow: inset 0 -3px var(--color-border-strong);
|
|
1129
|
+
}
|
|
1130
|
+
[data-border-style="offset"] { --appearance-overlay-content: "";
|
|
1131
|
+
--appearance-overlay-inset: -1px;
|
|
1132
|
+
/* An opaque, hard shadow keeps underlying content out of the offset. */
|
|
1133
|
+
--appearance-panel-shadow: 3px 3px 0 0 var(--color-border-strong);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
:where([data-border-style]) :is(.card, .dialog, .table-wrap, .logview, .marked, .palette, pre) {
|
|
1137
|
+
border-radius: var(--appearance-corners);
|
|
1138
|
+
border-style: var(--appearance-panel-border);
|
|
1139
|
+
}
|
|
1140
|
+
/* Paint decorative edges above table headers and panel footers. */
|
|
1141
|
+
:is(.card, .dialog, .table-wrap, .logview, .marked, .palette, pre)::before {
|
|
1142
|
+
content: var(--appearance-overlay-content, none);
|
|
1143
|
+
position: absolute;
|
|
1144
|
+
inset: var(--appearance-overlay-inset);
|
|
1145
|
+
border: var(--appearance-overlay-border);
|
|
1146
|
+
border-radius: var(--appearance-overlay-radius);
|
|
1147
|
+
box-shadow: var(--appearance-panel-shadow);
|
|
1148
|
+
pointer-events: none;
|
|
1149
|
+
z-index: 1;
|
|
1150
|
+
}
|
|
1151
|
+
:where([data-border-style]) .palette { overflow: visible; }
|
|
1152
|
+
:where([data-border-style]) .palette-list { border-end-start-radius: var(--radius-surface); border-end-end-radius: var(--radius-surface); }
|
|
1153
|
+
:where([data-border-style]) :is(.card-footer, .dialog-footer) {
|
|
1154
|
+
border-end-start-radius: var(--appearance-footer-start);
|
|
1155
|
+
border-end-end-radius: var(--radius-surface);
|
|
1156
|
+
}
|
|
1157
|
+
:where([data-border-style]) :is(.btn:not(.btn-xs), .input, .select, .textarea, .nav-item, .menu-item) {
|
|
1158
|
+
border-radius: var(--appearance-control-corners);
|
|
1159
|
+
}
|
|
1050
1160
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1161
|
+
[data-mark-size="small"] { --corner-mark-tick: 2px; --corner-mark-gap: 1px; }
|
|
1162
|
+
[data-mark-size="medium"] { --corner-mark-tick: 4px; --corner-mark-gap: 2px; }
|
|
1163
|
+
[data-mark-size="large"] { --corner-mark-tick: 8px; --corner-mark-gap: 4px; }
|
|
1164
|
+
[data-corner-marks] {
|
|
1165
|
+
--corner-mark: 1;
|
|
1166
|
+
--appearance-palette-marks: "";
|
|
1167
|
+
--appearance-mark-mask: none;
|
|
1168
|
+
--appearance-mark-bg: transparent;
|
|
1169
|
+
--appearance-mark-inset: initial;
|
|
1170
|
+
--appearance-mark-images: initial;
|
|
1171
|
+
}
|
|
1172
|
+
[data-corner-marks="none"] { --corner-mark: 0; }
|
|
1173
|
+
:is(.card, .dialog, .table-wrap, .logview, .marked, .palette, pre)::after {
|
|
1060
1174
|
content: "";
|
|
1061
1175
|
position: absolute;
|
|
1062
|
-
/* Reach far enough out that a tick clears the frame by the gap. */
|
|
1063
|
-
inset: calc(-1 * (var(--corner-mark-tick) + var(--corner-mark-gap)));
|
|
1064
1176
|
pointer-events: none;
|
|
1065
1177
|
opacity: var(--corner-mark);
|
|
1066
1178
|
background-repeat: no-repeat;
|
|
1067
|
-
background-image:
|
|
1068
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1069
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1070
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1071
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1072
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1073
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1074
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1075
|
-
linear-gradient(var(--color-corner-mark), var(--color-corner-mark));
|
|
1076
1179
|
background-size:
|
|
1077
1180
|
var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick),
|
|
1078
1181
|
var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick),
|
|
1079
1182
|
var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick),
|
|
1080
1183
|
var(--corner-mark-tick) 1px, 1px var(--corner-mark-tick);
|
|
1081
|
-
/* The offset lands each tick exactly on the 1px frame line it extends. */
|
|
1082
1184
|
background-position:
|
|
1083
|
-
left 0 top
|
|
1084
|
-
left
|
|
1085
|
-
right 0 top
|
|
1185
|
+
left 0 top calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
|
|
1186
|
+
left calc(var(--corner-mark-tick) + var(--corner-mark-gap)) top 0,
|
|
1187
|
+
right 0 top calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
|
|
1086
1188
|
right calc(var(--corner-mark-tick) + var(--corner-mark-gap)) top 0,
|
|
1087
|
-
left 0 bottom
|
|
1088
|
-
left
|
|
1189
|
+
left 0 bottom calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
|
|
1190
|
+
left calc(var(--corner-mark-tick) + var(--corner-mark-gap)) bottom 0,
|
|
1089
1191
|
right 0 bottom calc(var(--corner-mark-tick) + var(--corner-mark-gap)),
|
|
1090
1192
|
right calc(var(--corner-mark-tick) + var(--corner-mark-gap)) bottom 0;
|
|
1091
|
-
|
|
1193
|
+
inset: var(--appearance-mark-inset, calc(-1 * (var(--corner-mark-tick) + var(--corner-mark-gap))));
|
|
1194
|
+
background-image: var(--appearance-mark-images,
|
|
1195
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1196
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1197
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1198
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1199
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1200
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1201
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)),
|
|
1202
|
+
linear-gradient(var(--color-corner-mark), var(--color-corner-mark)));
|
|
1203
|
+
background-color: var(--appearance-mark-bg, transparent);
|
|
1204
|
+
mask-image: var(--appearance-mark-mask, none);
|
|
1205
|
+
mask-size: calc(var(--corner-mark-tick) + 1px) calc(var(--corner-mark-tick) + 1px);
|
|
1206
|
+
mask-position: left top, right top, left bottom, right bottom;
|
|
1207
|
+
mask-repeat: no-repeat;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
[data-corner-marks="brackets"] {
|
|
1211
|
+
--appearance-mark-images: none;
|
|
1212
|
+
--appearance-mark-bg: var(--color-corner-mark);
|
|
1213
|
+
--appearance-mark-inset: calc(-1 * (var(--corner-mark-gap) + 1px));
|
|
1214
|
+
--appearance-mark-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5V.5H9.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1215
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%2810%200%29%20scale%28-1%201%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5V.5H9.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1216
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%280%2010%29%20scale%281%20-1%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5V.5H9.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1217
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%2810%2010%29%20scale%28-1%20-1%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5V.5H9.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
[data-corner-marks="arcs"] {
|
|
1221
|
+
--appearance-mark-images: none;
|
|
1222
|
+
--appearance-mark-bg: var(--color-corner-mark);
|
|
1223
|
+
--appearance-mark-inset: calc(-1 * (var(--corner-mark-gap) + 1px));
|
|
1224
|
+
--appearance-mark-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5Q.5%20.5%209.5%20.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1225
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%2810%200%29%20scale%28-1%201%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5Q.5%20.5%209.5%20.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1226
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%280%2010%29%20scale%281%20-1%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5Q.5%20.5%209.5%20.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1227
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%2810%2010%29%20scale%28-1%20-1%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Cpath%20d%3D%22M.5%209.5Q.5%20.5%209.5%20.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
[data-corner-marks="dots"] {
|
|
1231
|
+
--appearance-mark-images: none;
|
|
1232
|
+
--appearance-mark-bg: var(--color-corner-mark);
|
|
1233
|
+
--appearance-mark-inset: calc(-1 * (var(--corner-mark-gap) + 1px));
|
|
1234
|
+
--appearance-mark-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%223%22%20fill%3D%22black%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1235
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%2810%200%29%20scale%28-1%201%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%223%22%20fill%3D%22black%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1236
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%280%2010%29%20scale%281%20-1%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%223%22%20fill%3D%22black%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
|
|
1237
|
+
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2010%2010%22%3E%3Cg%20transform%3D%22translate%2810%2010%29%20scale%28-1%20-1%29%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20%3E%3Ccircle%20cx%3D%225%22%20cy%3D%225%22%20r%3D%223%22%20fill%3D%22black%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
.palette::after { content: var(--appearance-palette-marks, none); }
|
|
1092
1241
|
.marked { position: relative; }
|
|
1093
1242
|
|
|
1094
1243
|
/* ===========================================================================
|
|
@@ -1185,7 +1334,7 @@ pre::after {
|
|
|
1185
1334
|
.time-range-presets small { color: var(--color-muted-foreground); font-weight: var(--type-weight-regular); }
|
|
1186
1335
|
.meter[data-slot="progress"] .meter-track > span { background: var(--color-chart-1); }
|
|
1187
1336
|
.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; }
|
|
1337
|
+
.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
1338
|
@media (max-width: 1024px) {
|
|
1190
1339
|
.dashboard-panel { grid-column: span 6; }
|
|
1191
1340
|
.dashboard-panel[data-span="12"] { grid-column: span 12; }
|
|
@@ -1198,6 +1347,52 @@ pre::after {
|
|
|
1198
1347
|
.disclosure > summary { min-height: var(--size-touch-min); display: list-item; align-content: center; }
|
|
1199
1348
|
}
|
|
1200
1349
|
|
|
1350
|
+
/* StepList and StepBar, issue #98. A run's steps, walked by a machine and
|
|
1351
|
+
read by a person. The rail is the progress: each connector takes the state
|
|
1352
|
+
of the step below it, so the line fills as the run advances. Running is the
|
|
1353
|
+
success colour because it is alive; neutral is what is not happening. */
|
|
1354
|
+
.step-list { list-style: none; margin: 0; padding: 0; display: grid; }
|
|
1355
|
+
.step { display: grid; grid-template-columns: var(--spacing-xl) minmax(0, 1fr); column-gap: var(--spacing-sm); }
|
|
1356
|
+
.step-rail { position: relative; display: grid; justify-items: center; }
|
|
1357
|
+
.step-rail::before { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 3px; translate: -50% 0; background: var(--color-secondary); }
|
|
1358
|
+
.step:first-child .step-rail::before { top: 12px; }
|
|
1359
|
+
.step:last-child .step-rail::before { bottom: auto; height: 12px; }
|
|
1360
|
+
.step[data-state="done"] .step-rail::before, .step[data-state="skipped"] .step-rail::before { background: var(--color-success); }
|
|
1361
|
+
.step[data-state="running"] .step-rail::before { background: linear-gradient(var(--color-success) 0 12px, var(--color-secondary) 12px 100%); }
|
|
1362
|
+
.step[data-state="failed"] .step-rail::before { background: linear-gradient(var(--color-success) 0 12px, var(--color-danger) 12px 100%); }
|
|
1363
|
+
.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); }
|
|
1364
|
+
.step[data-state="done"] .step-mark { background: var(--color-success); border-color: var(--color-success); }
|
|
1365
|
+
.step[data-state="skipped"] .step-mark { border-color: var(--color-success); }
|
|
1366
|
+
.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; }
|
|
1367
|
+
.step[data-state="failed"] .step-mark { background: var(--color-danger); border-color: var(--color-danger); }
|
|
1368
|
+
/* 12px dot plus 6px of glow fits the 24px rail column, which a Pane clips at its edge. */
|
|
1369
|
+
@keyframes step-pulse { 50% { box-shadow: 0 0 0 6px transparent; } }
|
|
1370
|
+
.step-body { min-width: 0; padding-bottom: var(--spacing-sm); }
|
|
1371
|
+
.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; }
|
|
1372
|
+
button.step-row { cursor: pointer; }
|
|
1373
|
+
button.step-row:hover .step-label { text-decoration: underline; text-underline-offset: var(--spacing-2xs); }
|
|
1374
|
+
button.step-row:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; border-radius: var(--radius-sm); }
|
|
1375
|
+
.step-label { font-size: var(--type-size-label); font-weight: var(--type-weight-medium); }
|
|
1376
|
+
.step[data-state="pending"] .step-label, .step[data-state="skipped"] .step-label { color: var(--color-muted-foreground); font-weight: var(--type-weight-regular); }
|
|
1377
|
+
.step[data-state="running"] .step-label, .step[data-state="failed"] .step-label { font-weight: var(--type-weight-semibold); }
|
|
1378
|
+
.step[data-state="failed"] .step-label { color: var(--color-danger); }
|
|
1379
|
+
.step-row[aria-pressed="true"] .step-label { text-decoration: underline; text-underline-offset: var(--spacing-2xs); }
|
|
1380
|
+
.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; }
|
|
1381
|
+
.step-detail { margin-top: var(--spacing-sm); }
|
|
1382
|
+
@media (pointer: coarse) {
|
|
1383
|
+
button.step-row { min-height: var(--size-touch-min); }
|
|
1384
|
+
}
|
|
1385
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1386
|
+
.step[data-state="running"] .step-mark { animation: none; }
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
.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; }
|
|
1390
|
+
.step-bar > span { border-radius: var(--radius-xs); background: var(--color-secondary); }
|
|
1391
|
+
.step-bar > span[data-state="done"] { background: var(--color-success); }
|
|
1392
|
+
.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%); }
|
|
1393
|
+
.step-bar > span[data-state="skipped"] { background: repeating-linear-gradient(45deg, var(--color-success) 0 2px, transparent 2px 5px); }
|
|
1394
|
+
.step-bar > span[data-state="failed"] { background: var(--color-danger); }
|
|
1395
|
+
|
|
1201
1396
|
/* Chart presentation options. Exact values remain available in every layout. */
|
|
1202
1397
|
.chart-body, .chart-plots { min-width: 0; }
|
|
1203
1398
|
.framed-chart[data-legend="sidebar"] .chart-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(140px, 180px); gap: var(--spacing-lg); }
|
|
@@ -1223,3 +1418,13 @@ pre::after {
|
|
|
1223
1418
|
@media (pointer: coarse) {
|
|
1224
1419
|
.chart-series-button { min-height: var(--size-touch-min); min-width: var(--size-touch-min); }
|
|
1225
1420
|
}
|
|
1421
|
+
|
|
1422
|
+
/* Respect reduced motion in every consumer, including React controls. */
|
|
1423
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1424
|
+
*,
|
|
1425
|
+
*::before,
|
|
1426
|
+
*::after {
|
|
1427
|
+
animation: none !important;
|
|
1428
|
+
transition: none !important;
|
|
1429
|
+
}
|
|
1430
|
+
}
|