@neuravision/construct 2.0.3 → 2.1.2
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 +318 -0
- package/README.md +158 -149
- package/behaviors/combobox.js +486 -0
- package/behaviors/drawer.js +18 -0
- package/behaviors/dropdown.js +310 -0
- package/behaviors/index.d.ts +335 -0
- package/behaviors/index.js +9 -0
- package/behaviors/internal/dialog-controller.js +421 -0
- package/behaviors/internal/dom.js +408 -0
- package/behaviors/internal/overlay.js +241 -0
- package/behaviors/internal/popup-layer.js +190 -0
- package/behaviors/modal.js +17 -0
- package/behaviors/popover.js +278 -0
- package/behaviors/select-menu.js +344 -0
- package/behaviors/tabs.js +241 -0
- package/behaviors/toggle-group.js +266 -0
- package/behaviors/tooltip.js +257 -0
- package/components/README.md +319 -83
- package/components/_shared.css +22 -10
- package/components/_shell-shared.css +20 -4
- package/components/accordion.css +8 -0
- package/components/app-shell-v2.css +28 -14
- package/components/app-shell.css +30 -14
- package/components/badge.css +15 -0
- package/components/banner.css +32 -1
- package/components/button.css +103 -15
- package/components/card.css +67 -8
- package/components/chart.css +26 -0
- package/components/checkbox.css +35 -2
- package/components/chip.css +30 -2
- package/components/combobox.css +21 -0
- package/components/datepicker.css +58 -9
- package/components/datum.css +277 -0
- package/components/dropdown.css +23 -3
- package/components/field.css +6 -4
- package/components/file-upload.css +1 -1
- package/components/index.css +5 -0
- package/components/list.css +28 -2
- package/components/meter.css +182 -0
- package/components/navbar.css +102 -4
- package/components/pagination.css +18 -0
- package/components/progress-bar.css +22 -1
- package/components/select-menu.css +8 -0
- package/components/select.css +8 -0
- package/components/sidebar.css +15 -2
- package/components/skip-link.css +6 -2
- package/components/slider.css +7 -1
- package/components/status.css +107 -0
- package/components/switch.css +66 -5
- package/components/table.css +53 -4
- package/components/tabs.css +55 -3
- package/components/toast.css +10 -1
- package/components/toggle-group.css +16 -5
- package/components/toolbar.css +17 -1
- package/components/tooltip.css +4 -0
- package/components/tree.css +30 -0
- package/docs/architecture.md +79 -0
- package/docs/behaviors.md +122 -0
- package/docs/fonts.md +70 -0
- package/docs/governance.md +85 -0
- package/docs/guidelines.md +72 -25
- package/examples/react/README.md +20 -0
- package/examples/react/SettingsModal.jsx +66 -0
- package/examples/react/construct.css +5 -0
- package/fonts.css +10 -0
- package/foundations.css +14 -1
- package/package.json +76 -21
- package/schemas/components.schema.json +122 -0
- package/schemas/examples/theme.example.json +27 -0
- package/schemas/primitives.schema.json +135 -0
- package/schemas/semantic.schema.json +224 -0
- package/schemas/theme.schema.json +63 -0
- package/scripts/build-tokens.mjs +1499 -0
- package/scripts/construct-theme.mjs +43 -0
- package/scripts/validate-tokens.mjs +25 -0
- package/standalone/accordion.css +3 -0
- package/standalone/alert.css +3 -0
- package/standalone/app-shell-v2.css +4 -0
- package/standalone/app-shell.css +4 -0
- package/standalone/avatar.css +3 -0
- package/standalone/badge.css +3 -0
- package/standalone/banner.css +3 -0
- package/standalone/breadcrumbs.css +3 -0
- package/standalone/button.css +3 -0
- package/standalone/card.css +3 -0
- package/standalone/chart.css +3 -0
- package/standalone/checkbox.css +3 -0
- package/standalone/chip.css +3 -0
- package/standalone/combobox.css +3 -0
- package/standalone/core.css +4 -0
- package/standalone/data-table.css +3 -0
- package/standalone/datepicker.css +3 -0
- package/standalone/datum.css +3 -0
- package/standalone/divider.css +3 -0
- package/standalone/drawer.css +3 -0
- package/standalone/dropdown.css +3 -0
- package/standalone/empty-state.css +3 -0
- package/standalone/field.css +3 -0
- package/standalone/file-upload.css +3 -0
- package/standalone/icon.css +3 -0
- package/standalone/input.css +3 -0
- package/standalone/list.css +3 -0
- package/standalone/meter.css +3 -0
- package/standalone/modal.css +3 -0
- package/standalone/navbar.css +3 -0
- package/standalone/pagination.css +3 -0
- package/standalone/popover.css +3 -0
- package/standalone/progress-bar.css +3 -0
- package/standalone/select-menu.css +3 -0
- package/standalone/select.css +3 -0
- package/standalone/sidebar.css +3 -0
- package/standalone/skeleton.css +3 -0
- package/standalone/skip-link.css +3 -0
- package/standalone/slider.css +3 -0
- package/standalone/spinner.css +3 -0
- package/standalone/status.css +3 -0
- package/standalone/switch.css +3 -0
- package/standalone/table.css +3 -0
- package/standalone/tabs.css +3 -0
- package/standalone/textarea.css +3 -0
- package/standalone/toast.css +3 -0
- package/standalone/toggle-group.css +3 -0
- package/standalone/toolbar.css +3 -0
- package/standalone/tooltip.css +3 -0
- package/standalone/tree.css +3 -0
- package/themes/README.md +37 -0
- package/themes/walnut.theme.json +106 -0
- package/tokens/README.md +135 -123
- package/tokens/components.json +64 -0
- package/tokens/primitives.json +268 -0
- package/tokens/semantic.dark.json +94 -0
- package/tokens/semantic.high-contrast-dark.json +94 -0
- package/tokens/semantic.high-contrast.json +94 -0
- package/tokens/semantic.light.json +179 -0
- package/tokens/tokens.css +960 -58
- package/tokens/tokens.js +729 -120
- package/tokens/tokens.json +1158 -116
- package/tokens/tokens.ts +729 -120
package/components/index.css
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
@import './_shared.css';
|
|
5
5
|
@import './_keyframes.css';
|
|
6
6
|
|
|
7
|
+
/* Structural grammar — the "datum" reference-line vocabulary */
|
|
8
|
+
@import './datum.css';
|
|
9
|
+
|
|
7
10
|
/* Components */
|
|
8
11
|
@import './button.css';
|
|
9
12
|
@import './field.css';
|
|
@@ -33,6 +36,7 @@
|
|
|
33
36
|
@import './skeleton.css';
|
|
34
37
|
@import './icon.css';
|
|
35
38
|
@import './progress-bar.css';
|
|
39
|
+
@import './meter.css';
|
|
36
40
|
@import './toolbar.css';
|
|
37
41
|
@import './sidebar.css';
|
|
38
42
|
@import './toggle-group.css';
|
|
@@ -52,3 +56,4 @@
|
|
|
52
56
|
@import './list.css';
|
|
53
57
|
@import './tree.css';
|
|
54
58
|
@import './chart.css';
|
|
59
|
+
@import './status.css';
|
package/components/list.css
CHANGED
|
@@ -90,6 +90,9 @@
|
|
|
90
90
|
min-height: 0;
|
|
91
91
|
text-decoration: none;
|
|
92
92
|
color: inherit;
|
|
93
|
+
/* The datum edge slides in on selection instead of popping. */
|
|
94
|
+
transition: background var(--duration-fast) var(--easing-standard),
|
|
95
|
+
box-shadow var(--duration-fast) var(--easing-standard);
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
/* ── Item Slots ── */
|
|
@@ -222,7 +225,7 @@
|
|
|
222
225
|
.ct-list__item[aria-selected='true'] {
|
|
223
226
|
background: var(--ct-list-item-bg-active);
|
|
224
227
|
/* The datum: an orange leading edge marks the active/selected item. */
|
|
225
|
-
box-shadow: inset var(--
|
|
228
|
+
box-shadow: inset var(--component-datum-edge-width) 0 0 0 var(--color-brand-accent);
|
|
226
229
|
}
|
|
227
230
|
|
|
228
231
|
.ct-list__item--active .ct-list__item-title,
|
|
@@ -351,7 +354,8 @@
|
|
|
351
354
|
.ct-list--nav .ct-list__item {
|
|
352
355
|
cursor: pointer;
|
|
353
356
|
transition: background var(--duration-fast) var(--easing-standard),
|
|
354
|
-
color var(--duration-fast) var(--easing-standard)
|
|
357
|
+
color var(--duration-fast) var(--easing-standard),
|
|
358
|
+
box-shadow var(--duration-fast) var(--easing-standard);
|
|
355
359
|
}
|
|
356
360
|
|
|
357
361
|
@media (hover: hover) {
|
|
@@ -475,3 +479,25 @@
|
|
|
475
479
|
animation: none;
|
|
476
480
|
}
|
|
477
481
|
}
|
|
482
|
+
|
|
483
|
+
/* ── Forced Colors ── */
|
|
484
|
+
|
|
485
|
+
@media (forced-colors: active) {
|
|
486
|
+
/* The datum edge is an inset box-shadow, which forced colors drops —
|
|
487
|
+
re-encode it as a border. */
|
|
488
|
+
.ct-list__item--active,
|
|
489
|
+
.ct-list__item[data-state='active'],
|
|
490
|
+
.ct-list__item[aria-selected='true'] {
|
|
491
|
+
border-inline-start: var(--component-datum-edge-width) solid SelectedItem;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/* Skeleton rows hide their placeholder text with `color: transparent`;
|
|
495
|
+
keep the decorative loading state hidden when forced colors would
|
|
496
|
+
otherwise reveal it. */
|
|
497
|
+
.ct-list__item--skeleton .ct-list__item-leading,
|
|
498
|
+
.ct-list__item--skeleton .ct-list__item-title,
|
|
499
|
+
.ct-list__item--skeleton .ct-list__item-description,
|
|
500
|
+
.ct-list__item--skeleton .ct-list__item-trailing {
|
|
501
|
+
forced-color-adjust: none;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/* ── Segmented Meter / Stacked Progress ────────────────────────── */
|
|
2
|
+
|
|
3
|
+
.ct-meter {
|
|
4
|
+
--ct-meter-height: var(--component-meter-height);
|
|
5
|
+
--ct-meter-radius: var(--component-meter-radius);
|
|
6
|
+
--ct-meter-track: var(--component-meter-track);
|
|
7
|
+
--ct-meter-gap: var(--space-3);
|
|
8
|
+
|
|
9
|
+
display: grid;
|
|
10
|
+
gap: var(--ct-meter-gap);
|
|
11
|
+
width: 100%;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.ct-meter__header {
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: baseline;
|
|
17
|
+
justify-content: space-between;
|
|
18
|
+
gap: var(--space-3);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ct-meter__label {
|
|
22
|
+
color: var(--color-text-primary);
|
|
23
|
+
font-size: var(--font-size-sm);
|
|
24
|
+
font-weight: var(--font-weight-semibold);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.ct-meter__summary {
|
|
28
|
+
color: var(--color-text-secondary);
|
|
29
|
+
font-size: var(--font-size-xs);
|
|
30
|
+
font-variant-numeric: tabular-nums lining-nums;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.ct-meter__track {
|
|
34
|
+
display: flex;
|
|
35
|
+
width: 100%;
|
|
36
|
+
height: var(--ct-meter-height);
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
border: var(--border-thin) solid var(--color-border-subtle);
|
|
39
|
+
border-radius: var(--ct-meter-radius);
|
|
40
|
+
background: var(--ct-meter-track);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ct-meter__segment {
|
|
44
|
+
--ct-meter-segment-color: var(--color-brand-primary);
|
|
45
|
+
|
|
46
|
+
flex: 0 0 var(--ct-meter-segment-size, auto);
|
|
47
|
+
min-width: 0;
|
|
48
|
+
height: 100%;
|
|
49
|
+
background: var(--ct-meter-segment-color);
|
|
50
|
+
transition: flex-basis var(--duration-normal) var(--easing-standard);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.ct-meter__segment[data-variant='accent'] {
|
|
54
|
+
--ct-meter-segment-color: var(--color-brand-accent);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.ct-meter__segment[data-variant='info'] {
|
|
58
|
+
--ct-meter-segment-color: var(--color-state-info);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.ct-meter__segment[data-variant='success'] {
|
|
62
|
+
--ct-meter-segment-color: var(--color-state-success);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.ct-meter__segment[data-variant='warning'] {
|
|
66
|
+
--ct-meter-segment-color: var(--color-state-warning);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.ct-meter__segment[data-variant='danger'] {
|
|
70
|
+
--ct-meter-segment-color: var(--color-state-danger);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ct-meter__segment[data-variant='muted'] {
|
|
74
|
+
--ct-meter-segment-color: var(--color-border-strong);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.ct-meter__legend {
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-wrap: wrap;
|
|
80
|
+
gap: var(--space-2) var(--space-5);
|
|
81
|
+
margin: 0;
|
|
82
|
+
padding: 0;
|
|
83
|
+
color: var(--color-text-secondary);
|
|
84
|
+
font-size: var(--font-size-xs);
|
|
85
|
+
list-style: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.ct-meter__legend-item {
|
|
89
|
+
display: inline-flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: var(--space-2);
|
|
92
|
+
min-width: 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.ct-meter__marker {
|
|
96
|
+
--ct-meter-segment-color: var(--color-brand-primary);
|
|
97
|
+
|
|
98
|
+
width: var(--space-3);
|
|
99
|
+
height: var(--space-3);
|
|
100
|
+
flex: none;
|
|
101
|
+
border: var(--border-thin) solid currentColor;
|
|
102
|
+
border-radius: var(--radius-xs);
|
|
103
|
+
background: var(--ct-meter-segment-color);
|
|
104
|
+
color: var(--ct-meter-segment-color);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ct-meter__marker[data-variant='accent'] {
|
|
108
|
+
--ct-meter-segment-color: var(--color-brand-accent);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.ct-meter__marker[data-variant='info'] {
|
|
112
|
+
--ct-meter-segment-color: var(--color-state-info);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.ct-meter__marker[data-variant='success'] {
|
|
116
|
+
--ct-meter-segment-color: var(--color-state-success);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.ct-meter__marker[data-variant='warning'] {
|
|
120
|
+
--ct-meter-segment-color: var(--color-state-warning);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.ct-meter__marker[data-variant='danger'] {
|
|
124
|
+
--ct-meter-segment-color: var(--color-state-danger);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.ct-meter__marker[data-variant='muted'] {
|
|
128
|
+
--ct-meter-segment-color: var(--color-border-strong);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.ct-meter__legend-value {
|
|
132
|
+
color: var(--color-text-primary);
|
|
133
|
+
font-weight: var(--font-weight-semibold);
|
|
134
|
+
font-variant-numeric: tabular-nums lining-nums;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.ct-meter__message {
|
|
138
|
+
margin: 0;
|
|
139
|
+
color: var(--color-text-secondary);
|
|
140
|
+
font-size: var(--font-size-xs);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.ct-meter:is([aria-busy='true'], [data-state='loading']) {
|
|
144
|
+
cursor: wait;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.ct-meter:is([aria-disabled='true'], [data-state='disabled']) {
|
|
148
|
+
opacity: var(--opacity-disabled);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.ct-meter[data-state='error'] .ct-meter__track {
|
|
152
|
+
border-color: var(--color-state-danger-border);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.ct-meter[data-state='error'] .ct-meter__message {
|
|
156
|
+
color: var(--color-state-danger-text);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.ct-meter--sm {
|
|
160
|
+
--ct-meter-height: var(--space-2);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.ct-meter--lg {
|
|
164
|
+
--ct-meter-height: var(--space-5);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@media (prefers-reduced-motion: reduce) {
|
|
168
|
+
.ct-meter__segment {
|
|
169
|
+
transition: none;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@media (forced-colors: active) {
|
|
174
|
+
.ct-meter__track,
|
|
175
|
+
.ct-meter__marker {
|
|
176
|
+
border-color: currentColor;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.ct-meter__segment + .ct-meter__segment {
|
|
180
|
+
border-inline-start: var(--border-medium) solid currentColor;
|
|
181
|
+
}
|
|
182
|
+
}
|
package/components/navbar.css
CHANGED
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
display: flex;
|
|
30
30
|
align-items: center;
|
|
31
31
|
gap: var(--ct-navbar-gap);
|
|
32
|
-
|
|
32
|
+
width: 100%;
|
|
33
|
+
min-width: 0;
|
|
34
|
+
/* min-height, not height: the bar must grow with text scaling. */
|
|
35
|
+
min-height: var(--ct-navbar-height);
|
|
33
36
|
padding: var(--ct-navbar-padding-y) var(--ct-navbar-padding-x);
|
|
34
37
|
background: var(--ct-navbar-bg);
|
|
35
38
|
border-bottom: var(--border-thin) solid var(--ct-navbar-border-color);
|
|
@@ -44,6 +47,7 @@
|
|
|
44
47
|
display: flex;
|
|
45
48
|
align-items: center;
|
|
46
49
|
flex-shrink: 0;
|
|
50
|
+
min-width: 0;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
.ct-navbar__brand {
|
|
@@ -56,6 +60,12 @@
|
|
|
56
60
|
flex-shrink: 0;
|
|
57
61
|
}
|
|
58
62
|
|
|
63
|
+
.ct-navbar__brand:focus-visible {
|
|
64
|
+
outline: var(--border-medium) solid var(--color-focus-ring);
|
|
65
|
+
outline-offset: var(--border-medium);
|
|
66
|
+
border-radius: var(--ct-navbar-item-radius);
|
|
67
|
+
}
|
|
68
|
+
|
|
59
69
|
.ct-navbar__logo {
|
|
60
70
|
height: var(--ct-navbar-brand-img-height);
|
|
61
71
|
width: auto;
|
|
@@ -63,8 +73,11 @@
|
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
.ct-navbar__title {
|
|
76
|
+
min-width: 0;
|
|
66
77
|
font-size: var(--font-size-md);
|
|
67
78
|
font-weight: var(--font-weight-semibold);
|
|
79
|
+
overflow: hidden;
|
|
80
|
+
text-overflow: ellipsis;
|
|
68
81
|
white-space: nowrap;
|
|
69
82
|
}
|
|
70
83
|
|
|
@@ -345,6 +358,8 @@
|
|
|
345
358
|
border-bottom: var(--border-thin) solid var(--ct-navbar-border-color);
|
|
346
359
|
box-shadow: var(--shadow-md);
|
|
347
360
|
padding: var(--space-4);
|
|
361
|
+
max-height: calc(100dvh - var(--ct-navbar-height));
|
|
362
|
+
overflow-y: auto;
|
|
348
363
|
display: flex;
|
|
349
364
|
flex-direction: column;
|
|
350
365
|
gap: var(--space-1);
|
|
@@ -420,8 +435,36 @@
|
|
|
420
435
|
font-size: var(--font-size-lg);
|
|
421
436
|
}
|
|
422
437
|
|
|
438
|
+
/* ── Compact Product Header ────────────────────────────────────── */
|
|
439
|
+
|
|
440
|
+
.ct-navbar--compact {
|
|
441
|
+
--ct-navbar-height: var(--control-height-lg);
|
|
442
|
+
--ct-navbar-padding-x: var(--space-4);
|
|
443
|
+
--ct-navbar-padding-y: var(--space-2);
|
|
444
|
+
--ct-navbar-gap: var(--space-2);
|
|
445
|
+
--ct-navbar-actions-gap: var(--space-1);
|
|
446
|
+
--ct-navbar-brand-img-height: var(--space-8);
|
|
447
|
+
--ct-navbar-item-padding-x: var(--space-3);
|
|
448
|
+
--ct-navbar-item-padding-y: var(--space-2);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.ct-navbar--compact .ct-navbar__brand {
|
|
452
|
+
min-width: 0;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.ct-navbar--compact .ct-navbar__title {
|
|
456
|
+
max-width: 18ch;
|
|
457
|
+
font-size: var(--font-size-sm);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.ct-navbar--compact .ct-navbar__actions {
|
|
461
|
+
flex-shrink: 0;
|
|
462
|
+
}
|
|
463
|
+
|
|
423
464
|
/* ── Sticky ────────────────────────────────────────────────────── */
|
|
424
465
|
|
|
466
|
+
/* Consumers: set --ct-scroll-offset-top on :root (see foundations.css) so
|
|
467
|
+
scrolled-to content is not obscured behind the bar (WCAG 2.4.11). */
|
|
425
468
|
.ct-navbar--sticky {
|
|
426
469
|
position: sticky;
|
|
427
470
|
inset-block-start: 0;
|
|
@@ -429,6 +472,8 @@
|
|
|
429
472
|
|
|
430
473
|
/* ── Fixed ─────────────────────────────────────────────────────── */
|
|
431
474
|
|
|
475
|
+
/* Consumers: set --ct-scroll-offset-top on :root (see foundations.css) so
|
|
476
|
+
scrolled-to content is not obscured behind the bar (WCAG 2.4.11). */
|
|
432
477
|
.ct-navbar--fixed {
|
|
433
478
|
position: fixed;
|
|
434
479
|
inset-block-start: 0;
|
|
@@ -463,7 +508,7 @@
|
|
|
463
508
|
|
|
464
509
|
@media (hover: hover) {
|
|
465
510
|
.ct-navbar--transparent .ct-navbar__link:hover {
|
|
466
|
-
background:
|
|
511
|
+
background: color-mix(in srgb, var(--color-text-inverse) 15%, transparent);
|
|
467
512
|
color: var(--color-text-inverse);
|
|
468
513
|
}
|
|
469
514
|
}
|
|
@@ -486,7 +531,7 @@
|
|
|
486
531
|
|
|
487
532
|
@media (hover: hover) {
|
|
488
533
|
.ct-navbar--transparent .ct-navbar__toggle:hover {
|
|
489
|
-
background:
|
|
534
|
+
background: color-mix(in srgb, var(--color-text-inverse) 15%, transparent);
|
|
490
535
|
}
|
|
491
536
|
}
|
|
492
537
|
|
|
@@ -590,15 +635,57 @@
|
|
|
590
635
|
position: relative;
|
|
591
636
|
}
|
|
592
637
|
|
|
593
|
-
.ct-navbar__nav {
|
|
638
|
+
.ct-navbar:has(.ct-navbar__toggle) .ct-navbar__nav {
|
|
594
639
|
display: none;
|
|
595
640
|
}
|
|
596
641
|
|
|
642
|
+
/* Progressive fallback: when no mobile toggle/menu is supplied, keep
|
|
643
|
+
primary navigation reachable as a horizontally scrollable row. */
|
|
644
|
+
.ct-navbar:not(:has(.ct-navbar__toggle)) nav {
|
|
645
|
+
min-width: 0;
|
|
646
|
+
overflow-x: auto;
|
|
647
|
+
scrollbar-width: thin;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.ct-navbar:not(:has(.ct-navbar__toggle)) .ct-navbar__nav {
|
|
651
|
+
display: flex;
|
|
652
|
+
width: max-content;
|
|
653
|
+
}
|
|
654
|
+
|
|
597
655
|
.ct-navbar__toggle {
|
|
598
656
|
display: inline-flex;
|
|
599
657
|
}
|
|
600
658
|
}
|
|
601
659
|
|
|
660
|
+
@media (max-width: 599px) { /* < sm breakpoint (600px) */
|
|
661
|
+
.ct-navbar,
|
|
662
|
+
.ct-navbar--compact {
|
|
663
|
+
--ct-navbar-padding-x: var(--space-3);
|
|
664
|
+
--ct-navbar-gap: var(--space-1);
|
|
665
|
+
--ct-navbar-actions-gap: var(--space-1);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.ct-navbar--compact .ct-navbar__title {
|
|
669
|
+
max-width: 10ch;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
.ct-navbar--compact .ct-navbar__actions [data-priority='secondary'] {
|
|
673
|
+
display: none;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.ct-navbar__mobile-menu {
|
|
677
|
+
padding: var(--space-3);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/* ── Construct 44×44 target policy (WCAG 2.2 SC 2.5.5 is AAA) ──── */
|
|
682
|
+
|
|
683
|
+
@media (pointer: coarse) {
|
|
684
|
+
.ct-navbar__link {
|
|
685
|
+
min-height: 44px;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
602
689
|
/* ── Reduced Motion ────────────────────────────────────────────── */
|
|
603
690
|
|
|
604
691
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -612,3 +699,14 @@
|
|
|
612
699
|
transition: none;
|
|
613
700
|
}
|
|
614
701
|
}
|
|
702
|
+
|
|
703
|
+
@media (forced-colors: active) {
|
|
704
|
+
.ct-navbar {
|
|
705
|
+
border-color: currentColor;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.ct-navbar__link[aria-current='page'] {
|
|
709
|
+
outline: var(--border-medium) solid currentColor;
|
|
710
|
+
outline-offset: calc(-1 * var(--border-medium));
|
|
711
|
+
}
|
|
712
|
+
}
|
|
@@ -110,6 +110,15 @@
|
|
|
110
110
|
--ct-pagination-line-height: var(--line-height-md);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/* Construct 44×44 target policy: --control-height-xs is not coarse-remapped
|
|
114
|
+
in _shared.css, so the small variant is bumped explicitly. */
|
|
115
|
+
@media (pointer: coarse) {
|
|
116
|
+
.ct-pagination--sm {
|
|
117
|
+
--ct-pagination-height: 44px;
|
|
118
|
+
--ct-pagination-min-width: 44px;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
113
122
|
/* ── Pagination: Responsive ───────────────────────────────── */
|
|
114
123
|
|
|
115
124
|
@media (max-width: 599px) { /* < sm breakpoint (600px) */
|
|
@@ -129,3 +138,12 @@
|
|
|
129
138
|
transition: none;
|
|
130
139
|
}
|
|
131
140
|
}
|
|
141
|
+
|
|
142
|
+
/* ── Pagination: Forced Colors ────────────────────────────── */
|
|
143
|
+
|
|
144
|
+
@media (forced-colors: active) {
|
|
145
|
+
.ct-pagination__link[aria-current='page'] {
|
|
146
|
+
outline: var(--border-medium) solid currentColor;
|
|
147
|
+
outline-offset: calc(-1 * var(--border-medium));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -4,12 +4,16 @@
|
|
|
4
4
|
--ct-progress-height: 8px;
|
|
5
5
|
--ct-progress-radius: var(--radius-pill);
|
|
6
6
|
--ct-progress-bg: var(--color-bg-muted);
|
|
7
|
-
|
|
7
|
+
/* accent-strong, not accent: the fill must hold 3:1 against the muted
|
|
8
|
+
track (1.4.11) — validated as "strong accent on muted" per theme. */
|
|
9
|
+
--ct-progress-fill: var(--color-brand-accent-strong);
|
|
8
10
|
|
|
9
11
|
width: 100%;
|
|
10
12
|
height: var(--ct-progress-height);
|
|
11
13
|
border-radius: var(--ct-progress-radius);
|
|
12
14
|
background: var(--ct-progress-bg);
|
|
15
|
+
/* the track boundary, so the component is identifiable on any surface */
|
|
16
|
+
border: var(--border-thin) solid var(--color-border-default);
|
|
13
17
|
overflow: hidden;
|
|
14
18
|
}
|
|
15
19
|
|
|
@@ -52,5 +56,22 @@
|
|
|
52
56
|
@media (prefers-reduced-motion: reduce) {
|
|
53
57
|
.ct-progress-bar--indeterminate .ct-progress-bar__track {
|
|
54
58
|
animation: none;
|
|
59
|
+
/* A frozen 30% sweep reads as determinate-and-stuck; a full-width
|
|
60
|
+
dimmed fill reads as "busy, extent unknown". */
|
|
61
|
+
width: 100%;
|
|
62
|
+
opacity: 0.4;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@media (forced-colors: active) {
|
|
67
|
+
/* Backgrounds are forced to Canvas — without these the whole bar
|
|
68
|
+
disappears (mirrors the meter's forced-colors strategy). */
|
|
69
|
+
.ct-progress-bar {
|
|
70
|
+
border: 1px solid ButtonText;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ct-progress-bar__track {
|
|
74
|
+
background: SelectedItem;
|
|
75
|
+
forced-color-adjust: none;
|
|
55
76
|
}
|
|
56
77
|
}
|
|
@@ -257,6 +257,14 @@
|
|
|
257
257
|
--ct-select-menu-option-padding-y: var(--space-4);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
/* ── Construct 44×44 target policy (WCAG 2.2 SC 2.5.5 is AAA) ───── */
|
|
261
|
+
|
|
262
|
+
@media (pointer: coarse) {
|
|
263
|
+
.ct-select-menu__option {
|
|
264
|
+
min-block-size: 44px;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
260
268
|
/* ── Reduced motion ─────────────────────────────────────────────── */
|
|
261
269
|
|
|
262
270
|
@media (prefers-reduced-motion: reduce) {
|
package/components/select.css
CHANGED
|
@@ -28,3 +28,11 @@
|
|
|
28
28
|
appearance: none;
|
|
29
29
|
padding-inline-end: calc(var(--space-4) + 0.75em + var(--space-4));
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
@media (forced-colors: active) {
|
|
33
|
+
/* The native arrow is removed via appearance: none, so the mask-drawn
|
|
34
|
+
chevron must be repainted with system ink. */
|
|
35
|
+
.ct-select-wrap::after {
|
|
36
|
+
background-color: ButtonText;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/components/sidebar.css
CHANGED
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
box-shadow: var(--shadow-lg);
|
|
41
41
|
/* LTR: slide in from the left */
|
|
42
42
|
translate: -100% 0;
|
|
43
|
+
/* keep off-canvas content out of tab order and the accessibility tree */
|
|
44
|
+
visibility: hidden;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
/* RTL: overlay sidebar starts at inline-start (right edge) — slide in from the right */
|
|
@@ -49,6 +51,7 @@
|
|
|
49
51
|
|
|
50
52
|
.ct-sidebar--over[data-state='open'] {
|
|
51
53
|
translate: 0 0;
|
|
54
|
+
visibility: visible;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
/* Push variant: slides off-screen and collapses flex space via negative margin */
|
|
@@ -129,7 +132,8 @@
|
|
|
129
132
|
font-size: var(--font-size-sm);
|
|
130
133
|
font-weight: var(--font-weight-medium);
|
|
131
134
|
transition: background var(--duration-fast) var(--easing-standard),
|
|
132
|
-
color var(--duration-fast) var(--easing-standard)
|
|
135
|
+
color var(--duration-fast) var(--easing-standard),
|
|
136
|
+
box-shadow var(--duration-fast) var(--easing-standard);
|
|
133
137
|
cursor: pointer;
|
|
134
138
|
}
|
|
135
139
|
|
|
@@ -151,7 +155,7 @@
|
|
|
151
155
|
color: var(--color-brand-primary);
|
|
152
156
|
font-weight: var(--font-weight-semibold);
|
|
153
157
|
/* The datum: an orange leading edge marks the current location. */
|
|
154
|
-
box-shadow: inset var(--
|
|
158
|
+
box-shadow: inset var(--component-datum-edge-width) 0 0 0 var(--color-brand-accent);
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
.ct-nav-item__icon {
|
|
@@ -183,3 +187,12 @@
|
|
|
183
187
|
background: var(--color-brand-accent);
|
|
184
188
|
color: var(--color-brand-on-accent);
|
|
185
189
|
}
|
|
190
|
+
|
|
191
|
+
@media (forced-colors: active) {
|
|
192
|
+
/* The datum edge is an inset box-shadow, which forced colors drops —
|
|
193
|
+
re-encode it as a border. */
|
|
194
|
+
.ct-nav-item--active,
|
|
195
|
+
.ct-nav-item[aria-current='page'] {
|
|
196
|
+
border-inline-start: var(--component-datum-edge-width) solid SelectedItem;
|
|
197
|
+
}
|
|
198
|
+
}
|
package/components/skip-link.css
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
z-index: var(--z-tooltip);
|
|
13
13
|
padding: var(--space-4) var(--space-6);
|
|
14
14
|
background: var(--color-brand-primary);
|
|
15
|
-
|
|
15
|
+
/* on-primary, not inverse: inverse is near-invisible on the light primary of the dark theme */
|
|
16
|
+
color: var(--color-text-on-primary);
|
|
16
17
|
font-family: var(--font-family-body);
|
|
17
18
|
font-size: var(--font-size-sm);
|
|
18
19
|
font-weight: var(--font-weight-semibold);
|
|
@@ -27,7 +28,10 @@
|
|
|
27
28
|
.ct-skip-link:focus,
|
|
28
29
|
.ct-skip-link:focus-visible {
|
|
29
30
|
transform: translateY(0);
|
|
30
|
-
|
|
31
|
+
/* on-primary, not the focus ring: the inset outline draws on the primary
|
|
32
|
+
background, and on-primary is the pairing validated against it in every
|
|
33
|
+
theme (the orange ring fails 3:1 on the dark theme's light primary). */
|
|
34
|
+
outline: 2px solid var(--color-text-on-primary);
|
|
31
35
|
outline-offset: -2px;
|
|
32
36
|
}
|
|
33
37
|
|
package/components/slider.css
CHANGED
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
appearance: none;
|
|
24
24
|
width: 100%;
|
|
25
25
|
height: var(--ct-slider-thumb-size);
|
|
26
|
+
/* WCAG 2.2 SC 2.5.8: small thumbs shrink the strip below 24px — keep
|
|
27
|
+
the pointer target at least that tall in fine-pointer contexts. */
|
|
28
|
+
min-height: 24px;
|
|
26
29
|
background: transparent;
|
|
27
30
|
cursor: pointer;
|
|
28
31
|
margin: 0;
|
|
@@ -199,6 +202,8 @@
|
|
|
199
202
|
position: relative;
|
|
200
203
|
flex: 1;
|
|
201
204
|
height: var(--ct-slider-thumb-size);
|
|
205
|
+
/* Same 24px pointer-target floor as the single-thumb input strip. */
|
|
206
|
+
min-height: 24px;
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
.ct-slider--range .ct-slider__track::after {
|
|
@@ -269,7 +274,8 @@
|
|
|
269
274
|
opacity: 1;
|
|
270
275
|
}
|
|
271
276
|
|
|
272
|
-
/*
|
|
277
|
+
/* Construct 44×44 target policy: meets the size in WCAG 2.2 SC 2.5.5
|
|
278
|
+
(AAA) and exceeds the AA minimum in SC 2.5.8. */
|
|
273
279
|
|
|
274
280
|
@media (pointer: coarse) {
|
|
275
281
|
.ct-slider {
|