@ponchia/ui 0.5.0 → 0.6.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/CHANGELOG.md +322 -0
- package/MIGRATIONS.json +14 -0
- package/README.md +28 -5
- package/annotations/index.d.ts +398 -276
- package/annotations/index.d.ts.map +1 -0
- package/annotations/index.js +315 -45
- package/behaviors/carousel.js +17 -16
- package/behaviors/combobox.js +47 -16
- package/behaviors/command.js +18 -15
- package/behaviors/connectors.js +4 -5
- package/behaviors/crosshair.js +4 -5
- package/behaviors/dialog.js +3 -2
- package/behaviors/disclosure.js +3 -2
- package/behaviors/dismissible.js +3 -2
- package/behaviors/forms.js +41 -13
- package/behaviors/glyph.js +4 -5
- package/behaviors/internal.js +47 -0
- package/behaviors/legend.js +23 -2
- package/behaviors/menu.js +3 -2
- package/behaviors/popover.js +78 -7
- package/behaviors/spotlight.js +4 -5
- package/behaviors/table.js +39 -12
- package/behaviors/tabs.js +14 -14
- package/behaviors/theme.js +5 -3
- package/behaviors/toast.js +13 -1
- package/classes/classes.json +1857 -0
- package/classes/index.d.ts +28 -13
- package/classes/index.js +34 -18
- package/classes/vscode.css-custom-data.json +12 -0
- package/connectors/index.d.ts +189 -69
- package/connectors/index.d.ts.map +1 -0
- package/connectors/index.js +120 -24
- package/css/app.css +43 -13
- package/css/base.css +15 -10
- package/css/connectors.css +17 -0
- package/css/content.css +7 -1
- package/css/dataviz.css +5 -1
- package/css/disclosure.css +38 -6
- package/css/dots.css +57 -0
- package/css/feedback.css +60 -2
- package/css/forms.css +42 -1
- package/css/legend.css +11 -7
- package/css/marks.css +38 -8
- package/css/motion.css +24 -44
- package/css/navigation.css +7 -0
- package/css/overlay.css +31 -1
- package/css/primitives.css +91 -5
- package/css/report.css +40 -63
- package/css/site.css +16 -2
- package/css/sources.css +43 -1
- package/css/spotlight.css +1 -1
- package/css/tokens.css +36 -1
- package/css/workbench.css +1 -1
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -1
- package/dist/css/app.css +1 -1
- package/dist/css/base.css +1 -1
- package/dist/css/connectors.css +1 -1
- package/dist/css/content.css +1 -1
- package/dist/css/disclosure.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/legend.css +1 -1
- package/dist/css/marks.css +1 -1
- package/dist/css/motion.css +1 -1
- package/dist/css/navigation.css +1 -1
- package/dist/css/overlay.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/report.css +1 -1
- package/dist/css/site.css +1 -1
- package/dist/css/sources.css +1 -1
- package/dist/css/spotlight.css +1 -1
- package/dist/css/tokens.css +1 -1
- package/dist/css/workbench.css +1 -1
- package/docs/adr/0003-theme-model.md +1 -1
- package/docs/annotations.md +94 -14
- package/docs/architecture.md +50 -6
- package/docs/contrast.md +116 -92
- package/docs/d2.md +195 -0
- package/docs/legends.md +18 -2
- package/docs/marks.md +9 -2
- package/docs/mermaid.md +152 -0
- package/docs/reference.md +78 -22
- package/docs/reporting.md +395 -57
- package/docs/sources.md +27 -0
- package/docs/stability.md +9 -2
- package/docs/usage.md +101 -4
- package/docs/vega.md +225 -0
- package/docs/workbench.md +7 -1
- package/glyphs/glyphs.js +6 -4
- package/llms.txt +139 -14
- package/package.json +50 -12
- package/qwik/index.d.ts +42 -59
- package/qwik/index.d.ts.map +1 -0
- package/qwik/index.js +55 -3
- package/react/index.d.ts +39 -61
- package/react/index.d.ts.map +1 -0
- package/react/index.js +57 -3
- package/solid/index.d.ts +64 -61
- package/solid/index.d.ts.map +1 -0
- package/solid/index.js +60 -3
- package/tokens/d2.d.ts +38 -0
- package/tokens/d2.js +71 -0
- package/tokens/d2.json +43 -0
- package/tokens/index.d.ts +5 -5
- package/tokens/index.js +15 -1
- package/tokens/index.json +9 -0
- package/tokens/mermaid.d.ts +23 -0
- package/tokens/mermaid.js +181 -0
- package/tokens/mermaid.json +163 -0
- package/tokens/resolved.json +45 -1
- package/tokens/skins.js +3 -2
- package/tokens/tokens.dtcg.json +26 -0
- package/tokens/vega.d.ts +34 -0
- package/tokens/vega.js +155 -0
- package/tokens/vega.json +179 -0
package/css/feedback.css
CHANGED
|
@@ -212,8 +212,27 @@
|
|
|
212
212
|
line-height: 1;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
/* Touch: enlarge the dismiss/close hit areas to the project's coarse-pointer
|
|
216
|
+
tap-target floor (2.9rem, as in primitives.css / forms.css) without changing
|
|
217
|
+
the desktop glyph size. The box is centred so the glyph stays put. */
|
|
218
|
+
@media (pointer: coarse) {
|
|
219
|
+
.ui-alert__dismiss,
|
|
220
|
+
.ui-toast__close {
|
|
221
|
+
display: inline-grid;
|
|
222
|
+
place-items: center;
|
|
223
|
+
min-block-size: 2.9rem;
|
|
224
|
+
min-inline-size: 2.9rem;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.ui-alert__dismiss {
|
|
228
|
+
padding: 0;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@media (hover: hover) {
|
|
233
|
+
.ui-toast__close:hover {
|
|
234
|
+
color: var(--text);
|
|
235
|
+
}
|
|
217
236
|
}
|
|
218
237
|
|
|
219
238
|
.ui-toast--accent::before {
|
|
@@ -420,6 +439,7 @@
|
|
|
420
439
|
.ui-progress__bar {
|
|
421
440
|
background: var(--accent);
|
|
422
441
|
block-size: 100%;
|
|
442
|
+
display: block;
|
|
423
443
|
transition: inline-size var(--duration-base) var(--ease-out);
|
|
424
444
|
inline-size: calc(clamp(0, var(--value, 0), 100) * 1%);
|
|
425
445
|
}
|
|
@@ -465,6 +485,7 @@
|
|
|
465
485
|
.ui-meter__fill {
|
|
466
486
|
background: var(--text-dim);
|
|
467
487
|
block-size: 100%;
|
|
488
|
+
display: block;
|
|
468
489
|
transition: inline-size var(--duration-base) var(--ease-out);
|
|
469
490
|
inline-size: calc(clamp(0, var(--value, 0), 100) * 1%);
|
|
470
491
|
}
|
|
@@ -485,6 +506,10 @@
|
|
|
485
506
|
background: var(--danger);
|
|
486
507
|
}
|
|
487
508
|
|
|
509
|
+
.ui-meter--info .ui-meter__fill {
|
|
510
|
+
background: var(--info);
|
|
511
|
+
}
|
|
512
|
+
|
|
488
513
|
/* --- Steps — progress through a multi-step flow. Use an <ol>; the
|
|
489
514
|
current step is aria-current="step" (no class), completed steps take
|
|
490
515
|
--done. Counter-numbered markers, hairline connectors. --- */
|
|
@@ -553,3 +578,36 @@
|
|
|
553
578
|
border-color: var(--accent);
|
|
554
579
|
color: var(--button-text);
|
|
555
580
|
}
|
|
581
|
+
|
|
582
|
+
/* Print: the progress/meter fill is the data (a measured proportion), so its
|
|
583
|
+
painted background must survive the print "economy" default. The fill tokens
|
|
584
|
+
are re-pointed to print-legible inks by the global print remap in base.css. */
|
|
585
|
+
@media print {
|
|
586
|
+
.ui-progress__bar,
|
|
587
|
+
.ui-meter__fill {
|
|
588
|
+
-webkit-print-color-adjust: exact;
|
|
589
|
+
print-color-adjust: exact;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* Forced-colors flattens the fill's tone to the system palette and can erase it
|
|
594
|
+
against the track, dropping the only visual cue of the measured proportion.
|
|
595
|
+
Re-assert a system colour so the bar stays visible; the tone's *semantic* is
|
|
596
|
+
carried by the author-written label beside it, not the colour. (a11y C10.)
|
|
597
|
+
The toned `.ui-meter--TONE .ui-meter__fill` rules are (0,2,0); the bare
|
|
598
|
+
`.ui-meter__fill` reset is only (0,1,0), so it lost — a toned fill stayed
|
|
599
|
+
`var(--TONE)` and was forced to black-on-black (component-audit C3). Match the
|
|
600
|
+
tone specificity here (and set `forced-color-adjust: none`) so every meter,
|
|
601
|
+
toned or not, paints `Highlight`, mirroring the `.ui-dot` precedent. */
|
|
602
|
+
@media (forced-colors: active) {
|
|
603
|
+
.ui-progress__bar,
|
|
604
|
+
.ui-meter__fill,
|
|
605
|
+
.ui-meter--accent .ui-meter__fill,
|
|
606
|
+
.ui-meter--success .ui-meter__fill,
|
|
607
|
+
.ui-meter--warning .ui-meter__fill,
|
|
608
|
+
.ui-meter--danger .ui-meter__fill,
|
|
609
|
+
.ui-meter--info .ui-meter__fill {
|
|
610
|
+
background: Highlight;
|
|
611
|
+
forced-color-adjust: none;
|
|
612
|
+
}
|
|
613
|
+
}
|
package/css/forms.css
CHANGED
|
@@ -77,6 +77,29 @@
|
|
|
77
77
|
opacity: 0.5;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/* Disabled affordance parity. The text inputs above style :disabled directly;
|
|
81
|
+
the controls that WRAP a native input (switch/check/segmented) showed no
|
|
82
|
+
disabled cue and their label kept cursor:pointer — a lie. Mirror the cue via
|
|
83
|
+
:has(input:disabled); the native-element controls (range/file) take :disabled
|
|
84
|
+
directly. (a11y/forms review C4.) */
|
|
85
|
+
.ui-range:disabled,
|
|
86
|
+
.ui-file:disabled,
|
|
87
|
+
.ui-switch:has(input:disabled),
|
|
88
|
+
.ui-check:has(input:disabled),
|
|
89
|
+
.ui-segmented__option:has(input:disabled) {
|
|
90
|
+
cursor: not-allowed;
|
|
91
|
+
opacity: 0.5;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Keep autofilled fields on-theme — the UA's yellow fill otherwise paints over
|
|
95
|
+
the monochrome surface and breaks the contrast story. (forms review C24.) */
|
|
96
|
+
.ui-input:autofill,
|
|
97
|
+
.ui-search input:autofill {
|
|
98
|
+
-webkit-text-fill-color: var(--text);
|
|
99
|
+
box-shadow: inset 0 0 0 100rem var(--bg-elevated);
|
|
100
|
+
caret-color: var(--text);
|
|
101
|
+
}
|
|
102
|
+
|
|
80
103
|
.ui-input[aria-invalid='true'],
|
|
81
104
|
.ui-select[aria-invalid='true'],
|
|
82
105
|
.ui-textarea[aria-invalid='true'] {
|
|
@@ -221,7 +244,10 @@
|
|
|
221
244
|
|
|
222
245
|
.ui-error-summary__title {
|
|
223
246
|
color: var(--danger);
|
|
224
|
-
|
|
247
|
+
|
|
248
|
+
/* The must-be-read failure heading uses the legible sans, not the low-legibility
|
|
249
|
+
Doto display face — reserve --display for decorative numerals. (forms C27.) */
|
|
250
|
+
font-family: var(--sans);
|
|
225
251
|
font-size: var(--text-sm);
|
|
226
252
|
font-weight: 700;
|
|
227
253
|
letter-spacing: var(--tracking-wide);
|
|
@@ -262,6 +288,14 @@
|
|
|
262
288
|
border-color: var(--accent);
|
|
263
289
|
}
|
|
264
290
|
|
|
291
|
+
/* Keyboard focus ring to match every sibling input (which use a 2px ring); the
|
|
292
|
+
border-colour shift alone read markedly fainter on this one control. Keyed to
|
|
293
|
+
:focus-visible on the inner input so it stays keyboard-only. (a11y review C12.) */
|
|
294
|
+
.ui-search:has(input:focus-visible) {
|
|
295
|
+
outline: 2px solid var(--focus-ring);
|
|
296
|
+
outline-offset: 1px;
|
|
297
|
+
}
|
|
298
|
+
|
|
265
299
|
.ui-search:focus-within::before {
|
|
266
300
|
background: var(--accent);
|
|
267
301
|
}
|
|
@@ -384,6 +418,13 @@
|
|
|
384
418
|
min-block-size: 2.9rem;
|
|
385
419
|
}
|
|
386
420
|
|
|
421
|
+
/* The whole label is the toggle target — float it to the ~44px floor so the
|
|
422
|
+
small track/box isn't a sub-target on touch (WCAG 2.5.8 — C24). */
|
|
423
|
+
.ui-switch,
|
|
424
|
+
.ui-check {
|
|
425
|
+
min-block-size: 2.9rem;
|
|
426
|
+
}
|
|
427
|
+
|
|
387
428
|
.ui-check input {
|
|
388
429
|
block-size: 1.15rem;
|
|
389
430
|
inline-size: 1.15rem;
|
package/css/legend.css
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* ==========================================================================
|
|
2
2
|
legend — opt-in data keys for charts, reports, and analytical figures.
|
|
3
3
|
|
|
4
|
-
A standalone, portable
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
A standalone, portable data key: `.ui-legend` reads the Tier-4 `--chart-*`
|
|
5
|
+
tokens and pairs with any chart (a token-themed inline SVG/canvas figure, or
|
|
6
|
+
an external engine like Vega-Lite — see docs/vega.md). Not imported by
|
|
7
|
+
core.css — import it beside css/dataviz.css.
|
|
8
8
|
|
|
9
9
|
Bronto paints and positions; it owns no scales, data mapping, or series
|
|
10
10
|
state. Colour is never the sole channel: a swatch mirrors its chart mark
|
|
@@ -205,12 +205,16 @@
|
|
|
205
205
|
|
|
206
206
|
.ui-legend--with-values .ui-legend__value {
|
|
207
207
|
margin-inline-start: 0;
|
|
208
|
+
text-align: end;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
/* Interactive entries are real <button aria-pressed> controls. Bronto styles
|
|
211
212
|
the control + the inactive state; behaviors/legend.js (optional) flips
|
|
212
|
-
aria-pressed and emits an event. The host hides the series and announces it.
|
|
213
|
-
|
|
213
|
+
aria-pressed and emits an event. The host hides the series and announces it.
|
|
214
|
+
Scoped to button/role=button so a non-button entry never gets cursor:pointer
|
|
215
|
+
— a pointer-only affordance with no keyboard path is a lie (WCAG 2.1.1 — C11;
|
|
216
|
+
the behavior ignores and warns about non-button entries to match). */
|
|
217
|
+
.ui-legend--interactive .ui-legend__item:is(button, [role='button']) {
|
|
214
218
|
background: none;
|
|
215
219
|
border: 0;
|
|
216
220
|
border-radius: var(--radius-sm);
|
|
@@ -222,7 +226,7 @@
|
|
|
222
226
|
text-align: start;
|
|
223
227
|
}
|
|
224
228
|
|
|
225
|
-
.ui-legend--interactive .ui-legend__item:focus-visible {
|
|
229
|
+
.ui-legend--interactive .ui-legend__item:is(button, [role='button']):focus-visible {
|
|
226
230
|
outline: 2px solid var(--accent);
|
|
227
231
|
outline-offset: 2px;
|
|
228
232
|
}
|
package/css/marks.css
CHANGED
|
@@ -12,12 +12,20 @@
|
|
|
12
12
|
========================================================================== */
|
|
13
13
|
|
|
14
14
|
.ui-mark {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
/* No base `--mark-color`: each draw style supplies its own fallback default
|
|
16
|
+
(highlight/box keep the subtle `--line-strong`; the full-opacity
|
|
17
|
+
`--underline`/`--strike` decorations default to the darker `--text-dim` so
|
|
18
|
+
they read on a light surface — C33). A tone modifier SETS `--mark-color`,
|
|
19
|
+
so it still wins everywhere the fallback would otherwise apply. */
|
|
20
|
+
|
|
21
|
+
/* A bare `<mark>` carries the UA `background-color: yellow`; the translucent
|
|
22
|
+
highlight gradient sits on top of it, so without this reset the UA yellow
|
|
23
|
+
bleeds through (an author declaration always beats the UA origin). */
|
|
24
|
+
background-color: transparent;
|
|
17
25
|
background-image: linear-gradient(
|
|
18
26
|
90deg,
|
|
19
|
-
color-mix(in srgb, var(--mark-color) 30%, transparent),
|
|
20
|
-
color-mix(in srgb, var(--mark-color) 30%, transparent)
|
|
27
|
+
color-mix(in srgb, var(--mark-color, var(--line-strong)) 30%, transparent),
|
|
28
|
+
color-mix(in srgb, var(--mark-color, var(--line-strong)) 30%, transparent)
|
|
21
29
|
);
|
|
22
30
|
background-repeat: no-repeat;
|
|
23
31
|
background-size: 100% 100%;
|
|
@@ -59,7 +67,7 @@
|
|
|
59
67
|
.ui-mark--underline {
|
|
60
68
|
background: none;
|
|
61
69
|
padding: 0;
|
|
62
|
-
text-decoration-color: var(--mark-color);
|
|
70
|
+
text-decoration-color: var(--mark-color, var(--text-dim));
|
|
63
71
|
text-decoration-line: underline;
|
|
64
72
|
text-decoration-thickness: 0.12em;
|
|
65
73
|
text-underline-offset: 0.18em;
|
|
@@ -67,21 +75,24 @@
|
|
|
67
75
|
|
|
68
76
|
.ui-mark--box {
|
|
69
77
|
background: none;
|
|
70
|
-
border: 1px solid var(--mark-color);
|
|
78
|
+
border: 1px solid var(--mark-color, var(--line-strong));
|
|
71
79
|
border-radius: var(--radius-sm);
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
.ui-mark--strike {
|
|
75
83
|
background: none;
|
|
76
84
|
padding: 0;
|
|
77
|
-
text-decoration-color: var(--mark-color);
|
|
85
|
+
text-decoration-color: var(--mark-color, var(--text-dim));
|
|
78
86
|
text-decoration-line: line-through;
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
/* Draw-on highlight sweep. Only the highlight fill animates, and only when
|
|
82
90
|
motion is welcome — reduced-motion keeps the resting full highlight. */
|
|
83
91
|
@media (prefers-reduced-motion: no-preference) {
|
|
84
|
-
|
|
92
|
+
/* The sweep animates `background-size`, i.e. the highlight FILL — so it is
|
|
93
|
+
inert on the no-fill styles (underline/box/strike). Scope it out rather
|
|
94
|
+
than let `--draw` look applied but do nothing. (content review C14.) */
|
|
95
|
+
.ui-mark--draw:not(.ui-mark--underline, .ui-mark--box, .ui-mark--strike) {
|
|
85
96
|
animation: ui-mark-draw 0.6s var(--ease, ease) both;
|
|
86
97
|
}
|
|
87
98
|
}
|
|
@@ -120,6 +131,10 @@
|
|
|
120
131
|
--mark-color: var(--accent);
|
|
121
132
|
}
|
|
122
133
|
|
|
134
|
+
.ui-bracket-note--success {
|
|
135
|
+
--mark-color: var(--success);
|
|
136
|
+
}
|
|
137
|
+
|
|
123
138
|
.ui-bracket-note--warning {
|
|
124
139
|
--mark-color: var(--warning);
|
|
125
140
|
}
|
|
@@ -142,3 +157,18 @@
|
|
|
142
157
|
text-decoration-line: underline;
|
|
143
158
|
}
|
|
144
159
|
}
|
|
160
|
+
|
|
161
|
+
/* Print: the highlight is a painted background, so force it through the print
|
|
162
|
+
"economy" default that would otherwise drop it. Settle the draw sweep to its
|
|
163
|
+
resting full highlight in case it is mid-animation when the page is printed. */
|
|
164
|
+
@media print {
|
|
165
|
+
.ui-mark {
|
|
166
|
+
-webkit-print-color-adjust: exact;
|
|
167
|
+
background-size: 100% 100%;
|
|
168
|
+
print-color-adjust: exact;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.ui-mark--draw {
|
|
172
|
+
animation: none;
|
|
173
|
+
}
|
|
174
|
+
}
|
package/css/motion.css
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/* ==========================================================================
|
|
2
2
|
motion — keyframes + animation utilities
|
|
3
3
|
Restrained, dot-flavoured. Everything collapses under reduced-motion.
|
|
4
|
-
Keyframes from the legacy responsive layer live here so consumers that
|
|
5
|
-
import only core.css keep their existing animations.
|
|
6
4
|
========================================================================== */
|
|
7
5
|
|
|
8
6
|
@keyframes pulseDot {
|
|
@@ -18,45 +16,6 @@
|
|
|
18
16
|
}
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
@keyframes scan {
|
|
22
|
-
0% {
|
|
23
|
-
transform: translateY(-120%);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
100% {
|
|
27
|
-
transform: translateY(320%);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@keyframes growBar {
|
|
32
|
-
to {
|
|
33
|
-
transform: scaleX(1);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@keyframes drawLine {
|
|
38
|
-
from {
|
|
39
|
-
opacity: 0;
|
|
40
|
-
stroke-dasharray: 0 999;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
to {
|
|
44
|
-
opacity: 1;
|
|
45
|
-
stroke-dasharray: 999 0;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@keyframes pulseNode {
|
|
50
|
-
0%,
|
|
51
|
-
100% {
|
|
52
|
-
transform: scale(1);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
50% {
|
|
56
|
-
transform: scale(1.08);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
19
|
@keyframes pulseRing {
|
|
61
20
|
0% {
|
|
62
21
|
opacity: 0.7;
|
|
@@ -233,9 +192,13 @@
|
|
|
233
192
|
animation-delay: 360ms;
|
|
234
193
|
}
|
|
235
194
|
|
|
236
|
-
/* Reveal-on-scroll: add .ui-reveal, toggle .is-visible
|
|
237
|
-
|
|
238
|
-
|
|
195
|
+
/* Reveal-on-scroll: add .ui-reveal, then toggle .is-visible (e.g. from an
|
|
196
|
+
IntersectionObserver you own) to play it in. For a ZERO-JS reveal, use
|
|
197
|
+
`.ui-scroll-reveal` (scroll-driven, CSS-only) instead — that is the path for
|
|
198
|
+
an LLM-authored or no-build report. The hidden initial state below is gated
|
|
199
|
+
on `scripting: enabled`, so with scripting OFF the content is fully visible
|
|
200
|
+
and never silently hidden behind a script that will never run. */
|
|
201
|
+
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) {
|
|
239
202
|
.ui-reveal {
|
|
240
203
|
opacity: 0;
|
|
241
204
|
transform: translateY(14px);
|
|
@@ -365,14 +328,31 @@
|
|
|
365
328
|
scroll-behavior: auto;
|
|
366
329
|
}
|
|
367
330
|
|
|
331
|
+
/* !important is required: inside @layer bronto, layered rules lose to
|
|
332
|
+
unlayered author rules at equal specificity — only a layered !important
|
|
333
|
+
stays authoritative over unlayered declarations (CSS cascade §6.2). */
|
|
368
334
|
*,
|
|
369
335
|
*::before,
|
|
370
336
|
*::after {
|
|
371
337
|
animation-duration: 0.01ms !important;
|
|
372
338
|
animation-iteration-count: 1 !important;
|
|
339
|
+
|
|
340
|
+
/* Zero the delay too: `.ui-stagger` children animate `uiRise` with
|
|
341
|
+
`fill-mode: both`, so a non-zero `animation-delay` holds them at the
|
|
342
|
+
`opacity: 0` from-state for the full delay and then pops them in — the
|
|
343
|
+
exact late flash a reduced-motion user asked to avoid (C4). */
|
|
344
|
+
animation-delay: 0s !important;
|
|
373
345
|
transition-duration: 0.01ms !important;
|
|
374
346
|
}
|
|
375
347
|
|
|
348
|
+
/* Freeze the shimmer gradient mid-sweep would expose a diagonal band.
|
|
349
|
+
Flatten the skeleton to its base panel colour instead. */
|
|
350
|
+
.ui-skeleton {
|
|
351
|
+
animation: none;
|
|
352
|
+
background: var(--panel-soft);
|
|
353
|
+
background-size: auto;
|
|
354
|
+
}
|
|
355
|
+
|
|
376
356
|
.ui-reveal {
|
|
377
357
|
opacity: 1 !important;
|
|
378
358
|
transform: none !important;
|
package/css/navigation.css
CHANGED
package/css/overlay.css
CHANGED
|
@@ -249,7 +249,7 @@ dialog.ui-modal[open]::backdrop {
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
.ui-menu__item::before {
|
|
252
|
-
background:
|
|
252
|
+
background: currentcolor;
|
|
253
253
|
border-radius: 50%;
|
|
254
254
|
content: '';
|
|
255
255
|
block-size: 0.3rem;
|
|
@@ -275,6 +275,15 @@ dialog.ui-modal[open]::backdrop {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
.ui-menu__item:focus-visible {
|
|
279
|
+
background: var(--bg-accent);
|
|
280
|
+
color: var(--text);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.ui-menu__item:focus-visible::before {
|
|
284
|
+
opacity: 1;
|
|
285
|
+
}
|
|
286
|
+
|
|
278
287
|
/* --- Combobox: an input with a filtered listbox popup (APG pattern,
|
|
279
288
|
wired by initCombobox). Reuses the menu surface tokens. --- */
|
|
280
289
|
.ui-combobox {
|
|
@@ -363,6 +372,14 @@ dialog.ui-modal[open]::backdrop {
|
|
|
363
372
|
inset-inline: 0;
|
|
364
373
|
min-inline-size: 0;
|
|
365
374
|
}
|
|
375
|
+
|
|
376
|
+
/* Let the combobox shed its 14rem floor and span the viewport so the input
|
|
377
|
+
(and its full-width listbox) can't overflow a narrow screen. */
|
|
378
|
+
.ui-combobox {
|
|
379
|
+
display: block;
|
|
380
|
+
inline-size: 100%;
|
|
381
|
+
min-inline-size: 0;
|
|
382
|
+
}
|
|
366
383
|
}
|
|
367
384
|
|
|
368
385
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -376,3 +393,16 @@ dialog.ui-modal[open]::backdrop {
|
|
|
376
393
|
transition: none;
|
|
377
394
|
}
|
|
378
395
|
}
|
|
396
|
+
|
|
397
|
+
/* Forced-colors drops both `backdrop-filter: blur()` and the `color-mix()`
|
|
398
|
+
scrim, so the dialog/lightbox would float over an undimmed page with no
|
|
399
|
+
separation. Re-assert a translucent scrim with `forced-color-adjust: none`
|
|
400
|
+
so the layering reads in High Contrast, matching the meter/dot precedent
|
|
401
|
+
(C28). */
|
|
402
|
+
@media (forced-colors: active) {
|
|
403
|
+
.ui-modal::backdrop,
|
|
404
|
+
.ui-lightbox::backdrop {
|
|
405
|
+
background: color-mix(in srgb, #000 50%, transparent);
|
|
406
|
+
forced-color-adjust: none;
|
|
407
|
+
}
|
|
408
|
+
}
|
package/css/primitives.css
CHANGED
|
@@ -87,7 +87,11 @@
|
|
|
87
87
|
(island-safe). Inert until applied, so existing layouts/baselines
|
|
88
88
|
are unaffected. */
|
|
89
89
|
.ui-cq {
|
|
90
|
-
container
|
|
90
|
+
/* The container-name is fixed: the `@container bronto (…)` collapse queries
|
|
91
|
+
below hardcode `bronto`. There is no `--cq-name` knob — the name is not
|
|
92
|
+
author-tunable, and an author-set `--cq-name` is simply ignored (nothing
|
|
93
|
+
reads it). Name a different container yourself if you need a custom scope. */
|
|
94
|
+
container: bronto / inline-size;
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
@container bronto (max-width: 34rem) {
|
|
@@ -196,8 +200,9 @@
|
|
|
196
200
|
font-family: var(--display);
|
|
197
201
|
font-size: 1.9rem;
|
|
198
202
|
font-variant-numeric: tabular-nums;
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
font-weight: var(--display-weight-strong);
|
|
204
|
+
letter-spacing: 0.02em;
|
|
205
|
+
line-height: 1.05;
|
|
201
206
|
}
|
|
202
207
|
|
|
203
208
|
.ui-stat__delta,
|
|
@@ -216,6 +221,22 @@
|
|
|
216
221
|
color: var(--danger);
|
|
217
222
|
}
|
|
218
223
|
|
|
224
|
+
/* A direction arrow is the non-colour channel — colour alone (success/danger)
|
|
225
|
+
fails WCAG 1.4.1, so the tile carries the same ▲/▼ glyph as `.ui-delta`
|
|
226
|
+
(C13). Marked aria-hidden-equivalent by being generated content; the sign is
|
|
227
|
+
still in the author's text ("+12%"). */
|
|
228
|
+
.ui-stat__delta.is-pos::before,
|
|
229
|
+
.ui-app-metric__delta.is-pos::before {
|
|
230
|
+
content: '▲ ';
|
|
231
|
+
font-size: 0.85em;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.ui-stat__delta.is-neg::before,
|
|
235
|
+
.ui-app-metric__delta.is-neg::before {
|
|
236
|
+
content: '▼ ';
|
|
237
|
+
font-size: 0.85em;
|
|
238
|
+
}
|
|
239
|
+
|
|
219
240
|
/* --- Numeric value vocabulary ---
|
|
220
241
|
The same tabular/aligned/tone intent the table has shipped since
|
|
221
242
|
0.1.0, but freed from `.ui-table` so cards, stats and inline figures
|
|
@@ -238,6 +259,58 @@
|
|
|
238
259
|
color: var(--text-dim);
|
|
239
260
|
}
|
|
240
261
|
|
|
262
|
+
/* --- Trend delta ---
|
|
263
|
+
A standalone change indicator: a direction arrow (the non-colour channel,
|
|
264
|
+
WCAG 1.4.1) plus the figure, tabular so a column of deltas aligns.
|
|
265
|
+
Direction sets the glyph AND the conventional tone (up = positive,
|
|
266
|
+
down = negative). When "up" is the bad direction (latency, error rate,
|
|
267
|
+
cost, churn), add `ui-delta--invert` to swap only the tone — the arrow
|
|
268
|
+
still reports real direction. Pair with words; the arrow is visual, not a
|
|
269
|
+
substitute for stating the change. */
|
|
270
|
+
.ui-delta {
|
|
271
|
+
align-items: baseline;
|
|
272
|
+
color: var(--text-soft);
|
|
273
|
+
display: inline-flex;
|
|
274
|
+
font-variant-numeric: tabular-nums;
|
|
275
|
+
gap: 0.2em;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.ui-delta::before {
|
|
279
|
+
font-size: 0.85em;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.ui-delta--up {
|
|
283
|
+
color: var(--success);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.ui-delta--up::before {
|
|
287
|
+
content: '▲';
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.ui-delta--down {
|
|
291
|
+
color: var(--danger);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.ui-delta--down::before {
|
|
295
|
+
content: '▼';
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.ui-delta--flat {
|
|
299
|
+
color: var(--text-dim);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.ui-delta--flat::before {
|
|
303
|
+
content: '—';
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.ui-delta--invert.ui-delta--up {
|
|
307
|
+
color: var(--danger);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.ui-delta--invert.ui-delta--down {
|
|
311
|
+
color: var(--success);
|
|
312
|
+
}
|
|
313
|
+
|
|
241
314
|
/* --- Eyebrow / section label — dot-matrix face --- */
|
|
242
315
|
|
|
243
316
|
.ui-eyebrow {
|
|
@@ -338,6 +411,15 @@
|
|
|
338
411
|
opacity: 0.45;
|
|
339
412
|
}
|
|
340
413
|
|
|
414
|
+
/* aria-disabled keeps the element in the a11y tree but the browser does NOT
|
|
415
|
+
block activation (a real <a class="ui-button" aria-disabled> still navigates,
|
|
416
|
+
a <button> still fires). Looking dead while staying live is the defect — kill
|
|
417
|
+
pointer activation. (a11y review C3; native :disabled already inert.) */
|
|
418
|
+
.ui-button[aria-disabled='true'],
|
|
419
|
+
.ui-link[aria-disabled='true'] {
|
|
420
|
+
pointer-events: none;
|
|
421
|
+
}
|
|
422
|
+
|
|
341
423
|
.ui-button:active {
|
|
342
424
|
transform: translateY(1px);
|
|
343
425
|
}
|
|
@@ -401,8 +483,8 @@
|
|
|
401
483
|
|
|
402
484
|
.ui-link--arrow::after,
|
|
403
485
|
.ui-link--cta::after {
|
|
404
|
-
border-inline-end: 1px solid
|
|
405
|
-
border-block-start: 1px solid
|
|
486
|
+
border-inline-end: 1px solid currentcolor;
|
|
487
|
+
border-block-start: 1px solid currentcolor;
|
|
406
488
|
content: '';
|
|
407
489
|
block-size: 0.42rem;
|
|
408
490
|
transform: rotate(45deg);
|
|
@@ -459,6 +541,10 @@
|
|
|
459
541
|
(the soft tint can't carry 4.5:1 small-bold tone-on-tone — WCAG). */
|
|
460
542
|
.ui-badge--accent {
|
|
461
543
|
background: var(--accent-soft);
|
|
544
|
+
|
|
545
|
+
/* Accent mixes 45% (vs 40% for the status tones below) on purpose: the brand
|
|
546
|
+
hue is lower-chroma here than the status hues, so it needs a touch more to
|
|
547
|
+
read at the same border weight. Intentional, not a copy-paste slip. (Q15.) */
|
|
462
548
|
border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
|
|
463
549
|
}
|
|
464
550
|
|