@bsuite/theme 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/package.json +1 -1
- package/src/css/index.css +1 -1
- package/src/css/utilities.css +41 -0
- package/src/css/vars.css +84 -44
- 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/README.md
CHANGED
|
@@ -126,6 +126,18 @@ Braden keeps separate corporate identity tokens in `@bsuite/theme/braden-css`: B
|
|
|
126
126
|
|
|
127
127
|
WCAG AA compliance: use semantic text tokens (`text-foreground`, `text-muted-foreground`, `text-text-on-primary`, `text-text-on-accent`) rather than raw `text-white`/`text-black`. Dark-surface text is capped at L=0.94 for extended-session comfort.
|
|
128
128
|
|
|
129
|
+
## Text-role contract (v0.6.0)
|
|
130
|
+
|
|
131
|
+
Six measured tiers — `--role-text-heading`, `--role-text-body`, `--role-text-secondary`, `--role-text-muted`, `--role-text-subtle`, `--role-text-disabled` — each with documented WCAG contrast in both modes. Full numbers + methodology: `docs/TOKEN-MAPPING.md` §8.1.
|
|
132
|
+
|
|
133
|
+
## Canonical gradient (v0.6.0)
|
|
134
|
+
|
|
135
|
+
Exactly one decorative accent gradient exists suite-wide — `--gradient-accent` / `.bsuite-accent-gradient` (`--role-primary` → `--role-accent`). Marketing heroes only, never functional text. `docs/TOKEN-MAPPING.md` §8.2.
|
|
136
|
+
|
|
137
|
+
## Grid/dot doctrine (v0.6.0)
|
|
138
|
+
|
|
139
|
+
`<HeroGrid>` (public/pre-auth hero bands) and `<DotPattern>` (authenticated shells, `@bsuite/ui`) are mutually exclusive per context and enforced by `@bsuite/dry-lint`'s `no-grid-dot-doctrine-violation` rule. `docs/TOKEN-MAPPING.md` §8.3.
|
|
140
|
+
|
|
129
141
|
## License
|
|
130
142
|
|
|
131
143
|
UNLICENSED — internal BSuite use only.
|
package/package.json
CHANGED
package/src/css/index.css
CHANGED
package/src/css/utilities.css
CHANGED
|
@@ -47,6 +47,47 @@
|
|
|
47
47
|
box-shadow 300ms ease;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/* ============================================================
|
|
51
|
+
CANONICAL ACCENT GRADIENT — W3 §3.1
|
|
52
|
+
Exactly ONE gradient exists suite-wide: --role-primary -> --role-accent
|
|
53
|
+
(Electric Blue -> Cyan by default; follows tenant BrandingProvider
|
|
54
|
+
overrides automatically via the var() chain). Marketing/pre-auth hero
|
|
55
|
+
surfaces ONLY — never functional text, labels, or body copy. Apply to
|
|
56
|
+
a decorative element (underline, badge, background swatch) or to text
|
|
57
|
+
via `background-clip: text` at the call site — this utility only
|
|
58
|
+
supplies the gradient itself.
|
|
59
|
+
============================================================ */
|
|
60
|
+
.bsuite-accent-gradient {
|
|
61
|
+
background-image: var(--gradient-accent);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ============================================================
|
|
65
|
+
HERO GRID — W3 §3.3 grid/dot doctrine
|
|
66
|
+
Public/pre-auth marketing hero bands ONLY. Localised to the hero
|
|
67
|
+
wrapper (which must be `position: relative`); never full-viewport,
|
|
68
|
+
never behind authenticated content. Mutually exclusive with the DOT
|
|
69
|
+
pattern (packages/ui DotPattern), which is authenticated-shell-only.
|
|
70
|
+
Consumed via the <HeroGrid> component in @bsuite/ui (packages/ui/src/
|
|
71
|
+
hero-grid.tsx) — do not hand-roll this pattern; the grid/dot lint rule
|
|
72
|
+
(@bsuite/dry-lint no-grid-dot-doctrine-violation) flags duplicates.
|
|
73
|
+
Lifted verbatim from braden's `.platform-hero-grid`
|
|
74
|
+
(braden/src/index.css) so the corporate and D2C marketing surfaces
|
|
75
|
+
share one visual language for this specific device.
|
|
76
|
+
============================================================ */
|
|
77
|
+
.bsuite-hero-grid {
|
|
78
|
+
position: absolute;
|
|
79
|
+
inset: 0;
|
|
80
|
+
background-image:
|
|
81
|
+
linear-gradient(oklch(0 0 0 / 0.03) 1px, transparent 1px),
|
|
82
|
+
linear-gradient(90deg, oklch(0 0 0 / 0.03) 1px, transparent 1px);
|
|
83
|
+
background-size: 32px 32px;
|
|
84
|
+
}
|
|
85
|
+
.dark .bsuite-hero-grid {
|
|
86
|
+
background-image:
|
|
87
|
+
linear-gradient(oklch(1 0 0 / 0.03) 1px, transparent 1px),
|
|
88
|
+
linear-gradient(90deg, oklch(1 0 0 / 0.03) 1px, transparent 1px);
|
|
89
|
+
}
|
|
90
|
+
|
|
50
91
|
/* ===== prefers-reduced-motion — cap animation duration ===== */
|
|
51
92
|
@media (prefers-reduced-motion: reduce) {
|
|
52
93
|
*,
|
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-*)
|
|
@@ -52,12 +52,17 @@
|
|
|
52
52
|
--light-bg-accent: oklch(1 0 0.5);
|
|
53
53
|
|
|
54
54
|
/* D2C light text scale — hue 260 (cool blue-grey), capped L=0.22.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
Measured WCAG contrast vs --light-bg-primary oklch(0.961 0 0.5), OKLCH ->
|
|
56
|
+
linear-sRGB -> WCAG relative-luminance pipeline, round-trip-verified
|
|
57
|
+
against 6 known hex references (packages/theme/docs/TOKEN-MAPPING.md §8).
|
|
58
|
+
Ratios re-measured 2026-07-17 (W3 §3.1) — supersede prior approximate
|
|
59
|
+
inline values; vs --light-bg-accent (bg-panel, pure white) is always
|
|
60
|
+
HIGHER, so bg-body is the conservative floor for every tier below. */
|
|
61
|
+
--light-text-primary: oklch(0.22 0.015 260); /* 15.46:1 ✓ AAA (large+normal) */
|
|
62
|
+
--light-text-secondary: oklch(0.38 0.018 260); /* 8.94:1 ✓ AAA (large+normal) */
|
|
63
|
+
--light-text-muted: oklch(0.52 0.018 260); /* 4.92:1 ✓ AA (normal, 4.5:1 floor) */
|
|
64
|
+
--light-text-subtle: oklch(0.60 0.012 260); /* 3.52:1 ✓ AA large only (3:1) — ✗ AA normal */
|
|
65
|
+
--light-text-disabled: oklch(0.72 0.010 260); /* 2.21:1 ✗ fails AA at any size — MUST pair with icon cue */
|
|
61
66
|
/* Legacy aliases (kept for consumers that haven't migrated) */
|
|
62
67
|
--light-text-tertiary: var(--light-text-muted);
|
|
63
68
|
--light-text-quaternary: var(--light-text-subtle);
|
|
@@ -91,13 +96,15 @@
|
|
|
91
96
|
--role-success: var(--neon-electric-green); /* oklch(0.723 0.192 149.6) */
|
|
92
97
|
--role-info: var(--neon-electric-cyan); /* oklch(0.769 0.132 191.7) */
|
|
93
98
|
|
|
94
|
-
/* Text roles
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
--role-text-
|
|
98
|
-
--role-text-
|
|
99
|
-
--role-text-
|
|
100
|
-
--role-text-
|
|
99
|
+
/* Text roles — six-tier scale (W3 §3.1 contract). Every tier below is
|
|
100
|
+
measured against --role-bg-body (the conservative floor); all tiers
|
|
101
|
+
score HIGHER against --role-bg-panel/--role-bg-surface. */
|
|
102
|
+
--role-text-heading: oklch(0.20 0.018 263); /* 16.17:1 ✓ AAA (slightly darker + bluer than body) */
|
|
103
|
+
--role-text-body: var(--light-text-primary); /* 15.46:1 ✓ AAA */
|
|
104
|
+
--role-text-secondary: var(--light-text-secondary); /* 8.94:1 ✓ AAA */
|
|
105
|
+
--role-text-muted: var(--light-text-muted); /* 4.92:1 ✓ AA normal */
|
|
106
|
+
--role-text-subtle: var(--light-text-subtle); /* 3.52:1 ✓ AA large only */
|
|
107
|
+
--role-text-disabled: var(--light-text-disabled); /* 2.21:1 ✗ icon cue required */
|
|
101
108
|
|
|
102
109
|
/* Surface roles */
|
|
103
110
|
--role-bg-body: var(--light-bg-primary);
|
|
@@ -154,6 +161,17 @@
|
|
|
154
161
|
--color-accent-text: oklch(0.486 0.084 191.5); /* Dark cyan — AA on light bg */
|
|
155
162
|
--color-primary-text: oklch(0.485 0.243 263.6); /* Saturated blue — AA on light bg */
|
|
156
163
|
|
|
164
|
+
/* ============================================================
|
|
165
|
+
CANONICAL ACCENT GRADIENT (W3 §3.1) — exactly ONE gradient
|
|
166
|
+
exists suite-wide. Marketing/pre-auth heroes ONLY — never on
|
|
167
|
+
functional text (labels, body copy, buttons). Consumed via the
|
|
168
|
+
`.bsuite-accent-gradient` utility (utilities.css). App-local
|
|
169
|
+
decorative gradients (e.g. crm7's `.crm7-gradient`) are
|
|
170
|
+
quarantined and must not be used for new work — see
|
|
171
|
+
docs/TOKEN-MAPPING.md §8.
|
|
172
|
+
============================================================ */
|
|
173
|
+
--gradient-accent: linear-gradient(135deg, var(--role-primary), var(--role-accent));
|
|
174
|
+
|
|
157
175
|
/* ============================================================
|
|
158
176
|
GLOW + SHADOW MULTIPLIERS
|
|
159
177
|
============================================================ */
|
|
@@ -169,26 +187,44 @@
|
|
|
169
187
|
--card-glow-source: var(--app-accent, var(--role-accent));
|
|
170
188
|
--glow-card: none;
|
|
171
189
|
--glow-card-hover: none;
|
|
190
|
+
}
|
|
172
191
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
/* ============================================================
|
|
193
|
+
SRGB FALLBACKS (for browsers without oklch support) — W3 §3.4
|
|
194
|
+
True-source hexes, each re-derived directly from its oklch token
|
|
195
|
+
(OKLCH -> OKLab -> linear-sRGB -> gamma-encoded sRGB) rather than
|
|
196
|
+
eyeballed against a Tailwind palette. Round-trip-verified: every
|
|
197
|
+
value below computes ΔE(OKLab) < 0.01 against its oklch token —
|
|
198
|
+
at least twice inside the < 0.02 acceptance bar (most values are
|
|
199
|
+
one to two orders of magnitude inside it; see docs/TOKEN-MAPPING.md
|
|
200
|
+
§8 for the full per-token ΔE table). The prior Tailwind-palette-
|
|
201
|
+
derived hexes were ΔE 0.03-0.10 off.
|
|
202
|
+
|
|
203
|
+
Deliberately declared at the TOP LEVEL, not nested inside another
|
|
204
|
+
`:root { }` block: engines that lack `oklch()` support predate CSS
|
|
205
|
+
nesting too, so a `@supports` block nested inside `:root` would be
|
|
206
|
+
silently dropped by exactly the browsers it's meant to serve when
|
|
207
|
+
this file is consumed raw (unbundled). It works when bundled
|
|
208
|
+
through the Tailwind v4 / LightningCSS pipeline only because that
|
|
209
|
+
pipeline hoists nested at-rules — this top-level form is correct
|
|
210
|
+
for both the raw and the bundled case.
|
|
211
|
+
============================================================ */
|
|
212
|
+
@supports not (color: oklch(0 0 0)) {
|
|
213
|
+
:root {
|
|
214
|
+
--neon-electric-blue: #2563eb;
|
|
215
|
+
--neon-electric-cyan: #00cec9;
|
|
216
|
+
--neon-electric-indigo: #4f46e5;
|
|
217
|
+
--neon-electric-purple: #6c5ce7;
|
|
218
|
+
--neon-electric-magenta: #fd79a8;
|
|
183
219
|
--neon-electric-pink: #ec4899;
|
|
184
|
-
--neon-electric-coral: #
|
|
185
|
-
--neon-electric-orange: #
|
|
186
|
-
--neon-electric-yellow: #
|
|
220
|
+
--neon-electric-coral: #ff4757;
|
|
221
|
+
--neon-electric-orange: #ff7675;
|
|
222
|
+
--neon-electric-yellow: #fdcb6e;
|
|
187
223
|
--neon-electric-green: #22c55e;
|
|
188
|
-
--neon-electric-lavender: #
|
|
189
|
-
--role-error: #
|
|
190
|
-
--role-destructive: #
|
|
191
|
-
--light-text-primary: #
|
|
224
|
+
--neon-electric-lavender: #a29bfe;
|
|
225
|
+
--role-error: #6c5ce7;
|
|
226
|
+
--role-destructive: #6c5ce7;
|
|
227
|
+
--light-text-primary: #171b22;
|
|
192
228
|
--dark-text-primary: #e8eaf6;
|
|
193
229
|
}
|
|
194
230
|
}
|
|
@@ -207,12 +243,16 @@
|
|
|
207
243
|
/* D2C dark text scale — hue 260, capped L=0.94.
|
|
208
244
|
Pure white (L=1.0) is BANNED as a text token.
|
|
209
245
|
Eye-strain: 16:1 → ~14:1; perceived glare drops significantly.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
--dark-text-
|
|
246
|
+
Measured WCAG contrast vs --dark-bg-primary oklch(0.166 0.026 269.4)
|
|
247
|
+
via the same OKLCH -> linear-sRGB -> WCAG pipeline as the light scale
|
|
248
|
+
above (re-measured 2026-07-17, W3 §3.1 — supersedes prior approximate
|
|
249
|
+
inline values). vs --role-bg-surface/--role-bg-panel is always HIGHER,
|
|
250
|
+
so bg-body is the conservative floor. */
|
|
251
|
+
--dark-text-primary: oklch(0.94 0.012 260); /* body — 16.16:1 ✓ AAA */
|
|
252
|
+
--dark-text-secondary: oklch(0.82 0.015 260); /* labels — 11.04:1 ✓ AAA */
|
|
253
|
+
--dark-text-muted: oklch(0.68 0.018 260); /* metadata — 6.69:1 ✓ AA (normal) */
|
|
254
|
+
--dark-text-subtle: oklch(0.56 0.015 260); /* placeholders — 4.14:1 ✓ AA large only — ✗ AA normal */
|
|
255
|
+
--dark-text-disabled: oklch(0.44 0.010 260); /* disabled — 2.48:1 ✗ fails AA at any size — MUST pair with icon cue */
|
|
216
256
|
/* Legacy aliases */
|
|
217
257
|
--dark-text-tertiary: var(--dark-text-muted);
|
|
218
258
|
--dark-text-quaternary: var(--dark-text-disabled);
|
|
@@ -220,13 +260,13 @@
|
|
|
220
260
|
--dark-border: oklch(0.428 0.015 248.2);
|
|
221
261
|
--dark-hover: oklch(0.39 0.035 265);
|
|
222
262
|
|
|
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-
|
|
263
|
+
/* Rebind roles to dark-mode surface values — six-tier scale (W3 §3.1). */
|
|
264
|
+
--role-text-heading: oklch(0.92 0.014 260); /* 15.21:1 ✓ AAA */
|
|
265
|
+
--role-text-body: var(--dark-text-primary); /* 16.16:1 ✓ AAA */
|
|
266
|
+
--role-text-secondary: var(--dark-text-secondary); /* 11.04:1 ✓ AAA */
|
|
267
|
+
--role-text-muted: var(--dark-text-muted); /* 6.69:1 ✓ AA normal */
|
|
268
|
+
--role-text-subtle: var(--dark-text-subtle); /* 4.14:1 ✓ AA large only */
|
|
269
|
+
--role-text-disabled: var(--dark-text-disabled); /* 2.48:1 ✗ icon cue required */
|
|
230
270
|
|
|
231
271
|
--role-bg-body: var(--dark-bg-primary);
|
|
232
272
|
--role-bg-surface: var(--dark-bg-secondary);
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* runtime-branding.css — populated at runtime by <BrandingProvider>
|
|
3
|
-
*
|
|
4
|
-
* DO NOT add static values here. BrandingProvider reads the tenant's
|
|
5
|
-
* branding JSON from Supabase and calls
|
|
6
|
-
* document.documentElement.style.setProperty('--primary', value)
|
|
7
|
-
* for each key. This file is a documentation placeholder only.
|
|
8
|
-
*
|
|
9
|
-
* Keys populated at runtime (if tenant has branding configured):
|
|
10
|
-
* --primary (oklch string)
|
|
11
|
-
* --accent (oklch string)
|
|
12
|
-
* --accent-primary (oklch string)
|
|
13
|
-
* --app-primary (oklch string)
|
|
14
|
-
* --app-accent (oklch string)
|
|
15
|
-
* Logo URLs are injected via JS into CSS vars:
|
|
16
|
-
* --logo-url (url() string)
|
|
17
|
-
* --mark-url (url() string)
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
:root[data-branding-loaded="true"] {
|
|
21
|
-
/* intentionally empty — BrandingProvider injects vars directly via JS */
|
|
22
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @bsuite/theme — tokens-brand-corporate-braden.css
|
|
3
|
-
*
|
|
4
|
-
* Braden corporate brand deviation.
|
|
5
|
-
* Applied via .theme-braden or data-brand="braden" — NEVER auto-applied.
|
|
6
|
-
*
|
|
7
|
-
* ⚠️ This file is EXEMPT from the D2C oklch-only rule (BRADEN-EXEMPT).
|
|
8
|
-
* Do NOT import this file from index.css or any D2C app entry point.
|
|
9
|
-
* Braden's own stylesheet opts in explicitly.
|
|
10
|
-
*
|
|
11
|
-
* Source of truth: TOKEN-MAPPING.md §4 + §6
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
.theme-braden,
|
|
15
|
-
[data-brand="braden"] {
|
|
16
|
-
|
|
17
|
-
/* ===== Braden brand primitives ===== */
|
|
18
|
-
--app-primary: oklch(0.488 0.170 17.6); /* Braden Red */
|
|
19
|
-
--app-accent: oklch(0.769 0.096 90.9); /* Braden Gold */
|
|
20
|
-
--app-primary-dark: oklch(0.400 0.137 16.8); /* Braden Red — pressed/hover state */
|
|
21
|
-
|
|
22
|
-
/* ===== Background ===== */
|
|
23
|
-
--bg-body: oklch(1 0 0);
|
|
24
|
-
--bg-panel: oklch(1 0 0);
|
|
25
|
-
--bg-surface: oklch(0.975 0 0);
|
|
26
|
-
|
|
27
|
-
/* ===== Text ===== */
|
|
28
|
-
--text-primary: oklch(0.156 0 0);
|
|
29
|
-
|
|
30
|
-
/* ===== Border ===== */
|
|
31
|
-
--border-color: oklch(0.916 0 0);
|
|
32
|
-
|
|
33
|
-
/* ===== Accent / brand ===== */
|
|
34
|
-
--accent-primary: oklch(0.488 0.170 17.6); /* Braden Red */
|
|
35
|
-
--accent-secondary: oklch(0.769 0.096 90.9); /* Braden Gold */
|
|
36
|
-
|
|
37
|
-
/* ===== shadcn/ui bridge tokens ===== */
|
|
38
|
-
--primary: oklch(0.488 0.170 17.6); /* Braden Red */
|
|
39
|
-
--primary-foreground: oklch(1 0 0);
|
|
40
|
-
--accent: oklch(0.769 0.096 90.9); /* Braden Gold */
|
|
41
|
-
--accent-foreground: oklch(0.156 0 0);
|
|
42
|
-
--ring: oklch(0.488 0.170 17.6); /* Braden Red ring */
|
|
43
|
-
}
|
package/src/css/tokens-dark.css
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @bsuite/theme — tokens-dark.css
|
|
3
|
-
*
|
|
4
|
-
* Full semantic token set for the dark theme.
|
|
5
|
-
* Applied to .dark.
|
|
6
|
-
*
|
|
7
|
-
* All values are in OKLCH — no hex, no hsl() wrappers.
|
|
8
|
-
* Source of truth: TOKEN-MAPPING.md v0.2.0 + vars.css
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
.dark {
|
|
12
|
-
|
|
13
|
-
/* ===== Text ===== */
|
|
14
|
-
--text-primary: oklch(0.94 0.012 260);
|
|
15
|
-
--text-secondary: oklch(0.82 0.015 260);
|
|
16
|
-
--text-muted: oklch(0.68 0.018 260);
|
|
17
|
-
--text-subtle: oklch(0.56 0.015 260);
|
|
18
|
-
--text-disabled: oklch(0.44 0.010 260);
|
|
19
|
-
--text-on-primary: oklch(0.99 0 0);
|
|
20
|
-
--text-on-surface: oklch(0.94 0.012 260);
|
|
21
|
-
--color-primary-text: oklch(0.623 0.188 259.8); /* WCAG AA blue text on dark bg */
|
|
22
|
-
--color-accent-text: oklch(0.769 0.132 191.7); /* WCAG AA cyan text on dark bg */
|
|
23
|
-
|
|
24
|
-
/* ===== Background ===== */
|
|
25
|
-
--bg-body: oklch(0.166 0.026 269.4); /* deep navy */
|
|
26
|
-
--bg-surface: oklch(0.19 0.02 260);
|
|
27
|
-
--bg-panel: oklch(0.242 0.03 269.9);
|
|
28
|
-
--bg-tertiary: oklch(0.326 0.036 266.7);
|
|
29
|
-
--bg-elevated: oklch(0.292 0.034 270);
|
|
30
|
-
--bg-input: oklch(0.242 0.03 269.9 / 0.6);
|
|
31
|
-
--bg-hover: oklch(0.39 0.035 265);
|
|
32
|
-
--bg-selected: oklch(0.546 0.215 262.9 / 0.15);
|
|
33
|
-
|
|
34
|
-
/* ===== Border ===== */
|
|
35
|
-
--border-color: oklch(0.769 0.132 191.7 / 0.15);
|
|
36
|
-
--border-color-strong: oklch(0.769 0.132 191.7 / 0.3);
|
|
37
|
-
--border-shell: oklch(0.769 0.132 191.7 / 0.18);
|
|
38
|
-
|
|
39
|
-
/* ===== Accent / brand ===== */
|
|
40
|
-
--accent-primary: oklch(0.546 0.215 262.9); /* Electric Blue */
|
|
41
|
-
--accent-secondary: oklch(0.769 0.132 191.7); /* Electric Cyan */
|
|
42
|
-
|
|
43
|
-
/* ===== Status (same values in both themes) ===== */
|
|
44
|
-
--color-success: oklch(0.697 0.135 172.1);
|
|
45
|
-
--color-warning: oklch(0.868 0.125 81.4);
|
|
46
|
-
--color-error: oklch(0.568 0.202 283.1);
|
|
47
|
-
--color-info: oklch(0.769 0.132 191.7);
|
|
48
|
-
|
|
49
|
-
/* ===== shadcn/ui bridge tokens ===== */
|
|
50
|
-
--background: oklch(0.166 0.026 269.4);
|
|
51
|
-
--foreground: var(--text-primary);
|
|
52
|
-
--card: oklch(0.242 0.03 269.9);
|
|
53
|
-
--card-foreground: var(--text-primary);
|
|
54
|
-
--popover: oklch(0.292 0.034 270);
|
|
55
|
-
--popover-foreground: var(--text-primary);
|
|
56
|
-
--primary: oklch(0.769 0.132 191.7); /* Cyan as primary in dark */
|
|
57
|
-
--primary-foreground: oklch(0.166 0.026 269.4);
|
|
58
|
-
--secondary: oklch(0.242 0.03 269.9);
|
|
59
|
-
--secondary-foreground: var(--text-primary);
|
|
60
|
-
--muted: oklch(0.242 0.03 269.9);
|
|
61
|
-
--muted-foreground: var(--text-muted);
|
|
62
|
-
--accent: oklch(0.546 0.215 262.9); /* Blue as accent in dark */
|
|
63
|
-
--accent-foreground: var(--text-primary);
|
|
64
|
-
--destructive: var(--color-error);
|
|
65
|
-
--destructive-foreground: oklch(0.99 0 0);
|
|
66
|
-
--border: oklch(0.769 0.132 191.7 / 0.15);
|
|
67
|
-
--input: oklch(0.769 0.132 191.7 / 0.15);
|
|
68
|
-
--ring: oklch(0.769 0.132 191.7); /* Cyan ring in dark */
|
|
69
|
-
|
|
70
|
-
/* ===== Box shadows — deep blacks + neon cyan glow ===== */
|
|
71
|
-
--shadow-elev-0: none;
|
|
72
|
-
--shadow-elev-1: 0 1px 3px oklch(0 0 0 / 0.3);
|
|
73
|
-
--shadow-elev-2: 0 4px 8px oklch(0 0 0 / 0.4), 0 1px 3px oklch(0 0 0 / 0.3);
|
|
74
|
-
--shadow-elev-3: 0 8px 16px oklch(0 0 0 / 0.5), 0 4px 8px oklch(0 0 0 / 0.3);
|
|
75
|
-
--shadow-elev-4: 0 16px 32px oklch(0 0 0 / 0.6), 0 8px 16px oklch(0 0 0 / 0.4);
|
|
76
|
-
|
|
77
|
-
/* ===== Neon glow helpers ===== */
|
|
78
|
-
--glow-button: 0 0 20px oklch(0.769 0.132 191.7 / 0.3);
|
|
79
|
-
--glow-button-hover: 0 0 30px oklch(0.769 0.132 191.7 / 0.5);
|
|
80
|
-
|
|
81
|
-
/*
|
|
82
|
-
* Card glow — subtle neon separation for card surfaces, dark mode only.
|
|
83
|
-
* Derived from the app's accent colour (--app-accent, falling back to
|
|
84
|
-
* the shared --role-accent default, matching the live vars.css) so
|
|
85
|
-
* per-tenant
|
|
86
|
-
* BrandingProvider overrides and per-app brand accents (Conduit green,
|
|
87
|
-
* R80.3 amber, etc.) automatically re-colour the glow. Two layers:
|
|
88
|
-
* a 1px accent ring (edge definition, replaces a hard border) plus a
|
|
89
|
-
* soft negative-spread halo (ambient separation). Kept subtle by
|
|
90
|
-
* design — this is surface separation, not a decorative outline.
|
|
91
|
-
*/
|
|
92
|
-
--card-glow-source: var(--app-accent, var(--role-accent));
|
|
93
|
-
--glow-card: 0 0 0 1px color-mix(in oklch, var(--card-glow-source) 30%, transparent),
|
|
94
|
-
0 0 14px -4px color-mix(in oklch, var(--card-glow-source) 35%, transparent);
|
|
95
|
-
--glow-card-hover: 0 0 0 1px color-mix(in oklch, var(--card-glow-source) 42%, transparent),
|
|
96
|
-
0 0 20px -4px color-mix(in oklch, var(--card-glow-source) 48%, transparent);
|
|
97
|
-
|
|
98
|
-
/* ===== Button shadow ===== */
|
|
99
|
-
--button-shadow: 0 0 20px oklch(0.769 0.132 191.7 / 0.3);
|
|
100
|
-
--button-hover-shadow: 0 0 30px oklch(0.769 0.132 191.7 / 0.5);
|
|
101
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @bsuite/theme — tokens-high-contrast.css
|
|
3
|
-
*
|
|
4
|
-
* AAA accessibility overrides for users who have opted into
|
|
5
|
-
* "More Contrast" in their OS/browser settings.
|
|
6
|
-
*
|
|
7
|
-
* Kept intentionally minimal — only tokens that fail AAA at default
|
|
8
|
-
* values are overridden. All other tokens inherit from tokens-light.css
|
|
9
|
-
* or tokens-dark.css.
|
|
10
|
-
*
|
|
11
|
-
* Source of truth: TOKEN-MAPPING.md v0.2.0
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
@media (prefers-contrast: more) {
|
|
15
|
-
|
|
16
|
-
/* ----- Light mode overrides (default / :root) ----- */
|
|
17
|
-
:root,
|
|
18
|
-
.light {
|
|
19
|
-
--text-primary: oklch(0 0 0); /* pure black */
|
|
20
|
-
--text-secondary: oklch(0.1 0 0);
|
|
21
|
-
--text-muted: oklch(0.2 0 0);
|
|
22
|
-
--border-color: oklch(0 0 0);
|
|
23
|
-
--border-color-strong: oklch(0 0 0);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* ----- Dark mode overrides ----- */
|
|
27
|
-
.dark {
|
|
28
|
-
--text-primary: oklch(1 0 0); /* pure white */
|
|
29
|
-
--text-secondary: oklch(0.9 0 0);
|
|
30
|
-
--text-muted: oklch(0.8 0 0);
|
|
31
|
-
--border-color: oklch(1 0 0);
|
|
32
|
-
--border-color-strong: oklch(1 0 0);
|
|
33
|
-
}
|
|
34
|
-
}
|
package/src/css/tokens-light.css
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @bsuite/theme — tokens-light.css
|
|
3
|
-
*
|
|
4
|
-
* Full semantic token set for the light theme.
|
|
5
|
-
* Applied to :root and .light.
|
|
6
|
-
*
|
|
7
|
-
* All values are in OKLCH — no hex, no hsl() wrappers.
|
|
8
|
-
* Source of truth: TOKEN-MAPPING.md v0.2.0
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
:root,
|
|
12
|
-
.light {
|
|
13
|
-
|
|
14
|
-
/* ===== Text ===== */
|
|
15
|
-
--text-primary: oklch(0.22 0.015 260);
|
|
16
|
-
--text-secondary: oklch(0.38 0.018 260);
|
|
17
|
-
--text-muted: oklch(0.52 0.018 260);
|
|
18
|
-
--text-subtle: oklch(0.60 0.012 260);
|
|
19
|
-
--text-disabled: oklch(0.72 0.010 260);
|
|
20
|
-
--text-on-primary: oklch(0.99 0 0);
|
|
21
|
-
--text-on-surface: oklch(0.22 0.015 260);
|
|
22
|
-
--color-primary-text: oklch(0.485 0.243 263.6); /* WCAG AA blue text on light bg */
|
|
23
|
-
--color-accent-text: oklch(0.486 0.084 191.5); /* WCAG AA cyan text on light bg */
|
|
24
|
-
|
|
25
|
-
/* ===== Background ===== */
|
|
26
|
-
--bg-body: oklch(0.961 0 0.5);
|
|
27
|
-
--bg-surface: oklch(0.982 0.002 248);
|
|
28
|
-
--bg-panel: oklch(1 0 0);
|
|
29
|
-
--bg-tertiary: oklch(0.963 0.003 228.9);
|
|
30
|
-
--bg-elevated: oklch(1 0 0);
|
|
31
|
-
--bg-input: oklch(0.982 0.002 248);
|
|
32
|
-
--bg-hover: oklch(0.963 0.003 228.9);
|
|
33
|
-
--bg-selected: oklch(0.546 0.215 262.9 / 0.08);
|
|
34
|
-
|
|
35
|
-
/* ===== Border ===== */
|
|
36
|
-
--border-color: oklch(0.916 0.006 248);
|
|
37
|
-
--border-color-strong: oklch(0.741 0.022 250 / 0.5);
|
|
38
|
-
--border-shell: oklch(0.741 0.022 250 / 0.2);
|
|
39
|
-
|
|
40
|
-
/* ===== Accent / brand ===== */
|
|
41
|
-
--accent-primary: oklch(0.546 0.215 262.9); /* Electric Blue */
|
|
42
|
-
--accent-secondary: oklch(0.769 0.132 191.7); /* Electric Cyan */
|
|
43
|
-
|
|
44
|
-
/* ===== Status ===== */
|
|
45
|
-
--color-success: oklch(0.697 0.135 172.1);
|
|
46
|
-
--color-warning: oklch(0.868 0.125 81.4);
|
|
47
|
-
--color-error: oklch(0.568 0.202 283.1);
|
|
48
|
-
--color-info: oklch(0.769 0.132 191.7);
|
|
49
|
-
|
|
50
|
-
/* ===== shadcn/ui bridge tokens ===== */
|
|
51
|
-
--background: oklch(0.961 0 0.5);
|
|
52
|
-
--foreground: var(--text-primary);
|
|
53
|
-
--card: oklch(1 0 0);
|
|
54
|
-
--card-foreground: var(--text-primary);
|
|
55
|
-
--popover: oklch(1 0 0);
|
|
56
|
-
--popover-foreground: var(--text-primary);
|
|
57
|
-
--primary: oklch(0.546 0.215 262.9); /* Electric Blue */
|
|
58
|
-
--primary-foreground: var(--text-on-primary);
|
|
59
|
-
--secondary: oklch(0.961 0 0.5);
|
|
60
|
-
--secondary-foreground: var(--text-primary);
|
|
61
|
-
--muted: oklch(0.961 0 0.5);
|
|
62
|
-
--muted-foreground: var(--text-muted);
|
|
63
|
-
--accent: oklch(0.769 0.132 191.7); /* Electric Cyan */
|
|
64
|
-
--accent-foreground: oklch(0.17 0.02 260);
|
|
65
|
-
--destructive: var(--color-error);
|
|
66
|
-
--destructive-foreground: oklch(0.99 0 0);
|
|
67
|
-
--border: oklch(0.916 0.006 248); /* from hsl(214.3 31.8% 91.4%) */
|
|
68
|
-
--input: oklch(0.916 0.006 248);
|
|
69
|
-
--ring: oklch(0.546 0.215 262.9); /* Electric Blue */
|
|
70
|
-
|
|
71
|
-
/* ===== Border-radius ===== */
|
|
72
|
-
--radius: 0.5rem;
|
|
73
|
-
|
|
74
|
-
/* ===== Box shadows — soft neutral, no neon glow in light mode ===== */
|
|
75
|
-
--shadow-elev-0: none;
|
|
76
|
-
--shadow-elev-1: 0 1px 2px oklch(0 0 0 / 0.05);
|
|
77
|
-
--shadow-elev-2: 0 4px 6px oklch(0 0 0 / 0.07), 0 2px 4px oklch(0 0 0 / 0.06);
|
|
78
|
-
--shadow-elev-3: 0 10px 15px oklch(0 0 0 / 0.1), 0 4px 6px oklch(0 0 0 / 0.05);
|
|
79
|
-
--shadow-elev-4: 0 20px 25px oklch(0 0 0 / 0.1), 0 10px 10px oklch(0 0 0 / 0.04);
|
|
80
|
-
|
|
81
|
-
/* ===== Glow helpers — disabled in light mode ===== */
|
|
82
|
-
--glow-button: none;
|
|
83
|
-
--glow-button-hover: none;
|
|
84
|
-
--glow-card: none;
|
|
85
|
-
--glow-card-hover: none;
|
|
86
|
-
|
|
87
|
-
/* ===== Button shadow — transparent/none in light mode ===== */
|
|
88
|
-
--button-shadow: none;
|
|
89
|
-
}
|