"""Brand single source of truth — name, domain, palette, fonts. The product is **Read the Markets** (read.markets). "Cassandra" remains the in-product *AI persona* (system prompt + chat label) — distinct from the brand, the way Slackbot is distinct from Slack. Anything that crosses into user-visible chrome (page titles, email headers, OpenRouter referer) must read `BRAND_NAME` from here; do not hard-code the string. Internal identifiers (`cassandra_session` cookie, pyproject package name, SQLAlchemy GET_LOCK keys, env var `CASSANDRA_TOKEN`) keep the legacy name on purpose — renaming them would invalidate live sessions / advisory locks / configs for zero brand benefit. The colour palette below is hand-authored in CSS as well; a drift- detection test (`tests/test_branding_consistency.py`) parses `tokens.css` and asserts every variable matches. Update both or neither. 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 `` and persists in `localStorage`). Mail clients that honour `prefers-color-scheme: dark` get the dark palette via media query. """ from __future__ import annotations BRAND_NAME = "Read the Markets" BRAND_SHORT = "Read" DOMAIN = "read.markets" SITE_URL = "https://read.markets" # The app lives at the apex too — same host serves landing/legal *and* # the dashboard. SITE_URL and APP_URL are kept as separate symbols so a # future split (marketing/apex, app/subdomain) is a two-line change. APP_URL = "https://read.markets" EMAIL_FROM_DEFAULT = f"noreply@{DOMAIN}" # Marketing line — printed in the landing hero. Single source of truth so # OG cards, email subjects, and the landing template stay in sync. The # wording is a stance, not just a description: this is for people who # treat investing and gambling as different activities. The "news # aggregator / media service" framing still lives in the body copy and # the disclaimer, where it does the legal distancing work. TAGLINE = "Understand markets. Don't gamble on them." # Legal-page operator details. Placeholders until the user supplies real # ones; only the legal pages read them. LEGAL_OPERATOR = BRAND_NAME OPERATOR_EMAIL = f"hello@{DOMAIN}" OPERATOR_JURISDICTION = "United Kingdom" DARK: dict[str, str] = { "bg": "#0a0e14", "surface": "#11151c", "surface-2": "#161b25", "border": "#2a3142", "text": "#d4dae8", "muted": "#8189a1", "dim": "#565f89", "accent": "#00d9ff", "positive": "#50fa7b", "negative": "#ff5b5b", "alert": "#ff8a4a", "warning": "#f1fa8c", } LIGHT: dict[str, str] = { "bg": "#f5f3ec", "surface": "#ffffff", "surface-2": "#efece3", "border": "#d6d3cb", "text": "#1c1f25", "muted": "#545b69", "dim": "#8a8f9a", "accent": "#0e7490", "positive": "#166534", "negative": "#b91c1c", "alert": "#c2410c", "warning": "#a16207", } FONT_MONO = ( "'JetBrains Mono', 'IBM Plex Mono', 'Fira Code', " "ui-monospace, Menlo, Consolas, monospace" ) FONT_SANS = ( "-apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto, " "'Helvetica Neue', system-ui, sans-serif" )