Files
ScadaBridge/docs/plans/2026-06-18-m10-t34-spike-findings.md
T
2026-06-18 19:18:49 -04:00

8.0 KiB

T34 Spike: Theme Dark-Mode Feasibility Findings

Date: 2026-06-18 Task: Verify whether the external ZB.MOM.WW.Theme shell can go dark via data-bs-theme CSS override.


1. CSS Load Order

Confirmed from src/ZB.MOM.WW.ScadaBridge.Host/Components/App.razor:

bootstrap.min.css          (line 8)
bootstrap-icons.css        (line 9)
<ThemeHead />              (line 10)  → injects theme.css then layout.css
Host.styles.css            (line 11)
site.css                   (line 12)  ← our override point

site.css loads after theme.css and layout.css. A [data-bs-theme="dark"] block in site.css has sufficient specificity to shadow every :root token defined in theme.css, because [attr] selector specificity (0,1,0) beats :root (0,0,1) at equal cascade layer.


2. Token Inventory (theme.css :root)

All tokens defined in the :root block of ~/.nuget/packages/zb.mom.ww.theme/0.3.1/staticwebassets/css/theme.css:

Surfaces & ink

Token Light value Role
--paper #f4f4f1 page background
--card #ffffff raised surfaces, bars, table heads
--ink #1b1d21 primary text
--ink-soft #5a6066 secondary text, labels
--ink-faint #8b9097 tertiary text, captions
--rule #e4e4df hairline borders, row dividers
--rule-strong #d2d2cb emphasised hairlines, bar underline, pills

Accent

Token Light value Role
--accent #2f5fd0 links, sort arrows, primary actions
--accent-deep #1e3f99 hover/pressed accent

Status — foreground

Token Light value
--ok #2f9e44
--warn #e8920c
--bad #e03131
--idle #868e96

Status — tinted backgrounds

Token Light value
--ok-bg #e9f6ec
--warn-bg #fdf1dd
--bad-bg #fceaea
--idle-bg #eef0f2

Status — borders

Token Light value
--ok-border #c6e6cd
--warn-border #efd6a6
--bad-border #eec3c3
--ok-border-soft #bfe3c6
--warn-border-soft #f0d9ab
--bad-border-soft #f0c0c0

Warning ink

Token Light value
--warn-ink #b56a00
--warn-ink-deep #8a5a00

Info tint

Token Light value
--info-bg #e7ecfb
--info-border #cdd9f7

Neutral surface washes

Token Light value Role
--zebra-bg #fbfbf9 even-row / sticky-head fill
--hover-bg #f3f6fd row / rail-link hover
--active-bg #eef2fc active rail-link fill

Bootstrap overrides (derive from above)

Token Value
--bs-body-bg var(--paper)
--bs-body-color var(--ink)
--bs-body-font-family var(--sans)
--bs-body-font-size 0.9rem
--bs-primary var(--accent)
--bs-border-color var(--rule)
--bs-emphasis-color var(--ink)

3. Rail Tokenization Audit (layout.css)

Every colour-bearing rule in the side-rail uses CSS custom properties. No hard-coded hex or rgb values appear anywhere in layout.css. Key rules:

Rail background and border:

.side-rail {
    background: var(--card);
    border-right: 1px solid var(--rule-strong);
}

Brand block:

.side-rail .brand {
    color: var(--ink);
    border-bottom: 1px solid var(--rule);
}
.side-rail .brand .mark { color: var(--accent); }

Section eyebrow / toggle:

.rail-eyebrow-toggle { color: var(--ink-faint); }
.rail-eyebrow-toggle:hover { color: var(--ink); }
.rail-section > summary::before { color: var(--ink-faint); }

Nav links (default / hover / active):

.rail-link { color: var(--ink-soft); }
.rail-link:hover { background: var(--hover-bg); color: var(--ink); }
.rail-link.active { background: var(--active-bg); border-left-color: var(--accent); color: var(--accent-deep); }

Rail foot / session block:

.rail-foot { border-top: 1px solid var(--rule); }
.rail-btn { color: var(--ink-soft); background: var(--card); border: 1px solid var(--rule-strong); }
.rail-btn:hover { border-color: var(--accent); color: var(--accent); }
.rail-roles { color: var(--ink-faint); }
.rail-ico { color: var(--ink-faint); }

Login title:

.login-title { color: var(--ink); }

4. VERDICT

RAIL TOKENIZES → dark feasible by token override.

Every rail background, text, and border colour in layout.css resolves through a CSS custom property from the token set. Overriding the token values under [data-bs-theme="dark"] in site.css (which loads after theme.css/layout.css) will fully recolour the side-rail, app chrome, panels, data tables, chips, and status elements — no Theme-package coordination required.


5. Concrete Dark Token Override List

Paste this entire block under [data-bs-theme="dark"] in site.css. Accent colour (--accent) is kept at #4d7fe8 — a lighter shade of the brand blue that reads well on dark backgrounds while preserving brand identity.

[data-bs-theme="dark"] {
  /* Surfaces & ink */
  --paper:        #1b1d21;
  --card:         #25282d;
  --ink:          #e6e8ec;
  --ink-soft:     #9aa0aa;
  --ink-faint:    #6b727c;
  --rule:         #33373e;
  --rule-strong:  #3a3f46;

  /* Accent — lightened for contrast on dark */
  --accent:       #4d7fe8;
  --accent-deep:  #7aa0ef;

  /* Status — foregrounds unchanged (inherently visible on dark) */
  --ok:           #40b856;
  --warn:         #f0a030;
  --bad:          #f05050;
  --idle:         #7a8290;

  /* Status — tinted backgrounds (dark surface tints) */
  --ok-bg:        #1a2e1e;
  --warn-bg:      #2e2210;
  --bad-bg:       #2e1616;
  --idle-bg:      #25282d;

  /* Status — borders on dark tints */
  --ok-border:        #2a5030;
  --warn-border:      #4a3510;
  --bad-border:       #4a2020;
  --ok-border-soft:   #264a2c;
  --warn-border-soft: #44300e;
  --bad-border-soft:  #44201e;

  /* Warning ink — brightened amber for dark contrast */
  --warn-ink:      #d4891a;
  --warn-ink-deep: #b8741a;

  /* Info tint */
  --info-bg:      #1a2240;
  --info-border:  #2a3660;

  /* Neutral surface washes */
  --zebra-bg:     #202328;
  --hover-bg:     #2a2e38;
  --active-bg:    #1e2640;

  /* Bootstrap bridge tokens */
  --bs-body-bg:        var(--paper);
  --bs-body-color:     var(--ink);
  --bs-border-color:   var(--rule);
  --bs-emphasis-color: var(--ink);
}

6. Caveats

  1. Bootstrap intrinsic dark utilities: Bootstrap 5.3 has its own [data-bs-theme="dark"] rules for components (alerts, badges, modals, etc.). Our token block sits in site.css at cascade level 0; Bootstrap's own dark-mode block in bootstrap.min.css (loaded earlier) will also fire. The Bootstrap rules and our token rules are additive and complementary — they should not conflict, but any Bootstrap component that ignores our tokens and uses Bootstrap's built-in dark-mode palette may have a slightly different feel. Inspect on first run.

  2. body gradient in theme.css: The body rule in theme.css is:

    body {
      background: radial-gradient(1200px 480px at 88% -8%, var(--card) 0%, rgba(255,255,255,0) 70%),
                  var(--paper);
    }
    

    On dark mode, rgba(255,255,255,0) in the gradient is transparent white and will remain unchanged. The gradient will still render; var(--card) will resolve to the dark card value and the effect will be a subtle lighter sheen in the top-right corner — acceptable, but the gradient can be suppressed in site.css for a flatter dark background if preferred.

  3. Status tints on dark: The status background tokens (--ok-bg, --warn-bg, --bad-bg) are deliberately dark-surface equivalents (very low-saturation tints). Verify contrast ratios of status chip text against these backgrounds before shipping.

  4. data-bs-theme placement: The attribute must be set on <html> (or <body>) so the CSS selector matches all descendants. The toggle implementation (next task) should write document.documentElement.setAttribute('data-bs-theme', 'dark').