@bsuite/theme 0.5.0 → 0.7.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/README.md +12 -0
- package/dist/react/BrandingProvider.js +1 -1
- package/dist/react/ThemeProvider.d.ts +1 -1
- package/dist/react/ThemeProvider.d.ts.map +1 -1
- package/dist/react/ThemeProvider.js +1 -1
- package/dist/react/components/StatusBadge.d.ts +5 -2
- package/dist/react/components/StatusBadge.d.ts.map +1 -1
- package/dist/react/components/StatusBadge.js +18 -8
- package/dist/react/index.d.ts +12 -12
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +7 -7
- package/dist/react/useBranding.d.ts +1 -1
- package/dist/react/useBranding.d.ts.map +1 -1
- package/dist/react/useBranding.js +1 -1
- package/dist/react/usePlatformLogo.d.ts +1 -1
- package/dist/react/usePlatformLogo.d.ts.map +1 -1
- package/dist/react/usePlatformLogo.js +1 -1
- package/dist/react/useTheme.d.ts +1 -1
- package/dist/react/useTheme.d.ts.map +1 -1
- package/dist/react/useTheme.js +1 -1
- package/dist/ssr/index.js +1 -1
- package/package.json +1 -3
- package/src/css/braden.css +4 -4
- package/src/css/index.css +1 -1
- package/src/css/utilities.css +44 -0
- package/src/css/vars.css +196 -99
- package/src/preset-v4.css +123 -113
- package/src/css/runtime-branding.css +0 -22
- package/src/css/tokens-brand-corporate-braden.css +0 -43
- package/src/css/tokens-dark.css +0 -101
- package/src/css/tokens-high-contrast.css +0 -34
- package/src/css/tokens-light.css +0 -89
- package/src/tailwind-preset.js +0 -150
package/src/css/vars.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* @bsuite/theme — CSS custom properties (:root + .dark)
|
|
3
|
-
* Version 0.
|
|
3
|
+
* Version 0.6.0
|
|
4
4
|
*
|
|
5
5
|
* Architecture — 5 layers (inner → outer):
|
|
6
6
|
* 1. Palette — frozen oklch primitives (--neon-electric-*, --braden-*)
|
|
@@ -12,13 +12,27 @@
|
|
|
12
12
|
* Consumers should bind to Layer 3 (roles) or Layer 4 (shadcn) — never
|
|
13
13
|
* directly to palette primitives. Roles make white-labelling safe.
|
|
14
14
|
*
|
|
15
|
-
* Colourblind policy (WCAG 1.4.1
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Colourblind policy (WCAG 1.4.1) — REWRITTEN 2026-08-02, contract 0.7.0:
|
|
16
|
+
* The invariant is SEPARATION, not a fixed hue. --role-error must be
|
|
17
|
+
* maximally separated from --role-primary under deuteranopia and
|
|
18
|
+
* protanopia. D2C's primary is blue, so error is RED.
|
|
19
|
+
* The previous "error = purple" rule was actively harmful: under
|
|
20
|
+
* protanopia purple measured DeltaE 0.006 against primary blue — the
|
|
21
|
+
* destructive colour and the primary action colour were the SAME swatch.
|
|
22
|
+
* Purple and indigo are therefore quarantined from semantics entirely.
|
|
23
|
+
* Warm states (red/amber) separate by LIGHTNESS, not hue — under
|
|
24
|
+
* deuteranopia everything warm collapses to yellow, so error is the dark
|
|
25
|
+
* one and warning the light one. Never put two cool hues in opposition.
|
|
26
|
+
* Colour is never the sole signifier: shape + label always.
|
|
27
|
+
* TENANT OVERRIDE BLOCKED on --role-error / --role-destructive.
|
|
18
28
|
*
|
|
19
|
-
* Eye-strain policy:
|
|
20
|
-
*
|
|
21
|
-
* text
|
|
29
|
+
* Eye-strain / pure-endpoint policy:
|
|
30
|
+
* Pure white (L=1.0) and pure black (L=0) are BANNED in EVERY role —
|
|
31
|
+
* text, surface, border, ring and shadow alike (operator ruling
|
|
32
|
+
* 2026-08-02). The prior text-only scoping of this rule is what let
|
|
33
|
+
* --light-bg-accent ship as oklch(1 0 0.5) and render every shadcn card
|
|
34
|
+
* and popover pure white. "White" here means oklch(0.982 0.002 248)
|
|
35
|
+
* (#f8f9fa); the lightest surface is bg-panel at L=0.994.
|
|
22
36
|
*
|
|
23
37
|
* OKLCH format is MANDATORY for all new tokens. No hex/rgb/hsl.
|
|
24
38
|
* Syntax: oklch(L C H) — L=lightness 0–1, C=chroma 0–0.4, H=hue 0–360.
|
|
@@ -41,6 +55,17 @@
|
|
|
41
55
|
--neon-electric-green: oklch(0.723 0.192 149.6);
|
|
42
56
|
--neon-electric-lavender: oklch(0.736 0.141 285.6);
|
|
43
57
|
|
|
58
|
+
/* Semantic hues — added 2026-08-02 (contract 0.7.0). The 11 above were
|
|
59
|
+
chosen for looks; these four were chosen for SEPARATION, measured via
|
|
60
|
+
Vienot-Brettel dichromat simulation. Worst-case DeltaE(OKLab) across
|
|
61
|
+
normal/deuteranopia/protanopia for every semantic pair is >= 0.156;
|
|
62
|
+
the pairing these replace scored 0.006. Never bind a component to
|
|
63
|
+
these directly — bind to the --role-* alias. */
|
|
64
|
+
--neon-electric-red: oklch(0.580 0.230 25); /* error / destructive */
|
|
65
|
+
--neon-electric-amber: oklch(0.800 0.150 75); /* warning */
|
|
66
|
+
--neon-electric-teal: oklch(0.600 0.130 195); /* success */
|
|
67
|
+
--neon-electric-deep: oklch(0.380 0.140 270); /* secondary action */
|
|
68
|
+
|
|
44
69
|
/* ============================================================
|
|
45
70
|
LAYER 2 — SURFACE PRIMITIVES (light mode)
|
|
46
71
|
============================================================ */
|
|
@@ -49,18 +74,23 @@
|
|
|
49
74
|
--light-bg-primary: oklch(0.961 0 0.5);
|
|
50
75
|
--light-bg-secondary: oklch(0.982 0.002 248);
|
|
51
76
|
--light-bg-tertiary: oklch(0.963 0.003 228.9);
|
|
52
|
-
|
|
77
|
+
/* bg-panel. Was oklch(1 0 0.5) — pure white, and since --card and
|
|
78
|
+
--popover bridge to it, every shadcn card and popover in all five D2C
|
|
79
|
+
apps rendered pure white in light mode from this one line. */
|
|
80
|
+
--light-bg-accent: oklch(0.994 0.002 260);
|
|
53
81
|
|
|
54
82
|
/* D2C light text scale — hue 260 (cool blue-grey), capped L=0.22.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
--light-text-
|
|
63
|
-
--light-text-
|
|
83
|
+
Measured WCAG contrast vs --light-bg-primary oklch(0.961 0 0.5), OKLCH ->
|
|
84
|
+
linear-sRGB -> WCAG relative-luminance pipeline, round-trip-verified
|
|
85
|
+
against 6 known hex references (packages/theme/docs/TOKEN-MAPPING.md §8).
|
|
86
|
+
Ratios re-measured 2026-07-17 (W3 §3.1) — supersede prior approximate
|
|
87
|
+
inline values; vs --light-bg-accent (bg-panel, pure white) is always
|
|
88
|
+
HIGHER, so bg-body is the conservative floor for every tier below. */
|
|
89
|
+
--light-text-primary: oklch(0.22 0.015 260); /* 15.46:1 ✓ AAA (large+normal) */
|
|
90
|
+
--light-text-secondary: oklch(0.38 0.018 260); /* 8.94:1 ✓ AAA (large+normal) */
|
|
91
|
+
--light-text-muted: oklch(0.52 0.018 260); /* 4.92:1 ✓ AA (normal, 4.5:1 floor) */
|
|
92
|
+
--light-text-subtle: oklch(0.60 0.012 260); /* 3.52:1 ✓ AA large only (3:1) — ✗ AA normal */
|
|
93
|
+
--light-text-disabled: oklch(0.72 0.010 260); /* 2.21:1 ✗ fails AA at any size — MUST pair with icon cue */
|
|
64
94
|
|
|
65
95
|
--light-border: oklch(0.942 0.005 247.9);
|
|
66
96
|
--light-hover: oklch(0.963 0.003 228.9);
|
|
@@ -78,49 +108,62 @@
|
|
|
78
108
|
|
|
79
109
|
/* Action colours */
|
|
80
110
|
--role-primary: var(--neon-electric-blue); /* oklch(0.546 0.215 262.9) */
|
|
81
|
-
--role-secondary: var(--neon-electric-
|
|
111
|
+
--role-secondary: var(--neon-electric-deep); /* was indigo — 0.037 from primary */
|
|
82
112
|
--role-accent: var(--neon-electric-cyan); /* oklch(0.769 0.132 191.7) */
|
|
83
113
|
|
|
84
|
-
/* ⚠️
|
|
85
|
-
|
|
86
|
-
|
|
114
|
+
/* ⚠️ SEPARATION POLICY (contract 0.7.0). The invariant is NOT a fixed hue —
|
|
115
|
+
it is that error must be maximally separated from PRIMARY under
|
|
116
|
+
deuteranopia and protanopia. D2C's primary is blue, so error is RED.
|
|
117
|
+
Purple scored DeltaE 0.006 against primary under protanopia: the
|
|
118
|
+
destructive colour and the primary action colour were the same swatch.
|
|
119
|
+
Purple and indigo are quarantined from semantics entirely.
|
|
120
|
+
Warm states separate by LIGHTNESS (under deuteranopia red and amber
|
|
121
|
+
both read yellow — error is the dark one, warning the light one).
|
|
87
122
|
TENANT OVERRIDE BLOCKED: BrandingProvider rejects --role-error changes. */
|
|
88
|
-
--role-error: var(--neon-electric-
|
|
89
|
-
--role-destructive: var(--neon-electric-
|
|
90
|
-
--role-warning: var(--neon-electric-
|
|
91
|
-
--role-success: var(--neon-electric-
|
|
123
|
+
--role-error: var(--neon-electric-red); /* was purple — 0.006 from primary */
|
|
124
|
+
--role-destructive: var(--neon-electric-red); /* synonym — same value */
|
|
125
|
+
--role-warning: var(--neon-electric-amber); /* was orange h22.5 — 0.059 from red */
|
|
126
|
+
--role-success: var(--neon-electric-teal); /* was green — 0.043 from red */
|
|
92
127
|
--role-info: var(--neon-electric-cyan); /* oklch(0.769 0.132 191.7) */
|
|
93
128
|
|
|
94
|
-
/*
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
--role-text
|
|
98
|
-
--role-text
|
|
99
|
-
--role-text
|
|
100
|
-
--role-text
|
|
129
|
+
/* AA-safe text renderings of the saturated roles on light surfaces.
|
|
130
|
+
A saturated fill colour is not a legible text colour; these are the
|
|
131
|
+
text variants and are the ONLY correct token for coloured type. */
|
|
132
|
+
--role-primary-text: oklch(0.541 0.215 262.9); /* 4.71:1 ✓ AA */
|
|
133
|
+
--role-accent-text: oklch(0.499 0.132 191.7); /* 4.70:1 ✓ AA */
|
|
134
|
+
--role-error-text: oklch(0.556 0.230 25); /* 4.69:1 ✓ AA */
|
|
135
|
+
--role-warning-text: oklch(0.535 0.150 75); /* 4.70:1 ✓ AA */
|
|
136
|
+
--role-success-text: oklch(0.501 0.130 195); /* 4.70:1 ✓ AA */
|
|
137
|
+
|
|
138
|
+
/* Text roles — six-tier scale (W3 §3.1 contract). Every tier below is
|
|
139
|
+
measured against --role-bg-body (the conservative floor); all tiers
|
|
140
|
+
score HIGHER against --role-bg-panel/--role-bg-surface. */
|
|
141
|
+
--role-text-heading: oklch(0.20 0.018 263); /* 16.17:1 ✓ AAA (slightly darker + bluer than body) */
|
|
142
|
+
--role-text-body: var(--light-text-primary); /* 15.46:1 ✓ AAA */
|
|
143
|
+
--role-text-secondary: var(--light-text-secondary); /* 8.94:1 ✓ AAA */
|
|
144
|
+
--role-text-muted: var(--light-text-muted); /* 4.92:1 ✓ AA normal */
|
|
145
|
+
--role-text-subtle: var(--light-text-subtle); /* 3.52:1 ✓ AA large only */
|
|
146
|
+
--role-text-disabled: var(--light-text-disabled); /* 2.21:1 ✗ icon cue required */
|
|
101
147
|
|
|
102
148
|
/* Surface roles */
|
|
103
|
-
--role-bg-body:
|
|
104
|
-
--role-bg-surface:
|
|
105
|
-
--role-bg-panel:
|
|
106
|
-
--role-bg-input:
|
|
107
|
-
--role-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
--text-on-primary: oklch(0.99 0 0); /* on blue L≈0.55 — 5.9:1 ✓ AA */
|
|
111
|
-
--text-on-accent: oklch(0.17 0.02 260); /* on cyan L≈0.77 — 6.1:1 ✓ AA */
|
|
112
|
-
--text-on-error: oklch(0.99 0 0); /* on purple L≈0.57 */
|
|
113
|
-
--text-on-success: oklch(0.17 0.02 260); /* on green L≈0.72 — dark text */
|
|
114
|
-
--text-on-warning: oklch(0.17 0.02 260); /* on amber L≈0.82 — dark text */
|
|
149
|
+
--role-bg-body: var(--light-bg-primary);
|
|
150
|
+
--role-bg-surface: var(--light-bg-secondary);
|
|
151
|
+
--role-bg-panel: var(--light-bg-accent);
|
|
152
|
+
--role-bg-input: var(--light-bg-tertiary);
|
|
153
|
+
--role-bg-sunken: oklch(0.938 0.004 250);
|
|
154
|
+
--role-border: var(--light-border);
|
|
155
|
+
--role-border-strong: oklch(0.880 0.008 250);
|
|
115
156
|
|
|
116
|
-
/*
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
--
|
|
121
|
-
--
|
|
122
|
-
--
|
|
123
|
-
--
|
|
157
|
+
/* Inverse text on coloured fills. Two values only — the fill is either
|
|
158
|
+
light enough to need dark text, or dark enough to need light text.
|
|
159
|
+
Neither is a pure endpoint. */
|
|
160
|
+
--text-on-light-fill: oklch(0.98 0.006 260);
|
|
161
|
+
--text-on-dark-fill: oklch(0.19 0.020 255);
|
|
162
|
+
--text-on-primary: var(--text-on-light-fill); /* on blue L≈0.55 — 4.88:1 ✓ AA */
|
|
163
|
+
--text-on-error: var(--text-on-light-fill); /* on red L≈0.58 — 4.55:1 ✓ AA */
|
|
164
|
+
--text-on-accent: var(--text-on-dark-fill); /* on cyan L≈0.77 — 9.38:1 ✓ AAA */
|
|
165
|
+
--text-on-warning: var(--text-on-dark-fill); /* on amber L≈0.80 — 9.68:1 ✓ AAA */
|
|
166
|
+
--text-on-success: var(--text-on-dark-fill); /* on teal L≈0.60 — 5.17:1 ✓ AA */
|
|
124
167
|
|
|
125
168
|
/* ============================================================
|
|
126
169
|
LAYER 4 — SHADCN/UI BRIDGE (light mode)
|
|
@@ -148,11 +191,15 @@
|
|
|
148
191
|
--ring: var(--role-primary);
|
|
149
192
|
|
|
150
193
|
/* ============================================================
|
|
151
|
-
|
|
152
|
-
|
|
194
|
+
CANONICAL ACCENT GRADIENT (W3 §3.1) — exactly ONE gradient
|
|
195
|
+
exists suite-wide. Marketing/pre-auth heroes ONLY — never on
|
|
196
|
+
functional text (labels, body copy, buttons). Consumed via the
|
|
197
|
+
`.bsuite-accent-gradient` utility (utilities.css). App-local
|
|
198
|
+
decorative gradients (e.g. crm7's `.crm7-gradient`) are
|
|
199
|
+
quarantined and must not be used for new work — see
|
|
200
|
+
docs/TOKEN-MAPPING.md §8.
|
|
153
201
|
============================================================ */
|
|
154
|
-
--
|
|
155
|
-
--color-primary-text: oklch(0.485 0.243 263.6); /* Saturated blue — AA on light bg */
|
|
202
|
+
--gradient-accent: linear-gradient(135deg, var(--role-primary), var(--role-accent));
|
|
156
203
|
|
|
157
204
|
/* ============================================================
|
|
158
205
|
GLOW + SHADOW MULTIPLIERS
|
|
@@ -169,29 +216,75 @@
|
|
|
169
216
|
--card-glow-source: var(--app-accent, var(--role-accent));
|
|
170
217
|
--glow-card: none;
|
|
171
218
|
--glow-card-hover: none;
|
|
219
|
+
}
|
|
172
220
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
221
|
+
/* ============================================================
|
|
222
|
+
LAYER 5 — PER-APP ACCENT
|
|
223
|
+
Added 2026-08-02: the 0.7.0 contract specifies these blocks but the
|
|
224
|
+
package had never shipped them — only a `var(--app-accent, …)` fallback
|
|
225
|
+
reference, so every app resolved to the shared cyan and the per-app
|
|
226
|
+
identity existed on paper only.
|
|
227
|
+
|
|
228
|
+
Set `data-app` on <body>. The FILL is the brand hue; the TEXT variants
|
|
229
|
+
are solved per mode, because a saturated fill colour is not a legible
|
|
230
|
+
text colour and the accent must never render below AA.
|
|
231
|
+
============================================================ */
|
|
232
|
+
[data-app="crm7"] {
|
|
233
|
+
--app-accent: oklch(0.769 0.132 191.7);
|
|
234
|
+
--app-accent-text-l: oklch(0.505 0.132 191.7);
|
|
235
|
+
--app-accent-text-d: oklch(0.769 0.132 191.7);
|
|
236
|
+
}
|
|
237
|
+
[data-app="bsu"] {
|
|
238
|
+
--app-accent: oklch(0.541 0.247 293);
|
|
239
|
+
--app-accent-text-l: oklch(0.564 0.247 293);
|
|
240
|
+
--app-accent-text-d: oklch(0.745 0.247 293);
|
|
194
241
|
}
|
|
242
|
+
[data-app="conduit"] {
|
|
243
|
+
--app-accent: oklch(0.723 0.192 149.6);
|
|
244
|
+
--app-accent-text-l: oklch(0.505 0.192 149.6);
|
|
245
|
+
--app-accent-text-d: oklch(0.723 0.192 149.6);
|
|
246
|
+
}
|
|
247
|
+
[data-app="r80"] {
|
|
248
|
+
--app-accent: oklch(0.666 0.157 58.3);
|
|
249
|
+
--app-accent-text-l: oklch(0.546 0.157 58.3);
|
|
250
|
+
--app-accent-text-d: oklch(0.703 0.157 58.3);
|
|
251
|
+
}
|
|
252
|
+
/* R8.04 — the rates engine replacing R80.3. Deliberately REUSES r80's
|
|
253
|
+
orange: it serves the same users doing the same job, and a rates engine
|
|
254
|
+
is not where people should be re-learning which app they are in.
|
|
255
|
+
Requested by the r804 lane 2026-08-02. */
|
|
256
|
+
[data-app="r804"] {
|
|
257
|
+
--app-accent: oklch(0.666 0.157 58.3);
|
|
258
|
+
--app-accent-text-l: oklch(0.546 0.157 58.3);
|
|
259
|
+
--app-accent-text-d: oklch(0.703 0.157 58.3);
|
|
260
|
+
}
|
|
261
|
+
[data-app="throughput"] {
|
|
262
|
+
--app-accent: oklch(0.656 0.212 354.3);
|
|
263
|
+
--app-accent-text-l: oklch(0.564 0.212 354.3);
|
|
264
|
+
--app-accent-text-d: oklch(0.731 0.212 354.3);
|
|
265
|
+
}
|
|
266
|
+
/* Light/dark rebinding of the text variant. */
|
|
267
|
+
:root { --app-accent-text: var(--app-accent-text-l); }
|
|
268
|
+
.dark { --app-accent-text: var(--app-accent-text-d); }
|
|
269
|
+
|
|
270
|
+
/* ============================================================
|
|
271
|
+
NO sRGB FALLBACK — DELIBERATELY REMOVED 2026-08-02.
|
|
272
|
+
Precedent: precedent__bsuite__20260802__theme_conformance_is_absolute.
|
|
273
|
+
|
|
274
|
+
The `@supports not (color: oklch(0 0 0))` block that stood here shipped
|
|
275
|
+
a parallel hex palette. It is gone, and must not be reinstated:
|
|
276
|
+
|
|
277
|
+
· OKLCH has been Baseline-available in every evergreen engine since
|
|
278
|
+
Firefox 113 (May 2023), after Safari 15.4 (2022) and Chrome 111
|
|
279
|
+
(Mar 2023). It guarded a population that no longer exists.
|
|
280
|
+
· It was a second source of truth for the same colours, so it drifted:
|
|
281
|
+
it still bound --role-error to purple after the semantic set moved
|
|
282
|
+
to red. A fallback that disagrees with the tokens is worse than none.
|
|
283
|
+
|
|
284
|
+
If a colour needs to exist in hex (email HTML, PDF, canvas, manifest),
|
|
285
|
+
derive it at that call site from the oklch token — do not re-introduce a
|
|
286
|
+
second palette here.
|
|
287
|
+
============================================================ */
|
|
195
288
|
|
|
196
289
|
/* ============================================================
|
|
197
290
|
DARK MODE — Layer 2 surface overrides + Layer 3 role rebind
|
|
@@ -207,37 +300,41 @@
|
|
|
207
300
|
/* D2C dark text scale — hue 260, capped L=0.94.
|
|
208
301
|
Pure white (L=1.0) is BANNED as a text token.
|
|
209
302
|
Eye-strain: 16:1 → ~14:1; perceived glare drops significantly.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
--dark-text-
|
|
216
|
-
/*
|
|
217
|
-
--dark-text-
|
|
218
|
-
--dark-text-
|
|
303
|
+
Measured WCAG contrast vs --dark-bg-primary oklch(0.166 0.026 269.4)
|
|
304
|
+
via the same OKLCH -> linear-sRGB -> WCAG pipeline as the light scale
|
|
305
|
+
above (re-measured 2026-07-17, W3 §3.1 — supersedes prior approximate
|
|
306
|
+
inline values). vs --role-bg-surface/--role-bg-panel is always HIGHER,
|
|
307
|
+
so bg-body is the conservative floor. */
|
|
308
|
+
--dark-text-primary: oklch(0.94 0.012 260); /* body — 16.16:1 ✓ AAA */
|
|
309
|
+
--dark-text-secondary: oklch(0.82 0.015 260); /* labels — 11.04:1 ✓ AAA */
|
|
310
|
+
--dark-text-muted: oklch(0.68 0.018 260); /* metadata — 6.69:1 ✓ AA (normal) */
|
|
311
|
+
--dark-text-subtle: oklch(0.56 0.015 260); /* placeholders — 4.14:1 ✓ AA large only — ✗ AA normal */
|
|
312
|
+
--dark-text-disabled: oklch(0.44 0.010 260); /* disabled — 2.48:1 ✗ fails AA at any size — MUST pair with icon cue */
|
|
219
313
|
|
|
220
314
|
--dark-border: oklch(0.428 0.015 248.2);
|
|
221
315
|
--dark-hover: oklch(0.39 0.035 265);
|
|
222
316
|
|
|
223
|
-
/* Rebind roles to dark-mode surface values */
|
|
224
|
-
--role-text-
|
|
225
|
-
--role-text-
|
|
226
|
-
--role-text-
|
|
227
|
-
--role-text-
|
|
228
|
-
--role-text-
|
|
229
|
-
--role-text-
|
|
317
|
+
/* Rebind roles to dark-mode surface values — six-tier scale (W3 §3.1). */
|
|
318
|
+
--role-text-heading: oklch(0.92 0.014 260); /* 15.21:1 ✓ AAA */
|
|
319
|
+
--role-text-body: var(--dark-text-primary); /* 16.16:1 ✓ AAA */
|
|
320
|
+
--role-text-secondary: var(--dark-text-secondary); /* 11.04:1 ✓ AAA */
|
|
321
|
+
--role-text-muted: var(--dark-text-muted); /* 6.69:1 ✓ AA normal */
|
|
322
|
+
--role-text-subtle: var(--dark-text-subtle); /* 4.14:1 ✓ AA large only */
|
|
323
|
+
--role-text-disabled: var(--dark-text-disabled); /* 2.48:1 ✗ icon cue required */
|
|
230
324
|
|
|
231
325
|
--role-bg-body: var(--dark-bg-primary);
|
|
232
326
|
--role-bg-surface: var(--dark-bg-secondary);
|
|
233
|
-
--role-bg-panel: oklch(0.
|
|
234
|
-
--role-bg-input: oklch(0.
|
|
327
|
+
--role-bg-panel: oklch(0.190 0.020 260);
|
|
328
|
+
--role-bg-input: oklch(0.240 0.020 260);
|
|
329
|
+
--role-bg-sunken: oklch(0.145 0.022 268);
|
|
235
330
|
--role-border: var(--dark-border);
|
|
236
331
|
|
|
237
|
-
/*
|
|
238
|
-
|
|
239
|
-
--
|
|
240
|
-
--
|
|
332
|
+
/* Role text variants rebind for the dark surface — all AAA on navy. */
|
|
333
|
+
--role-primary-text: oklch(0.721 0.215 262.9); /* 7.01:1 ✓ AAA */
|
|
334
|
+
--role-accent-text: var(--neon-electric-cyan); /* 9.78:1 ✓ AAA */
|
|
335
|
+
--role-error-text: oklch(0.786 0.230 25); /* 7.00:1 ✓ AAA */
|
|
336
|
+
--role-warning-text: var(--neon-electric-amber);/* 10.10:1 ✓ AAA */
|
|
337
|
+
--role-success-text: oklch(0.671 0.130 195); /* 6.99:1 ✓ AAA */
|
|
241
338
|
|
|
242
339
|
/* Glow/shadow scale up in dark mode */
|
|
243
340
|
--glow-strength: 0.6;
|