feat: Studio onboarding wizard — custom theme palette upload in Step 3 (FU-CUSTOM-THEME, refs #499 / epic &51)
Follow-up from MR1c (Studio onboarding wizard, #499 (closed) / epic &51).
MR1c's Step 3 picks one of three curated theme presets (forest / ocean / canyon). Production deployments need brand-accurate palettes — agency colors, accessibility-tuned text/background pairs against the official brand book — not three pre-baked options.
Scope
- Step 3 gains a "custom palette" expand affordance.
- Operator pastes hex values for the core palette tokens (surface / surface_raised / primary / accent / text_body / border_soft, both light + dark).
- Wizard validates each hex is a valid 6-digit color and runs WCAG-AA contrast checks on text-on-surface pairs at submit.
- bundle.rs
render_theme_tomlwrites the custom palette when set; preset path still works as the default.
Out of scope
- Logo upload / branding/agency_short edits (already in scope of Step 1).
- Layout (nav_position, etc.) — those are deployment-time switches, not theme.
Acceptance
- 6 hex inputs per light + dark = 12 inputs.
- Submit fails 422 if any contrast pair drops below WCAG AA (4.5:1 normal text; 3:1 large text).
- Generated theme.toml reflects custom palette; preset radio cards still selectable as a fallback.
- Unit + Playwright coverage parallels MR1c's preset test grid.