@bsuite/theme 0.10.0 → 0.10.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 +2 -2
- package/src/css/braden.css +100 -10
- package/src/css/vars.css +36 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsuite/theme",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.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
|
|
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).",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
17
|
"src/css",
|
package/src/css/braden.css
CHANGED
|
@@ -193,11 +193,23 @@
|
|
|
193
193
|
--text-on-warning: var(--text-on-dark-fill);
|
|
194
194
|
--text-on-success: var(--text-on-dark-fill);
|
|
195
195
|
--text-on-info: var(--text-on-light-fill);
|
|
196
|
+
/* Was MISSING and preset-v4.css references it, so --color-overlay-foreground
|
|
197
|
+
resolved to nothing and any text on a scrim fell back to whatever it
|
|
198
|
+
inherited. Measured undefined in the browser on 2026-08-03. The scrim is
|
|
199
|
+
dark in both modes, so this is light in both. */
|
|
200
|
+
--text-on-overlay: var(--text-on-light-fill);
|
|
196
201
|
|
|
197
202
|
/* ============================================================
|
|
198
203
|
DECORATION — shadow, glow, dot and grid
|
|
199
204
|
============================================================ */
|
|
200
205
|
--gradient-accent: linear-gradient(135deg, var(--braden-red), var(--braden-gold));
|
|
206
|
+
/* Same gradient, re-stopped for a DARK backdrop. --gradient-accent is built
|
|
207
|
+
for fills on a light surface: against the hero scrim (L~0.36) its red stop
|
|
208
|
+
measures ~1.7:1 and the text half-disappears. This keeps the red hue and
|
|
209
|
+
chroma exactly (17.6 / 0.17) and lifts only lightness to a value the
|
|
210
|
+
contract already ships, so both stops clear the scrim and G2 still passes. */
|
|
211
|
+
--braden-red-on-dark: oklch(0.704 0.170 17.6);
|
|
212
|
+
--gradient-accent-on-dark: linear-gradient(135deg, var(--braden-red-on-dark), var(--braden-gold));
|
|
201
213
|
--shadow-xs: 0 1px 2px oklch(0.30 0.03 250 / 0.06);
|
|
202
214
|
--shadow-sm: 0 1px 3px oklch(0.30 0.03 250 / 0.08), 0 1px 2px oklch(0.30 0.03 250 / 0.04);
|
|
203
215
|
--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);
|
|
@@ -283,15 +295,93 @@
|
|
|
283
295
|
}
|
|
284
296
|
|
|
285
297
|
/* ============================================================
|
|
286
|
-
BASE — the heading
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
298
|
+
BASE — Corporate sets the heading FACE only.
|
|
299
|
+
============================================================
|
|
300
|
+
Not colour, not size, not weight, not transform. Reverted to this after
|
|
301
|
+
operator review ("well that looks worse") and a measurement that showed
|
|
302
|
+
why: on the live site the hero H1 picked up the ramp colour while the 25
|
|
303
|
+
headings below it kept their explicit `text-braden-navy`. One heading
|
|
304
|
+
stopped matching the rest. That is not a hierarchy.
|
|
305
|
+
|
|
306
|
+
A base rule only reaches elements that do not style themselves. In a
|
|
307
|
+
dense app UI that is most headings, which is the case the ramp was
|
|
308
|
+
measured against. On a marketing site it is almost none — 59 headings
|
|
309
|
+
here carry an explicit brand colour and their own size utility — so a
|
|
310
|
+
base ramp cannot create hierarchy there, only a mismatch on whichever
|
|
311
|
+
few it happens to reach.
|
|
312
|
+
|
|
313
|
+
font-family is the exception: nothing on the page overrides it, so it
|
|
314
|
+
lands uniformly and is exactly what a base rule is for.
|
|
315
|
+
|
|
316
|
+
D2C keeps the full ramp (see vars.css) — those apps ARE the dense-UI
|
|
317
|
+
case, and the ramp is verified there in a real browser by G5. */
|
|
290
318
|
@layer base {
|
|
291
|
-
h1 { font-family: var(--font-display);
|
|
292
|
-
h2 { font-family: var(--font-heading);
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
319
|
+
h1 { font-family: var(--font-display); }
|
|
320
|
+
h2, h3, h4, h5, h6 { font-family: var(--font-heading); }
|
|
321
|
+
|
|
322
|
+
/* The root element's colour was the UA default — measured pure black (L=0)
|
|
323
|
+
in BOTH modes on 2026-08-03, i.e. the one banned value, sitting at the top
|
|
324
|
+
of the inheritance chain. Nothing renders text at <html> so it was
|
|
325
|
+
invisible to review, but every element that does not set a colour and is
|
|
326
|
+
not under a styled ancestor lands on it. */
|
|
327
|
+
html { color: var(--role-text-body); background-color: var(--role-bg-base); }
|
|
328
|
+
|
|
329
|
+
/* The contract names a family and the package shipped the token, but NOTHING
|
|
330
|
+
bound it to an element — so every app fell back to whatever it happened
|
|
331
|
+
to set itself, which is how crm7 ran Inter against a Geist contract and
|
|
332
|
+
the estate ran four families at once. Same defect as the heading ramp:
|
|
333
|
+
a token nobody applies is not a font, it is a variable. */
|
|
334
|
+
body { font-family: var(--font-body); }
|
|
335
|
+
code, kbd, samp, pre { font-family: var(--font-mono); }
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/* ============================================================
|
|
339
|
+
DARK SURFACES INSIDE LIGHT MODE
|
|
340
|
+
============================================================
|
|
341
|
+
A navy or red panel on a light page is a dark surface, and the mode-sensitive
|
|
342
|
+
role tokens are still resolving their LIGHT values inside it. That is not a
|
|
343
|
+
theoretical problem — measured on the contact section 2026-08-03:
|
|
344
|
+
|
|
345
|
+
--role-accent-text (light) on bg-braden-navy ....... 2.20:1 FAIL
|
|
346
|
+
--braden-gold on bg-braden-navy ..... 5.07:1 AA
|
|
347
|
+
|
|
348
|
+
and the mirror holds on a light background, where the brand gold is 2.05:1
|
|
349
|
+
and the light accent is 4.71:1. No single value passes on both, so this
|
|
350
|
+
cannot be fixed by picking a better gold — the token has to follow the
|
|
351
|
+
SURFACE, not just the mode. Mark a dark panel and its accent text flips. */
|
|
352
|
+
[data-surface='dark'] {
|
|
353
|
+
--role-accent-text: var(--braden-gold);
|
|
354
|
+
--role-text-body: var(--text-on-light-fill);
|
|
355
|
+
--role-text-secondary: var(--text-on-light-fill);
|
|
356
|
+
/* D2C's heading ramp reads this; Corporate has no colour ramp, but a shared
|
|
357
|
+
surface contract should behave the same in both brands. */
|
|
358
|
+
--heading-color: currentColor;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* ============================================================
|
|
362
|
+
GRADIENT TEXT — the one place the accent gradient paints glyphs.
|
|
363
|
+
============================================================
|
|
364
|
+
background-clip:text needs `color: transparent` to show through, which means
|
|
365
|
+
a failed gradient produces INVISIBLE TEXT rather than an ugly one. So both
|
|
366
|
+
stops resolve from tokens defined above in this same file, never from a
|
|
367
|
+
token an app might or might not have. */
|
|
368
|
+
@layer components {
|
|
369
|
+
.text-gradient-accent {
|
|
370
|
+
background-image: var(--gradient-accent);
|
|
371
|
+
-webkit-background-clip: text;
|
|
372
|
+
background-clip: text;
|
|
373
|
+
color: transparent;
|
|
374
|
+
}
|
|
375
|
+
.text-gradient-accent-on-dark {
|
|
376
|
+
background-image: var(--gradient-accent-on-dark);
|
|
377
|
+
-webkit-background-clip: text;
|
|
378
|
+
background-clip: text;
|
|
379
|
+
color: transparent;
|
|
380
|
+
}
|
|
381
|
+
/* Forced-colours mode drops background-image entirely, which would leave
|
|
382
|
+
transparent glyphs on screen. Hand the text back to the system palette. */
|
|
383
|
+
@media (forced-colors: active) {
|
|
384
|
+
.text-gradient-accent,
|
|
385
|
+
.text-gradient-accent-on-dark { background-image: none; color: CanvasText; }
|
|
386
|
+
}
|
|
297
387
|
}
|
package/src/css/vars.css
CHANGED
|
@@ -500,16 +500,44 @@
|
|
|
500
500
|
hierarchy survives greyscale and both dichromacies rather than relying on
|
|
501
501
|
size alone.
|
|
502
502
|
|
|
503
|
-
Scoped to @layer base so any component class
|
|
504
|
-
|
|
503
|
+
Scoped to @layer base so any component class ON THE HEADING ITSELF wins.
|
|
504
|
+
That is a narrower guarantee than it looks, and the earlier version of this
|
|
505
|
+
comment ("it does not fight Tailwind utilities") was simply wrong.
|
|
506
|
+
|
|
507
|
+
WHAT IT DOES OVERRIDE: an INHERITED colour. Inheritance is the last resort in
|
|
508
|
+
the cascade, so a rule targeting `h1` beats `text-primary-foreground` sitting
|
|
509
|
+
on an ancestor — specificity never enters into it. Measured on braden
|
|
510
|
+
2026-08-03: a hero `<h1>` inheriting a near-white foreground from its wrapper
|
|
511
|
+
rendered dark navy against a dark scrim, i.e. all but invisible, and it was
|
|
512
|
+
the ONLY heading on the page that moved. That is the signature of this bug —
|
|
513
|
+
one heading changing is not a small problem, it is the coloured-container
|
|
514
|
+
case, and coloured containers are where text goes invisible.
|
|
515
|
+
|
|
516
|
+
--heading-color is the escape hatch. Any container that colours its own text
|
|
517
|
+
sets it once and the whole heading subtree defers:
|
|
518
|
+
<div class="text-primary-foreground [--heading-color:currentColor]">
|
|
519
|
+
currentColor there resolves to the container's colour, so headings inherit
|
|
520
|
+
again instead of being repainted. */
|
|
505
521
|
@layer base {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
522
|
+
/* See braden.css: the root element inherits the UA default pure black when
|
|
523
|
+
nothing sets it, which is the one banned value at the top of the chain. */
|
|
524
|
+
html { color: var(--role-text-body); background-color: var(--role-bg-base); }
|
|
525
|
+
|
|
526
|
+
/* The contract names a family and the package shipped the token, but NOTHING
|
|
527
|
+
bound it to an element — so every app fell back to whatever it happened
|
|
528
|
+
to set itself, which is how crm7 ran Inter against a Geist contract and
|
|
529
|
+
the estate ran four families at once. Same defect as the heading ramp:
|
|
530
|
+
a token nobody applies is not a font, it is a variable. */
|
|
531
|
+
body { font-family: var(--font-body); }
|
|
532
|
+
code, kbd, samp, pre { font-family: var(--font-mono); }
|
|
533
|
+
|
|
534
|
+
h1 { color: var(--heading-color, var(--role-h1)); font-size: 25px; font-weight: 700; letter-spacing: var(--track-display); }
|
|
535
|
+
h2 { color: var(--heading-color, var(--role-h2)); font-size: 19px; }
|
|
536
|
+
h3 { color: var(--heading-color, var(--role-h3)); font-size: 16px; }
|
|
537
|
+
h4 { color: var(--heading-color, var(--role-h4)); font-size: 14px; }
|
|
538
|
+
h5 { color: var(--heading-color, var(--role-h5)); font-size: 13px; }
|
|
511
539
|
h6 {
|
|
512
|
-
color: var(--role-h6);
|
|
540
|
+
color: var(--heading-color, var(--role-h6));
|
|
513
541
|
font-size: 11px;
|
|
514
542
|
text-transform: uppercase;
|
|
515
543
|
letter-spacing: var(--track-eyebrow);
|