diff --git a/CLAUDE.md b/CLAUDE.md index 9275242..082b13c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -76,10 +76,11 @@ Keep this seam clean — it is the most architecturally load-bearing part of the ### Theming and dark mode -- MudBlazor is the UI framework. Light and dark palettes (bespoke "Charleston in the Day" / "Lowcountry Summer Nights") defined inline in `MainLayout.razor`. +- MudBlazor is the UI framework. Light and dark palettes (bespoke "Charleston in the Day" / "Lowcountry Summer Nights") defined in `DeepDrftShared.Client/Common/DeepDrftPalettes.cs`. `MainLayout.razor` mounts `` — the palettes are not inline in the layout. - Dark mode toggles via cookie (`darkMode`, 365 days). Client-side via JS interop. - During server prerender, `DarkModeService` (in `DeepDrftPublic`) reads the cookie and seeds `DarkModeSettings.IsDarkMode`, which carries into WASM render via `PersistentComponentState`. Avoids "wrong theme flash" on initial paint. - `DarkModeSettings` lives in `DeepDrftPublic.Client.Common` (consumed by both server prerender and client components). +- **Theme-aware token layer:** `DeepDrftShared.Client/wwwroot/styles/deepdrft-tokens.css` defines two kinds of CSS custom properties. *Source tokens* (`--deepdrft-navy`, `--deepdrft-white`, `--deepdrft-green-accent`, etc.) are brand constants — identical in `:root` and `.deepdrft-theme-dark`. *Theme-aware aliases* are defined in both blocks and flip when the theme wrapper class changes. Component and page CSS must bind the **alias**, not the source token, so neutral surfaces invert for free. Current alias families: `--deepdrft-page-surface`/`-text`/`-text-muted` (neutral page backgrounds and text), `--deepdrft-play-chip`/`-glyph`/`-chip-soft` (play-state icon chip and glyph), `--deepdrft-popover-surface` (default MudBlazor popover background). Bespoke dark-glass panels (visualizer/queue/privacy) bind `--deepdrft-panel-ground` directly and are intentionally exempt from the neutral-surface alias. - Typography: Google Fonts (Bodoni Moda, Cormorant, DM Sans). Hand-rolled gas-lamp icon (lit/unlit) lives in `DeepDrftShared.Client/Common/DDIcons.cs`. ### TypeScript interop, not raw JS diff --git a/COMPLETED.md b/COMPLETED.md index 155051a..6fb528b 100644 --- a/COMPLETED.md +++ b/COMPLETED.md @@ -6,6 +6,29 @@ Newest entries at the top. Group by phase/wave header (mirroring `PLAN.md` / `CM --- +## Phase 18 — Theme / Dark-Mode Remediation (landed 2026-06-19) + +**Landed:** 2026-06-19 on dev (Wave 1 + Wave 2). + +- **What:** A DRY token pass resolving six theming symptoms (five in dark mode, one in light) that all traced to three root causes: neutral page surfaces bound to constant brand tokens, the play chip bound to a constant light-grey, and no theme-aware popover-surface token. Resolved as one coherent pass via a shared token layer rather than per-component patches. + +- **Why:** Symptom consolidation and root-cause analysis showed all six symptoms shared the same underlying structure — component CSS bypassing the theme-aware alias layer and binding constant source tokens directly. A single additive token pass in `deepdrft-tokens.css` plus targeted re-pointing of consumers fixes all six without scattering dark-mode rules. + +- **Shape:** + - **Token foundation (`deepdrft-tokens.css`):** Three new theme-aware token families added to `DeepDrftShared.Client/wwwroot/styles/deepdrft-tokens.css`, each defined in both `:root` (light) and `.deepdrft-theme-dark` (dark): + - `--deepdrft-page-surface` / `--deepdrft-page-text` / `--deepdrft-page-text-muted` — neutral page surface family. Light: `--deepdrft-white` / `--deepdrft-navy` / `--deepdrft-muted`. Dark: `var(--mud-palette-background)` (#0D1B2A, the true page ground) / `--deepdrft-white` / `color-mix(muted 70%, white)` — neutral sections dissolve into the site background as one continuous dark field rather than reading as raised panels. + - `--deepdrft-play-chip` / `--deepdrft-play-glyph` / `--deepdrft-play-chip-soft` — play-chip family. Light: soft-grey chip (matching prior `--deepdrft-soft`). Dark: `--deepdrft-green-accent` chip + `--deepdrft-navy` glyph (navy-on-green for solid chips); `--deepdrft-play-chip-soft` is `color-mix(green-accent 30%, transparent)` (the player-bar translucent override). + - `--deepdrft-popover-surface` — popover surface. Light: `color-mix(navy 8%, white)` soft desaturated-navy wash. Dark: `#162437` (pixel-identical to `DeepDrftPalettes.Dark.Surface` — dark popovers unchanged, only light is retoned). + - **Neutral-surface inversion (T2):** `Home.razor.css`, `About.razor.css`, `DeepDrftFooter.razor.css` re-pointed from constant `--deepdrft-white`/`--deepdrft-navy` to `--deepdrft-page-surface`/`--deepdrft-page-text`. Decorative navy/green sections (`.section-dark`, `.split-left`, `.cta-banner`, hero overlays) untouched — classification encoded in which token each section binds. + - **Play-chip theming (T3):** `PlayStateIcon.razor.css` `.icon-container` re-pointed to `--deepdrft-play-chip`; glyph to `--deepdrft-play-glyph`. Player-bar context overrides chip to `--deepdrft-play-chip-soft` (translucent green wash). Light-mode parity and connect-option hover also corrected. + - **Popover surface (T4):** `deepdrft-styles.css` binds `--deepdrft-popover-surface` to the MudBlazor default popover surface. Bespoke dark-glass panels (`--deepdrft-panel-ground`) untouched. + - **Wave 2 refinements (on top of T1–T4):** App bar background moved to navy (`#112338`) from near-black (`#0D1B2A`). Neutral page surfaces re-pointed to `var(--mud-palette-background)` (`#0D1B2A`) as the true dark ground — sections dissolve into the body background rather than reading as navy-mid raised panels (resolves Wave 1's open question in favour of ground). Dark-mode hero legibility: `DeepDrftHero.razor.css` adds `:global(.deepdrft-theme-dark)` overrides for `.hero-title` → `--deepdrft-page-text`, `.hero-title em` → `--deepdrft-green-accent`, `.hero-desc` → `--deepdrft-page-text`. Play-glyph settled on navy-on-green (solid chips) and green-on-green (player bar, via `--deepdrft-play-chip-soft`). + - **Open questions resolved:** Dark neutral surface = ground (continuous field, `--mud-palette-background`) — not elevated navy-mid. Popover target: `color-mix(navy 8%, white)` in light; dark binds `#162437` (MudBlazor dark Surface) unchanged. + +- **Design memo:** `product-notes/theme-dark-mode-remediation.md`. + +--- + ## Phase 17 — Player-Bar Queue View: Wave 17.3 — Fixed embed panel + iframe resize (landed 2026-06-19) **Landed:** 2026-06-19 on dev. diff --git a/PLAN.md b/PLAN.md index cad6899..bc2984b 100644 --- a/PLAN.md +++ b/PLAN.md @@ -342,44 +342,6 @@ the open-question set: `product-notes/phase-17-player-queue-view.md`. --- -## Phase 18 — Theme / Dark-Mode Remediation (DRY token pass) - -A punch-list of six theming symptoms Daniel reported — five in dark mode, one in light — -that all trace to **three** root causes in how component/page CSS bypasses the theme-aware -token layer and binds *constant* source tokens instead. Resolved as one coherent token pass, -not six per-component patches. Full design, architecture map, root-cause analysis, token -table, and track breakdown: `product-notes/theme-dark-mode-remediation.md`. - -**Root-cause collapse (six symptoms → three causes):** -- **Cause 1 — neutral surfaces don't invert.** Home hero-left + footer (#3) and About light - sections (#4) hardcode `background: var(--deepdrft-white)` / text on `--deepdrft-navy` — - brand *constants* that are identical in `:root` and `.deepdrft-theme-dark`, so they cannot - flip. Fix: bind a theme-aware `--deepdrft-page-surface` / `--deepdrft-page-text` alias. The - inversion must stay **neutral to the intentionally navy/green decorative sections** - (`.section-dark`, `.split-left`, `.cta-banner`, hero overlays) — a classify-then-recolor job. -- **Cause 2 — play chip binds a constant grey.** `PlayStateIcon.razor.css` `.icon-container` - hardcodes `--deepdrft-soft` (#e3e7ec). One shared component drives the release-hero chip, the - Cut track rows, *and* the player bar — so it reads "greyed-out" over dark heroes (#5) and "too - bright" on the navy player surface (#6). Fix: theme-aware `--deepdrft-play-chip` (moss-green + - navy glyph in dark) with a translucent `--deepdrft-play-chip-soft` override for the player bar. -- **Cause 3 — no theme-aware popover surface.** Light-mode default MudPopovers read "too dark" - (#1); there's no token for the wanted "desaturated navy." Fix: a `--deepdrft-popover-surface` - token; leave the bespoke `--deepdrft-panel-ground` panels alone. - -**Sequenced as four tracks, `T1 → {T2, T3, T4}`.** T1 (additive token foundation in -`deepdrft-tokens.css`) is the cold-start prerequisite; T2 (neutral-surface inversion), T3 -(play-chip theming), T4 (popover token) fan out behind it and are mutually independent. Pure -CSS-token pass — no source code, data layer, or streaming-seam changes. Prior art: -`product-notes/track-card-theming.md` solved this exact class of theme-aware recolor once -already; this generalizes the fix from one component to the pattern. - -**Open questions for Daniel (spec §5):** (1) dark neutral surface = navy *ground* (continuous -field — recommended for footer/hero) vs. *elevated* navy-mid (distinct panels); (2) popover -target distance from white (recommend a light `color-mix(navy ~8%, white)` wash). Exact green -opacity + muted-text mixes are tune-on-screen details, not decision gates. - ---- - ## Phase 19 — AuthBlocks User Management (CMS-only: admin surfaces + public self-registration) Wire **all three** AuthBlocks account-creation paths into the `DeepDrftManager` CMS — the admin