// template-composition-rules.jsx
// CHARTE D'ESPACEMENT — Grammaire officielle de la page Allo Education Books v1.3
// CE N'EST PAS UN PACK DE TEMPLATES. C'est la règle qui gouverne TOUS les templates.

const CR_C = {
  ink:    "var(--ae-text)",
  inkSoft:"var(--ae-text-soft)",
  muted:  "var(--ae-muted)",
  border: "var(--ae-border)",
  primary:"var(--ae-primary)",
  primaryDeep:"var(--ae-primary-deep)",
  ok:     "var(--ae-success)",
  ko:     "var(--ae-error)",
  warn:   "var(--ae-yellow-dark)",
};

/* ─── Petits primitives visuels (planche, pas page réelle) ─────────── */

function CRChip({ tone = "primary", children }) {
  const map = {
    primary:["var(--ae-primary-soft)","var(--ae-primary)"],
    yellow: ["var(--ae-yellow-soft)","#7a5a1c"],
    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)"],
  };
  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",
  }}>{children}</span>;
}

function CRToken({ name, value, role }) {
  return (
    <div style={{
      display:"grid", gridTemplateColumns:"180px 80px 1fr", alignItems:"baseline",
      padding:"8px 10px", borderBottom:`1px dashed ${CR_C.border}`, fontSize:13,
    }}>
      <code style={{ fontFamily:"var(--ae-font-mono)", color:CR_C.primaryDeep, fontWeight:700 }}>{name}</code>
      <span style={{ fontFamily:"var(--ae-font-mono)", color:CR_C.primary, fontWeight:700 }}>{value}</span>
      <span style={{ color:CR_C.inkSoft, lineHeight:1.55 }}>{role}</span>
    </div>
  );
}

function CRMeasure({ label, value, vertical, length = 60 }) {
  if (vertical) {
    return (
      <div style={{ display:"inline-flex", alignItems:"center", gap:6 }}>
        <svg width={20} height={length} style={{ flexShrink:0 }}>
          <line x1="10" y1="2" x2="10" y2={length-2} stroke={CR_C.primary} strokeWidth="1.5" />
          <polygon points={`6,8 10,2 14,8`} fill={CR_C.primary} />
          <polygon points={`6,${length-8} 10,${length-2} 14,${length-8}`} fill={CR_C.primary} />
        </svg>
        <div style={{ fontFamily:"var(--ae-font-mono)", fontSize:10.5, color:CR_C.primary, fontWeight:700 }}>
          <div>{label}</div>
          <div style={{ color:CR_C.muted, fontWeight:600 }}>{value}</div>
        </div>
      </div>
    );
  }
  return null;
}

/* ─── 1. Anatomie d'une page ──────────────────────────────────────── */

function CRPageAnatomy() {
  // SVG annoté : page 8.5×11 réduite à 320×420 (ratio respecté)
  const W = 340, H = 440;
  const margin = 18;
  const headerH = 38;
  const titleH = 30;
  const footerH = 30;
  const contentTop = margin + headerH + 10;
  const contentBottom = H - margin - footerH - 10;

  return (
    <div style={{
      display:"grid", gridTemplateColumns:"auto 1fr", gap:24,
      padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14,
    }}>
      <svg viewBox={`0 0 ${W+120} ${H+20}`} style={{ width:W+120, height:H+20 }}>
        {/* Page sheet */}
        <rect x="10" y="10" width={W} height={H} fill="white" stroke={CR_C.border} strokeWidth="1.5" rx="4" />

        {/* Header */}
        <rect x="10" y="10" width={W} height={headerH} fill="var(--ae-primary-deep)" rx="4" />
        <text x={10+W/2} y={10+headerH/2+4} textAnchor="middle" fill="white" fontSize="11" fontWeight="700">HEADER · matière · niveau · page</text>

        {/* Title zone */}
        <rect x={margin+10} y={contentTop} width={W-margin*2} height={titleH} fill="var(--ae-orange-soft)" stroke="var(--ae-orange-dark)" strokeWidth="1" strokeDasharray="3 2" rx="3" />
        <text x={20+margin} y={contentTop+18} fill="var(--ae-orange-dark)" fontSize="10" fontWeight="800">PAGE TITLE  (eyebrow + titre + sous-titre)</text>

        {/* First major block */}
        <rect x={margin+10} y={contentTop+titleH+18} width={W-margin*2} height="56" fill="var(--ae-primary-soft)" stroke="var(--ae-primary)" strokeWidth="1.2" rx="6" />
        <text x={20+margin} y={contentTop+titleH+18+30} fill="var(--ae-primary-deep)" fontSize="10" fontWeight="700">BLOC MAJEUR · Objectif</text>

        {/* Second block */}
        <rect x={margin+10} y={contentTop+titleH+18+70} width={W-margin*2} height="78" fill="var(--ae-yellow-soft)" stroke="var(--ae-yellow-dark)" strokeWidth="1.2" rx="6" />
        <text x={20+margin} y={contentTop+titleH+18+90} fill="#7a5a1c" fontSize="10" fontWeight="700">BLOC MAJEUR · À retenir</text>

        {/* Third block */}
        <rect x={margin+10} y={contentTop+titleH+18+162} width={W-margin*2} height="96" fill="var(--ae-success-soft)" stroke={CR_C.ok} strokeWidth="1.2" rx="6" />
        <text x={20+margin} y={contentTop+titleH+18+178} fill={CR_C.ok} fontSize="10" fontWeight="700">BLOC MAJEUR · Exercice</text>

        {/* Footer safe area */}
        <rect x={margin+10} y={contentBottom-22} width={W-margin*2} height="20" fill="white" stroke={CR_C.warn} strokeWidth="1" strokeDasharray="2 2" rx="3" />
        <text x={20+margin} y={contentBottom-9} fill={CR_C.warn} fontSize="9" fontWeight="800">⛔ ZONE TAMPON · footer-safe-gap</text>

        {/* Footer */}
        <rect x="10" y={H+10-footerH} width={W} height={footerH} fill="var(--ae-primary-deep)" opacity="0.85" rx="4" />
        <text x={10+W/2} y={H+10-footerH/2+4} textAnchor="middle" fill="white" fontSize="11" fontWeight="700">FOOTER · score · QR · pagination</text>

        {/* MEASURE GUIDES (right side) */}
        {/* page-header-gap */}
        <line x1={W+22} y1={10+headerH} x2={W+22} y2={contentTop} stroke={CR_C.primary} strokeWidth="1" />
        <polygon points={`${W+18},${10+headerH+4} ${W+22},${10+headerH} ${W+26},${10+headerH+4}`} fill={CR_C.primary} />
        <polygon points={`${W+18},${contentTop-4} ${W+22},${contentTop} ${W+26},${contentTop-4}`} fill={CR_C.primary} />
        <text x={W+30} y={(10+headerH+contentTop)/2+4} fontSize="9" fontWeight="700" fill={CR_C.primary}>page-header-gap</text>
        <text x={W+30} y={(10+headerH+contentTop)/2+15} fontSize="9" fill={CR_C.muted}>0.40 in</text>

        {/* page-title-gap */}
        <line x1={W+22} y1={contentTop+titleH} x2={W+22} y2={contentTop+titleH+18} stroke={CR_C.primary} strokeWidth="1" />
        <text x={W+30} y={contentTop+titleH+13} fontSize="9" fontWeight="700" fill={CR_C.primary}>page-title-gap · 0.22 in</text>

        {/* block-gap-md */}
        <line x1={W+22} y1={contentTop+titleH+18+56} x2={W+22} y2={contentTop+titleH+18+70} stroke={CR_C.primary} strokeWidth="1" />
        <text x={W+30} y={contentTop+titleH+18+67} fontSize="9" fontWeight="700" fill={CR_C.primary}>block-gap-md · 0.24 in</text>

        {/* block-gap-lg */}
        <line x1={W+22} y1={contentTop+titleH+18+148} x2={W+22} y2={contentTop+titleH+18+162} stroke="var(--ae-orange-dark)" strokeWidth="1.4" />
        <text x={W+30} y={contentTop+titleH+18+158} fontSize="9" fontWeight="700" fill="var(--ae-orange-dark)">block-gap-lg · 0.34 in</text>

        {/* footer-safe-gap */}
        <line x1={W+22} y1={contentBottom-22} x2={W+22} y2={H+10-footerH} stroke={CR_C.warn} strokeWidth="1.4" />
        <text x={W+30} y={contentBottom-5} fontSize="9" fontWeight="800" fill={CR_C.warn}>footer-safe-gap · 0.30 in</text>
      </svg>

      <div style={{ display:"flex", flexDirection:"column", gap:12, paddingTop:6 }}>
        <h3 style={{ margin:0, fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
          1. Anatomie d'une page
        </h3>
        <p style={{ margin:0, fontSize:13.5, lineHeight:1.6, color:CR_C.inkSoft }}>
          Une page Allo Education Books est <b>toujours</b> structurée selon cette anatomie. Aucun
          template n'a le droit d'inventer ses propres marges, son propre header, ni de toucher au
          footer.
        </p>
        <ul style={{ margin:0, paddingLeft:18, fontSize:13, lineHeight:1.75, color:CR_C.ink }}>
          <li><b>Header (0.95 in)</b> — bandeau bleu fixe, matière + niveau + n° de page.</li>
          <li><b>Page title</b> — eyebrow + titre + sous-titre, séparé du header par <code>page-header-gap</code>.</li>
          <li><b>Zone contenu</b> — uniquement des blocs autorisés, espacés par les tokens.</li>
          <li><b>Zone tampon (0.30 in)</b> — <span style={{color:CR_C.warn,fontWeight:800}}>obligatoire</span> avant le footer. Aucun bloc n'a le droit de la traverser.</li>
          <li><b>Footer (0.85 in)</b> — score, QR Ketty, pagination. Inchangé d'une page à l'autre.</li>
        </ul>
        <div style={{
          padding:"10px 12px", background:"var(--ae-yellow-soft)", border:`1.5px solid var(--ae-yellow-dark)`,
          borderRadius:10, fontSize:12.5, color:"#7a5a1c", lineHeight:1.55,
        }}>
          <b>Règle d'or</b> : si un bloc empiète sur la zone tampon, la page est invalide. On split en deux pages
          ou on passe la densité d'air → standard, ou standard → dense.
        </div>
      </div>
    </div>
  );
}

/* ─── 2. Anatomie d'un bloc ──────────────────────────────────────── */

function CRBlockAnatomy() {
  const W = 360, H = 240;
  return (
    <div style={{
      display:"grid", gridTemplateColumns:"auto 1fr", gap:24,
      padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14,
    }}>
      <svg viewBox={`0 0 ${W+150} ${H+30}`} style={{ width:W+150, height:H+30 }}>
        <defs>
          <pattern id="grid-pad" width="6" height="6" patternUnits="userSpaceOnUse">
            <rect width="6" height="6" fill="var(--ae-primary-soft)" />
            <line x1="0" y1="0" x2="6" y2="6" stroke="var(--ae-primary)" strokeWidth="0.3" opacity="0.4" />
          </pattern>
        </defs>

        {/* Outer block */}
        <rect x="10" y="20" width={W} height={H} fill="white" stroke={CR_C.primary} strokeWidth="1.5" rx="10" />

        {/* Tab */}
        <rect x="22" y="6" width="120" height="22" fill={CR_C.primary} rx="5" />
        <text x="82" y="21" textAnchor="middle" fill="white" fontSize="11" fontWeight="800">EXERCICE 1</text>

        {/* Padding regions */}
        <rect x="10" y="20" width={W} height="22" fill="url(#grid-pad)" opacity="0.6" />
        <rect x="10" y={20+H-22} width={W} height="22" fill="url(#grid-pad)" opacity="0.6" />
        <rect x="10" y="20" width="22" height={H} fill="url(#grid-pad)" opacity="0.4" />
        <rect x={W-12} y="20" width="22" height={H} fill="url(#grid-pad)" opacity="0.4" />

        {/* Tab clearance */}
        <line x1="40" y1="42" x2={W-20} y2="42" stroke="var(--ae-orange-dark)" strokeDasharray="3 3" />

        {/* Body content (mock text) */}
        <text x="42" y="68" fill={CR_C.ink} fontSize="11" fontWeight="700">Consigne · 1 ligne d'explication.</text>
        <line x1="42" y1="86"  x2={W-30} y2="86"  stroke={CR_C.border} />
        <line x1="42" y1="106" x2={W-30} y2="106" stroke={CR_C.border} />
        <line x1="42" y1="126" x2={W-30} y2="126" stroke={CR_C.border} />
        <line x1="42" y1="146" x2={W-30} y2="146" stroke={CR_C.border} />
        <line x1="42" y1="166" x2={W-30} y2="166" stroke={CR_C.border} />
        <line x1="42" y1="186" x2={W-30} y2="186" stroke={CR_C.border} />

        {/* Annotations */}
        {/* padding-y top */}
        <line x1={W+22} y1="20" x2={W+22} y2="42" stroke={CR_C.primary} strokeWidth="1" />
        <text x={W+30} y="36" fontSize="9" fontWeight="700" fill={CR_C.primary}>block-padding-y · 0.18 in</text>

        {/* tab clearance */}
        <line x1={W+22} y1="42" x2={W+22} y2="56" stroke="var(--ae-orange-dark)" strokeWidth="1" />
        <text x={W+30} y="53" fontSize="9" fontWeight="700" fill="var(--ae-orange-dark)">block-tab-clear · 0.12 in</text>

        {/* intra-block-gap */}
        <line x1={W+22} y1="106" x2={W+22} y2="126" stroke={CR_C.ok} strokeWidth="1" />
        <text x={W+30} y="120" fontSize="9" fontWeight="700" fill={CR_C.ok}>intra-block-gap · 0.10 in</text>

        {/* padding-y bottom */}
        <line x1={W+22} y1={20+H-22} x2={W+22} y2={20+H} stroke={CR_C.primary} strokeWidth="1" />
        <text x={W+30} y={20+H-8} fontSize="9" fontWeight="700" fill={CR_C.primary}>block-padding-y · 0.18 in</text>

        {/* padding-x */}
        <line x1="10" y1={H+24} x2="32" y2={H+24} stroke={CR_C.primary} strokeWidth="1" />
        <text x="36" y={H+28} fontSize="9" fontWeight="700" fill={CR_C.primary}>block-padding-x · 0.20 in</text>
      </svg>

      <div style={{ display:"flex", flexDirection:"column", gap:12, paddingTop:6 }}>
        <h3 style={{ margin:0, fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
          2. Anatomie d'un bloc
        </h3>
        <p style={{ margin:0, fontSize:13.5, lineHeight:1.6, color:CR_C.inkSoft }}>
          Un bloc est <b>toujours</b> construit avec : un onglet (label), un clearance, un corps. Le texte
          du corps ne doit jamais lécher un bord.
        </p>
        <ul style={{ margin:0, paddingLeft:18, fontSize:12.8, lineHeight:1.7, color:CR_C.ink }}>
          <li><b>block-padding-y</b> · 0.18 in (haut/bas) — fixe.</li>
          <li><b>block-padding-x</b> · 0.20 in (gauche/droite) — fixe.</li>
          <li><b>block-tab-clear</b> · 0.12 in — clearance sous l'onglet, indispensable.</li>
          <li><b>intra-block-gap</b> · 0.10 in — entre 2 lignes/items d'un même bloc.</li>
          <li><b>min-height</b> · 0.46 in — pas de bloc plus court (sinon → ligne, pas bloc).</li>
        </ul>
        <div style={{
          padding:"10px 12px", background:"var(--ae-success-soft)", border:`1.5px solid ${CR_C.ok}`,
          borderRadius:10, fontSize:12.5, color:CR_C.ok, lineHeight:1.55,
        }}>
          <b>Court ou long</b>, c'est le bloc qui s'adapte — pas ses paddings. Si le contenu est très long,
          il rallonge le bloc. Si très court, le bloc garde sa min-height, le texte est centré.
        </div>
      </div>
    </div>
  );
}

/* ─── 3. Hiérarchie d'espacement entre blocs ─────────────────────── */

function GapDemo({ label, value, color }) {
  return (
    <div style={{ display:"flex", flexDirection:"column", gap:6 }}>
      <div style={{
        fontSize:10, fontWeight:800, letterSpacing:"0.08em", textTransform:"uppercase",
        color, fontFamily:"var(--ae-font-mono)",
      }}>{label} · {value}</div>
      <div style={{ display:"flex", flexDirection:"column" }}>
        <div style={{ height:28, background:"var(--ae-primary-soft)", border:`1.2px solid ${CR_C.primary}`, borderRadius:6, padding:"4px 8px", fontSize:10.5, color:CR_C.primaryDeep, fontWeight:700, display:"flex", alignItems:"center" }}>Bloc A</div>
        <div style={{
          height: value === "0.10 in" ? 6 : value === "0.16 in" ? 11 : value === "0.24 in" ? 17 : value === "0.34 in" ? 24 : 30,
          borderLeft:`2px solid ${color}`,
          marginLeft:14,
          position:"relative",
        }}>
          <span style={{ position:"absolute", left:8, top:"50%", transform:"translateY(-50%)", fontSize:9.5, color, fontWeight:700, whiteSpace:"nowrap" }}>{value}</span>
        </div>
        <div style={{ height:28, background:"var(--ae-yellow-soft)", border:`1.2px solid var(--ae-yellow-dark)`, borderRadius:6, padding:"4px 8px", fontSize:10.5, color:"#7a5a1c", fontWeight:700, display:"flex", alignItems:"center" }}>Bloc B</div>
      </div>
    </div>
  );
}

function CRGapHierarchy() {
  return (
    <div style={{ padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14 }}>
      <h3 style={{ margin:"0 0 4px", fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
        3. Hiérarchie d'espacement entre blocs
      </h3>
      <p style={{ margin:"0 0 18px", fontSize:13.5, color:CR_C.inkSoft, lineHeight:1.6, maxWidth:820 }}>
        Cinq niveaux d'espacement, à choisir <b>selon la relation</b> entre deux blocs. Jamais d'espacement improvisé.
      </p>
      <div style={{ display:"grid", gridTemplateColumns:"repeat(5, 1fr)", gap:18 }}>
        <GapDemo label="intra-block" value="0.10 in" color={CR_C.ok} />
        <GapDemo label="block-gap-sm" value="0.16 in" color={CR_C.muted} />
        <GapDemo label="block-gap-md" value="0.24 in" color={CR_C.primary} />
        <GapDemo label="block-gap-lg" value="0.34 in" color="var(--ae-orange-dark)" />
        <GapDemo label="section-gap" value="0.42 in" color={CR_C.warn} />
      </div>

      <div style={{ marginTop:22, padding:"14px 16px", background:"var(--ae-bg-cool)", border:`1px solid ${CR_C.border}`, borderRadius:10 }}>
        <div style={{ fontSize:11, fontWeight:800, letterSpacing:"0.1em", textTransform:"uppercase", color:CR_C.primary, marginBottom:8 }}>Quand utiliser quoi</div>
        <table style={{ width:"100%", borderCollapse:"collapse", fontSize:12.5 }}>
          <thead><tr>
            <th style={{ textAlign:"left", padding:"6px 8px", borderBottom:`1px solid ${CR_C.border}`, color:CR_C.muted, fontWeight:700 }}>Relation entre les deux blocs</th>
            <th style={{ textAlign:"left", padding:"6px 8px", borderBottom:`1px solid ${CR_C.border}`, color:CR_C.muted, fontWeight:700 }}>Espacement</th>
            <th style={{ textAlign:"left", padding:"6px 8px", borderBottom:`1px solid ${CR_C.border}`, color:CR_C.muted, fontWeight:700 }}>Exemple</th>
          </tr></thead>
          <tbody>
            {[
              ["Lignes d'un même bloc","intra-block-gap","Items d'une liste Méthode"],
              ["2 blocs mineurs liés","block-gap-sm","Ketty mini + QR mini"],
              ["2 blocs majeurs liés","block-gap-md","Objectif → À retenir"],
              ["Changement de pédagogie","block-gap-lg","À retenir → Exercice 1"],
              ["Nouvelle section","section-gap","Cours → Exercices · Exercice → Bilan"],
              ["Avant footer","footer-safe-gap","Dernier bloc → footer (obligatoire)"],
            ].map(([a,b,c]) => (
              <tr key={a}>
                <td style={{ padding:"6px 8px", borderBottom:`1px dashed ${CR_C.border}` }}>{a}</td>
                <td style={{ padding:"6px 8px", borderBottom:`1px dashed ${CR_C.border}`, fontFamily:"var(--ae-font-mono)", fontWeight:700, color:CR_C.primary }}>{b}</td>
                <td style={{ padding:"6px 8px", borderBottom:`1px dashed ${CR_C.border}`, color:CR_C.inkSoft }}>{c}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

/* ─── 4. Blocs majeurs vs mineurs ───────────────────────────────── */

function BlockChip({ name, kind }) {
  const ok = kind === "major";
  return (
    <div style={{
      padding:"10px 12px",
      background: ok ? "var(--ae-primary-soft)" : "var(--ae-bg-cool)",
      border:`1.5px ${ok ? "solid" : "dashed"} ${ok ? CR_C.primary : CR_C.border}`,
      borderRadius:10,
      fontWeight: ok ? 800 : 600,
      color: ok ? CR_C.primaryDeep : CR_C.inkSoft,
      fontSize:12.5,
      display:"flex", alignItems:"center", gap:8,
    }}>
      <span style={{
        width:8, height:8, borderRadius:999,
        background: ok ? CR_C.primary : CR_C.muted,
      }} />
      {name}
    </div>
  );
}

function CRMajorMinor() {
  return (
    <div style={{ padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14 }}>
      <h3 style={{ margin:"0 0 4px", fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
        4. Blocs majeurs vs blocs mineurs
      </h3>
      <p style={{ margin:"0 0 14px", fontSize:13.5, color:CR_C.inkSoft, lineHeight:1.6, maxWidth:820 }}>
        Tous les blocs n'ont pas le même poids visuel. Cette distinction conditionne l'espacement.
      </p>
      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:18 }}>
        <div>
          <div style={{ fontSize:11, fontWeight:800, letterSpacing:"0.1em", textTransform:"uppercase", color:CR_C.primary, marginBottom:10 }}>Blocs majeurs</div>
          <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:8 }}>
            {["Objectif","À retenir","Exemple guidé","Exercice principal","Problème guidé","Bilan","Correction","Mini-sujet"]
              .map(n => <BlockChip key={n} name={n} kind="major" />)}
          </div>
        </div>
        <div>
          <div style={{ fontSize:11, fontWeight:800, letterSpacing:"0.1em", textTransform:"uppercase", color:CR_C.muted, marginBottom:10 }}>Blocs mineurs</div>
          <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:8 }}>
            {["Mini-rappel","Astuce courte","Check rapide","Ligne de réponse","Micro-consigne","QR compact","Ketty mini","Note de bas"]
              .map(n => <BlockChip key={n} name={n} kind="minor" />)}
          </div>
        </div>
      </div>
      <div style={{
        marginTop:14, padding:"10px 12px", background:"var(--ae-error-soft)",
        border:`1.5px solid ${CR_C.ko}`, borderRadius:10, fontSize:13, color:CR_C.ko, lineHeight:1.55,
      }}>
        <b>Règle non négociable</b> · deux blocs majeurs ne doivent jamais être visuellement collés.
        Entre eux : <code style={{ background:"white", padding:"1px 5px", borderRadius:4 }}>block-gap-md</code> minimum,
        <code style={{ background:"white", padding:"1px 5px", borderRadius:4 }}>block-gap-lg</code> si changement de pédagogie.
      </div>
    </div>
  );
}

/* ─── 5. Densités ───────────────────────────────────────────────── */

function DensityCard({ name, gap, padding, gapMd, useCase, color }) {
  return (
    <div style={{ padding:"14px 16px", background:"white", border:`1.5px solid ${color}`, borderRadius:12, display:"flex", flexDirection:"column", gap:10 }}>
      <div>
        <div style={{ fontSize:10.5, fontWeight:800, letterSpacing:"0.1em", textTransform:"uppercase", color }}>{useCase}</div>
        <div style={{ fontFamily:"var(--ae-font-title)", fontSize:20, fontWeight:700, color:CR_C.primaryDeep }}>{name}</div>
      </div>
      <div style={{ display:"flex", flexDirection:"column", gap:6, fontFamily:"var(--ae-font-mono)", fontSize:11.5, color:CR_C.inkSoft }}>
        <div>--ae-block-gap : <b style={{ color }}>{gap}</b></div>
        <div>--block-gap-md : <b style={{ color }}>{gapMd}</b></div>
        <div>--block-padding-y : <b style={{ color }}>{padding}</b></div>
      </div>
      {/* visual */}
      <div style={{ marginTop:4, padding:8, background:"var(--ae-bg-cool)", borderRadius:8, display:"flex", flexDirection:"column", gap }}>
        {[1,2,3].map(i => (
          <div key={i} style={{ height:18, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:4 }} />
        ))}
      </div>
    </div>
  );
}

function CRDensity() {
  return (
    <div style={{ padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14 }}>
      <h3 style={{ margin:"0 0 4px", fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
        5. Trois densités, jamais plus
      </h3>
      <p style={{ margin:"0 0 16px", fontSize:13.5, color:CR_C.inkSoft, lineHeight:1.6, maxWidth:820 }}>
        Même en densité <i>dense</i>, la séparation visuelle entre blocs reste obligatoire. La densité
        ajuste les marges, pas la hiérarchie.
      </p>
      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr 1fr", gap:16 }}>
        <DensityCard name="Air" gap="0.28 in" padding="0.20 in" gapMd="0.28 in" useCase="CP · CE1 · pages d'écriture" color="var(--ae-success)" />
        <DensityCard name="Standard" gap="0.24 in" padding="0.18 in" gapMd="0.24 in" useCase="Collège · brevet · défaut" color="var(--ae-primary)" />
        <DensityCard name="Dense" gap="0.14 in" padding="0.11 in" gapMd="0.14 in" useCase="Corrigés · mini-sujets" color="var(--ae-orange-dark)" />
      </div>
    </div>
  );
}

/* ─── 6. Exemples Bon / Mauvais ─────────────────────────────────── */

function PageMockup({ verdict, label, sub, gap = 8, pad = 8, blocks, footerGap = 12 }) {
  const tone = verdict === "ok" ? CR_C.ok : CR_C.ko;
  return (
    <div style={{ border:`2px solid ${tone}`, borderRadius:10, background:"white", overflow:"hidden" }}>
      <div style={{ background:tone, color:"white", padding:"5px 10px", fontSize:10.5, fontWeight:800, letterSpacing:"0.08em", textTransform:"uppercase", display:"flex", justifyContent:"space-between" }}>
        <span>{verdict === "ok" ? "✓ Bon" : "✕ Mauvais"}</span>
        <span>{label}</span>
      </div>
      <div style={{ padding:12, display:"flex", flexDirection:"column", gap:6 }}>
        <div style={{ fontSize:11.5, color:CR_C.inkSoft, lineHeight:1.5 }}>{sub}</div>
        <div style={{ aspectRatio:"8.5 / 11", background:"var(--ae-bg-cool)", border:`1px solid ${CR_C.border}`, borderRadius:6, padding:6, display:"flex", flexDirection:"column", gap:3 }}>
          {/* header */}
          <div style={{ height:10, background:"var(--ae-primary-deep)", borderRadius:2 }} />
          {/* body */}
          <div style={{ flex:1, display:"flex", flexDirection:"column", gap, padding: pad }}>
            {blocks.map((b,i) => (
              <div key={i} style={{
                flex: b.flex || 1,
                background: b.bg, border:`1px ${b.dashed?"dashed":"solid"} ${b.border}`,
                borderRadius:3, padding: b.pad || "3px 5px",
                fontSize:8.5, fontWeight:700, color:b.fg, letterSpacing:"0.03em",
                display:"flex", alignItems:"center",
              }}>{b.label}</div>
            ))}
            <div style={{ height: footerGap }} />
          </div>
          {/* footer */}
          <div style={{ height:10, background:"var(--ae-primary-deep)", opacity:0.85, borderRadius:2 }} />
        </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 blkRed = (label, opts={}) => ({ label, bg:"var(--ae-error-soft)", border:"var(--ae-error)", fg:"var(--ae-error)", ...opts });
const blkOr = (label, opts={}) => ({ label, bg:"var(--ae-orange-soft)", border:"var(--ae-orange-dark)", fg:"var(--ae-orange-dark)", ...opts });

const COMPARISONS = [
  // pair 1 : gap
  {
    bad: { label:"Blocs collés", sub:"Tous les blocs se touchent. Aucune respiration. Le lecteur ne voit plus la hiérarchie.",
      gap:2, pad:6, footerGap:6,
      blocks:[blkRed("Objectif"),blkRed("À retenir"),blkRed("Exemple"),blkRed("Exercice 1"),blkRed("Exercice 2"),blkRed("Bilan")] },
    good: { label:"Espace équilibré", sub:"Gap = block-gap-md entre blocs majeurs. Le rythme visuel respire et hiérarchise.",
      gap:10, pad:8, footerGap:14,
      blocks:[blkOK("Objectif",{flex:0.6}),blkYel("À retenir",{flex:1.1}),blkOr("Exemple",{flex:1}),blkOK("Exercice 1",{flex:1.3})] },
  },
  // pair 2 : padding interne
  {
    bad: { label:"Texte qui lèche le bord", sub:"Padding interne nul. Le texte touche le cadre. Impression d'arrachement, illisible.",
      gap:8, pad:6, footerGap:10,
      blocks:[blkRed("Objectif · Texte AU BORD DU CADRE",{pad:"0 0"}),blkRed("À retenir · texte qui touche",{pad:"0 0"})] },
    good: { label:"Padding confortable", sub:"block-padding-x = 0.20 in, block-padding-y = 0.18 in. Le texte respire dans son cadre.",
      gap:8, pad:8, footerGap:10,
      blocks:[blkOK("· Objectif (0.20 in inset) ·"),blkYel("· À retenir (0.20 in inset) ·")] },
  },
  // pair 3 : footer
  {
    bad: { label:"Footer écrasé", sub:"Le dernier bloc touche le footer. Le QR du footer paraît être dans le bloc.",
      gap:8, pad:6, footerGap:0,
      blocks:[blkOK("Objectif",{flex:0.6}),blkYel("À retenir",{flex:1}),blkRed("Exercice (colle le footer)",{flex:1.6})] },
    good: { label:"Zone tampon avant footer", sub:"footer-safe-gap = 0.30 in. Le footer redevient lisible et autonome.",
      gap:8, pad:6, footerGap:16,
      blocks:[blkOK("Objectif",{flex:0.6}),blkYel("À retenir",{flex:1}),blkOK("Exercice",{flex:1.4})] },
  },
  // pair 4 : page vide
  {
    bad: { label:"Page trop vide", sub:"Deux petits blocs en haut, énorme trou blanc. Donne l'impression d'une page bâclée.",
      gap:8, pad:6, footerGap:60,
      blocks:[blkOK("Objectif",{flex:0.5}),blkYel("À retenir",{flex:0.7})] },
    good: { label:"Dernier bloc absorbe l'espace", sub:"Le bloc principal porte .ae-grow. Sa zone de réponse s'étire. Plus de trou.",
      gap:10, pad:6, footerGap:14,
      blocks:[blkOK("Objectif",{flex:0.5}),blkYel("À retenir",{flex:0.7}),blkOK("Exercice · zone réponse étirée",{flex:2.5})] },
  },
];

function CRGoodBad() {
  return (
    <div style={{ padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14 }}>
      <h3 style={{ margin:"0 0 4px", fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
        6. Bons vs mauvais exemples
      </h3>
      <p style={{ margin:"0 0 16px", fontSize:13.5, color:CR_C.inkSoft, lineHeight:1.6, maxWidth:820 }}>
        Quatre paires côte-à-côte. Mauvais à gauche, bon à droite. À mémoriser visuellement plutôt qu'en règle.
      </p>
      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:16 }}>
        {COMPARISONS.map((pair,i) => (
          <React.Fragment key={i}>
            <PageMockup verdict="ko" {...pair.bad} />
            <PageMockup verdict="ok" {...pair.good} />
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

/* ─── 7. Règles anti-overflow ───────────────────────────────────── */

function CRAntiOverflow() {
  const items = [
    { rule:"Si la page dépasse → la page est invalide", explain:"Aucun contenu n'est silencieusement coupé. La page est rejetée à l'audit." },
    { rule:"On ne colle pas les blocs pour faire rentrer", explain:"Ne jamais descendre sous block-gap-sm. Si ça ne rentre pas avec md, on change de densité." },
    { rule:"D'abord : essayer la version compacte", explain:"Chaque bloc a une variante compacte documentée dans Pack 7. C'est le premier réflexe." },
    { rule:"Ensuite : passer en densité dense", explain:"Cela touche tous les tokens d'espacement, en cohérence. Jamais d'override local." },
    { rule:"Si encore overflow → split en 2 pages", explain:"Deux pages aérées valent mieux qu'une page écrasée. C'est la règle finale, sans exception." },
    { rule:"Zone tampon footer non négociable", explain:"footer-safe-gap = 0.30 in. Aucun bloc n'entre dedans. L'auditeur PDF rejette automatiquement." },
  ];
  return (
    <div style={{ padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14 }}>
      <h3 style={{ margin:"0 0 4px", fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
        7. Règles anti-overflow
      </h3>
      <p style={{ margin:"0 0 16px", fontSize:13.5, color:CR_C.inkSoft, lineHeight:1.6, maxWidth:820 }}>
        L'ordre exact à suivre quand un contenu déborde. Pas de bricolage local : on respecte cette chaîne, dans cet ordre.
      </p>
      <ol style={{ margin:0, padding:0, listStyle:"none", display:"flex", flexDirection:"column", gap:10 }}>
        {items.map((it,i) => (
          <li key={i} style={{
            display:"grid", gridTemplateColumns:"36px 1fr", gap:14,
            padding:"12px 14px", background:"var(--ae-bg-cool)", border:`1px solid ${CR_C.border}`, borderRadius:10,
          }}>
            <div style={{
              width:32, height:32, borderRadius:999, background:CR_C.primary, color:"white",
              display:"grid", placeItems:"center", fontFamily:"var(--ae-font-mono)", fontWeight:800, fontSize:14,
            }}>{i+1}</div>
            <div>
              <div style={{ fontWeight:800, color:CR_C.primaryDeep, fontSize:14 }}>{it.rule}</div>
              <div style={{ fontSize:12.5, color:CR_C.inkSoft, marginTop:2, lineHeight:1.55 }}>{it.explain}</div>
            </div>
          </li>
        ))}
      </ol>
    </div>
  );
}

/* ─── 8. Tokens officiels ───────────────────────────────────────── */

function CRTokens() {
  return (
    <div style={{ padding:20, background:"white", border:`1px solid ${CR_C.border}`, borderRadius:14 }}>
      <h3 style={{ margin:"0 0 4px", fontFamily:"var(--ae-font-title)", fontSize:22, color:CR_C.primaryDeep, fontWeight:700 }}>
        8. Tokens de spacing officiels
      </h3>
      <p style={{ margin:"0 0 16px", fontSize:13.5, color:CR_C.inkSoft, lineHeight:1.6, maxWidth:820 }}>
        Onze variables CSS, livrées en V1.3, à utiliser dans <b>tous</b> les templates. Plus jamais
        de pixels ou d'inches en dur dans un template.
      </p>
      <div style={{ background:"var(--ae-bg-cool)", border:`1px solid ${CR_C.border}`, borderRadius:10, overflow:"hidden" }}>
        <div style={{ display:"grid", gridTemplateColumns:"180px 80px 1fr", padding:"8px 10px", background:CR_C.primaryDeep, color:"white", fontSize:10.5, fontWeight:800, letterSpacing:"0.08em", textTransform:"uppercase" }}>
          <span>Token</span><span>Valeur</span><span>Rôle</span>
        </div>
        <CRToken name="--page-header-gap"  value="0.40 in" role="Entre le header bleu et le PageTitle." />
        <CRToken name="--page-title-gap"   value="0.22 in" role="Entre le PageTitle et le premier bloc majeur." />
        <CRToken name="--intra-block-gap"  value="0.10 in" role="Entre items / lignes d'un même bloc." />
        <CRToken name="--block-gap-sm"     value="0.16 in" role="Entre deux blocs mineurs." />
        <CRToken name="--block-gap-md"     value="0.24 in" role="Défaut entre deux blocs majeurs liés." />
        <CRToken name="--block-gap-lg"     value="0.34 in" role="Entre deux blocs majeurs si changement de pédagogie." />
        <CRToken name="--section-gap"      value="0.42 in" role="Séparation de groupes (cours → exercices)." />
        <CRToken name="--footer-safe-gap"  value="0.30 in" role="Zone tampon obligatoire avant le footer." />
        <CRToken name="--block-padding-x"  value="0.20 in" role="Padding horizontal interne d'un bloc." />
        <CRToken name="--block-padding-y"  value="0.18 in" role="Padding vertical interne d'un bloc." />
        <CRToken name="--block-tab-clear"  value="0.12 in" role="Clearance sous l'onglet du bloc." />
      </div>
      <div style={{ marginTop:12, padding:"10px 14px", background:"var(--ae-yellow-soft)", border:`1.5px solid var(--ae-yellow-dark)`, borderRadius:10, fontSize:12.5, color:"#7a5a1c", lineHeight:1.55 }}>
        <b>Pour le dev</b> · ces tokens sont scalés automatiquement par la classe de densité (<code>.density-air</code>, <code>.density-std</code>, <code>.density-dense</code>). Ne jamais override en local.
      </div>
    </div>
  );
}

/* ─── Composant principal ──────────────────────────────────────── */

function CompositionRules() {
  return (
    <div style={{ display:"flex", flexDirection:"column", gap:20 }}>
      {/* Hero */}
      <div style={{
        background:"linear-gradient(160deg, var(--ae-primary-deep), var(--ae-primary))",
        color:"white", borderRadius:16, padding:"28px 28px", position:"relative", overflow:"hidden",
      }}>
        <div style={{ position:"absolute", top:-50, right:-50, width:240, height:240, borderRadius:"50%", background:"var(--ae-yellow)", opacity:0.18 }} />
        <div style={{ position:"relative" }}>
          <div style={{ fontSize:11, fontWeight:800, letterSpacing:"0.18em", textTransform:"uppercase", opacity:0.85 }}>Charte v1.3 · Composition</div>
          <h1 style={{ margin:"8px 0 6px", fontFamily:"var(--ae-font-title)", fontSize:38, fontWeight:700, lineHeight:1.05 }}>
            Comment une page Allo Education Books doit respirer
          </h1>
          <p style={{ margin:0, fontSize:15, opacity:0.92, maxWidth:780, lineHeight:1.6 }}>
            La grammaire d'espacement officielle : anatomie d'une page, anatomie d'un bloc, hiérarchie des
            gaps, règles anti-overflow, tokens. Si cette base est claire, tous les templates respirent.
          </p>
          <div style={{ display:"flex", gap:8, marginTop:14, flexWrap:"wrap" }}>
            <CRChip tone="yellow">11 tokens d'espacement</CRChip>
            <CRChip tone="green">3 densités</CRChip>
            <CRChip tone="primary">8 chapitres</CRChip>
            <CRChip tone="red">overflow = page invalide</CRChip>
          </div>
        </div>
      </div>

      <CRPageAnatomy />
      <CRBlockAnatomy />
      <CRGapHierarchy />
      <CRMajorMinor />
      <CRDensity />
      <CRGoodBad />
      <CRAntiOverflow />
      <CRTokens />

      {/* Closer */}
      <div style={{
        padding:"16px 18px", background:"linear-gradient(180deg, var(--ae-success-soft), white)",
        border:`1.5px solid ${CR_C.ok}`, borderRadius:12,
      }}>
        <div style={{ fontWeight:800, color:CR_C.ok, fontSize:11, letterSpacing:"0.1em", textTransform:"uppercase", marginBottom:4 }}>
          Pour conclure
        </div>
        <p style={{ margin:0, fontSize:14, color:CR_C.inkSoft, lineHeight:1.6, maxWidth:820 }}>
          Cette charte ne donne pas de nouveaux templates. Elle dit comment les blocs s'assemblent.
          Si chaque template applique ces tokens via <code>density-std</code> et utilise <code>.ae-grow</code> sur son bloc principal,
          la page respire automatiquement — sans bricolage local.
        </p>
      </div>
    </div>
  );
}

Object.assign(window, { CompositionRules });
