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_toml writes 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.