/* ============================================================================
   Oltanis — ce qui ne sert QU'À l'accueil.
   Chargé par index.php seulement, APRÈS site.css, dont il dépend pour les
   tokens, la trame et les composants communs.

   Séparé de site.css parce que ces 52 Ko partaient sur les vingt-sept pages
   sans y avoir la moindre cible : héros et tableau de bord, bento, carte des
   modules, cartes de prix, option facturation, Olto, FAQ, vidéo, actualités.

   Une règle ne descend ici que si aucune autre page que l'accueil ne porte un
   élément qu'elle vise — et à condition qu'aucune règle postérieure de
   site.css ne la recouvre, faute de quoi la cascade changerait de vainqueur
   (voir l'en-tête de site.css).
   ========================================================================== */
img { max-width: 100%; display: block; }
.section-encre { background: var(--encre); color: var(--blanc); }
.section-encre .section-head { border-color: var(--blanc-20); }
.section-encre .section-intro { color: var(--blanc-80); }
.section-encre .section-pag { color: var(--blanc-60); }

/* ===========================================================================
   Hero
   ========================================================================== */
.hero { position: relative; border-bottom: 1px solid var(--hairline); overflow: hidden; }
.hero::before { content: ""; position: absolute; inset: -10% -5% auto auto; width: 70%; height: 120%; background: var(--glow-cobalt); pointer-events: none; z-index: 0; }
.hero-inner { position: relative; z-index: 1; padding-top: 64px; padding-bottom: 72px; }
/* Entrée échelonnée du hero (motion premium) */
@media (prefers-reduced-motion: no-preference) {
  .hero-eyebrow[data-reveal] { transition-delay: 40ms; }
  .hero-lead[data-reveal]    { transition-delay: 220ms; }
  .hero-actions[data-reveal] { transition-delay: 320ms; }
  .hero-trust[data-reveal]   { transition-delay: 400ms; }}
@media (min-width: 768px) { .hero-inner { padding-top: 88px; padding-bottom: 96px; }}
.hero-grid { display: grid; grid-template-columns: 1fr; gap: 56px; align-items: center; }
@media (min-width: 1000px) { .hero-grid { grid-template-columns: 1.05fr 0.95fr; gap: 64px; }}
.hero-eyebrow { display: inline-flex; align-items: center; gap: 12px; padding: 7px 14px; border: 1px solid var(--hairline); border-radius: 999px; }
.hero-eyebrow .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--cobalt); }
@media (prefers-reduced-motion: no-preference) { .hero-eyebrow .dot { animation: pulse 2.4s ease-in-out infinite; }}
.hero-title { margin: 28px 0 0; max-width: 16ch; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.045em; font-size: clamp(44px, 7vw, 82px); line-height: 0.94; }
.hero-title .accent-i { color: var(--cobalt); font-style: italic; }
.hero-lead { margin: 28px 0 0; max-width: 46ch; font-size: clamp(17px, 2vw, 20px); line-height: 1.55; color: var(--encre-80); }
.hero-actions { margin-top: 36px; display: flex; flex-wrap: wrap; gap: 12px; }
.hero-trust { margin-top: 28px; display: flex; flex-wrap: wrap; gap: 8px 22px; }
.hero-trust span { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--encre-60); display: inline-flex; align-items: center; gap: 8px; }
.hero-trust span::before { content: "—"; color: var(--accent-texte); }

/* Hero dashboard mock — pure CSS, hairline / table aesthetic, gentle float */
.dash-float { will-change: transform; }
@media (prefers-reduced-motion: no-preference) { .dash-float { animation: floaty 7s ease-in-out infinite; }}
.dash { border: 1px solid var(--encre); }
.dash-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--hairline); background: var(--encre); color: var(--blanc); }
.dash-bar .wm { font-size: 16px; color: var(--blanc); }
.dash-bar .wm .accent-i { color: var(--accent-display); }   /* barre sombre du mock, pas la carte blanche */
.dash-live { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em; display: inline-flex; align-items: center; gap: 8px; color: var(--blanc-70); }
.dash-live .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--cobalt); display: inline-block; }
@media (prefers-reduced-motion: no-preference) { .dash-live .dot { animation: pulse 2.4s ease-in-out infinite; }}
.dash-kpis { display: grid; grid-template-columns: repeat(3, 1fr); }
.dash-kpi { padding: 18px 16px; border-right: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }
.dash-kpi:nth-child(3) { border-right: none; }
.dash-kpi .k-label { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--encre-60); }
.dash-kpi .k-val { margin-top: 8px; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.045em; font-size: 30px; line-height: 1; }
/* Le mock du tableau de bord est un îlot BLANC dans la page sombre : ses gris
   suivent l'échelle --encre. --encre-50 y valait 3,71:1 à 10-14 px. */
.dash-kpi .k-val .unit { font-size: 14px; color: var(--encre-60); margin-left: 2px; }
.dash-rows { padding: 6px 0; }
.dash-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 14px; padding: 11px 16px; }
.dash-row + .dash-row { border-top: 1px solid var(--hairline); }
.dash-row .r-idx { font-family: var(--font-mono); font-size: 11px; color: var(--encre-60); }
.dash-row .r-name { font-size: 14px; font-weight: 500; }
.dash-row .r-meta { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--encre-60); }
.dash-row .r-tag { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; padding: 3px 8px; border-radius: 999px; }
.dash-row .r-tag.ok { color: var(--cobalt); border: 1px solid var(--cobalt); }
.dash-row .r-tag.muted { color: var(--encre-60); border: 1px solid var(--hairline); }

/* ===========================================================================
   Targets band
   ========================================================================== */
.targets { border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); background: var(--blanc); }
.targets-inner { display: flex; align-items: center; flex-wrap: wrap; gap: 16px 0; padding-top: 26px; padding-bottom: 26px; }
.targets-list { display: flex; flex-wrap: wrap; align-items: center; gap: 0; flex: 1; }
.targets-item { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.04em; font-size: clamp(22px, 3vw, 34px); line-height: 1; padding: 0 clamp(16px, 3vw, 36px); color: var(--encre); transition: color var(--dur-ui) var(--ease), transform var(--dur-ui) var(--ease); cursor: default; }
.targets-item:hover { color: var(--accent-texte); transform: translateY(-2px); }
.targets-item + .targets-item { border-left: 1px solid var(--hairline); }

/* ---- Bande de garanties / confiance (proof strip) ---------------------- */
.trustband { border-bottom: 1px solid var(--hairline); background: var(--blanc); overflow-x: clip; }
.trustband-inner { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px; padding-top: 18px; padding-bottom: 18px; }
.trustband-list { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 22px; }
.trustband-item svg { flex: none; width: 15px; height: 15px; color: var(--accent-texte); }
@media (max-width: 640px) { .trustband-inner { gap: 10px 18px; } .trustband-lab { width: 100%; }}

/* ===========================================================================
   Problème → Solution
   ========================================================================== */
.ps-grid { display: grid; grid-template-columns: 1fr; gap: 0; border: 1px solid var(--blanc-20); }
@media (min-width: 860px) { .ps-grid { grid-template-columns: 1fr 1fr; }}
.ps-col { padding: 36px; }
@media (min-width: 768px) { .ps-col { padding: 48px; }}
.ps-col + .ps-col { border-top: 1px solid var(--blanc-20); }
@media (min-width: 860px) { .ps-col + .ps-col { border-top: none; border-left: 1px solid var(--blanc-20); }}
.ps-col.is-sol { background: var(--cobalt); }
.ps-h { margin: 18px 0 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.045em; font-size: clamp(26px, 3vw, 36px); line-height: 1.02; }
.ps-list { list-style: none; margin: 28px 0 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
.ps-list li { display: flex; align-items: baseline; gap: 14px; padding: 16px 0; font-size: 16px; line-height: 1.5; color: var(--blanc-80); border-top: 1px solid var(--blanc-15); }
.ps-list li .m { font-family: var(--font-mono); font-size: 12px; color: var(--blanc-60); flex: none; width: 16px; }
.ps-col.is-sol .ps-list li { color: var(--blanc-90); border-color: var(--blanc-20); }
.ps-col.is-sol .ps-list li .m { color: var(--blanc); }

/* ===========================================================================
   Bénéfices
   ========================================================================== */
.benef-num { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.045em; font-size: 30px; line-height: 1; color: var(--cobalt); }

/* ===========================================================================
   Modules — compteurs + cartes de la carte mentale
   ========================================================================== */
.mod-count { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--hairline); border: 1px solid var(--hairline); margin-bottom: 40px; }
@media (min-width: 720px) { .mod-count { grid-template-columns: repeat(4, 1fr); }}
.mod-count .cell { background: var(--blanc); padding: 24px 28px; }
.mod-count .num { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.045em; font-size: clamp(40px, 5vw, 56px); line-height: 1; }
.mod-count .lab { margin-top: 8px; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--encre-60); }
.module-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.module-icon { width: 54px; height: 54px; flex: none; display: block; }
.module-name { margin: 18px 0 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.045em; font-size: clamp(26px, 3vw, 31px); line-height: 1.05; }
.module-desc { margin: 12px 0 0; font-size: 14px; line-height: 1.5; color: var(--encre-80); }

/* ===========================================================================
   Comment ça marche
   ========================================================================== */
/* Démarrage — timeline horizontale dynamique (badges + trait cobalt qui se trace) */
.steps { position: relative; display: grid; grid-template-columns: 1fr; gap: 30px; }
@media (min-width: 820px) {
  .steps { grid-template-columns: repeat(3, 1fr); gap: 36px; }
  .steps::before, .steps::after { content: ""; position: absolute; top: 26px; left: 9%; right: 9%; height: 2px; z-index: 0; }
  .steps::before { background: var(--blanc-20); }
  .steps::after { background: var(--cobalt); transform-origin: left center; transform: scaleX(0); }}
@media (min-width: 820px) and (prefers-reduced-motion: no-preference) { .steps::after { transition: transform 1000ms var(--ease-out) 250ms; }}
.steps.is-revealed::after { transform: scaleX(1); }
.step { position: relative; z-index: 1; background: none; padding: 0; min-height: auto; display: flex; flex-direction: column; align-items: flex-start; }
.step-num { width: 54px; height: 54px; flex: none; border-radius: 999px; border: 2px solid var(--cobalt); background: var(--encre); color: var(--blanc); display: grid; place-items: center; font-family: var(--font-display); font-weight: 800; font-size: 21px; letter-spacing: -0.04em; }
.step-t { margin: 22px 0 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.04em; font-size: 24px; line-height: 1.06; }
.step-b { margin: 12px 0 0; font-size: 15px; line-height: 1.6; color: var(--blanc-80); }

/* ===========================================================================
   Réassurance
   ========================================================================== */
/* Confiance — cartes premium (bordées, accent cobalt, élévation + spotlight au survol) */
.assure-grid { display: grid; grid-template-columns: 1fr; gap: 14px; }
@media (min-width: 640px) { .assure-grid { grid-template-columns: repeat(2, 1fr); }}
@media (min-width: 1000px) { .assure-grid { grid-template-columns: repeat(4, 1fr); }}
.assure-t { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.04em; font-size: 21px; line-height: 1.08; }
/* `margin-top:auto` poussait le paragraphe en bas de la carte. Les cartes étant
   étirées à la hauteur de leur rangée, l'écart titre → texte suivait le nombre
   de lignes du titre : mesuré 142, 33, 121, 33, 56, 33, 77, 56 px sur les huit
   cartes du même bloc — un intérieur en dents de scie. Sans lui, le gap:12px du
   conteneur s'applique partout pareil et le mou retombe sous le paragraphe. */
.assure-b { font-size: 14px; line-height: 1.55; color: var(--encre-80); }

/* ===========================================================================
   Tarifs
   ========================================================================== */
.pricing-grid { display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 680px)  { .pricing-grid { grid-template-columns: repeat(2, 1fr); }}
/* Six packs depuis l'ajout de Solo et Solo IA : en 4 colonnes, la dernière
   rangée n'en portait que deux. 3 colonnes donnent deux rangées pleines. */
@media (min-width: 1200px) { .pricing-grid { grid-template-columns: repeat(3, 1fr); }}
/* Business IA : accent cobalt + liseré supérieur (carte « nouveau ») */
.pcol-ia { border-color: rgba(60, 99, 242, 0.55); }
.pcol-ia-olto { display: flex; align-items: center; gap: 12px; margin-top: 18px; }
.pcol-ia-olto .olto-ava { flex: none; width: 52px; height: 52px; border-radius: 14px; background: #fff; object-fit: contain; border: 1px solid var(--hairline); }
.pcol-ia-olto span { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--encre-60); line-height: 1.35; }
.pcol-ia-olto strong { font-weight: 500; color: var(--encre-85); }
.pcol-ia::before { content: ""; position: absolute; left: -1px; right: -1px; top: -1px; height: 3px; background: var(--grad-cobalt); }
.pcol-ia:hover { border-color: var(--cobalt); box-shadow: var(--shadow-cobalt); }
.pcol-cur { font-size: 0.4em; font-weight: 800; letter-spacing: 0; margin-left: 6px; margin-top: 0.16em; }
.pcol-amount--text { font-size: clamp(30px, 2.7vw, 38px); letter-spacing: -0.02em; }
.pcol-desc { margin-top: 18px; font-size: 15px; line-height: 1.55; color: var(--encre-80); }
.pcol-dark .pcol-desc { color: var(--blanc-80); }
/* Halo cobalt de la carte Business IA (élément dédié : le ::after sert déjà au
   spotlight). Ne respire QU'en vue, classe .is-live posée par landing.js. */
.pcol-glow { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; }
/* ---- Phase 4 : tarifs — les tirets se cochent, le prix pop, la carte IA respire */
@media (prefers-reduced-motion: no-preference) {
  .pricing-grid.is-revealed .pcol-feat li .tick { transform: scaleX(1); }
  .pcol-feat li:nth-child(6) .tick { transition-delay: 510ms; }
  .pricing-grid.is-revealed .pcol-amount { animation: pcolPricePop 560ms var(--ease-spring) 160ms both; }
  .pcol-ia.is-live .pcol-glow { box-shadow: 0 0 38px -6px rgba(60,99,242,0.58); animation: pcolBreathe 4.4s ease-in-out infinite; }}
/* L'argument qui justifie que l'option soit séparée des packs : c'est la
   première chose à lire sur la carte, avant la description. */
.addon-argument { display: block; margin-bottom: 8px; font-family: var(--font-display);
  font-weight: 800; letter-spacing: -.02em; font-size: 18px; line-height: 1.25; color: var(--blanc); }

/* CTA diagnostic (section "constat", fond encre) */
.probleme-cta { margin-top: 40px; padding-top: 32px; border-top: 1px solid var(--blanc-20); display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.probleme-cta-t { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.03em; font-size: clamp(20px, 2.6vw, 28px); line-height: 1.1; color: var(--blanc); margin: 0; }

/* Demo banner (inside pricing area) */
.demo-banner { margin-top: 16px; border: 1px solid var(--encre); background: var(--encre); color: var(--blanc); padding: 32px; display: flex; flex-direction: column; gap: 24px; }
@media (min-width: 760px) { .demo-banner { flex-direction: row; align-items: center; justify-content: space-between; padding: 36px 44px; }}
.demo-banner-t { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.04em; font-size: clamp(26px, 3vw, 38px); line-height: 1.02; max-width: 22ch; }
.demo-banner-t .accent-i { color: var(--cobalt); font-style: italic; }
.demo-banner-sub { margin: 12px 0 0; max-width: 36ch; font-size: 14px; line-height: 1.5; color: var(--blanc-70); }

/* ===========================================================================
   Scroll reveal (sober: fade + 8px translate)
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  /* Révélations directionnelles : déclarées dans colors_and_type.css, elles
     étaient écrasées par la règle ci-dessus — même spécificité, fichier chargé
     après. Redéclarées ici pour que data-dir produise enfin son effet. */
  [data-reveal][data-dir="left"]:not([data-stagger])  { transform: translateX(-30px); }
  [data-reveal][data-dir="right"]:not([data-stagger]) { transform: translateX(30px); }
  [data-reveal][data-dir].is-revealed                 { transform: none; }

  /* ---- Phase 2 : entrées chorégraphiées ------------------------------------
     Garanties : chaque ✓ se DESSINE (stroke-dashoffset via pathLength=1) juste
     après l'apparition de son libellé, en cascade. */
  .trustband-item svg path { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 420ms var(--ease-out); }
  .trustband-item.is-revealed svg path { stroke-dashoffset: 0; }
  .trustband-item[data-reveal]:nth-child(1) svg path { transition-delay: 210ms; }
  .trustband-item[data-reveal]:nth-child(2) svg path { transition-delay: 280ms; }
  .trustband-item[data-reveal]:nth-child(3) svg path { transition-delay: 350ms; }
  .trustband-item[data-reveal]:nth-child(4) svg path { transition-delay: 420ms; }
  .trustband-item[data-reveal]:nth-child(5) svg path { transition-delay: 490ms; }

  /* Bénéfices : le réseau de la carte maîtresse se « connecte » — le nœud
     central pulse en premier, les liens se tracent du centre vers l'extérieur,
     puis les nœuds périphériques apparaissent. Déclenché quand la carte est
     révélée (elle mène la cascade en tant que 1er enfant du bento). */
  .bv-lines line { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 520ms var(--ease-out); }
  .bv-nodes circle { transform: scale(0); transform-box: fill-box; transform-origin: center; transition: transform 360ms var(--ease-spring); }
  .bento-cell.is-lg.is-revealed .bv-lines line { stroke-dashoffset: 0; }
  .bento-cell.is-lg.is-revealed .bv-nodes circle { transform: scale(1); }
  .bv-nodes circle:nth-child(1) { transition-delay: 120ms; }
  .bv-lines line:nth-child(1) { transition-delay: 220ms; }
  .bv-lines line:nth-child(2) { transition-delay: 300ms; }
  .bv-lines line:nth-child(3) { transition-delay: 380ms; }
  .bv-lines line:nth-child(4) { transition-delay: 460ms; }
  .bv-nodes circle:nth-child(2) { transition-delay: 560ms; }
  .bv-nodes circle:nth-child(3) { transition-delay: 620ms; }
  .bv-nodes circle:nth-child(4) { transition-delay: 680ms; }
  .bv-nodes circle:nth-child(5) { transition-delay: 740ms; }}

/* ===========================================================================
   Olto — assistant IA (section dédiée)
   ========================================================================== */
.olto { position: relative; overflow: hidden; }
.olto::before { content: ""; position: absolute; inset: -25% -8% auto auto; width: 58%; height: 130%; background: radial-gradient(closest-side, rgba(60, 99, 242, 0.20), transparent 70%); pointer-events: none; z-index: 0; }
.olto > .page { position: relative; z-index: 1; }
.olto-grid { display: grid; grid-template-columns: 1fr; gap: 34px; align-items: center; }
@media (min-width: 920px) { .olto-grid { grid-template-columns: 1.04fr 0.96fr; gap: 56px; }}
.olto-feats { display: flex; flex-direction: column; gap: 26px; }
.olto-feat { display: flex; gap: 18px; align-items: flex-start; }
.olto-num { flex: none; font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.06em; color: var(--accent-texte); border: 1px solid var(--cobalt); border-radius: 999px; width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center; }
.olto-feat-t { margin: 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.03em; font-size: clamp(19px, 2.1vw, 24px); line-height: 1.1; color: var(--blanc); }
.olto-feat-b { margin: 9px 0 0; font-size: 15px; line-height: 1.55; color: var(--blanc-80); max-width: 48ch; }

/* Mini-conversation (illustration) */
.olto-chat { background: linear-gradient(180deg, rgba(255,255,255,0.055), rgba(255,255,255,0.02)); border: 1px solid var(--blanc-20); border-radius: 18px; padding: 20px; display: flex; flex-direction: column; gap: 12px; box-shadow: 0 30px 80px -42px rgba(0,0,0,0.85), 0 0 0 1px rgba(60,99,242,0.12); }
.olto-chat-head { display: flex; align-items: center; gap: 12px; padding-bottom: 14px; border-bottom: 1px solid var(--blanc-20); margin-bottom: 2px; }
.olto-avatar { flex: none; width: 44px; height: 44px; border-radius: 12px; background: #fff; object-fit: contain; border: 1px solid var(--blanc-20); box-shadow: var(--glow-cobalt); }
.olto-name { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.02em; color: var(--blanc); font-size: 16px; line-height: 1.1; }
.olto-status .dot { width: 7px; height: 7px; border-radius: 50%; background: #36d399; display: inline-block; }
.olto-msg { max-width: 86%; padding: 11px 14px; border-radius: 14px; font-size: 14px; line-height: 1.45; }
.olto-msg.user { align-self: flex-end; background: rgba(255,255,255,0.08); color: var(--blanc-90); border-bottom-right-radius: 4px; }
.olto-msg.bot { align-self: flex-start; background: rgba(60,99,242,0.18); border: 1px solid rgba(60,99,242,0.42); color: var(--blanc); border-bottom-left-radius: 4px; }
/* Chat joué en direct (assets/olto-chat.js) : messages révélés 1 par 1, bulle
   « en train d'écrire » avant chaque réponse d'Olto. */
@media (prefers-reduced-motion: no-preference) {
  .olto-chat.is-playing .olto-msg { display: none; }
  .olto-chat.is-playing .olto-msg.is-in { display: block; animation: oltoMsgIn 340ms var(--ease-out) both; }}
.olto-cta { margin-top: 44px; display: flex; flex-wrap: wrap; align-items: center; gap: 14px 20px; }
.olto-cta-note { font-size: 15px; color: var(--blanc-80); }
.olto-cta-note strong { color: var(--blanc); }
@media (max-width: 560px) { .olto-chat { padding: 16px; } .olto-msg { max-width: 92%; }}

/* ===========================================================================
   Formulaire de démo (dans le bandeau encre)
   ========================================================================== */
.demo-form { display: flex; flex-direction: column; gap: 12px; width: 100%; max-width: 540px; }
.demo-form .demo-row { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 560px) { .demo-form .demo-row { grid-template-columns: 1fr 1fr; }}
.demo-form input::placeholder, .demo-form textarea::placeholder { color: var(--blanc-60); }
.demo-form input:focus, .demo-form textarea:focus { border-color: var(--cobalt); }
.demo-form input:focus-visible, .demo-form textarea:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.demo-form textarea { resize: vertical; }
.demo-form .demo-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
/* La ligne de consentement était en display:flex. Le libellé est fait d'un nœud
   texte, d'un lien et d'un « ). » final : en flex, chacun de ces trois morceaux
   devient un item, donc une colonne — le lien partait à 390 px du texte qu'il
   termine. Grid a exactement le même défaut. Le libellé reste donc en flux
   inline normal, et la case sort du flux dans la gouttière de gauche. */
.demo-consent { display: block; position: relative; padding-left: 26px;
  font-size: 12px; line-height: 1.45; color: var(--blanc-70); }
.demo-consent a { color: var(--blanc-90); text-decoration: underline; }
/* La case restait la case native du système : blanche, sans bordure, sur un
   formulaire dont tous les autres champs sont bordés de blanc 20 %. */
.demo-consent input { position: absolute; left: 0; top: 1px; width: 16px; height: 16px;
  padding: 0; box-sizing: border-box;     /* sinon le padding des champs du formulaire l'étire */
  appearance: none; -webkit-appearance: none;
  border: 1px solid var(--blanc-40); border-radius: 3px; background: transparent;
  display: grid; place-content: center; cursor: pointer;
  transition: background var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease); }
.demo-consent input::before {
  content: ""; width: 9px; height: 9px; transform: scale(0);
  transition: transform var(--dur-fast) var(--ease);
  background: var(--ink-0);
  clip-path: polygon(14% 46%, 0 60%, 40% 100%, 100% 22%, 86% 8%, 38% 72%); }
.demo-consent input:checked { background: var(--accent-display); border-color: var(--accent-display); }
.demo-consent input:checked::before { transform: scale(1); }
.demo-consent input:hover { border-color: var(--blanc-60); }
.demo-form button { align-self: flex-start; }
.demo-status { font-size: 13px; line-height: 1.4; margin: 2px 0 0; min-height: 1em; color: var(--blanc-80); }

/* ===========================================================================
   Spotlight offre commerçant (bandeau cliquable sur l'accueil)
   ========================================================================== */
.spot { display: flex; flex-direction: column; gap: 32px; background: var(--encre); color: var(--blanc); border: 1px solid var(--encre); padding: 36px; text-decoration: none; overflow: hidden; }
@media (min-width: 860px) { .spot { flex-direction: row; align-items: center; gap: 48px; padding: 48px; }}
.spot-main { flex: 1; min-width: 0; }
.spot-t { margin: 14px 0 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.04em; font-size: clamp(26px, 3.4vw, 40px); line-height: 1.02; }
.spot-t .accent-i { color: var(--cobalt); font-style: italic; }
.spot-b { margin: 14px 0 0; max-width: 52ch; font-size: 15px; line-height: 1.55; color: var(--blanc-80); }
.spot-b strong { color: var(--blanc); }
.spot-meta { margin-top: 20px; display: flex; flex-wrap: wrap; gap: 8px 22px; }
.spot-meta span { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--blanc-70); display: inline-flex; align-items: center; gap: 8px; }
.spot-meta span::before { content: "—"; color: var(--cobalt); }
.spot-cta { margin-top: 28px; display: inline-flex; align-items: center; gap: 10px; background: var(--blanc); color: var(--encre); border-radius: var(--radius-ui); padding: 0 28px; height: 50px; font-family: var(--font-sans); font-weight: 500; font-size: 16px; }
.spot:hover .spot-cta { background: var(--cobalt); color: var(--blanc); }
.spot .arrow { display: inline-block; }
@media (prefers-reduced-motion: no-preference) { .spot .arrow { transition: transform 220ms var(--ease-spring); }}
.spot:hover .arrow, .spot:focus-visible .arrow { transform: translateX(4px); }

/* Bande « Pensé pour » : séparateurs propres au retour à la ligne */
@media (max-width: 600px) {
  .targets-inner { flex-direction: column; align-items: flex-start; gap: 14px; }
  .targets-lab { padding-right: 0; }
  .targets-list { gap: 4px 22px; }
  .targets-item { padding: 0; }
  .targets-item + .targets-item { border-left: none; }}

/* Mock tableau de bord du héros : compact sur smartphone */
@media (max-width: 480px) {
  .dash-bar { padding: 10px 12px; }
  .dash-kpi { padding: 14px 12px; }
  .dash-kpi .k-val { font-size: 24px; }
  .dash-row { padding: 10px 12px; gap: 10px; }
  .dash-row .r-name { font-size: 13px; }}

/* Spotlight commerçant : CTA pleine largeur (pas de débordement) sur mobile */
@media (max-width: 560px) {
  .spot { padding: 28px 22px; }
  .spot-cta { width: 100%; justify-content: center; height: auto; min-height: 50px; padding: 14px 20px; }}

/* Respiration verticale réduite sur petits téléphones */
@media (max-width: 520px) {
  .hero-inner { padding-top: 48px; padding-bottom: 56px; }
  .ps-col, .step { padding: 28px 24px; }
  .demo-banner { padding: 26px 22px; }}

/* Bande de garanties : apparition en cascade (délais par item) */
@media (prefers-reduced-motion: no-preference) {
  .trustband-item[data-reveal] { transition: opacity var(--dur-reveal) var(--ease-out), transform var(--dur-reveal) var(--ease-out); }
  .trustband-item[data-reveal]:nth-child(1) { transition-delay: 60ms; }
  .trustband-item[data-reveal]:nth-child(2) { transition-delay: 130ms; }
  .trustband-item[data-reveal]:nth-child(3) { transition-delay: 200ms; }
  .trustband-item[data-reveal]:nth-child(4) { transition-delay: 270ms; }
  .trustband-item[data-reveal]:nth-child(5) { transition-delay: 340ms; }}

/* Shimmer cobalt : un reflet passe une fois sur le mot accent du hero.
   Le mot est peint par ce dégradé détouré sur le texte, pas par `color` :
   c'est ici qu'il faut reprendre l'accent du thème sombre, sinon on écrase
   le reflet en posant un text-fill opaque. */
.hero-title .accent-i {
  background-image: linear-gradient(100deg, var(--accent-display) 38%, #C2D0FF 50%, var(--accent-display) 62%);
  background-size: 220% 100%; background-position: 120% 0;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .hero-title .accent-i { animation: heroShimmer 2.4s var(--ease-out) 900ms 1 forwards; }}
@media (prefers-reduced-motion: reduce) {
  .hero-title .accent-i { background: none; -webkit-text-fill-color: var(--accent-display); }}

/* Dashboard du hero : les lignes "streamées" une à une (effet Live) */
@media (prefers-reduced-motion: no-preference) {
  .dash-row { animation: dashRowIn 520ms var(--ease-out) both; }
  .dash-row:nth-child(1) { animation-delay: 520ms; }
  .dash-row:nth-child(2) { animation-delay: 660ms; }
  .dash-row:nth-child(3) { animation-delay: 800ms; }
  .dash-row:nth-child(4) { animation-delay: 940ms; }}

/* ===========================================================================
   "Wow" — hero spectaculaire (titre cinétique, aurora, 3D, magnétique)
   ========================================================================== */

/* Titre cinétique : chaque mot monte depuis derrière un masque */
.hero-kinetic .w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: 0.14em; margin-bottom: -0.14em; }
.hero-kinetic .wi { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .hero-kinetic .wi { animation: wordUp 0.72s var(--ease-out) both; }
  .hero-kinetic .w:nth-child(1) .wi { animation-delay: 0.12s; }
  .hero-kinetic .w:nth-child(2) .wi { animation-delay: 0.20s; }
  .hero-kinetic .w:nth-child(3) .wi { animation-delay: 0.28s; }
  .hero-kinetic .w:nth-child(4) .wi { animation-delay: 0.36s; }
  .hero-kinetic .w:nth-child(5) .wi { animation-delay: 0.44s; }
  .hero-kinetic .w:nth-child(6) .wi { animation-delay: 0.52s; }}

/* Halo "aurora" du hero : dérive lente et respiration */
@media (prefers-reduced-motion: no-preference) {
  .hero::before { animation: auroraDrift 16s ease-in-out infinite alternate; }}

/* Dashboard 3D : inclinaison au curseur (la transition est posée par landing.js) */
.hero-visual { perspective: 1100px; }
.dash { transform-style: preserve-3d; }

/* Le mot accent garde son shimmer EN PLUS de l'entrée cinétique (combiné) */
@media (prefers-reduced-motion: no-preference) {
  .hero-kinetic .wi.accent-i { animation: wordUp 0.72s var(--ease-out) 0.44s both, heroShimmer 2.2s var(--ease-out) 1.5s 1 forwards; }}

/* Sparkline trésorerie (dashboard) — tracé qui se dessine */
.dash-spark { padding: 14px 16px; border-bottom: 1px solid var(--hairline); }
.dash-spark-lab { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--encre-60); margin-bottom: 7px; }
.dash-spark svg { display: block; width: 100%; height: 40px; }
.dash-spark .line { fill: none; stroke: var(--cobalt); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.dash-spark .area { fill: rgba(24,70,220,0.08); stroke: none; }
@media (prefers-reduced-motion: no-preference) {
  .dash-spark .line { stroke-dasharray: 100; stroke-dashoffset: 100; animation: sparkDraw 1500ms var(--ease-out) 850ms forwards; }
  .dash-spark .area { opacity: 0; animation: sparkArea 900ms var(--ease-out) 1700ms forwards; }}

/* Icône de module : petit "pop" quand la carte est survolée */
.module-icon { transition: transform var(--dur-ui) var(--ease-spring); }
.module-card:hover .module-icon { transform: scale(1.08) rotate(-3deg); }

/* Quand GSAP pilote le dashboard (parallaxe scroll), on coupe le float CSS pour éviter le conflit de transform */
.gsap-ready .dash-float { animation: none !important; }
.gsap-ready .dash-row { animation: none !important; }  /* GSAP pilote l'assemblage au scroll (hero pin) */

/* Accent WebGL du hero (WebGL brut, sans bibliothèque) — canvas en fond, sous le contenu */
#hero3d { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; display: block; pointer-events: none; }
.hero3d-on .hero::before { opacity: 0.72; }   /* on atténue un peu l'aurora quand la 3D est active */

/* ===========================================================================
   Bento grid — section bénéfices (premium, dynamique, charte hairline/nette)
   ========================================================================== */
.bento { display: grid; grid-template-columns: 1fr; gap: 14px; }
@media (min-width: 760px) {
  .bento { grid-template-columns: repeat(6, 1fr); grid-auto-rows: minmax(150px, auto); }
  .bento-cell.is-lg   { grid-column: span 4; grid-row: span 2; }
  .bento-cell:not(.is-lg):not(.is-wide) { grid-column: span 2; }
  .bento-cell.is-wide { grid-column: span 6; }}
.bento-cell .benef-num { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.045em; font-size: 26px; line-height: 1; color: var(--accent-display); }
.bento-t { margin: 18px 0 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.04em; font-size: 22px; line-height: 1.05; }
.bento-b { margin: 12px 0 0; font-size: 15px; line-height: 1.55; color: var(--encre-80); max-width: 46ch; }
.bento-cell.is-lg { padding: 36px; justify-content: space-between; }
.bento-cell.is-lg .benef-num { font-size: 32px; }
.bento-cell.is-lg .bento-t { font-size: clamp(28px, 3.2vw, 40px); margin-top: 20px; }
.bento-cell.is-lg .bento-b { font-size: 17px; max-width: 42ch; }
.bento-viz { position: absolute; right: 20px; bottom: 16px; width: clamp(120px, 16vw, 180px); height: auto; color: var(--cobalt); opacity: 0.16; pointer-events: none; }
/* Cellule large sombre (contraste premium) */
.bento-cell.is-wide { flex-direction: column; gap: 18px; }
@media (min-width: 760px) { .bento-cell.is-wide { flex-direction: row; align-items: center; justify-content: space-between; }}
.bento-cell.is-dark .bento-b { color: var(--blanc-80); }
.bento-wide-main { max-width: 62ch; }
.bento-link { flex: none; display: inline-flex; align-items: center; gap: 10px; white-space: nowrap; font-family: var(--font-sans); font-weight: 500; font-size: 15px; color: var(--blanc); border: 1px solid var(--blanc-20); border-radius: var(--radius-ui); padding: 12px 20px; text-decoration: none; transition: background var(--dur-ui) var(--ease), color var(--dur-ui) var(--ease); }
.bento-link:hover { background: var(--blanc); color: var(--encre); }
@media (prefers-reduced-motion: no-preference) { .bento-link .arrow { transition: transform 220ms var(--ease-spring); }}
.bento-link:hover .arrow, .bento-link:focus-visible .arrow { transform: translateX(4px); }

/* Spotlight curseur aussi sur les cellules bento */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .bento-cell:hover::after { opacity: 1; }
  .bento-cell > * { position: relative; z-index: 1; }
  .bento-viz { z-index: 0; }}

/* Mini-nav de progression latérale (points) — desktop uniquement */
.section-nav { position: fixed; right: 22px; top: 50%; transform: translateY(-50%); z-index: 70; display: none; flex-direction: column; gap: 16px; }
@media (min-width: 1100px) { .section-nav { display: flex; }}
@media (prefers-reduced-motion: reduce) { .section-nav { display: none; }}
.section-dot { position: relative; width: 11px; height: 11px; border-radius: 999px; border: 1.5px solid rgba(255,255,255,0.45); background: transparent; transition: background var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease), transform var(--dur-ui) var(--ease-spring); }
.section-dot:hover { border-color: var(--accent-display); transform: scale(1.25); }
/* --cobalt ne donne que 2,81:1 sur le fond sombre — insuffisant pour un
   indicateur d'état (WCAG 1.4.11) — et le projet le reconnaît déjà ailleurs
   en lui préférant --accent-display dans le thème sombre. */
.section-dot.is-active { background: var(--accent-display); border-color: var(--accent-display); transform: scale(1.35); }
.section-dot:hover .section-dot-l, .section-dot:focus-visible .section-dot-l { opacity: 1; }

/* ===========================================================================
   Hero SOMBRE immersif — le glow WebGL + aurora y ressortent (Phase 4)
   ========================================================================== */
.hero { border-bottom-color: var(--encre); }
.hero .hero-eyebrow { border-color: var(--blanc-20); }
.hero .hero-eyebrow .kick { color: var(--blanc-70); }
.hero .hero-title { color: var(--blanc); }
.hero .hero-lead { color: var(--blanc-80); }
.hero .hero-trust span { color: var(--blanc-60); }
.hero .hero-trust span::before { color: var(--cobalt); }
.hero .btn-ghost { color: var(--blanc); border-color: var(--blanc-20); }
.hero .btn-ghost:hover { background: var(--blanc); color: var(--encre); }
.hero .dash { box-shadow: var(--shadow-lg); }
.hero::before { opacity: 1; }
.section-encre { background: var(--ink-1); }
.targets, .trustband { background: var(--ink-0); }
.hero { background: var(--grad-ink); }
/* Textes encore en --encre solide (sinon invisibles) */
.targets-item { color: var(--blanc); }
/* Le dashboard reste BLANC : on restaure des tokens texte sombres à l'intérieur */
.dash { background: var(--blanc); }
.dash, .dash * {
  --encre-85: rgba(10,10,10,0.85); --encre-80: rgba(10,10,10,0.80);
  --encre-70: rgba(10,10,10,0.70); --encre-60: rgba(10,10,10,0.60);
  --encre-50: rgba(10,10,10,0.50); --hairline: #E6E6E6;
}
/* Boutons blancs (spot-cta, btn-reverse) gardent leur texte encre solide → OK */

/* ===========================================================================
   Fusion des flux — 10 flux → 1 (animation scroll, section problème→solution)
   ========================================================================== */
.flowmerge .fm-stage { margin-top: 6px; }
#fm-stage { position: relative; }
.flowmerge .fm-stage svg { width: 100%; height: auto; display: block; overflow: visible; }

/* Les « tuyaux » : hairline cobalt discrète (tracée au scroll par anim-gsap.js) */
.fm-path { fill: none; stroke: var(--cobalt); stroke-width: 1.4; opacity: 0.30; }
/* Paquets de lumière qui filent en continu vers le hub */
.fm-flow { fill: none; stroke: var(--accent-texte); stroke-width: 2.6; stroke-linecap: round;
  stroke-dasharray: 5 155; opacity: 0.95; filter: drop-shadow(0 0 5px rgba(126,155,255,0.9)); }
.fm-in { fill: var(--blanc-70); }
.fm-label { fill: var(--blanc-70); font-family: var(--font-mono); font-size: 14px; letter-spacing: 0.05em; text-transform: uppercase; }

/* Hub d'unification */
.fm-halo { fill: url(#fmCore); opacity: 0.85; }
.fm-wave { fill: none; stroke: #6e8cff; stroke-width: 1.5; opacity: 0; transform-box: fill-box; transform-origin: center; }
.fm-out-ring { fill: none; stroke: #6e8cff; stroke-width: 2; opacity: 0.7; }
.fm-out { fill: var(--blanc); filter: drop-shadow(0 0 10px rgba(140,165,255,0.9)); }
.fm-out-label { fill: var(--blanc); font-family: var(--font-display); font-weight: 800; font-size: 22px; letter-spacing: -0.03em; }
.fm-caption { max-width: 62ch; margin: 28px 0 0; font-size: clamp(16px, 2vw, 19px); line-height: 1.55; color: var(--blanc-80); }

@media (prefers-reduced-motion: no-preference) {
  .fm-stage.is-live .fm-flow { animation: fmFlow 2.1s linear infinite; }
  .fm-stage.is-live .fm-wave { animation: fmWave 3.4s ease-out infinite; }
  .fm-stage.is-live .fm-halo { animation: fmBreathe 4s ease-in-out infinite; }
  .fm-stage.is-live .fm-out  { animation: fmBreathe 3s ease-in-out infinite; }}

@media (max-width: 640px) { .fm-label { font-size: 13px; } .fm-out-label { font-size: 26px; }}

#modules { position: relative; }
#modules > .page { position: relative; z-index: 1; }
.mod-count .cell { background: var(--ink-2); }
.dash { color: var(--encre); }
body.oltanis .olto-num          { border-color: var(--accent-texte); }
/* La carte « Vous tenez une boutique ? » était en background:--encre AVEC une
   bordure de la même valeur. Sur fond blanc la carte se détachait d'elle-même ;
   sur #08080c elle vaut 1,03:1 et sa bordure est invisible — la carte n'a plus
   de bord. On lui rend le filet du site, comme à toutes les autres surfaces. */
body.oltanis .spot { border-color: var(--hairline); }
body.oltanis .spot:hover { border-color: rgba(157,180,255,.55); }
/* .module-cat, .assure-k et .pcol-reco sont déjà repris plus bas (point 2 du
   bloc « Lisibilité »), avec le même token — inutile de les redéclarer ici. */

/* 5. Décor : marge d'exclusion sur la colonne de texte. Les arcs restent
      visibles côté visuel, mais ne traversent plus titres, chapôs ni boutons. */
body.oltanis .hero > [data-oltbc],
body.oltanis .section-cobalt > [data-oltbc] {
  -webkit-mask-image: linear-gradient(90deg, transparent 0 42%, #000 68%);
          mask-image: linear-gradient(90deg, transparent 0 42%, #000 68%);
}
@media (max-width: 999px) {
  body.oltanis .hero > [data-oltbc],
  body.oltanis .section-cobalt > [data-oltbc] {
    -webkit-mask-image: linear-gradient(180deg, transparent 0 58%, #000 86%);
            mask-image: linear-gradient(180deg, transparent 0 58%, #000 86%);
  }}
/* Le graphe « réseau » vit dans la moitié droite du viewBox : on le borne
   pour qu'il cesse de recouvrir le texte des étapes (#demarrage) et des listes. */
body.oltanis #probleme > [data-oltbc],
body.oltanis #demarrage > [data-oltbc],
body.oltanis .footer > [data-oltbc] {
  -webkit-mask-image: linear-gradient(90deg, transparent 0 48%, #000 74%);
          mask-image: linear-gradient(90deg, transparent 0 48%, #000 74%);
}

/* 6. Boutons fantômes posés sur du décor : une surface minimale suffit à ce
      qu'aucun trait ne traverse le libellé. */
body.oltanis .hero .btn-ghost { background: rgba(8,8,12,.55); }

/* 8. Héros : les deux colonnes étaient centrées alors qu'elles sont
      déséquilibrées de ~236 px — d'où le vide sous la carte tableau de bord. */
@media (min-width: 1000px) { body.oltanis .hero-grid { align-items: start; }}

/* ==========================================================================
   LONGUEUR — cartes modules en format horizontal compact sur petit écran.
   En une colonne, 46 cartes verticales représentaient 9 349 px : la section
   Modules pesait à elle seule un tiers de la page au doigt. Le contenu est
   identique (aucune carte retirée, aucun texte masqué), seule la disposition
   change : icône à gauche, texte à droite.
   ========================================================================== */
@media (max-width: 559px) {
  .module-card { flex-direction: row; align-items: flex-start; justify-content: flex-start;
                 gap: 14px; min-height: 0; padding: 18px 20px; }
  .module-top { flex-direction: column; align-items: flex-start; justify-content: flex-start;
                gap: 6px; flex: none; width: 56px; }
  .module-icon { width: 40px; height: 40px; }
  .module-name { margin: 0; font-size: 20px; line-height: 1.15; }
  .module-desc { margin: 6px 0 0; font-size: 13.5px; line-height: 1.45; }}

/* Fin de grille : le fond du conteneur servait de séparateur, donc les cellules
   vides de la dernière rangée (46 modules ÷ 4 colonnes = 2 restantes) se
   voyaient comme un bloc clair. Ce sont les cartes qui portent les filets. */
body.oltanis .module-card { border-right: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }

/* ==========================================================================
   CARTE MENTALE DES MODULES — 9 pôles repliables
   Sans JavaScript, toutes les branches sont ouvertes : les 46 modules restent
   lisibles par les crawlers et les moteurs de réponse. landing.js ajoute
   .js-mm sur <html>, replie les branches et gère l'ouverture au clic.
   ========================================================================== */
.mm { position: relative; }
.mm-hub { display: none; }
@media (min-width: 1100px) {
  .mm-hub { display: flex; flex-direction: column; align-items: center; justify-content: center;
            position: absolute; left: 0; top: 0; width: 132px; height: 132px;
            border: 1px solid rgba(60,99,242,.55); background: var(--ink-1); }
  .mm-hub-n { font-family: var(--font-display); font-weight: 800; font-size: 40px; letter-spacing: -.04em; color: var(--blanc); line-height: 1; }
  .mm-groups { margin-left: 172px; }
  /* Tronc : la ligne verticale d'où partent les branches */
  .mm-groups::before { content: ""; position: absolute; left: 66px; top: 132px; bottom: 22px;
                       width: 1px; background: var(--hairline); }}
.mm-groups { display: flex; flex-direction: column; gap: 0; border-top: 1px solid var(--hairline); }
.mm-group { position: relative; border-bottom: 1px solid var(--hairline); }
/* Rameau horizontal qui relie le tronc au nœud du pôle */
@media (min-width: 1100px) {
  .mm-group::before { content: ""; position: absolute; left: -106px; top: 33px; width: 106px; height: 1px;
                      background: var(--hairline); }}

/* ==========================================================================
   L'ARBRE VIVANT — ce qui remplace la galaxie 3D
   ==========================================================================
   Le fond de section précédent était un champ de particules WebGL (three.js,
   736 Ko) posé DERRIÈRE le titre, le chapô, les compteurs et les cartes. Il
   rendait le texte illisible ; deux masques successifs l'ont donc rétréci puis
   passé à 50 % d'opacité, jusqu'à ce qu'il ne reste plus qu'une ellipse coupée
   par le bas du canevas. On téléchargeait 736 Ko et on faisait tourner une
   boucle WebGL pour un effet devenu invisible.

   Le remplaçant tient dans la gouttière de 172 px à gauche de la carte mentale,
   où rien n'est jamais écrit : il ne peut pas concurrencer le texte. Et il dit
   la même chose que la page — un noyau, un tronc, 46 modules qui en partent.
   Coût : quelques centaines d'octets de CSS. Le halo et l'impulsion sont en
   opacity/transform, donc sur le compositeur ; la sève anime background-position,
   qui repeint — mais sur une colonne d'UN pixel de large, soit une surface
   négligeable. Dit autrement plutôt que promis à tort : ce n'est pas gratuit,
   c'est simplement sans commune mesure avec la boucle WebGL d'avant.
   ========================================================================== */
@media (min-width: 1100px) {
  /* Le moyeu respire : halo cobalt en pseudo-élément, jamais en box-shadow
     animée (c'est un recalcul de flou à chaque image). */
  /* z-index : le moyeu passe DEVANT les rameaux. Un rameau tombe dans sa boîte
     dès que sa hauteur relative est sous 132 px — c'est le cas du pôle 1, et du
     pôle 2 dès que le pôle 1 est refermé, donc au premier clic du visiteur : le
     trait cobalt traversait alors la boîte et se lisait comme un soulignement de
     « 9 PÔLES ». Le moyeu a déjà un fond opaque : il suffit qu'il peigne au
     dessus. Cela vaut pour tous les pôles et pour tous les états d'ouverture —
     à préférer à un cas particulier par pôle, qui ne peut pas les décrire tous. */
  .mm-hub { isolation: isolate; z-index: 1; }   /* position:absolute déjà posé plus haut */
  .mm-hub::before {
    content: ""; position: absolute; inset: -26px; z-index: -1; pointer-events: none;
    background: radial-gradient(circle at 50% 50%, rgba(60,99,242,.42), rgba(24,70,220,0) 68%);
    opacity: .55;
  }

  /* La sève : un segment clair qui descend le tronc, du moyeu vers le bas.
     Le tronc lui-même (::before) reste le filet gris : c'est le rail. */
  .mm-groups::after {
    content: ""; position: absolute; left: 66px; top: 132px; bottom: 22px; width: 1px;
    pointer-events: none;
    background: linear-gradient(180deg,
      rgba(91,124,255,0) 0%, rgba(91,124,255,.85) 42%, rgba(157,180,255,1) 50%,
      rgba(91,124,255,.85) 58%, rgba(91,124,255,0) 100%);
    background-size: 100% 90px;
    background-repeat: no-repeat;
    background-position: 0 -90px;
  }

  /* Le rameau du pôle ouvert s'allume : le chemin du noyau jusqu'au module
     affiché devient lisible d'un coup d'œil. */
  .mm-group.is-open::before { background: var(--accent-display); }
  .mm-group.is-open .mm-idx { color: var(--accent-display); }}

@media (min-width: 1100px) and (prefers-reduced-motion: no-preference) {
  .mm-groups::after { animation: mmSeve 5.2s cubic-bezier(.55,0,.45,1) infinite; }
  .mm-hub::before { animation: mmMoyeu 5.2s ease-in-out infinite; }

  /* À l'ouverture d'un pôle, une impulsion parcourt son rameau vers le nœud. */
  .mm-group.is-open::after {
    content: ""; position: absolute; left: -106px; top: 33px; width: 40px; height: 1px;
    pointer-events: none;
    background: linear-gradient(90deg, rgba(157,180,255,0), rgba(157,180,255,1));
    opacity: 0;                 /* état de repos : invisible */
    animation: mmRameau 620ms cubic-bezier(.22,1,.36,1) 1 both;
  }
  .mm-group::before { transition: background var(--dur-ui) var(--ease); }
  .mm-idx { transition: color var(--dur-ui) var(--ease); }}

.mm-h { margin: 0; }
.mm-node { display: flex; align-items: center; gap: 18px; width: 100%; padding: 18px 20px 18px 0;
           background: none; border: 0; cursor: pointer; text-align: left; font-family: inherit;
           color: var(--blanc); }
@media (prefers-reduced-motion: no-preference) {
  .mm-node { transition: background var(--dur-ui) var(--ease), padding-left var(--dur-ui) var(--ease); }}
@media (hover: hover) and (pointer: fine) {
  .mm-node:hover { background: var(--ink-2); padding-left: 10px; }}
.mm-idx { font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em; color: var(--accent-texte); flex: none; }
.mm-name { font-family: var(--font-display); font-weight: 800; letter-spacing: -.035em;
           font-size: clamp(22px, 3vw, 30px); line-height: 1.1; flex: 1 1 auto; }
/* Chevron : deux traits qui forment un + fermé et un − ouvert */
.mm-chev { position: relative; flex: none; width: 18px; height: 18px; }
.mm-chev::before, .mm-chev::after { content: ""; position: absolute; left: 50%; top: 50%; background: var(--accent-texte); }
.mm-chev::before { width: 14px; height: 1px; transform: translate(-50%, -50%); }
.mm-chev::after  { width: 1px; height: 14px; transform: translate(-50%, -50%); }
@media (prefers-reduced-motion: no-preference) { .mm-chev::after { transition: transform 350ms var(--ease); }}
.mm-node[aria-expanded="true"] .mm-chev::after { transform: translate(-50%, -50%) scaleY(0); }

.mm-branch { padding: 0 0 22px; }
.mm-cards { display: grid; grid-template-columns: 1fr; gap: 0;
            border: 1px solid var(--hairline); border-bottom: 0; }
@media (min-width: 560px)  { .mm-cards { grid-template-columns: repeat(2, 1fr); }}
@media (min-width: 980px)  { .mm-cards { grid-template-columns: repeat(3, 1fr); }}
@media (min-width: 1280px) { .mm-cards { grid-template-columns: repeat(4, 1fr); }}
.mm-cards .module-card { border-right: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }

/* --- Repli : uniquement quand le JS a pris la main ------------------------ */
.js-mm .mm-branch { display: none; }
.js-mm .mm-branch.is-open { display: block; }
@media (prefers-reduced-motion: no-preference) {
  .js-mm .mm-branch.is-open .mm-cards { animation: mmOpen 420ms var(--ease) both; }}

/* Dans la grille d'une branche, les titres doivent s'aligner d'une carte à
   l'autre : `space-between` les décalait selon la longueur du texte. */
.mm-cards .module-card { justify-content: flex-start; gap: 16px; }
.mm-cards .module-name { margin-top: 0; }

@media (max-width: 900px) {
  /* La case à consentement faisait 16 x 16 px : on l'agrandit et on étend la
     zone cliquable à son libellé. On reste en flux inline (voir la règle de
     base) : passer en flex disloquait le libellé, dont le lien et le « ). »
     final partaient en colonnes séparées. */
  .demo-consent { min-height: 44px; padding: 8px 0 8px 34px; }
  .demo-consent input[type="checkbox"] { width: 22px; height: 22px; top: 9px; }
  .demo-consent input[type="checkbox"]::before { width: 12px; height: 12px; }}

/* Survol « collé » au doigt : sur écran tactile, un tap laisse l'état hover
   actif jusqu'au tap suivant. On neutralise les survols décoratifs là où le
   pointeur n'est pas fin. */
@media (hover: none) {
  .targets-item:hover { color: inherit; transform: none; }}
/* Le paragraphe hors de la rangée de boutons : il courait sur 1 312 px, soit
   134 caractères par ligne. Il sort du flex pour reprendre sa propre mesure. */
p.olto-cta-note { flex-basis: 100%; max-width: 560px; }
body.oltanis .module-wip-b { color: var(--blanc-70); border-color: var(--blanc-20); }