# Android theme plan — mirroring the website frontend This is a summary of the **website frontend theme** (source of truth: `website/client/src/styles/theme.css`, applied at runtime by `website/client/src/contexts/SiteContext.jsx`) so the native Android client can present a visually consistent brand. Where the web uses CSS custom properties, the Android equivalent is a Compose `MaterialTheme` `ColorScheme` + `Typography`. ## Overall character A **dark, moody, "arcane fantasy" theme** — deep blue-black backgrounds, muted slate-blue accent, parchment-white text, and an engraved serif display face. It reads like a leather-and-moonlight fantasy ledger, not a bright consumer app. There is **no light mode** on the web; the app should ship dark-only to match. ## Color tokens The web theme is a flat set of CSS variables under `:root`. Map them to Compose as follows (hex is authoritative): | Web token | Hex | Role | Compose slot (suggested) | |-------------------|------------|----------------------------------------|-------------------------------| | `--bg` | `#0e1318` | App background | `background` | | `--bg-deep` | `#0b0f14` | Deepest surface / on-accent text | `surfaceDim` / `onPrimary` | | `--panel-a` | `#192231` | Card gradient top | `surface` | | `--panel-b` | `#141a21` | Card gradient bottom | `surfaceContainer` | | `--panel-flat` | `#11161d` | Flat panels, toolbars | `surfaceContainerLow` | | `--line` | `#2a3544` | Borders / dividers | `outline` | | `--line-soft` | `#1d2733` | Subtle row dividers | `outlineVariant` | | `--accent` | `#7f99bd` | **Primary accent** (brand-overridable) | `primary` | | `--accent-bright` | `#cdd9e8` | Primary button fill, active states | `primaryContainer` / bright | | `--ink` | `#eef3f8` | Highest-contrast text | `onBackground` | | `--head` | `#e6edf6` | Headings | heading color | | `--text` | `#c4cdd8` | Body prose | `onSurface` | | `--muted` | `#aeb8c4` | Secondary text | `onSurfaceVariant` | | `--dim` | `#6f7d8e` | Meta / captions / placeholders | dim / disabled text | | `--blue` | `#13243c` | Accent hover/active background | `secondaryContainer` | | `--mode-live` | `#5fb98a` | "Shard live" status (green) | success | | `--mode-maint` | `#e6c26a` | "Maintenance" status (amber) | warning | ### Semantic / status colors (used in badges, diffs, moderation) - **Success / published / live:** green `#5fb98a` (fills at ~16–22% alpha, text `#7fd0a4`). - **Warning / maintenance / moderation (kick/mute/warn):** amber `#e0b070` / `#e6c26a`. - **Danger / ban / red-link / errors:** desaturated red `#d98b84` (borders `#6e3b38`). - **Admin badge:** near-white `#d8e2ef` on `#3a4a5e`. ## Branding is data, not code The `--accent` value is **overridden at runtime** per shard instance. On the web, `SiteContext` reads `brand.accent` from the site settings API and sets the CSS variable, so one build reskins for any shard. **The Android app should do the same:** fetch the brand payload (name, `accent`, colors, logo/hero/favicon) from the website API and derive the `primary` color at runtime rather than hardcoding `#7f99bd`. Default to `#7f99bd` when the brand payload is absent/offline. ## Typography Three font families, by role: - **Display** (`--display`): **Cinzel**, falling back to Georgia serif — an engraved Roman capitals face used for the logo, `h1`/`.h1`, and prose `h2`/`h3`. Bundle Cinzel as an app font; this face carries the brand. - **Serif body** (`--serif`): **Georgia / Times New Roman** — default body and prose text; `line-height ≈ 1.6`. - **Sans** (`--sans`): **Helvetica Neue / Arial** — UI chrome: buttons, pills, form labels, table headers, badges, meta. Labels/eyebrows/kickers are UPPERCASE with wide letter-spacing (`0.1–0.18em`) and small (0.68–0.86rem). Heading scale is fluid on web (`h1` clamps ~2.4–3.6rem); pick fixed Material type scale equivalents (e.g. display for `h1`, headline for `h2`, title for `h3`). ## Shape, elevation & motion - **Corners:** cards/panels `10–12px` radius; inputs/small elements `8px`; pills and buttons are **fully rounded** (`999px` / capsule). - **Cards:** vertical gradient `--panel-a → --panel-b`, 1px `--line` border, soft drop shadow (`0 14px 34px rgba(0,0,0,0.3)`). On hover the web lifts `-3px` and brightens the border to `--accent` — translate to a pressed/focused accent border on Android. - **Buttons:** primary = bright fill (`--accent-bright`) with dark text; ghost/secondary = translucent dark fill with accent-on-hover border. - **Motion:** short, subtle transitions (0.12–0.18s). Keep animations understated. ## Signature accents (nice-to-have) - The **"moon"** motif: a radial-gradient sphere (`#eef3f8 → #9fb0c6 → #5d6e88`) — a small brand flourish worth reproducing. - Accent-tinted focus rings and left-border "note" callouts (`border-left: 3px solid --accent` over a translucent `--blue` background). ## Implementation note for Compose Define one `darkColorScheme(...)` from the table above, a `Typography` binding the three families, and a `Shapes` set (`small = 8.dp`, `medium = 10.dp`, capsule for buttons). Load `accent` from the brand API into a state holder and rebuild the `primary` (and derived `primaryContainer`) at runtime so a shard's custom accent flows through the whole UI — exactly as `SiteContext` does on the web.