/* Brain of Reese — Theme view module (phase 91, task 05; phase 92, * task 04): the admin palette + branding editor. * * The phase-76 shell-view-module contract (the tuning.js / tokens.js * shape): the router (assets/router.js) lazy-imports this module on * FIRST show of #view-theme and calls mount(root) ONCE (mount-once, * hide-forever — root is the view's
, every * DOM lookup scoped to it). The initSharedHeader() call never happens * here: in the shell the shared header boots exactly once, via the * chat module (app.js) at shell boot. * * What the editor does: * * • gate — fetchIsAdmin() (the SAME cached /api/whoami promise * header.js exports, zero extra requests): admin hides #theme-gate * and reveals #theme-content; anonymous / token-user keeps the * gate (the #nav-theme link is already hidden by header.js — the * gate is the DIRECT-URL case, the #tokens-gate pattern). No * /api/ui-settings request is ever made outside the admin branch. * • load — GET /api/ui-settings → populate the 12 inputs with the * EFFECTIVE values (the resolver's DB-over-env / DB-over-built-in * merge): the tab always shows the live theme — env defaults when * the row is empty. A failed fetch keeps the static form (the * built-in values ship in the inputs) and shows #theme-error with * a retry (the loadHealth house style — never a blanked panel). * • live preview (colors only, B4) — on `input` of any of the 9 * color pickers the value is written straight onto as an * inline custom property, so the WHOLE page repaints (every view, * the header) while the owner is picking. Text fields have NO page * effect: the 3 strings keep the brand.js runtime application * (owner-locked B4) — they apply via the /api/config boot fetch on * the NEXT page load, and the sub-copy says so. * • served-theme sync (phase 92, defect 1) — the phase-91 defect: * Save/Reset removed the preview overrides, and the page then * fell back to the