ui: light theme by default (dark is opt-in)

Swaps the role of `:root` (now light) and the data-theme attribute
(now `[data-theme="dark"]`) in cassandra.css, flips the localStorage
fallback from 'dark' to 'light' in base/login/verify templates, and
updates the theme-toggle label and the branding-consistency test
selectors to match.

Existing users with cassandra.theme=dark in localStorage still see
dark — their explicit preference wins. Only first-time visitors and
users with no stored preference shift to light.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Giorgio Gilestro 2026-05-22 21:51:23 +01:00
parent 9e058144ec
commit 89632e9937
6 changed files with 42 additions and 39 deletions

View file

@ -16,10 +16,11 @@ detection test (`tests/test_branding_consistency.py`) parses
`cassandra.css` and asserts every variable matches. Update both or
neither.
The light theme is the *default* in emails mail clients can't read
`localStorage`, so we can't replicate the dashboard's user-toggled
theme. Clients that honour `prefers-color-scheme` get the dark palette
via media query.
The light theme is the *default* everywhere dashboard `:root` block,
auth pages, and emails. Dark is opt-in via the in-app toggle (which
sets `data-theme="dark"` on `<html>` and persists in `localStorage`).
Mail clients that honour `prefers-color-scheme: dark` get the dark
palette via media query.
"""
from __future__ import annotations

View file

@ -2,23 +2,7 @@
* Mono for data, headers, terminal feel; sans for prose surfaces (log + chat). */
:root {
/* Dark theme (default) */
--bg: #0a0e14;
--surface: #11151c;
--surface-2: #161b25;
--border: #2a3142;
--text: #d4dae8; /* lifted from #c0caf5 for readability */
--muted: #8189a1; /* lifted from #565f89 — was unreadably dim */
--dim: #565f89;
--accent: #00d9ff;
--positive: #50fa7b;
--negative: #ff5b5b;
--alert: #ff8a4a;
--warning: #f1fa8c;
--user-bubble-bg: rgba(0, 217, 255, 0.08);
}
[data-theme="light"] {
/* Light theme (default) */
--bg: #f5f3ec; /* warm off-white, easier on the eyes than pure white */
--surface: #ffffff;
--surface-2: #efece3;
@ -34,6 +18,22 @@
--user-bubble-bg: rgba(14, 116, 144, 0.07);
}
[data-theme="dark"] {
--bg: #0a0e14;
--surface: #11151c;
--surface-2: #161b25;
--border: #2a3142;
--text: #d4dae8; /* lifted from #c0caf5 for readability */
--muted: #8189a1; /* lifted from #565f89 — was unreadably dim */
--dim: #565f89;
--accent: #00d9ff;
--positive: #50fa7b;
--negative: #ff5b5b;
--alert: #ff8a4a;
--warning: #f1fa8c;
--user-bubble-bg: rgba(0, 217, 255, 0.08);
}
/* Font stacks. Mono for terminal feel; sans for reading. */
:root {
--font-mono: 'JetBrains Mono', 'IBM Plex Mono', 'Fira Code', ui-monospace, monospace;
@ -104,8 +104,8 @@ a:hover { text-decoration: underline; }
text-transform: lowercase;
}
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
.theme-toggle__label::before { content: "◐ dark"; }
[data-theme="light"] .theme-toggle__label::before { content: "◐ light"; }
.theme-toggle__label::before { content: "◐ light"; }
[data-theme="dark"] .theme-toggle__label::before { content: "◐ dark"; }
/* Tone toggle (segmented control: Novice | Intermediate) */
.tone-toggle {

View file

@ -8,9 +8,9 @@
<script>
(function() {
try {
var t = localStorage.getItem('cassandra.theme') || 'dark';
var t = localStorage.getItem('cassandra.theme') || 'light';
document.documentElement.dataset.theme = t;
} catch (e) { document.documentElement.dataset.theme = 'dark'; }
} catch (e) { document.documentElement.dataset.theme = 'light'; }
})();
</script>
<link rel="stylesheet" href="{{ url_for('static', path='/css/cassandra.css') }}" />

View file

@ -6,8 +6,8 @@
<title>{{ BRAND_NAME }} · Sign in</title>
<script>
(function() {
try { document.documentElement.dataset.theme = localStorage.getItem('cassandra.theme') || 'dark'; }
catch (e) { document.documentElement.dataset.theme = 'dark'; }
try { document.documentElement.dataset.theme = localStorage.getItem('cassandra.theme') || 'light'; }
catch (e) { document.documentElement.dataset.theme = 'light'; }
})();
</script>
<link rel="stylesheet" href="{{ url_for('static', path='/css/cassandra.css') }}" />

View file

@ -6,8 +6,8 @@
<title>{{ BRAND_NAME }} · Verify email</title>
<script>
(function() {
try { document.documentElement.dataset.theme = localStorage.getItem('cassandra.theme') || 'dark'; }
catch (e) { document.documentElement.dataset.theme = 'dark'; }
try { document.documentElement.dataset.theme = localStorage.getItem('cassandra.theme') || 'light'; }
catch (e) { document.documentElement.dataset.theme = 'light'; }
})();
</script>
<link rel="stylesheet" href="{{ url_for('static', path='/css/cassandra.css') }}" />