The website merged runtime admin theming, brand assets and nav overrides to
main (website#126 / docs#109). The app reads exactly one field of it --
brand.accent -- and renders a hardcoded APP_MENU, so an admin who re-skins the
site and restructures the header sees none of it on the phone.
Adds docs/android/THEMING_AND_NAV.md as the design of record for M12, and the
PLAN.md §9 entry that anchors it. Plan only: no app code, no backend work.
Everything consumed is already live on website/main.
The points that shaped it:
- The app's ui/theme/Color.kt palette is already, value for value, the
runic-gateway preset -- M5 was drawn from the same theme.css the preset was
later extracted from. So "an untouched instance is unchanged" carries over as
a testable ColorScheme equality assertion, not an approximation.
- Radii apply as a ratio against that baseline, not as literal dp. The app's
Shapes came from the M5 mockup and genuinely differ (medium 12dp vs
--radius-card 10px); a literal mapping would restyle the untouched app the
day this ships, and copying the app's scale into the server would be a second
source of truth.
- Fonts are bundled, not downloadable: the Play Store font provider makes a
de-Googled device fall back silently. Seven families join the bundled Cinzel.
- Nav overrides are keyed by website paths, so the app needs a path -> route
table -- the one new cross-repo coupling here. An override for a path the app
does not surface in its menu is ignored: a nav override may never introduce
navigation.
- The gates are untouched. MenuAccess and MenuEntry.feature still run after the
merge, so hidden:false cannot un-hide what a role or the shard's visibility
config withholds.
- Read the resolved theme/brand fields, never the raw theme_visual/brand_assets
rows that ride along in the same payload -- re-deriving a palette from them
would be a second resolveThemeTokens in Kotlin, guaranteed to drift.
Nine phases into a fresh edge in both repos, reaching main as one edge -> main
merge, the same shape the website side used. Phase 0 must change nothing on
screen. Phase 7 (the authenticated navs) is marked optional: nav_player reaches
two app rows and nav_admin two, which is a thin return for a new authenticated
fetch and its cache teardown.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TgfKv5cz5pbY3dPeofSE5a