/* ============================================================================
   shell.css — la coquille de « SearchGuard, Episode II ».
   Tout ce qui est persistant d'un acte à l'autre :
     tokens de charte, typographie, fond, grille générique d'un acte,
     en-tête fixe, sommaire, règle graduée verticale, timeline mobile,
     bouton « maintenir pour avancer », couche de transition, fiches
     « pour tout comprendre », pied de page, carrés de remplacement des SVG.
   La mise en scène propre à chaque acte est dans acts.css.
   Aucun import de la CSS des infographies RESONEO classiques : pas de colonnes.
   ========================================================================= */

/* ---------------------------------------------------------------- charte */
:root{
  --deep:#05070c;          /* fond profond */
  --reso:#223c52;          /* bleu RESONEO */
  --imp:#8a8f98;           /* gris impérial */
  --alert:#e03127;         /* rouge alerte */
  --holo:#5fd4ff;          /* cyan hologramme */
  --crawl:#ffc93c;         /* jaune générique, acte 0 uniquement */

  --ink:#dfe6ee;
  --ink-dim:#9aa3ad;

  /* Tokens d'interface, basculés par .sg-light (acte VI). */
  --ui-fg:#e6edf4;
  --ui-dim:#8a8f98;
  --ui-bg:rgba(5,7,12,.66);
  --ui-bg-solid:#070a11;
  --ui-line:rgba(138,143,152,.30);
  --ui-accent:var(--holo);

  /* Variables lues par les fichiers SVG de ui/ (chacun a sa valeur de repli).
     --sg-vert est ramene au cyan hologramme pour rester dans la charte. */
  --sg-fond:#05070c;
  --sg-bleu:#223c52;
  --sg-gris:#8a8f98;
  --sg-rouge:#e03127;
  --sg-cyan:#5fd4ff;
  --sg-jaune:#ffc93c;
  --sg-vert:#5fd4ff;
  --sg-ambre:#e0a33c;

  --ttl:'Archivo','Arial Narrow',Helvetica,sans-serif;
  --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;

  --head-h:56px;
  --gut:clamp(16px,4vw,48px);
  --maxw:1180px;
  --ease:cubic-bezier(.22,.61,.36,1);
}
body.sg-light{
  --ui-fg:#0a1017;
  --ui-dim:#48525d;
  --ui-bg:rgba(236,241,245,.78);
  --ui-bg-solid:#eef2f5;
  --ui-line:rgba(34,60,82,.26);
  --ui-accent:var(--reso);
}

*{margin:0;padding:0;box-sizing:border-box}
html{background:var(--deep);scroll-behavior:smooth}
body{
  background:var(--deep);
  color:var(--ink);
  font-family:var(--ttl);
  font-variation-settings:'wdth' 100;
  font-size:clamp(15px,1.02vw,17px);
  line-height:1.62;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%;display:block}
a{color:var(--holo);text-decoration:none;text-underline-offset:3px}
a:hover{text-decoration:underline}
code,.mono{font-family:var(--mono);font-size:.86em;letter-spacing:-.01em}
code{color:var(--holo);word-break:break-word}
em{font-style:normal;color:#fff;border-bottom:1px solid rgba(95,212,255,.5)}
:focus-visible{outline:2px solid var(--holo);outline-offset:3px;border-radius:2px}

.sg-skip{position:fixed;left:12px;top:-120px;z-index:4000;background:var(--ui-bg-solid);color:var(--ui-fg);
  padding:10px 16px;border:1px solid var(--ui-line);transition:top .2s}
.sg-skip:focus{top:12px}

h2,h3{line-height:1.06;font-weight:800;letter-spacing:-.02em;font-variation-settings:'wdth' 112}

/* ---------------------------------------------------------------- boutons */
.sg-btn{
  font:inherit;font-weight:600;cursor:pointer;
  display:inline-flex;align-items:center;gap:.5em;
  background:transparent;color:var(--ui-fg);
  border:1px solid var(--ui-line);
  padding:.52em 1.05em;border-radius:2px;
  letter-spacing:.04em;text-transform:uppercase;font-size:.78rem;
  transition:border-color .2s,background .2s,color .2s;
}
.sg-btn:hover{border-color:var(--ui-accent);color:var(--ui-accent);text-decoration:none}
.sg-btn--ghost{border-style:dashed;color:var(--ui-dim)}
.sg-btn--solid{background:var(--reso);border-color:var(--reso);color:#fff}
.sg-btn--solid:hover{background:#2d5070;border-color:#2d5070;color:#fff}
.sg-btn--icon{padding:.42em;width:36px;height:36px;justify-content:center}
.sg-btn[disabled]{opacity:.45;cursor:default}

.sg-icon{width:1.25em;height:1.25em;flex:0 0 auto;display:inline-block;color:inherit}
/* Les reperes de zone des cadres (ui/*-frame.svg) ne servent qu'au calage. */
.sg-zone-guide{display:none}
/* Carrés de remplacement tant que ui/sprite.svg et les SVG autonomes n'existent pas. */
.sg-icon--ph{width:1.1em;height:1.1em;border:1px solid currentColor;opacity:.55;border-radius:1px}
.sg-uimg--ph{display:block;border:1px dashed var(--ui-line);opacity:.5;border-radius:2px}

/* interrupteur réutilisable */
.sg-switch{display:inline-flex;align-items:center;gap:.6em;cursor:pointer;font-size:.86rem}
.sg-switch input{position:absolute;opacity:0;width:1px;height:1px}
.sg-switch__box{width:40px;height:20px;border:1px solid var(--ui-line);border-radius:12px;position:relative;
  background:rgba(138,143,152,.14);transition:background .2s,border-color .2s;flex:0 0 auto}
.sg-switch__box::after{content:'';position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;
  background:var(--ui-dim);transition:transform .2s var(--ease),background .2s}
.sg-switch input:checked + .sg-switch__box{border-color:var(--alert);background:rgba(224,49,39,.22)}
.sg-switch input:checked + .sg-switch__box::after{transform:translateX(20px);background:var(--alert)}
.sg-switch input:focus-visible + .sg-switch__box{outline:2px solid var(--holo);outline-offset:3px}

/* ---------------------------------------------------------------- en-tête */
.sg-head{
  position:fixed;inset:0 0 auto 0;height:var(--head-h);z-index:900;
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:0 var(--gut);
  background:linear-gradient(to bottom,var(--ui-bg),transparent);
  backdrop-filter:blur(6px);
  color:var(--ui-fg);
  transition:color .4s,background .4s;
}
.sg-head__brand{display:flex;align-items:center;gap:10px;color:inherit}
.sg-head__brand:hover{text-decoration:none}
.sg-head__emblem{width:26px;height:26px}
.sg-head__wordmark{display:flex;flex-direction:column;line-height:1.05}
.sg-head__wordmark strong{font-size:.92rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;font-variation-settings:'wdth' 118}
.sg-head__wordmark span{font-family:var(--mono);font-size:.62rem;color:var(--ui-dim);letter-spacing:.2em;text-transform:uppercase}
.sg-head__tools{display:flex;align-items:center;gap:10px}

.sg-clearance{display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:.64rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ui-dim)}
.sg-clearance__slot{display:inline-flex;width:18px;height:18px}
.sg-clearance__img{width:18px;height:18px}
.sg-clearance__val{color:var(--ui-accent);font-weight:700;font-size:.8rem}
.sg-clearance__max{opacity:.6}

.sg-audio__on{display:none}
#sgAudio{position:relative}
#sgAudio[aria-pressed="true"] .sg-audio__on{display:inline-flex}
#sgAudio[aria-pressed="true"] .sg-audio__off{display:none}
#sgAudio[aria-pressed="true"]{color:var(--ui-accent);border-color:var(--ui-accent)}

/* Le son est allumé par défaut, mais le navigateur ne laisse rien démarrer
   avant un geste du visiteur : un clic, une touche, une tape. Tant que la
   lecture n'a pas pu commencer, le bouton porte un liseré cyan qui respire.
   C'est le liseré qui bouge, pas le bouton : l'en-tête ne sautille pas. */
#sgAudio.is-waiting{border-color:var(--sg-cyan);color:var(--sg-cyan)}
#sgAudio.is-waiting::after{
  content:'';position:absolute;inset:-3px;border:1px solid var(--sg-cyan);border-radius:3px;
  pointer-events:none;animation:sg-halo 2.6s ease-in-out infinite;
}
@keyframes sg-halo{
  0%,100%{opacity:.3;box-shadow:0 0 0 0 rgba(95,212,255,0)}
  50%    {opacity:1; box-shadow:0 0 12px 1px rgba(95,212,255,.55)}
}
/* La consigne sous le bouton (« Son au premier clic »), tant que le navigateur
   n'a pas laissé le son démarrer : sans elle, le visiteur qui ne fait que
   défiler (le défilement ne compte pas comme un geste) n'entendait rien avant
   son premier clic, souvent à l'acte I, trente secondes plus loin. Elle dit
   que le son est allumé et n'attend qu'un clic — pas qu'il faut l'activer.
   Posée en absolu sous le bouton : l'en-tête ne bouge pas. Elle fait partie
   du bouton : cliquer dessus lance le son. */
.sg-audio__hint{display:none;position:absolute;top:calc(100% + 9px);right:-3px;white-space:nowrap;
  font-family:var(--mono);font-size:.58rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--sg-cyan);text-shadow:0 0 8px rgba(5,7,12,.9)}
#sgAudio.is-waiting .sg-audio__hint{display:block}
/* le focus clavier doit rester distinct du liseré : trait clair, plus au large */
#sgAudio:focus-visible{outline:2px solid var(--ui-fg);outline-offset:5px}

.sg-lang{display:flex;border:1px solid var(--ui-line);border-radius:2px;overflow:hidden}
.sg-lang__btn{font-family:var(--mono);font-size:.66rem;letter-spacing:.1em;padding:.42em .6em;color:var(--ui-dim)}
.sg-lang__btn:hover{text-decoration:none;color:var(--ui-fg)}
.sg-lang__btn.is-on{background:var(--ui-accent);color:var(--deep)}
body.sg-light .sg-lang__btn.is-on{color:#fff}

/* ---------------------------------------------------------------- sommaire */
.sg-menu{
  position:fixed;inset:0;z-index:1200;background:rgba(5,7,12,.95);
  display:flex;flex-direction:column;justify-content:center;
  padding:calc(var(--head-h) + 20px) var(--gut) 32px;
  color:#e6edf4;
}
.sg-menu[hidden]{display:none}
.sg-menu__close{position:absolute;top:10px;right:var(--gut);color:#e6edf4;border-color:rgba(138,143,152,.3)}
.sg-menu__kicker{font-family:var(--mono);font-size:.68rem;letter-spacing:.3em;text-transform:uppercase;color:var(--imp);margin-bottom:18px}
.sg-menu__list{list-style:none;max-width:var(--maxw);width:100%;margin:0 auto;display:flex;flex-direction:column;gap:2px}
.sg-menu__list a{display:grid;grid-template-columns:3.2rem minmax(0,15rem) 1fr;gap:14px;align-items:baseline;
  padding:12px 10px;border-top:1px solid rgba(138,143,152,.18);color:#e6edf4}
.sg-menu__list a:hover{background:rgba(95,212,255,.07);text-decoration:none}
.sg-menu__list a.is-here{background:rgba(95,212,255,.1)}
.sg-menu__num{font-family:var(--mono);color:var(--holo);font-size:.9rem}
.sg-menu__ttl{font-weight:800;font-size:clamp(1.1rem,2.4vw,1.6rem);letter-spacing:-.02em;font-variation-settings:'wdth' 112}
.sg-menu__line{color:var(--imp);font-size:.85rem}
.sg-menu__foot{max-width:var(--maxw);width:100%;margin:26px auto 0;font-family:var(--mono);font-size:.74rem}

/* ---------------------------------------------------- règle graduée (droite) */
.sg-ruler{
  position:fixed;z-index:880;right:0;top:50%;transform:translateY(-50%);
  height:min(62vh,460px);width:116px;
  display:flex;align-items:center;justify-content:flex-end;
  padding-right:10px;

  /* LA GÉOMÉTRIE DU DESSIN, ET POURQUOI ELLE EST ÉCRITE ICI.
     Les graduations ne sont pas du HTML : elles sont dessinées dans
     `ui/ruler.svg`, de y=30 à y=390 dans un dessin haut de 420 — donc avec de
     l'air en haut et en bas. Les libellés, eux, sont du HTML posé dans un
     cadre de même hauteur. Les étaler de 0 à 100 % les met sur une autre
     échelle que les traits : mesuré à 33 px d'écart aux deux bouts, nul au
     milieu — le libellé du premier acte flottait au-dessus de son trait, celui
     du dernier en dessous. Les trois valeurs ci-dessous remettent le HTML sur
     l'échelle du dessin. Si `ui/ruler.svg` change de cadrage, c'est ici qu'on
     le répercute, et seulement ici (shell.js place le repère mobile avec les
     deux mêmes nombres, 30 et 360). */
  --ruler-y0:30;        /* première graduation, dans les unités du dessin */
  --ruler-span:360;     /* de la première à la dernière */
  --ruler-vb:420;       /* hauteur totale du dessin */
}
.sg-ruler__art{position:absolute;right:6px;top:0;height:100%;width:auto;color:var(--ui-dim)}
.sg-ruler__art #indicator{color:var(--ui-accent);transition:transform .14s linear}
.sg-ruler__art .sg-tick{opacity:.55;transition:opacity .25s,color .25s}
.sg-ruler__art .sg-tick.is-here{opacity:1;color:var(--ui-accent)}
.sg-ruler__art .sg-tick.is-done{opacity:.8}
/* numeros HTML seulement quand ui/ruler.svg n'est pas la */
body:not([data-ui-missing]) .sg-ruler__n{display:none}
.sg-ruler__ticks{list-style:none;position:relative;width:100%;height:100%}
.sg-ruler__tick{position:absolute;right:0;height:1px;width:100%;
  top:calc((var(--ruler-y0) + var(--i) / (var(--n) - 1) * var(--ruler-span)) / var(--ruler-vb) * 100%)}
.sg-ruler__tick a{
  position:absolute;right:0;top:-12px;height:24px;
  display:flex;align-items:center;justify-content:flex-end;gap:10px;
  padding-right:10px;color:var(--ui-dim);white-space:nowrap;
}
.sg-ruler__tick a::after{content:'';width:14px;height:1px;background:currentColor;flex:0 0 auto;transition:width .25s var(--ease)}
.sg-ruler__n{font-family:var(--mono);font-size:.68rem;letter-spacing:.08em}
.sg-ruler__lbl{
  font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;
  max-width:0;overflow:hidden;opacity:0;transition:max-width .3s var(--ease),opacity .22s;
}
.sg-ruler__tick a:hover,.sg-ruler__tick a:focus-visible{color:var(--ui-accent);text-decoration:none}
.sg-ruler__tick.is-here a{color:var(--ui-fg)}
.sg-ruler__tick.is-here a::after{width:26px;background:var(--ui-accent)}
/* Dépliage au survol ou au focus clavier. La marge droite n'est là que
   dépliée : elle écarte le texte du repère mobile, qui occupe la bande 48-66 px
   depuis le bord. Sans elle, le repère — désormais pilé sur la graduation de
   l'acte en cours — tombe systématiquement sur les dernières lettres du
   libellé actif, le seul qu'on veut justement pouvoir lire. Repliée, la marge
   disparaît : rien ne bouge dans la règle au repos. */
.sg-ruler:hover .sg-ruler__lbl,
.sg-ruler:focus-within .sg-ruler__lbl{max-width:9rem;opacity:1;margin-right:14px}
.sg-ruler:hover,.sg-ruler:focus-within{background:linear-gradient(to left,var(--ui-bg),transparent)}

/* ---------------------------------------------------- timeline mobile (bas) */
.sg-timeline{display:none}

/* ------------------------------------------ maintenir pour avancer (haut) */
/* En haut, centré sous l'en-tête, et sans libellé écrit. En bas il passait
   par-dessus les dernières lignes des actes ; à droite il serait entré dans la
   règle graduée. Le libellé disparaît parce que l'anneau qui se remplit sous le
   doigt explique le geste mieux qu'une consigne : l'appui long à jauge est un
   vocabulaire connu. Le texte reste le nom accessible du bouton et son
   info-bulle au survol (voir shell.js) : il n'est perdu pour personne. */
.sg-hold{
  position:fixed;z-index:890;left:50%;top:calc(var(--head-h) + 8px);transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;
  transition:opacity .3s;
}
.sg-hold.is-off{opacity:0;pointer-events:none}
.sg-hold__btn{
  position:relative;width:46px;height:46px;border-radius:50%;cursor:pointer;
  background:var(--ui-bg);border:1px solid var(--ui-line);color:var(--ui-fg);
  display:grid;place-items:center;backdrop-filter:blur(4px);
}
.sg-hold__btn:hover{border-color:var(--ui-accent)}
.sg-hold__art{position:absolute;inset:2px;width:calc(100% - 4px);height:calc(100% - 4px);color:var(--ui-fg)}
.sg-hold__art #progress{color:var(--ui-accent);stroke:var(--ui-accent);transition:stroke-dashoffset .08s linear}
/* acte VI, thème clair : le bleu RESONEO est moins lumineux que le cyan, on
   épaissit l'anneau pour qu'il se détache autant de sa piste */
body.sg-light .sg-hold__art #progress{stroke-width:3.4}
.sg-uimg--ph.sg-hold__art{inset:8px;width:auto;height:auto}
/* Masqué à l'œil, gardé pour les lecteurs d'écran : shell.js le désigne comme
   description du bouton. Surtout pas display:none, qui le retirerait aussi
   des technologies d'assistance. */
.sg-hold__lbl{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  white-space:nowrap;border:0;clip-path:inset(50%);
}

/* ---------------------------------------------------------------- transitions */
/* Couche autonome, au-dessus des actes, jamais interactive : elle ne peut pas
   bloquer le défilement. Pilotée par assets/js/transitions.js. */
.sg-trans{position:fixed;inset:0;z-index:950;pointer-events:none;opacity:0;visibility:hidden}
.sg-trans.is-live{opacity:1;visibility:visible}
.sg-trans__layer{position:absolute;inset:0;background-size:cover;background-position:center;opacity:0;
  will-change:transform,opacity}
.sg-trans__vig{position:absolute;inset:0;opacity:0;
  background:radial-gradient(ellipse at center,transparent 38%,rgba(5,7,12,.92) 88%)}
.sg-trans__canvas{position:absolute;inset:0;width:100%;height:100%;opacity:0}
.sg-trans__flash{position:absolute;inset:0;background:#fff;opacity:0}
.sg-trans__fade{position:absolute;inset:0;background:var(--deep);opacity:0}

/* Le tunnel « vitesse lumière » des passages, piloté au défilement par
   transitions.js, qui crée cette toile. Au-dessus des actes, mais SOUS la règle
   graduée (880), le bouton d'avance (890) et l'en-tête (900) : ils restent
   lisibles pendant la traversée et disent où l'on en est. Retirée du rendu
   hors des passages qui la demandent. */
.sg-warp{position:fixed;inset:0;width:100%;height:100%;z-index:860;pointer-events:none;display:none}
.sg-warp.is-on{display:block}

/* --------------------------------------------- grille générique d'un acte */
/* --sg-gate : la distance de défilement ajoutée entre deux actes, posée sur
   <html> par transitions.js (constante GATE_VH). Sans JavaScript elle vaut
   0px et les hauteurs sont celles d'avant. L'acte qui précède un tunnel
   reçoit sa propre valeur, plus longue, directement sur lui.
   Le dernier acte n'en a pas besoin : plus rien ne le suit. `:last-of-type`
   et non `:last-child` : actes/acte-6.php se termine par un <script>, qui
   est le vrai dernier enfant de <main> — la règle ne s'appliquait pas, et
   l'acte VI traînait la zone de passage comme un écran vide en fin de page. */
.act{position:relative;min-height:100vh;isolation:isolate}
.sg-js .act{height:calc(var(--h,260vh) + var(--sg-gate,0px))}
.sg-js .act--stub{height:calc(var(--h,170vh) + var(--sg-gate,0px))}
.sg-js #sgMain > section.act:last-of-type{--sg-gate:0px}

/* Fond : collé en haut, hauteur d'écran, et retiré du flux par la marge
   négative pour que le contenu collant se superpose exactement. */
.act__bg{position:sticky;top:0;height:100vh;margin-bottom:-100vh;overflow:hidden;z-index:0}
.plate{position:absolute;inset:-6% -4%;background-size:cover;background-position:center;will-change:transform}
.plate--far{
  transform:translate3d(0,calc(var(--p,0) * -4vh),0) scale(calc(1.04 + var(--p,0) * .10));
  filter:saturate(.85) contrast(1.05);
}
.plate--near{
  opacity:calc(.18 + var(--p,0) * .72);
  transform:translate3d(0,calc(var(--p,0) * -11vh),0) scale(calc(1.00 + var(--p,0) * .18));
  mix-blend-mode:screen;
}
.plate__veil{position:absolute;inset:0;
  background:
    linear-gradient(to bottom,rgba(5,7,12,.86) 0%,rgba(5,7,12,.42) 34%,rgba(5,7,12,.58) 72%,rgba(5,7,12,.94) 100%),
    radial-gradient(ellipse at 50% 55%,transparent 30%,rgba(5,7,12,.7) 92%);
}
.act[data-theme="light"] .plate__veil{
  background:linear-gradient(to bottom,rgba(238,242,245,.72) 0%,rgba(238,242,245,.5) 40%,rgba(238,242,245,.9) 100%);
}
/* grain léger, commun à toutes les plaques */
.act__bg::after{content:'';position:absolute;inset:0;pointer-events:none;opacity:.14;
  background-image:radial-gradient(rgba(255,255,255,.5) .5px,transparent .5px);
  background-size:3px 3px;mix-blend-mode:overlay}

/* Le haut laisse passer l'en-tête ET le bouton d'avance qui est juste en
   dessous : sans cette marge, le titre de l'acte passerait sous le bouton. */
/* Les deux marges passent par des variables : le filet des fenêtres peu hautes
   en a besoin pour calculer la hauteur disponible, et `max-height:100%` ne
   servirait à rien ici (un pourcentage ne se résout pas contre une hauteur
   seulement imposée par min-height). */
.act__sticky{position:sticky;top:0;min-height:100vh;display:flex;align-items:center;z-index:1;
  --pad-haut:calc(var(--head-h) + 66px);--pad-bas:86px;
  padding:var(--pad-haut) 0 var(--pad-bas)}
.act__inner{width:100%;max-width:var(--maxw);margin:0 auto;padding:0 clamp(16px,4vw,130px) 0 var(--gut)}
.act__inner.act--narrow{max-width:min(760px,100%)}
.act[data-theme="light"]{color:#0c1218}
.act[data-theme="light"] code{color:#10507a}
.act[data-theme="light"] em{color:#000;border-bottom-color:rgba(34,60,82,.5)}

.act__head{margin-bottom:clamp(14px,2.4vh,26px)}
.act__num{font-family:var(--mono);font-size:.68rem;letter-spacing:.34em;text-transform:uppercase;color:var(--holo);margin-bottom:8px}
.act[data-theme="light"] .act__num{color:var(--reso)}
.act__title{font-size:clamp(2rem,6.2vw,4.3rem);font-weight:900;letter-spacing:-.035em;text-transform:uppercase;
  font-variation-settings:'wdth' 118;text-wrap:balance}
.act__line{font-size:clamp(1rem,1.7vw,1.26rem);color:var(--imp);margin-top:10px;max-width:40ch}
.act[data-theme="light"] .act__line{color:#3b4a57}
/* Largeur de lecture par défaut des paragraphes d'un acte.
   `:where()` ne compte pas dans le calcul de priorité : la règle pèse donc
   autant qu'un simple `p`, et la moindre classe posée sur un paragraphe la
   remplace — `.act__line{max-width:40ch}` ci-dessus, `.act1__caveat`,
   `.act2__lane-sub`, etc. Écrite autrement (`.act p`), elle gagnait contre
   toutes ces classes et les largeurs par acte ne s'appliquaient jamais, en
   silence. Pour surcharger : une classe sur le paragraphe suffit. */
:where(.act) p{max-width:62ch}
.act__todo{
  margin-top:18px;font-family:var(--mono);font-size:.74rem;line-height:1.55;color:var(--imp);
  border-left:2px solid rgba(138,143,152,.4);padding-left:12px;max-width:58ch;
}

/* ------------------------------------------- la zone de passage entre deux actes */
/* Le défaut, entre tous les actes. shell.js écrit ici, à chaque image de
   défilement, l'avancement du passage sous forme de valeurs déjà calculées
   (voir SG.Transition.curve) ; la CSS ne fait que les appliquer. Aucune
   transition CSS sur ces propriétés : elles suivent le doigt, pas une durée.

   Le défaut corrigé : sans ces règles, l'acte qui arrive peint sa plaque à sa
   place naturelle, c'est-à-dire en remontant depuis le bas de l'écran par-dessus
   l'acte en cours. D'où la frontière horizontale nette entre deux décors.
   Ici la plaque entrante est ÉPINGLÉE plein écran (position:fixed, voir plus
   bas) avant d'être montrée, puis amenée en fondu : les deux décors sont
   toujours superposés plein écran, jamais bord à bord. */

/* LE MOUVEMENT D'ÉCHELLE NE TOUCHE JAMAIS LE CADRE, SEULEMENT L'IMAGE DEDANS.
   Agrandir .act__bg, qui fait exactement un écran, déplacerait son bord haut de
   la moitié de l'agrandissement — et à la sortie du passage, quand la règle est
   relâchée, ce déplacement revenait à zéro d'un coup : l'image sautait
   verticalement, dans les deux sens de défilement. Ici l'échelle est posée sur
   les plaques elles-mêmes, par la propriété `scale`, indépendante de leur
   `transform` de parallaxe. Le cadre, lui, ne bouge pas d'un pixel : il ne
   reste aucune discontinuité à relâcher. */

/* L'acte qui sort : son texte s'efface en premier, son image pousse un peu,
   puis s'efface à son tour dès que celle qui arrive couvre tout l'écran. */
.act[data-leave] > .act__sticky{opacity:var(--leave-text,1)}
.act[data-leave="off"] > .act__sticky{pointer-events:none}
.act[data-leave] > .act__bg{opacity:var(--leave-bg,1)}
.act[data-leave] > .act__bg .plate{scale:var(--leave-scale,1)}

/* L'acte qui entre : pendant le passage, son décor et son texte sont épinglés
   en haut de l'écran PAR LE NAVIGATEUR, le temps que le fondu se joue.

   POURQUOI position:fixed, ET SURTOUT PAS UN DÉCALAGE ÉCRIT PAR LE JAVASCRIPT.
   La version précédente relevait la scène entrante avec une variable --lift
   réécrite à chaque image de défilement. Or le navigateur compose le
   défilement AVANT d'exécuter cette passe : à chaque cran de molette, la scène
   entrante partait vers le haut de tout un cran, puis revenait à l'image
   suivante. Mesuré : 140 px d'aller-retour à chaque cran pendant tout le
   passage, et un saut de ~60 px à la sortie, image entièrement visible.
   C'était le tremblement.
   `position:fixed` confie l'épinglage au navigateur : plus rien à compenser,
   donc plus rien à retarder. Rien ne bouge pour autant dans la page : ces
   deux blocs ne pesaient déjà rien dans le flux (hauteur d'écran annulée par
   une marge basse négative, et la hauteur des actes est imposée en CSS), et
   le cadre fixe fait exactement la même largeur que dans le flux. À la sortie
   du passage, l'acte a son haut à zéro : le retour au collant tombe au pixel
   près au même endroit. */
@media (prefers-reduced-motion:no-preference){
  .act[data-enter] > :not(.act__sticky){
    position:fixed;top:0;left:0;right:0;height:100vh;margin-bottom:0;
  }
  .act[data-enter] > .act__bg{opacity:var(--enter-bg,0)}
  /* Le texte entrant n'est épinglé et montré que sur grand écran : sous 768 px
     le contenu n'est pas collant (voir plus bas), il défile normalement et n'a
     rien à faire d'un épinglage — et là, c'est lui qui donne sa hauteur à
     l'acte, le sortir du flux l'effondrerait. Le fondu des deux plaques, lui,
     s'applique partout. */
  @media (min-width:768px){
    .act[data-enter] > .act__sticky{
      position:fixed;top:0;left:0;right:0;
      transform:translate3d(0,var(--enter-ty,0px),0);
      opacity:var(--enter-text,0);
    }
    /* Seulement pendant le passage lui-même : dans la marge de sécurité qui le
       suit (data-enter="hold"), l'acte est arrivé et doit répondre au clic. */
    .act[data-enter="1"] > .act__sticky{pointer-events:none}
  }
}
.act[data-enter] > .act__bg .plate{scale:var(--enter-scale,1)}

/* Le repère de progression du passage, sur la règle graduée : le segment entre
   la graduation qu'on quitte et la suivante se remplit au fil du passage.
   Rien de neuf à l'écran, c'est la règle qui parle. */
.sg-ruler__ticks::after{
  content:'';position:absolute;right:13px;width:2px;border-radius:2px;
  top:calc((var(--ruler-y0) + var(--gi,0) / (var(--n) - 1) * var(--ruler-span)) / var(--ruler-vb) * 100%);
  height:calc(var(--ruler-span) / (var(--n) - 1) / var(--ruler-vb) * 100%);
  background:linear-gradient(to bottom,
    var(--ui-accent) 0,var(--ui-accent) calc(var(--gate,0) * 100%),
    rgba(138,143,152,.22) calc(var(--gate,0) * 100%));
  opacity:0;transition:opacity .25s;pointer-events:none;
}
.sg-ruler.is-gate .sg-ruler__ticks::after{opacity:1}
.sg-ruler.is-gate .sg-ruler__art #indicator{filter:drop-shadow(0 0 6px var(--ui-accent))}

/* entrée en scène : seulement quand le JavaScript tourne */
.sg-js .act__head,.sg-js .act__inner > p,.sg-js .act__inner > div:not(.act__bg){
  transition:opacity .75s var(--ease),transform .75s var(--ease);
}
.sg-js .act:not(.is-seen) .act__head{opacity:0;transform:translateY(20px)}
.sg-js .act:not(.is-seen) .act__inner > p{opacity:0;transform:translateY(14px)}

/* ------------------------------------- fiches « pour tout comprendre » */
.sg-dossier{
  font:inherit;font-size:.82em;cursor:pointer;background:none;border:0;
  color:var(--holo);border-bottom:1px dotted currentColor;
  display:inline-flex;align-items:center;gap:.35em;padding:0 0 1px;margin-left:.2em;
  font-family:var(--mono);letter-spacing:.02em;
}
.sg-dossier:hover{color:#fff;border-bottom-style:solid}
.act[data-theme="light"] .sg-dossier{color:#10507a}
.sg-dossier__ic{width:1em;height:1em}

.sg-card-store{display:none}

.sg-card{
  border:0;padding:0;background:transparent;color:var(--ink);
  position:fixed;inset:0;margin:auto;   /* le reset *{margin:0} tue le centrage natif */
  width:min(640px,calc(100vw - 32px));max-width:none;max-height:min(84vh,780px);
  overflow:visible;
}
.sg-card::backdrop{background:rgba(2,4,8,.82);backdrop-filter:blur(3px)}
.sg-card__frame{position:absolute;inset:-14px;pointer-events:none}
.sg-card__art{width:100%;height:100%;color:rgba(95,212,255,.45)}
.sg-card__in{
  position:relative;background:#080c13;border:1px solid rgba(95,212,255,.32);
  box-shadow:0 0 0 1px rgba(5,7,12,.9),0 30px 80px rgba(0,0,0,.6),inset 0 1px 0 rgba(95,212,255,.12);
  padding:clamp(22px,4vw,34px);max-height:min(84vh,780px);overflow-y:auto;
}
.sg-card__in::before{content:'';position:absolute;left:0;top:0;width:100%;height:2px;
  background:linear-gradient(to right,transparent,var(--holo),transparent);opacity:.7}
.sg-card__kicker{display:flex;align-items:center;gap:.5em;font-family:var(--mono);font-size:.64rem;
  letter-spacing:.26em;text-transform:uppercase;color:var(--holo);margin-bottom:12px}
.sg-card__ttl{font-size:clamp(1.3rem,3.4vw,1.9rem);margin-bottom:14px;text-wrap:balance}
.sg-card__body p{max-width:none;margin-bottom:12px;color:#c9d3dd}
.sg-card__body p:last-child{margin-bottom:0}
.sg-card__note{font-family:var(--mono);font-size:.72rem;color:var(--imp);border-top:1px solid var(--ui-line);padding-top:10px}
.sg-card__close{position:absolute;top:10px;right:10px;color:var(--imp)}

/* ---------------------------------------------------------------- pied */
.sg-foot{
  position:relative;z-index:2;background:#03050a;border-top:1px solid rgba(138,143,152,.2);
  padding:46px var(--gut) 60px;text-align:center;color:var(--imp);
}
.sg-foot__l1{font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:#cfd8e2;font-variation-settings:'wdth' 112}
.sg-foot__l2{max-width:62ch;margin:10px auto 0;font-size:.86rem}
.sg-foot__l3{margin-top:18px;font-family:var(--mono);font-size:.72rem;letter-spacing:.1em}
.sg-foot__credits{max-width:72ch;margin:16px auto 0;font-size:.74rem;text-align:left}
.sg-foot__credits summary{cursor:pointer;font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--imp);text-align:center}
.sg-foot__credits p{margin-top:8px;color:#78818c;line-height:1.5}

/* --------------------------------------------------- écrans peu hauts */
/* Le contenu d'un acte est collé : ce qui dépasse par le bas est perdu, le
   visiteur n'a aucun moyen d'y arriver. Sur un portable de 720 px de haut, la
   mise en page prévue pour 900 px ne tient pas. On resserre donc par paliers de
   HAUTEUR, exactement comme act4-6.css le fait pour ses propres éléments, mais
   ici sur ce qui appartient à la coquille : l'en-tête, les marges de l'acte, le
   titre, l'accroche, la graisse du texte courant.

   Ces règles passent volontairement devant les tailles posées acte par acte
   (d'où le `.sg-js .act` qui leur donne le dessus) : sur un écran court, faire
   tenir le texte compte plus que la taille exacte voulue pour un acte.

   Et si, malgré tout, un acte ne tient toujours pas — un acte très chargé sur
   une fenêtre très courte —, shell.js le repère et pose data-fit="tight" :
   le bloc défile alors sur lui-même. Ce n'est pas joli, mais plus rien n'est
   inatteignable, et le défilement continue naturellement sur la page une fois
   le bas du bloc atteint. */
@media (min-width:768px) and (max-height:860px){
  :root{--head-h:52px}
  body{font-size:clamp(14px,.97vw,16px);line-height:1.55}
  .act__sticky{--pad-haut:calc(var(--head-h) + 52px);--pad-bas:56px}
  .sg-hold{top:calc(var(--head-h) + 6px)}
  .sg-hold__btn{width:42px;height:42px}
  .sg-js .act .act__title{font-size:clamp(1.6rem,4.3vw,2.8rem)}
  .sg-js .act .act__head{margin-bottom:clamp(9px,1.5vh,15px)}
  .sg-js .act .act__line{font-size:clamp(.92rem,1.25vw,1.06rem);margin-top:6px}
  .act__todo{margin-top:12px;font-size:.7rem;line-height:1.45}
  .act__num{margin-bottom:5px}
}
@media (min-width:768px) and (max-height:770px){
  :root{--head-h:48px}
  body{font-size:13.6px;line-height:1.48}
  .act__sticky{--pad-haut:calc(var(--head-h) + 44px);--pad-bas:40px}
  .sg-hold__btn{width:38px;height:38px}
  .sg-js .act .act__title{font-size:clamp(1.4rem,3.4vw,2.2rem)}
  .sg-js .act .act__head{margin-bottom:8px}
  .sg-js .act .act__line{font-size:.9rem;margin-top:4px}
  .act__todo{margin-top:9px;font-size:.66rem}
  .act__num{font-size:.62rem;margin-bottom:3px}
}

/* Le filet : un acte qui ne tient toujours pas défile sur lui-même. Posé par
   shell.js, jamais en permanence — `overflow` découpe les décors qui débordent
   volontairement de leur cadre (les cadres de l'acte VI, par exemple). */
@media (min-width:768px){
  .act[data-fit="tight"] .act__inner{
    max-height:calc(100vh - var(--pad-haut) - var(--air-bas,14px));
    overflow-y:auto;overscroll-behavior-y:auto;
    scrollbar-width:thin;scrollbar-color:var(--ui-line) transparent;
  }
}

/* ---------------------------------------------------------------- mobile */
@media (max-width:767px){
  :root{--head-h:50px}
  .sg-ruler{display:none}
  .sg-timeline{
    display:flex;position:fixed;z-index:880;left:0;right:0;bottom:0;
    gap:3px;padding:8px 10px 10px;background:linear-gradient(to top,var(--ui-bg),transparent);
  }
  .sg-timeline[aria-hidden="true"]{display:flex}
  .sg-timeline__bar{flex:1;background:none;border:0;padding:6px 0 2px;cursor:pointer}
  .sg-timeline__bar i{display:block;height:3px;background:var(--ui-line);transition:background .25s}
  .sg-timeline__bar.is-here i,.sg-timeline__bar.is-done i{background:var(--ui-accent)}
  .sg-timeline__bar.is-done i{opacity:.45}
  /* Sous 768 px le haut est trop etroit : l'en-tete y tient deja le logo, le
     son et le menu, et le bouton centre tomberait dessus. Il reste donc en bas
     a droite, au-dessus de la timeline en barres, a portee du pouce. */
  .sg-hold{top:auto;bottom:34px;left:auto;right:12px;transform:none}
  .sg-hold__btn{width:44px;height:44px}
  .sg-head{gap:8px}
  .sg-head__wordmark span{display:none}
  .sg-head__wordmark strong{font-size:.76rem;letter-spacing:.08em}
  .sg-head__emblem{width:22px;height:22px}
  .sg-clearance__lbl{display:none}
  .act__inner{padding:0 var(--gut)}
  /* Le contenu ne reste pas colle sous 768 px : il defile sous un fond fixe.
     Les actes reprennent la hauteur de leur contenu. */
  .act__sticky{position:relative;z-index:1;padding:calc(var(--head-h) + 18px) 0 92px;align-items:flex-start}
  .sg-js .act,.sg-js .act--stub{height:auto}
  .act__bg{margin-bottom:-100vh}
  .act__title{font-size:clamp(1.8rem,10vw,2.6rem)}
  .sg-menu__list a{grid-template-columns:2.2rem 1fr;row-gap:2px}
  .sg-menu__line{grid-column:2}
}

/* ------------------------------------------------- mouvement réduit / sans JS */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .sg-js .act,.sg-js .act--stub{height:auto}
  .act__bg{position:absolute;inset:0;height:100%;margin:0}
  /* position:relative, et surtout pas static : la plaque de fond est
     positionnée, elle se peindrait PAR-DESSUS le texte de l'acte, qui
     deviendrait illisible. Le z-index de la règle générique n'agit que sur un
     élément positionné. Même raison sous 768 px et sans JavaScript. */
  .act__sticky{position:relative;z-index:1;min-height:0;padding:72px 0}
  .plate{position:absolute;inset:0;transform:none!important;filter:none}
  .plate--near{display:none}
  .sg-js .act:not(.is-seen) .act__head,
  .sg-js .act:not(.is-seen) .act__inner > p{opacity:1;transform:none}
  .act__bg::after{display:none}
  .sg-trans__canvas,.sg-warp{display:none!important}
  /* La zone de passage n'existe pas ici : la distance supplémentaire a déjà
     disparu avec les hauteurs d'acte, et le passage se réduit au fondu court
     de la couche #sgTrans. Garde-fou, au cas où un attribut traînerait. */
  .act[data-enter] > *,.act[data-leave] > *{transform:none!important;opacity:1!important}
  .act[data-enter] .plate,.act[data-leave] .plate{scale:none!important}
  /* le liseré du bouton son reste, il ne respire plus */
  #sgAudio.is-waiting::after{animation:none!important;opacity:.95;
    box-shadow:0 0 10px 1px rgba(95,212,255,.45)}
  .sg-ruler__ticks::after{display:none}
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
}
/* Sans JavaScript : empilement lisible, pas de sections collantes sur-dimensionnées. */
.sg-nojs .act__sticky{position:relative;z-index:1;padding:84px 0}
.sg-nojs .act__bg{position:absolute;inset:0;height:100%;margin:0}
.sg-nojs .sg-hold,.sg-nojs .sg-ruler__marker{display:none}
.sg-nojs .sg-card-store{display:block;max-width:var(--maxw);margin:0 auto;padding:40px var(--gut)}
.sg-nojs .sg-dossier{display:none}

@media print{
  .sg-head,.sg-ruler,.sg-timeline,.sg-hold,.sg-menu,.sg-trans,.act__bg{display:none}
  .act,.act__sticky{height:auto;position:static;min-height:0;padding:12px 0}
  body{background:#fff;color:#111}
}
