/* global React, ReactDOM, DemoContext, DemoModal, Header, Footer, HomePage, ServicesPage, AProposPage, ContactPage, useTweaks, TweaksPanel, TweakSection, TweakColor, TweakRadio, TweakSelect, TweakToggle */
const { useState, useEffect, useCallback, useRef } = React;

const ROUTES = {
  accueil: HomePage,
  services: ServicesPage,
  apropos: AProposPage,
  contact: ContactPage,
};
const HASH_TO_ROUTE = { "": "accueil", "/": "accueil", "/services": "services", "/a-propos": "apropos", "/contact": "contact" };

function parseHash() {
  const h = window.location.hash.replace(/^#/, "");
  return HASH_TO_ROUTE[h] || "accueil";
}

// ── Tweaks ───────────────────────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "azurvif",
  "typo": "technique",
  "nav": "discrète",
  "hero": "scindé",
  "heroBg": "signature",
  "heroShot": true,
  "reveals": true,
  "grain": true,
  "grainIntensity": 100
}/*EDITMODE-END*/;

// Typographie directions. Color themes and type are independent axes. Font vars
// MUST be applied at :root so the --text-* shorthand tokens (which bake in
// var(--font-display) at :root) recompute; the body.typo-* class only drives
// presentational treatment (mono eyebrows, italic neutralization) in CSS.
//   technique : Space Grotesk display + IBM Plex Mono accents (tech/security, default)
//   plex      : IBM Plex Sans throughout (sober enterprise/security)
//   edition   : original Spectral serif (editorial gravitas)
const FALLBACK_SANS = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif";
const TYPOS = {
  technique: {
    label: "Technique",
    vars: {
      "--font-display": `"Space Grotesk", "Inter", ${FALLBACK_SANS}`,
      "--font-sans": `"Inter", ${FALLBACK_SANS}`,
      "--font-mono": `"IBM Plex Mono", ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace`,
    },
  },
  plex: {
    label: "Plex",
    vars: {
      "--font-display": `"IBM Plex Sans", "Inter", ${FALLBACK_SANS}`,
      "--font-sans": `"IBM Plex Sans", "Inter", ${FALLBACK_SANS}`,
      "--font-mono": `"IBM Plex Mono", ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace`,
    },
  },
  edition: {
    label: "Édition",
    vars: {
      "--font-display": `"Spectral", "Iowan Old Style", Georgia, "Times New Roman", serif`,
      "--font-sans": `"Inter", ${FALLBACK_SANS}`,
      "--font-mono": `ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace`,
    },
  },
};
const TYPO_CLASSES = Object.keys(TYPOS).map((k) => "typo-" + k);
const TYPO_FONT_KEYS = [...new Set(Object.values(TYPOS).flatMap((ty) => Object.keys(ty.vars)))];

// Complete, pre-composed themes. Each retint the warm "paper" neutral ramp and
// the "brass" accent ramp cohesively (the rest of the design system cascades off
// these). `swatch` drives the picker chip; `dark` flips the page to ink-on-navy.
const THEMES = {
  ardoise: {
    label: "Ardoise",
    swatch: { bg: "#EDF0F3", accent: "#466782", ink: "#1E3349" },
    vars: {
      "--paper-0": "#FFFFFF", "--paper-50": "#F5F7F9", "--paper-100": "#EDF0F3",
      "--paper-200": "#E1E6EB", "--paper-300": "#D3DAE1", "--paper-400": "#BCC5CF",
      "--brass-700": "#2C4258", "--brass-600": "#38536C", "--brass-500": "#466782",
      "--brass-400": "#7C95AC", "--brass-200": "#CAD6E0", "--brass-100": "#E2E9EF", "--brass-50": "#EFF3F6",
      "--accent": "#466782", "--accent-hover": "#38536C", "--accent-foreground": "#FFFFFF", "--accent-tint": "#E2E9EF",
      "--ring": "color-mix(in oklab, #466782 42%, transparent)",
    },
  },
  robe: {
    label: "Robe",
    dark: true,
    swatch: { bg: "#10191F", accent: "#CBB47E", ink: "#ECEFF3" },
    vars: {
      "--paper-0": "#1B2832", "--paper-50": "#16222B", "--paper-100": "#10191F",
      "--paper-200": "#243441", "--paper-300": "#30414F", "--paper-400": "#415667",
      "--fg": "#ECEFF3", "--fg-muted": "#9FB2C2", "--fg-subtle": "#728698", "--fg-on-dark": "#ECEFF3",
      "--border": "#2B3B49", "--border-strong": "#3A4D5D", "--border-cool": "#2B3B49",
      "--primary": "#CBB47E", "--primary-hover": "#D7C290", "--primary-active": "#BBA269",
      "--primary-foreground": "#131D29", "--primary-tint": "#2E2718",
      "--brass-700": "#E2D4AD", "--brass-600": "#D7C290", "--brass-500": "#CBB47E", "--brass-400": "#C8B381",
      "--brass-200": "#463B22", "--brass-100": "#2E2718", "--brass-50": "#241F16",
      "--accent": "#CBB47E", "--accent-hover": "#D7C290", "--accent-foreground": "#131D29", "--accent-tint": "#2E2718",
      "--ring": "color-mix(in oklab, #CBB47E 40%, transparent)",
    },
  },
  // ── Variante orientée « souveraineté bleue » ─────────────────────────────
  //   Sceau — part d'Azur (bleu souverain) et y réintroduit l'or sur les
  //     détails (sceau, étoiles, badges) : actions/liens bleus, rampe brass dorée.
  // Azur — bleu souverain franc et frais, sur un sol profond.
  azur: {
    label: "Azur",
    dark: true,
    swatch: { bg: "#0C151E", accent: "#6BA6E4", ink: "#ECEFF3" },
    vars: {
      "--paper-0": "#172430", "--paper-50": "#111C26", "--paper-100": "#0C151E",
      "--paper-200": "#1E2D3B", "--paper-300": "#2B3C4B", "--paper-400": "#3C5163",
      "--fg": "#EAF1F8", "--fg-muted": "#9FB4C7", "--fg-subtle": "#70869B", "--fg-on-dark": "#EAF1F8",
      "--border": "#26384A", "--border-strong": "#35495D", "--border-cool": "#26384A",
      "--primary": "#6BA6E4", "--primary-hover": "#84B6EA", "--primary-active": "#5A96D8",
      "--primary-foreground": "#08131F", "--primary-tint": "#15273C",
      "--brass-700": "#A5C9EE", "--brass-600": "#84B6EA", "--brass-500": "#6BA6E4", "--brass-400": "#5A96D8",
      "--brass-200": "#1D3450", "--brass-100": "#15273C", "--brass-50": "#111F30",
      "--accent": "#6BA6E4", "--accent-hover": "#84B6EA", "--accent-foreground": "#08131F", "--accent-tint": "#15273C",
      "--ring": "color-mix(in oklab, #6BA6E4 45%, transparent)",
    },
  },
  // Sceau — Azur rehaussé de détails dorés : actions/liens restent bleus, la
  // rampe « brass » (sceau, étoiles, badges, pastilles) repasse à l'or antique.
  sceau: {
    label: "Sceau",
    dark: true,
    swatch: { bg: "#0C151E", accent: "#CBB47E", ink: "#EAF1F8" },
    vars: {
      "--paper-0": "#172430", "--paper-50": "#111C26", "--paper-100": "#0C151E",
      "--paper-200": "#1E2D3B", "--paper-300": "#2B3C4B", "--paper-400": "#3C5163",
      "--fg": "#EAF1F8", "--fg-muted": "#9FB4C7", "--fg-subtle": "#70869B", "--fg-on-dark": "#EAF1F8",
      "--border": "#26384A", "--border-strong": "#35495D", "--border-cool": "#26384A",
      "--primary": "#6BA6E4", "--primary-hover": "#84B6EA", "--primary-active": "#5A96D8",
      "--primary-foreground": "#08131F", "--primary-tint": "#15273C",
      "--brass-700": "#E2D4AD", "--brass-600": "#D7C290", "--brass-500": "#CBB47E", "--brass-400": "#C8B381",
      "--brass-200": "#3A3320", "--brass-100": "#2A2517", "--brass-50": "#221E13",
      "--accent": "#6BA6E4", "--accent-hover": "#84B6EA", "--accent-foreground": "#08131F", "--accent-tint": "#15273C",
      "--ring": "color-mix(in oklab, #6BA6E4 45%, transparent)",
    },
  },
  // ── Dérivés « bleu punchy » ───────────────────────────────────────────────
  // Même sol navy que Azur ; seul le bleu d'action change, pour comparer les
  // intensités à isopérimètre. Foreground blanc (les bleus saturés portent mal
  // l'encre sombre des boutons). Trois paliers : Vif (blue-500), Royal (blue-600),
  // Cobalt (bleu électrique lumineux), plus un Sceau Vif (action bleue + or).
  //
  // Azur Vif — bleu #3B82F6 (la référence demandée), franc et net.
  azurvif: {
    label: "Azur vif",
    dark: true,
    swatch: { bg: "#0C151E", accent: "#3B82F6", ink: "#EAF1F8" },
    vars: {
      "--paper-0": "#172430", "--paper-50": "#111C26", "--paper-100": "#0C151E",
      "--paper-200": "#1E2D3B", "--paper-300": "#2B3C4B", "--paper-400": "#3C5163",
      "--fg": "#EAF1F8", "--fg-muted": "#9FB4C7", "--fg-subtle": "#70869B", "--fg-on-dark": "#EAF1F8",
      "--border": "#26384A", "--border-strong": "#35495D", "--border-cool": "#26384A",
      "--primary": "#3B82F6", "--primary-hover": "#5E9AF8", "--primary-active": "#2D6FE0",
      "--primary-foreground": "#FFFFFF", "--primary-tint": "#14294A",
      "--brass-700": "#9BC2FC", "--brass-600": "#6FA4F9", "--brass-500": "#3B82F6", "--brass-400": "#2D6FE0",
      "--brass-200": "#16335A", "--brass-100": "#102541", "--brass-50": "#0C1D33",
      "--accent": "#3B82F6", "--accent-hover": "#5E9AF8", "--accent-foreground": "#FFFFFF", "--accent-tint": "#14294A",
      "--ring": "color-mix(in oklab, #3B82F6 48%, transparent)",
    },
  },
  // Royal — bleu #2563EB (blue-600), plus profond et institutionnel.
  royal: {
    label: "Royal",
    dark: true,
    swatch: { bg: "#0C151E", accent: "#2563EB", ink: "#EAF1F8" },
    vars: {
      "--paper-0": "#172430", "--paper-50": "#111C26", "--paper-100": "#0C151E",
      "--paper-200": "#1E2D3B", "--paper-300": "#2B3C4B", "--paper-400": "#3C5163",
      "--fg": "#EAF1F8", "--fg-muted": "#9FB4C7", "--fg-subtle": "#70869B", "--fg-on-dark": "#EAF1F8",
      "--border": "#26384A", "--border-strong": "#35495D", "--border-cool": "#26384A",
      "--primary": "#2563EB", "--primary-hover": "#4078EF", "--primary-active": "#1D52CC",
      "--primary-foreground": "#FFFFFF", "--primary-tint": "#122448",
      "--brass-700": "#8AAEF7", "--brass-600": "#5A8AF1", "--brass-500": "#2563EB", "--brass-400": "#1D52CC",
      "--brass-200": "#142A55", "--brass-100": "#0F2042", "--brass-50": "#0C1A36",
      "--accent": "#2563EB", "--accent-hover": "#4078EF", "--accent-foreground": "#FFFFFF", "--accent-tint": "#122448",
      "--ring": "color-mix(in oklab, #2563EB 48%, transparent)",
    },
  },
  // Cobalt — bleu #2E8FFF, électrique et lumineux (le plus « punchy »).
  cobalt: {
    label: "Cobalt",
    dark: true,
    swatch: { bg: "#0C151E", accent: "#2E8FFF", ink: "#EAF1F8" },
    vars: {
      "--paper-0": "#172430", "--paper-50": "#111C26", "--paper-100": "#0C151E",
      "--paper-200": "#1E2D3B", "--paper-300": "#2B3C4B", "--paper-400": "#3C5163",
      "--fg": "#EAF1F8", "--fg-muted": "#9FB4C7", "--fg-subtle": "#70869B", "--fg-on-dark": "#EAF1F8",
      "--border": "#26384A", "--border-strong": "#35495D", "--border-cool": "#26384A",
      "--primary": "#2E8FFF", "--primary-hover": "#57A6FF", "--primary-active": "#1B7CF0",
      "--primary-foreground": "#04111F", "--primary-tint": "#102C4E",
      "--brass-700": "#9ECBFF", "--brass-600": "#66ABFF", "--brass-500": "#2E8FFF", "--brass-400": "#1B7CF0",
      "--brass-200": "#103458", "--brass-100": "#0C2740", "--brass-50": "#0A1F33",
      "--accent": "#2E8FFF", "--accent-hover": "#57A6FF", "--accent-foreground": "#04111F", "--accent-tint": "#102C4E",
      "--ring": "color-mix(in oklab, #2E8FFF 50%, transparent)",
    },
  },
  // Sceau vif — action bleue #3B82F6, détails (sceau, étoiles, badges) en or antique.
  sceauvif: {
    label: "Sceau vif",
    dark: true,
    swatch: { bg: "#0C151E", accent: "#3B82F6", ink: "#EAF1F8" },
    vars: {
      "--paper-0": "#172430", "--paper-50": "#111C26", "--paper-100": "#0C151E",
      "--paper-200": "#1E2D3B", "--paper-300": "#2B3C4B", "--paper-400": "#3C5163",
      "--fg": "#EAF1F8", "--fg-muted": "#9FB4C7", "--fg-subtle": "#70869B", "--fg-on-dark": "#EAF1F8",
      "--border": "#26384A", "--border-strong": "#35495D", "--border-cool": "#26384A",
      "--primary": "#3B82F6", "--primary-hover": "#5E9AF8", "--primary-active": "#2D6FE0",
      "--primary-foreground": "#FFFFFF", "--primary-tint": "#14294A",
      "--brass-700": "#E2D4AD", "--brass-600": "#D7C290", "--brass-500": "#CBB47E", "--brass-400": "#C8B381",
      "--brass-200": "#3A3320", "--brass-100": "#2A2517", "--brass-50": "#221E13",
      "--accent": "#3B82F6", "--accent-hover": "#5E9AF8", "--accent-foreground": "#FFFFFF", "--accent-tint": "#14294A",
      "--ring": "color-mix(in oklab, #3B82F6 48%, transparent)",
    },
  },
};

// Union of every CSS var any theme touches — cleared before applying a theme so
// switching never leaves a stale override behind.
const THEME_KEYS = [...new Set(Object.values(THEMES).flatMap((th) => Object.keys(th.vars)))];

const HERO_CLASS = { "centré": "", "scindé": "hero-split", "éditorial": "hero-editorial" };

// Fonds de hero — traitements décoratifs, sobres et distinctement juridiques,
// posés en pleine largeur derrière le hero (voir site.css, body.herobg-*).
//   sobre       — aucun fond (canvas nu).
//   filigrane   — grand sceau Lexo en filigrane, brass, fondu hors-cadre.
//   guilloche   — gravure de sécurité (rosace guillochée, diplôme / billet).
//   quadrillage — trame de registre légal, hairline, fondue en vignette.
//   aurore      — halo souverain doux qui monte derrière le titre.
//   colonnade   — cannelures verticales (colonnes du palais de justice).
//   signature   — mix filigrane + aurore : halo souverain derrière le titre ET
//     sceau en filigrane sur le flanc. Le sceau se replace selon la disposition
//     (à droite en centré, à gauche en scindé) pour ne pas être caché par l'aperçu.
const HERO_BGS = ["sobre", "filigrane", "guilloche", "quadrillage", "aurore", "colonnade", "signature"];
const HERO_BG_CLASSES = HERO_BGS.map((k) => "herobg-" + k);

// Lexo seal as a tintable background-image. We bake the *theme's* brass into a
// data-URI SVG (rather than a fixed-gold file or a fragile CSS mask) so the
// filigrane/signature watermark follows the active theme and survives export.
const SEAL_PATH = "m 250,100 c -27.61424,0 -50,22.38576 -50,50 -1e-5,0.21922 -0.0176,0.45488 -0.0449,0.69727 a 50,50 0 0 1 -48.60547,49.21484 c -0.46755,0.0528 -0.92365,0.0878 -1.34961,0.0879 -27.61424,0 -50,22.38576 -50,50 0,27.61424 22.38576,50 50,50 a 50,50 0 0 1 49.9707,49.55078 C 199.99022,349.7087 200,349.85913 200,350 c 0,27.61424 22.38576,50 50,50 27.61424,0 50,-22.38576 50,-50 0,-27.61424 -22.38576,-50 -50,-50 -0.13264,-10e-6 -0.26758,-0.0111 -0.40234,-0.0273 A 50,50 0 0 1 200.04492,250.69922 C 200.01744,250.46641 200,250.23356 200,250 a 50,50 0 0 1 48.47656,-49.90039 c 0.53359,-0.0589 1.04796,-0.0996 1.52149,-0.0996 a 50,50 0 0 1 0.002,0 c 27.61424,0 50,-22.38576 50,-50 0,-27.61424 -22.38576,-50 -50,-50 z m 100,100 a 50,50 0 0 0 -50,50 50,50 0 0 0 50,50 50,50 0 0 0 50,-50 50,50 0 0 0 -50,-50 z";
function sealUrl(color) {
  const svg = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 300'><g transform='translate(-200,-100)'><path fill='${color}' d='${SEAL_PATH}' transform='translate(100)'/></g></svg>`;
  return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
}

const isDarkTheme = (t) => !!(THEMES[t] && THEMES[t].dark);
// The light theme the dark toggle returns to (defaults to Souverain).
const lightFallback = (t) => (isDarkTheme(t) ? "ardoise" : t);

function applyTheme(t) {
  const root = document.documentElement;
  // Clear every dynamic override first so switching never leaves a stale value behind.
  THEME_KEYS.forEach((k) => root.style.removeProperty(k));
  TYPO_FONT_KEYS.forEach((k) => root.style.removeProperty(k));

  // Theme (color) — retints the paper + brass ramps the rest of the system cascades off.
  const th = THEMES[t.theme] || THEMES.ardoise;
  Object.entries(th.vars).forEach(([k, v]) => root.style.setProperty(k, v));

  // Typography — applied at :root so the --text-* shorthand tokens recompute.
  const ty = TYPOS[t.typo] || TYPOS.technique;
  Object.entries(ty.vars).forEach(([k, v]) => root.style.setProperty(k, v));

  // Tint the hero seal with the theme's brass (now that the ramp is applied).
  const brass = getComputedStyle(root).getPropertyValue("--brass-500").trim() || "#9A7B43";
  root.style.setProperty("--seal-url", sealUrl(brass));

  // Body classes. `theme-tech` carries a discreet engineering treatment for any
  // tech-leaning theme — see site.css.
  document.body.classList.toggle("dark", !!th.dark);
  document.body.classList.toggle("theme-tech", !!th.tech);
  TYPO_CLASSES.forEach((c) => document.body.classList.remove(c));
  document.body.classList.add("typo-" + (TYPOS[t.typo] ? t.typo : "technique"));
  document.body.classList.toggle("nav-strong", t.nav === "marquée");
  document.body.classList.remove("hero-split", "hero-editorial");
  const hc = HERO_CLASS[t.hero];
  if (hc) document.body.classList.add(hc);
  HERO_BG_CLASSES.forEach((c) => document.body.classList.remove(c));
  document.body.classList.add("herobg-" + (HERO_BGS.includes(t.heroBg) ? t.heroBg : "sobre"));
  document.body.classList.toggle("no-reveal", !t.reveals);
  document.body.classList.toggle("grain-off", !t.grain);
  root.style.setProperty("--grain-i", String((t.grainIntensity ?? 100) / 100));
}

// Bouton flottant discret (bas-gauche) : ouvre/ferme le panneau Tweaks
// directement dans le site, sans dépendre de la barre d'outils de l'hôte. Il
// pilote le même protocole de messages que TweaksPanel (__activate_edit_mode /
// __deactivate_edit_mode) et reste donc synchronisé avec la bascule de l'hôte.
function TweaksFab() {
  const [open, setOpen] = useState(false);
  useEffect(() => {
    const onMsg = (e) => {
      const ty = e && e.data && e.data.type;
      if (ty === "__activate_edit_mode") setOpen(true);
      else if (ty === "__deactivate_edit_mode") setOpen(false);
    };
    window.addEventListener("message", onMsg);
    return () => window.removeEventListener("message", onMsg);
  }, []);
  const toggle = () =>
    window.postMessage({ type: open ? "__deactivate_edit_mode" : "__activate_edit_mode" }, "*");
  return (
    <button type="button" onClick={toggle} aria-label="Réglages d'affichage"
      aria-pressed={open} title="Réglages d'affichage" data-omelette-chrome=""
      style={{
        position: "fixed", left: 16, bottom: 16, zIndex: 2147483645,
        width: 38, height: 38, display: "grid", placeItems: "center",
        appearance: "none", cursor: "pointer", borderRadius: "var(--radius-full, 999px)",
        border: "1px solid var(--border, rgba(0,0,0,.12))",
        background: open ? "var(--primary, #1E3349)" : "color-mix(in oklab, var(--paper-0, #fff) 86%, transparent)",
        color: open ? "var(--primary-foreground, #fff)" : "var(--fg-muted, #5b6b7a)",
        WebkitBackdropFilter: "blur(8px)", backdropFilter: "blur(8px)",
        boxShadow: "var(--shadow-sm, 0 1px 2px rgba(19,29,41,.08))",
        transition: "background .15s, color .15s, box-shadow .15s, opacity .15s",
        opacity: 0.82,
      }}
      onMouseEnter={(e) => { e.currentTarget.style.opacity = "1"; }}
      onMouseLeave={(e) => { e.currentTarget.style.opacity = "0.82"; }}>
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none"
        stroke="currentColor" strokeWidth="1.85" strokeLinecap="round" strokeLinejoin="round">
        <line x1="4" y1="7" x2="20" y2="7" /><circle cx="9" cy="7" r="2.5" fill="currentColor" />
        <line x1="4" y1="17" x2="20" y2="17" /><circle cx="15" cy="17" r="2.5" fill="currentColor" />
      </svg>
    </button>
  );
}

// Theme picker — swatch chips (canvas + accent) rather than a flat dropdown.
function ThemePicker({ value, onChange }) {
  return (
    <TweakRow label="Thème">
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
        {Object.entries(THEMES).map(([key, th]) => {
          const on = key === value;
          return (
            <button key={key} type="button" onClick={() => onChange(key)}
              style={{
                position: "relative", appearance: "none", cursor: "default",
                display: "flex", alignItems: "center", gap: 8,
                padding: "8px 10px", borderRadius: 8, border: 0,
                background: th.swatch.bg,
                boxShadow: on
                  ? `0 0 0 2px ${th.swatch.accent}, 0 2px 7px rgba(0,0,0,.18)`
                  : "0 0 0 .5px rgba(0,0,0,.18), 0 1px 2px rgba(0,0,0,.08)",
                transition: "box-shadow .12s",
              }}>
              <span style={{
                width: 15, height: 15, borderRadius: "50%", flex: "none",
                background: th.swatch.accent, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.12)",
              }} />
              <span style={{
                font: "600 11.5px/1.2 var(--font-display, Georgia, serif)",
                color: th.swatch.ink, letterSpacing: ".01em",
              }}>{th.label}</span>
            </button>
          );
        })}
      </div>
    </TweakRow>
  );
}

function App() {
  const [route, setRoute] = useState(parseHash);
  const [demoOpen, setDemoOpen] = useState(false);
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Routing
  useEffect(() => {
    const on = () => { setRoute(parseHash()); window.scrollTo(0, 0); };
    window.addEventListener("hashchange", on);
    return () => window.removeEventListener("hashchange", on);
  }, []);

  // Theme / tweaks
  useEffect(() => { applyTheme(t); }, [t.theme, t.typo, t.nav, t.hero, t.heroBg, t.reveals, t.grain, t.grainIntensity]);

  // Reveal-on-scroll: re-observe after each route render
  useEffect(() => {
    const els = document.querySelectorAll(".reveal:not(.visible)");
    if (document.body.classList.contains("no-reveal")) {
      els.forEach((el) => el.classList.add("visible"));
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("visible"); io.unobserve(e.target); } });
    }, { threshold: 0.1, rootMargin: "0px 0px -40px 0px" });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, [route, t.reveals]);

  // Redraw lucide icons after route change (new DOM)
  useEffect(() => { if (window.lucide) { try { window.lucide.createIcons({ nameAttr: "data-lucide" }); } catch (e) {} } }, [route, demoOpen]);

  const openDemo = useCallback(() => setDemoOpen(true), []);
  const closeDemo = useCallback(() => setDemoOpen(false), []);
  const Page = ROUTES[route] || HomePage;

  return (
    <DemoContext.Provider value={openDemo}>
      <Header route={route} />
      <Page hero={t.hero} heroShot={t.heroShot} />
      <Footer />
      {demoOpen && <DemoModal onClose={closeDemo} />}
      <TweaksPanel title="Tweaks">
        <TweakSection label="Identité" />
        <ThemePicker value={t.theme} onChange={(v) => setTweak("theme", v)} />
        <TweakSection label="Mise en page" />
        <TweakRadio label="Barre de nav" value={t.nav} options={["discrète", "marquée"]} onChange={(v) => setTweak("nav", v)} />
        <TweakRadio label="Disposition du hero" value={t.hero} options={["centré", "scindé"]} onChange={(v) => setTweak("hero", v)} />
        <TweakSelect label="Fond du hero" value={t.heroBg} options={[{ value: "sobre", label: "Sobre (aucun)" }, { value: "signature", label: "Filigrane + Aurore ★" }, { value: "filigrane", label: "Filigrane — sceau" }, { value: "aurore", label: "Aurore — halo" }, { value: "guilloche", label: "Guilloché — gravure" }, { value: "quadrillage", label: "Quadrillage — registre" }, { value: "colonnade", label: "Colonnade — cannelures" }]} onChange={(v) => setTweak("heroBg", v)} />
        <TweakToggle label="Aperçu produit dans le hero" value={t.heroShot} onChange={(v) => setTweak("heroShot", v)} />
        <TweakToggle label="Animations au défilement" value={t.reveals} onChange={(v) => setTweak("reveals", v)} />
        <TweakToggle label="Grain (texture de fond)" value={t.grain} onChange={(v) => setTweak("grain", v)} />
        {t.grain && <TweakSlider label="Intensité du grain" value={t.grainIntensity} min={0} max={200} step={10} unit="%" onChange={(v) => setTweak("grainIntensity", v)} />}
      </TweaksPanel>
      {/* <TweaksFab /> */}
    </DemoContext.Provider>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
