@tensor_1/tokens 2.55.3 → 2.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,155 @@
1
+ /* uix file kit (2.57) — FileKindIcon, FileRow, FileDrop. One hue per kind of file (--uix-file-<kind>):
2
+ the icon draws in it, a row's left edge carries its tint, an upload fills with it, and a drop row
3
+ takes the colours of what is dragged over it. Depends only on --uix-* tokens. */
4
+ @layer uix.components {
5
+ /* Kind plumbing: every piece reads --file-kind*. */
6
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="img"] { --file-kind: var(--uix-file-img); --file-kind-soft: var(--uix-file-img-soft); --file-kind-strong: var(--uix-file-img-strong); --file-kind-edge: var(--uix-file-img-edge); --file-kind-label: var(--uix-file-img-label); }
7
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="doc"] { --file-kind: var(--uix-file-doc); --file-kind-soft: var(--uix-file-doc-soft); --file-kind-strong: var(--uix-file-doc-strong); --file-kind-edge: var(--uix-file-doc-edge); --file-kind-label: var(--uix-file-doc-label); }
8
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="sheet"] { --file-kind: var(--uix-file-sheet); --file-kind-soft: var(--uix-file-sheet-soft); --file-kind-strong: var(--uix-file-sheet-strong); --file-kind-edge: var(--uix-file-sheet-edge); --file-kind-label: var(--uix-file-sheet-label); }
9
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="mail"] { --file-kind: var(--uix-file-mail); --file-kind-soft: var(--uix-file-mail-soft); --file-kind-strong: var(--uix-file-mail-strong); --file-kind-edge: var(--uix-file-mail-edge); --file-kind-label: var(--uix-file-mail-label); }
10
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="code"] { --file-kind: var(--uix-file-code); --file-kind-soft: var(--uix-file-code-soft); --file-kind-strong: var(--uix-file-code-strong); --file-kind-edge: var(--uix-file-code-edge); --file-kind-label: var(--uix-file-code-label); }
11
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="log"] { --file-kind: var(--uix-file-log); --file-kind-soft: var(--uix-file-log-soft); --file-kind-strong: var(--uix-file-log-strong); --file-kind-edge: var(--uix-file-log-edge); --file-kind-label: var(--uix-file-log-label); }
12
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="archive"] { --file-kind: var(--uix-file-archive); --file-kind-soft: var(--uix-file-archive-soft); --file-kind-strong: var(--uix-file-archive-strong); --file-kind-edge: var(--uix-file-archive-edge); --file-kind-label: var(--uix-file-archive-label); }
13
+ :is(.uix-file-icon, .uix-file-row, .uix-file-drop)[data-file-kind="other"] { --file-kind: var(--uix-file-other); --file-kind-soft: var(--uix-file-other-soft); --file-kind-strong: var(--uix-file-other-strong); --file-kind-edge: var(--uix-file-other-edge); --file-kind-label: var(--uix-file-other-label); }
14
+
15
+ /* A blocked file is amber and a failed upload red, in place of the kind (icon included). */
16
+ .uix-file-row[data-state="blocked"], .uix-file-row[data-state="blocked"] .uix-file-icon {
17
+ --file-kind: var(--uix-warning-text); --file-kind-soft: var(--uix-warning-bg); --file-kind-strong: var(--uix-warning-bg);
18
+ --file-kind-edge: color-mix(in srgb, var(--uix-warning-border) 30%, var(--uix-border)); --file-kind-label: var(--uix-warning-text);
19
+ }
20
+ .uix-file-row[data-state="failed"], .uix-file-row[data-state="failed"] .uix-file-icon {
21
+ --file-kind: var(--uix-danger-text); --file-kind-soft: var(--uix-danger-bg); --file-kind-strong: var(--uix-danger-bg);
22
+ --file-kind-edge: color-mix(in srgb, var(--uix-danger-border) 28%, var(--uix-border)); --file-kind-label: var(--uix-danger-text);
23
+ }
24
+
25
+ /* ── FileKindIcon: the kind's glyph in its colour, the type as a solid label on the corner ── */
26
+ .uix-file-icon { position: relative; flex: none; display: inline-grid; place-items: center; width: 34px; height: 34px; color: var(--file-kind, var(--uix-file-other)); }
27
+ .uix-file-icon .uix-file-icon__glyph { width: 28px; height: 28px; transform: translateX(-3px); }
28
+ .uix-file-icon__type {
29
+ position: absolute; right: -4px; bottom: 3px; padding: calc(var(--uix-space-1) / 2) var(--uix-space-1);
30
+ border-radius: var(--uix-radius-xs); background: var(--file-kind-label, var(--uix-file-other-label)); color: var(--uix-file-label-fg);
31
+ font-family: var(--uix-font-sans); font-size: 7.5px; font-weight: 700; line-height: 1; letter-spacing: 0; text-transform: uppercase; white-space: nowrap;
32
+ box-shadow: 0 0 0 1.5px var(--uix-surface);
33
+ }
34
+ .uix-file-icon--sm { width: 30px; height: 30px; }
35
+ .uix-file-icon--sm .uix-file-icon__glyph { width: 25px; height: 25px; }
36
+ .uix-file-icon--lg { width: 52px; height: 52px; }
37
+ .uix-file-icon--lg .uix-file-icon__glyph { width: 42px; height: 42px; }
38
+ .uix-file-icon--lg .uix-file-icon__type { right: -2px; bottom: 5px; font-size: 9px; }
39
+
40
+ /* ── FileRow ── */
41
+ .uix-file-rows { display: grid; gap: var(--uix-space-2); margin: 0; padding: 0; list-style: none; min-width: 0; }
42
+ .uix-file-row {
43
+ position: relative; overflow: hidden; display: flex; align-items: center; gap: var(--uix-space-3); min-width: 0;
44
+ padding: var(--uix-space-2) var(--uix-space-2) var(--uix-space-2) var(--uix-space-3);
45
+ border: 1px solid var(--file-kind-edge); border-radius: var(--uix-radius-md);
46
+ background: linear-gradient(to right, var(--file-kind-soft), transparent 55%) var(--uix-surface);
47
+ color: var(--uix-text);
48
+ transition: border-color var(--uix-dur-change) var(--uix-ease-out);
49
+ }
50
+ .uix-file-row:dir(rtl) { background: linear-gradient(to left, var(--file-kind-soft), transparent 55%) var(--uix-surface); }
51
+ .uix-file-row--compact { gap: var(--uix-space-2); padding: var(--uix-space-2) var(--uix-space-1) var(--uix-space-2) var(--uix-space-2); }
52
+ .uix-file-row > :is(.uix-file-row__icon, .uix-file-row__text, .uix-file-row__actions) { position: relative; }
53
+
54
+ /* The upload fill: the same tint, soft to strong, scaled to the real progress, with a thin leading edge. */
55
+ .uix-file-row__fill {
56
+ position: absolute; inset: 0; pointer-events: none; transform-origin: left center; transform: scaleX(var(--file-progress, 0));
57
+ background: linear-gradient(to right, var(--file-kind-soft), var(--file-kind-strong));
58
+ transition: transform var(--uix-dur-slow) linear, opacity var(--uix-dur-change) var(--uix-ease-out);
59
+ }
60
+ .uix-file-row__edge {
61
+ position: absolute; top: 0; bottom: 0; left: 0; width: 100%; pointer-events: none;
62
+ border-right: 2px solid color-mix(in srgb, var(--file-kind) 55%, transparent);
63
+ transform: translateX(calc((var(--file-progress, 0) - 1) * 100%));
64
+ transition: transform var(--uix-dur-slow) linear;
65
+ }
66
+ .uix-file-row:dir(rtl) .uix-file-row__fill { transform-origin: right center; background: linear-gradient(to left, var(--file-kind-soft), var(--file-kind-strong)); }
67
+ .uix-file-row:dir(rtl) .uix-file-row__edge { left: auto; right: 0; border-right: 0; border-left: 2px solid color-mix(in srgb, var(--file-kind) 55%, transparent); transform: translateX(calc((1 - var(--file-progress, 0)) * 100%)); }
68
+ /* Done: the fill completes, then fades back to the resting edge. */
69
+ .uix-file-row[data-state="done"] .uix-file-row__fill { opacity: 0; }
70
+
71
+ .uix-file-row__icon { flex: none; display: grid; }
72
+ /* The check draws at the icon's corner, holds, and leaves. */
73
+ .uix-file-row__check {
74
+ position: absolute; right: -4px; top: -3px; width: 16px; height: 16px; display: grid; place-items: center;
75
+ border-radius: var(--uix-radius-pill); background: var(--uix-surface);
76
+ animation: uix-file-check-in var(--uix-dur-slower) var(--uix-ease-out) both, uix-file-check-out var(--uix-dur-exit) var(--uix-ease-out) calc(var(--uix-dur-change) + var(--uix-hold-result)) forwards;
77
+ }
78
+ .uix-file-row__check svg { width: 12px; height: 12px; fill: none; stroke: var(--uix-success-solid); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
79
+ .uix-file-row__check path { stroke-dasharray: 1; stroke-dashoffset: 0; animation: uix-file-check-draw var(--uix-dur-slower) var(--uix-ease-out) var(--uix-dur-fast) both; }
80
+
81
+ /* The kit's title rhythm (HAR-1577): a name and its secondary line are --uix-space-1 apart. */
82
+ .uix-file-row__text { flex: 1; min-width: 0; display: grid; gap: var(--uix-space-1); }
83
+ .uix-file-row__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--uix-text-body); font-weight: 600; }
84
+ .uix-file-row__meta { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--uix-text-meta); color: var(--uix-text-muted); font-variant-numeric: tabular-nums; }
85
+ .uix-file-row__kind { color: var(--file-kind-label); font-weight: 600; }
86
+ /* A refusal is read whole: it wraps instead of ending in an ellipsis. */
87
+ .uix-file-row:is([data-state="blocked"], [data-state="failed"]) .uix-file-row__meta { white-space: normal; overflow-wrap: anywhere; }
88
+ /* In a narrow panel its button moves under the words rather than squeezing them to a column. */
89
+ .uix-file-row:is([data-state="blocked"], [data-state="failed"]) { flex-wrap: wrap; row-gap: var(--uix-space-2); }
90
+ .uix-file-row:is([data-state="blocked"], [data-state="failed"]) .uix-file-row__text { flex: 1 1 12rem; }
91
+ .uix-file-row:is([data-state="blocked"], [data-state="failed"]) .uix-file-row__actions { margin-inline-start: auto; }
92
+ .uix-file-row[data-state="blocked"] .uix-file-row__meta { color: var(--uix-warning-text); }
93
+ .uix-file-row[data-state="failed"] .uix-file-row__meta { color: var(--uix-danger-text); }
94
+ .uix-file-row--compact .uix-file-row__name { font-size: calc(var(--uix-text-body) * .9643); }
95
+
96
+ .uix-file-row__actions { flex: none; display: flex; align-items: center; gap: var(--uix-space-1); }
97
+ /* With a fine pointer the resting actions wait for hover or focus; touch always shows them. */
98
+ @media (hover: hover) and (pointer: fine) {
99
+ .uix-file-row__actions > :not(.uix-file-row__keep) { opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
100
+ .uix-file-row:hover .uix-file-row__actions > *,
101
+ .uix-file-row:focus-within .uix-file-row__actions > *,
102
+ .uix-file-row__actions > [aria-expanded="true"] { opacity: 1; }
103
+ }
104
+
105
+ /* ── FileDrop (slim) ── */
106
+ .uix-file-drop {
107
+ position: relative; display: flex; align-items: center; gap: var(--uix-space-2); min-width: 0;
108
+ padding: var(--uix-space-2) var(--uix-space-3);
109
+ border: 1.5px dashed var(--uix-border-strong); border-radius: var(--uix-radius-md);
110
+ background: var(--uix-surface); color: var(--uix-text-muted); font-size: var(--uix-text-meta); cursor: pointer;
111
+ transition: border-color var(--uix-dur-fast) var(--uix-ease-out), color var(--uix-dur-fast) var(--uix-ease-out);
112
+ }
113
+ @media (hover: hover) and (pointer: fine) {
114
+ .uix-file-drop:not([data-disabled]):hover { border-color: var(--uix-text-muted); }
115
+ }
116
+ .uix-file-drop > :not(.uix-file-drop__aura) { position: relative; }
117
+ .uix-file-drop__aura { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity var(--uix-dur-slow) var(--uix-ease-out); }
118
+ .uix-file-drop[data-dragging] { border-color: color-mix(in srgb, var(--file-kind) 55%, var(--uix-border)); color: var(--uix-text); }
119
+ .uix-file-drop[data-dragging] .uix-file-drop__aura { opacity: 1; }
120
+ .uix-file-drop__icon { color: var(--uix-text-muted); }
121
+ .uix-file-drop__line { flex: 1; min-width: 0; display: grid; }
122
+ .uix-file-drop__line > * { grid-area: 1 / 1; min-width: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
123
+ /* The summary sits over the sentence in the same cell; it must never take the button's clicks. */
124
+ .uix-file-drop__summary { pointer-events: none; opacity: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--uix-text); }
125
+ .uix-file-drop[data-dragging] .uix-file-drop__text { opacity: 0; }
126
+ .uix-file-drop[data-dragging] .uix-file-drop__summary { opacity: 1; }
127
+ .uix-file-drop__choose {
128
+ margin: 0; padding: 0; border: 0; border-radius: var(--uix-radius-xs); background: none; font: inherit; font-weight: 600; color: var(--uix-link); cursor: pointer;
129
+ text-decoration: underline; text-underline-offset: .18em; text-decoration-color: color-mix(in srgb, var(--uix-link) 40%, transparent);
130
+ }
131
+ .uix-file-drop__choose:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 2px; }
132
+ .uix-file-drop[data-disabled] { cursor: not-allowed; opacity: .6; }
133
+ .uix-file-drop__choose:disabled { cursor: not-allowed; }
134
+
135
+ /* Forced colours drop the label's fill and ring: an outline keeps it a label over the glyph. */
136
+ @media (forced-colors: active) {
137
+ .uix-file-icon__type { border: 1px solid CanvasText; background: Canvas; color: CanvasText; }
138
+ .uix-file-row:not([data-state="done"]) .uix-file-row__fill { background: Highlight; opacity: .35; }
139
+ }
140
+
141
+ /* Reduced motion keeps only the fades: the fill jumps (the global policy drops transform), and the check fades in and out instead of growing and drawing. */
142
+ @media (prefers-reduced-motion: reduce) {
143
+ .uix-file-row__check { animation: uix-file-check-fade calc(var(--uix-dur-change) + var(--uix-hold-result) + var(--uix-dur-exit)) linear both !important; }
144
+ .uix-file-row__check path { animation: none !important; }
145
+ }
146
+ @media (prefers-reduced-motion: no-preference) {
147
+ :root[data-motion="reduce"] .uix-file-row__check { animation: uix-file-check-fade calc(var(--uix-dur-change) + var(--uix-hold-result) + var(--uix-dur-exit)) linear both !important; }
148
+ :root[data-motion="reduce"] .uix-file-row__check path { animation: none !important; }
149
+ }
150
+ }
151
+
152
+ @keyframes uix-file-check-in { from { opacity: 0; transform: scale(.6); } }
153
+ @keyframes uix-file-check-draw { from { stroke-dashoffset: 1; } }
154
+ @keyframes uix-file-check-out { to { opacity: 0; } }
155
+ @keyframes uix-file-check-fade { 0% { opacity: 0; } 12% { opacity: 1; } 96% { opacity: 1; } 100% { opacity: 0; } }
@@ -118,13 +118,12 @@
118
118
  .uix-flow__edge-label { fill: var(--uix-text-muted); font-family: var(--uix-font-sans); font-size: var(--uix-text-eyebrow); }
119
119
  .uix-flow__edge-label--loop { fill: var(--uix-accent); }
120
120
 
121
- /* hovering/focusing a diagram sets its edges "flowing" (marching dashes) to read direction */
121
+ /* the edges never march (2.57, Rules for apps: no decorative loops); the arrowheads give direction.
122
+ Hovering or focusing a diagram only thickens its edges, at once (no transition). */
122
123
  @media (hover: hover) and (pointer: fine) {
123
- .uix-flow:hover .uix-flow__edge,
124
- .uix-flow:focus-within .uix-flow__edge {
125
- stroke-dasharray: 5 4; animation: uix-flow-march var(--uix-dur-slow) linear infinite;
126
- }
124
+ .uix-flow:hover .uix-flow__edge { stroke-width: 2; }
127
125
  }
126
+ .uix-flow:focus-within .uix-flow__edge { stroke-width: 2; }
128
127
 
129
128
  /* ---- linear: flex row of nodes + pure-CSS connectors (no SVG) ---- */
130
129
  .uix-flow--linear .uix-flow__row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--uix-space-1); }
@@ -206,13 +205,10 @@
206
205
 
207
206
  /* ============================================================ motion */
208
207
  @keyframes uix-flow-spin { to { transform: rotate(360deg); } }
209
- @keyframes uix-flow-march { to { stroke-dashoffset: -18; } }
210
208
 
211
209
  @media (prefers-reduced-motion: reduce) {
212
210
  /* a running node keeps showing it runs: the icon breathes instead of turning */
213
211
  .uix-node--running .uix-node__icon svg { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; }
214
- .uix-flow:hover .uix-flow__edge,
215
- .uix-flow:focus-within .uix-flow__edge { animation: none; }
216
212
  }
217
213
 
218
214
  @media (max-width: 720px) {
@@ -1,25 +1,12 @@
1
- /* uix heartbeat / live status indicator — a pulsing ping. Under reduced motion the ping (it grows) goes
2
- and the dot itself breathes, so "live" is still visible. */
1
+ /* uix heartbeat / live status indicator — a still dot in the state's colour (2.57, Rules for apps:
2
+ no pulsing or looping on status). "Live" is said by the words beside it (LiveIndicator), never by
3
+ motion. The ring span stays in the markup for compatibility and is not drawn. */
3
4
  @layer uix.components {
4
5
  .uix-heartbeat { position: relative; display: inline-grid; place-items: center; width: 8px; height: 8px; flex: none; }
5
6
  .uix-heartbeat__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--uix-success); z-index: var(--uix-z-raised); }
6
- .uix-heartbeat__ping { position: absolute; inset: 0; border-radius: 50%; background: var(--uix-success); animation: uix-ping var(--uix-loop-ping) var(--uix-ease-out) infinite; }
7
- @keyframes uix-ping { 0% { transform: scale(1); opacity: .55; } 100% { transform: scale(2.8); opacity: 0; } }
8
- .uix-heartbeat--warning .uix-heartbeat__dot, .uix-heartbeat--warning .uix-heartbeat__ping { background: var(--uix-warning); }
9
- .uix-heartbeat--danger .uix-heartbeat__dot, .uix-heartbeat--danger .uix-heartbeat__ping { background: var(--uix-danger); }
7
+ .uix-heartbeat__ping { display: none; }
8
+ .uix-heartbeat--warning .uix-heartbeat__dot { background: var(--uix-warning); }
9
+ .uix-heartbeat--danger .uix-heartbeat__dot { background: var(--uix-danger); }
10
10
  .uix-heartbeat--idle .uix-heartbeat__dot { background: var(--uix-text-muted); }
11
- .uix-heartbeat--idle .uix-heartbeat__ping { display: none; }
12
- @media (prefers-reduced-motion: reduce) {
13
- .uix-heartbeat__ping { display: none; }
14
- .uix-heartbeat:not(.uix-heartbeat--idle) .uix-heartbeat__dot { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; }
15
- }
16
11
  .uix-live { display: inline-flex; align-items: center; gap: var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 500; color: var(--uix-text-hushed); }
17
12
  }
18
-
19
- /* the in-app reduced-motion preference (HAR-1372, <html data-motion="reduce">): the same rule */
20
- @layer uix.components {
21
- @media (prefers-reduced-motion: no-preference) {
22
- :root[data-motion="reduce"] .uix-heartbeat__ping { display: none; }
23
- :root[data-motion="reduce"] .uix-heartbeat:not(.uix-heartbeat--idle) .uix-heartbeat__dot { animation: uix-pulse var(--uix-loop-pulse) var(--uix-ease-in-out) infinite !important; }
24
- }
25
- }
@@ -15,4 +15,16 @@
15
15
  --uix-accent-text, not --uix-accent: the raw accent of a bright brand is 2.62:1 on the track. */
16
16
  .uix-meter__fill[data-tone="neutral"] { background: var(--uix-text-muted); }
17
17
  .uix-meter__fill[data-tone="accent"] { background: var(--uix-accent-text); }
18
+
19
+ /* A target (calm kit 2.56): a thin ink mark across the track where the goal is ("Ziel 95 %"),
20
+ so "under target" reads from the bar itself. The track stops clipping so the mark can stand
21
+ a little proud of it; the fill keeps its rounded clip in __clip. --target is 0-1. */
22
+ .uix-meter--target { position: relative; overflow: visible; }
23
+ .uix-meter__clip { height: 100%; border-radius: inherit; overflow: hidden; }
24
+ .uix-meter__target {
25
+ position: absolute; top: calc(-1 * var(--uix-space-1)); bottom: calc(-1 * var(--uix-space-1));
26
+ inset-inline-start: calc(var(--target, 1) * 100%); width: 2px;
27
+ border-radius: var(--uix-radius-xs); background: var(--uix-text-hushed);
28
+ }
29
+ @media (forced-colors: active) { .uix-meter__target { background: CanvasText; } }
18
30
  }
@@ -11,8 +11,11 @@
11
11
  .uix-pill--info { --tone-bg: var(--uix-info-bg); --tone-fg: var(--uix-info-text); --tone-dot: var(--uix-info); }
12
12
  .uix-pill--warning { --tone-bg: var(--uix-warning-bg); --tone-fg: var(--uix-warning-text); --tone-dot: var(--uix-warning); }
13
13
  .uix-pill--danger { --tone-bg: var(--uix-danger-bg); --tone-fg: var(--uix-danger-text); --tone-dot: var(--uix-danger); }
14
- /* critical = the one SOLID fill (most urgent); muted = a quiet, chrome-less label */
15
- .uix-pill--critical { --tone-bg: var(--uix-danger); --tone-fg: var(--uix-danger-fg); --tone-dot: var(--uix-danger-fg); }
14
+ /* critical (calm kit 2.56): no longer a solid red fill. The danger tint with the danger words
15
+ in semibold and the danger dot, so the one thing that is broken now reads apart from a plain
16
+ danger pill without shouting. A solid red fill is kept for the destructive button only. */
17
+ .uix-pill--critical { --tone-bg: var(--uix-danger-bg); --tone-fg: var(--uix-danger-text); --tone-dot: var(--uix-danger-solid); font-weight: 600; }
18
+ /* muted = a quiet, chrome-less label */
16
19
  .uix-pill--muted { --tone-bg: transparent; --tone-fg: var(--uix-text-muted); --tone-dot: var(--uix-text-muted); }
17
20
  /* time-pressure tones (U1 tokens — distinct from severity and validation-error) */
18
21
  .uix-pill--attention { --tone-bg: var(--uix-attention-bg); --tone-fg: var(--uix-attention-text); --tone-dot: var(--uix-attention); }
@@ -65,3 +68,32 @@
65
68
  /* the dot treatment has no box at any size: its label lines up with the cell's other text */
66
69
  .uix-pill--dot:is(.uix-pill--sm, .uix-pill--lg) { padding-inline: 0; }
67
70
  }
71
+
72
+ /* StatusDot (calm kit 2.56): a dot and a word, no box, for the signal ladder on a glance page.
73
+ neutral is ink, info the accent, warning amber and critical red: the word carries the meaning,
74
+ the dot is the glance. Word and dot wear the tone's TEXT role: AA on the surface, the app
75
+ background and the tone's own tint in both modes, so the dot clears 3:1 wherever the word can
76
+ sit (the SOLID role measured 2.78:1 for success and 2.91:1 for warning on their light tints).
77
+ Never pulses. */
78
+ @layer uix.components {
79
+ .uix-status-dot {
80
+ display: inline-flex; align-items: baseline; gap: var(--uix-space-2);
81
+ font-size: var(--uix-text-meta); font-weight: 600; line-height: 1.4; color: var(--tone-fg, var(--uix-text-hushed));
82
+ }
83
+ .uix-status-dot::before {
84
+ content: ""; flex: none; align-self: center; width: 7px; height: 7px; border-radius: 50%;
85
+ background: var(--tone-dot, var(--uix-text-hushed));
86
+ }
87
+ .uix-status-dot--neutral { --tone-fg: var(--uix-text-hushed); --tone-dot: var(--uix-text-hushed); font-weight: 500; }
88
+ .uix-status-dot--info { --tone-fg: var(--uix-info-text); --tone-dot: var(--uix-info-text); }
89
+ .uix-status-dot--success { --tone-fg: var(--uix-success-text); --tone-dot: var(--uix-success-text); }
90
+ .uix-status-dot--warning { --tone-fg: var(--uix-warning-text); --tone-dot: var(--uix-warning-text); }
91
+ .uix-status-dot--critical { --tone-fg: var(--uix-danger-text); --tone-dot: var(--uix-danger-text); }
92
+ /* quiet: the word in ink, only the dot keeps the hue (a list of services, a legend line) */
93
+ .uix-status-dot--quiet { color: var(--uix-text-hushed); font-weight: 500; }
94
+ .uix-status-dot--sm { gap: var(--uix-space-1); font-size: var(--uix-text-eyebrow); }
95
+ .uix-status-dot--sm::before { width: 6px; height: 6px; }
96
+ @media (forced-colors: active) {
97
+ .uix-status-dot::before { background: CanvasText; }
98
+ }
99
+ }
@@ -25,24 +25,24 @@
25
25
  "ring": { "$type": "color", "$value": "var(--uix-brand,#1447E6)", "$description": "Runtime: chains through --uix-brand." },
26
26
  "brand-muted": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-accent) 12%, transparent)", "$description": "Runtime: color-mix of the live accent." },
27
27
 
28
- "success": { "$type": "color", "$value": "#047857" },
28
+ "success": { "$type": "color", "$value": "#2B7752", "$description": "Success role, light: the TEXT colour (--uix-success-text aliases it) and the fill of a success button with white --uix-success-fg (5.4:1). Calm kit (2.56): chroma 0.096, was #047857. 4.8:1 on its own tint." },
29
29
  "success-fg": { "$type": "color", "$value": "#FFFFFF" },
30
- "success-bg": { "$type": "color", "$value": "#D0FAE5" },
30
+ "success-bg": { "$type": "color", "$value": "#E8F4ED" },
31
31
  "success-text": { "$type": "color", "$value": "var(--uix-success)", "$description": "Success-toned TEXT (pill, alert icon, stat trend, SLA ok). Light aliases --uix-success (#047857, already AA on the pale tint), so a theme's light success override still reaches text; dark sets its own value in the calibrated status-text band (HAR-1562). Paint text with this, not with --uix-success, which is the solid/dot role on dark." },
32
- "warning": { "$type": "color", "$value": "#F99C00" },
32
+ "warning": { "$type": "color", "$value": "#D4A03A", "$description": "Warning FILL, light (a warning button or banner bar with the dark --uix-warning-fg, 7.4:1). Calm kit (2.56): a softer amber, was #F99C00. Text is --uix-warning-text; a dot is --uix-warning-solid." },
33
33
  "warning-fg": { "$type": "color", "$value": "#1A1A1A" },
34
- "warning-bg": { "$type": "color", "$value": "#FEF3D6" },
35
- "warning-text": { "$type": "color", "$value": "#92400E", "$description": "Warning-toned TEXT, legible on the faint --uix-warning-bg in light mode — the bright --uix-warning (#F99C00) fails contrast on pale yellow, so the foreground is a hand-darkened amber. Dark mode overrides to track --uix-warning. Used by status-pill --warning." },
36
- "warning-border": { "$type": "color", "$value": "#D97706", "$description": "Warning-toned BORDER for an outlined container on a neutral surface (stat tile --warning). The bright --uix-warning is 2.1:1 on white; this amber clears the 3:1 non-text minimum on --uix-surface and --uix-bg-app." },
37
- "info": { "$type": "color", "$value": "#1447E6" },
34
+ "warning-bg": { "$type": "color", "$value": "#FAF2E1" },
35
+ "warning-text": { "$type": "color", "$value": "#8F6213", "$description": "Warning-toned TEXT, light: 5.4:1 on --uix-surface and 4.8:1 on --uix-warning-bg (calm kit 2.56, was #92400E). Dark mode overrides to track --uix-warning. Used by status-pill --warning." },
36
+ "warning-border": { "$type": "color", "$value": "#B8862C", "$description": "Warning-toned BORDER for an outlined container on a neutral surface (stat tile --warning): 3.2:1 on --uix-surface, so it clears the 3:1 non-text minimum (calm kit 2.56, was #D97706)." },
37
+ "info": { "$type": "color", "$value": "#3A5BD0", "$description": "Info role, light: the TEXT colour on --uix-info-bg (5.1:1) and the fill of an info badge with white --uix-info-fg (5.9:1). Calm kit (2.56): no longer the brand blue #1447E6." },
38
38
  "info-fg": { "$type": "color", "$value": "#FFFFFF" },
39
- "info-bg": { "$type": "color", "$value": "#E3EBFF" },
40
- "info-text": { "$type": "color", "$value": "#1447E6", "$description": "Info-toned TEXT, legible on --uix-info-bg and dark surfaces. Light = --uix-info (already AA on the pale tint); dark brightens it (the deep --uix-info #2563EB fails as text on the dark tint). Used by status-pill/alert/node --info. See --uix-warning-text for the same TEXT-vs-SOLID split." },
41
- "danger": { "$type": "color", "$value": "#E40014" },
39
+ "info-bg": { "$type": "color", "$value": "#ECF0FC" },
40
+ "info-text": { "$type": "color", "$value": "#3A5BD0", "$description": "Info-toned TEXT, legible on --uix-info-bg and the surfaces (5.9:1 on white). Light = --uix-info; dark brightens it. Used by status-pill/alert/node --info." },
41
+ "danger": { "$type": "color", "$value": "#B8433C", "$description": "Danger FILL, light: the destructive button and the solid critical pill (treatment=\"solid\") with white --uix-danger-fg, 5.4:1. Calm kit (2.56): chroma 0.15, was the saturated #E40014 (C 0.24). Text is --uix-danger-text; a dot is --uix-danger-solid." },
42
42
  "danger-fg": { "$type": "color", "$value": "#FFFFFF" },
43
- "danger-bg": { "$type": "color", "$value": "#FFE4E6" },
44
- "danger-border": { "$type": "color", "$value": "#E40014", "$description": "Danger-toned BORDER for an outlined container on a neutral surface (stat tile --danger). 4.9:1 on white, so it clears the 3:1 non-text minimum; a separate role so a theme can soften the outline without touching the solid --uix-danger." },
45
- "danger-text": { "$type": "color", "$value": "#C20012", "$description": "Danger-toned TEXT, legible on --uix-danger-bg (the bright --uix-danger #E40014 is only 4.05:1 on #FFE4E6). A hand-darkened red for text; --uix-danger stays the SOLID role (danger button bg, critical pill, dots). Dark mode brightens it. Used by pill/alert/stat-trend/field-error/menu/sla/node/audit --danger." },
43
+ "danger-bg": { "$type": "color", "$value": "#FBEDEB" },
44
+ "danger-border": { "$type": "color", "$value": "#D65A50", "$description": "Danger-toned BORDER for an outlined container on a neutral surface (stat tile --danger): 3.9:1 on white, so it clears the 3:1 non-text minimum. Calm kit (2.56), was #E40014." },
45
+ "danger-text": { "$type": "color", "$value": "#B9423C", "$description": "Danger-toned TEXT: 5.4:1 on --uix-surface and 4.7:1 on --uix-danger-bg (calm kit 2.56, was #C20012). --uix-danger stays the FILL role (destructive button, solid critical pill). Dark mode brightens it. Used by pill/alert/stat-trend/field-error/menu/sla/node/audit --danger and StatusDot critical." },
46
46
  "amber": { "$type": "color", "$value": "#C98A1E", "$description": "SEV-3 / medium-severity tone — the third tier of the severity ramp (danger = SEV-1, warning = SEV-2, amber = SEV-3). A muted ochre, deliberately distinct from the brighter --uix-warning so the three tiers read apart." },
47
47
  "amber-text": { "$type": "color", "$value": "#795006", "$description": "Amber-toned TEXT, legible on a faint amber tint and on dark surfaces (the SEV-3 ochre is too light as text on pale fills). Dark mode brightens it to track --uix-amber. Used by severity-3 badges." },
48
48
  "amber-bg": { "$type": "color", "$value": "#FEFCE8", "$description": "Amber-toned wash for SEV-3 pill backgrounds. Completes the amber ramp (amber / amber-text / amber-bg) to match the depth of the warning/danger/info ramps." },
@@ -52,10 +52,10 @@
52
52
  "attention-text": { "$type": "color", "$value": "#9A3412", "$description": "Attention-toned TEXT legible on --uix-attention-bg (#FFEDD5). Dark mode brightens to track --uix-attention." },
53
53
  "attention-solid": { "$type": "color", "$value": "#EA580C", "$description": "SOLID role for attention fills/dots/pulses (see success-solid)." },
54
54
 
55
- "overdue": { "$type": "color", "$value": "#DC2626", "$description": "Time-pressure semantic — 'breached / past due'. Same hue family as danger but a SEPARATE role so products retheme breach independently of validation error. Covers SLA breach and hard-deadline misses." },
56
- "overdue-bg": { "$type": "color", "$value": "#FEE2E2" },
57
- "overdue-text": { "$type": "color", "$value": "#991B1B", "$description": "Overdue-toned TEXT legible on --uix-overdue-bg (#FEE2E2). Dark mode brightens." },
58
- "overdue-solid": { "$type": "color", "$value": "#EF4444", "$description": "SOLID role for overdue fills/dots (see success-solid)." },
55
+ "overdue": { "$type": "color", "$value": "#B8433C", "$description": "Time-pressure semantic, 'breached / past due'. The danger family as a SEPARATE role so products retheme breach independently of validation error. Calm kit (2.56): follows the softened danger values, was #DC2626." },
56
+ "overdue-bg": { "$type": "color", "$value": "#FBEDEB" },
57
+ "overdue-text": { "$type": "color", "$value": "#B9423C", "$description": "Overdue-toned TEXT legible on --uix-overdue-bg (4.7:1). Calm kit (2.56), was #991B1B. Dark mode brightens." },
58
+ "overdue-solid": { "$type": "color", "$value": "#D65A50", "$description": "SOLID role for overdue fills/dots: 3.9:1 on white (calm kit 2.56, was #EF4444)." },
59
59
 
60
60
  "sev-4": { "$type": "color", "$value": "var(--uix-info)", "$description": "SEV-4 alias → info tone. Full severity ramp: SEV-1=danger, SEV-2=warning, SEV-3=amber, SEV-4=info, SEV-5=neutral. var() reference — no dark override needed." },
61
61
  "sev-4-bg": { "$type": "color", "$value": "var(--uix-info-bg)" },
@@ -64,35 +64,79 @@
64
64
  "sev-5-bg": { "$type": "color", "$value": "var(--uix-bg-active)" },
65
65
  "sev-5-text": { "$type": "color", "$value": "var(--uix-text-hushed)" },
66
66
 
67
- "success-solid": { "$type": "color", "$value": "#10B981", "$description": "SOLID status role — the vivid fill/dot/pulse color, distinct from the legible TEXT role (--uix-success). Products override per brand." },
68
- "warning-solid": { "$type": "color", "$value": "#F59E0B", "$description": "SOLID status role (see success-solid)." },
69
- "info-solid": { "$type": "color", "$value": "#2563EB", "$description": "SOLID status role (see success-solid)." },
70
- "danger-solid": { "$type": "color", "$value": "#EF4444", "$description": "SOLID status role (see success-solid)." },
67
+ "success-solid": { "$type": "color", "$value": "#3FA373", "$description": "SOLID status role: the dot/fill/pulse colour, 3.1:1 on white (calm kit 2.56, was #10B981). Distinct from the legible TEXT role (--uix-success). Products override per brand." },
68
+ "warning-solid": { "$type": "color", "$value": "#B8862C", "$description": "SOLID status role (see success-solid): 3.2:1 on white (calm kit 2.56, was #F59E0B, 2.1:1)." },
69
+ "info-solid": { "$type": "color", "$value": "#5B7BE3", "$description": "SOLID status role (see success-solid): 3.9:1 on white (calm kit 2.56, was #2563EB)." },
70
+ "danger-solid": { "$type": "color", "$value": "#D65A50", "$description": "SOLID status role: the critical DOT (StatusDot, the dot pill), 3.9:1 on white. Calm kit (2.56): was #EF4444. Not a fill for text; that is --uix-danger." },
71
71
 
72
72
  "neutral-solid": { "$type": "color", "$value": "#8A8A8A", "$description": "NEUTRAL status family (HAR-1562): the default, non-alarming status tone (open, scheduled, draft, in progress). Solid = the dot/fill, 3:1 non-text on white. Dark overrides." },
73
73
  "neutral-text": { "$type": "color", "$value": "var(--uix-text-hushed)", "$description": "Neutral status TEXT, alias of --uix-text-hushed. var() reference, no dark override needed." },
74
74
  "neutral-bg": { "$type": "color", "$value": "var(--uix-bg-active)", "$description": "Neutral status tint, alias of --uix-bg-active." },
75
75
  "neutral-border": { "$type": "color", "$value": "var(--uix-border-strong)", "$description": "Neutral status outline, alias of --uix-border-strong." },
76
76
 
77
- "chart-1": { "$type": "color", "$value": "#0455E6", "$description": "Categorical palette, light. Fixed hue order (blue, cyan, green, ochre, orange, crimson, violet, pink), re-stepped so the dataviz validator passes on --uix-surface and --uix-bg-app: L 0.43-0.77, C >= 0.10, adjacent CVD dE >= 8, normal-vision dE >= 15, >= 3:1 (HAR-1552)." },
78
- "chart-2": { "$type": "color", "$value": "#249BC8" },
79
- "chart-3": { "$type": "color", "$value": "#06A543" },
80
- "chart-4": { "$type": "color", "$value": "#905709" },
81
- "chart-5": { "$type": "color", "$value": "#F25C1B" },
82
- "chart-6": { "$type": "color", "$value": "#B00825" },
83
- "chart-7": { "$type": "color", "$value": "#8143E6" },
84
- "chart-8": { "$type": "color", "$value": "#DB2579" },
77
+ "chart-1": { "$type": "color", "$value": "#0455E6", "$description": "Categorical palette v2 (calm kit 2.56), light. The first slot is THE series colour (--uix-chart-series) and the brand blue (#0455E6, unchanged from 2.55); 2 teal and 3 violet are the three quiet category hues; 4-8 extend it for report charts. No red slot (red never encodes a series) and no amber slot (amber is reserved for attention). Validated on --uix-surface and --uix-bg-app: L 0.43-0.77, C >= 0.10, adjacent CVD dE >= 8, normal-vision dE >= 15, >= 3:1 (chart-palette.test.mjs)." },
78
+ "chart-2": { "$type": "color", "$value": "#1F978A" },
79
+ "chart-3": { "$type": "color", "$value": "#8C72D6" },
80
+ "chart-4": { "$type": "color", "$value": "#4C9A5A" },
81
+ "chart-5": { "$type": "color", "$value": "#B45E9A" },
82
+ "chart-6": { "$type": "color", "$value": "#7F8A2E" },
83
+ "chart-7": { "$type": "color", "$value": "#2F8FC2" },
84
+ "chart-8": { "$type": "color", "$value": "#5E7D3A" },
85
+ "chart-series": { "$type": "color", "$value": "var(--uix-chart-1)", "$description": "THE series colour of a glance chart (calm kit 2.56): one series in blue, any second one in --uix-chart-comparison grey. Alias of --uix-chart-1, so a theme that re-steps the palette moves it too." },
86
+ "chart-series-soft": { "$type": "color", "$value": "rgba(4,85,230,.14)", "$description": "The series colour as a faint wash: an area under a glance line, a highlighted bucket. Dark overrides." },
85
87
  "chart-neutral": { "$type": "color", "$value": "#64748B" },
86
88
  "chart-grid": { "$type": "color", "$value": "#EDEDED", "$description": "Chart gridline: a SOLID 1px hairline, recessive. Dashes are reserved for projections and thresholds (HAR-1552)." },
87
89
  "chart-axis": { "$type": "color", "$value": "#D4D4D4", "$description": "Chart axis line (labels use --uix-text-muted)." },
88
90
  "chart-reference": { "$type": "color", "$value": "#525252", "$description": "Neutral ink for target, budget and baseline reference lines: 7.8:1 on --uix-surface. Not a status colour." },
89
91
  "chart-zone-warning": { "$type": "color", "$value": "rgba(217,119,6,.10)", "$description": "Alpha fill for a warning threshold zone behind the series." },
90
- "chart-zone-danger": { "$type": "color", "$value": "rgba(228,0,20,.07)", "$description": "Alpha fill for a danger threshold zone behind the series." },
92
+ "chart-zone-danger": { "$type": "color", "$value": "rgba(214,90,80,.08)", "$description": "Alpha fill for a danger threshold zone behind the series (the calm danger dot at 8 %)." },
91
93
  "chart-forecast-band": { "$type": "color", "$value": "rgba(10,10,10,.06)", "$description": "Alpha fill for a forecast / confidence band; neutral so it works under any series hue." },
92
94
  "chart-event": { "$type": "color", "$value": "#737373", "$description": "Event-marker line and label ink (deploys, incidents, releases): 4.7:1 on --uix-surface." },
93
95
  "chart-partial": { "$type": "color", "$value": "rgba(10,10,10,.10)", "$description": "Hatch base for a partial (incomplete) period." },
94
96
  "chart-comparison": { "$type": "color", "$value": "#B8B8B8", "$description": "Muted ghost line for the comparison period (last week, last year)." },
95
97
 
98
+ "file-img": { "$type": "color", "$value": "var(--uix-chart-3)", "$description": "File kinds (file kit 2.57): one hue per kind of attachment, drawn by FileIcon, FileRow and FileDrop. None is red (red stays for broken) and none is the brand blue (blue stays for actions). Five equal a calm chart slot in light and alias it, so a file and a chart never fight: img chart-3, doc chart-5, mail chart-7, code chart-2, log chart-6. Every kind clears 3:1 on --uix-surface and --uix-bg-app as an icon stroke (file-kinds.test.mjs)." },
99
+ "file-img-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-img) 12%, transparent)", "$description": "The kind as a resting tint: the left edge of a FileRow, the start of an upload fill. Dark 15 %." },
100
+ "file-img-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-img) 22%, transparent)", "$description": "The leading end of an upload fill. Dark 26 %." },
101
+ "file-img-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-img) 28%, var(--uix-border))", "$description": "A FileRow border: the kind mixed into the line colour. Dark 32 %." },
102
+ "file-img-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-img) 86%, #000000)", "$description": "The fill of the type label on a FileIcon corner, under --uix-file-label-fg. Light deepens the kind by 14 % black so white label text clears 4.5:1 on every kind (the plain kinds give white 3.6-4.2:1); dark uses the kind itself." },
103
+ "file-doc": { "$type": "color", "$value": "var(--uix-chart-5)", "$description": "Dokument. Alias of --uix-chart-5 (#B45E9A)." },
104
+ "file-doc-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-doc) 12%, transparent)" },
105
+ "file-doc-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-doc) 22%, transparent)" },
106
+ "file-doc-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-doc) 28%, var(--uix-border))" },
107
+ "file-doc-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-doc) 86%, #000000)" },
108
+ "file-sheet": { "$type": "color", "$value": "#3F8F55", "$description": "Tabelle (#3F8F55)." },
109
+ "file-sheet-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-sheet) 12%, transparent)" },
110
+ "file-sheet-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-sheet) 22%, transparent)" },
111
+ "file-sheet-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-sheet) 28%, var(--uix-border))" },
112
+ "file-sheet-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-sheet) 86%, #000000)" },
113
+ "file-mail": { "$type": "color", "$value": "var(--uix-chart-7)", "$description": "E-Mail. Alias of --uix-chart-7 (#2F8FC2)." },
114
+ "file-mail-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-mail) 12%, transparent)" },
115
+ "file-mail-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-mail) 22%, transparent)" },
116
+ "file-mail-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-mail) 28%, var(--uix-border))" },
117
+ "file-mail-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-mail) 86%, #000000)" },
118
+ "file-code": { "$type": "color", "$value": "var(--uix-chart-2)", "$description": "Code & Konfiguration. Alias of --uix-chart-2 (#1F978A)." },
119
+ "file-code-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-code) 12%, transparent)" },
120
+ "file-code-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-code) 22%, transparent)" },
121
+ "file-code-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-code) 28%, var(--uix-border))" },
122
+ "file-code-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-code) 86%, #000000)" },
123
+ "file-log": { "$type": "color", "$value": "var(--uix-chart-6)", "$description": "Protokoll. Alias of --uix-chart-6 (#7F8A2E)." },
124
+ "file-log-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-log) 12%, transparent)" },
125
+ "file-log-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-log) 22%, transparent)" },
126
+ "file-log-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-log) 28%, var(--uix-border))" },
127
+ "file-log-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-log) 86%, #000000)" },
128
+ "file-archive": { "$type": "color", "$value": "#8A7A66", "$description": "Archiv (#8A7A66)." },
129
+ "file-archive-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-archive) 12%, transparent)" },
130
+ "file-archive-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-archive) 22%, transparent)" },
131
+ "file-archive-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-archive) 28%, var(--uix-border))" },
132
+ "file-archive-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-archive) 86%, #000000)" },
133
+ "file-other": { "$type": "color", "$value": "#808080", "$description": "Datei (#808080)." },
134
+ "file-other-soft": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-other) 12%, transparent)" },
135
+ "file-other-strong": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-other) 22%, transparent)" },
136
+ "file-other-edge": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-other) 28%, var(--uix-border))" },
137
+ "file-other-label": { "$type": "color", "$value": "color-mix(in srgb, var(--uix-file-other) 86%, #000000)" },
138
+ "file-label-fg": { "$type": "color", "$value": "#FFFFFF", "$description": "Text on a file type label: white in light, ink in dark. 4.5:1 or more on every --uix-file-*-label." },
139
+
96
140
  "row": { "$type": "color", "$value": "#FFFFFF" },
97
141
  "row-alt": { "$type": "color", "$value": "#FAFAFA" },
98
142
  "row-pinned-bg": { "$type": "color", "$value": "#F4F7FF" },
@@ -37,7 +37,16 @@
37
37
  "loop-blink": { "$type": "duration", "$value": "1100ms", "$description": "One caret blink cycle." },
38
38
  "loop-pulse": { "$type": "duration", "$value": "2000ms", "$description": "One cycle of the reduced-motion opacity pulse that replaces spinners, shimmer and indeterminate progress, so a still-working indicator stays visibly alive without movement." },
39
39
 
40
+ "dur-arrive": { "$type": "duration", "$value": "420ms", "$description": "Arrival (calm kit 2.56): how long one card of a glance page takes to fade and rise into place on the first paint of a session. Never on a refresh or a data change." },
41
+ "stagger-arrive": { "$type": "duration", "$value": "45ms", "$description": "Arrival: the gap between one card starting and the next, in reading order." },
42
+ "delay-arrive-trace": { "$type": "duration", "$value": "150ms", "$description": "Arrival: how long after its card starts a chart begins to draw (a line traces, bars grow)." },
43
+ "dur-arrive-trace": { "$type": "duration", "$value": "700ms", "$description": "Arrival: a line or sparkline tracing in from the left." },
44
+ "dur-arrive-grow": { "$type": "duration", "$value": "500ms", "$description": "Arrival: one bar growing from its baseline (paired bars, a bar list, a meter)." },
45
+ "stagger-arrive-grow": { "$type": "duration", "$value": "25ms", "$description": "Arrival: the gap between one bar (or bucket) starting to grow and the next." },
46
+ "dur-arrive-count": { "$type": "duration", "$value": "600ms", "$description": "Arrival: a headline number counting up from zero (Count arrive). Later changes tick once instead." },
47
+
40
48
  "lift": { "$type": "dimension", "$value": "4px" },
49
+ "arrive-rise": { "$type": "dimension", "$value": "8px", "$description": "Arrival: how far a card rises while it fades in." },
41
50
 
42
51
  "z-raised": { "$type": "number", "$value": "1", "$description": "z-index ladder (semantic stacking order). raised = locally lifted within a component: a sticky table header & first column, a flow node title over its diamond, a heartbeat dot over its ping." },
43
52
  "z-sticky": { "$type": "number", "$value": "3", "$description": "A sticky plane that must outrank raised siblings — the pinned-column header corner, which sits above both the sticky row and the sticky column." },