@apliteni/apliteni-ui 0.36.0 → 0.37.1
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/README.md +11 -0
- package/package.json +1 -1
- package/react/dist/index.css +3 -2
- package/src/components/index.js +3 -3
- package/src/components/success.js +2 -2
- package/src/inline.js +1 -1
- package/src/styles/back.css +2 -2
- package/src/styles/badge.css +13 -13
- package/src/styles/base.css +5 -5
- package/src/styles/button.css +7 -7
- package/src/styles/callout.css +16 -20
- package/src/styles/card.css +4 -4
- package/src/styles/code.css +3 -3
- package/src/styles/command-palette.css +6 -6
- package/src/styles/confirm.css +2 -2
- package/src/styles/drawer.css +5 -5
- package/src/styles/dropdown.css +12 -12
- package/src/styles/feedback.css +9 -9
- package/src/styles/footer.css +3 -3
- package/src/styles/input.css +11 -11
- package/src/styles/layout.css +15 -15
- package/src/styles/loading.css +1 -1
- package/src/styles/motion.css +1 -1
- package/src/styles/nav.css +18 -18
- package/src/styles/pagination.css +1 -1
- package/src/styles/segmented.css +2 -2
- package/src/styles/success.css +8 -6
- package/src/styles/table.css +3 -3
- package/src/styles/tabs.css +2 -2
- package/src/styles/tooltip.css +1 -1
- package/src/styles/topbar.css +11 -11
- package/src/tokens/tokens.css +49 -7
package/README.md
CHANGED
|
@@ -105,6 +105,10 @@ import { tokensCss, topbarCss, cssText } from '@apliteni/apliteni-ui/inline';
|
|
|
105
105
|
// …inline tokensCss + topbarCss into the <style> you serve.
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
`cssText` includes every sheet. When selecting individual sheets from `styles`,
|
|
109
|
+
`successPanel()` needs both `styles.callout` (panel layout) and `styles.success`
|
|
110
|
+
(shared glowing check and reduced-motion styles), after `tokensCss` and `baseCss`.
|
|
111
|
+
|
|
108
112
|
## React components (stateful surfaces)
|
|
109
113
|
|
|
110
114
|
`DataTable`, `Pagination`, `Modal`, `Button`, `Badge`, `Card` and `Icon` — same `.ui-*` classes,
|
|
@@ -151,6 +155,13 @@ Each accent re-points only the accent family (`--accent`, `--purple*`, `--glow-p
|
|
|
151
155
|
stay put — so **every accent works in both themes** and every component follows with no
|
|
152
156
|
component-level change.
|
|
153
157
|
|
|
158
|
+
Focus uses a surface-coloured gap, a solid band and a decorative glow. Tune
|
|
159
|
+
`--ring-width`, `--ring-color`, `--ring-gap-width` and `--ring-gap` at the root;
|
|
160
|
+
`--ring` remains the composed shadow. Kit surfaces recompose it to match their
|
|
161
|
+
background, so an ancestor's custom `--ring` must also be applied on those surfaces.
|
|
162
|
+
The page shell inherits root overrides; it does not introduce another composition.
|
|
163
|
+
See [the focus-ring contract](docs/specification.md#the-focus-ring).
|
|
164
|
+
|
|
154
165
|
Both attributes are overrides, not requirements: with neither present the kit paints dark
|
|
155
166
|
Nebula, and `data-accent` alone paints that accent on the dark theme. An absent `data-theme`
|
|
156
167
|
is *not* "follow the system" — the kit ships no `prefers-color-scheme` rule, so a host that
|
package/package.json
CHANGED
package/react/dist/index.css
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
.rx-modal {
|
|
45
45
|
width: min(480px, 92vw);
|
|
46
46
|
background: var(--bg-elevated);
|
|
47
|
+
--ring-gap: var(--bg-elevated);
|
|
47
48
|
border: 1px solid var(--border-strong);
|
|
48
49
|
box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
|
|
49
50
|
border-radius: var(--radius-xl);
|
|
@@ -92,8 +93,8 @@
|
|
|
92
93
|
color: inherit;
|
|
93
94
|
}
|
|
94
95
|
.rx-sort:focus-visible {
|
|
95
|
-
outline: 2px solid
|
|
96
|
-
|
|
96
|
+
outline: 2px solid transparent;
|
|
97
|
+
box-shadow: var(--ring);
|
|
97
98
|
border-radius: 4px;
|
|
98
99
|
}
|
|
99
100
|
.rx-caret {
|
package/src/components/index.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// viz/ server-render idiom so the portal can adopt them with no framework.
|
|
3
3
|
import { icon } from '../assets/icons.js';
|
|
4
4
|
import { illo } from '../assets/illustrations.js';
|
|
5
|
+
import { successCheck } from './success.js';
|
|
5
6
|
const HTML_ENTITIES = { '&': '&', '<': '<', '>': '>', '"': '"' };
|
|
6
7
|
const cx = (...a) => a.filter(Boolean).join(' ');
|
|
7
8
|
export const esc = (s) => String(s == null ? '' : s).replace(/[&<>"]/g, (c) => HTML_ENTITIES[c]);
|
|
8
|
-
|
|
9
9
|
// ---- Button --------------------------------------------------------------
|
|
10
10
|
// `iconSvg` is a raw leading-icon SVG string (trusted markup, not escaped) for
|
|
11
11
|
// branded glyphs the kit's icon set doesn't own — e.g. a Google "G". It takes
|
|
@@ -261,9 +261,9 @@ export function toast({
|
|
|
261
261
|
// The kit also publishes success() from components/success.js, which is the same
|
|
262
262
|
// idea at page size: layouts, a backdrop, follow-up buttons and an auto-redirect
|
|
263
263
|
// countdown. Pick by how much of the screen the confirmation owns. The two share
|
|
264
|
-
//
|
|
264
|
+
// the glowing check; their layout and content remain independent.
|
|
265
265
|
export function successPanel({ title = 'Done', sub = '' } = {}) {
|
|
266
|
-
return `<div class="ui-success"><div class="ui-success__check">${
|
|
266
|
+
return `<div class="ui-success"><div class="ui-success__check">${successCheck()}</div><div class="ui-success__title">${esc(title)}</div>${sub ? `<div class="ui-success__sub">${esc(sub)}</div>` : ''}</div>`;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
// ---- Empty state ---------------------------------------------------------
|
|
@@ -60,8 +60,8 @@ function countdownEl({ seconds = 5, label = 'Redirecting' } = {}) {
|
|
|
60
60
|
// For a confirmation that stays inside the page the user is already on, the kit
|
|
61
61
|
// publishes successPanel() from components/index.js — a check, a title and one
|
|
62
62
|
// line of sub, and nothing to configure. Pick by how much of the screen the
|
|
63
|
-
// confirmation owns. The two share
|
|
64
|
-
//
|
|
63
|
+
// confirmation owns. The two share the glowing check, while their layout
|
|
64
|
+
// and content remain independent.
|
|
65
65
|
export function success({
|
|
66
66
|
layout = 'hero', // 'hero' | 'split' | 'compact'
|
|
67
67
|
level, // heading level of the title; see the note below
|
package/src/inline.js
CHANGED
|
@@ -25,7 +25,7 @@ export const baseCss = read('styles/base.css');
|
|
|
25
25
|
// Canonical topbar (same class names the portal already uses).
|
|
26
26
|
export const topbarCss = read('styles/topbar.css');
|
|
27
27
|
|
|
28
|
-
// Individual
|
|
28
|
+
// Individual sheets; successPanel() needs both styles.callout and styles.success.
|
|
29
29
|
export const styles = {
|
|
30
30
|
base: baseCss,
|
|
31
31
|
reducedMotion: read('styles/reduced-motion.css'),
|
package/src/styles/back.css
CHANGED
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
(0,2,0) wins without !important — the argument `.ui-nav .ui-nav__item` makes
|
|
32
32
|
in nav.css. */
|
|
33
33
|
.ui-back[href] { color: var(--text); }
|
|
34
|
-
.ui-back[href]:hover { color: var(--strong); background: var(--surface-2); }
|
|
35
|
-
.ui-back:focus-visible { outline:
|
|
34
|
+
.ui-back[href]:hover { color: var(--strong); background: var(--surface-2); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
|
|
35
|
+
.ui-back:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring); }
|
|
36
36
|
|
|
37
37
|
/* 16px, with the stroke raised to match: the glyph set draws at 1.7 on a 24-unit
|
|
38
38
|
box, which is 1.13 CSS px at this size and under the kit's 1.5 for a stroked
|
package/src/styles/badge.css
CHANGED
|
@@ -15,29 +15,29 @@
|
|
|
15
15
|
padding: 3px 9px;
|
|
16
16
|
border-radius: var(--radius-pill);
|
|
17
17
|
color: var(--text);
|
|
18
|
-
background: var(--surface-2);
|
|
18
|
+
background: var(--surface-2); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */
|
|
19
19
|
white-space: nowrap;
|
|
20
20
|
}
|
|
21
21
|
/* Status chips take the --chip-* pairs, so the light app's solid fills live in
|
|
22
22
|
tokens.css rather than in a theme override down here: on white the glow-tints
|
|
23
23
|
wash out and the ink has to deepen to clear AA, and that is a token decision. */
|
|
24
|
-
.ui-badge--live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
25
|
-
.ui-badge--soon { color: var(--purple-mid); background: var(--glow-purple); }
|
|
26
|
-
.ui-badge--info { color: var(--chip-info-ink); background: var(--chip-info-fill); }
|
|
24
|
+
.ui-badge--live { color: var(--chip-success-ink); background: var(--chip-success-fill); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
25
|
+
.ui-badge--soon { color: var(--purple-mid); background: var(--glow-purple); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
|
|
26
|
+
.ui-badge--info { color: var(--chip-info-ink); background: var(--chip-info-fill); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
27
27
|
.ui-badge--warn { color: var(--chip-warn-ink); background: var(--chip-warn-fill); }
|
|
28
|
-
.ui-badge--danger { color: var(--chip-danger-ink); background: var(--chip-danger-fill); }
|
|
29
|
-
.ui-badge--archive { /* muted-ink: state — archived record */ color: var(--muted); background: var(--surface); }
|
|
28
|
+
.ui-badge--danger { color: var(--chip-danger-ink); background: var(--chip-danger-fill); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
29
|
+
.ui-badge--archive { /* muted-ink: state — archived record */ color: var(--muted); background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
30
30
|
|
|
31
31
|
/* Semantic status variants — for record/row status in data tables
|
|
32
32
|
(paid / verified / pending / failed …). Same chip, mapped to meaning. */
|
|
33
|
-
.ui-badge--success { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
33
|
+
.ui-badge--success { color: var(--chip-success-ink); background: var(--chip-success-fill); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
34
34
|
.ui-badge--pending { color: var(--chip-warn-ink); background: var(--chip-warn-fill); }
|
|
35
|
-
.ui-badge--neutral { color: var(--text); background: var(--surface-2); }
|
|
35
|
+
.ui-badge--neutral { color: var(--text); background: var(--surface-2); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
36
36
|
|
|
37
37
|
/* The two neutral chips are the exception: their light fill is already in the
|
|
38
38
|
surface scale (--surface-3), and only archive uses muted state ink. */
|
|
39
|
-
:root[data-theme="light"] .ui-badge--neutral { background: var(--surface-3); }
|
|
40
|
-
:root[data-theme="light"] .ui-badge--archive { /* muted-ink: state — archived record */ color: var(--muted); background: var(--surface-3); }
|
|
39
|
+
:root[data-theme="light"] .ui-badge--neutral { background: var(--surface-3); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
40
|
+
:root[data-theme="light"] .ui-badge--archive { /* muted-ink: state — archived record */ color: var(--muted); background: var(--surface-3); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
41
41
|
|
|
42
42
|
/* Pill: same shape, sentence case, a touch larger — a metadata chip */
|
|
43
43
|
.ui-pill {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
/* rank: chip */
|
|
48
48
|
font-size: var(--text-xs);
|
|
49
49
|
color: var(--text);
|
|
50
|
-
background: var(--surface-2);
|
|
50
|
+
background: var(--surface-2); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */
|
|
51
51
|
border-radius: var(--radius-pill);
|
|
52
52
|
padding: 4px 11px;
|
|
53
53
|
font-weight: var(--weight-semibold);
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
/* The live pill is the same status paint as the live badge, so it takes the
|
|
56
56
|
same pair. On its own it was --green on --glow-green, which is 3.97:1 over
|
|
57
57
|
white — under AA, while the badge beside it cleared at 4.64:1. See issue #131. */
|
|
58
|
-
.ui-pill--live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
59
|
-
.ui-pill--soon { color: var(--purple-mid); background: var(--glow-purple); }
|
|
58
|
+
.ui-pill--live { color: var(--chip-success-ink); background: var(--chip-success-fill); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
59
|
+
.ui-pill--soon { color: var(--purple-mid); background: var(--glow-purple); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
|
|
60
60
|
|
|
61
61
|
/* Status dot */
|
|
62
62
|
.ui-dot {
|
package/src/styles/base.css
CHANGED
|
@@ -15,7 +15,7 @@ html {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
body {
|
|
18
|
-
background: var(--bg);
|
|
18
|
+
background: var(--bg); /* ring-gap: inherit — page background inherits root overrides. */
|
|
19
19
|
color: var(--text);
|
|
20
20
|
font-family: var(--font-sans);
|
|
21
21
|
font-weight: var(--weight-normal);
|
|
@@ -27,7 +27,7 @@ body {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
::selection {
|
|
30
|
-
background: color-mix(in srgb, var(--accent) 30%, transparent);
|
|
30
|
+
background: color-mix(in srgb, var(--accent) 30%, transparent); /* ring-gap: inherit — selection paint is not a focus container. */
|
|
31
31
|
color: var(--strong);
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -87,7 +87,7 @@ strong {
|
|
|
87
87
|
|
|
88
88
|
/* Spotlight — a soft radial from the top-centre (auth cards, focused heroes). */
|
|
89
89
|
.ui-bg-spotlight::before {
|
|
90
|
-
background: radial-gradient(620px 340px at 50% -12%, var(--glow-purple), transparent 70%);
|
|
90
|
+
background: radial-gradient(620px 340px at 50% -12%, var(--glow-purple), transparent 70%); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */
|
|
91
91
|
}
|
|
92
92
|
/* Grid — a faint token-coloured grid, masked to fade at the edges. */
|
|
93
93
|
.ui-bg-grid::before {
|
|
@@ -107,7 +107,7 @@ strong {
|
|
|
107
107
|
}
|
|
108
108
|
/* Accent wash — a gentle top-down tint in the current accent. */
|
|
109
109
|
.ui-bg-wash::before {
|
|
110
|
-
background: linear-gradient(180deg, var(--glow-purple), transparent 45%);
|
|
110
|
+
background: linear-gradient(180deg, var(--glow-purple), transparent 45%); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/* Layout helpers used by the example apps */
|
|
@@ -142,6 +142,6 @@ svg:where(:not([width]):not([height])) {
|
|
|
142
142
|
.ui-input:focus-visible,
|
|
143
143
|
.ui-seg button:focus-visible,
|
|
144
144
|
.ui-switch:focus-visible {
|
|
145
|
-
outline:
|
|
145
|
+
outline: 2px solid transparent;
|
|
146
146
|
box-shadow: var(--ring);
|
|
147
147
|
}
|
package/src/styles/button.css
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
padding: var(--btn-pad-y) var(--btn-pad-x);
|
|
21
21
|
cursor: pointer;
|
|
22
22
|
border: 1px solid var(--border);
|
|
23
|
-
background: var(--surface-2);
|
|
23
|
+
background: var(--surface-2); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
|
|
24
24
|
color: var(--text);
|
|
25
25
|
white-space: nowrap;
|
|
26
26
|
transition: background var(--dur-fast) var(--ease),
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
.ui-btn:hover {
|
|
34
34
|
border-color: var(--accent);
|
|
35
|
-
background: color-mix(in srgb, var(--accent) 14%, var(--surface-2));
|
|
35
|
+
background: color-mix(in srgb, var(--accent) 14%, var(--surface-2)); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
|
|
36
36
|
color: var(--strong);
|
|
37
37
|
}
|
|
38
38
|
.ui-btn:active { transform: translateY(1px); }
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
color: var(--text);
|
|
60
60
|
}
|
|
61
61
|
.ui-btn--ghost:hover {
|
|
62
|
-
background: var(--surface-2);
|
|
62
|
+
background: var(--surface-2); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
|
|
63
63
|
border-color: transparent;
|
|
64
64
|
color: var(--strong);
|
|
65
65
|
}
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
.ui-btn--danger:hover {
|
|
69
69
|
color: var(--pink);
|
|
70
70
|
border-color: var(--pink);
|
|
71
|
-
background: color-mix(in srgb, var(--pink) 10%, transparent);
|
|
71
|
+
background: color-mix(in srgb, var(--pink) 10%, transparent); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
/* -- Sizes -------------------------------------------------------------- */
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
makes this read as inert; the quiet ink is the rest. #220 */
|
|
94
94
|
.ui-btn:disabled,
|
|
95
95
|
.ui-btn[aria-disabled="true"] {
|
|
96
|
-
background: var(--disabled-surface);
|
|
96
|
+
background: var(--disabled-surface); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
|
|
97
97
|
border-color: var(--disabled-border);
|
|
98
98
|
/* muted-ink: state — unavailable control */ color: var(--disabled-ink);
|
|
99
99
|
cursor: not-allowed;
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
left: 10px; right: 10px; bottom: 5px;
|
|
138
138
|
height: 3px;
|
|
139
139
|
border-radius: 999px;
|
|
140
|
-
background: color-mix(in srgb, var(--accent) 22%, transparent);
|
|
140
|
+
background: color-mix(in srgb, var(--accent) 22%, transparent); /* ring-gap: inherit — decorative paint has no nested focus target. */
|
|
141
141
|
overflow: hidden;
|
|
142
142
|
/* Clean entrance: grow + fade in on state change, once. */
|
|
143
143
|
transform-origin: center;
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
/* On the filled primary the surface IS the accent, so shimmer in the contrast
|
|
157
157
|
colour instead — otherwise the bars vanish into the button. */
|
|
158
158
|
.ui-btn--primary .ui-btn__bars {
|
|
159
|
-
background: color-mix(in srgb, var(--accent-contrast) 26%, transparent);
|
|
159
|
+
background: color-mix(in srgb, var(--accent-contrast) 26%, transparent); /* ring-gap: inherit — decorative paint has no nested focus target. */
|
|
160
160
|
}
|
|
161
161
|
.ui-btn--primary .ui-btn__bars i {
|
|
162
162
|
background: linear-gradient(90deg,
|
package/src/styles/callout.css
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
gap: 12px;
|
|
8
8
|
padding: 15px 17px;
|
|
9
9
|
border-radius: var(--radius-md);
|
|
10
|
-
background: var(--surface-2);
|
|
10
|
+
background: var(--surface-2); --ring-gap: var(--surface-2);
|
|
11
11
|
font-size: calc(var(--text-sm) + 0.5px);
|
|
12
12
|
line-height: 1.55;
|
|
13
13
|
color: var(--text);
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
.ui-callout b { color: var(--text); font-weight: var(--weight-semibold); }
|
|
18
18
|
.ui-callout code { font-family: var(--font-mono); font-size: 0.92em; color: var(--text); }
|
|
19
19
|
|
|
20
|
-
.ui-callout--info { background: var(--glow-cyan); }
|
|
20
|
+
.ui-callout--info { --ring-gap: inherit; background: var(--glow-cyan); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
|
|
21
21
|
.ui-callout--info .ui-callout__icon { color: var(--chip-info-ink); } /* the chip inks, not the raw signals: in light the raw signal cleared the graphic bar by a tenth on its own wash and read as a smudge, and a stroke is read the way text is. The two are the same value in dark by construction, so only light moves. #206 */
|
|
22
|
-
.ui-callout--success { background: var(--glow-green); }
|
|
22
|
+
.ui-callout--success { --ring-gap: inherit; background: var(--glow-green); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
|
|
23
23
|
.ui-callout--success .ui-callout__icon { color: var(--chip-success-ink); }
|
|
24
|
-
.ui-callout--warn { background: color-mix(in srgb, var(--amber) 13%, transparent); }
|
|
24
|
+
.ui-callout--warn { --ring-gap: inherit; background: color-mix(in srgb, var(--amber) 13%, transparent); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
|
|
25
25
|
.ui-callout--warn .ui-callout__icon { color: var(--chip-warn-ink); }
|
|
26
|
-
.ui-callout--danger { background: var(--glow-pink); }
|
|
26
|
+
.ui-callout--danger { --ring-gap: inherit; background: var(--glow-pink); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
|
|
27
27
|
.ui-callout--danger .ui-callout__icon { color: var(--chip-danger-ink); }
|
|
28
28
|
|
|
29
29
|
/* ----------------------------------------------------------------------------
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
the ink is dark and darkens it where the ink is bright — the hovered pair is
|
|
86
86
|
at or above the resting pair in both. */
|
|
87
87
|
.ui-toast__action { flex: none; align-self: center; background: none; border: 0; padding: 4px 9px; border-radius: var(--radius-xs); font: inherit; font-weight: var(--weight-medium); color: var(--toast-action-ink); cursor: pointer; }
|
|
88
|
-
.ui-toast__action:hover { background: color-mix(in srgb, var(--bg) 55%, transparent); }
|
|
88
|
+
.ui-toast__action:hover { background: color-mix(in srgb, var(--bg) 55%, transparent); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
|
|
89
89
|
|
|
90
90
|
.ui-toast__close { flex: none; align-self: flex-start; background: none; border: 0; /* muted-ink: glyph — dismiss icon */ color: var(--muted); cursor: pointer; padding: 2px; display: grid; place-items: center; position: relative; font: inherit; }
|
|
91
91
|
.ui-toast__close svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2.5; }
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
/* style: soft — tinted surface. The shadow used to be its edge, so it takes the
|
|
118
118
|
status-tinted hairline the outline style carries, at half the weight. #295 */
|
|
119
119
|
.ui-toast--soft {
|
|
120
|
-
background: var(--toast-glow);
|
|
120
|
+
background: var(--toast-glow); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */
|
|
121
121
|
border: 1px solid color-mix(in srgb, var(--toast-accent) 22%, transparent);
|
|
122
122
|
--elev-edge: color-mix(in srgb, var(--toast-accent) 11%, transparent);
|
|
123
123
|
}
|
|
@@ -130,8 +130,8 @@
|
|
|
130
130
|
clear each other — and four of the ten status x theme combinations did not.
|
|
131
131
|
Gated for all ten in stories/signal-contrast.test.js. See #149. */
|
|
132
132
|
.ui-toast--solid {
|
|
133
|
-
--toast-ink: var(--signal-solid-ink);
|
|
134
|
-
background: var(--toast-solid);
|
|
133
|
+
--toast-ink: var(--signal-solid-ink); --ring-color: var(--toast-ink);
|
|
134
|
+
background: var(--toast-solid); --ring-gap: var(--toast-solid);
|
|
135
135
|
color: var(--toast-ink);
|
|
136
136
|
/* No inner line: a solid toast has no outer one either. It keeps the drop. */
|
|
137
137
|
--elev-edge: transparent;
|
|
@@ -143,18 +143,18 @@
|
|
|
143
143
|
there, and 2.25 on the dark danger fill — the pair was correct and the
|
|
144
144
|
dilution then spent it. */
|
|
145
145
|
.ui-toast--solid .ui-toast__text { color: var(--toast-ink); }
|
|
146
|
-
.ui-toast--solid .ui-toast__icon { background: color-mix(in srgb, var(--toast-ink) 22%, transparent); color: var(--toast-ink); }
|
|
146
|
+
.ui-toast--solid .ui-toast__icon { background: color-mix(in srgb, var(--toast-ink) 22%, transparent); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ color: var(--toast-ink); }
|
|
147
147
|
.ui-toast--solid .ui-toast__action { color: var(--toast-ink); }
|
|
148
148
|
/* Hover darkens the FILL rather than lightening the ink. Washing the ink over
|
|
149
149
|
itself was the one surface #149 did not reach, and it worked against the pair
|
|
150
150
|
it was drawn from: it pulled the fill towards the ink it has to clear. */
|
|
151
|
-
.ui-toast--solid .ui-toast__action:hover { background: color-mix(in srgb, var(--signal-contrast) 14%, transparent); }
|
|
151
|
+
.ui-toast--solid .ui-toast__action:hover { background: color-mix(in srgb, var(--signal-contrast) 14%, transparent); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
|
|
152
152
|
.ui-toast--solid .ui-toast__close { /* muted-ink: glyph — dismiss icon on solid toast */ color: color-mix(in srgb, var(--toast-ink) 68%, transparent); }
|
|
153
153
|
.ui-toast--solid .ui-toast__close:hover { color: var(--toast-ink); }
|
|
154
|
-
.ui-toast--solid .ui-toast__timer { background: color-mix(in srgb, var(--toast-ink) 55%, transparent); }
|
|
154
|
+
.ui-toast--solid .ui-toast__timer { background: color-mix(in srgb, var(--toast-ink) 55%, transparent); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
155
155
|
|
|
156
156
|
/* style: outline — elevated card with a status-tinted border */
|
|
157
|
-
.ui-toast--outline { background: var(--bg-elevated); border: 1px solid color-mix(in srgb, var(--toast-accent) 40%, transparent); --elev-edge: color-mix(in srgb, var(--toast-accent) 20%, transparent); }
|
|
157
|
+
.ui-toast--outline { background: var(--bg-elevated); --ring-gap: var(--bg-elevated); border: 1px solid color-mix(in srgb, var(--toast-accent) 40%, transparent); --elev-edge: color-mix(in srgb, var(--toast-accent) 20%, transparent); }
|
|
158
158
|
|
|
159
159
|
/* compact — single line, no body text */
|
|
160
160
|
.ui-toast--compact { align-items: center; padding-top: 10px; padding-bottom: 10px; }
|
|
@@ -178,17 +178,13 @@
|
|
|
178
178
|
border-radius: var(--radius-lg);
|
|
179
179
|
padding: 30px;
|
|
180
180
|
text-align: center;
|
|
181
|
-
background: var(--glow-green);
|
|
181
|
+
background: var(--glow-green); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */
|
|
182
182
|
}
|
|
183
183
|
.ui-success__check {
|
|
184
|
+
--sx-green: var(--chip-success-ink);
|
|
184
185
|
width: 48px; height: 48px;
|
|
185
|
-
border-radius: 50%;
|
|
186
|
-
background: var(--green);
|
|
187
|
-
color: var(--signal-contrast);
|
|
188
|
-
display: grid;
|
|
189
|
-
place-items: center;
|
|
190
186
|
margin: 0 auto 14px;
|
|
191
187
|
}
|
|
192
|
-
.ui-success__check
|
|
188
|
+
.ui-success__check .ui-sx__check { width: 100%; height: 100%; }
|
|
193
189
|
.ui-success__title { color: var(--strong); font-size: var(--text-lg); font-weight: var(--weight-semibold); margin-bottom: 5px; }
|
|
194
190
|
.ui-success__sub { color: var(--text); font-size: var(--text-base); }
|
package/src/styles/card.css
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/* Flat since #284 and edged in both themes since #295: the surface is the step, the
|
|
7
7
|
line is what makes it legible. why: docs/specification.md#elevation */
|
|
8
8
|
.ui-card {
|
|
9
|
-
background: var(--surface);
|
|
9
|
+
background: var(--surface); --ring-gap: var(--surface);
|
|
10
10
|
border: 1px solid var(--border);
|
|
11
11
|
border-radius: var(--radius-xl);
|
|
12
12
|
padding: var(--space-6) 26px;
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
/* An accent-tinted card, e.g. a highlighted plan / success surface. The accent edge is
|
|
29
29
|
the card's own hairline re-coloured: an inset ring over it would draw two. #295 */
|
|
30
30
|
.ui-card--accent {
|
|
31
|
-
background: color-mix(in srgb, var(--accent) 9%, var(--surface));
|
|
31
|
+
background: color-mix(in srgb, var(--accent) 9%, var(--surface)); --ring-gap: color-mix(in srgb, var(--accent) 9%, var(--surface));
|
|
32
32
|
border-color: color-mix(in srgb, var(--accent) 22%, transparent);
|
|
33
33
|
}
|
|
34
34
|
.ui-card--live {
|
|
35
|
-
background: color-mix(in srgb, var(--green) 10%, var(--surface));
|
|
35
|
+
background: color-mix(in srgb, var(--green) 10%, var(--surface)); --ring-gap: color-mix(in srgb, var(--green) 10%, var(--surface));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/* Interactive card (link / button semantics) */
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
border-radius: var(--radius-md);
|
|
90
90
|
display: grid;
|
|
91
91
|
place-items: center;
|
|
92
|
-
background: var(--glow-purple);
|
|
92
|
+
background: var(--glow-purple); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */
|
|
93
93
|
color: var(--accent);
|
|
94
94
|
flex: none;
|
|
95
95
|
}
|
package/src/styles/code.css
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* ========================================================================== */
|
|
5
5
|
|
|
6
6
|
.ui-snippet {
|
|
7
|
-
background: var(--surface-2);
|
|
7
|
+
background: var(--surface-2); --ring-gap: var(--surface-2);
|
|
8
8
|
border-radius: var(--radius-md);
|
|
9
9
|
overflow: hidden;
|
|
10
10
|
}
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
|
|
62
62
|
/* Reveal: a live secret/token, tinted green */
|
|
63
63
|
.ui-snippet--reveal {
|
|
64
|
-
background: color-mix(in srgb, var(--green) 10%, var(--surface));
|
|
64
|
+
background: color-mix(in srgb, var(--green) 10%, var(--surface)); --ring-gap: color-mix(in srgb, var(--green) 10%, var(--surface));
|
|
65
65
|
}
|
|
66
66
|
.ui-snippet--reveal .ui-snippet__bar span { color: var(--green); }
|
|
67
67
|
.ui-snippet--reveal pre { color: var(--green); word-break: break-all; white-space: pre-wrap; }
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
.ui-code {
|
|
71
71
|
font-family: var(--font-mono);
|
|
72
72
|
font-size: 0.9em;
|
|
73
|
-
background: var(--surface-2);
|
|
73
|
+
background: var(--surface-2); --ring-gap: var(--surface-2);
|
|
74
74
|
padding: 2px 6px;
|
|
75
75
|
border-radius: var(--radius-xs);
|
|
76
76
|
color: var(--text);
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
display: flex;
|
|
69
69
|
flex-direction: column;
|
|
70
70
|
font-family: var(--font-sans);
|
|
71
|
-
background: var(--cmdk-surface);
|
|
71
|
+
background: var(--cmdk-surface); --ring-gap: var(--cmdk-surface);
|
|
72
72
|
/* The two-step edge and the drop: --border-strong outside, --border one pixel
|
|
73
73
|
inside it, then the broad faint drop. why: docs/specification.md#elevation */
|
|
74
74
|
border: 1px solid var(--border-strong);
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
box-shadow list replaces the whole list, so `box-shadow: var(--ring)` alone
|
|
87
87
|
took the panel's edge and its drop off for as long as it held focus.
|
|
88
88
|
why: docs/specification.md#elevation */
|
|
89
|
-
.ui-cmdk__panel:focus-visible { outline:
|
|
89
|
+
.ui-cmdk__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop); }
|
|
90
90
|
|
|
91
91
|
/* -- The text box --------------------------------------------------------- */
|
|
92
92
|
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
background: none;
|
|
179
179
|
}
|
|
180
180
|
.ui-cmdk__item[hidden] { display: none; } /* motion: still — a row the query no longer answers is gone on the next keystroke */
|
|
181
|
-
.ui-cmdk__item.is-active { background: var(--surface-3); }
|
|
181
|
+
.ui-cmdk__item.is-active { background: var(--surface-3); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
|
|
182
182
|
.ui-cmdk__item.is-active .ui-cmdk__label { color: var(--strong); }
|
|
183
183
|
|
|
184
184
|
.ui-cmdk__ic {
|
|
@@ -258,7 +258,7 @@
|
|
|
258
258
|
border-radius: var(--radius-xs);
|
|
259
259
|
/* A key cap reads as raised, so it takes the step above the panel rather than
|
|
260
260
|
the card step below it. why: docs/specification.md#elevation */
|
|
261
|
-
background: var(--surface-3);
|
|
261
|
+
background: var(--surface-3); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */
|
|
262
262
|
font-family: var(--font-sans);
|
|
263
263
|
font-size: var(--text-xs);
|
|
264
264
|
line-height: 1.5;
|
|
@@ -301,10 +301,10 @@
|
|
|
301
301
|
align-items: center;
|
|
302
302
|
justify-content: center;
|
|
303
303
|
border-radius: var(--radius-sm);
|
|
304
|
-
background: var(--surface);
|
|
304
|
+
background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */
|
|
305
305
|
border: 1px solid var(--border);
|
|
306
306
|
}
|
|
307
|
-
.ui-cmdk--roomy .ui-cmdk__item.is-active .ui-cmdk__ic { background: var(--surface-2); }
|
|
307
|
+
.ui-cmdk--roomy .ui-cmdk__item.is-active .ui-cmdk__ic { background: var(--surface-2); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
308
308
|
|
|
309
309
|
/* -- Narrow --------------------------------------------------------------- */
|
|
310
310
|
/* At the kit's narrowest step the palette is the page: full width, off the top
|
package/src/styles/confirm.css
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
flex-direction: column;
|
|
62
62
|
gap: var(--space-2);
|
|
63
63
|
padding: var(--space-5);
|
|
64
|
-
background: var(--confirm-surface);
|
|
64
|
+
background: var(--confirm-surface); --ring-gap: var(--confirm-surface);
|
|
65
65
|
/* The two-step edge and the drop: --border-strong outside, --border one pixel
|
|
66
66
|
inside it, then the broad faint drop. why: docs/specification.md#elevation */
|
|
67
67
|
border: 1px solid var(--border-strong);
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
box-shadow list replaces the whole list, so `box-shadow: var(--ring)` alone
|
|
79
79
|
took the panel's edge and its drop off for as long as it held focus.
|
|
80
80
|
why: docs/specification.md#elevation */
|
|
81
|
-
.ui-confirm__panel:focus-visible { outline:
|
|
81
|
+
.ui-confirm__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop); }
|
|
82
82
|
|
|
83
83
|
/* -- Slots ----------------------------------------------------------------- */
|
|
84
84
|
/* The question and the answers keep their size; the consequence between them is
|
package/src/styles/drawer.css
CHANGED
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
position: absolute;
|
|
58
58
|
display: flex;
|
|
59
59
|
flex-direction: column;
|
|
60
|
-
background: var(--drawer-surface);
|
|
60
|
+
background: var(--drawer-surface); --ring-gap: var(--drawer-surface);
|
|
61
61
|
/* A drawer is flush to a screen edge, so it has one edge rather than four and the
|
|
62
62
|
two-step edge runs along that one: --border-strong on the edge rule below, the
|
|
63
63
|
inner line one pixel inside it. This is the one floating surface that writes no
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
box-shadow list replaces the whole list, so a bare `box-shadow: var(--ring)` would
|
|
116
116
|
take the drawer's edge and its drop off for as long as it held focus.
|
|
117
117
|
why: docs/specification.md#elevation */
|
|
118
|
-
.ui-drawer__panel:focus-visible { outline:
|
|
118
|
+
.ui-drawer__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), var(--drawer-line), var(--elev-drop); }
|
|
119
119
|
|
|
120
120
|
/* -- Sizes ----------------------------------------------------------------- */
|
|
121
121
|
/* left|right → width; top|bottom → height. Same names, axis chosen by side. */
|
|
@@ -169,8 +169,8 @@
|
|
|
169
169
|
background var(--dur-fast) var(--ease),
|
|
170
170
|
border-color var(--dur-fast) var(--ease);
|
|
171
171
|
}
|
|
172
|
-
.ui-drawer__close:hover { color: var(--strong); background: var(--surface-3); }
|
|
173
|
-
.ui-drawer__close:focus-visible { outline:
|
|
172
|
+
.ui-drawer__close:hover { color: var(--strong); background: var(--surface-3); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
|
|
173
|
+
.ui-drawer__close:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring); border-color: var(--accent); }
|
|
174
174
|
.ui-drawer__close svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2.1; }
|
|
175
175
|
|
|
176
176
|
.ui-drawer__body {
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
gap: 10px;
|
|
192
192
|
padding: 16px 20px;
|
|
193
193
|
border-top: 1px solid var(--border);
|
|
194
|
-
background: var(--surface-2);
|
|
194
|
+
background: var(--surface-2); --ring-gap: var(--surface-2);
|
|
195
195
|
flex: none;
|
|
196
196
|
}
|
|
197
197
|
|
package/src/styles/dropdown.css
CHANGED
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
font-size: calc(var(--text-sm) - 0.5px);
|
|
18
18
|
font-weight: 500;
|
|
19
19
|
color: var(--text);
|
|
20
|
-
background: var(--surface);
|
|
20
|
+
background: var(--surface); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
|
|
21
21
|
border: 1px solid var(--border);
|
|
22
22
|
border-radius: var(--radius-pill);
|
|
23
23
|
padding: 7px 11px 7px 13px;
|
|
24
24
|
transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
|
|
25
25
|
}
|
|
26
26
|
.ui-dropdown__trigger:hover { border-color: var(--accent); }
|
|
27
|
-
.ui-dropdown__trigger:focus-visible { outline:
|
|
27
|
+
.ui-dropdown__trigger:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring); border-color: var(--accent); }
|
|
28
28
|
.ui-dropdown__pre { color: var(--text); }
|
|
29
29
|
.ui-dropdown__value { color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
30
30
|
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
min-width: 240px;
|
|
71
71
|
/* The floating step, not the sunken one — a panel held open over a card cannot be
|
|
72
72
|
painted the colour of an inset. why: docs/specification.md#elevation */
|
|
73
|
-
background: var(--bg-elevated);
|
|
73
|
+
background: var(--bg-elevated); --ring-gap: var(--bg-elevated);
|
|
74
74
|
/* The two-step edge and the drop: --border-strong outside, --border one pixel
|
|
75
75
|
inside it, then the broad faint drop. why: docs/specification.md#elevation */
|
|
76
76
|
border: 1px solid var(--border-strong);
|
|
@@ -152,8 +152,8 @@
|
|
|
152
152
|
transition: background var(--dur-fast) var(--ease);
|
|
153
153
|
}
|
|
154
154
|
/* A row in a raised panel lifts: the step above it, never the card step below. why: docs/specification.md#elevation */
|
|
155
|
-
.ui-dropdown__item:hover { background: var(--surface-3); }
|
|
156
|
-
.ui-dropdown__item:focus-visible { outline:
|
|
155
|
+
.ui-dropdown__item:hover { background: var(--surface-3); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
|
|
156
|
+
.ui-dropdown__item:focus-visible { outline: 2px solid transparent; background: var(--surface-3); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ box-shadow: var(--ring); }
|
|
157
157
|
.ui-dropdown__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
158
158
|
.ui-dropdown__label { font-family: var(--font-sans); font-size: calc(var(--text-sm) - 0.5px); color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
159
159
|
.ui-dropdown__desc { font-size: var(--text-xs); color: var(--text); line-height: 1.35; }
|
|
@@ -180,14 +180,14 @@
|
|
|
180
180
|
flex: none;
|
|
181
181
|
color: var(--text);
|
|
182
182
|
/* A chip is the top step. why: docs/specification.md#elevation */
|
|
183
|
-
background: var(--surface-3);
|
|
183
|
+
background: var(--surface-3); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */
|
|
184
184
|
}
|
|
185
|
-
.ui-dropdown__badge.is-live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
185
|
+
.ui-dropdown__badge.is-live { color: var(--chip-success-ink); background: var(--chip-success-fill); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
186
186
|
/* The accent counter keeps the badge's flat surface and changes only the ink — the shape
|
|
187
187
|
src/styles/nav.css:163 `.ui-nav__item.is-active .ui-nav__badge.is-accent` already holds.
|
|
188
188
|
The accent wash goes on a base surface, never a raised one, and #295 made this panel a
|
|
189
189
|
raised one. why: docs/specification.md#elevation */
|
|
190
|
-
.ui-dropdown__badge.is-accent { color: var(--accent); background: var(--surface-3); }
|
|
190
|
+
.ui-dropdown__badge.is-accent { color: var(--accent); background: var(--surface-3); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ }
|
|
191
191
|
|
|
192
192
|
/* Disabled + danger rows */
|
|
193
193
|
.ui-dropdown__item.is-disabled { /* muted-ink: state — unavailable control */ color: var(--disabled-ink); cursor: not-allowed; pointer-events: none; }
|
|
@@ -258,7 +258,7 @@
|
|
|
258
258
|
font-size: calc(var(--text-sm) - 0.5px);
|
|
259
259
|
color: var(--strong);
|
|
260
260
|
/* A field is the sunken step, the same one .ui-input takes. why: docs/specification.md#elevation */
|
|
261
|
-
background: var(--surface-2);
|
|
261
|
+
background: var(--surface-2); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
|
|
262
262
|
border: 1px solid var(--border);
|
|
263
263
|
border-radius: var(--radius-sm);
|
|
264
264
|
padding: 8px 12px 8px 34px;
|
|
@@ -271,11 +271,11 @@
|
|
|
271
271
|
kit paints, so --surface-2 falls two rungs under it rather than one. The
|
|
272
272
|
numbers are in the spec and the gate is stories/dropdown-field-ground.test.js.
|
|
273
273
|
why: docs/specification.md#elevation */
|
|
274
|
-
:root[data-theme="light"] .ui-dropdown__search-input { background: var(--bg); }
|
|
274
|
+
:root[data-theme="light"] .ui-dropdown__search-input { background: var(--bg); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
|
|
275
275
|
|
|
276
276
|
.ui-dropdown__search-input::placeholder { /* muted-ink: placeholder — empty search field */ color: var(--muted); }
|
|
277
277
|
.ui-dropdown__search-input:hover { border-color: var(--border-strong); }
|
|
278
|
-
.ui-dropdown__search-input:focus-visible { outline:
|
|
278
|
+
.ui-dropdown__search-input:focus-visible { outline: 2px solid transparent; border-color: var(--accent); box-shadow: var(--ring); }
|
|
279
279
|
|
|
280
280
|
.ui-dropdown__list { max-height: 300px; overflow-y: auto; }
|
|
281
281
|
/* A row is `display: flex`, which outranks the UA's [hidden], so a row the
|
|
@@ -284,7 +284,7 @@
|
|
|
284
284
|
|
|
285
285
|
/* The row Enter would pick. Focus stays in the field, which carries the ring,
|
|
286
286
|
so this row takes the hover fill and a bar rather than a second ring. */
|
|
287
|
-
.ui-dropdown__item.is-active { background: var(--surface-3); box-shadow: inset 2px 0 0 var(--accent); }
|
|
287
|
+
.ui-dropdown__item.is-active { background: var(--surface-3); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ box-shadow: inset 2px 0 0 var(--accent); }
|
|
288
288
|
|
|
289
289
|
/* No match — a nudge and no action, per Guidelines / Microcopy. Empty while
|
|
290
290
|
anything matches, so it takes no room. */
|