/* ibudo.css — BUNDLE APLATI (généré par tools/flatten-css.mjs, ne pas éditer à la main.
   Source : idl/system/*.css — motif : TigerProtect 429 sur les rafales d'@import). */
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&family=Figtree:ital,wght@0,400;0,500;0,600;1,400&display=swap');
@import url('https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@3.31.0/dist/tabler-icons.min.css');

/* ==== tokens.css (inliné par tools/flatten-css.mjs) ==== */
/* ============================================================================
   IBUDO DESIGN LANGUAGE — tokens.css  (3 tiers : primitive → semantic → component)
   Source canonique machine-readable : /tokens/*.tokens.json (DTCG 2025.10).
   Architecture : cf. ops/decisions/ADR-0001. Theming au TIER 2 (semantic) uniquement.
   TIER 1 = sections 1–3 · TIER 2 = sections 4–6 (+feedback) · TIER 3 = component.
   Exportable en Global Colors/Fonts Elementor pour le rollout WordPress.
   ============================================================================ */
:root{
  /* ---------- 1. COULEURS DE MARQUE ---------------------------------------- */
  /* Bleu — le noyau du "O ouvert" : l'humain, la confiance. PRIMAIRE unique. */
  --ibu-blue-900:#0a2f6b;
  --ibu-blue-800:#0d3c8b;
  --ibu-blue-700:#0f4bb0;
  --ibu-blue-600:#1862db;   /* ← brand, charte #1862DB */
  --ibu-blue-500:#357ae9;   /* charte tint */
  --ibu-blue-400:#5a92ed;   /* charte tint */
  --ibu-blue-300:#91b6f3;   /* charte tint */
  --ibu-blue-200:#c2d7f8;
  --ibu-blue-100:#e0ebfc;
  --ibu-blue-50:#eff5fe;

  /* Ink — fond sombre signature : la "face nuit" de l'orbite (indigo profond). */
  --ibu-ink-900:#0a0c2a;
  --ibu-ink-800:#11143c;
  --ibu-ink-700:#1a1e57;    /* canvas sombre principal */
  --ibu-ink-600:#272c74;
  --ibu-ink-500:#3a3f93;

  /* ---------- 2. ACCENTS EN ORBITE (les 4 autres couleurs charte) ---------- */
  /* Vert émeraude — dynamisme/vitalité */
  --a-green-600:#01a847; --a-green-500:#01d859; --a-green-400:#20fe79; --a-green-100:#d6ffe6;
  /* Jaune or — chaleur/optimisme (TEXTE INTERDIT dessus : encre obligatoire) */
  --a-yellow-600:#c9c400; --a-yellow-500:#f8f326; --a-yellow-400:#faf875; --a-yellow-100:#fdfdd8;
  /* Violet améthyste — élégance/créativité */
  --a-violet-600:#8a3df0; --a-violet-500:#ad61ff; --a-violet-400:#c085ff; --a-violet-100:#efe2ff;
  /* Rouge pastèque — énergie/passion */
  --a-red-600:#e23149; --a-red-500:#ff4e63; --a-red-400:#ff858f; --a-red-100:#ffe0e4;

  /* Raccourcis accent (valeur de base) */
  --a-blue:var(--ibu-blue-600);
  --a-green:var(--a-green-500);
  --a-yellow:var(--a-yellow-500);
  --a-violet:var(--a-violet-500);
  --a-red:var(--a-red-500);

  /* ---------- 3. NEUTRES FROIDS (l'AJOUT premium — absent de la charte) ----- */
  --n-0:#ffffff;
  --n-50:#f7f8fb;
  --n-100:#eff1f6;
  --n-200:#e4e7ef;
  --n-300:#d2d7e2;
  --n-400:#aeb5c6;
  --n-500:#828ba1;
  --n-600:#5c657c;
  --n-700:#3d4458;
  --n-800:#262b3b;
  --n-900:#14182a;

  /* ---------- 4. ACCENT COURANT (tourne par section/vertical) -------------- */
  --accent:var(--ibu-blue-600);
  --accent-strong:var(--ibu-blue-700);
  --accent-soft:var(--ibu-blue-100);
  --on-accent:var(--n-0);          /* texte sur l'accent (jaune surchargé plus bas) */

  /* ---------- 5. TOKENS SÉMANTIQUES (thème clair par défaut) --------------- */
  --bg:var(--n-0);
  --bg-subtle:var(--n-50);
  --surface:var(--n-0);
  --surface-2:var(--n-50);
  --surface-raised:var(--n-0);
  --text:var(--n-900);
  --text-muted:var(--n-600);
  --text-faint:var(--n-500);
  --border:var(--n-200);
  --border-strong:var(--n-300);
  --ring:color-mix(in srgb, var(--accent) 45%, transparent);

  /* Feedback (sémantique — les composants doivent référencer CECI, pas les primitives) */
  --color-feedback-info:var(--ibu-blue-600);
  --color-feedback-success:var(--a-green-500);
  --color-feedback-warning:var(--a-yellow-600);
  --color-feedback-danger:var(--a-red-500);
  --color-feedback-info-soft:var(--ibu-blue-50);
  --color-feedback-success-soft:var(--a-green-100);
  --color-feedback-warning-soft:var(--a-yellow-100);
  --color-feedback-danger-soft:var(--a-red-100);

  /* ---------- TIER 3 — TOKENS COMPONENT (réfèrent le semantic) ------------- */
  --button-bg:var(--accent);
  --button-bg-hover:var(--accent-strong);
  --button-fg:var(--on-accent);
  --button-radius:var(--r-pill);
  --card-bg:var(--surface-raised);
  --card-border:var(--border);
  --card-radius:var(--r-lg);
  --vcard-accent:var(--accent);   /* point d'override : accent par carte (orbite) */
  --input-border:var(--border);
  --input-focus:var(--accent);

  /* ---------- 6. TYPOGRAPHIE ---------------------------------------------- */
  --font-display:"Outfit", system-ui, -apple-system, sans-serif;  /* titres */
  --font-body:"Figtree", system-ui, -apple-system, sans-serif;    /* corps/UI */
  --font-mono:"JetBrains Mono", ui-monospace, "SFMono-Regular", monospace;

  /* Échelle fluide (clamp) — tue les ruptures de breakpoint */
  --t-display:clamp(3rem, 1.8rem + 6vw, 7rem);
  --t-h1:clamp(2.4rem, 1.6rem + 3.6vw, 4.4rem);
  --t-h2:clamp(1.9rem, 1.4rem + 2.2vw, 3rem);
  --t-h3:clamp(1.4rem, 1.15rem + 1.1vw, 2rem);
  --t-h4:clamp(1.15rem, 1.05rem + .5vw, 1.4rem);
  --t-lead:clamp(1.05rem, 1rem + .5vw, 1.35rem);
  --t-body:1.0625rem;        /* 17px */
  --t-sm:0.9375rem;           /* 15px */
  --t-xs:0.8125rem;           /* 13px */
  --t-over:.78rem;           /* overline */

  --lh-tight:1.04; --lh-snug:1.2; --lh-body:1.6;
  --tr-tight:-.03em; --tr-over:.2em;
  --fw-light:300; --fw-reg:400; --fw-med:500; --fw-semi:600; --fw-bold:700; --fw-black:800;

  /* ---------- 7. ESPACEMENT (base 4px) + fluide --------------------------- */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:20px; --s-6:24px;
  --s-8:32px; --s-10:40px; --s-12:48px; --s-16:64px; --s-20:80px; --s-24:96px; --s-32:128px;
  --section-y:clamp(72px, 8vw, 160px);   /* padding vertical de section, cohérent */
  --gutter:clamp(20px, 4vw, 48px);
  --container:1200px;
  --container-narrow:760px;

  /* ---------- 8. RAYONS / ÉLÉVATION (formes ouvertes, rondes) -------------- */
  --r-xs:8px; --r-sm:12px; --r-md:16px; --r-lg:22px; --r-xl:30px; --r-pill:999px;
  --shadow-1:0 1px 2px rgba(20,24,42,.05), 0 4px 16px rgba(20,24,42,.05);
  --shadow-2:0 8px 30px rgba(20,24,42,.10);
  --shadow-3:0 20px 60px rgba(20,24,42,.16);

  /* ---------- 9. MOUVEMENT (mécanique orbitale) --------------------------- */
  --ease:cubic-bezier(.2,.7,.2,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --spring:cubic-bezier(.34,1.56,.64,1);
  --dur-1:.15s; --dur-2:.25s; --dur-3:.45s; --dur-4:.7s;

  /* ---------- 10. DIVERS -------------------------------------------------- */
  --z-nav:80; --z-cursor:9999; --z-modal:200;
  --maxlen:62ch;
}

/* Le jaune ne porte jamais de texte clair : encre obligatoire */
[data-accent="yellow"]{ --on-accent:var(--ibu-ink-900); }

/* ---------- ACCENTS PAR VERTICAL / SECTION (la couleur "orbite") ---------- */
[data-accent="blue"]  { --accent:var(--ibu-blue-600); --accent-strong:var(--ibu-blue-700); --accent-soft:var(--ibu-blue-100); --on-accent:#fff; }
[data-accent="green"] { --accent:var(--a-green-500);  --accent-strong:var(--a-green-600);  --accent-soft:var(--a-green-100);  --on-accent:#06351a; }
[data-accent="violet"]{ --accent:var(--a-violet-500); --accent-strong:var(--a-violet-600); --accent-soft:var(--a-violet-100); --on-accent:#fff; }
[data-accent="red"]   { --accent:var(--a-red-500);    --accent-strong:var(--a-red-600);    --accent-soft:var(--a-red-100);    --on-accent:#fff; }
[data-accent="yellow"]{ --accent:var(--a-yellow-500); --accent-strong:var(--a-yellow-600); --accent-soft:var(--a-yellow-100); --on-accent:var(--ibu-ink-900); }
/* Charte : le JAUNE ne porte jamais de texte (contraste insuffisant). Sous accent jaune,
   les éléments qui colorent leur TEXTE avec l'accent passent en encre ; le jaune reste
   réservé aux FORMES (fonds de boutons, dots, barres, arcs, bordures, dégradés). */
[data-accent="yellow"] :is(.overline,.stat .n,.hl,.tag-accent,.card-link .arrow,
  .step .num,.toc a.active,.doc-nav a.active,.breadcrumb a:hover,.acc-item.open .acc-head){
  color:var(--ibu-ink-700);
}

/* ---------- THÈMES PAR COULEUR (à poser sur <html data-theme="…">) -------- */
/* Un thème = accent + canvas subtilement teinté. Applique le tier semantic. */
[data-theme="blue"]  { --accent:var(--ibu-blue-600); --accent-strong:var(--ibu-blue-700); --accent-soft:var(--ibu-blue-100); --on-accent:#fff; --bg-subtle:#f4f8fe; --surface-2:#f4f8fe; }
[data-theme="green"] { --accent:var(--a-green-500);  --accent-strong:var(--a-green-600);  --accent-soft:var(--a-green-100);  --on-accent:#06351a; --bg-subtle:#f1fdf6; --surface-2:#f1fdf6; }
[data-theme="violet"]{ --accent:var(--a-violet-500); --accent-strong:var(--a-violet-600); --accent-soft:var(--a-violet-100); --on-accent:#fff; --bg-subtle:#f8f4ff; --surface-2:#f8f4ff; }
[data-theme="red"]   { --accent:var(--a-red-500);    --accent-strong:var(--a-red-600);    --accent-soft:var(--a-red-100);    --on-accent:#fff; --bg-subtle:#fff4f5; --surface-2:#fff4f5; }
[data-theme="yellow"]{ --accent:var(--a-yellow-600); --accent-strong:#9a9500;            --accent-soft:var(--a-yellow-100); --on-accent:var(--ibu-ink-900); --bg-subtle:#fdfdea; --surface-2:#fdfdea; }

/* ---------- THÈME SOMBRE (Ibudo Ink) ------------------------------------- */
[data-theme="ink"]{
  --bg:var(--ibu-ink-700); --bg-subtle:var(--ibu-ink-800);
  --surface:var(--ibu-ink-600); --surface-2:var(--ibu-ink-800); --surface-raised:var(--ibu-ink-600);
  --text:#ffffff; --text-muted:#c4c8ec; --text-faint:#9aa0d8;
  --border:rgba(255,255,255,.14); --border-strong:rgba(255,255,255,.24);
  --shadow-1:none; --shadow-2:0 10px 40px rgba(0,0,0,.35); --shadow-3:0 24px 70px rgba(0,0,0,.5);
}

/* ==== base.css (inliné par tools/flatten-css.mjs) ==== */
/* ============================================================================
   IBUDO DESIGN LANGUAGE — base.css
   Reset + éléments de base + utilitaires porteurs d'identité (motif •••, arcs,
   focus en anneau ouvert, conteneurs, grilles). Charge tokens.css avant.
   ============================================================================ */



/* Icônes Tabler — base unique du système. Usage : <i class="ti ti-rocket"></i> */
.ti{font-size:1.2em;line-height:1;vertical-align:-.125em;display:inline-block}
.ti-lg{font-size:1.6em}.ti-xl{font-size:2.2em}

*,*::before,*::after{box-sizing:border-box}
*{margin:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  font-family:var(--font-body);
  font-size:var(--t-body);
  line-height:var(--lh-body);
  color:var(--text);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img,svg,video{display:block;max-width:100%;height:auto}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}
ul[role="list"]{list-style:none;padding:0}

/* ---------- Typographie ---------- */
h1,h2,h3,h4,h5,.display{font-family:var(--font-display);font-weight:var(--fw-black);line-height:var(--lh-tight);letter-spacing:var(--tr-tight);text-wrap:balance}
p{text-wrap:pretty}                     /* évite les orphelines (no-op si non supporté) */
[data-count]{font-variant-numeric:tabular-nums} /* compteurs animés : largeur stable */
.display{font-size:var(--t-display)}
h1,.h1{font-size:var(--t-h1)}
h2,.h2{font-size:var(--t-h2)}
h3,.h3{font-size:var(--t-h3);font-weight:var(--fw-bold)}
h4,.h4{font-size:var(--t-h4);font-weight:var(--fw-semi);line-height:var(--lh-snug)}
/* Cinquieme niveau. Sans lui, un <h3> pose dans une carte gardait la regle
   d'element h3 (--t-h3) et sortait donc PLUS GROS que le titre de la carte
   en .h4 juste au-dessus : la hierarchie s'inversait. Une echelle qui
   s'arrete trop tot ne laisse pas le choix, elle laisse une faute. */
h5,.h5{font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);
  line-height:var(--lh-snug);letter-spacing:.01em}
.lead{font-size:var(--t-lead);color:var(--text-muted);line-height:1.5;max-width:var(--maxlen)}
.muted{color:var(--text-muted)}
.faint{color:var(--text-faint)}
.balance{text-wrap:balance}
::selection{background:color-mix(in srgb,var(--accent) 28%,transparent)}

/* Overline + motif ••• (signature Ibudo, rappel des 4 points du logo) */
.overline{
  font-family:var(--font-display);font-weight:var(--fw-semi);
  text-transform:uppercase;letter-spacing:var(--tr-over);font-size:var(--t-over);
  color:var(--accent);display:inline-flex;align-items:center;gap:.8em;
  transition:color var(--dur-4) var(--ease);
}
.dots{display:inline-flex;gap:5px}
.dots i{width:7px;height:7px;border-radius:50%;display:block}
.dots i:nth-child(1){background:var(--a-red)}
.dots i:nth-child(2){background:var(--a-green)}
.dots i:nth-child(3){background:var(--a-violet)}
.dots i:nth-child(4){background:var(--a-yellow)}
/* variante mono-accent (prend la couleur d'orbite courante) */
.dots.mono i{background:var(--accent);opacity:.35}
.dots.mono i:nth-child(2){opacity:.6}
.dots.mono i:nth-child(3){opacity:.85}
.dots.mono i:nth-child(4){opacity:1}

/* ---------- Focus accessible = anneau OUVERT (clin d'œil au "O ouvert") ---- */
:where(a,button,input,select,textarea,[tabindex]):focus-visible{
  outline:3px solid var(--ring);outline-offset:3px;border-radius:var(--r-xs);
}

/* ---------- Layout ---------- */
.container{width:100%;max-width:var(--container);margin-inline:auto;padding-inline:var(--gutter)}
.container.narrow{max-width:var(--container-narrow)}
.section{padding-block:var(--section-y);position:relative}
.section.tight{padding-block:clamp(48px,5vw,96px)}
.stack>*+*{margin-top:var(--s-4)}
.stack.lg>*+*{margin-top:var(--s-8)}
.grid{display:grid;gap:var(--s-4)}
.grid.gap-sm{gap:var(--s-3)}
.grid.gap-md{gap:var(--s-4)}
.grid.gap-lg{gap:var(--s-6)}
/* minmax calibré pour ne JAMAIS dépasser N colonnes dans un .container (1200px) :
   avec plus d'items que N, auto-fit créait une colonne de trop (ex. 8 vcards → 5+3). */
.cols-2{grid-template-columns:repeat(auto-fit,minmax(380px,1fr))}
.cols-3{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.cols-4{grid-template-columns:repeat(auto-fit,minmax(235px,1fr))}
@media (max-width:420px){.cols-2,.cols-3,.cols-4{grid-template-columns:1fr}}
.center{text-align:center}
.center .lead,.center .overline{margin-inline:auto}
.eyebrow-row{display:flex;flex-direction:column;gap:var(--s-3)}

/* ---------- Arc ouvert : séparateur / décor de section (motif identitaire) - */
.arc-divider{height:2px;border:0;background:
  linear-gradient(90deg,transparent,var(--border) 12%,var(--border) 88%,transparent);
  position:relative;margin-block:var(--s-12)}
.arc-divider::after{content:"";position:absolute;left:50%;top:50%;width:10px;height:10px;
  border-radius:50%;background:var(--accent);transform:translate(-50%,-50%)}

/* Anneau orbital décoratif (concentriques, façon line-art de la charte) */
.orbit-bg{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.orbit-bg svg{position:absolute;width:min(900px,90vw);height:auto;opacity:.5}
.orbit-bg path{fill:none;stroke:var(--accent);stroke-width:1.3;opacity:.22;
  transition:stroke var(--dur-4) var(--ease)}

/* ---------- Utilitaires ---------- */
.flow{position:relative;z-index:1}
.hidden{display:none}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.tag-accent{color:var(--accent)}
.bg-ink{background:var(--ibu-ink-700)}
.reveal{opacity:0;transform:translateY(28px)}
.is-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.reveal{opacity:1;transform:none}}

/* ==== components.css (inliné par tools/flatten-css.mjs) ==== */
/* ============================================================================
   IBUDO DESIGN LANGUAGE — components.css
   La bibliothèque. Chaque composant rappelle l'esprit Ibudo : noyau bleu,
   accent qui s'allume, anneau ouvert, motif •••, mouvement orbital.
   Dépend de tokens.css + base.css.
   ============================================================================ */

/* ====================== BOUTONS ========================================== */
.btn{
  --bw:1.5px;
  display:inline-flex;align-items:center;justify-content:center;gap:.6em;
  font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);
  line-height:1;padding:14px 24px;border-radius:var(--r-pill);
  border:var(--bw) solid transparent;cursor:pointer;white-space:nowrap;
  transition:background var(--dur-2) var(--ease),color var(--dur-2),border-color var(--dur-3),transform var(--dur-1),box-shadow var(--dur-2);
}
.btn:hover{transform:translateY(-2px)}
.btn:active{transform:translateY(0) scale(.96)}
.btn-primary{background:var(--accent);color:var(--on-accent)}
.btn-primary:hover{background:var(--accent-strong);box-shadow:0 8px 22px color-mix(in srgb,var(--accent) 35%,transparent)}
.btn-ghost{background:transparent;color:var(--text);border-color:var(--border-strong)}
.btn-ghost:hover{border-color:var(--accent);color:var(--accent)}
.btn-soft{background:var(--accent-soft);color:var(--accent-strong)}
.btn-ink{background:var(--ibu-ink-700);color:#fff}
.btn-lg{padding:17px 30px;font-size:var(--t-body)}
.btn-sm{padding:10px 16px;font-size:var(--t-xs)}
/* détail orbital : un petit point qui "tourne" à l'arrivée */
.btn .orb{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.55;transition:opacity var(--dur-2),transform var(--dur-3) var(--spring)}
.btn:hover .orb{opacity:1;transform:translateX(3px)}
.btn-block{display:flex;width:100%}

/* ====================== PILLS / TAGS / BADGES ============================ */
.pill{display:inline-flex;align-items:center;gap:.5em;padding:7px 14px;border-radius:var(--r-pill);
  font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-xs);
  background:var(--surface-2);color:var(--text-muted);border:1px solid var(--border)}
.pill.accent{background:var(--accent-soft);color:var(--accent-strong);border-color:transparent}
.pill .dot{width:7px;height:7px;border-radius:50%;background:var(--accent)}
.badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 7px;
  border-radius:var(--r-pill);background:var(--accent);color:var(--on-accent);font-size:11px;font-weight:var(--fw-bold)}
.tag{font-family:var(--font-display);font-weight:var(--fw-semi);text-transform:uppercase;letter-spacing:.14em;
  font-size:.7rem;color:var(--text-faint);transition:color var(--dur-3)}

/* ====================== CARTE DE BASE ==================================== */
.card{position:relative;background:var(--surface-raised);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:var(--s-8);transition:transform var(--dur-3) var(--ease),
  box-shadow var(--dur-3) var(--ease),border-color var(--dur-3)}
.card.hover:hover{transform:translateY(-6px);box-shadow:var(--shadow-2)}
.card-media{border-radius:var(--r-md);overflow:hidden;margin:calc(-1*var(--s-8)) calc(-1*var(--s-8)) var(--s-6);aspect-ratio:16/10;background:var(--surface-2)}
.card-media img{width:100%;height:100%;object-fit:cover}

/* Carte "vertical" — la couleur s'allume au survol (signature) ----------- */
.vcard{position:relative;display:block;background:var(--surface-raised);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:var(--s-8);overflow:hidden;color:inherit;
  transition:transform var(--dur-3) var(--ease),box-shadow var(--dur-3) var(--ease),border-color var(--dur-3)}
.vcard::before{content:"";position:absolute;left:0;top:0;right:0;height:5px;background:var(--ca,var(--accent));
  transform:scaleX(0);transform-origin:left;transition:transform var(--dur-3) var(--ease)}
.vcard .vtag{font-family:var(--font-display);font-weight:var(--fw-semi);text-transform:uppercase;
  letter-spacing:.14em;font-size:.72rem;color:var(--text-faint);transition:color var(--dur-3)}
.vcard h3{font-size:var(--t-h3);margin:var(--s-3) 0 var(--s-2)}
.vcard p{color:var(--text-muted);font-size:var(--t-sm)}
.vcard .go{margin-top:var(--s-6);font-family:var(--font-display);font-weight:var(--fw-semi);
  color:var(--ca,var(--accent));opacity:0;transform:translateX(-8px);transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease)}
.vcard:hover{transform:translateY(-8px);box-shadow:var(--shadow-2);border-color:var(--ca,var(--accent))}
.vcard:hover::before{transform:scaleX(1)}
.vcard:hover .vtag{color:var(--ca,var(--accent))}
.vcard:hover .go{opacity:1;transform:translateX(0)}
/* arc déco qui apparaît au survol (auto-injecté par orbital.js) */
.vcard .arc{position:absolute;right:-36px;top:-36px;width:120px;height:120px;opacity:0;
  color:var(--ca,var(--accent));transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease);transform:rotate(-15deg) scale(.8)}
.vcard:hover .arc{opacity:.9;transform:rotate(0) scale(1)}

/* ====================== FEATURE / ICON-BOX ============================== */
.feature{display:flex;flex-direction:column;gap:var(--s-3)}
.feature .ficon{width:52px;height:52px;border-radius:var(--r-md);display:grid;place-items:center;
  background:var(--accent-soft);color:var(--accent-strong);font-size:24px;
  transition:background var(--dur-3),color var(--dur-3),transform var(--dur-3) var(--spring)}
.feature:hover .ficon{transform:translateY(-3px) rotate(-6deg)}
.feature h4{font-size:var(--t-h4)}
.feature p{color:var(--text-muted);font-size:var(--t-sm)}
/* en ligne (icône à gauche) */
.feature.inline{flex-direction:row;align-items:flex-start;gap:var(--s-4)}

/* ====================== STAT / COUNTER ================================== */
.stat .n{font-family:var(--font-display);font-weight:var(--fw-black);font-size:clamp(2.6rem,5vw,4.4rem);
  line-height:1;color:var(--accent);letter-spacing:var(--tr-tight)}
.stat .l{color:var(--text-muted);margin-top:var(--s-2)}
.stat-band{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--s-6)}

/* ====================== ÉQUIPE (gris→couleur au survol) ================= */
.member{text-align:center}
.member .photo{aspect-ratio:1;border-radius:var(--r-lg);position:relative;overflow:hidden;
  filter:grayscale(1) contrast(.94) brightness(1.02);outline:0 solid var(--ca,var(--accent));outline-offset:6px;
  transition:filter var(--dur-3) var(--ease),transform var(--dur-3) var(--ease),outline-width var(--dur-3)}
.member .photo img{width:100%;height:100%;object-fit:cover}
.member:hover .photo{filter:none;transform:translateY(-6px);outline-width:3px}
.member .nm{font-family:var(--font-display);font-weight:var(--fw-semi);margin-top:var(--s-4)}
.member .rl{color:var(--text-muted);font-size:var(--t-sm)}

/* ====================== TÉMOIGNAGE / CITATION =========================== */
.quote{background:var(--surface-raised);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--s-10)}
.quote .mark{font-family:var(--font-display);font-weight:var(--fw-black);font-size:3rem;line-height:.6;color:var(--accent);height:.5em;display:block}
.quote blockquote{font-size:var(--t-lead);line-height:1.5;margin:var(--s-4) 0 var(--s-6)}
.quote .by{display:flex;align-items:center;gap:var(--s-3)}
/* L'avatar accepte une image OU des initiales. Le second cas n'etait pas
   traite : sans centrage ni graisse, deux lettres flottaient en haut a gauche
   d'un disque gris, ce qui ressemblait a un chargement rate plutot qu'a un
   repli assume. */
.avatar{display:inline-grid;place-items:center;flex:0 0 auto;width:44px;height:44px;
  border-radius:50%;overflow:hidden;object-fit:cover;background:var(--surface-2);
  font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);
  line-height:1;letter-spacing:.02em;color:var(--text-muted);text-transform:uppercase;
  user-select:none;box-shadow:inset 0 0 0 1px rgba(0,0,0,.06)}
.avatar img{width:100%;height:100%;object-fit:cover;border-radius:inherit}
.avatar.sm{width:32px;height:32px;font-size:var(--t-xs)}
.avatar.lg{width:64px;height:64px;font-size:var(--t-body)}
.avatar.xl{width:96px;height:96px;font-size:var(--t-h4)}
.avatar.ring{outline:2px solid var(--accent);outline-offset:2px}
/* Sur fond sombre, le liseré noir devient invisible et le gris trop proche du
   fond : on inverse les deux. */
[data-theme="ink"] .avatar{background:rgba(255,255,255,.12);color:rgba(255,255,255,.9);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.14)}

/* ====================== PRICING ======================================== */
.price{background:var(--surface-raised);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--s-8);position:relative}
.price.featured{border-color:var(--accent);box-shadow:var(--shadow-2)}
.price .amt{font-family:var(--font-display);font-weight:var(--fw-black);font-size:3rem;line-height:1;margin:var(--s-2) 0}
.price .amt small{font-size:1rem;font-weight:var(--fw-med);color:var(--text-muted)}
.price ul{list-style:none;padding:0;margin:var(--s-6) 0;display:grid;gap:var(--s-3)}
.price li{display:flex;gap:.6em;align-items:flex-start;color:var(--text-muted);font-size:var(--t-sm)}
.price li::before{content:"";flex:0 0 auto;margin-top:.45em;width:7px;height:7px;border-radius:50%;background:var(--accent)}

/* ====================== NAV / HEADER =================================== */
.nav{position:sticky;top:0;z-index:var(--z-nav);background:color-mix(in srgb,var(--bg) 78%,transparent);
  backdrop-filter:blur(16px);border-bottom:1px solid var(--border)}
.nav-inner{display:flex;align-items:center;justify-content:space-between;height:70px;gap:var(--s-6)}
.nav .brand{flex:0 0 auto}
.nav .brand img{height:30px;width:auto;max-width:none}
.nav-links{display:flex;gap:var(--s-8);font-weight:var(--fw-med);font-size:var(--t-sm)}
.nav-links a{color:var(--text-muted);transition:color var(--dur-2);position:relative}
.nav-links a:hover{color:var(--text)}
.nav-links a::after{content:"";position:absolute;left:0;right:100%;bottom:-6px;height:2px;background:var(--accent);transition:right var(--dur-3) var(--ease)}
.nav-links a:hover::after{right:0}
/* Burger + nav mobile (le bouton .nav-burger n'apparaît qu'en < 860px) */
.nav-burger{display:none;align-items:center;justify-content:center;width:44px;height:44px;
  background:none;border:0;border-radius:var(--r-sm);color:var(--text);cursor:pointer;font-size:1.5em}
.nav-burger:hover{background:var(--surface-2)}
@media (max-width:860px){
  .nav-burger{display:inline-flex}
  .nav-inner>.nav-links{position:absolute;top:calc(100% + 12px);right:0;left:0;flex-direction:column;gap:0;
    background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);
    box-shadow:var(--shadow-2);padding:var(--s-3);
    opacity:0;visibility:hidden;transform:translateY(-8px);
    transition:opacity var(--dur-2) var(--ease),transform var(--dur-2) var(--ease),visibility var(--dur-2)}
  .nav.open .nav-inner>.nav-links{opacity:1;visibility:visible;transform:none}
  .nav-links ul.nav-links{position:static;flex-direction:column;background:none;border:0;box-shadow:none;
    padding:0;opacity:1;visibility:visible;transform:none;gap:0;width:100%}
  .nav-links li{width:100%;list-style:none}
  .nav-links a{display:block;width:100%;padding:12px 14px;border-radius:var(--r-sm)}
  .nav-links a:hover{background:var(--surface-2);color:var(--text)}
  .nav-links a::after{display:none}
}

/* ====================== FOOTER ========================================= */
.footer{background:var(--ibu-ink-700);color:#fff;padding-block:var(--s-20) var(--s-10)}
.footer a{color:#c4c8ec;transition:color var(--dur-2)}
.footer a:hover{color:#fff}
.footer .cols{display:grid;grid-template-columns:1.4fr repeat(3,1fr);gap:var(--s-8)}
.footer h5{font-family:var(--font-display);font-size:var(--t-sm);text-transform:uppercase;letter-spacing:.12em;color:#9aa0d8;margin-bottom:var(--s-4)}
.footer .links{display:grid;gap:var(--s-2);font-size:var(--t-sm)}
.footer .bottom{margin-top:var(--s-12);padding-top:var(--s-6);border-top:1px solid rgba(255,255,255,.12);display:flex;justify-content:space-between;gap:var(--s-4);flex-wrap:wrap;color:#9aa0d8;font-size:var(--t-xs)}
/* Logo de footer : wordmark MONO officiel (vectoriel, non rogné) recoloré en blanc
   pour le fond sombre. brightness(0) → noir, invert(1) → blanc. Logo non déformé. */
.footer .foot-logo{height:30px;width:auto;margin-bottom:var(--s-3);filter:brightness(0) invert(1)}

/* ====================== HERO =========================================== */
.hero{position:relative;padding-block:clamp(96px,12vw,180px) var(--section-y);overflow:hidden}
.hero .display{max-width:15ch}
.hero .display .hl{color:var(--accent)}
.hero-art{position:absolute;right:max(-160px,-10vw);top:50%;transform:translateY(-50%);width:min(560px,52vw);opacity:.96;pointer-events:none;z-index:0}
.hero-cta{display:flex;gap:var(--s-3);flex-wrap:wrap;margin-top:var(--s-8)}

/* ====================== SECTION HEADER ================================= */
.sec-head{max-width:var(--maxlen);margin-bottom:var(--s-12)}
.sec-head h2{margin:var(--s-3) 0}
.sec-head.center{margin-inline:auto;text-align:center}

/* ====================== ACCORDION / FAQ ================================ */
.acc-item{border-bottom:1px solid var(--border)}
.acc-head{width:100%;display:flex;align-items:center;justify-content:space-between;gap:var(--s-4);
  padding:var(--s-5) 0;background:none;border:0;cursor:pointer;text-align:left;
  font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-h4)}
.acc-head .ico{flex:0 0 auto;width:26px;height:26px;border-radius:50%;border:2px solid var(--border-strong);
  position:relative;transition:border-color var(--dur-2)}
.acc-head .ico::before,.acc-head .ico::after{content:"";position:absolute;background:currentColor;inset:0;margin:auto}
.acc-head .ico::before{width:10px;height:2px}.acc-head .ico::after{width:2px;height:10px;transition:transform var(--dur-3) var(--ease)}
.acc-item.open .acc-head{color:var(--accent)}
.acc-item.open .acc-head .ico{border-color:var(--accent)}
.acc-item.open .acc-head .ico::after{transform:rotate(90deg) scaleX(0)}
.acc-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--dur-3) var(--ease)}
.acc-item.open .acc-body{grid-template-rows:1fr}
.acc-body>div{overflow:hidden}
.acc-body p{padding-bottom:var(--s-5);color:var(--text-muted);max-width:var(--maxlen)}

/* ====================== TABS =========================================== */
.tablist{display:inline-flex;gap:4px;background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-pill);padding:4px}
.tablist [role="tab"]{border:0;background:none;cursor:pointer;padding:9px 18px;border-radius:var(--r-pill);
  font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);color:var(--text-muted);transition:background-color var(--dur-2),color var(--dur-2)}
.tablist [role="tab"][aria-selected="true"]{background:var(--accent);color:var(--on-accent)}
[role="tabpanel"]{padding-top:var(--s-6)}

/* ====================== FORMULAIRES ==================================== */
.field{display:grid;gap:7px;margin-bottom:var(--s-4)}
.field label{font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);display:flex;gap:.4em;align-items:center}
.field label .req{color:var(--a-red-500)}
.field .hint{font-size:var(--t-xs);color:var(--text-faint)}
.input,.textarea,.select{
  width:100%;padding:12px 14px;border-radius:var(--r-md);border:1.5px solid var(--border);
  background:var(--surface-2);color:var(--text);font-size:var(--t-sm);font-family:var(--font-body);
  transition:border-color var(--dur-2) var(--ease),box-shadow var(--dur-2),background var(--dur-2)}
.input::placeholder,.textarea::placeholder{color:var(--text-faint)}
.input:hover,.textarea:hover,.select:hover{border-color:var(--border-strong)}
.input:focus,.textarea:focus,.select:focus{outline:0;border-color:var(--accent);background:var(--surface);box-shadow:0 0 0 4px var(--ring)}
.input:disabled,.textarea:disabled,.select:disabled{opacity:.55;cursor:not-allowed}
.textarea{min-height:118px;resize:vertical;line-height:1.5}
.input-sm{padding:8px 11px;font-size:var(--t-xs)}
.input-lg{padding:15px 17px;font-size:var(--t-body)}
/* select : chevron custom (fini la flèche système) */
.select{appearance:none;-webkit-appearance:none;padding-right:40px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%235c657c' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:18px}
/* input avec icône / affixe */
.input-group{position:relative;display:flex;align-items:center}
.input-group>.ti{position:absolute;left:14px;color:var(--text-faint);pointer-events:none;font-size:1.05em}
.input-group>.ti~.input,.input-group>.input.has-icon{padding-left:42px}
.input-affix{display:flex;align-items:stretch;border:1.5px solid var(--border);border-radius:var(--r-md);overflow:hidden;background:var(--surface-2);transition:border-color var(--dur-2),box-shadow var(--dur-2)}
.input-affix:focus-within{border-color:var(--accent);box-shadow:0 0 0 4px var(--ring);background:var(--surface)}
.input-affix .input{border:0;background:none;box-shadow:none;border-radius:0}
.input-affix .input:focus{box-shadow:none}
.input-affix .pre,.input-affix .post{display:flex;align-items:center;padding:0 14px;background:var(--surface-2);color:var(--text-muted);font-size:var(--t-sm);font-weight:var(--fw-med)}
.input-affix .post{border-left:1px solid var(--border)}
.input-affix .pre{border-right:1px solid var(--border)}
/* états */
.field.is-error .input,.field.is-error .select,.field.is-error .textarea{border-color:var(--a-red-500)}
.field.is-error .hint{color:var(--a-red-600)}
.field.is-success .input{border-color:var(--a-green-500)}
.field.is-success .hint{color:var(--a-green-600)}
/* checkbox / radio personnalisés.
   « accent-color » ne repeint que la coche : la boîte reste celle du système,
   avec ses angles, son trait et sa teinte à lui. À côté de champs au rayon 10
   et au trait 1,5, ça se voit immédiatement. On dessine donc la boîte, en
   gardant l'input natif dessous pour le clavier, l'autofill et les tests. */
.check{display:inline-flex;align-items:center;gap:.7em;font-size:var(--t-sm);
  color:var(--text-muted);cursor:pointer}
.check input{position:absolute;width:1px;height:1px;opacity:0;margin:0;pointer-events:none}
.check input + span::before{content:"";flex:0 0 auto;display:inline-block;width:20px;height:20px;
  margin-right:.7em;vertical-align:-.32em;border:1.5px solid var(--border-strong);border-radius:6px;
  background:var(--surface);
  transition:background-color var(--dur-2),border-color var(--dur-2),box-shadow var(--dur-2)}
.check input[type=radio] + span::before{border-radius:50%}
.check:hover input:not(:checked) + span::before{border-color:var(--accent)}
.check input:checked + span::before{background:var(--accent);border-color:var(--accent);
  /* La coche est dessinée en masque : elle suit la couleur du texte du contrôle
     et reste nette à toute densité de pixels, ce qu'une image ne fait pas. */
  -webkit-mask:var(--tick) center/13px 13px no-repeat;mask:var(--tick) center/13px 13px no-repeat;
  box-shadow:inset 0 0 0 20px var(--accent)}
.check input[type=radio]:checked + span::before{-webkit-mask:none;mask:none;
  box-shadow:inset 0 0 0 4px var(--surface)}
.check input:focus-visible + span::before{outline:2px solid var(--accent);outline-offset:2px}
.check input:disabled + span{opacity:.55;cursor:not-allowed}
:root{--tick:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20 6 9 17l-5-5' fill='none' stroke='%23000' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
/* file upload.
   Le composant est le LABEL, pas l'input. Posée sur l'input, la classe laissait
   le bouton natif du navigateur (« Choisir un fichier · Aucun fichier
   sélectionné ») s'afficher tel quel dans une boîte pointillée : deux styles
   empilés, aucun des deux au design system.
   L'input reste dans le DOM, simplement invisible : c'est lui qui porte le
   focus clavier, l'accessibilité et la valeur envoyée. */
.file{display:inline-flex;align-items:center;gap:.6em;padding:12px 18px;
  border:1.5px dashed var(--border-strong);border-radius:var(--r-md);color:var(--text-muted);
  cursor:pointer;background:var(--surface-2);max-width:100%;
  transition:border-color var(--dur-2),color var(--dur-2),background-color var(--dur-2)}
.file:hover{border-color:var(--accent);color:var(--accent)}
.file input[type=file]{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.file:focus-within{border-color:var(--accent);color:var(--accent);
  outline:2px solid var(--accent);outline-offset:2px}
.file i{flex:0 0 auto}
.file .file-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.file.has-file{border-style:solid;border-color:var(--accent);color:var(--accent-strong);
  background:var(--accent-soft)}
.file.is-dragover{border-color:var(--accent);background:var(--accent-soft)}
/* range */
input[type=range].range{-webkit-appearance:none;appearance:none;width:100%;height:6px;border-radius:var(--r-pill);background:var(--surface-2);outline:none}
input[type=range].range::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;border-radius:50%;background:var(--accent);cursor:pointer;border:3px solid var(--surface);box-shadow:var(--shadow-1)}
input[type=range].range::-moz-range-thumb{width:20px;height:20px;border:3px solid var(--surface);border-radius:50%;background:var(--accent);cursor:pointer}

/* ====================== MARQUEE / LOGO WALL ============================ */
.marquee{overflow:hidden;-webkit-mask:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
.marquee-track{display:flex;gap:var(--s-12);width:max-content;animation:ibu-marq 28s linear infinite}
.marquee:hover .marquee-track{animation-play-state:paused}
@keyframes ibu-marq{to{transform:translateX(-50%)}}
.logo-wall{display:flex;gap:var(--s-10);align-items:center;flex-wrap:wrap;justify-content:center;opacity:.85}
.logo-wall img,.logo-wall span{filter:grayscale(1);opacity:.65;transition:filter var(--dur-3),opacity var(--dur-3);font-weight:var(--fw-bold);color:var(--text-muted)}
.logo-wall img:hover,.logo-wall span:hover{filter:none;opacity:1}
@media (prefers-reduced-motion:reduce){.marquee-track{animation:none}}

/* ====================== PROCESS / TIMELINE (étapes orbitales) =========== */
.steps{counter-reset:step;display:grid;gap:var(--s-8)}
.step{display:grid;grid-template-columns:auto 1fr;gap:var(--s-5);align-items:start}
.step .num{counter-increment:step;width:54px;height:54px;border-radius:50%;display:grid;place-items:center;
  font-family:var(--font-display);font-weight:var(--fw-bold);border:2px solid var(--border-strong);color:var(--accent);position:relative}
.step .num::after{content:counter(step,decimal-leading-zero)}
.step:not(:last-child) .num::before{content:"";position:absolute;top:54px;left:50%;width:2px;height:calc(100% + var(--s-8) - 54px);background:var(--border);transform:translateX(-50%)}
.step h4{font-size:var(--t-h4);margin-bottom:var(--s-2)}
.step p{color:var(--text-muted);font-size:var(--t-sm)}

/* ====================== CTA BAND ======================================= */
.cta{position:relative;overflow:hidden;border-radius:var(--r-xl);padding:clamp(48px,6vw,88px);
  background:var(--ibu-ink-700);color:#fff}
.cta h2{max-width:18ch}.cta p{color:#c4c8ec;max-width:46ch;margin-top:var(--s-3)}
.cta .hero-cta{margin-top:var(--s-8)}

/* ====================== CURSEUR ORBITAL (opt-in) ====================== */
.has-ibu-cursor{cursor:none}
.has-ibu-cursor a,.has-ibu-cursor button{cursor:none}
.ibu-cursor{position:fixed;left:0;top:0;width:34px;height:34px;margin:-17px 0 0 -17px;border-radius:50%;
  border:2px solid var(--accent);z-index:var(--z-cursor);pointer-events:none;
  clip-path:polygon(0 0,72% 0,72% 28%,100% 28%,100% 100%,0 100%);
  transition:width var(--dur-2),height var(--dur-2),border-color var(--dur-4)}
.ibu-cursor.lit{width:54px;height:54px;margin:-27px 0 0 -27px}
.ibu-cursor-dot{position:fixed;left:0;top:0;width:6px;height:6px;margin:-3px 0 0 -3px;border-radius:50%;
  background:var(--accent);z-index:var(--z-cursor);pointer-events:none}

/* ====================== CATALOGUE (vitrine) =========================== */
.ds-shell{display:grid;grid-template-columns:248px 1fr;min-height:100vh}
.ds-side{position:sticky;top:0;align-self:start;height:100vh;overflow:auto;border-right:1px solid var(--border);padding:var(--s-6)}
.ds-side .brand img{height:28px;margin-bottom:var(--s-8)}
.ds-nav{display:grid;gap:2px}
.ds-nav a{padding:8px 12px;border-radius:var(--r-sm);color:var(--text-muted);font-size:var(--t-sm);font-weight:var(--fw-med)}
.ds-nav a:hover{background:var(--surface-2);color:var(--text)}
.ds-nav .grp{font-family:var(--font-display);font-weight:var(--fw-bold);font-size:.72rem;text-transform:uppercase;letter-spacing:.12em;color:var(--text-faint);margin:var(--s-5) 0 var(--s-2);padding-left:12px}
.ds-main{min-width:0}
.ds-block{padding:var(--s-12) var(--gutter);border-bottom:1px solid var(--border)}
.ds-block>h2{font-size:var(--t-h2);margin-bottom:var(--s-2)}
.ds-block>.lead{margin-bottom:var(--s-8)}
.demo{background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--s-8);margin-bottom:var(--s-3);position:relative}
.demo.dark{background:var(--ibu-ink-700)}
.code{background:var(--ibu-ink-900);color:#cdd3ff;border-radius:var(--r-md);padding:var(--s-5) var(--s-6);overflow:auto;
  font-family:var(--font-mono);font-size:.82rem;line-height:1.6}
.code-wrap{position:relative}
.copy-btn{position:absolute;top:10px;right:10px;background:rgba(255,255,255,.1);color:#fff;border:1px solid rgba(255,255,255,.2);
  border-radius:var(--r-sm);padding:6px 12px;font-size:var(--t-xs);font-weight:var(--fw-semi);cursor:pointer}
/* — Toggle « Code » (extraction auto des démos par shell.js, chrome catalogue) — */
.code-toggle{margin:calc(-1*var(--s-2)) 0 var(--s-6)}
.code-toggle>summary{list-style:none;display:inline-flex;align-items:center;gap:6px;cursor:pointer;user-select:none;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm);padding:5px 12px;
  font-size:var(--t-xs);font-weight:var(--fw-semi);color:var(--text-muted)}
.code-toggle>summary::-webkit-details-marker{display:none}
.code-toggle>summary:hover{color:var(--accent);border-color:var(--accent)}
.code-toggle[open]>summary{margin-bottom:var(--s-3);color:var(--accent);border-color:var(--accent)}
/* — Chips « source » injectées par shell.js (data-source → GitHub) — */
.src-chips{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-4)}
.src-chips a{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:999px;
  padding:5px 12px;font-size:var(--t-xs);font-weight:var(--fw-semi);color:var(--text-muted);text-decoration:none}
.src-chips a:hover{color:var(--accent);border-color:var(--accent)}
.src-link{display:inline-flex;align-items:center;gap:4px;margin-left:var(--s-3);vertical-align:middle;
  font-size:var(--t-xs);font-weight:var(--fw-semi);color:var(--text-faint);text-decoration:none}
.src-link:hover{color:var(--accent)}
/* — Pager prev/next injecté par shell.js — */
.ds-pager{display:flex;justify-content:space-between;align-items:center;gap:var(--s-4);border-bottom:0;
  color:var(--text-faint);font-size:var(--t-sm)}
.ds-pager a{display:inline-flex;align-items:center;gap:8px;color:var(--accent);font-weight:var(--fw-semi)}
.swatch{border-radius:var(--r-md);overflow:hidden;border:1px solid var(--border)}
.swatch .b{height:72px}.swatch .c{padding:10px 12px;font-size:var(--t-xs);font-family:var(--font-display);font-weight:var(--fw-semi)}
.swatch .c small{display:block;color:var(--text-muted);font-weight:var(--fw-reg);font-family:var(--font-mono)}
.scale-bar{display:flex;height:46px;border-radius:var(--r-md);overflow:hidden;border:1px solid var(--border)}
.scale-bar div{flex:1}

/* ============== CHROME « DOCS » DU CATALOGUE (barre haut + 3 colonnes) ====
   shell.js injecte .ds-topbar (avant .ds-shell), remplit #ds-side en doc-nav,
   et ajoute <aside class="ds-toc"> + .has-toc sur .ds-shell. Look = tpl-docs. */
.ds-topbar{position:sticky;top:0;z-index:var(--z-nav);
  background:color-mix(in srgb,var(--bg) 82%,transparent);
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--border)}
.ds-topbar .tb-inner{max-width:1380px;margin-inline:auto;padding-inline:var(--gutter);
  display:flex;align-items:center;gap:var(--s-6);height:64px}
.ds-topbar .brand img{height:26px;width:auto;display:block}
.ds-topbar .tb-search{flex:1;max-width:480px;margin:0;position:relative}
.ds-topbar .tb-search .input{border-radius:var(--r-pill)}
/* Menu de résultats de recherche */
.tb-results{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:calc(var(--z-nav) + 1);
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
  box-shadow:var(--shadow-2);padding:var(--s-2);max-height:64vh;overflow:auto}
.tb-results a{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:var(--r-sm);
  color:var(--text);font-size:var(--t-sm)}
.tb-results a:hover{background:var(--surface-2)}
.tb-results a .ti{color:var(--text-faint);flex:0 0 auto}
.tb-results a small{margin-left:auto;color:var(--text-faint);font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.06em}
.tb-results .tb-empty{padding:12px;color:var(--text-faint);font-size:var(--t-sm)}
.ds-topbar .tb-links{margin-left:auto;align-items:center;gap:var(--s-6)}

/* Coquille centrée, colonnes alignées sur la barre du haut */
.ds-shell{max-width:1380px;margin-inline:auto;grid-template-columns:236px minmax(0,1fr)}
.ds-shell.has-toc{grid-template-columns:236px minmax(0,1fr) 232px}
.ds-side{top:64px;height:calc(100vh - 64px);padding:var(--s-8) var(--s-5)}
.ds-toc{position:sticky;top:64px;align-self:start;max-height:calc(100vh - 64px);overflow:auto;
  padding:var(--s-10) var(--s-5) var(--s-8) 0}
.ds-block{scroll-margin-top:80px}

/* Nav latérale = style doc-nav (groupes + item actif en pastille douce) */
.ds-nav a{display:flex;align-items:center;gap:10px}
.ds-nav a .ti{color:var(--text-faint);font-size:1.05em;flex:0 0 auto}
.ds-nav a.active{background:var(--accent-soft);color:var(--accent-strong);font-weight:var(--fw-semi)}
.ds-nav a.active .ti{color:var(--accent-strong)}

/* Colonne de lecture : mesure confortable */
.ds-block>.lead{max-width:64ch}
.ds-block p:not([class]){max-width:68ch}

@media (max-width:1180px){
  .ds-shell.has-toc{grid-template-columns:236px minmax(0,1fr)}
  .ds-toc{display:none}
}
@media (max-width:880px){
  .ds-topbar .tb-links a{display:none}
  .ds-shell,.ds-shell.has-toc{grid-template-columns:1fr}
  .ds-side{position:static;height:auto;border-right:0;border-bottom:1px solid var(--border)}
  .footer .cols{grid-template-columns:1fr 1fr}
}

/* ==== extended.css (inliné par tools/flatten-css.mjs) ==== */
/* ============================================================================
   IBUDO DESIGN LANGUAGE — extended.css
   Familles supplémentaires + VARIANTES (feedback, overlays, data, navigation,
   plus de cartes, plus de hero, carrousels). Charge après components.css.
   Inspiré de Geist / welcome-ui / gov.sg, sur la guideline orbitale Ibudo.
   ============================================================================ */

/* ====================== BOUTONS — variantes en plus ===================== */
.btn-icon{width:44px;height:44px;padding:0;border-radius:50%}
.btn-icon.sq{border-radius:var(--r-md)}
.btn-group{display:inline-flex;border:1.5px solid var(--border);border-radius:var(--r-pill);overflow:hidden}
.btn-group .btn{border-radius:0;border:0;border-right:1.5px solid var(--border)}
.btn-group .btn:last-child{border-right:0}
.btn-group .btn.active{background:var(--accent);color:var(--on-accent)}
.btn[disabled],.btn.is-loading{opacity:.55;pointer-events:none}
.btn.is-loading .orb{animation:ibu-spin .8s linear infinite}
.btn-fab{position:relative;width:56px;height:56px;border-radius:50%;box-shadow:var(--shadow-2);background:var(--accent);color:var(--on-accent);font-size:22px}
@keyframes ibu-spin{to{transform:rotate(360deg)}}

/* ====================== SWITCH / SEGMENTED / RATING ===================== */
.switch{--w:46px;position:relative;width:var(--w);height:26px;border-radius:var(--r-pill);background:var(--border-strong);cursor:pointer;transition:background var(--dur-2);flex:0 0 auto}
.switch::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;transition:transform var(--dur-3) var(--spring)}
.switch.on{background:var(--accent)}
.switch.on::after{transform:translateX(20px)}
.segmented{display:inline-flex;background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-pill);padding:4px;gap:4px}
.segmented button,.segmented a{text-decoration:none;border:0;background:none;cursor:pointer;padding:8px 16px;border-radius:var(--r-pill);font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);color:var(--text-muted)}
.segmented button.active,.segmented a.active{background:var(--surface);color:var(--text);box-shadow:var(--shadow-1)}
.rating{display:inline-flex;gap:3px;color:var(--a-yellow-500)}
.rating .s{font-size:18px}.rating .s.off{color:var(--border-strong)}

/* ====================== STATUS / BADGES / KBD ========================== */
.status{display:inline-flex;align-items:center;gap:.5em;font-size:var(--t-sm);font-weight:var(--fw-med)}
.status .d{width:9px;height:9px;border-radius:50%;background:var(--n-400)}
.status.ok .d{background:var(--a-green-500);box-shadow:0 0 0 4px var(--a-green-100)}
.status.warn .d{background:var(--a-yellow-500)}
.status.err .d{background:var(--a-red-500);box-shadow:0 0 0 4px var(--a-red-100)}
.status.info .d{background:var(--ibu-blue-600)}
.kbd{font-family:var(--font-mono);font-size:.8rem;padding:2px 7px;border-radius:6px;border:1px solid var(--border-strong);border-bottom-width:2px;background:var(--surface-2)}
.dot-badge{position:relative}
.dot-badge::after{content:"";position:absolute;top:-2px;right:-2px;width:9px;height:9px;border-radius:50%;background:var(--a-red-500);border:2px solid var(--bg)}

/* ====================== ALERTS / CALLOUTS / TOAST ====================== */
/* Alertes — CONTOUR COMPLET (pas de bande latérale) + icône en pastille.
   Réfère les tokens feedback sémantiques (--color-feedback-*). */
/* Contour complet conservé + fond transparent glassmorphisme (teinté feedback). */
.alert{display:flex;gap:var(--s-4);align-items:flex-start;padding:var(--s-4) var(--s-5);
  border-radius:var(--r-md);border:1.5px solid var(--ec,var(--border));
  background:color-mix(in srgb, var(--ec,var(--text)) 7%, transparent);
  backdrop-filter:blur(10px) saturate(1.25);-webkit-backdrop-filter:blur(10px) saturate(1.25)}
.alert .ic{flex:0 0 auto;width:36px;height:36px;border-radius:50%;display:grid;place-items:center;
  font-size:20px;background:var(--ec-soft,var(--surface-2));color:var(--ec,var(--text-muted))}
.alert h5{font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm)}
.alert p{font-size:var(--t-sm);color:var(--text-muted)}
.alert .alert-bd{padding-top:2px}
.alert.info{--ec:var(--color-feedback-info);--ec-soft:var(--color-feedback-info-soft)}
.alert.success{--ec:var(--color-feedback-success);--ec-soft:var(--color-feedback-success-soft)}
.alert.warning{--ec:var(--color-feedback-warning);--ec-soft:var(--color-feedback-warning-soft)}
.alert.danger{--ec:var(--color-feedback-danger);--ec-soft:var(--color-feedback-danger-soft)}
.toast{display:inline-flex;align-items:center;gap:var(--s-3);background:var(--ibu-ink-800);color:#fff;
  padding:var(--s-3) var(--s-5);border-radius:var(--r-md);box-shadow:var(--shadow-2);font-size:var(--t-sm)}
.toast .d{width:9px;height:9px;border-radius:50%;background:var(--a-green-500)}

/* ====================== PROGRESS / SKELETON / SPINNER ================== */
.progress{height:8px;border-radius:var(--r-pill);background:var(--surface-2);overflow:hidden}
.progress>i{display:block;height:100%;background:var(--accent);border-radius:inherit;transition:width var(--dur-4) var(--ease)}
.progress-ring{width:54px;height:54px;display:grid;place-items:center;position:relative}
.progress-ring svg{transform:rotate(-90deg)}
.progress-ring .t{stroke:var(--surface-2)}.progress-ring .v{stroke:var(--accent);stroke-linecap:round}
.progress-ring b{position:absolute;font-family:var(--font-display);font-weight:var(--fw-bold);font-size:var(--t-sm)}
.skeleton{background:linear-gradient(90deg,var(--surface-2),var(--n-100),var(--surface-2));background-size:200% 100%;
  animation:ibu-shimmer 1.4s infinite;border-radius:var(--r-sm)}
@keyframes ibu-shimmer{to{background-position:-200% 0}}
.spinner{width:26px;height:26px;border-radius:50%;border:3px solid var(--surface-2);border-top-color:var(--accent);animation:ibu-spin .8s linear infinite}
@media (prefers-reduced-motion:reduce){.skeleton,.spinner,.btn.is-loading .orb{animation:none}}

/* ====================== CHARGEMENT (loaders, esprit orbital) ===========
   Bâtis sur le motif •••• et le « O ouvert ». Les 5 couleurs Ibudo, ou
   l'accent dynamique. transform/opacity, prefers-reduced-motion respecté. */
/* 1 — Points qui rebondissent (5 couleurs) */
.loader-dots{display:inline-flex;gap:8px;align-items:center}
.loader-dots i{width:11px;height:11px;border-radius:50%;display:block;animation:ld-bounce 1.1s ease-in-out infinite}
.loader-dots i:nth-child(1){background:var(--ibu-blue-600)}
.loader-dots i:nth-child(2){background:var(--a-green-500);animation-delay:.12s}
.loader-dots i:nth-child(3){background:var(--a-yellow-500);animation-delay:.24s}
.loader-dots i:nth-child(4){background:var(--a-violet-500);animation-delay:.36s}
.loader-dots i:nth-child(5){background:var(--a-red-500);animation-delay:.48s}
@keyframes ld-bounce{0%,65%,100%{transform:translateY(0)}30%{transform:translateY(-13px)}}

/* 2 — Orbite : 5 points tournent autour du noyau (signature « O ouvert ») */
.loader-orbit{position:relative;width:46px;height:46px;animation:ld-rot 1.4s linear infinite}
.loader-orbit i{position:absolute;top:50%;left:50%;width:9px;height:9px;margin:-4.5px 0 0 -4.5px;border-radius:50%}
.loader-orbit i:nth-child(1){background:var(--ibu-blue-600);transform:rotate(0deg) translateX(18px)}
.loader-orbit i:nth-child(2){background:var(--a-green-500);transform:rotate(72deg) translateX(18px)}
.loader-orbit i:nth-child(3){background:var(--a-yellow-500);transform:rotate(144deg) translateX(18px)}
.loader-orbit i:nth-child(4){background:var(--a-violet-500);transform:rotate(216deg) translateX(18px)}
.loader-orbit i:nth-child(5){background:var(--a-red-500);transform:rotate(288deg) translateX(18px)}
@keyframes ld-rot{to{transform:rotate(360deg)}}

/* 3 — Pulsations (accent dynamique) */
.loader-pulse{display:inline-flex;gap:9px}
.loader-pulse i{width:12px;height:12px;border-radius:50%;background:var(--accent);animation:ld-pulse 1s ease-in-out infinite}
.loader-pulse i:nth-child(2){animation-delay:.16s}
.loader-pulse i:nth-child(3){animation-delay:.32s}
@keyframes ld-pulse{0%,100%{opacity:.25;transform:scale(.7)}50%{opacity:1;transform:scale(1)}}

/* 4 — Anneau orbital (arc d'accent qui tourne) */
.loader-ring{width:44px;height:44px;border-radius:50%;
  background:conic-gradient(var(--accent) 0 30%, color-mix(in srgb,var(--accent) 14%,transparent) 0);
  -webkit-mask:radial-gradient(closest-side, transparent 68%, #000 70%);
  mask:radial-gradient(closest-side, transparent 68%, #000 70%);
  animation:ld-rot .9s linear infinite}

/* 5 — Barre indéterminée arc-en-ciel */
.loader-bar{height:5px;border-radius:var(--r-pill);background:var(--surface-2);overflow:hidden;position:relative}
.loader-bar::before{content:"";position:absolute;top:0;bottom:0;left:-40%;width:40%;border-radius:inherit;
  background:linear-gradient(90deg,var(--ibu-blue-600),var(--a-green-500),var(--a-yellow-500),var(--a-violet-500),var(--a-red-500));
  animation:ld-bar 1.3s ease-in-out infinite}
@keyframes ld-bar{0%{left:-40%}100%{left:100%}}

/* 6 — Vague (barres qui ondulent, accent) */
.loader-wave{display:inline-flex;gap:5px;align-items:center}
.loader-wave i{width:5px;height:22px;border-radius:var(--r-pill);background:var(--accent);animation:ld-wave 1s ease-in-out infinite}
.loader-wave i:nth-child(2){animation-delay:.1s}.loader-wave i:nth-child(3){animation-delay:.2s}
.loader-wave i:nth-child(4){animation-delay:.3s}.loader-wave i:nth-child(5){animation-delay:.4s}
@keyframes ld-wave{0%,100%{transform:scaleY(.4)}50%{transform:scaleY(1)}}

/* État de chargement (loader centré + libellé) */
.loading-state{display:grid;place-items:center;gap:var(--s-4);padding:var(--s-12);text-align:center;color:var(--text-muted)}

@media (prefers-reduced-motion:reduce){
  .loader-dots i,.loader-orbit,.loader-pulse i,.loader-ring,.loader-bar::before,.loader-wave i{animation:none}
  .loader-pulse i{opacity:1}
}

/* ====================== NAVIGATION : breadcrumb / pagination / stepper = */
.breadcrumb{display:flex;align-items:center;gap:.6em;font-size:var(--t-sm);color:var(--text-muted)}
.breadcrumb a:hover{color:var(--accent)}
.breadcrumb .sep{width:5px;height:5px;border-radius:50%;background:var(--border-strong)}
.pagination{display:inline-flex;gap:6px}
.pagination a{min-width:38px;height:38px;display:grid;place-items:center;border-radius:var(--r-sm);
  border:1px solid var(--border);font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);color:var(--text-muted);transition:border-color var(--dur-2),color var(--dur-2),background-color var(--dur-2)}
.pagination a:hover{border-color:var(--accent);color:var(--accent)}
.pagination a.active{background:var(--accent);color:var(--on-accent);border-color:transparent}
.stepper{display:flex;align-items:center;gap:0}
.stepper .st{display:flex;align-items:center;gap:var(--s-2);font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm);color:var(--text-muted)}
.stepper .st .n{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;border:2px solid var(--border-strong);font-size:var(--t-xs)}
.stepper .st.done .n{background:var(--accent);color:var(--on-accent);border-color:transparent}
.stepper .st.active .n{border-color:var(--accent);color:var(--accent)}
.stepper .line{flex:1;height:2px;background:var(--border);min-width:24px;margin:0 var(--s-3)}
.stepper .st.done+.line{background:var(--accent)}

/* ====================== OVERLAYS : tooltip / modal / drawer / popover === */
.tooltip{position:relative;display:inline-flex}
.tooltip .tip{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%) translateY(4px);
  background:var(--ibu-ink-800);color:#fff;padding:6px 12px;border-radius:var(--r-sm);font-size:var(--t-xs);white-space:nowrap;
  opacity:0;pointer-events:none;transition:opacity var(--dur-2),transform var(--dur-2)}
.tooltip:hover .tip{opacity:1;transform:translateX(-50%) translateY(0)}
.tooltip .tip::after{content:"";position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:var(--ibu-ink-800)}
.faux-vp{min-height:360px;border-radius:var(--r-lg);background:rgba(10,12,42,.45);display:flex;align-items:center;justify-content:center;padding:var(--s-6);position:relative;overflow:hidden}
.modal{background:var(--surface);border-radius:var(--r-lg);padding:var(--s-8);max-width:440px;width:100%;box-shadow:var(--shadow-3)}
.modal h3{font-size:var(--t-h3);margin-bottom:var(--s-2)}
.modal .x{position:absolute}
.drawer{position:absolute;top:0;right:0;bottom:0;width:min(380px,86%);background:var(--surface);padding:var(--s-8);box-shadow:var(--shadow-3)}
.popover{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:var(--shadow-2);padding:var(--s-3);min-width:200px}
.popover .row{padding:9px 12px;border-radius:var(--r-sm);font-size:var(--t-sm);display:flex;gap:.6em;align-items:center}
.popover .row:hover{background:var(--surface-2)}

/* ====================== DATA : table / list / empty / kpi ============== */
.table{width:100%;border-collapse:collapse;font-size:var(--t-sm)}
.table th{text-align:left;font-family:var(--font-display);font-weight:var(--fw-semi);color:var(--text-muted);
  padding:var(--s-3) var(--s-4);border-bottom:1px solid var(--border);font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.08em}
.table td{padding:var(--s-4);border-bottom:1px solid var(--border)}
.table tbody tr{transition:background var(--dur-2)}
.table tbody tr:hover{background:var(--surface-2)}
.table.zebra tbody tr:nth-child(even){background:var(--surface-2)}
.list-row{display:flex;align-items:center;gap:var(--s-4);padding:var(--s-4);border-bottom:1px solid var(--border)}
.list-row .meta{margin-left:auto;color:var(--text-muted);font-size:var(--t-sm)}
.empty{text-align:center;padding:var(--s-16) var(--s-6);max-width:420px;margin-inline:auto}
.empty .ill{width:88px;height:88px;border-radius:50%;margin:0 auto var(--s-5);display:grid;place-items:center;
  background:var(--accent-soft);color:var(--accent);font-size:34px}
.kpi{background:var(--surface-2);border-radius:var(--r-md);padding:var(--s-5)}
.kpi .l{font-size:var(--t-xs);color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em}
.kpi .v{font-family:var(--font-display);font-weight:var(--fw-black);font-size:1.9rem;margin-top:4px}
.kpi .delta{font-size:var(--t-xs);font-weight:var(--fw-semi)}
.kpi .delta.up{color:var(--a-green-600)}.kpi .delta.down{color:var(--a-red-600)}

/* ====================== AVATARS ======================================= */
.avatar-group{display:flex}
.avatar-group .avatar{margin-left:-12px;border:2px solid var(--bg)}
.avatar-group .avatar:first-child{margin-left:0}
.avatar-group .more{width:44px;height:44px;border-radius:50%;display:grid;place-items:center;margin-left:-12px;
  background:var(--surface-2);border:2px solid var(--bg);font-size:var(--t-xs);font-weight:var(--fw-bold);color:var(--text-muted)}

/* ====================== BANNER (annonce) ============================== */
.banner{display:flex;align-items:center;justify-content:center;gap:var(--s-3);padding:10px var(--s-5);
  background:var(--ibu-ink-700);color:#fff;font-size:var(--t-sm);text-align:center}
.banner a{text-decoration:underline;font-weight:var(--fw-semi)}
.banner.accent{background:var(--accent);color:var(--on-accent)}

/* ====================== CARTES — variantes en plus ==================== */
.card-article{overflow:hidden;padding:0;display:flex;flex-direction:column}
.card-article .ph{aspect-ratio:16/10;background:var(--surface-2)}
.card-article .bd{padding:var(--s-6);display:flex;flex-direction:column;gap:var(--s-2);flex:1}
.card-article .bd h4{font-size:var(--t-h4)}
.card-article .bd .meta{margin-top:auto;color:var(--text-faint);font-size:var(--t-xs);display:flex;gap:.6em;align-items:center}
/* Carte horizontale : média à gauche, contenu à droite */
.card-row{display:grid;grid-template-columns:minmax(96px,34%) 1fr;overflow:hidden;padding:0;align-items:stretch}
.card-row .ph{background:var(--surface-2);overflow:hidden}
.card-row .ph img{width:100%;height:100%;object-fit:cover;display:block;transition:transform var(--dur-4) var(--ease)}
.card-row:hover .ph img{transform:scale(1.05)}
.card-row .bd{padding:var(--s-6);display:flex;flex-direction:column;gap:var(--s-2);min-width:0;justify-content:center}
@media (max-width:520px){.card-row{grid-template-columns:1fr}.card-row .ph{aspect-ratio:16/9}}
.card-link{display:flex;align-items:center;gap:var(--s-4);padding:var(--s-5);border:1px solid var(--border);border-radius:var(--r-md);transition:border-color var(--dur-3),transform var(--dur-3)}
.card-link:hover{border-color:var(--accent);transform:translateX(4px)}
.card-link .arrow{margin-left:auto;color:var(--accent);transition:transform var(--dur-3)}
.card-link:hover .arrow{transform:translateX(4px)}
.card-profile{text-align:center}
.card-profile .av{width:84px;height:84px;border-radius:50%;margin:0 auto var(--s-4);outline:3px solid var(--accent);outline-offset:3px;background:var(--surface-2)}
.card-gradient{color:#fff;border:0;background:
  radial-gradient(120% 120% at 100% 0%, color-mix(in srgb,var(--accent) 85%, #000) 0%, var(--ibu-ink-700) 60%)}
.card-gradient h3,.card-gradient h4{color:#fff}.card-gradient p{color:rgba(255,255,255,.8)}
.card-glass{background:color-mix(in srgb,var(--surface) 60%,transparent);backdrop-filter:blur(12px);border:1px solid color-mix(in srgb,var(--text) 10%,transparent)}
/* bento */
/* minmax(0,1fr) et non 1fr : « 1fr » vaut minmax(auto,1fr), donc une piste
   peut dépasser sa part dès qu'un contenu a un min-content plus large, et la
   grille pousse la page en débordement horizontal. Invisible sur la démo du
   catalogue, qui n'a que des blocs vides ; mesuré sur une grille de 24 cartes
   réelles le 2026-08-31 (page 110px trop large). */
.bento{display:grid;gap:var(--s-4);grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:minmax(120px,auto)}
.bento>*{background:var(--surface-raised);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--s-6)}
.bento .lg{grid-column:span 2;grid-row:span 2}
.bento .wide{grid-column:span 2}
/* Deux paliers, et non un seul. À 760px, .wide doit être remis à plat lui
   aussi : la règle d'origine ne traitait que .lg, et une tuile large
   continuait de réclamer deux colonnes. Sous 560px, une seule colonne :
   deux colonnes de 170px ne peuvent pas contenir une carte à image, et la
   grille poussait la page à 929px de large sur un écran de 375. Mesuré sur
   collab.ibudo.co le 2026-08-31. */
@media (max-width:760px){.bento{grid-template-columns:repeat(2,minmax(0,1fr))}
  .bento .lg,.bento .wide{grid-column:span 2;grid-row:auto}}
@media (max-width:560px){.bento{grid-template-columns:minmax(0,1fr)}
  .bento .lg,.bento .wide{grid-column:auto;grid-row:auto}}

/* ====================== HERO — variantes ============================== */
.hero-split{display:grid;grid-template-columns:1.05fr .95fr;gap:var(--s-12);align-items:center}
.hero-split .media{aspect-ratio:4/3;border-radius:var(--r-xl);background:var(--surface-2);overflow:hidden;position:relative}
/* hero-compact : hero d'INDEX, pour une page dont le visiteur vient chercher une
   liste et non une promesse (accueil d'annuaire, de catalogue, d'événements).
   Le hero par défaut vise une accroche de trois mots : .hero .display plafonne
   la mesure à 15ch et --t-display monte à 7rem. Un titre en phrase y tombe sur
   quatre lignes de 112px et repousse le premier élément de la liste à plus de
   1200px du haut, donc hors de l'écran. Mesuré sur collab.ibudo.co le 2026-08-31.
   Ici : taille de h1, mesure de phrase, hauteur resserrée. */
.hero.hero-compact{padding-block:var(--s-12) var(--s-10)}
.hero.hero-compact .display{font-size:var(--t-h1);max-width:26ch}
.hero.hero-compact .lead{max-width:62ch;text-wrap:pretty}
@media (max-width:760px){.hero.hero-compact{padding-block:var(--s-10) var(--s-8)}}

.hero-center{text-align:center;max-width:760px;margin-inline:auto}
.hero-center .hero-cta{justify-content:center}
/* Titre d'un hero centré : le plein --t-display (jusqu'à 7rem) est calibré pour le
   hero-split ; centré, un titre de plus de ~20 caractères déborde du premier écran.
   (Le catalogue faisait déjà cette réduction en inline — règle mutualisée ici.) */
.hero-center .display{font-size:clamp(2.2rem,1.5rem + 3vw,4.2rem);max-width:22ch;margin-inline:auto}
.hero-image{position:relative;color:#fff;border-radius:var(--r-xl);overflow:hidden;padding:clamp(48px,7vw,110px);
  background:linear-gradient(180deg,rgba(10,12,42,.2),rgba(10,12,42,.7)),var(--ibu-ink-700)}
.hero-minimal{padding-block:clamp(60px,8vw,120px)}
.hero-minimal .display{font-size:clamp(2.4rem,5vw,4.2rem)}
.hero-stat{display:grid;grid-template-columns:1.2fr 1fr;gap:var(--s-12);align-items:end}
@media (max-width:820px){.hero-split,.hero-stat{grid-template-columns:1fr}}

/* ====================== CARROUSELS — variantes ======================= */
/* 1. marquee = dans components.css. 2. scroll-snap card slider : */
.carousel{display:flex;gap:var(--s-4);overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:var(--s-3);scrollbar-width:thin}
.carousel>*{scroll-snap-align:start;flex:0 0 clamp(240px,30%,320px)}
.carousel.peek>*{flex:0 0 clamp(260px,42%,420px)}
/* .fit : N cartes ENTIÈRES par vue (aucune coupée), pilotage aux flèches
   UNIQUEMENT — pas de défilement local (molette/swipe neutralisés, le JS
   anime scrollLeft). ⚠️ overflow:hidden sur LES DEUX AXES : `overflow-x`
   seul force overflow-y en auto → le moindre débordement vertical rend le
   carrousel scrollable à la molette (piège constaté). --per = cartes/vue. */
.carousel.fit{--per:3;overflow:hidden;scroll-snap-type:none;padding-bottom:0}
.carousel.fit>*{flex:0 0 calc((100% - (var(--per) - 1)*var(--s-4))/var(--per))}
@media (max-width:980px){.carousel.fit{--per:2}}
@media (max-width:640px){.carousel.fit{--per:1}}
.carousel-dots{display:flex;gap:8px;justify-content:center;margin-top:var(--s-4)}
.carousel-dots i{width:8px;height:8px;border-radius:50%;background:var(--border-strong);transition:background-color var(--dur-2),width var(--dur-2),border-radius var(--dur-2)}
.carousel-dots i.active{background:var(--accent);width:22px;border-radius:var(--r-pill)}
.carousel-ctrl{display:flex;gap:8px}

/* ====================== SPLIT FEATURE (alterné) ====================== */
.feature-split{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-12);align-items:center}
.feature-split:nth-of-type(even) .fs-media{order:2}
/* .reverse : alternance explicite quand les splits ne sont pas frères (un par <section>,
   cas des pages composées par sections — le :nth-of-type ci-dessus ne les voit pas). */
.feature-split.reverse .fs-media{order:2}
.fs-media{aspect-ratio:4/3;border-radius:var(--r-xl);background:var(--surface-2);overflow:hidden}
/* .portrait : média vertical (couverture de rapport, affiche…) — cadre 3/4 borné en largeur
   pour que la hauteur reste raisonnable dans la colonne. */
.fs-media.portrait{aspect-ratio:3/4;max-width:420px;margin-inline:auto}
@media (max-width:820px){.feature-split{grid-template-columns:1fr}.feature-split .fs-media,.feature-split.reverse .fs-media{order:-1}}

/* Un scope [data-theme] ré-ancre la couleur de texte : sans ça, les titres et textes
   sans couleur explicite HÉRITENT de la couleur calculée du body (encre) au lieu de
   re-résoudre var(--text) dans le scope → texte sombre sur fond Ink. No-op en clair. */
[data-theme]{color:var(--text)}

/* ====================== PROSE (contenu d'article/blog libre) ===========
   Le corps d'un article rédigé dans l'éditeur WP : titres à l'échelle LECTURE
   (pas display), rythme vertical qui respire (titre = grand espace AU-DESSUS,
   collé à son paragraphe EN DESSOUS), largeur de lecture confortable.
   À poser sur le conteneur de the_content() (cf. single.php). */
.prose{max-width:72ch;font-size:var(--t-body);line-height:1.75;color:var(--text)}
.prose > * + *{margin-top:var(--s-5)}
.prose :is(h2,h3,h4){font-family:var(--font-display);font-weight:var(--fw-bold);
  line-height:var(--lh-snug);letter-spacing:var(--tr-tight);color:var(--text);max-width:34ch}
.prose h2{font-size:clamp(1.55rem,1.3rem + 1vw,2rem);margin-top:var(--s-12)}
.prose h3{font-size:clamp(1.3rem,1.15rem + .6vw,1.6rem);margin-top:var(--s-10)}
.prose h4{font-size:var(--t-h4);margin-top:var(--s-8)}
/* un titre colle le bloc qui le suit (petit espace) plutôt que le rythme normal */
.prose :is(h2,h3,h4) + *{margin-top:var(--s-3)}
/* la bouillie de copier-coller Word/Docs : spans font-weight:400 dans les titres
   (titres qui paraissent maigres) → on rétablit le gras ; paragraphes "vides" &nbsp; neutralisés. */
.prose :is(h2,h3,h4) span{font-weight:inherit!important;font-size:inherit!important}
.prose p:empty,.prose p > br:only-child{display:none}
.prose p{max-width:72ch}
.prose ul,.prose ol{padding-left:1.5em}
.prose :is(ul,ol) li + li{margin-top:var(--s-2)}
.prose li::marker{color:var(--accent)}
.prose a{color:var(--accent);text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px}
.prose img{border-radius:var(--r-lg);margin-block:var(--s-6)}
.prose blockquote{border-left:3px solid var(--accent);padding-left:var(--s-5);color:var(--text-muted);font-style:italic}
.prose strong{font-weight:var(--fw-semi)}

/* ====================== DIVERS ======================================= */
.note{border-left:3px solid var(--accent);background:var(--accent-soft);padding:var(--s-4) var(--s-5);border-radius:0 var(--r-md) var(--r-md) 0;font-size:var(--t-sm)}
/* align-items:center, et non l'etirement par defaut : une pastille garde sa
   hauteur naturelle. Sans cette ligne, la plus haute de la rangee impose son
   gabarit a toutes les autres, et deux pastilles voisines n'ont plus la meme
   taille sans qu'on comprenne pourquoi. */
.chip-row{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap}
.divider-dots{display:flex;align-items:center;justify-content:center;gap:8px;color:var(--border-strong);margin-block:var(--s-8)}
.divider-dots i{width:6px;height:6px;border-radius:50%;background:currentColor}
.divider-dots i:nth-child(2){background:var(--accent)}

/* ====================== GRADIENT & GLASS (étendus) ===================== */
/* Dégradé de marque : accent → Ink, dans l'esprit du « O ouvert ». À doser. */
.grad-accent{color:#fff;border:0;background:radial-gradient(130% 130% at 100% 0%, color-mix(in srgb,var(--accent) 88%,#000) 0%, var(--ibu-ink-700) 62%)}
.grad-accent h1,.grad-accent h2,.grad-accent h3,.grad-accent h4{color:#fff}
.grad-accent p,.grad-accent .lead,.grad-accent .muted{color:rgba(255,255,255,.82)}
.grad-soft{background:linear-gradient(135deg,var(--accent-soft),var(--surface))}
/* Verre dépoli — à poser sur un média ou un gradient */
.glass{background:color-mix(in srgb,var(--surface) 55%,transparent);
  backdrop-filter:blur(14px) saturate(1.4);-webkit-backdrop-filter:blur(14px) saturate(1.4);
  border:1px solid color-mix(in srgb,var(--text) 10%,transparent)}
.glass-dark{background:rgba(20,24,42,.42);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border:1px solid rgba(255,255,255,.14);color:#fff}
/* Header glassmorphism (le .nav l'utilise déjà ; variante renforcée) */
.nav.glass-nav{background:color-mix(in srgb,var(--bg) 62%,transparent);backdrop-filter:blur(18px) saturate(1.5);-webkit-backdrop-filter:blur(18px) saturate(1.5)}
/* Bouton gradient (réservé aux CTA forts) */
.btn-gradient{color:#fff;border:0;background:linear-gradient(120deg,var(--accent),var(--accent-strong))}
.btn-gradient:hover{filter:brightness(1.07)}
/* Hero gradient */
.hero-gradient{position:relative;overflow:hidden;border-radius:var(--r-xl);padding:clamp(48px,7vw,110px);
  color:#fff;background:radial-gradient(120% 140% at 90% 10%, color-mix(in srgb,var(--accent) 80%,#000), var(--ibu-ink-700) 65%)}
.hero-gradient h1,.hero-gradient h2{color:#fff}
/* Hero « bandes obliques + verre » — full-bleed 100svh. Cinq bandes des couleurs
   Ibudo en diagonale (floues, masquées aux bords → présentes « un peu ») derrière un
   panneau glassmorphism qui les floute (effet premium). */
.hero-bands{position:relative;min-height:100vh;min-height:100svh;display:grid;place-items:center;
  overflow:hidden;isolation:isolate;background:var(--bg)}
.hero-bands .hb-bands{position:absolute;z-index:0;left:-15%;right:-15%;top:50%;height:min(620px,80%);
  transform:translateY(-50%) rotate(-14deg);pointer-events:none;filter:blur(7px);opacity:.62;
  background:linear-gradient(90deg,
    transparent 0 3%,
    color-mix(in srgb,var(--ibu-blue-600) 80%,transparent) 3% 19%,
    transparent 19% 22%,
    color-mix(in srgb,var(--a-green-500) 80%,transparent) 22% 38%,
    transparent 38% 41%,
    color-mix(in srgb,var(--a-yellow-500) 84%,transparent) 41% 57%,
    transparent 57% 60%,
    color-mix(in srgb,var(--a-violet-500) 80%,transparent) 60% 76%,
    transparent 76% 79%,
    color-mix(in srgb,var(--a-red-500) 80%,transparent) 79% 95%,
    transparent 95% 100%);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 22%,#000 78%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 22%,#000 78%,transparent)}
.hero-bands .hb-glass{position:relative;z-index:1;max-width:640px;margin-inline:auto;text-align:center;
  padding:clamp(32px,5vw,60px);border-radius:var(--r-xl);
  background:color-mix(in srgb,var(--surface) 55%,transparent);
  backdrop-filter:blur(22px) saturate(1.4);-webkit-backdrop-filter:blur(22px) saturate(1.4);
  border:1px solid color-mix(in srgb,var(--text) 12%,transparent);box-shadow:var(--shadow-3)}
/* Stat / KPI gradient */
.stat-grad{border-radius:var(--r-lg);padding:var(--s-6);color:#fff;
  background:radial-gradient(120% 120% at 100% 0%, color-mix(in srgb,var(--accent) 85%,#000), var(--ibu-ink-700))}
.stat-grad .n{color:#fff}.stat-grad .l{color:rgba(255,255,255,.75)}

/* ====================== COMPOSANTS DE TEMPLATE (Vague C) ===============
   Composants réutilisables introduits pour assembler les templates de page.
   ====================================================================== */

/* --- Maquette navigateur : montre un template dans un cadre "fenêtre" --- */
.browser-mock{border:1px solid var(--border);border-radius:var(--r-lg);overflow:hidden;
  background:var(--surface);box-shadow:var(--shadow-2)}
.bm-bar{display:flex;align-items:center;gap:var(--s-3);padding:10px var(--s-4);
  background:var(--surface-2);border-bottom:1px solid var(--border)}
.bm-dots{display:flex;gap:7px;flex:0 0 auto}
.bm-dots i{width:11px;height:11px;border-radius:50%;background:var(--border-strong)}
.bm-dots i:nth-child(1){background:var(--a-red-500)}
.bm-dots i:nth-child(2){background:var(--a-yellow-500)}
.bm-dots i:nth-child(3){background:var(--a-green-500)}
.bm-url{flex:1;min-width:0;display:flex;align-items:center;gap:.5em;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-pill);padding:6px 14px;
  font-family:var(--font-mono);font-size:var(--t-xs);color:var(--text-muted);
  overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.bm-url .ti{color:var(--a-green-600);font-size:1em;flex:0 0 auto}
.bm-actions{flex:0 0 auto;display:flex;gap:var(--s-2)}
.bm-frame{position:relative;background:var(--surface)}
.bm-frame iframe{display:block;width:100%;height:560px;border:0;background:var(--surface)}
@media (max-width:640px){.bm-actions .label{display:none}.bm-frame iframe{height:460px}}

/* --- Countdown (événement / festival) --- */
.countdown{display:flex;gap:var(--s-3);flex-wrap:wrap}
.cd-cell{flex:0 0 auto;min-width:84px;text-align:center;padding:var(--s-4) var(--s-3);
  border-radius:var(--r-md);background:var(--surface-raised);border:1px solid var(--border)}
.cd-n{font-family:var(--font-display);font-weight:var(--fw-black);
  font-size:clamp(2rem,4vw,3rem);line-height:1;color:var(--accent);
  letter-spacing:var(--tr-tight);font-variant-numeric:tabular-nums}
.cd-l{font-family:var(--font-display);font-weight:var(--fw-semi);text-transform:uppercase;
  letter-spacing:.12em;font-size:var(--t-xs);color:var(--text-faint);margin-top:var(--s-2)}
.countdown.on-dark .cd-cell{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.18)}
.countdown.on-dark .cd-n{color:#fff}
.countdown.on-dark .cd-l{color:rgba(255,255,255,.72)}
.countdown.done{opacity:.7}

/* --- Barre de filtres (annuaire / listing filtrable) --- */
.filter-bar{display:flex;gap:var(--s-2);flex-wrap:wrap;align-items:center}
.filter-bar .pill{cursor:pointer;user-select:none}
.filter-bar .pill[aria-pressed="true"]{background:var(--accent);color:var(--on-accent);border-color:transparent}
.filter-count{color:var(--text-faint);font-size:var(--t-sm)}
.is-filtered-out{display:none!important}

/* --- Docs : layout 3 colonnes + sommaire (TOC scrollspy) --- */
.doc-layout{display:grid;grid-template-columns:220px minmax(0,1fr) 200px;gap:var(--s-10);align-items:start}
.doc-nav{position:sticky;top:90px;align-self:start;display:grid;gap:2px;font-size:var(--t-sm)}
.doc-nav .grp{font-family:var(--font-display);font-weight:var(--fw-bold);font-size:.72rem;
  text-transform:uppercase;letter-spacing:.12em;color:var(--text-faint);margin:var(--s-5) 0 var(--s-2)}
.doc-nav a{padding:7px 12px;border-radius:var(--r-sm);color:var(--text-muted);font-weight:var(--fw-med)}
.doc-nav a:hover{background:var(--surface-2);color:var(--text)}
.doc-nav a.active{background:var(--accent-soft);color:var(--accent-strong)}
/* Variante 2 colonnes (contenu + sommaire) — quand la nav de gauche est déjà
   assurée par la sidebar du catalogue (ds-side). */
.doc-layout.two-col{grid-template-columns:minmax(0,1fr) 200px}
.doc-main{min-width:0}
.doc-main h2{margin:var(--s-10) 0 var(--s-4);scroll-margin-top:90px}
.doc-main>h2:first-child{margin-top:0}
.doc-main h3{margin:var(--s-6) 0 var(--s-3);scroll-margin-top:90px}
.doc-main p{margin-bottom:var(--s-4);max-width:var(--maxlen)}
.doc-main>ul{margin:0 0 var(--s-4) var(--s-5);display:grid;gap:var(--s-2);color:var(--text-muted)}
.doc-aside{position:sticky;top:90px;align-self:start}
.toc{display:grid;gap:4px;border-left:2px solid var(--border);padding-left:var(--s-4)}
.toc .toc-ttl{font-family:var(--font-display);font-weight:var(--fw-bold);font-size:.72rem;
  text-transform:uppercase;letter-spacing:.12em;color:var(--text-faint);margin-bottom:var(--s-2)}
.toc a{font-size:var(--t-sm);color:var(--text-muted);padding:3px 0}
.toc a:hover{color:var(--text)}
.toc a.active{color:var(--accent);font-weight:var(--fw-semi)}
@media (max-width:1080px){.doc-layout{grid-template-columns:1fr}.doc-nav,.doc-aside{display:none}}

/* ====================== SURFACES APPLICATIVES (auth + dashboard) =======
   « App » : on applique les tokens (couleurs/typo/champs/boutons), pas les
   blocs marketing. Cf. audit/COMPONENTS.md §E. */

/* --- Auth : split panneau Ink + formulaire (login / signup) --- */
.auth-split{display:grid;grid-template-columns:1.05fr .95fr;min-height:100vh}
.auth-aside{position:relative;overflow:hidden;background:var(--ibu-ink-700);color:#fff;
  padding:clamp(32px,5vw,64px);display:flex;flex-direction:column;justify-content:space-between;gap:var(--s-12)}
.auth-aside .display,.auth-aside h1,.auth-aside h2{color:#fff}
.auth-main{display:flex;align-items:center;justify-content:center;padding:clamp(28px,5vw,64px)}
.auth-form{width:100%;max-width:408px}
@media (max-width:820px){ .auth-split{grid-template-columns:1fr} .auth-aside{min-height:auto} }
/* Aperçu d'auth DANS la doc : hauteur bornée (on ne quitte pas le DS) */
.auth-preview{border:1px solid var(--border);border-radius:var(--r-lg);overflow:hidden}
.auth-preview .auth-split{min-height:480px}
.auth-preview .auth-aside,.auth-preview .auth-main{padding:clamp(20px,3vw,36px)}
@media (max-width:640px){.auth-preview .auth-split{min-height:0}}

/* Séparateur texte « ou » */
.or-sep{display:flex;align-items:center;gap:var(--s-3);color:var(--text-faint);font-size:var(--t-xs);
  text-transform:uppercase;letter-spacing:.1em;margin:var(--s-5) 0}
.or-sep::before,.or-sep::after{content:"";flex:1;height:1px;background:var(--border)}

/* Chips à bascule (centres d'intérêt, filtres de saisie) — hook data-chip-toggle */
.chip-toggle{cursor:pointer;user-select:none}
.chip-toggle[aria-pressed="true"]{background:var(--accent);color:var(--on-accent);border-color:transparent}

/* Formulaire multi-étapes (wizard) — hook data-wizard */
.wizard-step{display:none}
.wizard-step.active{display:block}
.wiz-bar{display:flex;gap:var(--s-2)}
.wiz-bar .seg{flex:1;height:5px;border-radius:var(--r-pill);background:var(--border);transition:background var(--dur-3) var(--ease)}
.wiz-bar .seg.on{background:var(--accent)}
/* radio « riche » (label descriptif sur une ligne) */
.radio-card{display:flex;align-items:flex-start;gap:.7em;padding:var(--s-3) 0;font-size:var(--t-sm);cursor:pointer}
.radio-card input{accent-color:var(--accent);width:18px;height:18px;margin-top:1px;flex:0 0 auto}

/* --- App shell (dashboard) --- */
.app-shell{display:grid;grid-template-columns:240px 1fr;min-height:100vh}
.app-nav{background:var(--ibu-ink-700);color:#fff;padding:var(--s-6) var(--s-4);
  display:flex;flex-direction:column;gap:2px;position:sticky;top:0;height:100vh;overflow:auto}
.app-nav .brand{margin:var(--s-2) var(--s-2) var(--s-6);display:block}
.app-nav .brand img{height:24px;width:auto}
.app-nav a{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:var(--r-sm);
  color:#c4c8ec;font-size:var(--t-sm);font-weight:var(--fw-med)}
.app-nav a .ti{color:#9aa0d8;flex:0 0 auto}
.app-nav a:hover{background:rgba(255,255,255,.08);color:#fff}
.app-nav a.active{background:var(--ibu-blue-600);color:#fff}
.app-nav a.active .ti{color:#fff}
.app-nav .grp{font-family:var(--font-display);font-size:.68rem;text-transform:uppercase;letter-spacing:.12em;color:#9aa0d8;margin:var(--s-5) var(--s-3) var(--s-2)}
.app-nav .app-foot{margin-top:auto}
.app-main{min-width:0;background:var(--bg-subtle)}
.app-topbar{position:sticky;top:0;z-index:10;display:flex;align-items:center;gap:var(--s-4);
  height:64px;padding-inline:var(--s-8);background:color-mix(in srgb,var(--bg) 85%,transparent);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-bottom:1px solid var(--border)}
.app-content{padding:var(--s-8)}
@media (max-width:820px){ .app-shell{grid-template-columns:1fr} .app-nav{display:none} }

/* Mini bar-chart (dashboard) — formes only, accent courant */
.bars{display:flex;align-items:flex-end;gap:var(--s-3);height:180px;padding-top:var(--s-6)}
.bars .col{flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;gap:var(--s-2);height:100%}
.bars .bar{width:100%;background:linear-gradient(var(--accent),var(--accent-soft));border-radius:var(--r-sm) var(--r-sm) 0 0;min-height:6px;transition:filter var(--dur-2)}
.bars .col:hover .bar{filter:brightness(1.05)}
.bars .lab{font-size:var(--t-xs);color:var(--text-faint)}

/* ====================== MÉDIA + TEXTE (texte qui flotte sur la photo) ===
   Photo plein cadre + scrim dégradé + contenu superposé. La couleur est
   « dynamique » : overline/CTA en accent, scrim teintable à l'accent (.tint),
   l'accent peut tourner par section (data-accent-rotate). */
.media-overlay{position:relative;isolation:isolate;overflow:hidden;border-radius:var(--r-xl);
  color:#fff;display:flex;flex-direction:column;justify-content:flex-end;
  min-height:clamp(360px,58vh,600px);padding:clamp(24px,4vw,52px);
  transition:transform var(--dur-3) var(--ease),box-shadow var(--dur-3) var(--ease)}
.media-overlay>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;
  transition:transform var(--dur-4) var(--ease)}
/* scrim : transparent en haut -> Ink en bas (texte lisible, contraste AA) */
.media-overlay::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to top, rgba(10,12,42,.92) 0%, rgba(10,12,42,.55) 38%, rgba(10,12,42,0) 72%)}
.media-overlay :is(h1,h2,h3,.display){color:#fff}
.media-overlay p{color:rgba(255,255,255,.85);max-width:46ch}
.media-overlay .overline{color:#fff}
.media-overlay .hero-cta{margin-top:var(--s-6)}
.media-overlay:hover{box-shadow:var(--shadow-3)}
.media-overlay:hover>img{transform:scale(1.05)}
/* variante : texte centré */
.media-overlay.center{justify-content:center;align-items:center;text-align:center}
.media-overlay.center::after{background:linear-gradient(rgba(10,12,42,.45),rgba(10,12,42,.65))}
.media-overlay.center p{margin-inline:auto}
/* variante : scrim TEINTÉ à l'accent (couleur dynamique forte) */
.media-overlay.tint::after{background:linear-gradient(to top,
  color-mix(in srgb,var(--accent) 78%, #0a0c2a) 0%,
  color-mix(in srgb,var(--accent) 30%, rgba(10,12,42,.55)) 42%, rgba(10,12,42,0) 78%)}
/* variante « fumée » : au survol, un nuage d'accent dérive et se déforme
   comme de la fumée en suivant le curseur (calque injecté par orbital.js). */
.media-overlay .smoke-layer{position:absolute;inset:0;pointer-events:none;opacity:0;
  mix-blend-mode:screen;will-change:transform,opacity;transition:opacity var(--dur-4) var(--ease);
  background:radial-gradient(circle 36% at var(--mx,50%) var(--my,50%),
    color-mix(in srgb,var(--accent) 92%,#fff) 0%,
    color-mix(in srgb,var(--accent) 62%,transparent) 40%, transparent 66%);
  filter:blur(40px) saturate(1.35)}
.media-overlay.smoke:hover .smoke-layer{opacity:.92;animation:ibu-smoke 7s ease-in-out infinite}
@keyframes ibu-smoke{0%,100%{transform:scale(1) rotate(0deg)}33%{transform:scale(1.2) rotate(7deg)}66%{transform:scale(1.08) rotate(-6deg)}}
@media (prefers-reduced-motion:reduce){.media-overlay.smoke:hover .smoke-layer{animation:none;opacity:.7}}

/* compact (carte de grille) */
.media-overlay.sm{min-height:clamp(260px,34vh,360px);padding:var(--s-6);border-radius:var(--r-lg)}
.media-overlay.sm h3{font-size:var(--t-h4)}
/* grille éditoriale de cartes photo+texte */
.media-grid{display:grid;gap:var(--s-4);grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.media-grid .feat{grid-column:span 2}
@media (max-width:720px){.media-grid .feat{grid-column:span 1}}

/* ====================== BOUTON « RETOUR EN HAUT » (flottant) ============
   Apparaît au scroll. Hook orbital.js : <button class="to-top" data-to-top>. */
.to-top{position:fixed;right:clamp(16px,3vw,28px);bottom:clamp(16px,3vw,28px);z-index:60;
  width:48px;height:48px;border-radius:var(--r-md);display:grid;place-items:center;font-size:22px;
  background:var(--accent);color:var(--on-accent);box-shadow:var(--shadow-2);border:0;cursor:pointer;
  opacity:0;transform:translateY(10px) scale(.9);pointer-events:none;
  transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--spring),background var(--dur-4)}
.to-top.show{opacity:1;transform:none;pointer-events:auto}
.to-top:hover{filter:brightness(1.05)}
@media (prefers-reduced-motion:reduce){.to-top{transition:opacity var(--dur-2)}}

/* ====================== PHOTOS — meilleure gestion (dynamisme + air) =====
   Remplissage propre (object-fit), léger zoom au survol, plus d'espace dans
   les splits, survol des photos d'articles. Mot d'accent sur photo. */
.fs-media>img,.hero-split .media>img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform var(--dur-4) var(--ease)}
.fs-media,.hero-split .media{transition:box-shadow var(--dur-3) var(--ease)}
.feature-split:hover .fs-media>img,.hero-split:hover .media>img{transform:scale(1.045)}
.feature-split:hover .fs-media,.hero-split:hover .media{box-shadow:var(--shadow-2)}
/* plus d'air : entre texte et photo, et entre splits empilés */
.feature-split{gap:clamp(var(--s-8),5vw,var(--s-16))}
.stack.lg>.feature-split + .feature-split{margin-top:var(--s-16)}
/* Photos d'articles : zoom au survol (façon welcometothejungle) */
.card-article .ph{overflow:hidden}
.card-article .ph img{width:100%;height:100%;object-fit:cover;transition:transform var(--dur-4) var(--ease)}
.card-article:hover .ph img{transform:scale(1.06)}
/* Mot d'accent sur une media-overlay (header photo + couleur dynamique, façon e-estonia) */
.media-overlay .hl{color:var(--accent)}
.media-overlay .display{text-wrap:balance}

/* ====================== TICKER DE VALEURS (bande déroulante) ===========
   Réutilise .marquee ; chaque item = pastille colorée + libellé. */
.vitem{display:inline-flex;align-items:center;gap:.6em;font-family:var(--font-display);
  font-weight:var(--fw-semi);font-size:var(--t-body);white-space:nowrap;color:var(--text)}
.vdot{width:11px;height:11px;border-radius:50%;flex:0 0 auto}

/* ====================== HERO SLIDER (galerie) + barre arc-en-ciel ======
   Façon Slider Revolution : UNE image à la fois (fondu). Une barre en bas,
   sur toute la largeur, se remplit (arc-en-ciel Ibudo) ; à la fin → image
   suivante. Piloté par orbital.js (heroGallery). */
.hero-gallery{position:relative;isolation:isolate;overflow:hidden;border-radius:var(--r-xl);
  min-height:clamp(440px,66vh,640px);display:flex;align-items:center;color:#fff;padding:clamp(28px,5vw,64px)}
.hg-slides{position:absolute;inset:0;z-index:-2}
.hg-slides img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity 1.1s var(--ease)}
.hg-slides img.active{opacity:1}
.hero-gallery::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(10,12,42,.32),rgba(10,12,42,.5) 55%,rgba(10,12,42,.82))}
.hero-gallery :is(h1,h2,.display){color:#fff}
.hero-gallery p{color:rgba(255,255,255,.86)}
/* barre de progression = défilement, en arc-en-ciel Ibudo */
.hg-progress{position:absolute;left:0;right:0;bottom:0;height:5px;background:rgba(255,255,255,.16);z-index:2;overflow:hidden}
.hg-progress>i{position:absolute;inset:0;clip-path:inset(0 100% 0 0);
  background:linear-gradient(90deg,var(--ibu-blue-600),var(--a-green-500),var(--a-yellow-500),var(--a-violet-500),var(--a-red-500))}
.hg-progress>i.run{animation:hg-fill var(--hg-dur,10s) linear forwards}
@keyframes hg-fill{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 0 0 0)}}
@media (prefers-reduced-motion:reduce){.hg-slides img{transition:none}.hg-progress>i{clip-path:inset(0 0 0 0)}}

/* Bande arc-en-ciel Ibudo autonome (déco) qui glisse de gauche à droite */
.rainbow-bar{height:6px;border-radius:var(--r-pill);overflow:hidden;
  background:linear-gradient(90deg,var(--ibu-blue-600),var(--a-green-500),var(--a-yellow-500),var(--a-violet-500),var(--a-red-500),var(--ibu-blue-600));
  background-size:200% 100%;animation:rainbow-slide 5s linear infinite}
@keyframes rainbow-slide{from{background-position:0 0}to{background-position:-200% 0}}
@media (prefers-reduced-motion:reduce){.rainbow-bar{animation:none}}

/* ====================== TITRE À MOT ROTATIF (façon WTTJ) ==============
   Un mot du titre change en boucle, dans un badge glass coloré : chaque mot
   prend une couleur Ibudo (--rc, pilotée par orbital.js), contour + verre,
   la largeur s'anime en douceur. Hook data-rotate. */
.rotator{display:inline-flex;align-items:center;justify-content:center;
  padding:.04em .36em;border:2px solid var(--rc,var(--accent));border-radius:var(--r-md);
  color:var(--rc,var(--accent));white-space:nowrap;overflow:hidden;vertical-align:.06em;
  background:color-mix(in srgb,var(--rc,var(--accent)) 12%,transparent);
  backdrop-filter:blur(6px) saturate(1.3);-webkit-backdrop-filter:blur(6px) saturate(1.3);
  transition:width .45s var(--ease),color .45s var(--ease),border-color .45s var(--ease),background .45s var(--ease)}
.rotator-word{display:inline-block}
.rotator-word.anim{animation:rot-word .45s var(--ease-out)}
@keyframes rot-word{from{opacity:0;transform:translateY(.5em)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.rotator{transition:none}.rotator-word.anim{animation:none}}

/* ====================== HERO « VITRE DE LABO » ========================
   Photo en fond + verre dépoli teinté des 5 couleurs Ibudo (buées mêlées),
   et doodles d'icônes « dessinés à la buée » sur la vitre (hook data-doodle,
   orbital.js — purement décoratif, aria-hidden). Se combine avec .hero et
   le titre à mot rotatif. Image : --hv-img sur la section. */
.hero-vitre{position:relative;isolation:isolate;overflow:hidden;color:#fff}
.hero-vitre::before{content:"";position:absolute;inset:0;z-index:-2;
  background:var(--hv-img) center/cover no-repeat}
.hero-vitre::after{content:"";position:absolute;inset:0;z-index:-1;
  backdrop-filter:blur(7px) saturate(1.2);-webkit-backdrop-filter:blur(7px) saturate(1.2);
  background:
    radial-gradient(46% 60% at 12% 18%, color-mix(in srgb,var(--ibu-blue-600) 22%,transparent), transparent 70%),
    radial-gradient(40% 55% at 88% 12%, color-mix(in srgb,var(--a-violet-500) 20%,transparent), transparent 70%),
    radial-gradient(42% 58% at 82% 86%, color-mix(in srgb,var(--a-green-500) 15%,transparent), transparent 70%),
    radial-gradient(36% 50% at 16% 88%, color-mix(in srgb,var(--a-red-500) 13%,transparent), transparent 70%),
    radial-gradient(30% 42% at 50% 2%, color-mix(in srgb,var(--a-yellow-500) 9%,transparent), transparent 70%),
    linear-gradient(180deg, rgba(10,12,42,.26), rgba(10,12,42,.52))}
.hero-vitre>.container{position:relative;z-index:1}
.hero-vitre :is(h1,h2,.display){color:#fff}
.hero-vitre .lead{color:rgba(255,255,255,.86)}
.hero-vitre .overline{color:rgba(255,255,255,.8)}
/* Doodles « à la buée » : traits doux aux 5 couleurs Ibudo (cyclées par
   orbital.js via color inline), léger flou + halo currentColor, comme
   dessinés du doigt sur une vitre embuée. Positions/tailles semées par JS. */
.doodle-layer{position:absolute;inset:0;z-index:0;pointer-events:none}
.doodle-layer .ti{position:absolute;color:rgba(255,255,255,.5);
  filter:blur(.4px);text-shadow:0 0 9px currentColor;
  transform:rotate(var(--da,0deg))}

/* ====================== MODAL FONCTIONNELLE (popup) =================== */
.modal-overlay{position:fixed;inset:0;z-index:var(--z-modal);display:grid;place-items:center;padding:var(--s-5);
  background:rgba(10,12,42,.55);backdrop-filter:blur(5px);-webkit-backdrop-filter:blur(5px);
  opacity:0;pointer-events:none;transition:opacity var(--dur-3) var(--ease)}
.modal-overlay.open{opacity:1;pointer-events:auto}
.modal-overlay .modal{transform:translateY(12px) scale(.98);transition:transform var(--dur-3) var(--spring);position:relative}
.modal-overlay.open .modal{transform:none}
@media (prefers-reduced-motion:reduce){.modal-overlay .modal{transition:none}}

/* ====================== TOAST (notifications) ======================== */
.toast-stack{position:fixed;right:clamp(14px,3vw,24px);bottom:clamp(14px,3vw,24px);z-index:calc(var(--z-modal) + 10);
  display:flex;flex-direction:column;gap:var(--s-3);width:min(360px,calc(100vw - 28px))}
.toast-stack .toast{width:100%}
.toast{position:relative;overflow:hidden;align-items:flex-start}
.toast .ti{font-size:18px;margin-top:1px}
.toast .tx{display:grid;gap:1px;min-width:0}
.toast .tt{font-family:var(--font-display);font-weight:var(--fw-semi);font-size:var(--t-sm)}
.toast .ts{font-size:var(--t-xs);color:rgba(255,255,255,.72)}
.toast .x{margin-left:auto;background:none;border:0;color:rgba(255,255,255,.6);cursor:pointer;font-size:17px;line-height:1;padding:0 2px}
.toast .x:hover{color:#fff}
.toast.success .d{background:var(--a-green-500)}
.toast.info .d{background:var(--ibu-blue-500)}
.toast.warning .d{background:var(--a-yellow-500)}
.toast.danger .d{background:var(--a-red-500)}
.toast .bar{position:absolute;left:0;bottom:0;height:3px;width:100%;transform-origin:left;background:var(--a-green-500);animation:toast-bar linear forwards}
.toast.info .bar{background:var(--ibu-blue-500)}.toast.warning .bar{background:var(--a-yellow-500)}.toast.danger .bar{background:var(--a-red-500)}
@keyframes toast-bar{to{transform:scaleX(0)}}
.toast.enter{animation:toast-in var(--dur-3) var(--spring)}
@keyframes toast-in{from{opacity:0;transform:translateX(22px)}to{opacity:1;transform:none}}
.toast.leave{opacity:0;transform:translateX(22px);transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease)}
@media (prefers-reduced-motion:reduce){.toast .bar,.toast.enter{animation:none}}

/* ====================== DROPDOWN MENU ================================ */
.dropdown{position:relative;display:inline-flex}
.dropdown-menu{position:absolute;top:calc(100% + 8px);left:0;min-width:210px;z-index:50;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:var(--shadow-2);
  padding:var(--s-2);opacity:0;transform:translateY(-6px);pointer-events:none;
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-2) var(--ease)}
.dropdown.open .dropdown-menu{opacity:1;transform:none;pointer-events:auto}
.dropdown-menu a,.dropdown-menu button{display:flex;align-items:center;gap:.6em;width:100%;
  padding:9px 12px;border-radius:var(--r-sm);font-size:var(--t-sm);color:var(--text);background:none;border:0;cursor:pointer;text-align:left}
.dropdown-menu a:hover,.dropdown-menu button:hover{background:var(--surface-2)}
.dropdown-menu .ti{color:var(--text-faint)}
.dropdown-menu .sep{height:1px;background:var(--border);margin:var(--s-2) 0}

/* ====================== PAGINATION GLASS ============================= */
.pagination.glass a{background:color-mix(in srgb,var(--surface) 55%,transparent);
  backdrop-filter:blur(10px) saturate(1.3);-webkit-backdrop-filter:blur(10px) saturate(1.3);
  border-color:color-mix(in srgb,var(--text) 12%,transparent)}
.pagination.glass a:hover{border-color:var(--accent);color:var(--accent)}
.pagination.glass a.active{background:var(--accent);border-color:transparent;color:var(--on-accent)}

/* ====================== UTILITAIRES DE DÉMO =========================== */
/* Mise en page des exemples (catalogue et sites) — remplace les style=""
   de layout dans les démos pour garder des snippets copiables propres.
   Empilement vertical : utiliser .stack (base.css). */
.u-row{display:flex;flex-wrap:wrap;gap:var(--s-3);align-items:center}
.u-center{display:grid;place-items:center}
.u-grid-auto{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--s-4)}
.u-txt-sm-muted{font-size:var(--t-sm);color:var(--text-muted)}

/* ====================== SPLASH (écran de chargement) =================== */
/* <div class="splash" data-splash> en tout début de <body> : voile plein
   écran aux couleurs Ibudo (points + wordmark), retiré par orbital.js dès
   que la page est chargée (600 ms min, failsafe 4 s, reduced-motion : retrait
   immédiat). Variante sombre : .splash.ink. La variante .static sert aux
   démos du catalogue (remplit son conteneur au lieu de l'écran). */
.splash{position:fixed;inset:0;z-index:calc(var(--z-modal) + 50);display:grid;place-items:center;
  background:var(--bg);transition:opacity .45s var(--ease),visibility .45s}
.splash.ink{background:var(--ibu-ink-700)}
.splash .inner{display:grid;justify-items:center;gap:var(--s-6)}
.splash img{height:26px}
.splash.ink img{filter:brightness(0) invert(1)}
.splash.done{opacity:0;visibility:hidden;pointer-events:none}
.splash.static{position:absolute;z-index:1}

/* ==========================================================================
   CARTE DE LISTING
   .vcard est faite pour des libellés courts : son titre est en --t-h3, soit
   jusqu'à 32 px face à un corps de 15 px, et son lien « go » n'apparaît qu'au
   survol en laissant un vide réservé. Sur une liste de projets aux titres longs,
   le résultat est un titre démesuré posé au-dessus d'un trou. D'où cette carte,
   pensée pour du contenu : titre à l'échelle du texte, hauteurs égales, et un
   pied de carte qui porte la méta au lieu d'un blanc.
   ========================================================================== */
.listing-card{display:flex;flex-direction:column;gap:var(--s-2);height:100%;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);
  padding:var(--s-5);text-decoration:none;color:inherit;
  transition:border-color var(--dur-2) var(--ease),box-shadow var(--dur-2) var(--ease),
             transform var(--dur-2) var(--ease)}
.listing-card:hover{border-color:var(--accent);box-shadow:var(--shadow-1);transform:translateY(-2px)}
.listing-card:active{transform:translateY(-2px) scale(.99)}

.listing-card .lc-org{display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  font-size:var(--t-xs);font-weight:var(--fw-semi);letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-muted)}
.listing-card .lc-org i{color:var(--a-green-500,#01d859);font-size:1.1em}
.listing-card .lc-demo{text-transform:none;letter-spacing:0;font-weight:var(--fw-med);
  background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-pill);
  padding:1px 8px;color:var(--text-muted)}

/* Titre à l'échelle du contenu : lisible, hiérarchisé, jamais monumental. */
.listing-card .lc-title{overflow-wrap:anywhere;font-family:var(--font-display);font-weight:var(--fw-semi);
  font-size:var(--t-h4);line-height:1.25;margin:0;text-wrap:balance}
.listing-card .lc-text{overflow-wrap:anywhere;color:var(--text-muted);font-size:var(--t-sm);margin:0}

/* Pied : la méta remplit l'espace au lieu de le laisser vide, et pousse les
   cartes d'une même rangée à la même hauteur. */
.listing-card .lc-foot{margin-top:auto;padding-top:var(--s-4);display:flex;align-items:center;
  gap:6px;flex-wrap:wrap;border-top:1px solid var(--border)}
/* Pastille ODD. Autonome : elle sert dans une carte de listing, dans un
   rapport, sur un tableau de bord et sur la page d'un objectif. Definie sous
   un parent, elle n'avait aucun style dans trois de ces quatre endroits.
   La largeur est un minimum, pas une taille fixe : « 17 » ne doit pas avoir
   moins de place que « 4 », et un cercle ecrase se voit tout de suite. */
.sdg-badge{display:inline-grid;place-items:center;box-sizing:border-box;
  min-width:28px;height:28px;padding-inline:7px;border-radius:var(--r-pill);
  color:#fff;font-family:var(--font-display);font-size:13px;font-weight:var(--fw-semi);
  line-height:1;font-variant-numeric:tabular-nums;text-decoration:none;flex:0 0 auto;
  transition:transform var(--dur-2),box-shadow var(--dur-2)}
a.sdg-badge:hover{transform:scale(1.06);box-shadow:var(--shadow-1)}
a.sdg-badge:active{transform:scale(.96)}
.sdg-badge:focus-visible{outline:2px solid var(--text);outline-offset:2px}
/* Variante compacte pour le pied d'une carte de listing, ou elle accompagne
   un texte de 12 px et ne doit pas lui voler la vedette. */
.sdg-badge.sm{min-width:22px;height:22px;padding-inline:5px;font-size:11px}
.listing-card .lc-meta{margin-left:auto;display:inline-flex;align-items:center;gap:4px;
  color:var(--text-muted);font-size:var(--t-xs)}

/* ==========================================================================
   PAGE DE DÉTAIL (projet, organisation, ressource)
   Contenu principal plus colonne d'action collante. Sans cette colonne, une
   fiche au contenu court se lit comme une suite de blocs pleine largeur séparés
   de grands vides, et l'action utile finit reléguée tout en bas.
   ========================================================================== */
.detail-split{display:grid;gap:var(--s-8);grid-template-columns:minmax(0,1fr)}
@media (min-width:920px){
  .detail-split{grid-template-columns:minmax(0,1.9fr) minmax(0,1fr);gap:var(--s-10)}
  .detail-aside{position:sticky;top:var(--s-8);align-self:start}
}

/* Bandeau d'en-tête d'une page de détail : plus dense qu'un hero de landing.
   Le titre y reste en h1 et non en .display, qui est réservé aux accueils.

   IMPORTANT : ce bloc PEINT son fond. Poser data-theme="ink" sur une section
   redéfinit ses tokens mais ne dessine rien : sans background, on obtient un
   texte clair sur du blanc, c'est-à-dire un grand vide. Constaté en production
   le 2026-08-02. Le fond et la couleur de texte viennent donc des tokens, ce qui
   marche aussi bien en clair qu'en Ink. */
.detail-head{padding-block:clamp(36px,4vw,64px);background:var(--bg);color:var(--text)}

/* RYTHME VERTICAL.
   L'espacement entre les éléments d'un en-tête doit suivre la taille du titre,
   pas une valeur fixe. Avec 16 px au-dessus d'un titre de 70 px et 12 px en
   dessous, tout se colle et le bloc paraît compressé, quelle que soit la
   hauteur du bandeau. Les écarts sont donc proportionnels : em pour ce qui
   touche au titre, échelle d'espacement pour le reste. */
.detail-head .overline{color:var(--text-faint);margin-bottom:var(--s-5)}
.detail-head h1{color:var(--text);font-size:clamp(1.9rem, 1.4rem + 2vw, 3rem);
  margin:0 0 var(--s-5)}
.detail-head .lead{max-width:52ch;color:var(--text-muted);margin:0}
.detail-head .chip-row{margin-top:var(--s-8)}
.detail-head .head-actions{display:flex;gap:var(--s-3);flex-wrap:wrap;margin-top:var(--s-10)}
.detail-head a{color:inherit}

/* Accueil : même alignement à gauche que les autres en-têtes, mais une échelle
   de titre plus grande et un rythme proportionnellement plus large, parce que
   c'est la seule affirmation de la page.
   ⚠️ L'échelle d'espacement du DS n'a PAS de --s-7, --s-9 ni --s-11. Un var()
   sur un token inexistant rend la déclaration invalide et la marge tombe à zéro
   sans le moindre avertissement : c'est ce qui collait tout le bloc. */
.detail-head.is-home{padding-block:clamp(64px,6.5vw,112px)}
.detail-head.is-home .overline{margin-bottom:var(--s-6)}
.detail-head.is-home h1{font-size:var(--t-h1);max-width:17ch;margin:0 0 var(--s-6)}
.detail-head.is-home .lead{max-width:54ch;font-size:var(--t-lead)}
.detail-head.is-home .head-actions{margin-top:var(--s-12)}

/* Rôle ouvert : une ligne, pas une carte. Une carte pour trois mots crée
   un bloc vide qui donne l'impression que la page manque de contenu. */
/* Le chiffre reste insecable (« 20 h par semaine · 10 places » ne doit pas se
   casser n'importe ou), mais la RANGEE, elle, se replie. Sans ce flex-wrap, un
   intitule long dans une colonne etroite poussait le chiffre hors de la carte.
   justify-content plutot que margin-left:auto : une fois repliee, la seconde
   ligne revient au debut au lieu de rester collee a droite, toute seule. */
.role-row{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;
  gap:2px var(--s-3);padding:var(--s-3) 0;border-bottom:1px solid var(--border)}
.role-row:last-child{border-bottom:0}
.role-row .rr-name{font-weight:var(--fw-semi);min-width:0}
.role-row .rr-meta{color:var(--text-muted);font-size:var(--t-sm);
  font-variant-numeric:tabular-nums;white-space:nowrap}

/* Case à cocher dont le libellé est une PHRASE, éventuellement avec des liens.
   .check est un inline-flex avec gap : sans conteneur, chaque fragment de texte
   et chaque <a> devient un élément flex distinct, la phrase se casse en colonnes
   et la ponctuation finale se détache. Le libellé doit donc tenir dans un seul
   <span>, et l'alignement passe en haut dès qu'il occupe plusieurs lignes. */
.check > span{display:block;min-width:0}
.check.check-start{align-items:flex-start;line-height:var(--lh-normal,1.55)}
.check.check-start input{flex:0 0 auto;margin-top:.15em}

/* ==========================================================================
   CERTIFICAT & VÉRIFICATION
   Famille ajoutée pour ENGAGE (certification de l'engagement). Trois niveaux de
   confiance à distinguer d'un coup d'œil : vérifié, attesté, auto-déclaré. La
   distinction est portée par la FORME (icône, contour) autant que par la
   couleur, pour rester lisible en daltonisme et en impression noir et blanc.
   ========================================================================== */

/* Sceau de confiance. */
.trust-badge{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:var(--r-pill);
  font-size:var(--t-xs);font-weight:var(--fw-semi);line-height:1;border:1px solid transparent;white-space:nowrap}
.trust-badge i{font-size:1.05em}
.trust-badge.verified{background:var(--a-green-50,#e9fbf1);color:var(--a-green-700,#017a33);
  border-color:var(--a-green-500,#01d859)}
.trust-badge.attested{background:var(--ibu-blue-50,#eef3fe);color:var(--ibu-blue-700,#1450b4);
  border-color:var(--ibu-blue-200,#b9cdf7)}
.trust-badge.declared{background:var(--surface-2);color:var(--text-muted);border-color:var(--border)}
.trust-badge.revoked{background:var(--a-red-50,#fdecec);color:var(--a-red-700,#b3261e);
  border-color:var(--a-red-500,#f04438)}

/* Carte de certificat : bandeau d'accent en tête, contenu en paires. */
.cert-card{position:relative;background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:var(--s-6);overflow:hidden;
  box-shadow:0 1px 2px rgba(16,24,40,.04),0 8px 24px rgba(16,24,40,.06)}
.cert-card::before{content:"";position:absolute;inset:0 0 auto 0;height:4px;background:var(--accent)}
.cert-card.is-revoked::before{background:var(--a-red-500,#f04438)}
.cert-card.is-revoked{opacity:.92}
.cert-card .cert-head{display:flex;align-items:flex-start;gap:var(--s-4);flex-wrap:wrap;
  margin-bottom:var(--s-5)}
.cert-card .cert-head h2,.cert-card .cert-head h3{margin:0;font-family:var(--font-display);
  font-weight:var(--fw-semi);text-wrap:balance}
.cert-card .cert-id{font-family:var(--font-mono);font-size:var(--t-sm);letter-spacing:.06em;
  color:var(--text-muted);font-variant-numeric:tabular-nums}

/* Paires clé/valeur du certificat. */
.cert-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));gap:var(--s-4) var(--s-5);
  margin:var(--s-5) 0}
.cert-meta > div{min-width:0}
.cert-meta dt,.cert-meta .k{color:var(--text-muted);font-size:var(--t-xs);text-transform:uppercase;
  letter-spacing:.06em;margin-bottom:3px}
.cert-meta dd,.cert-meta .v{margin:0;font-weight:var(--fw-med);overflow-wrap:anywhere}

/* Empreinte : monospace, coupable proprement, sélectionnable d'un clic. */
.hash-mono{font-family:var(--font-mono);font-size:var(--t-xs);color:var(--text-muted);
  background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-sm);
  padding:8px 10px;overflow-wrap:anywhere;user-select:all;display:block}

/* Bandeau de résultat de vérification. */
.verify-banner{display:flex;align-items:center;gap:var(--s-4);padding:var(--s-5) var(--s-6);
  border-radius:var(--r-lg);border:1px solid transparent;margin-bottom:var(--s-6)}
.verify-banner .vb-icon{flex:0 0 auto;width:44px;height:44px;border-radius:var(--r-pill);
  display:grid;place-items:center;font-size:22px}
.verify-banner h1,.verify-banner h2{margin:0 0 2px;font-size:var(--t-h4);font-family:var(--font-display)}
.verify-banner p{margin:0;font-size:var(--t-sm)}
.verify-banner.ok{background:var(--a-green-50,#e9fbf1);border-color:var(--a-green-500,#01d859)}
.verify-banner.ok .vb-icon{background:var(--a-green-500,#01d859);color:#fff}
.verify-banner.ko{background:var(--a-red-50,#fdecec);border-color:var(--a-red-500,#f04438)}
.verify-banner.ko .vb-icon{background:var(--a-red-500,#f04438);color:#fff}
.verify-banner.warn{background:var(--a-yellow-50,#fffbe6);border-color:var(--a-yellow-600,#d9b400)}
.verify-banner.warn .vb-icon{background:var(--a-yellow-600,#d9b400);color:var(--ibu-ink-900,#111)}

/* QR de vérification, posé à côté du certificat. */
.cert-qr{display:grid;gap:var(--s-2);justify-items:center;text-align:center}
.cert-qr img,.cert-qr svg{width:132px;height:132px;border:1px solid var(--border);
  border-radius:var(--r-md);background:#fff;padding:6px}
.cert-qr .cap{font-size:var(--t-xs);color:var(--text-muted)}

@media (max-width:640px){
  .cert-card{padding:var(--s-5)}
  .verify-banner{flex-direction:column;align-items:flex-start;gap:var(--s-3)}
}

/* ---- Réordonnancement (poignée, flèches, barre d'enregistrement) -------- */
/* La poignée fait 40 px de zone tactile pour une icône de 20 : en dessous, on
   rate la prise sur mobile et le glisser devient un défilement. */
.reorder-handle{display:flex;align-items:center;justify-content:center;width:40px;height:40px;flex:none;
  border:0;border-radius:var(--r-sm);background:none;color:var(--text-faint);cursor:grab;
  transition:background-color .15s cubic-bezier(.2,0,0,1),color .15s cubic-bezier(.2,0,0,1)}
.reorder-handle:hover{background:var(--surface-2);color:var(--text-muted)}
.reorder-handle:active{cursor:grabbing;scale:.96}
.reorder-handle:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.reorder-row{transition:box-shadow .15s cubic-bezier(.2,0,0,1),opacity .15s cubic-bezier(.2,0,0,1)}
.reorder-row.is-dragging{opacity:.6;box-shadow:0 1px 2px rgba(0,0,0,.06),0 12px 32px rgba(0,0,0,.16)}
.reorder-arrows{display:none;flex-direction:column;gap:2px;flex:none}
.reorder-arrows .btn{min-height:36px;padding-inline:var(--s-2)}
@media (hover:none){.reorder-handle{display:none}.reorder-arrows{display:flex}}
.order-bar{position:sticky;bottom:var(--s-4);z-index:5;display:flex;gap:var(--s-4);align-items:center;
  justify-content:space-between;max-width:44rem;margin-top:var(--s-5);padding:var(--s-3) var(--s-4);
  border-radius:var(--r-md);background:var(--surface);font-size:var(--t-sm);
  box-shadow:0 1px 2px rgba(0,0,0,.06),0 10px 28px rgba(0,0,0,.12)}

/* ---- Objectifs de developpement durable, en fiche projet ----------------
   Grille a deux colonnes et non un flex en ligne : la pastille tient sa propre
   colonne, et TOUT le texte, intitule comme cibles, s'aligne sur la seconde.
   Avec l'ancien flex, l'intitule s'alignait sur la pastille mais les cibles
   retombaient sur une indentation en pixels qui ne coincidait avec rien :
   trois alignements differents dans un meme bloc. */
.sdg-list{display:grid;gap:var(--s-6)}
.sdg-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--s-3);align-items:start}
.sdg-item .pill{text-decoration:none}
.sdg-body{min-width:0}
.sdg-goal{margin:0;font-weight:var(--fw-semi);text-wrap:pretty}
.sdg-target{margin:var(--s-3) 0 0;font-size:var(--t-sm);color:var(--text-muted);text-wrap:pretty}
.sdg-target strong{color:var(--text);font-variant-numeric:tabular-nums;margin-right:.35em}

/* ---- Rapport par ODD ---------------------------------------------------
   Le libelle est le nom COURT de l'objectif, pas son intitule officiel : la
   version longue fait trois lignes et noie le chiffre, qui est ce qu'on vient
   lire. L'intitule complet reste en infobulle et sur la page /odd/<n>. */
.sdg-report-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  gap:var(--s-4);align-items:start;padding-block:var(--s-4)}
.sdg-report-row + .sdg-report-row{border-top:1px solid var(--border)}
.srr-label{margin:0 0 var(--s-3);font-weight:var(--fw-semi);text-wrap:pretty}
.srr-bar{display:block;height:6px;border-radius:3px;background:var(--surface-2);overflow:hidden}
.srr-bar > span{display:block;height:100%;border-radius:3px}
.srr-figures{text-align:right;min-width:8rem}
.srr-hours{display:block;font-weight:var(--fw-semi);font-variant-numeric:tabular-nums}
.srr-sub{display:block;font-size:var(--t-xs);color:var(--text-muted)}
@media (max-width:560px){
  .sdg-report-row{grid-template-columns:auto minmax(0,1fr)}
  .srr-figures{grid-column:2;text-align:left;min-width:0}
}

/* ---- Guide de demarrage ------------------------------------------------
   Une seule etape porte un bouton : celle a faire maintenant. Un guide qui
   propose quatre actions equivalentes ne guide rien, il remet la decision a
   celui qui vient justement d'arriver. */
.steps-guide{list-style:none;margin:0;padding:0;display:grid;gap:var(--s-1,4px);counter-reset:sg}
.steps-guide li{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:var(--s-4);
  align-items:center;padding:var(--s-4);border-radius:var(--r-md);
  transition:background-color var(--dur-2)}
.steps-guide li.is-current{background:var(--accent-soft)}
.steps-guide .sg-mark{display:grid;place-items:center;width:34px;height:34px;border-radius:50%;
  background:var(--surface-2);color:var(--text-faint);flex:0 0 auto}
.steps-guide li.is-current .sg-mark{background:var(--accent);color:var(--on-accent)}
.steps-guide li.is-done .sg-mark{background:var(--a-green-500,#01D859);color:#0b3d1d}
.steps-guide .sg-body{min-width:0;display:grid;gap:2px}
.steps-guide .sg-body strong{font-family:var(--font-display);font-size:var(--t-body)}
.steps-guide .sg-body span{font-size:var(--t-sm);color:var(--text-muted);text-wrap:pretty}
.steps-guide li.is-done .sg-body strong{color:var(--text-muted);text-decoration:line-through;
  text-decoration-thickness:1px;text-decoration-color:var(--border-strong)}
.steps-guide .sg-later{font-size:var(--t-xs);color:var(--text-faint);white-space:nowrap}
@media (max-width:560px){
  .steps-guide li{grid-template-columns:auto minmax(0,1fr)}
  .steps-guide li > .btn,.steps-guide .sg-later{grid-column:2}
}

/* ═══ Initiales colorées ══════════════════════════════════════════════════
   Sans photo, .avatar retombe sur un disque gris. Répété quinze fois sur une
   grille de projets, ça donne une page morte et des personnes indistinctes.
   La couleur se pose par data-accent, donc elle vient des tokens et reste dans
   la palette. Elle doit être DÉTERMINISTE côté serveur (dérivée du nom) : la
   même personne garde sa couleur d'un écran à l'autre, c'est ce qui la rend
   reconnaissable du coin de l'oeil. */
.avatar[data-accent]{background:var(--accent-soft);color:var(--accent-strong);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 22%,transparent)}
[data-theme="ink"] .avatar[data-accent]{background:color-mix(in srgb,var(--accent) 30%,transparent);
  color:#fff;box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 45%,transparent)}

/* ═══ Orbite d'événements ═════════════════════════════════════════════════
   Carrousel 3D en boucle pour une page d'index d'événements. Chaque entrée est
   un « viseur » : un disque qui cadre le visuel de l'événement. Celui du centre
   est net et de face, les autres reculent, pivotent et se floutent. La mise au
   point fait le travail que ferait autrement un titre énorme : elle dit où
   regarder, sans crier.

   Le placement est calculé en JS (data-orbit dans orbital.js) parce qu'il dépend
   du nombre d'entrées ; le CSS ne porte que l'apparence et les transitions, pour
   qu'un défaut de JS laisse une liste de liens utilisable. */
.event-orbit{position:relative;perspective:1200px;perspective-origin:50% 45%;
  min-height:clamp(280px,32vw,380px);display:grid;place-items:center}
.orbit-track{position:relative;width:100%;height:100%;transform-style:preserve-3d;
  display:grid;place-items:center}
.orbit-item{position:absolute;display:grid;justify-items:center;gap:var(--s-4);
  text-decoration:none;color:inherit;will-change:transform,filter,opacity;
  transition:transform var(--dur-6,.6s) var(--ease),filter var(--dur-6,.6s) var(--ease),
             opacity var(--dur-6,.6s) var(--ease)}
.orbit-lens{position:relative;width:clamp(160px,21vw,260px);aspect-ratio:1;border-radius:50%;
  overflow:hidden;background:var(--surface-2);display:grid;place-items:center;
  box-shadow:0 24px 60px -20px rgba(0,0,0,.55),0 0 0 10px rgba(255,255,255,.06),
             inset 0 0 0 1px rgba(0,0,0,.08)}
.orbit-lens img{width:100%;height:100%;object-fit:cover;display:block}
/* Le cercle du viseur, posé par-dessus l'image : c'est lui qui donne l'idée
   d'optique plutôt que de simple vignette ronde. */
.orbit-lens::after{content:"";position:absolute;inset:0;border-radius:50%;pointer-events:none;
  box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--accent) 65%,transparent),
             inset 0 0 0 12px rgba(255,255,255,.14)}
.orbit-item .orbit-name{font-family:var(--font-display);font-weight:var(--fw-semi);
  font-size:var(--t-body);text-align:center;max-width:22ch;text-wrap:balance}
.orbit-item .orbit-meta{font-size:var(--t-xs);color:var(--text-muted)}
/* Les entrées hors foyer : reculées, floutées, effacées. Elles restent
   cliquables, elles ne sont pas décoratives. */
.orbit-item[data-focus="0"]{z-index:3}
.orbit-item:not([data-focus="0"]){filter:blur(4px) saturate(.55);opacity:.32;z-index:1}
.orbit-item:not([data-focus="0"]) .orbit-name,
.orbit-item:not([data-focus="0"]) .orbit-meta{opacity:0}
.orbit-item:focus-visible{outline:none}
.orbit-item:focus-visible .orbit-lens{outline:3px solid var(--accent);outline-offset:6px}
.orbit-nav{display:flex;gap:var(--s-3);justify-content:center;align-items:center;margin-top:var(--s-6)}
.orbit-dots{display:inline-flex;gap:8px;align-items:center}
.orbit-dots button{width:9px;height:9px;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:var(--border);transition:background var(--dur-3,.3s) var(--ease),transform var(--dur-3,.3s) var(--ease)}
.orbit-dots button[aria-current="true"]{background:var(--accent);transform:scale(1.35)}
/* Cible tactile : la pastille fait 9px, son atteinte doit faire 40px. */
.orbit-dots button{position:relative}
.orbit-dots button::before{content:"";position:absolute;inset:-16px}
@media (max-width:640px){
  .event-orbit{min-height:340px}
  .orbit-item:not([data-focus="0"]){opacity:.35}
}
@media (prefers-reduced-motion:reduce){
  .orbit-item{transition:none}
  .orbit-item:not([data-focus="0"]){filter:none;opacity:.7}
}

/* ═══ Scène d'accueil plein écran ═════════════════════════════════════════
   Une page d'index qui tient sur le premier écran : photo de fond, contenu
   centré, pied de page collé en bas SANS position:fixed (qui mangerait le
   contenu au moindre débordement). 100svh et non 100vh : sur mobile, vh compte
   la barre d'adresse repliée, et le pied de page se retrouve sous le pli. */
body.stage-page{min-height:100svh;display:flex;flex-direction:column}
body.stage-page > main{flex:1;display:flex;flex-direction:column;justify-content:center}
/* Le voile et la photo sont DEUX COUCHES DE LA MÊME propriété background, et
   non un pseudo-élément en z-index négatif. Motif : avec isolation:isolate, un
   ::before en z-index:-1 dépend de l'ordre de peinture du contexte
   d'empilement, et le résultat n'était pas celui attendu (photo invisible sous
   un aplat). Deux couches de background, elles, se composent toujours dans
   l'ordre déclaré : le dégradé d'abord, donc au-dessus, la photo dessous.
   La photo arrive par --stage-img, posée en ligne par le gabarit. */
.stage-photo{position:relative;flex:1;display:grid;place-items:center;
  /* Trois couches. Un puits sombre au centre, là où vivent le titre et le
     viseur : c'est lui qui sépare le contenu de la photo. Un dégradé vertical
     pour ancrer le haut et le bas. La photo dessous, qui respire sur les bords.
     Sans ce puits, deux couches photographiques de force égale se battaient et
     le titre devenait pénible à lire. */
  background-image:radial-gradient(ellipse 62% 58% at 50% 46%,
                     rgba(11,13,32,.95) 0%,rgba(11,13,32,.72) 55%,rgba(11,13,32,.30) 100%),
                   linear-gradient(180deg,rgba(11,13,32,.72) 0%,rgba(11,13,32,.42) 45%,rgba(11,13,32,.92) 100%),
                   var(--stage-img,none);
  background-size:cover,cover,cover;background-position:center,center,center;
  background-repeat:no-repeat,no-repeat,no-repeat;
  /* Multiply plutôt qu'une simple superposition : le voile assombrit la photo
     sans la laver, elle garde sa matière et cesse de concurrencer le contenu.
     Deux couches photographiques de force égale, c'est du bruit. */
  background-blend-mode:normal,multiply,normal}
.stage-photo,.stage-photo .orbit-name,.stage-photo h1,.stage-photo .lead{color:#fff}
.stage-photo .lead{color:rgba(255,255,255,.78)}
.stage-photo .orbit-meta{color:rgba(255,255,255,.66)}
.stage-photo .orbit-lens{background:rgba(255,255,255,.08)}
.stage-photo .orbit-dots button{background:rgba(255,255,255,.28)}
.stage-photo .orbit-dots button[aria-current="true"]{background:#fff}
.stage-photo .btn-ghost{color:#fff;border-color:rgba(255,255,255,.35)}
.stage-photo .btn-ghost:hover{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.6)}

/* ═══ Vignette générée ════════════════════════════════════════════════════
   Une carte sans image laissait un trou, et une grille où une tuile sur deux a
   une image et l'autre non est exactement ce qui donne des hauteurs en dents de
   scie. Ici : un aplat dégradé tiré de l'accent, l'initiale du projet en grand.
   Déterministe, donc le même projet garde sa vignette d'une visite à l'autre. */
.thumb{position:relative;display:grid;place-items:center;width:100%;height:170px;
  border-radius:var(--r-md);overflow:hidden;background:var(--surface-sunken)}
.thumb img{width:100%;height:100%;object-fit:cover;display:block;
  outline:1px solid rgba(0,0,0,.1);outline-offset:-1px}
.thumb.generated{background:linear-gradient(135deg,
  color-mix(in srgb,var(--accent) 24%,var(--surface-raised)) 0%,
  color-mix(in srgb,var(--accent) 8%,var(--surface-raised)) 100%)}
.thumb.generated span{font-family:var(--font-display);font-weight:var(--fw-black);
  font-size:3.2rem;line-height:1;color:color-mix(in srgb,var(--accent) 62%,transparent);
  user-select:none}
/* Le motif des quatre points, en filigrane : la vignette générée reste une
   surface Ibudo, pas un carré de couleur anonyme. */
.thumb.generated::after{content:"";position:absolute;right:12px;bottom:12px;width:46px;height:8px;
  background:radial-gradient(circle 4px at 4px 4px,color-mix(in srgb,var(--accent) 45%,transparent) 99%,transparent 100%)
             repeat-x;background-size:14px 8px;opacity:.8}

/* ═══ Grille de projets ═══════════════════════════════════════════════════
   Trois par ligne, toutes de la même hauteur. C'est ce que fait l'outil de
   référence, et c'est ce qui rend une liste de vingt-trois projets lisible :
   le bento donnait des tuiles de 202 à 420px, l'oeil n'a plus de ligne de base.
   Le titre et le résumé sont tronqués à un nombre de lignes fixe, sinon la
   variation de contenu ressort quand même. */
.project-grid{display:grid;gap:var(--s-5);grid-template-columns:repeat(3,minmax(0,1fr));align-items:stretch}
.project-grid > *{min-width:0}
.project-grid .listing-card{height:100%}
.project-grid .lc-title{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;min-height:2.4em}
.project-grid .lc-text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;min-height:3.9em}
@media (max-width:900px){.project-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.project-grid{grid-template-columns:minmax(0,1fr)}}

/* ═══ Aperçu en fenêtre ═══════════════════════════════════════════════════
   Fenêtre superposée qui affiche le contenu d'une page sans quitter la liste.
   Comportement : data-peek (orbital.js). Le lien reste un vrai lien, la fenêtre
   n'est qu'un raccourci : sans JavaScript, on obtient la page complète. */
.peek-modal{position:relative;width:min(880px,94vw);max-height:88vh;overflow:auto;
  background:var(--surface-raised);border-radius:var(--r-lg);padding:var(--s-8) var(--s-8) var(--s-10);
  box-shadow:0 40px 90px -30px rgba(11,13,32,.55),0 0 0 1px rgba(0,0,0,.06)}
.peek-modal .section{padding-block:0}
.peek-modal .container,.peek-modal .container.narrow{padding-inline:0;max-width:none}
.peek-close{position:sticky;top:0;float:right;margin:calc(var(--s-4) * -1) calc(var(--s-4) * -1) 0 0;
  background:var(--surface-raised);z-index:2}
.peek-body:focus{outline:none}
.peek-body .loading-state{display:grid;place-items:center;min-height:220px}
@media (max-width:640px){
  .peek-modal{width:100vw;max-height:100svh;height:100svh;border-radius:0;padding:var(--s-6)}
}
