// template-pack-7-design-patterns.jsx
// PACK 7 · DESIGN PATTERNS & PAGE COMPOSITION RULES — Allo Education Books v1.2
//
// ❗️ Ce fichier n'est PAS un template de page. C'est une PLANCHE DESIGN.
// Sortie : une fiche de référence pour rédacteur / dev / auditeur PDF.
// Aucune ligne pédagogique réelle — uniquement des blocs montrés à l'état pur,
// avec leurs règles (items max, lignes max, combinaisons OK / KO, anti-overflow).

/* ───────────────────────────────────────────────────────────────────────
   Mini-helpers internes : aucune dépendance aux PageShell. C'est une planche.
   ─────────────────────────────────────────────────────────────────────── */

const P7_TOKEN = {
  cardBg: "white",
  border: "var(--ae-border)",
  rail: "var(--ae-primary)",
  ok: "var(--ae-success)",
  ko: "var(--ae-error)",
  warn: "var(--ae-yellow-dark)",
  ink: "var(--ae-text)",
  inkSoft: "var(--ae-text-soft)",
  muted: "var(--ae-muted)",
};

function P7Pill({ tone = "primary", children }) {
  const map = {
    primary: ["var(--ae-primary-soft)", "var(--ae-primary)"],
    yellow:  ["var(--ae-yellow-soft)",  "var(--ae-yellow-dark)"],
    orange:  ["var(--ae-orange-soft)",  "var(--ae-orange-dark)"],
    green:   ["var(--ae-success-soft)", "var(--ae-success)"],
    red:     ["var(--ae-error-soft)",   "var(--ae-error)"],
    cool:    ["var(--ae-bg-cool)",      "var(--ae-text-soft)"],
    cream:   ["#FBF8F1",                "#7a5a1c"],
  };
  const [bg, fg] = map[tone] || map.cool;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      padding: "3px 9px", borderRadius: 999,
      background: bg, color: fg,
      fontSize: 11, fontWeight: 800,
      letterSpacing: "0.04em", textTransform: "uppercase",
      whiteSpace: "nowrap",
    }}>{children}</span>
  );
}

function P7Card({ num, name, usage, max, combine, avoid, overflow, std, compact }) {
  return (
    <article className="p7-card" style={{
      border: `1px solid ${P7_TOKEN.border}`,
      borderRadius: 14,
      background: P7_TOKEN.cardBg,
      overflow: "hidden",
    }}>
      <style>{`
        .p7-card { display: grid; grid-template-columns: minmax(0, 1fr) 240px; }
        .p7-card > .p7-left  { padding: 18px 20px; border-right: 1px solid ${P7_TOKEN.border}; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
        .p7-card > .p7-right { padding: 18px; background: var(--ae-bg-cool); min-width: 0; }
        .p7-variants { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
        .p7-variants > * { min-width: 0; }
        @media (max-width: 980px) {
          .p7-card { grid-template-columns: minmax(0, 1fr); }
          .p7-card > .p7-left { border-right: none; border-bottom: 1px solid ${P7_TOKEN.border}; }
        }
        @media (max-width: 560px) {
          .p7-variants { grid-template-columns: 1fr; }
        }
      `}</style>

      {/* Left: previews */}
      <div className="p7-left">
        <header style={{ display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap", minWidth: 0 }}>
          <span style={{
            fontFamily: "var(--ae-font-mono)", fontWeight: 700,
            color: "var(--ae-primary)", fontSize: 12, letterSpacing: "0.06em",
          }}>P7-{String(num).padStart(2, "0")}</span>
          <h3 style={{ margin: 0, fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 22, color: "var(--ae-primary-deep)", minWidth: 0 }}>
            {name}
          </h3>
        </header>
        <p style={{ margin: 0, color: P7_TOKEN.inkSoft, fontSize: 13.5, lineHeight: 1.55 }}>{usage}</p>

        <div className="p7-variants">
          <div style={{ display: "flex", flexDirection: "column", gap: 6, minWidth: 0 }}>
            <P7VariantHead label="Standard" />
            <div style={{ border: `1px dashed ${P7_TOKEN.border}`, borderRadius: 10, padding: 10, background: "#FAFBFE", minWidth: 0 }}>
              {std}
            </div>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 6, minWidth: 0 }}>
            <P7VariantHead label="Compact" />
            <div style={{ border: `1px dashed ${P7_TOKEN.border}`, borderRadius: 10, padding: 10, background: "#FAFBFE", minWidth: 0 }}>
              {compact}
            </div>
          </div>
        </div>
      </div>

      {/* Right: rules */}
      <aside className="p7-right">
        <P7RulesRow label="Max items"   value={max?.items} />
        <P7RulesRow label="Max lignes"  value={max?.lines} />
        <P7RulesRow label="Combine avec" rows={combine} tone="green" />
        <P7RulesRow label="Évite avec"   rows={avoid}   tone="red" />
        <div style={{
          marginTop: 12, padding: "8px 10px",
          background: "white", border: `1px solid ${P7_TOKEN.border}`,
          borderRadius: 8, fontSize: 12, lineHeight: 1.55, color: P7_TOKEN.inkSoft,
        }}>
          <div style={{ fontWeight: 800, color: P7_TOKEN.warn, marginBottom: 4, fontSize: 10.5, letterSpacing: "0.08em", textTransform: "uppercase" }}>Anti-overflow</div>
          {overflow}
        </div>
      </aside>
    </article>
  );
}

function P7VariantHead({ label }) {
  return (
    <div style={{
      fontSize: 10.5, fontWeight: 800, letterSpacing: "0.1em", textTransform: "uppercase",
      color: P7_TOKEN.muted,
    }}>{label}</div>
  );
}

function P7RulesRow({ label, value, rows, tone }) {
  if (rows) {
    return (
      <div style={{ marginBottom: 10 }}>
        <div style={{ fontSize: 10.5, fontWeight: 800, letterSpacing: "0.1em", textTransform: "uppercase", color: P7_TOKEN.muted, marginBottom: 4 }}>{label}</div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
          {rows.map((r, i) => <P7Pill key={i} tone={tone}>{r}</P7Pill>)}
        </div>
      </div>
    );
  }
  return (
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 8 }}>
      <span style={{ fontSize: 10.5, fontWeight: 800, letterSpacing: "0.1em", textTransform: "uppercase", color: P7_TOKEN.muted }}>{label}</span>
      <span style={{ fontFamily: "var(--ae-font-mono)", fontWeight: 700, color: P7_TOKEN.ink, fontSize: 14 }}>{value}</span>
    </div>
  );
}

/* ───────────────────────────────────────────────────────────────────────
   Mini-blocs visuels (jamais utilisés en page — uniquement ici, en planche)
   ─────────────────────────────────────────────────────────────────────── */

function MiniBox({ tone = "primary", label, dashed, children, pad = "10px 12px" }) {
  const map = {
    primary: ["var(--ae-primary-soft)", "var(--ae-primary)"],
    yellow:  ["var(--ae-yellow-soft)",  "var(--ae-yellow-dark)"],
    orange:  ["var(--ae-orange-soft)",  "var(--ae-orange-dark)"],
    green:   ["var(--ae-success-soft)", "var(--ae-success)"],
    red:     ["var(--ae-error-soft)",   "var(--ae-error)"],
    cool:    ["var(--ae-bg-cool)",      "var(--ae-text-soft)"],
    cream:   ["#FBF8F1",                "#7a5a1c"],
    neutral: ["white",                  "var(--ae-border)"],
  };
  const [bg, bd] = map[tone] || map.neutral;
  return (
    <div style={{
      position: "relative",
      background: bg,
      border: `${dashed ? "1.5px dashed" : "1.5px solid"} ${bd}`,
      borderRadius: 8,
      padding: pad,
      fontSize: 11.5, color: P7_TOKEN.ink, lineHeight: 1.5,
    }}>
      {label && (
        <div style={{
          position: "absolute", top: -10, left: 10,
          background: bd, color: tone === "yellow" ? "var(--ae-primary-deep)" : "white",
          padding: "2px 8px", borderRadius: 999,
          fontSize: 9.5, fontWeight: 800, letterSpacing: "0.06em", textTransform: "uppercase",
        }}>{label}</div>
      )}
      {children}
    </div>
  );
}

function MiniHRule({ w = "100%" }) {
  return <div style={{ height: 9, background: "repeating-linear-gradient(90deg, var(--ae-border) 0 4px, transparent 4px 8px)", borderRadius: 2, width: w }} />;
}
function MiniWriteLine({ w = "100%" }) {
  return <div style={{ height: 1.5, background: P7_TOKEN.border, width: w, borderRadius: 2 }} />;
}
function MiniWriteBox({ h = 28 }) {
  return <div style={{
    height: h, background: "repeating-linear-gradient(180deg, white 0 14px, var(--ae-border) 14px 15px)",
    border: `1px solid ${P7_TOKEN.border}`, borderRadius: 4,
  }} />;
}
function MiniDot({ c = "var(--ae-primary)" }) {
  return <span style={{ display: "inline-block", width: 8, height: 8, background: c, borderRadius: 999, marginRight: 6, verticalAlign: "middle" }} />;
}
function MiniQR({ size = 44 }) {
  return (
    <div style={{
      width: size, height: size,
      background: `
        linear-gradient(white, white),
        repeating-conic-gradient(var(--ae-primary-deep) 0 25%, white 0 50%) 0 0/8px 8px
      `,
      backgroundBlendMode: "multiply",
      border: "1.5px solid var(--ae-primary-deep)", borderRadius: 4,
    }} />
  );
}

/* ───────────────────────────────────────────────────────────────────────
   PLANCHE 1 — Hero
   ─────────────────────────────────────────────────────────────────────── */

function P7Hero() {
  return (
    <div style={{
      background: "linear-gradient(160deg, var(--ae-primary-deep), var(--ae-primary))",
      color: "white", borderRadius: 16, padding: "28px 28px", marginBottom: 24,
      position: "relative", overflow: "hidden",
    }}>
      <div style={{
        position: "absolute", top: -40, right: -40,
        width: 220, height: 220, borderRadius: "50%",
        background: "var(--ae-yellow)", opacity: 0.18,
      }} />
      <div style={{
        position: "absolute", bottom: -60, right: 120,
        width: 180, height: 180, borderRadius: "50%",
        background: "var(--ae-orange)", opacity: 0.18,
      }} />
      <div style={{ position: "relative" }}>
        <div style={{ fontSize: 11, fontWeight: 800, letterSpacing: "0.18em", textTransform: "uppercase", opacity: 0.8 }}>
          Pack 7 · Patterns
        </div>
        <h1 style={{ margin: "8px 0 6px", fontFamily: "var(--ae-font-title)", fontSize: 38, fontWeight: 700, lineHeight: 1.05 }}>
          Design Patterns &amp; Composition Rules
        </h1>
        <p style={{ margin: 0, fontSize: 15, opacity: 0.92, maxWidth: 720, lineHeight: 1.6 }}>
          La planche visuelle des 18 blocs autorisés dans Allo Education Books. Pour le rédacteur :
          combien d'items écrire. Pour le dev : quels blocs existent. Pour l'auditeur PDF : ce qui est
          valide, ce qui ne l'est pas, et comment composer une page qui respire.
        </p>
        <div style={{ display: "flex", gap: 8, marginTop: 14, flexWrap: "wrap" }}>
          <P7Pill tone="yellow">v1.2 · verrouillé</P7Pill>
          <P7Pill tone="green">18 blocs documentés</P7Pill>
          <P7Pill tone="orange">5 compositions OK</P7Pill>
          <P7Pill tone="red">5 compositions KO</P7Pill>
        </div>
      </div>
    </div>
  );
}

/* ───────────────────────────────────────────────────────────────────────
   PLANCHE 2 — Les 18 blocs
   ─────────────────────────────────────────────────────────────────────── */

const BLOCKS = [
  /* 01 — Objectif */
  {
    num: 1, name: "Objectif",
    usage: "Énonce ce que l'élève doit savoir faire à la fin de la page. Toujours en haut, jamais ailleurs.",
    max: { items: "1 objectif", lines: "1 à 2 lignes" },
    combine: ["À retenir", "Méthode", "Exemple guidé", "Exercice"],
    avoid: ["Autre Objectif", "Bilan final"],
    overflow: "Si l'objectif dépasse 2 lignes, réécris plus court — n'ajoute pas une 3ᵉ ligne.",
    std: (
      <MiniBox tone="primary" label="Objectif">
        Comparer deux fractions de même dénominateur.
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="primary" label="Objectif" pad="6px 10px">
        Comparer 2 fractions.
      </MiniBox>
    ),
  },

  /* 02 — À retenir */
  {
    num: 2, name: "À retenir",
    usage: "Règle, définition ou notion-clé que l'élève doit mémoriser. Style fond jaune, marqueur visuel fort.",
    max: { items: "1 règle + 0–4 bullets", lines: "5 lignes max" },
    combine: ["Objectif", "Exemple guidé", "Méthode", "Exercice"],
    avoid: ["Mini-sujet", "Correction compacte"],
    overflow: "Découper en deux \"À retenir\" plutôt qu'un seul trop long. Pas de paragraphe fleuve.",
    std: (
      <MiniBox tone="yellow" label="À retenir">
        Une fraction représente une partie d'un tout.<br />
        <span style={{ display: "inline-flex", gap: 4 }}><MiniDot c="var(--ae-yellow-dark)" />Numérateur en haut.</span><br />
        <span style={{ display: "inline-flex", gap: 4 }}><MiniDot c="var(--ae-yellow-dark)" />Dénominateur en bas.</span>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="yellow" label="Je retiens" pad="6px 10px">
        Numérateur ÷ Dénominateur.
      </MiniBox>
    ),
  },

  /* 03 — Méthode / Étapes */
  {
    num: 3, name: "Méthode / Étapes",
    usage: "Procédure pas-à-pas, numérotée. Verts. Disponible en vertical (standard) et horizontal (compact).",
    max: { items: "3 à 6 étapes", lines: "1 ligne / étape" },
    combine: ["Objectif", "Exemple guidé", "Problème"],
    avoid: ["Autre Méthode", "Mini-sujet"],
    overflow: "Au-delà de 6 étapes : c'est deux méthodes. Ou ce n'est pas une méthode.",
    std: (
      <MiniBox tone="green" label="Méthode">
        <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
          {["Je lis l'énoncé.", "Je repère les données.", "Je pose le calcul.", "Je rédige la phrase."].map((s, i) => (
            <div key={i} style={{ display: "flex", gap: 6, alignItems: "baseline" }}>
              <span style={{ minWidth: 14, height: 14, borderRadius: 999, background: "var(--ae-success)", color: "white", fontSize: 9, display: "grid", placeItems: "center", fontWeight: 800 }}>{i + 1}</span>
              <span>{s}</span>
            </div>
          ))}
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="green" label="Méthode" pad="6px 10px">
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {["Lire", "Repérer", "Calculer", "Rédiger"].map((s, i) => (
            <span key={i} style={{ display: "inline-flex", alignItems: "center", gap: 4, padding: "2px 6px", background: "white", border: "1px solid var(--ae-success)", borderRadius: 999, fontSize: 10 }}>
              <span style={{ width: 12, height: 12, borderRadius: 999, background: "var(--ae-success)", color: "white", fontSize: 8, display: "grid", placeItems: "center", fontWeight: 800 }}>{i + 1}</span>
              {s}
            </span>
          ))}
        </div>
      </MiniBox>
    ),
  },

  /* 04 — Exemple guidé */
  {
    num: 4, name: "Exemple guidé",
    usage: "Un exemple résolu sous les yeux de l'élève. Énoncé court + démarche courte + résultat. Disponible en variante maths, français, sciences.",
    max: { items: "1 exemple", lines: "3 à 5 lignes de calcul" },
    combine: ["À retenir", "Méthode", "Exercice"],
    avoid: ["Autre exemple", "Correction compacte"],
    overflow: "Si la démarche dépasse 5 lignes, soit la méthode est mal expliquée, soit l'exemple est trop dur.",
    std: (
      <MiniBox tone="cream" label="Exemple">
        <div style={{ fontStyle: "italic", color: P7_TOKEN.inkSoft, marginBottom: 4 }}>Compare 3/5 et 4/5.</div>
        <div style={{ fontFamily: "var(--ae-font-mono)" }}>3/5 &lt; 4/5</div>
        <div style={{ fontSize: 11, color: P7_TOKEN.muted, marginTop: 2 }}>même dénominateur → on compare les numérateurs.</div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="cream" label="Ex." pad="6px 10px">
        <span style={{ fontFamily: "var(--ae-font-mono)" }}>3/5 &lt; 4/5</span>
      </MiniBox>
    ),
  },

  /* 05 — Exercice simple */
  {
    num: 5, name: "Exercice simple",
    usage: "Grille d'items courts, même format. 2 colonnes. Chaque item = énoncé minimal + zone réponse.",
    max: { items: "4 à 6 items", lines: "1 ligne d'énoncé / item" },
    combine: ["Objectif", "À retenir", "Méthode"],
    avoid: ["Exercice progressif (sur la même page)", "Mini-sujet"],
    overflow: "Plus de 6 items → c'est un exercice progressif, pas un exo simple. Utilise le bloc 06.",
    std: (
      <MiniBox tone="primary" label="Exercice 1">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
          {[1, 2, 3, 4].map(n => (
            <div key={n} style={{ display: "flex", alignItems: "center", gap: 6 }}>
              <span style={{ minWidth: 16, height: 16, borderRadius: 4, background: "var(--ae-primary)", color: "white", fontSize: 10, display: "grid", placeItems: "center", fontWeight: 700 }}>{n}</span>
              <MiniWriteLine />
            </div>
          ))}
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="primary" label="Exercice" pad="6px 10px">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 4 }}>
          {[1, 2, 3, 4].map(n => (
            <div key={n} style={{ fontFamily: "var(--ae-font-mono)", fontSize: 10 }}>
              {n}. ___
            </div>
          ))}
        </div>
      </MiniBox>
    ),
  },

  /* 06 — Exercice progressif */
  {
    num: 6, name: "Exercice progressif",
    usage: "Deux exercices structurés sur la même page, du plus facile au plus difficile. Zones de calcul compactes.",
    max: { items: "2 exercices · 4 items / exo", lines: "2 lignes de calcul / item" },
    combine: ["Objectif", "Méthode", "Auto-évaluation"],
    avoid: ["Exemple guidé long", "Problème guidé", "Mini-sujet"],
    overflow: "Si un seul exo prend toute la page, c'est un Problème guidé, pas un exo progressif.",
    std: (
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        <MiniBox tone="primary" label="Exercice 1 · facile">
          <MiniWriteLine /><div style={{ height: 4 }} /><MiniWriteLine />
        </MiniBox>
        <MiniBox tone="orange" label="Exercice 2 · expert">
          <MiniWriteBox h={26} />
        </MiniBox>
      </div>
    ),
    compact: (
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
        <MiniBox tone="primary" label="Ex. 1" pad="6px 10px"><MiniWriteLine /></MiniBox>
        <MiniBox tone="orange" label="Ex. 2" pad="6px 10px"><MiniWriteLine /></MiniBox>
      </div>
    ),
  },

  /* 07 — QCM */
  {
    num: 7, name: "QCM",
    usage: "Questions à choix multiples. Trois choix A/B/C systématiques. Option justification courte.",
    max: { items: "3 à 5 questions", lines: "1 ligne / option" },
    combine: ["Objectif", "À retenir", "Auto-évaluation"],
    avoid: ["Problème guidé", "Mini-sujet (le QCM EST déjà un mini-sujet)"],
    overflow: "Au-delà de 5 questions → couper en deux QCM ou passer en mini-sujet (bloc 15).",
    std: (
      <MiniBox tone="orange" label="QCM">
        <div style={{ marginBottom: 4 }}>1. La capitale de l'Italie est…</div>
        <div style={{ display: "flex", gap: 8, fontSize: 10.5 }}>
          {["A Rome", "B Paris", "C Madrid"].map(o => (
            <span key={o} style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
              <span style={{ width: 12, height: 12, borderRadius: 3, border: "1.2px solid var(--ae-orange)" }} />
              {o}
            </span>
          ))}
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="orange" label="QCM" pad="6px 10px">
        <span style={{ fontSize: 10.5 }}>1. … <b>A</b> · <b>B</b> · <b>C</b></span>
      </MiniBox>
    ),
  },

  /* 08 — Problème guidé */
  {
    num: 8, name: "Problème guidé",
    usage: "Situation → données → étapes → phrase réponse. Format long. Maximum 1 ou 2 problèmes par page.",
    max: { items: "1 à 2 problèmes", lines: "8 à 10 lignes / problème" },
    combine: ["Méthode", "Ketty (astuce)", "Auto-évaluation"],
    avoid: ["Mini-sujet", "QCM", "Exercice progressif"],
    overflow: "2 problèmes = limite stricte. Si tu veux 3 problèmes → 2 pages.",
    std: (
      <MiniBox tone="primary" label="Problème 1">
        <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
          <div style={{ fontStyle: "italic", fontSize: 11, color: P7_TOKEN.inkSoft }}>Léa achète 3 livres à 8 €. Combien paye-t-elle ?</div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 4 }}>
            <MiniBox tone="cool" pad="4px 6px"><span style={{ fontSize: 9.5, color: P7_TOKEN.muted }}>Données</span></MiniBox>
            <MiniBox tone="cool" pad="4px 6px"><span style={{ fontSize: 9.5, color: P7_TOKEN.muted }}>Calcul</span></MiniBox>
          </div>
          <MiniWriteLine />
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="primary" label="Pb." pad="6px 10px">
        <div style={{ fontSize: 10.5 }}>3 livres × 8 € = ___</div>
      </MiniBox>
    ),
  },

  /* 09 — Figure / Schéma */
  {
    num: 9, name: "Figure / Schéma",
    usage: "SVG géométrique, schéma scientifique, carte muette. Toujours légendé. Question associée immédiate.",
    max: { items: "1 figure principale", lines: "—" },
    combine: ["Question", "Tableau (données)"],
    avoid: ["Autre figure", "Ketty long"],
    overflow: "Hauteur max recommandée 3 in. Si plus, c'est une planche → page dédiée.",
    std: (
      <MiniBox tone="cool" label="Figure 1">
        <div style={{ height: 70, background: "white", border: `1px solid ${P7_TOKEN.border}`, borderRadius: 6, display: "grid", placeItems: "center" }}>
          <svg viewBox="0 0 80 50" style={{ width: "70%", height: "70%" }}>
            <rect x="10" y="6" width="60" height="38" fill="var(--ae-primary-soft)" stroke="var(--ae-primary)" strokeWidth="1.5" />
            <text x="40" y="28" textAnchor="middle" fontSize="9" fill="var(--ae-primary-deep)" fontWeight="700">ABCD</text>
          </svg>
        </div>
        <div style={{ fontSize: 10, color: P7_TOKEN.muted, marginTop: 4 }}>Quadrilatère ABCD · 4 cm × 3 cm</div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="cool" pad="6px 10px">
        <div style={{ height: 36, background: "white", border: `1px solid ${P7_TOKEN.border}`, borderRadius: 4, display: "grid", placeItems: "center" }}>
          <span style={{ fontSize: 9, color: P7_TOKEN.muted }}>schéma</span>
        </div>
      </MiniBox>
    ),
  },

  /* 10 — Tableau */
  {
    num: 10, name: "Tableau",
    usage: "Donnée structurée. Variantes : proportionnalité, tableur (gris), statistiques.",
    max: { items: "2 à 5 colonnes · 2 à 5 lignes", lines: "—" },
    combine: ["Question", "Figure (légende)"],
    avoid: ["Autre tableau plein", "Problème guidé long"],
    overflow: "Une cellule = un mot ou un nombre. Pas de phrase dans une cellule.",
    std: (
      <MiniBox tone="neutral" label="Tableau">
        <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 10 }}>
          <thead><tr style={{ background: "var(--ae-primary-soft)" }}>
            <th style={{ border: "1px solid var(--ae-border)", padding: 3, fontWeight: 700, color: "var(--ae-primary-deep)" }}>Élève</th>
            <th style={{ border: "1px solid var(--ae-border)", padding: 3, fontWeight: 700, color: "var(--ae-primary-deep)" }}>Note</th>
          </tr></thead>
          <tbody>
            <tr><td style={{ border: "1px solid var(--ae-border)", padding: 3 }}>Léa</td><td style={{ border: "1px solid var(--ae-border)", padding: 3 }}>16</td></tr>
            <tr><td style={{ border: "1px solid var(--ae-border)", padding: 3 }}>Sam</td><td style={{ border: "1px solid var(--ae-border)", padding: 3 }}>14</td></tr>
          </tbody>
        </table>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="neutral" pad="6px 10px">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", fontFamily: "var(--ae-font-mono)", fontSize: 9.5 }}>
          <div style={{ borderBottom: "1px solid var(--ae-border)" }}>×</div>
          <div style={{ borderBottom: "1px solid var(--ae-border)" }}>2</div>
          <div style={{ borderBottom: "1px solid var(--ae-border)" }}>3</div>
          <div>P</div><div>4</div><div>6</div>
        </div>
      </MiniBox>
    ),
  },

  /* 11 — Graphique / Repère */
  {
    num: 11, name: "Graphique / Repère",
    usage: "Repère orthonormé, axes gradués, points placés. Toujours suivi de 2-3 questions de lecture.",
    max: { items: "1 repère · 5 points max", lines: "—" },
    combine: ["Question", "Tableau"],
    avoid: ["Figure 3D", "Ketty long"],
    overflow: "Taille max 2.5 in × 2.5 in. Au-delà = page dédiée graphique.",
    std: (
      <MiniBox tone="cool" label="Repère">
        <svg viewBox="0 0 90 60" style={{ width: "100%", height: 70, background: "white" }}>
          <line x1="10" y1="55" x2="85" y2="55" stroke="var(--ae-border)" />
          <line x1="10" y1="5"  x2="10" y2="55" stroke="var(--ae-border)" />
          {[20, 30, 40, 50, 60, 70, 80].map(x => <line key={x} x1={x} y1="53" x2={x} y2="55" stroke="var(--ae-border)" />)}
          {[15, 25, 35, 45].map(y => <line key={y} x1="8" y1={y} x2="10" y2={y} stroke="var(--ae-border)" />)}
          <circle cx="30" cy="40" r="2.5" fill="var(--ae-primary)" />
          <circle cx="55" cy="22" r="2.5" fill="var(--ae-primary)" />
          <circle cx="75" cy="15" r="2.5" fill="var(--ae-primary)" />
        </svg>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="cool" pad="6px 10px">
        <svg viewBox="0 0 60 40" style={{ width: "100%", height: 40 }}>
          <line x1="4" y1="36" x2="56" y2="36" stroke="var(--ae-border)" />
          <line x1="4" y1="4" x2="4" y2="36" stroke="var(--ae-border)" />
          <circle cx="40" cy="14" r="2" fill="var(--ae-primary)" />
        </svg>
      </MiniBox>
    ),
  },

  /* 12 — Auto-évaluation */
  {
    num: 12, name: "Auto-évaluation",
    usage: "Petite ligne de fin de page. Oui / Presque / À revoir. Jamais énorme. Toujours en bas, jamais en haut.",
    max: { items: "3 lignes", lines: "1 ligne / item" },
    combine: ["Exercice", "Problème", "QCM"],
    avoid: ["Ketty long", "Bilan final", "Mini-sujet"],
    overflow: "Si l'élève doit lire plus de 3 phrases pour s'auto-évaluer → c'est devenu un bilan.",
    std: (
      <MiniBox tone="green" label="Je m'auto-évalue">
        {["J'ai compris la leçon.", "Je sais l'appliquer seul·e.", "Je peux expliquer à un·e camarade."].map((s, i) => (
          <div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 14px 14px 14px", gap: 6, alignItems: "center", marginTop: 2 }}>
            <span style={{ fontSize: 10.5 }}>{s}</span>
            {[0,1,2].map(j => <span key={j} style={{ width: 12, height: 12, borderRadius: 3, border: `1.2px solid var(--ae-success)` }} />)}
          </div>
        ))}
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="green" pad="6px 10px">
        <div style={{ display: "flex", justifyContent: "space-between", fontSize: 10 }}>
          <span>Oui</span><span>Presque</span><span>À revoir</span>
        </div>
      </MiniBox>
    ),
  },

  /* 13 — Ketty */
  {
    num: 13, name: "Ketty",
    usage: "Bulle de coaching de la mascotte. Court, encourageant. Types : astuce, méthode, erreur, bravo.",
    max: { items: "1 bulle / page (2 max)", lines: "2 à 3 lignes" },
    combine: ["Problème", "Exercice", "Exemple guidé"],
    avoid: ["Bilan final", "Mini-sujet", "Correction compacte"],
    overflow: "Si Ketty dit + de 3 lignes, c'est plus une bulle, c'est un paragraphe. Coupe.",
    std: (
      <MiniBox tone="primary" label="Astuce Ketty">
        <div style={{ display: "grid", gridTemplateColumns: "26px 1fr", gap: 6, alignItems: "center" }}>
          <div style={{ width: 26, height: 26, borderRadius: 999, background: "var(--ae-primary)", display: "grid", placeItems: "center", color: "white", fontWeight: 800, fontSize: 11 }}>K</div>
          <span style={{ fontSize: 10.5 }}>Repère d'abord le dénominateur — c'est lui qui décide.</span>
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="primary" pad="6px 10px">
        <span style={{ fontSize: 10.5 }}><b>Ketty —</b> repère le dénominateur.</span>
      </MiniBox>
    ),
  },

  /* 14 — QR */
  {
    num: 14, name: "QR",
    usage: "Bloc d'accès aux ressources : corrections, audio, quiz. Position recommandée : bas-droit ou bas-page.",
    max: { items: "1 QR principal / page", lines: "—" },
    combine: ["Footer", "Auto-évaluation", "Bilan"],
    avoid: ["Ketty long juste à côté", "Tableau dense juste à côté"],
    overflow: "Taille min imprimable : 0.6 in. Sous-label = 1 ligne max.",
    std: (
      <MiniBox tone="neutral" label="QR ressource">
        <div style={{ display: "grid", gridTemplateColumns: "auto 1fr", gap: 8, alignItems: "center" }}>
          <MiniQR size={44} />
          <div>
            <div style={{ fontWeight: 800, fontSize: 11 }}>Corriger avec Ketty</div>
            <div style={{ fontSize: 9.5, color: P7_TOKEN.muted }}>alloeducation.fr/qr/p28</div>
          </div>
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="neutral" pad="6px 8px">
        <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
          <MiniQR size={28} />
          <span style={{ fontSize: 9.5, color: P7_TOKEN.muted }}>p28</span>
        </div>
      </MiniBox>
    ),
  },

  /* 15 — Mini-sujet */
  {
    num: 15, name: "Mini-sujet",
    usage: "Sujet d'examen blanc : conditions, exercices, barème. Mode TRÈS compact, attention overflow.",
    max: { items: "3 à 5 exercices", lines: "3 lignes max / consigne" },
    combine: ["Auto-évaluation très compacte", "QR mini"],
    avoid: ["Méthode", "Ketty", "Exemple guidé", "Problème guidé"],
    overflow: "Le mini-sujet mange déjà la page. AUCUN autre bloc large. Zones de réponse minimales.",
    std: (
      <MiniBox tone="orange" label="Sujet · 30 min">
        <div style={{ fontSize: 10, color: P7_TOKEN.muted, marginBottom: 3 }}>Calculatrice interdite.</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 3, fontSize: 10.5 }}>
          {["Ex 1 · /4 ……………", "Ex 2 · /6 ……………", "Ex 3 · /5 ……………", "Ex 4 · /5 ……………"].map(s => <div key={s}>{s}</div>)}
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="orange" pad="6px 10px">
        <span style={{ fontSize: 10 }}>Sujet · 4 ex · /20</span>
      </MiniBox>
    ),
  },

  /* 16 — Correction compacte */
  {
    num: 16, name: "Correction compacte",
    usage: "Page de fin de cahier : réponses finales uniquement. AUCUN développement, aucune méthode.",
    max: { items: "6 à 10 groupes", lines: "1 ligne / réponse" },
    combine: ["QR mini", "Renvoi page"],
    avoid: ["Méthode", "Ketty", "Exemple guidé", "Tableau plein"],
    overflow: "Si tu veux expliquer une correction → c'est dans le QR, pas sur la page.",
    std: (
      <MiniBox tone="cool" label="Correction">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 2, fontFamily: "var(--ae-font-mono)", fontSize: 10 }}>
          {["p28 · 1) 12", "p28 · 2) 5,4", "p29 · 1) Vrai", "p29 · 2) 3/4"].map(s => <div key={s}>{s}</div>)}
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="cool" pad="6px 10px">
        <div style={{ fontFamily: "var(--ae-font-mono)", fontSize: 9.5 }}>p28→p32 · 12 réponses</div>
      </MiniBox>
    ),
  },

  /* 17 — Formulaire */
  {
    num: 17, name: "Formulaire",
    usage: "Cartes de formules / propriétés. 2 colonnes. Aucune phrase — uniquement les formules avec nom.",
    max: { items: "6 à 10 cartes", lines: "Nom + formule" },
    combine: ["Mini-sujet (à côté, page miroir)"],
    avoid: ["Exemple guidé", "Méthode", "Problème"],
    overflow: "Si une carte fait 3 lignes, ce n'est pas une formule, c'est un mini-cours. Sors-la d'ici.",
    std: (
      <MiniBox tone="yellow" label="Formulaire">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 4 }}>
          {[["Aire carré", "c × c"], ["Aire rect.", "L × l"], ["P. carré", "4 × c"], ["P. rect.", "2(L+l)"]].map(([n, f]) => (
            <div key={n} style={{ background: "white", border: "1px solid var(--ae-yellow-dark)", borderRadius: 4, padding: "3px 5px" }}>
              <div style={{ fontSize: 9, color: P7_TOKEN.muted, fontWeight: 700 }}>{n}</div>
              <div style={{ fontFamily: "var(--ae-font-mono)", fontSize: 11, color: "var(--ae-primary-deep)" }}>{f}</div>
            </div>
          ))}
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="yellow" pad="6px 10px">
        <span style={{ fontFamily: "var(--ae-font-mono)", fontSize: 10 }}>A=L×l · P=2(L+l)</span>
      </MiniBox>
    ),
  },

  /* 18 — Fin de livre */
  {
    num: 18, name: "Fin de livre",
    usage: "Famille de blocs premium : diplôme, bilan, hub QR, mentions. Style sobre, encadrement, dégradé léger autorisé.",
    max: { items: "1 bloc / page", lines: "—" },
    combine: ["Couverture intérieure", "Collection showcase"],
    avoid: ["Exercice", "Mini-sujet", "Méthode", "Problème"],
    overflow: "Ne JAMAIS mélanger fin de livre + exercice sur la même page. Page dédiée toujours.",
    std: (
      <MiniBox tone="cream" label="Diplôme" pad="14px 12px">
        <div style={{ textAlign: "center" }}>
          <div style={{ fontSize: 9, fontWeight: 800, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--ae-primary)" }}>Diplôme</div>
          <div style={{ fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 16, color: "var(--ae-primary-deep)", margin: "2px 0" }}>Léa Martinez</div>
          <div style={{ fontSize: 9.5, color: P7_TOKEN.muted }}>Cahier terminé · 12 chapitres</div>
        </div>
      </MiniBox>
    ),
    compact: (
      <MiniBox tone="cream" pad="6px 10px">
        <span style={{ fontSize: 10 }}>Diplôme · Bilan · QR</span>
      </MiniBox>
    ),
  },
];

/* ───────────────────────────────────────────────────────────────────────
   PLANCHE 3 — Compositions OK / KO
   ─────────────────────────────────────────────────────────────────────── */

function PageMock({ verdict = "ok", title, sub, blocks }) {
  const railColor = verdict === "ok" ? "var(--ae-success)" : "var(--ae-error)";
  return (
    <div style={{
      border: `1.5px solid ${railColor}`,
      borderRadius: 12,
      background: "white",
      overflow: "hidden",
      display: "flex", flexDirection: "column",
    }}>
      {/* Header strip */}
      <div style={{
        display: "flex", justifyContent: "space-between", alignItems: "center",
        background: railColor, color: "white",
        padding: "6px 10px",
        fontSize: 10, fontWeight: 800, letterSpacing: "0.08em", textTransform: "uppercase",
      }}>
        <span>{verdict === "ok" ? "Combinaison recommandée" : "Combinaison à éviter"}</span>
        <span>{verdict === "ok" ? "✓" : "✕"}</span>
      </div>
      {/* Body */}
      <div style={{ padding: "12px 12px 10px", display: "flex", flexDirection: "column", gap: 8 }}>
        <div>
          <div style={{ fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 14, color: "var(--ae-primary-deep)" }}>{title}</div>
          <div style={{ fontSize: 11, color: P7_TOKEN.muted }}>{sub}</div>
        </div>
        {/* Page silhouette 8.5×11 reduced */}
        <div style={{
          aspectRatio: "8.5 / 11",
          background: "var(--ae-bg-cool)",
          border: `1px solid ${P7_TOKEN.border}`,
          borderRadius: 6,
          padding: 6,
          display: "flex", flexDirection: "column", gap: 4,
          position: "relative",
        }}>
          {/* faux header */}
          <div style={{ height: 12, background: "var(--ae-primary)", borderRadius: 3 }} />
          {/* content */}
          <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 4 }}>
            {blocks.map((b, i) => (
              <div key={i} style={{
                flex: b.flex || 1,
                background: b.bg || "white",
                border: `1px ${b.dashed ? "dashed" : "solid"} ${b.border || P7_TOKEN.border}`,
                borderRadius: 3,
                padding: "2px 4px",
                fontSize: 8.5, color: b.fg || P7_TOKEN.inkSoft,
                fontWeight: 700, letterSpacing: "0.03em",
                display: "flex", alignItems: "center",
              }}>
                {b.label}
              </div>
            ))}
          </div>
          {/* faux footer */}
          <div style={{ height: 10, background: "var(--ae-primary)", borderRadius: 3, opacity: 0.65 }} />
          {/* KO cross overlay */}
          {verdict === "ko" && (
            <div style={{
              position: "absolute", inset: 0, pointerEvents: "none",
              background: "linear-gradient(45deg, transparent 49%, rgba(214,46,46,0.18) 49%, rgba(214,46,46,0.18) 51%, transparent 51%), linear-gradient(-45deg, transparent 49%, rgba(214,46,46,0.18) 49%, rgba(214,46,46,0.18) 51%, transparent 51%)",
              borderRadius: 6,
            }} />
          )}
        </div>
        {/* Reasoning */}
        <div style={{ fontSize: 11, color: P7_TOKEN.inkSoft, lineHeight: 1.5 }}>
          {sub === undefined ? null : null}
        </div>
      </div>
    </div>
  );
}

const blkOK = (label, opts = {}) => ({
  label, bg: "var(--ae-primary-soft)", border: "var(--ae-primary)", fg: "var(--ae-primary-deep)", ...opts,
});
const blkYel = (label, opts = {}) => ({
  label, bg: "var(--ae-yellow-soft)", border: "var(--ae-yellow-dark)", fg: "#7a5a1c", ...opts,
});
const blkGr = (label, opts = {}) => ({
  label, bg: "var(--ae-success-soft)", border: "var(--ae-success)", fg: "var(--ae-success)", ...opts,
});
const blkOr = (label, opts = {}) => ({
  label, bg: "var(--ae-orange-soft)", border: "var(--ae-orange-dark)", fg: "var(--ae-orange-dark)", ...opts,
});
const blkCr = (label, opts = {}) => ({
  label, bg: "#FBF8F1", border: "#d8c89a", fg: "#7a5a1c", ...opts,
});
const blkN = (label, opts = {}) => ({
  label, bg: "white", border: "var(--ae-border)", fg: "var(--ae-text-soft)", ...opts,
});
const blkRed = (label, opts = {}) => ({
  label, bg: "var(--ae-error-soft)", border: "var(--ae-error)", fg: "var(--ae-error)", ...opts,
});

const COMPOSITIONS_OK = [
  { title: "Leçon courte", sub: "Objectif → À retenir → Exemple → À toi → QR", blocks: [
    blkOK("Objectif", { flex: 0.6 }),
    blkYel("À retenir", { flex: 1.1 }),
    blkCr("Exemple guidé", { flex: 1 }),
    blkOK("Exercice simple · 4 items", { flex: 1.4 }),
    blkN("QR + Auto-éval", { flex: 0.7 }),
  ]},
  { title: "Exercice progressif", sub: "Objectif → Ex 1 → Ex 2 → Auto-évaluation → QR", blocks: [
    blkOK("Objectif", { flex: 0.5 }),
    blkOK("Exercice 1 · facile", { flex: 1.4 }),
    blkOr("Exercice 2 · expert", { flex: 1.6 }),
    blkGr("Auto-évaluation", { flex: 0.6 }),
    blkN("QR", { flex: 0.5 }),
  ]},
  { title: "Problème guidé", sub: "Situation → Données → Étapes → Réponse → Ketty → QR", blocks: [
    blkOK("Situation + Données", { flex: 1 }),
    blkGr("Méthode 4 étapes", { flex: 0.9 }),
    blkOK("Calcul + Phrase réponse", { flex: 1.6 }),
    blkOK("Ketty · 2 lignes", { flex: 0.6 }),
    blkN("QR", { flex: 0.5 }),
  ]},
  { title: "Mini-sujet (brevet blanc)", sub: "Conditions → 4 exercices → Score → QR", blocks: [
    blkOr("Conditions · 30 min · /20", { flex: 0.5 }),
    blkOr("Exercice 1 · /4", { flex: 1 }),
    blkOr("Exercice 2 · /6", { flex: 1.1 }),
    blkOr("Exercice 3 · /5", { flex: 1 }),
    blkOr("Exercice 4 · /5", { flex: 1 }),
    blkN("Score · QR mini", { flex: 0.4 }),
  ]},
  { title: "Correction", sub: "Réponses compactes · 2 colonnes · QR explication", blocks: [
    blkN("Titre · p28 → p32", { flex: 0.4 }),
    blkN("Réponses ex 1-4 (2 col)", { flex: 1.6 }),
    blkN("Réponses ex 5-8 (2 col)", { flex: 1.6 }),
    blkN("QR explications détaillées", { flex: 0.5 }),
  ]},
];

const COMPOSITIONS_KO = [
  { title: "Grosse figure + gros tableau + Ketty long", sub: "Tout en concurrence. Aucun élément ne respire.", blocks: [
    blkRed("Figure 3.5 in"),
    blkRed("Tableau plein 5×5"),
    blkRed("Ketty · 6 lignes"),
    blkRed("Exercice · 6 items"),
  ]},
  { title: "Mini-sujet + grandes zones de réponse", sub: "Le mini-sujet est déjà dense. Les zones débordent.", blocks: [
    blkRed("Sujet · conditions"),
    blkRed("Ex 1 + zone réponse 2 in"),
    blkRed("Ex 2 + zone réponse 2 in"),
    blkRed("Ex 3 + zone réponse 2 in"),
  ]},
  { title: "Correction compacte + explications longues", sub: "La correction n'explique jamais. C'est le rôle du QR.", blocks: [
    blkRed("Correction p28"),
    blkRed("Explication détaillée"),
    blkRed("Méthode pas à pas"),
    blkRed("Exemple guidé"),
  ]},
  { title: "QR large + footer chargé", sub: "Double QR au pied de page. Choix : ou page, ou footer.", blocks: [
    blkN("Contenu page"),
    blkRed("QR large 1.5 in"),
    blkRed("Footer · score · QR factory · page"),
  ]},
  { title: "Plus de 2 problèmes guidés sur 1 page", sub: "Limite stricte : 2 problèmes max. Au-delà → 2 pages.", blocks: [
    blkRed("Problème 1"),
    blkRed("Problème 2"),
    blkRed("Problème 3"),
    blkRed("Problème 4"),
  ]},
];

/* ───────────────────────────────────────────────────────────────────────
   PLANCHE 4 — Règles d'espacement
   ─────────────────────────────────────────────────────────────────────── */

function SpacingVisual({ gap, label, verdict }) {
  const tone = verdict === "ok" ? "var(--ae-success)" : verdict === "ko-tight" ? "var(--ae-error)" : "var(--ae-yellow-dark)";
  return (
    <div style={{
      border: `1.5px solid ${tone}`, borderRadius: 10, padding: 12, background: "white",
      display: "flex", flexDirection: "column", gap: 8,
    }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
        <div style={{ fontWeight: 800, color: tone, fontSize: 12, textTransform: "uppercase", letterSpacing: "0.08em" }}>{label}</div>
        <div style={{ fontFamily: "var(--ae-font-mono)", fontSize: 11, color: P7_TOKEN.muted }}>gap : {gap}</div>
      </div>
      <div style={{ background: "var(--ae-bg-cool)", padding: 8, borderRadius: 6, display: "flex", flexDirection: "column", gap: gap }}>
        {[1,2,3].map(i => (
          <div key={i} style={{
            height: 18, background: "white",
            border: `1px solid ${P7_TOKEN.border}`,
            borderRadius: 3, padding: "2px 6px",
            fontSize: 9.5, color: P7_TOKEN.muted, fontWeight: 700,
            display: "flex", alignItems: "center",
          }}>Bloc {i}</div>
        ))}
      </div>
    </div>
  );
}

function P7Spacing() {
  return (
    <section style={{ marginTop: 28 }}>
      <h2 style={{ fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 24, color: "var(--ae-primary-deep)", margin: "0 0 4px" }}>
        Règles d'espacement entre blocs
      </h2>
      <p style={{ margin: "0 0 16px", color: P7_TOKEN.inkSoft, fontSize: 14, maxWidth: 820, lineHeight: 1.55 }}>
        Un cahier d'exercices DOIT respirer. La V1.2 verrouille trois densités. Si une page est trop
        serrée OU trop vide, c'est qu'on a choisi la mauvaise densité — pas qu'on doit improviser des marges.
      </p>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 14 }}>
        <SpacingVisual gap="6px"  label="Trop serré"  verdict="ko-tight" />
        <SpacingVisual gap="14px" label="Standard · 0.20 in" verdict="ok" />
        <SpacingVisual gap="26px" label="Trop vide"   verdict="ko-loose" />
      </div>

      <div style={{
        marginTop: 16, padding: "14px 16px",
        background: "var(--ae-primary-soft)",
        border: "1.5px solid var(--ae-primary)",
        borderRadius: 12,
      }}>
        <div style={{ fontWeight: 800, color: "var(--ae-primary)", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 6 }}>
          Tokens officiels
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10, fontSize: 13 }}>
          {[
            { name: "Air (CP / CE1)",     gap: "0.26 in", lh: 1.6,  ah: "0.84 in" },
            { name: "Standard (par défaut)", gap: "0.20 in", lh: 1.5,  ah: "0.60 in" },
            { name: "Dense (lycée)",      gap: "0.14 in", lh: 1.45, ah: "0.50 in" },
          ].map(d => (
            <div key={d.name} style={{ background: "white", border: `1px solid ${P7_TOKEN.border}`, borderRadius: 8, padding: "10px 12px" }}>
              <div style={{ fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 14, color: "var(--ae-primary-deep)" }}>{d.name}</div>
              <div style={{ marginTop: 6, display: "flex", flexDirection: "column", gap: 2, fontFamily: "var(--ae-font-mono)", fontSize: 11.5, color: P7_TOKEN.inkSoft }}>
                <div>blockGap · <b>{d.gap}</b></div>
                <div>lineHeight · <b>{d.lh}</b></div>
                <div>answerBox · <b>{d.ah}</b></div>
              </div>
            </div>
          ))}
        </div>
      </div>

      <div style={{
        marginTop: 14, padding: "14px 16px",
        background: "white", border: `1px solid ${P7_TOKEN.border}`, borderRadius: 12,
      }}>
        <div style={{ fontWeight: 800, color: P7_TOKEN.warn, fontSize: 11, textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 8 }}>
          Anti-trous blancs — checklist auditeur
        </div>
        <ul style={{ margin: 0, paddingLeft: 18, fontSize: 13.5, lineHeight: 1.7, color: P7_TOKEN.inkSoft }}>
          <li>Si une zone vide dépasse <b>1.5 in de haut</b> → ajouter un bloc, agrandir une zone réponse, ou réduire la densité.</li>
          <li>Si deux blocs se touchent (gap &lt; 0.14 in) → c'est <b>trop serré</b>, on passe en densité standard ou air.</li>
          <li>Une page d'exercices DOIT avoir au moins <b>3 blocs distincts</b>. Sinon = trop vide.</li>
          <li>Une page DOIT avoir au plus <b>6 blocs principaux</b>. Au-delà = trop chargé.</li>
          <li>Le footer ne compte pas comme bloc. Le header non plus.</li>
        </ul>
      </div>
    </section>
  );
}

/* ───────────────────────────────────────────────────────────────────────
   PLANCHE 5 — Le composant principal
   ─────────────────────────────────────────────────────────────────────── */

function Pack7DesignPatterns() {
  return (
    <div style={{
      background: "white",
      border: `1px solid ${P7_TOKEN.border}`,
      borderRadius: 16,
      padding: "24px 24px 28px",
    }}>
      <P7Hero />

      {/* Bloc-by-bloc */}
      <section>
        <div style={{
          display: "flex", justifyContent: "space-between", alignItems: "baseline",
          marginBottom: 14,
        }}>
          <h2 style={{ fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 24, color: "var(--ae-primary-deep)", margin: 0 }}>
            Les 18 blocs autorisés
          </h2>
          <span style={{ fontSize: 12, color: P7_TOKEN.muted }}>Bloc → règles → standard + compact</span>
        </div>
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          {BLOCKS.map(b => <P7Card key={b.num} {...b} />)}
        </div>
      </section>

      {/* OK */}
      <section style={{ marginTop: 32 }}>
        <h2 style={{ fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 24, color: "var(--ae-success)", margin: "0 0 4px" }}>
          Combinaisons recommandées par page
        </h2>
        <p style={{ margin: "0 0 14px", color: P7_TOKEN.inkSoft, fontSize: 14, maxWidth: 820, lineHeight: 1.55 }}>
          Cinq compositions canoniques. Reprends-les telles quelles plutôt que d'inventer.
        </p>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))", gap: 14 }}>
          {COMPOSITIONS_OK.map((c, i) => <PageMock key={i} verdict="ok" {...c} />)}
        </div>
      </section>

      {/* KO */}
      <section style={{ marginTop: 32 }}>
        <h2 style={{ fontFamily: "var(--ae-font-title)", fontWeight: 700, fontSize: 24, color: "var(--ae-error)", margin: "0 0 4px" }}>
          Combinaisons à éviter
        </h2>
        <p style={{ margin: "0 0 14px", color: P7_TOKEN.inkSoft, fontSize: 14, maxWidth: 820, lineHeight: 1.55 }}>
          Cinq combinaisons que l'auditeur PDF doit rejeter automatiquement.
        </p>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))", gap: 14 }}>
          {COMPOSITIONS_KO.map((c, i) => <PageMock key={i} verdict="ko" {...c} />)}
        </div>
      </section>

      {/* Spacing */}
      <P7Spacing />

      {/* Closer */}
      <div style={{
        marginTop: 28, padding: "16px 18px",
        background: "linear-gradient(180deg, var(--ae-yellow-soft), white)",
        border: "1.5px solid var(--ae-yellow-dark)",
        borderRadius: 12,
      }}>
        <div style={{ fontWeight: 800, color: "var(--ae-yellow-dark)", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 4 }}>
          Pourquoi cette planche existe
        </div>
        <p style={{ margin: 0, fontSize: 14, color: P7_TOKEN.inkSoft, lineHeight: 1.6, maxWidth: 820 }}>
          Cette planche n'est pas une page de livre. C'est l'outil de référence partagé entre rédacteur,
          dev et auditeur PDF. Si un nouveau template doit naître, il <b>commence</b> ici : choisis 3 à 5
          blocs autorisés, vérifie les compositions OK / KO, applique la densité, puis seulement écris le contenu.
        </p>
      </div>
    </div>
  );
}

Object.assign(window, { Pack7DesignPatterns, P7_BLOCKS: BLOCKS });
