Motivka

Fix: Light Mode Colours Bleed into Admin Pages

Fixed a CSS token architecture bug where toggling light mode on the public site caused admin pages to inherit light colours, breaking the always-dark admin theme.

1 Phases
3 Tasks
1 Days

The Problem

Toggle light mode on any public page, then navigate to the admin dashboard. Every admin page -- sidebar, headers, cards, buttons -- would render with light-coloured backgrounds and dark text. The admin interface is supposed to be permanently dark regardless of the visitor-facing colour mode preference.

The workaround was absurd: navigate back to a public page, toggle dark mode, then return to admin. The colour mode toggle is deliberately hidden on admin pages, so there was no way to fix it from within the admin interface itself.

Root Cause

The --admin-* CSS custom properties were defined as references to semantic tokens that change with colour mode:

  • --admin-bg: var(--bg-primary) resolved to var(--charcoal-ember) in dark mode but flipped to a light value when [data-colour-mode='light'] was active
  • --admin-text: var(--text-primary) similarly resolved to light-on-dark or dark-on-light depending on mode

CSS custom properties resolve at use-time, not definition-time. So when the light mode selector was active on <html>, every admin token that referenced a semantic token inherited the light value. The light mode block in app.css had no admin token overrides to protect against this.

The Fix

I pinned all six admin tokens directly to their dark palette values -- the stable constants that never change with colour mode:

  • --admin-bg: var(--charcoal-ember) instead of var(--bg-primary)
  • --admin-text: var(--powder-sand) instead of var(--text-primary)
  • Hard values for --admin-bg-elevated, --admin-border, --admin-text-secondary, and --admin-text-muted

The admin chart tokens (--chart-*-admin) referenced --admin-* tokens rather than semantic tokens directly, so they inherited the fix automatically.

This was a CSS-only change. No JavaScript, no Svelte component modifications. The fix follows the architectural rule I have since codified: admin tokens must be self-contained and never depend on tokens that change based on user preference.

Testing

I used the Defensive TDD workflow -- safety net tests first, then a failing reproduction test, then the fix. The E2E test navigates to the homepage, toggles light mode, navigates to admin, and asserts the background luminance remains dark. That test failed before the fix and passes after.

Bugs Fixed

Key Decisions

  • Pinned admin tokens to palette values instead of adding light-mode admin overrides — Admin tokens should be self-contained constants, not responsive to user preference. This is the architecturally correct boundary.
  • Used Defensive TDD workflow — Safety net tests first, then reproduction, then fix -- ensures no regressions and proves the bug is genuinely resolved