From a3a59852685c3c093612744b3150d6f4b6853cd4 Mon Sep 17 00:00:00 2001 From: wtclaude Date: Sun, 19 Jul 2026 22:41:45 -0500 Subject: [PATCH] docs(android): summarize website frontend theme for Android client Co-Authored-By: Claude --- android/theme-plan.md | 98 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 android/theme-plan.md diff --git a/android/theme-plan.md b/android/theme-plan.md new file mode 100644 index 0000000..d09ce3c --- /dev/null +++ b/android/theme-plan.md @@ -0,0 +1,98 @@ +# 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. -- 2.49.1