# 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.
