// charte-tabs-3.jsx
// Final tabs: Templates (3 example pages) + Tokens (theme.json + CSS)
// Plus the main App shell with sidebar nav and Tweaks panel.

const { useState: __useState } = React;

/* ---------- Tab: Templates (3 example pages) ---------- */
function TabTemplates({ tweaks }) {
  const [active, setActive] = __useState("primaire");
  const density = tweaks.density;
  const qrVisible = tweaks.qrVisible;
  const scoreVisible = tweaks.scoreVisible;

  const templates = [
    { id: "primaire", label: "Primaire · Français CM2", pageEl: <PrimaireFrancais density={density} qrVisible={qrVisible} scoreVisible={scoreVisible} /> },
    { id: "college",  label: "Collège · Maths 4ᵉ",      pageEl: <CollegeMaths    density={density} qrVisible={qrVisible} scoreVisible={scoreVisible} /> },
    { id: "lycee",    label: "Lycée · SVT 1ʳᵉ",           pageEl: <LyceeSVT        density={density} qrVisible={qrVisible} scoreVisible={scoreVisible} /> },
  ];

  return (
    <>
      <section className="section" style={{ marginTop: 0 }}>
        <h2>Templates de référence</h2>
        <p className="section-sub">
          Trois pages produites avec le système, à l'échelle réelle 8.5×11 (vue à 65%).
          Mêmes header / footer, mêmes composants, identité partagée — seul le centre de page change.
        </p>

        <div className="tpl-tabs">
          {templates.map(t => (
            <button key={t.id} className={active === t.id ? "active" : ""} onClick={() => setActive(t.id)}>
              {t.label}
            </button>
          ))}
        </div>

        <div className="page-preview" style={{ background: "var(--ae-bg-cool)", padding: "30px 0", borderRadius: 14, border: "1px solid var(--ae-border)" }}>
          <div style={{ width: `calc(8.5in * 0.7)`, height: `calc(11in * 0.7)`, position: "relative", overflow: "hidden", boxShadow: "0 12px 40px rgba(15,26,61,.18)" }}>
            {React.cloneElement(templates.find(t => t.id === active).pageEl, { scale: 0.7 })}
          </div>
        </div>
      </section>

      <section className="section">
        <h2>Comment lire ces templates</h2>
        <div className="info-grid">
          <div className="info-chip"><div className="lbl">Identique partout</div><div className="desc">Header, footer, marges, grille, typo, palette.</div></div>
          <div className="info-chip"><div className="lbl">Variable par page</div><div className="desc">Matière, niveau, page, contenu central, présence Ketty.</div></div>
          <div className="info-chip"><div className="lbl">Variable par niveau</div><div className="desc">Densité, taille de texte, place des illustrations.</div></div>
          <div className="info-chip"><div className="lbl">Pilotable depuis Tweaks</div><div className="desc">Densité, QR / score visible, niveau, primaire color, typo.</div></div>
        </div>
      </section>
    </>
  );
}

/* ---------- Tab: Tokens ---------- */
const themeJsonString = `{
  "$schema": "./allo-education.schema.json",
  "brand": "Allo Education",
  "edition": "Éditions Allo Education",
  "format": { "width": "8.5in", "height": "11in", "dpi": 300, "kdp": true },

  "level": "college",
  "density": "standard",
  "fontPair": "fredoka-nunito",

  "colors": {
    "primary":      "#1B3FB8",
    "primaryDark":  "#102A85",
    "primaryDeep":  "#0B1F66",
    "primarySoft":  "#E8EEFB",
    "secondary":    "#F5781C",
    "secondaryDark":"#D85F0A",
    "accent":       "#FFC533",
    "accentSoft":   "#FFF6D6",
    "success":      "#1F9E5A",
    "successSoft":  "#E2F4EA",
    "warning":      "#E6A82B",
    "error":        "#D62E2E",
    "errorSoft":    "#FCE7E7",
    "background":   "#FFFFFF",
    "backgroundAlt":"#FBF8F1",
    "text":         "#0F1A3D",
    "textSoft":     "#2B3656",
    "muted":        "#6A748F",
    "border":       "#D8DEEC",
    "rule":         "#C4CCDF"
  },

  "typography": {
    "title": { "family": "Fredoka",     "weights": [500, 600, 700] },
    "body":  { "family": "Nunito Sans", "weights": [400, 600, 700, 800] },
    "mono":  { "family": "JetBrains Mono", "fallback": "Arial, Noto Sans Math" },
    "scale": {
      "displayCover": "0.9in",
      "h1":           "0.36in",
      "h2":           "0.22in",
      "h3":           "0.18in",
      "consigne":     "0.15in",
      "body":         "0.13in",
      "bodyMin":      "0.12in",
      "eyebrow":      "0.10in"
    }
  },

  "grid": {
    "marginSide":   "0.55in",
    "marginTop":    "0.5in",
    "marginBottom": "0.5in",
    "headerHeight": "0.95in",
    "footerHeight": "0.85in",
    "columns":      6,
    "gutter":       "0.18in",
    "baseline":     "0.21in",
    "bleed":        "0.125in"
  },

  "header": {
    "background":  "primary",
    "logoColor":   ["#FFFFFF", "secondary"],
    "matierePill": { "border": "rgba(255,255,255,.45)", "color": "#FFFFFF" },
    "pageBadge":   { "background": "accent", "color": "primaryDeep" },
    "doodles":     true
  },

  "footer": {
    "score":  { "visible": true, "border": "primary", "style": "dashed" },
    "qr":     { "visible": true, "discColor": "primary", "label": "Corriger avec Ketty", "url": "alloeducation.fr" },
    "page":   { "background": "primary", "color": "#FFFFFF" }
  },

  "components": {
    "lessonCard":  { "tone": "yellow",  "tabPosition": "top-left" },
    "method":      { "tone": "green",   "label": "Méthode" },
    "pitfall":     { "tone": "red",     "label": "Erreur à éviter" },
    "exercice":    { "tone": "primary", "tabStyle": "halfPill" },
    "qcm":         { "tone": "secondary","letterStyle": "boxed" },
    "kettyBubble": { "border": "primary", "labelStyle": "filled-pill" },
    "qrBlock":     { "tone": "yellow",  "minSize": "0.6in" },
    "bilan":       { "tone": "yellow-orange-gradient" },
    "defi":        { "tone": "secondary", "border": "dashed" }
  },

  "density": {
    "air":      { "blockGap": "0.26in", "lineHeight": 1.6,  "answerBoxHeight": "0.84in" },
    "standard": { "blockGap": "0.20in", "lineHeight": 1.5,  "answerBoxHeight": "0.6in"  },
    "dense":    { "blockGap": "0.14in", "lineHeight": 1.45, "answerBoxHeight": "0.5in"  }
  },

  "levelOverrides": {
    "cp":    { "density": "air",       "bodySize": "0.16in", "kettyPerPage": 2 },
    "ce":    { "density": "air",       "bodySize": "0.14in", "kettyPerPage": 1 },
    "6e":    { "density": "standard",  "bodySize": "0.14in", "kettyPerPage": 1 },
    "4e":    { "density": "standard",  "bodySize": "0.13in", "kettyPerPage": 1 },
    "lycee": { "density": "dense",     "bodySize": "0.13in", "kettyPerPage": 0 }
  },

  "ketty": {
    "asset": "img/ketty/{pose}.png",
    "poses": ["hello", "pointing", "thinking", "celebrating", "thumbsup"],
    "maxPerPage": 2,
    "defaultWidth": "0.85in"
  },

  "qr": {
    "factoryUrl": "https://qr.alloeducation.fr/{slug}",
    "minPrintSize": "0.6in",
    "quietZone": "0.06in",
    "darkColor": "#0F1A3D",
    "lightColor": "#FFFFFF"
  },

  "i18n": { "locale": "fr-FR", "decimalSeparator": "," }
}`;

const cssVarsString = `:root {
  /* Brand */
  --ae-primary:        #1B3FB8;
  --ae-primary-dark:   #102A85;
  --ae-primary-deep:   #0B1F66;
  --ae-primary-soft:   #E8EEFB;
  --ae-orange:         #F5781C;
  --ae-orange-dark:    #D85F0A;
  --ae-orange-soft:    #FFEEDC;
  --ae-yellow:         #FFC533;
  --ae-yellow-dark:    #E6A82B;
  --ae-yellow-soft:    #FFF6D6;
  --ae-pink:           #E91E78; /* couverture only */

  /* Sémantiques */
  --ae-success:        #1F9E5A;
  --ae-success-soft:   #E2F4EA;
  --ae-warning:        #E6A82B;
  --ae-error:          #D62E2E;
  --ae-error-soft:     #FCE7E7;

  /* Neutres */
  --ae-bg:             #FFFFFF;
  --ae-bg-cream:       #FBF8F1;
  --ae-bg-cool:        #F6F8FC;
  --ae-text:           #0F1A3D;
  --ae-text-soft:      #2B3656;
  --ae-muted:          #6A748F;
  --ae-border:         #D8DEEC;

  /* Typographie */
  --ae-font-title:  "Fredoka", system-ui, sans-serif;
  --ae-font-body:   "Nunito Sans", system-ui, sans-serif;
  --ae-font-mono:   "JetBrains Mono", "Arial", monospace;

  /* Grille 8.5 × 11 */
  --ae-page-w:        8.5in;
  --ae-page-h:        11in;
  --ae-margin-side:   0.55in;
  --ae-margin-top:    0.5in;
  --ae-margin-bottom: 0.5in;
  --ae-header-h:      0.95in;
  --ae-footer-h:      0.85in;

  /* Density (override par .density-air | .density-std | .density-dense) */
  --ae-block-gap:     0.20in;
  --ae-density-y:     0.18in;
}`;

function colorize(json) {
  // Light syntax tinting for pretty display (JSON)
  return json
    .replace(/("[^"]+")\s*:/g, '<span class="k">$1</span>:')
    .replace(/:\s*("[^"]+")/g, ': <span class="s">$1</span>')
    .replace(/:\s*(true|false|null)/g, ': <span class="n">$1</span>')
    .replace(/:\s*(-?\d+(\.\d+)?)/g, ': <span class="n">$1</span>');
}

function TabTokens() {
  return (
    <>
      <section className="section" style={{ marginTop: 0 }}>
        <h2>theme.json</h2>
        <p className="section-sub">
          Schéma central de la collection. Tout fichier de cahier (Maths-CM2, SVT-1re…) hérite
          de ce thème de base et y applique des overrides précis (matière, niveau, palette par matière éventuelle).
        </p>
        <pre className="code" dangerouslySetInnerHTML={{ __html: colorize(themeJsonString) }} />
      </section>

      <section className="section">
        <h2>Variables CSS</h2>
        <p className="section-sub">
          Le développeur peut consommer ces tokens directement dans les templates HTML / SCSS.
          Tous les composants de la charte référencent ces variables — changer une valeur ici
          la propage à <b>toute la collection</b>.
        </p>
        <pre className="code" style={{ background: "#0F1A3D" }}>{cssVarsString}</pre>
      </section>

      <section className="section">
        <h2>Override d'un cahier (exemple)</h2>
        <p className="section-sub">Configuration minimale pour générer le cahier <b>Maths · 4ᵉ</b> à partir du thème de base :</p>
        <pre className="code">{`{
  "extends": "./theme.json",
  "title": "Mon cahier de Maths",
  "matiere": "Maths",
  "niveau": "4ᵉ",
  "level": "4e",
  "density": "standard",
  "header": { "page": "Bloc {block} · Page {n}" },
  "ketty": { "maxPerPage": 1 },
  "qr": { "slug": "maths-4e/{block}-{page}" }
}`}</pre>
      </section>

      <section className="section">
        <h2>Tableau récapitulatif</h2>
        <table className="token-table">
          <thead><tr><th>Token</th><th>Valeur</th><th>Rôle</th></tr></thead>
          <tbody>
            {[
              ["--ae-primary",     "#1B3FB8", "Bleu Allo Education — header, primary actions"],
              ["--ae-orange",      "#F5781C", "Énergie — QCM, défis, mise en exergue"],
              ["--ae-yellow",      "#FFC533", "Accent — leçon, je retiens, badges"],
              ["--ae-success",     "#1F9E5A", "Méthode, validation, corrigé"],
              ["--ae-error",       "#D62E2E", "Erreur à éviter, piège"],
              ["--ae-text",        "#0F1A3D", "Texte courant, titres en bleu deep"],
              ["--ae-muted",       "#6A748F", "Métadonnées, légendes"],
              ["--ae-border",      "#D8DEEC", "Bordures de cartes neutres"],
              ["--ae-page-w",      "8.5in",   "Largeur page (KDP)"],
              ["--ae-page-h",      "11in",    "Hauteur page"],
              ["--ae-header-h",    "0.95in",  "Hauteur header"],
              ["--ae-footer-h",    "0.85in",  "Hauteur footer"],
              ["--ae-margin-side", "0.55in",  "Marge latérale (+0.125in côté reliure)"],
            ].map(([t, v, r]) => (
              <tr key={t}><td className="tk">{t}</td><td className="val">{v}</td><td>{r}</td></tr>
            ))}
          </tbody>
        </table>
      </section>
    </>
  );
}

/* =========================================================================
   App shell with sidebar + Tweaks panel
   ========================================================================= */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "primaryHue": "#1B3FB8",
  "level": "college",
  "density": "std",
  "qrVisible": true,
  "scoreVisible": true,
  "fontPair": "fredoka-nunito"
}/*EDITMODE-END*/;

const PRIMARY_PALETTES = [
  "#1B3FB8",  // Bleu Allo Education (officiel)
  "#0E7C66",  // Variante verte (cahier sciences)
  "#9F1239",  // Variante bordeaux (cahier histoire)
  "#5B21B6",  // Variante violette (cahier philo)
];

const FONT_PAIRS = {
  "fredoka-nunito": { title: "Fredoka", body: "Nunito Sans" },
  "plus-jakarta":   { title: "Plus Jakarta Sans", body: "Plus Jakarta Sans" },
  "lora-nunito":    { title: "Lora", body: "Nunito Sans" },
};

function App() {
  const [tab, setTab] = __useState("overview");
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Apply primary color override across the whole app
  React.useEffect(() => {
    document.documentElement.style.setProperty("--ae-primary", t.primaryHue);
    // derive a dark version
    const dark = darken(t.primaryHue, 0.18);
    const deep = darken(t.primaryHue, 0.36);
    const soft = lighten(t.primaryHue, 0.85);
    document.documentElement.style.setProperty("--ae-primary-dark", dark);
    document.documentElement.style.setProperty("--ae-primary-deep", deep);
    document.documentElement.style.setProperty("--ae-primary-soft", soft);
  }, [t.primaryHue]);

  React.useEffect(() => {
    const pair = FONT_PAIRS[t.fontPair] || FONT_PAIRS["fredoka-nunito"];
    document.documentElement.style.setProperty("--ae-font-title", `"${pair.title}", system-ui, sans-serif`);
    document.documentElement.style.setProperty("--ae-font-body",  `"${pair.body}", system-ui, sans-serif`);
  }, [t.fontPair]);

  const tabs = [
    { id: "overview",   num: "00", label: "Vue d'ensemble",    section: "Marque" },
    { id: "colors",     num: "01", label: "Couleurs",          section: "Marque" },
    { id: "typography", num: "02", label: "Typographie",       section: "Marque" },
    { id: "grid",       num: "03", label: "Grille 8.5×11",      section: "Système" },
    { id: "header",     num: "04", label: "Header / Footer",   section: "Système" },
    { id: "components", num: "05", label: "Composants",        section: "Système" },
    { id: "ketty",      num: "06", label: "Ketty",             section: "Système" },
    { id: "levels",     num: "07", label: "Variantes niveau",  section: "Règles" },
    { id: "dodont",     num: "08", label: "Do / Don't",        section: "Règles" },
    { id: "templates",  num: "09", label: "Templates",         section: "Production" },
    { id: "stress",     num: "10", label: "Stress test (10)",  section: "Production" },
    { id: "pack1",      num: "11", label: "Pack 1 · Universel",section: "Production" },
    { id: "pack2",      num: "12", label: "Pack 2 · FR / Langues", section: "Production" },
    { id: "mathsbrevet",num: "13", label: "Maths Brevet",      section: "Production" },
    { id: "pack3",      num: "14", label: "Pack 3 · HG / Sciences", section: "Production" },
    { id: "pack4",      num: "15", label: "Pack 4 · Jeux éducatifs", section: "Production" },
    { id: "pack5",      num: "16", label: "Pack 5 · Primaire",  section: "Production" },
    { id: "pack6",      num: "17", label: "Pack 6 · Fin de livre", section: "Production" },
    { id: "pack7",      num: "18", label: "Pack 7 · Patterns",  section: "Production" },
    { id: "composition", num: "19", label: "Règles de composition", section: "Charte" },
    { id: "tokens",     num: "20", label: "Tokens",            section: "Production" },
  ];

  const currentTab = tabs.find(x => x.id === tab) || tabs[0];

  // Group sidebar
  const sections = [];
  tabs.forEach(t => {
    let g = sections.find(s => s.label === t.section);
    if (!g) { g = { label: t.section, items: [] }; sections.push(g); }
    g.items.push(t);
  });

  return (
    <div className="app-shell">
      <aside className="sidebar">
        <div className="sidebar-brand">
          <div className="logo-mark">
            <svg viewBox="0 0 64 64">
              <path d="M32 10 L58 22 L32 34 L6 22 Z" fill="var(--ae-primary)"/>
              <path d="M14 26 L14 38 Q14 46 32 46 Q50 46 50 38 L50 26" fill="none" stroke="var(--ae-primary)" strokeWidth="3" strokeLinecap="round"/>
              <circle cx="56" cy="26" r="2.2" fill="var(--ae-orange)"/>
              <path d="M56 28 L56 36" stroke="var(--ae-orange)" strokeWidth="2" strokeLinecap="round"/>
            </svg>
          </div>
          <div className="logo-text">
            <span className="l1">Allo</span>
            <span className="l2">Education</span>
            <span className="l3">Charte v1.2 · verrouillée</span>
          </div>
        </div>

        {sections.map(sec => (
          <div className="nav" key={sec.label}>
            <div className="nav-section">{sec.label}</div>
            {sec.items.map(it => (
              <button key={it.id} className={tab === it.id ? "active" : ""} onClick={() => { setTab(it.id); window.scrollTo({ top: 0 }); }}>
                <span className="num">{it.num}</span> {it.label}
              </button>
            ))}
          </div>
        ))}

        <div className="sidebar-meta">
          <div className="pill">Print · KDP</div>
          <div>Format 8.5 × 11 in · 300 dpi · CMJN ready.</div>
          <div style={{ marginTop: 8 }}>Référence interne :<br/><code style={{ color: "white" }}>allo-education-books · v1.2</code></div>
        </div>
      </aside>

      <main className="main">
        <header className="main-header">
          <div>
            <div className="eyebrow">{currentTab.num} · {currentTab.section}</div>
            <h1>{currentTab.label}</h1>
            <p className="lede">
              {{
                overview:   "La carte d'identité de la collection Allo Education — du CP à la Terminale, multi-matières, imprimable KDP.",
                colors:     "Bleu profond, orange énergie, jaune accent. Une palette systémique, des règles claires, une identité reconnaissable.",
                typography: "Fredoka pour la chaleur des titres, Nunito Sans pour le confort de lecture en print. Une échelle calée en pouces.",
                grid:       "Toutes les pages partent de la même grille 8.5 × 11 in, 6 colonnes, marges fixes — l'ossature commune de la collection.",
                header:     "Le shell que toutes les pages partagent. On change les données, jamais la structure.",
                components: "Les briques pédagogiques réutilisables : leçon, méthode, exercice, QCM, Ketty, QR, bilan…",
                ketty:      "La coach pédagogique 3D de la collection. Toujours utile, jamais décorative.",
                levels:     "Le même système se décline en cinq niveaux d'intensité, du plus illustré au plus académique.",
                dodont:     "Cas concrets pour calibrer hiérarchie, alignements, couleurs, zones de réponse et présence de Ketty.",
                templates:  "Trois pages réelles produites avec le système, à l'échelle 8.5 × 11 in.",
                stress:     "10 pages de stress test du CP à la Terminale, construites uniquement avec les blocs verrouillés.",
                pack1:      "Pack 1 · 10 templates universels prêts pour la production : les patterns les plus utilisés de la collection.",
                pack2:      "Pack 2 · 10 templates pour le texte : vocabulaire, conjugaison, grammaire, lecture, dictée, écriture, dialogue, traduction.",
                mathsbrevet:"Maths Brevet · 15 templates pour générer les 100 pages d'Objectif Brevet Maths 3e (calculs, équations, fonctions, géométrie, brevets blancs, corrections).",
                pack3:      "Pack 3 · 10 templates pour les pages visuelles complexes — frises, cartes, schémas, protocoles, documents et tableaux scientifiques.",
                pack4:      "Pack 4 · 12 templates de jeux éducatifs universels — mots croisés, mots mêlés, code secret, intrus, V/F, relier, ordre, labyrinthe, coloriage magique, pixel art, memory, énigmes.",
                pack5:      "Pack 5 · 12 templates primaire CP / CE1 / CE2 — sons, lecture, compréhension, écriture, dictée, calcul mental, calcul posé, problèmes, numération, géométrie, fiche du jour, modèle prof / parent.",
                pack7:      "Pack 7 · Planche design — 18 blocs autorisés documentés visuellement (standard + compact), 5 compositions recommandées, 5 à éviter, règles d'espacement. Référence partagée rédacteur / dev / auditeur PDF.",
                composition: "Charte d'espacement v1.3 — anatomie de page + de bloc, hiérarchie des gaps (intra / sm / md / lg / section), 3 densités, blocs majeurs vs mineurs, exemples bon/mauvais, règles anti-overflow, 11 tokens officiels.",
                pack6:      "Pack 6 · 12 templates de fin de livre — diplôme, bilan, hub QR, suite collection, défi bonus, brouillon, carnet d'erreurs, planning, mentions légales, couverture intérieure, ouverture de chapitre.",
                tokens:     "Le contrat développeur : theme.json + variables CSS pour générer les 50+ templates de manière cohérente.",
              }[tab]}
            </p>
          </div>
          <div className="step-pill">
            <span className="dot"></span>
            {currentTab.num === "00" ? "Commence ici" : `Étape ${parseInt(currentTab.num,10)} / ${tabs.length - 1}`}
          </div>
        </header>

        {tab === "overview"   && <TabOverview />}
        {tab === "colors"     && <TabColors />}
        {tab === "typography" && <TabTypography />}
        {tab === "grid"       && <TabGrid />}
        {tab === "header"     && <TabHeaderFooter />}
        {tab === "components" && <TabComponents />}
        {tab === "ketty"      && <TabKetty />}
        {tab === "levels"     && <TabLevels />}
        {tab === "dodont"     && <TabDoDont />}
        {tab === "templates"  && <TabTemplates tweaks={t} />}
        {tab === "stress"     && <TabStressTest tweaks={t} />}
        {tab === "pack1"      && <TabPack1Universal tweaks={t} />}
        {tab === "pack2"      && <TabPack2FrancaisLangues tweaks={t} />}
        {tab === "mathsbrevet"&& <TabMathsBrevet tweaks={t} />}
        {tab === "pack3"      && <TabPack3HGSciences tweaks={t} />}
        {tab === "pack4"      && <TabPack4JeuxEducatifs tweaks={t} />}
        {tab === "pack5"      && <TabPack5Primaire tweaks={t} />}
        {tab === "pack6"      && <TabPack6FinLivre tweaks={t} />}
        {tab === "pack7"      && <TabPack7Patterns tweaks={t} />}
        {tab === "composition" && <TabComposition />}
        {tab === "tokens"     && <TabTokens />}
      </main>

      <TweaksPanel title="Tweaks · Charte">
        <TweakSection label="Identité" />
        <TweakColor
          label="Primary"
          value={t.primaryHue}
          options={PRIMARY_PALETTES}
          onChange={v => setTweak("primaryHue", v)}
        />
        <TweakSelect
          label="Pair typographique"
          value={t.fontPair}
          options={[
            { value: "fredoka-nunito", label: "Fredoka × Nunito Sans (officiel)" },
            { value: "plus-jakarta",   label: "Plus Jakarta (mono-sans alt)" },
            { value: "lora-nunito",    label: "Lora × Nunito Sans (manuel)" },
          ]}
          onChange={v => setTweak("fontPair", v)}
        />

        <TweakSection label="Variantes" />
        <TweakSelect
          label="Niveau (preview templates)"
          value={t.level}
          options={[
            { value: "cp",      label: "CP / CE1" },
            { value: "ce",      label: "CE2 / CM" },
            { value: "college", label: "6ᵉ / 5ᵉ" },
            { value: "3e",      label: "4ᵉ / 3ᵉ" },
            { value: "lycee",   label: "Lycée" },
          ]}
          onChange={v => setTweak("level", v)}
        />
        <TweakRadio
          label="Densité"
          value={t.density}
          options={[
            { value: "light", label: "Light" },
            { value: "std",   label: "Standard" },
            { value: "dense", label: "Dense" },
          ]}
          onChange={v => setTweak("density", v)}
        />

        <TweakSection label="Footer" />
        <TweakToggle label="QR visible"    value={t.qrVisible}    onChange={v => setTweak("qrVisible", v)} />
        <TweakToggle label="Score visible" value={t.scoreVisible} onChange={v => setTweak("scoreVisible", v)} />
      </TweaksPanel>
    </div>
  );
}

/* ---------- color helpers ---------- */
function hexToRgb(hex) {
  const h = hex.replace("#", "");
  return [parseInt(h.slice(0,2),16), parseInt(h.slice(2,4),16), parseInt(h.slice(4,6),16)];
}
function rgbToHex(r,g,b) {
  return "#" + [r,g,b].map(v => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2,"0")).join("");
}
function darken(hex, amount) {
  const [r,g,b] = hexToRgb(hex);
  return rgbToHex(r * (1 - amount), g * (1 - amount), b * (1 - amount));
}
function lighten(hex, amount) {
  const [r,g,b] = hexToRgb(hex);
  return rgbToHex(r + (255 - r) * amount, g + (255 - g) * amount, b + (255 - b) * amount);
}

Object.assign(window, { App, TabTemplates, TabTokens });
