R6 L1+L3: motore di stile del form (token + CSS custom)

Il form era gia' tokenizzato (~30 var CSS in :root): non riscriviamo nulla,
iniettiamo un blocco di override DOPO il CSS di base, cosi' un errore di
configurazione del merchant non puo' rompere il default.

- theme.ts (modulo PURO, condiviso con la futura anteprima admin): ThemeTokens,
  FONT_PRESETS, themeStyle(). Sanificazione a monte: colori solo esadecimali,
  raggio e larghezza clampati, font da whitelist, CSS custom con rimozione di
  </style, @import, expression(), javascript: e cap a 4000 char.
  Derivati: --focus-ring da accent (rgba), --primary-bg-hover per shading.
- recesso.server: tokenizzati anche font (--font) e larghezza (--card-max), che
  erano hardcoded; renderShell(inner, theme) inietta l'override; renderStep1..4
  accettano e propagano il tema.
- Settings: themeAccent/ButtonBg/ButtonText/Radius/Font/Width/CustomCss + migrazione.
- proxy: loadTheme(shop) in loader e action, propagato ai 22 punti di render.
  Nell'early-return senza sessione il tema e' null (non conosciamo lo shop).

fly.toml: min_machines_running resta 0 per scelta (TODO go-live, vedi
PROTECTED-CUSTOMER-DATA.md §5.2).
This commit is contained in:
2026-07-10 13:07:43 +02:00
parent 787553af22
commit d331e609a5
6 changed files with 229 additions and 34 deletions

View File

@@ -0,0 +1,8 @@
-- AlterTable
ALTER TABLE "Settings" ADD COLUMN "themeAccent" TEXT,
ADD COLUMN "themeButtonBg" TEXT,
ADD COLUMN "themeButtonText" TEXT,
ADD COLUMN "themeCustomCss" TEXT,
ADD COLUMN "themeFont" TEXT,
ADD COLUMN "themeRadius" INTEGER,
ADD COLUMN "themeWidth" INTEGER;