css: split cassandra.css into per-section files

Splits the 2571-line cassandra.css into ten focused stylesheets:
tokens (palette + fonts), layout (chrome), panels, dashboard,
portfolio, log-chat, auth, settings, news, public. base.html and
public_base.html load only what they need; auth pages (login,
verify, unsubscribe confirm) load tokens + layout + auth.

Brand drift-detection test repointed at tokens.css (where the
palette now lives). 291 tests still pass.
This commit is contained in:
Giorgio Gilestro 2026-05-28 12:31:29 +02:00
parent 78ce8c8b0d
commit 355593c4f7
19 changed files with 2556 additions and 2585 deletions

View file

@ -1,6 +1,6 @@
"""Drift-detection: brand palette in `app/branding.py` must match the CSS.
Both the website (cassandra.css) and the email templates use the same
Both the website (tokens.css) and the email templates use the same
palette. The CSS hand-authors the values in :root and [data-theme="light"]
blocks; this test parses those blocks and asserts every variable matches
its counterpart in branding.py. If a colour changes, both must change.
@ -15,7 +15,7 @@ import pytest
from app import branding
CSS_PATH = Path(__file__).resolve().parent.parent / "app" / "static" / "css" / "cassandra.css"
CSS_PATH = Path(__file__).resolve().parent.parent / "app" / "static" / "css" / "tokens.css"
def _extract_vars(css: str, selector: str) -> dict[str, str]:
@ -23,7 +23,7 @@ def _extract_vars(css: str, selector: str) -> dict[str, str]:
selector block. Strips whitespace; lowercases hex values."""
# Match the selector followed by its block. Non-greedy on the body to
# stop at the first closing brace at the same depth (these blocks
# don't nest in cassandra.css).
# don't nest in tokens.css).
pattern = re.escape(selector) + r"\s*\{([^}]*)\}"
m = re.search(pattern, css)
if not m: