# Phase 91 — Admin Theme tab: pickers + fields, pre-paint theme, CSS-file theming retired **Source:** `TODO.md` L4 — "Custom theming isn't really working. The page loads red first and then the theme "pops" into view, replacing words and colors in an obvious way. Remove the custom css file theming. Create a new admin tab that allows the user to change everything the env var and custom css currently supports but with buttons and color pickers. Theme should load immediately, not pop in after the page load." **Story:** n/a (TODO-derived — owner roadmap confirmation 2026-09-09). **Context:** Today's theming: `BOR_THEME=.css` (bare-filename validated at boot in `app/config.py::_theme_bare_css_filename`, fail-loud) → served by `GET /api/config` → `frontend/assets/brand.js` step 7 inserts `` **after the boot fetch settles** — so the page paints with the built-in red-first palette, then the theme's `:root` overrides swap in: the pop-in the owner saw. A theme file is one `:root` block overriding the **8 identity variables** (`--bg`, `--surface`, `--ink`, `--ink-soft`, `--line`, `--brand`, `--brand-soft`, `--brand-ink` — built-ins in `frontend/assets/styles.css`; authoring guide + the 5 contrast pairs in `frontend/assets/themes/README.md`; the semantic families `--accent-*`/`--ok-*`/`--err-*` are deliberately NOT identity). The env vars also carry 3 strings the same boot fetch applies via `brand.js`: `BOR_APP_NAME` (name passes incl. the TreeWalker prose replace), `BOR_INPUT_PLACEHOLDER`, `BOR_FOOTER_TEXT` (empty = template default = byte-identical contract). `Containerfile` line 27 ships `assets/themes` into the image. **Admin-tab pattern** (Tuning/Tokens, phases 76/79): a hidden `