From 5510cebde1ad62e9727ed24ed4849d09be60c57e Mon Sep 17 00:00:00 2001 From: David Keane Date: Tue, 9 Jun 2026 23:54:09 +0100 Subject: [PATCH] feat(v0.5.0-prep): light mode support across all three surfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements the v0.4.0-plan-noted light mode using `@media (prefers-color-scheme: light)` blocks that override the :root CSS variables. The extension now auto-follows the user's OS theme — no toggle, no setting, no preference UI required (Phase 2 toggle deferred to a later release if anyone asks for it). Light-mode palette preserves brand identity: --bg #f6f4ed cream-leaning off-white --bg-soft #ece5d2 header / footer bars --bg-row #ddd6c0 hover backgrounds --bg-row-hi #c8c0a8 active rows --fg #2a2f28 dark forest-green-leaning text --fg-muted #6a7064 secondary text --accent #2a7d3e darker brand green (primary on light) --accent-dim #6dbf7a lighter brand green (secondary) --cream #b8861a darker amber — readable on light bg --danger #b53a2b darker red — readable on light bg Every existing CSS rule using var(--*) tokens carries over unchanged. The only surface-specific overrides are: - State pills (popup + newtab) — text colour flips to white when the background becomes solid accent/cream/danger - Primary play button (pressed state) — text colour flips - Helmet watermark on NewTab — opacity bumped 0.025 → 0.04 via a new --watermark-opacity var since the helmet contrasts differently against the lighter background - Toast (Options) — text colour flips to white on solid bg - Danger button hover (Options) — text colour flips to white Total: 3 files, +98 lines, 1 line modified. Bundled with the v0.4.1-prep back-link fix already merged into this branch. Together: a complete UX polish release (first-run hint shipped in v0.4.0 plus back-link plus light mode = v0.5.0). --- src/newtab/newtab.css | 31 ++++++++++++++++++++++++++++++- src/options/options.css | 28 ++++++++++++++++++++++++++++ src/popup/popup.css | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/newtab/newtab.css b/src/newtab/newtab.css index 6174fb7..5b1acb9 100644 --- a/src/newtab/newtab.css +++ b/src/newtab/newtab.css @@ -17,6 +17,35 @@ --danger: #c9685b; --radius: 8px; --maxw: 760px; + --watermark-opacity: 0.025; +} + +/* ────────────────────────────────────────────────────────────────────── + Light mode (v0.5.0) — auto-follows OS theme. Same approach as popup: + override :root vars so every existing rule using var(--*) keeps + working unchanged. Watermark opacity bumped slightly since the + helmet contrasts more against light bg. + ────────────────────────────────────────────────────────────────────── */ +@media (prefers-color-scheme: light) { + :root { + --bg: #f6f4ed; + --bg-soft: #ece5d2; + --bg-row: #ddd6c0; + --bg-row-hi: #c8c0a8; + --fg: #2a2f28; + --fg-muted: #6a7064; + --accent: #2a7d3e; + --accent-dim: #6dbf7a; + --cream: #b8861a; + --danger: #b53a2b; + --watermark-opacity: 0.04; + } + + /* State pills — keep them readable when their background is solid */ + .nt-state-pill[data-state="playing"] { color: #fff; } + .nt-state-pill[data-state="buffering"] { color: #fff; } + .nt-state-pill[data-state="error"] { color: #fff; } + .nt-btn--primary[aria-pressed="true"] { color: #fff; } } * { box-sizing: border-box; } @@ -40,7 +69,7 @@ body::before { background-repeat: no-repeat; background-position: center; background-size: min(60vh, 600px); - opacity: 0.025; + opacity: var(--watermark-opacity); pointer-events: none; z-index: 0; } diff --git a/src/options/options.css b/src/options/options.css index 395fb7a..3ea38b2 100644 --- a/src/options/options.css +++ b/src/options/options.css @@ -16,6 +16,34 @@ --radius: 6px; } +/* ────────────────────────────────────────────────────────────────────── + Light mode (v0.5.0) — auto-follows OS theme. Same approach as popup + + newtab: flip the :root vars only. Existing rules using var(--*) + carry over unchanged. Toast text + danger-button hover adjusted for + light-bg readability. + ────────────────────────────────────────────────────────────────────── */ +@media (prefers-color-scheme: light) { + :root { + --bg: #f6f4ed; + --bg-soft: #ece5d2; + --bg-row: #ddd6c0; + --bg-row-hi: #c8c0a8; + --fg: #2a2f28; + --fg-muted: #6a7064; + --accent: #2a7d3e; + --accent-dim: #6dbf7a; + --cream: #b8861a; + --danger: #b53a2b; + } + + /* Toast — keep readable when its background is solid accent / danger */ + .opt-toast { color: #fff; } + .opt-toast[data-tone="error"] { color: #fff; } + + /* Danger button hover — text flips to white when bg goes red */ + .opt-btn--danger:hover { color: #fff; } +} + * { box-sizing: border-box; } html, body { diff --git a/src/popup/popup.css b/src/popup/popup.css index 93fc4a8..dca6449 100644 --- a/src/popup/popup.css +++ b/src/popup/popup.css @@ -14,6 +14,38 @@ --cream: #f4e9b7; --danger: #c9685b; --radius: 6px; + + /* First-run hint pulse colour (RGB tuple — alpha applied in keyframes). */ + --pulse-rgb: 109, 191, 122; +} + +/* ────────────────────────────────────────────────────────────────────── + Light mode (v0.5.0) — auto-follows OS theme via prefers-color-scheme. + Flips backgrounds + foregrounds to a cream-leaning palette while + preserving the brand green as the accent. Every existing rule that + uses the var(--*) tokens keeps working unchanged. + ────────────────────────────────────────────────────────────────────── */ +@media (prefers-color-scheme: light) { + :root { + --bg: #f6f4ed; /* cream-leaning off-white */ + --bg-soft: #ece5d2; /* slightly darker for header bars */ + --bg-row: #ddd6c0; /* hover background */ + --bg-row-hi: #c8c0a8; /* active row background */ + --fg: #2a2f28; /* dark forest-green-leaning text */ + --fg-muted: #6a7064; /* muted secondary text */ + --accent: #2a7d3e; /* darker brand green for primary contrast */ + --accent-dim: #6dbf7a; /* lighter brand green for fills */ + --cream: #b8861a; /* darker amber — readable on light bg */ + --danger: #b53a2b; /* darker red — readable on light bg */ + } + + /* State pills — light-mode adjustments so playing/buffering states + stay readable. The "playing" green stays bright but text flips white; + "buffering" cream gets dark text since the cream is now amber. */ + .tuner-state[data-state="playing"] { color: #fff; } + .tuner-state[data-state="buffering"] { color: #fff; } + .tuner-state[data-state="error"] { color: #fff; } + .btn-primary[aria-pressed="true"] { color: #fff; } } * { box-sizing: border-box; }