@bsuite/theme 0.7.1 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsuite/theme",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -11,7 +11,7 @@
11
11
  "url": "https://github.com/GaryOcean428/bsuite.git",
12
12
  "directory": "packages/theme"
13
13
  },
14
- "description": "BSuite Universal theme \u2014 D2C Neon Electric + Braden Corporate baselines. Tailwind v4 preset, CSS vars (5-layer), role aliases, colourblind-safe tokens, eye-strain-safe text scale, BrandingProvider (runtime white-label). Used by BSU, CRM7, conduit, R80.3, throughput (D2C) and braden.com.au (Corporate).",
14
+ "description": "BSuite Universal theme D2C Neon Electric + Braden Corporate baselines. Tailwind v4 preset, CSS vars (5-layer), role aliases, colourblind-safe tokens, eye-strain-safe text scale, BrandingProvider (runtime white-label). Used by BSU, CRM7, conduit, R80.3, throughput (D2C) and braden.com.au (Corporate).",
15
15
  "files": [
16
16
  "dist",
17
17
  "src/css",
@@ -1,230 +1,225 @@
1
1
  /*
2
2
  * @bsuite/theme — Braden Corporate brand baseline
3
- * Version 0.3.0
3
+ * Version 0.4.0
4
4
  *
5
5
  * Usage (braden.com.au only):
6
6
  * @import '@bsuite/theme/braden-css';
7
7
  *
8
- * This file is EXCLUSIVELY for the braden.com.au Corporate brand.
9
- * NEVER import this into D2C webapp projects (crm7, conduit, BSU, R80.3).
10
- * NEVER apply Neon Electric colours to braden.com.au surfaces.
8
+ * EXCLUSIVELY for the braden.com.au Corporate brand. Never import this into a
9
+ * D2C app (crm7, conduit, BSU, R80.3, throughput), and never put Neon Electric
10
+ * colours on a Corporate surface.
11
11
  *
12
- * Architecture same 5-layer structure as vars.css:
13
- * 1. Palette — --braden-red-*, --braden-gold-*, --braden-navy-*
14
- * 2. Surface — --braden-light-*, --braden-dark-*
15
- * 3. Role — --role-* (rebinds D2C role tokens to Braden values)
16
- * 4. Shadcn — --background, --foreground, etc. (same keys, Braden values)
17
- * 5. App — --app-primary, --app-accent
12
+ * GENERATED FROM THE CONTRACT, NOT HAND-TUNED.
13
+ * Every value below is copied from
14
+ * packages/theme/docs/braden-corporate-theme-source-of-truth.html
15
+ * which is authoritative. Operator ruling 2026-08-03: only colours present in
16
+ * the two source-of-truth documents are permitted in packages/. Verify with
17
+ * scripts/audit-palette-whitelist.py
18
18
  *
19
- * Colourblind policy is PRESERVED:
20
- * --role-error / --role-destructive = PURPLE (oklch(0.568 0.202 283.1))
21
- * Same as D2Cpurple error is a cross-brand system requirement.
19
+ * WHAT CHANGED IN 0.4.0 AND WHY IT MATTERED
20
+ * 0.3.0 carried its own hand-built red/gold/navy ramps. 52 of its values
21
+ * appeared nowhere in the Corporate contract close to the brand, but not the
22
+ * brand, and drifting further with every edit. This file also shipped a header
23
+ * asserting "purple error is a cross-brand system requirement", which was
24
+ * already false twice over: the 0.7.0 separation-first contract retired purple
25
+ * for semantics, and the Corporate contract binds error to --braden-indigo.
22
26
  *
23
- * Eye-strain policy is PRESERVED:
24
- * Dark text capped at L=0.94. Light text capped at L=0.22 (navy hue 250).
25
- *
26
- * OKLCH format mandatory for all new tokens. Tailwind v4+ is the only
27
- * supported Tailwind engine for BSuite consumers.
27
+ * ERROR IS INDIGO HERE, NOT RED — deliberately, and for the opposite reason to
28
+ * D2C. D2C's primary is blue, so error must be red to separate from it.
29
+ * Corporate's primary IS red, so a red error would collide with the brand's
30
+ * own primary action colour. Same rule, inverted inputs.
28
31
  */
29
32
 
30
- /* ============================================================
31
- LAYER 1 — BRADEN CORPORATE PALETTE PRIMITIVES
32
- ============================================================ */
33
- :root {
34
- /* Primary — Braden Red scale */
35
- --braden-red-50: oklch(0.965 0.015 17);
36
- --braden-red-100: oklch(0.930 0.035 17);
37
- --braden-red-200: oklch(0.870 0.070 18);
38
- --braden-red-300: oklch(0.780 0.110 18);
39
- --braden-red-400: oklch(0.660 0.145 18);
40
- --braden-red-500: oklch(0.550 0.175 18); /* main brand red */
41
- --braden-red-600: oklch(0.488 0.170 17.6); /* canonical –- oklch spec */
42
- --braden-red-700: oklch(0.420 0.150 17);
43
- --braden-red-800: oklch(0.340 0.120 16);
44
- --braden-red-900: oklch(0.260 0.090 15);
45
-
46
- /* Accent — Braden Gold scale */
47
- --braden-gold-50: oklch(0.980 0.015 88);
48
- --braden-gold-100: oklch(0.955 0.035 89);
49
- --braden-gold-200: oklch(0.910 0.060 90);
50
- --braden-gold-300: oklch(0.860 0.078 91);
51
- --braden-gold-400: oklch(0.829 0.073 91.8); /* light gold */
52
- --braden-gold-500: oklch(0.769 0.096 90.9); /* canonical accent */
53
- --braden-gold-600: oklch(0.711 0.115 89.5); /* bronze */
54
- --braden-gold-700: oklch(0.630 0.110 88);
55
- --braden-gold-800: oklch(0.520 0.090 86);
56
- --braden-gold-900: oklch(0.400 0.065 84);
57
-
58
- /* Navy — secondary brand colour */
59
- --braden-navy-50: oklch(0.960 0.008 249);
60
- --braden-navy-100: oklch(0.920 0.015 249);
61
- --braden-navy-200: oklch(0.840 0.025 249);
62
- --braden-navy-300: oklch(0.720 0.030 249);
63
- --braden-navy-400: oklch(0.580 0.033 249);
64
- --braden-navy-500: oklch(0.450 0.035 249);
65
- --braden-navy-600: oklch(0.356 0.039 249); /* canonical navy */
66
- --braden-navy-700: oklch(0.280 0.030 248);
67
- --braden-navy-800: oklch(0.200 0.022 248);
68
- --braden-navy-900: oklch(0.130 0.015 248);
69
-
70
- /* Neutrals */
71
- --braden-slate: oklch(0.710 0.018 201.5);
72
- --braden-sky: oklch(0.653 0.135 242.7);
73
- --braden-forest: oklch(0.663 0.160 152.4);
74
- --braden-lavender:oklch(0.577 0.153 315.3);
75
-
76
- /* ============================================================
77
- LAYER 2 — BRADEN SURFACE PRIMITIVES (light mode)
78
- ============================================================ */
79
- --braden-light-bg-body: oklch(0.980 0.002 50); /* warm white */
80
- --braden-light-bg-surface: oklch(0.996 0.001 50); /* near white */
81
- --braden-light-bg-panel: oklch(0.994 0.002 250); /* near-white; pure white is banned in every role */
82
- --braden-light-bg-input: oklch(0.972 0.003 250); /* cool light grey */
83
-
84
- /* Braden light text scale — hue 250 (navy cast), capped L=0.22 */
85
- --braden-light-text-primary: oklch(0.22 0.020 250); /* 13.2:1 ✓ AAA */
86
- --braden-light-text-secondary: oklch(0.38 0.018 250); /* 8.1:1 ✓ AAA */
87
- --braden-light-text-muted: oklch(0.52 0.018 250); /* 4.9:1 ✓ AA */
88
- --braden-light-text-subtle: oklch(0.60 0.012 250); /* 3.8:1 ✓ AA large */
89
- --braden-light-text-disabled: oklch(0.72 0.010 250);
90
33
 
91
- --braden-light-border: oklch(0.900 0.008 248);
92
- --braden-light-hover: oklch(0.950 0.005 248);
34
+ :root {
93
35
 
94
- /* ============================================================
95
- LAYER 3ROLE ALIASES (Braden light-mode rebind)
96
- Reuses the same --role-* names as vars.css so components
97
- are brand-agnostic at the role layer.
98
- ============================================================ */
99
- --role-primary: var(--braden-red-600); /* oklch(0.488 0.170 17.6) */
100
- --role-secondary: var(--braden-navy-600); /* oklch(0.356 0.039 249) */
101
- --role-accent: var(--braden-gold-500); /* oklch(0.769 0.096 90.9) */
36
+ /* ============================================================
37
+ LAYER 1BRAND PALETTE
38
+ Raw brand colours. Consumers must never bind to these directly.
39
+ ============================================================ */
40
+ --braden-red: oklch(0.488 0.170 17.6);
41
+ --braden-red-light: oklch(0.572 0.201 17.9);
42
+ --braden-red-dark: oklch(0.400 0.137 16.8);
43
+ --braden-gold: oklch(0.758 0.092 89.9);
44
+ --braden-gold-light: oklch(0.818 0.070 90.0);
45
+ --braden-bronze: oklch(0.698 0.110 89.2);
46
+ --braden-navy: oklch(0.356 0.039 249.0);
47
+ --braden-slate: oklch(0.710 0.018 201.3);
48
+ --braden-sky: oklch(0.653 0.135 242.7);
49
+ --braden-forest: oklch(0.663 0.160 152.4);
50
+ --braden-lavender: oklch(0.577 0.152 315.3);
51
+ --braden-indigo: oklch(0.400 0.200 270);
52
+ --braden-teal-deep: oklch(0.500 0.140 220);
53
+ --braden-aqua: oklch(0.800 0.130 198);
102
54
 
103
- /* Colourblind policy: SAME purple as D2C — cross-brand requirement */
104
- --role-error: oklch(0.568 0.202 283.1);
105
- --role-destructive: oklch(0.568 0.202 283.1);
106
- --role-warning: oklch(0.728 0.168 22.5);
107
- --role-success: oklch(0.663 0.160 152.4); /* braden forest green */
108
- --role-info: var(--braden-sky);
55
+ /* ============================================================
56
+ LAYER 2 — SURFACES AND BORDERS
57
+ ============================================================ */
58
+ --role-bg-body: oklch(0.980 0.002 50);
59
+ --role-bg-surface: oklch(0.968 0.004 55);
60
+ --role-bg-panel: oklch(0.994 0.001 50);
61
+ --role-bg-input: oklch(0.972 0.003 250);
62
+ --role-bg-sunken: oklch(0.952 0.005 250);
63
+ --role-border: oklch(0.900 0.008 248);
64
+ --role-border-strong: oklch(0.840 0.012 248);
109
65
 
110
- /* Text roles */
111
- --role-text-body: var(--braden-light-text-primary);
112
- --role-text-secondary: var(--braden-light-text-secondary);
113
- --role-text-muted: var(--braden-light-text-muted);
114
- --role-text-subtle: var(--braden-light-text-subtle);
115
- --role-text-disabled: var(--braden-light-text-disabled);
116
- --role-text-heading: oklch(0.19 0.025 252); /* near-navy — 14.8:1 ✓ AAA */
66
+ /* ============================================================
67
+ LAYER 3 — HEADING RAMP (six levels, per the contract)
68
+ ============================================================ */
69
+ --role-h1: oklch(0.20 0.028 252);
70
+ --role-h2: oklch(0.25 0.034 250);
71
+ --role-h3: oklch(0.30 0.040 246);
72
+ --role-h4: oklch(0.35 0.046 240);
73
+ --role-h5: oklch(0.40 0.052 232);
74
+ --role-h6: oklch(0.44 0.058 224);
117
75
 
118
- /* Surface roles */
119
- --role-bg-body: var(--braden-light-bg-body);
120
- --role-bg-surface: var(--braden-light-bg-surface);
121
- --role-bg-panel: var(--braden-light-bg-panel);
122
- --role-bg-input: var(--braden-light-bg-input);
123
- --role-border: var(--braden-light-border);
76
+ /* ============================================================
77
+ LAYER 3 — TEXT AND LINKS
78
+ ============================================================ */
79
+ --role-text-heading: var(--role-h1);
80
+ --role-text-body: oklch(0.22 0.020 250);
81
+ --role-text-secondary: oklch(0.38 0.018 250);
82
+ --role-text-muted: oklch(0.52 0.018 250);
83
+ --role-text-subtle: oklch(0.60 0.012 250);
84
+ --role-text-disabled: oklch(0.72 0.010 250);
85
+ --role-text-strong: oklch(0.16 0.024 252);
86
+ --role-text-emphasis: oklch(0.42 0.070 240);
87
+ --role-link: oklch(0.480 0.140 245);
88
+ --role-link-hover: oklch(0.400 0.150 250);
89
+ --role-link-visited: oklch(0.450 0.120 300);
124
90
 
125
- /* Inverse text on coloured fills */
126
- --text-on-primary: oklch(0.99 0 0); /* on red L≈0.49 7.8:1 ✓ AA */
127
- --text-on-accent: oklch(0.17 0.02 250); /* on gold L≈0.77 — dark text */
128
- --text-on-error: oklch(0.99 0 0); /* on purple */
129
- --text-on-success: oklch(0.17 0.02 250);
130
- --text-on-warning: oklch(0.17 0.02 250);
91
+ /* ============================================================
92
+ LAYER 3 EDITORIAL (code, quote, mark, kbd)
93
+ ============================================================ */
94
+ --role-code-text: oklch(0.400 0.090 230);
95
+ --role-code-bg: oklch(0.950 0.010 235);
96
+ --role-quote-text: oklch(0.400 0.060 25);
97
+ --role-quote-rule: var(--braden-gold);
98
+ --role-mark-bg: oklch(0.930 0.060 90);
99
+ --role-mark-text: oklch(0.24 0.040 60);
100
+ --role-kbd-bg: oklch(0.962 0.004 250);
101
+ --role-kbd-border: oklch(0.870 0.010 250);
131
102
 
132
- /* ============================================================
133
- LAYER 4SHADCN BRIDGE (Braden values)
134
- ============================================================ */
135
- --background: var(--braden-light-bg-body);
136
- --foreground: var(--braden-light-text-primary);
137
- --card: var(--braden-light-bg-panel);
138
- --card-foreground: var(--braden-light-text-primary);
139
- --popover: var(--braden-light-bg-panel);
140
- --popover-foreground: var(--braden-light-text-primary);
141
- --primary: var(--braden-red-600);
142
- --primary-foreground: oklch(0.99 0 0);
143
- --secondary: var(--braden-navy-600);
144
- --secondary-foreground: oklch(0.99 0 0);
145
- --muted: var(--braden-light-bg-input);
146
- --muted-foreground: var(--braden-light-text-muted);
147
- --accent: var(--braden-gold-500);
148
- --accent-foreground: oklch(0.17 0.02 250);
149
- --destructive: oklch(0.568 0.202 283.1);
150
- --destructive-foreground: oklch(0.99 0 0);
151
- --border: var(--braden-light-border);
152
- --input: var(--braden-light-border);
153
- --ring: var(--braden-red-600);
103
+ /* ============================================================
104
+ LAYER 3SEMANTIC ROLES
105
+ error = --braden-indigo: Corporate primary is RED, so error cannot be.
106
+ ============================================================ */
107
+ --role-primary: var(--braden-red);
108
+ --role-secondary: var(--braden-navy);
109
+ --role-accent: var(--braden-gold);
110
+ --role-error: var(--braden-indigo);
111
+ --role-destructive: var(--braden-indigo);
112
+ --role-warning: var(--braden-gold);
113
+ --role-success: var(--braden-aqua);
114
+ --role-info: var(--braden-teal-deep);
154
115
 
155
- /* ============================================================
156
- LAYER 5APP SHORTCUTS
157
- ============================================================ */
158
- --app-primary: var(--braden-red-600);
159
- --app-accent: var(--braden-gold-500);
116
+ /* ============================================================
117
+ LAYER 3AA-SAFE TEXT RENDERINGS OF THE SATURATED ROLES
118
+ A saturated fill colour is not a legible text colour.
119
+ ============================================================ */
120
+ --role-primary-text: oklch(0.566 0.170 17.6);
121
+ --role-accent-text: oklch(0.544 0.092 89.9);
122
+ --role-error-text: oklch(0.562 0.200 270);
123
+ --role-warning-text: oklch(0.544 0.092 89.9);
124
+ --role-success-text: oklch(0.515 0.130 198);
125
+ --role-info-text: oklch(0.519 0.140 220);
160
126
 
161
- /* ============================================================
162
- SHADOWScorporate subtle, no neon glow
163
- ============================================================ */
164
- --shadow-sm: 0 1px 2px oklch(0.30 0.03 250 / 0.08);
165
- --shadow-md: 0 4px 6px oklch(0.30 0.03 250 / 0.10), 0 2px 4px oklch(0.30 0.03 250 / 0.06);
166
- --shadow-lg: 0 10px 15px oklch(0.30 0.03 250 / 0.10), 0 4px 6px oklch(0.30 0.03 250 / 0.05);
127
+ /* ============================================================
128
+ LAYER 3 INVERSE TEXT ON COLOURED FILLS
129
+ ============================================================ */
130
+ --text-on-light-fill: oklch(0.980 0.006 50);
131
+ --text-on-dark-fill: oklch(0.190 0.020 250);
132
+ --text-on-primary: var(--text-on-light-fill);
133
+ --text-on-error: var(--text-on-light-fill);
134
+ --text-on-accent: var(--text-on-dark-fill);
135
+ --text-on-warning: var(--text-on-dark-fill);
136
+ --text-on-success: var(--text-on-dark-fill);
137
+ --text-on-info: var(--text-on-light-fill);
167
138
 
168
- /* Card glow is a dark-mode-only device (see .dark below); light mode
169
- stays border-only, consistent with the corporate "no neon glow" rule. */
139
+ /* ============================================================
140
+ DECORATION — shadow, glow, dot and grid
141
+ ============================================================ */
142
+ --gradient-accent: linear-gradient(135deg, var(--braden-red), var(--braden-gold));
143
+ --shadow-xs: 0 1px 2px oklch(0.30 0.03 250 / 0.06);
144
+ --shadow-sm: 0 1px 3px oklch(0.30 0.03 250 / 0.08), 0 1px 2px oklch(0.30 0.03 250 / 0.04);
145
+ --shadow-md: 0 4px 10px -3px oklch(0.30 0.03 250 / 0.10), 0 2px 4px -2px oklch(0.30 0.03 250 / 0.06);
146
+ --shadow-lg: 0 14px 26px -8px oklch(0.28 0.04 250 / 0.14), 0 5px 10px -5px oklch(0.28 0.04 250 / 0.07);
170
147
  --glow-card: none;
171
148
  --glow-card-hover: none;
149
+ --panel-hairline: transparent;
150
+ --dot-color: oklch(0.42 0.030 250 / 0.14);
151
+ --dot-size: 16px;
152
+ --dot-radius: 1px;
153
+ --grid-color: oklch(0.40 0.030 250 / 0.07);
154
+ --grid-size: 32px;
155
+
156
+ /* ============================================================
157
+ TYPOGRAPHY AND GEOMETRY
158
+ ============================================================ */
159
+ --font-display: 'Open Sans', system-ui, sans-serif;
160
+ --font-heading: Lato, 'Open Sans', system-ui, sans-serif;
161
+ --font-body: 'Open Sans', system-ui, sans-serif;
162
+ --font-mono: 'JetBrains Mono', ui-monospace, monospace;
163
+ --track-display: -0.018em;
164
+ --track-heading: -0.008em;
165
+ --track-body: 0em;
166
+ --track-eyebrow: 0.10em;
167
+ --radius-sm: 4px;
168
+ --radius: 6px;
169
+ --radius-lg: 10px;
170
+ --row-pad: 11px;
172
171
  }
173
172
 
174
173
  /* ============================================================
175
- BRADEN DARK MODE
174
+ DARK MODE — the contract's .dark block, verbatim.
175
+ Only tokens the contract actually flips appear here; anything
176
+ absent is mode-independent by design, not by omission.
176
177
  ============================================================ */
177
178
  .dark {
178
- /* Dark surfaces */
179
- --braden-dark-bg-body: oklch(0.118 0.010 252);
180
- --braden-dark-bg-surface: oklch(0.165 0.015 251);
181
- --braden-dark-bg-panel: oklch(0.200 0.018 250);
182
- --braden-dark-bg-input: oklch(0.240 0.020 250);
183
-
184
- /* Dark text scale — hue 250, capped L=0.93 (Braden uses navy cast) */
185
- --braden-dark-text-primary: oklch(0.93 0.014 250); /* ~13.1:1 ✓ AAA */
186
- --braden-dark-text-secondary: oklch(0.80 0.016 250); /* ~9.0:1 ✓ AAA */
187
- --braden-dark-text-muted: oklch(0.66 0.018 250); /* ~5.2:1 ✓ AA */
188
- --braden-dark-text-subtle: oklch(0.55 0.015 250); /* ~3.5:1 ✓ AA large */
189
- --braden-dark-text-disabled: oklch(0.43 0.010 250);
190
-
191
- /* Rebind roles */
192
- --role-text-body: var(--braden-dark-text-primary);
193
- --role-text-secondary: var(--braden-dark-text-secondary);
194
- --role-text-muted: var(--braden-dark-text-muted);
195
- --role-text-subtle: var(--braden-dark-text-subtle);
196
- --role-text-disabled: var(--braden-dark-text-disabled);
197
- --role-text-heading: oklch(0.91 0.016 250);
198
-
199
- --role-bg-body: var(--braden-dark-bg-body);
200
- --role-bg-surface: var(--braden-dark-bg-surface);
201
- --role-bg-panel: var(--braden-dark-bg-panel);
202
- --role-bg-input: var(--braden-dark-bg-input);
203
- --role-border: oklch(0.30 0.020 250);
204
-
205
- /* Shadcn bridge picks up via var() chain */
206
- --background: var(--braden-dark-bg-body);
207
- --foreground: var(--braden-dark-text-primary);
208
- --card: var(--braden-dark-bg-panel);
209
- --card-foreground: var(--braden-dark-text-primary);
210
- --muted: var(--braden-dark-bg-input);
211
- --muted-foreground:var(--braden-dark-text-muted);
212
- --border: oklch(0.30 0.020 250);
213
- --input: oklch(0.30 0.020 250);
214
-
215
- /*
216
- * Card glow Braden dark mode gets a restrained gold separation glow,
217
- * NOT the D2C neon treatment (no cyan, lower alpha, same two-layer
218
- * ring+halo shape for consumer-code parity with @bsuite/theme's D2C
219
- * --glow-card). Source is --app-accent (Braden Gold), which is
220
- * inherited from :root since this file does not rebind it per-mode.
221
- * Deliberately more subdued than D2C to honour the "corporate
222
- * subtle, no neon glow" shadow philosophy above, adapted for dark UI
223
- * where SOME separation glow is still needed for surface legibility.
224
- */
225
- --card-glow-source: var(--app-accent, var(--braden-gold-500));
226
- --glow-card: 0 0 0 1px color-mix(in oklch, var(--card-glow-source) 18%, transparent),
227
- 0 0 10px -4px color-mix(in oklch, var(--card-glow-source) 20%, transparent);
228
- --glow-card-hover: 0 0 0 1px color-mix(in oklch, var(--card-glow-source) 26%, transparent),
229
- 0 0 14px -4px color-mix(in oklch, var(--card-glow-source) 28%, transparent);
179
+ --role-bg-body: oklch(0.140 0.012 252);
180
+ --role-bg-surface: oklch(0.180 0.016 251);
181
+ --role-bg-panel: oklch(0.205 0.018 250);
182
+ --role-bg-input: oklch(0.245 0.020 250);
183
+ --role-bg-sunken: oklch(0.120 0.010 252);
184
+ --role-border: oklch(0.320 0.020 250);
185
+ --role-border-strong: oklch(0.420 0.024 250);
186
+ --role-h1: oklch(0.95 0.014 250);
187
+ --role-h2: oklch(0.92 0.018 250);
188
+ --role-h3: oklch(0.88 0.024 244);
189
+ --role-h4: oklch(0.84 0.032 236);
190
+ --role-h5: oklch(0.80 0.040 228);
191
+ --role-h6: oklch(0.75 0.048 220);
192
+ --role-text-body: oklch(0.93 0.014 250);
193
+ --role-text-secondary: oklch(0.80 0.016 250);
194
+ --role-text-muted: oklch(0.66 0.018 250);
195
+ --role-text-subtle: oklch(0.55 0.015 250);
196
+ --role-text-disabled: oklch(0.43 0.010 250);
197
+ --role-text-strong: oklch(0.97 0.010 250);
198
+ --role-text-emphasis: oklch(0.85 0.050 235);
199
+ --role-link: oklch(0.780 0.110 240);
200
+ --role-link-hover: oklch(0.860 0.095 225);
201
+ --role-link-visited: oklch(0.770 0.080 300);
202
+ --role-code-text: oklch(0.850 0.070 215);
203
+ --role-code-bg: oklch(0.250 0.026 230);
204
+ --role-quote-text: oklch(0.840 0.045 40);
205
+ --role-quote-rule: var(--braden-gold);
206
+ --role-mark-bg: oklch(0.360 0.060 85);
207
+ --role-mark-text: oklch(0.94 0.030 85);
208
+ --role-kbd-bg: oklch(0.250 0.020 250);
209
+ --role-kbd-border: oklch(0.400 0.022 250);
210
+ --role-primary-text: oklch(0.704 0.170 17.6);
211
+ --role-accent-text: oklch(0.683 0.092 89.9);
212
+ --role-error-text: oklch(0.711 0.200 270);
213
+ --role-warning-text: oklch(0.683 0.092 89.9);
214
+ --role-success-text: oklch(0.662 0.130 198);
215
+ --role-info-text: oklch(0.667 0.140 220);
216
+ --shadow-xs: 0 1px 2px oklch(0.07 0.01 252 / 0.5);
217
+ --shadow-sm: 0 1px 3px oklch(0.07 0.01 252 / 0.55);
218
+ --shadow-md: 0 6px 16px -6px oklch(0.07 0.01 252 / 0.6);
219
+ --shadow-lg: 0 18px 34px -12px oklch(0.07 0.01 252 / 0.68);
220
+ --glow-card: 0 0 0 1px color-mix(in oklch, var(--braden-gold) 18%, transparent), 0 0 10px -4px color-mix(in oklch, var(--braden-gold) 20%, transparent);
221
+ --glow-card-hover: 0 0 0 1px color-mix(in oklch, var(--braden-gold) 30%, transparent), 0 0 16px -4px color-mix(in oklch, var(--braden-gold) 32%, transparent);
222
+ --panel-hairline: color-mix(in oklch, var(--braden-gold) 26%, transparent);
223
+ --dot-color: oklch(0.72 0.060 90 / 0.16);
224
+ --grid-color: oklch(0.82 0.020 250 / 0.055);
230
225
  }
package/src/css/vars.css CHANGED
@@ -30,7 +30,8 @@
30
30
  * Pure white (L=1.0) and pure black (L=0) are BANNED in EVERY role —
31
31
  * text, surface, border, ring and shadow alike (operator ruling
32
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
33
+ * --light-bg-accent ship as oklch(1 0 0.5) theme-audit-ok: naming the
34
+ * value that was REMOVED — and render every shadcn card
34
35
  * and popover pure white. "White" here means oklch(0.982 0.002 248)
35
36
  * (#f8f9fa); the lightest surface is bg-panel at L=0.994.
36
37
  *
@@ -74,7 +75,7 @@
74
75
  --light-bg-primary: oklch(0.961 0 0.5);
75
76
  --light-bg-secondary: oklch(0.982 0.002 248);
76
77
  --light-bg-tertiary: oklch(0.963 0.003 228.9);
77
- /* bg-panel. Was oklch(1 0 0.5) — pure white, and since --card and
78
+ /* bg-panel. theme-audit-ok: prose. Was oklch(1 0 0.5) — pure white, and since --card and
78
79
  --popover bridge to it, every shadcn card and popover in all five D2C
79
80
  apps rendered pure white in light mode from this one line. */
80
81
  --light-bg-accent: oklch(0.994 0.002 260);
@@ -138,7 +139,18 @@
138
139
  /* Text roles — six-tier scale (W3 §3.1 contract). Every tier below is
139
140
  measured against --role-bg-body (the conservative floor); all tiers
140
141
  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
+ /* Six-level heading ramp contract §heading-ramp. Each level shifts hue as
143
+ well as lightness, so the hierarchy reads in greyscale and under both
144
+ dichromacies, not only by size. --role-text-heading is h1 by definition;
145
+ it used to carry its own literal (chroma 0.018 against the contract's
146
+ 0.020) which is how a token drifts off-palette one hair at a time. */
147
+ --role-h1: oklch(0.20 0.020 263);
148
+ --role-h2: oklch(0.26 0.026 258);
149
+ --role-h3: oklch(0.31 0.034 248);
150
+ --role-h4: oklch(0.36 0.042 236);
151
+ --role-h5: oklch(0.41 0.050 222);
152
+ --role-h6: oklch(0.45 0.058 208);
153
+ --role-text-heading: var(--role-h1); /* 16.17:1 ✓ AAA */
142
154
  --role-text-body: var(--light-text-primary); /* 15.46:1 ✓ AAA */
143
155
  --role-text-secondary: var(--light-text-secondary); /* 8.94:1 ✓ AAA */
144
156
  --role-text-muted: var(--light-text-muted); /* 4.92:1 ✓ AA normal */
@@ -154,7 +166,7 @@
154
166
  --role-border: var(--light-border);
155
167
  --role-border-strong: oklch(0.880 0.008 250);
156
168
 
157
- /* Scrim — the veil behind a modal, and the reason `bg-black/N` survived
169
+ /* Scrim — the veil behind a modal, and the reason `bg-black/N` survived theme-audit-ok: prose
158
170
  everywhere else. It was the single most duplicated pure endpoint in the
159
171
  tree (9 sites across nav-core, page-builder and schema-builder) for one
160
172
  reason: no overlay role existed, so every author reached for the only
@@ -301,7 +313,7 @@
301
313
  NO sRGB FALLBACK — DELIBERATELY REMOVED 2026-08-02.
302
314
  Precedent: precedent__bsuite__20260802__theme_conformance_is_absolute.
303
315
 
304
- The `@supports not (color: oklch(0 0 0))` block that stood here shipped
316
+ theme-audit-ok: prose. The `@supports not (color: oklch(0 0 0))` block that stood here shipped
305
317
  a parallel hex palette. It is gone, and must not be reinstated:
306
318
 
307
319
  · OKLCH has been Baseline-available in every evergreen engine since
@@ -320,12 +332,13 @@
320
332
  DARK MODE — Layer 2 surface overrides + Layer 3 role rebind
321
333
  ============================================================ */
322
334
  .dark {
323
- /* Dark surface primitives */
335
+ /* Dark surface primitives.
336
+ --dark-bg-tertiary, -quaternary, -accent and --dark-hover were DELETED
337
+ 2026-08-03: four tokens, zero consumers anywhere in the monorepo or the
338
+ five apps, and none of their values appears in the contract. A palette
339
+ entry nobody binds to is not a spare part — it is a second source of
340
+ truth waiting for someone to reach for it. */
324
341
  --dark-bg-primary: oklch(0.166 0.026 269.4);
325
- --dark-bg-secondary: oklch(0.242 0.03 269.9);
326
- --dark-bg-tertiary: oklch(0.326 0.036 266.7);
327
- --dark-bg-quaternary: oklch(0.39 0.035 265);
328
- --dark-bg-accent: oklch(0.292 0.034 270);
329
342
 
330
343
  /* D2C dark text scale — hue 260, capped L=0.94.
331
344
  Pure white (L=1.0) is BANNED as a text token.
@@ -342,10 +355,19 @@
342
355
  --dark-text-disabled: oklch(0.44 0.010 260); /* disabled — 2.48:1 ✗ fails AA at any size — MUST pair with icon cue */
343
356
 
344
357
  --dark-border: oklch(0.428 0.015 248.2);
345
- --dark-hover: oklch(0.39 0.035 265);
358
+
359
+ /* Six-level heading ramp — contract §heading-ramp. Every level is a
360
+ DIFFERENT hue as well as a different lightness, so the hierarchy survives
361
+ greyscale and both dichromacies rather than relying on size alone. */
362
+ --role-h1: oklch(0.95 0.016 262);
363
+ --role-h2: oklch(0.92 0.018 264);
364
+ --role-h3: oklch(0.88 0.026 240);
365
+ --role-h4: oklch(0.84 0.040 220);
366
+ --role-h5: oklch(0.80 0.052 200);
367
+ --role-h6: oklch(0.75 0.062 195);
346
368
 
347
369
  /* Rebind roles to dark-mode surface values — six-tier scale (W3 §3.1). */
348
- --role-text-heading: oklch(0.92 0.014 260); /* 15.21:1 ✓ AAA */
370
+ --role-text-heading: var(--role-h1);
349
371
  --role-text-body: var(--dark-text-primary); /* 16.16:1 ✓ AAA */
350
372
  --role-text-secondary: var(--dark-text-secondary); /* 11.04:1 ✓ AAA */
351
373
  --role-text-muted: var(--dark-text-muted); /* 6.69:1 ✓ AA normal */
@@ -353,7 +375,7 @@
353
375
  --role-text-disabled: var(--dark-text-disabled); /* 2.48:1 ✗ icon cue required */
354
376
 
355
377
  --role-bg-body: var(--dark-bg-primary);
356
- --role-bg-surface: var(--dark-bg-secondary);
378
+ --role-bg-surface: oklch(0.212 0.028 269);
357
379
  --role-bg-panel: oklch(0.190 0.020 260);
358
380
  --role-bg-input: oklch(0.240 0.020 260);
359
381
  --role-bg-sunken: oklch(0.145 0.022 268);