:root {
  color-scheme: dark;
  --bg: #06030b;
  --surface: rgba(255, 255, 255, 0.035);
  --text: #f4f1fa;
  --muted: #9d97b4;
  /* #4c4661 donnait 2,30:1 sur --bg : sous les 4,5:1 de AA, et il portait
     QUATRE choses, pas une — « Chargement », « Passer », le mot de fin du
     bloc final (une vraie phrase) et le bouton « Faire revivre le cube ».
     #8a83a3 donne 5,71:1 (mesure, pas estime) et garde le registre sourd. */
  --sourd: #8d96a8;
  --hairline: rgba(168, 130, 255, 0.14);
  --accent: #a855f7;
  --accent-clair: #c084fc;
  --glace: #bcd8ff;
  --glass: rgba(6, 3, 11, 0.72);
  --radius: 18px;
  --maxw: 1240px;
  --mono: ui-monospace, "SF Mono", Menlo, monospace;
  --vite: cubic-bezier(0.16, 1, 0.3, 1);

  /* ═══════════════ PANNEAU DE RÉGLAGE ═══════════════
     Tout ce qui se règle d'un chiffre est ici. Tu peux me dire par exemple
     « mets --cube-accueil à 70px » ou « le trou 20 % plus bas ». */

  /* LE CUBE, a chaque etape de sa fonte : UNE taille par plaque,
     visiblement decroissante — c'est la fonte qui se lit (2026-08-24).
     L'accueil est monte a 82 px (« un peu plus gros sur cette premiere »). */
  /* -30 % SUR L'ECRAN D'ENTREE — Sebastien, 2026-08-31 : « reduis la
     hauteur du cube pis de la flaque d'environ 30 % ». 82 -> 57 et
     200 -> 140. LES POSITIONS SUIVENT TOUTES SEULES et c'est voulu :
     `.cube-repos` calcule son `left` a partir de l'ecart entre les deux
     largeurs, et son `bottom` a partir de la hauteur du cube. Les consignes
     E8 (la flaque a sa place), E9 (+1 cm, +5 mm) et le glacon monte d'une
     hauteur de cube tiennent donc sans qu'on y retouche — c'est exactement
     pour ca qu'elles avaient ete ecrites en `calc()` plutot qu'en dur. */
  --cube-accueil: 82px;    /* posé sur la flaque, écran d'entrée */
  --cube-hero: 66px;       /* il retombe au hero */
  --cube-marque: 60px;     /* PROVOLU et la bande */
  --cube-demarche: 55px;   /* le cerveau */
  --cube-reduire: 50px;    /* il traverse « Réduire au nécessaire » */
  /* --cube-faire (46px) : RETIRE le 2026-08-24 avec la plaque « ce qu'on
     fait ». Ne pas le remettre : le parcours passe de 50 px a 42 px. */
  /* LE RACCORD AVEC LA VIDEO (2026-08-24 au soir). Sebastien : « comme le
     glacon va se deplacer, puis va aller dans l'image [...] il devra deja
     etre plus gros. A peu pres 20 % plus gros. Quand il va vers l'image, il
     devrait augmenter encore d'un autre 10 %, pour que le transit vers le
     glacon gros se fasse plus doucement. »
     C'est le SEUL endroit ou la fonte cesse de decroitre, et c'est voulu :
     le glacon de la video est bien plus gros que 38 px, et le raccord se
     voyait. 42 -> 50 (+20 %), puis 50 -> 55 (+10 %). */
  --cube-travaux: 50px;    /* il actionne le carrousel, deja plus gros */
  --cube-final: 55px;      /* la fonte finale : la vidéo le reprend en douceur */

  /* LA FLAQUE (écran d'entrée seulement) */
  --flaque-accueil: 200px;
  /* LA HAUTEUR DE LA FLAQUE SE DEDUIT DE SA LARGEUR : flaque.webp est
     540 x 305, donc h = l x 305/540. On l'ecrit une fois pour que la
     position du glacon suive la flaque si sa taille change un jour. */
  --flaque-h: calc(var(--flaque-accueil) * 305 / 540);
  /* L'ECART BAS-DU-GLACON -> HAUT-DE-LA-FLAQUE, en clair et reglable.
     Sebastien, 2026-08-31 : « ca aurait plutot du etre le cube qui se
     rapproche de la flaque d'eau de 20 % ». L'ecart d'origine (avant R8)
     mesurait 24,8 px a l'ecran ; -20 % le porte a 19,84, arrondi a 20. */
  --cube-ecart: 20px;

  /* LE TROU d'entrée : position et taille */
  /* RAPPROCHES le 2026-08-24 au soir, a sa demande : « approcher le glacon
     du trou ». La diagonale flaque -> trou faisait toute la largeur et
     toute la hauteur du cadre : deux grandes zones mortes, et un geste
     long. E10 (« trou 2 cm vers la droite », 2026-08-23) est REVISEE ici —
     c'est lui qui l'a demande, ne pas la restaurer sans qu'il le redise. */
  --trou-x: calc(60% + 0.4cm); /* horizontale, depuis la gauche */
  --trou-y: 68%;               /* verticale — remonte vers le glacon */
  --trou-taille: 150px;    /* largeur de référence */
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; overflow-x: clip; }

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  /* Tout reduit de moitie (demande Sebastien, 2026-08-22) : la barre
     verticale du haut (50 % -12 %) etait la plus visible, mais les trois
     degrades passent a la moitie de leur opacite. */
  background:
    radial-gradient(60rem 40rem at 50% -12%, rgba(139, 92, 246, 0.08), transparent 65%),
    radial-gradient(44rem 32rem at 88% 30%, rgba(192, 132, 252, 0.03), transparent 60%),
    radial-gradient(50rem 36rem at 8% 85%, rgba(109, 40, 217, 0.045), transparent 60%);
}

/* ---------- les étoiles : elles scintillent près de la souris ---------- */

.galaxie { position: fixed; inset: 0; z-index: -1; pointer-events: none; }

/* ---------- la nebuleuse : la brume DERRIERE les etoiles (C-154, 2026-09-02) ----------
   Trois taches floues, gris froid, chacune a sa profondeur (--k). `--neb-y`
   est pose par accueil.js : par plaque pendant l'intro, au defilement sur la
   vraie page. Transparente : elle ne masque JAMAIS le canvas (regle 2 de
   CONSIGNES.md). Pas de violet, pas de bleu (E6). Invisible sur la plaque 1,
   figee ; elle se leve avec le decompte (html.demarre). */
.nebuleuse {
  position: fixed;
  inset: -14%;
  z-index: -2;
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
  transition: opacity 2.6s ease;
}
html.demarre .nebuleuse, html.vraie-page .nebuleuse { opacity: 1; }
.porte .nebuleuse { z-index: 0; }          /* dans la porte : sous les etoiles (1), sur son fond */
.nebuleuse.suit-page { z-index: -1; }     /* sous la vraie page, qui n'a pas de canvas */
.neb {
  position: absolute;
  border-radius: 50%;
  filter: blur(46px);
  will-change: transform;
  transform: translate3d(0, calc(var(--neb-y, 0px) * var(--k)), 0);
  transition: transform 1.8s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.neb-1 { --k: 0.45; left: -8%;  top: 6%;     width: 62vw; height: 46vh;
  background: radial-gradient(closest-side, rgba(158, 160, 172, 0.13), rgba(158, 160, 172, 0.04) 55%, transparent 72%); }
.neb-2 { --k: 0.8;  right: -12%; top: 28%;   width: 56vw; height: 52vh;
  background: radial-gradient(closest-side, rgba(146, 148, 162, 0.11), transparent 70%); }
.neb-3 { --k: 1.25; left: 22%;  bottom: -10%; width: 70vw; height: 40vh;
  background: radial-gradient(closest-side, rgba(164, 166, 178, 0.09), transparent 70%); }
/* sur la vraie page, la brume suit la molette image par image : pas de transition */
.nebuleuse.suit-page .neb { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .neb { transition: none; transform: none; }
}

/* ---------- la dactylo : chaque lettre nait (C-154, chantier 5) ----------
   `display: inline` volontaire : un inline-block par lettre autoriserait une
   cesure au milieu d'un mot. Opacite et flou seulement. */
.mots .l { animation: lettre-nait 0.18s ease-out both; }
@keyframes lettre-nait {
  from { opacity: 0; filter: blur(3px); }
  to   { opacity: 1; filter: blur(0); }
}
@media (prefers-reduced-motion: reduce) { .mots .l { animation: none; } }
/* pendant la porte, elles vivent DANS l'écran d'entrée : au-dessus de son
   fond noir, sous le glaçon et le texte */
.porte .galaxie { z-index: 1; }

/* ================= LA PORTE ================= */

.porte-cadre {
  /* LA PAGE DANS LA PAGE — Sebastien, 2026-08-24 : la scene du glacon est
     cadree ; sur un grand ecran, plus rien ne fuit vers les bords. Les
     positions en % des enfants se lisent desormais dans CE cadre. */
  position: absolute;
  top: 0; bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: min(1240px, 100%);
}
.porte {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  /* PLUS DE LUEURS MAUVES NI BLEUES ICI (demande Sebastien, 2026-08-22) :
     seuls restent un fond uni et une vignette neutre qui referme les
     coins — les étoiles sont la seule lumière de la scène. */
  background:
    radial-gradient(122% 98% at 50% 46%, transparent 48%, rgba(2, 0, 6, 0.8) 100%),
    #05020a;
  overflow: hidden;
}
.porte.on { display: block; }
.porte.fin { opacity: 0; transition: opacity 0.9s ease; pointer-events: none; }

.phrase {
  position: absolute;
  left: clamp(6%, 9vw, 12%);
  bottom: clamp(20%, 28vh, 33%);   /* rapproche de la flaque, demande par Sebastien */
  max-width: 20ch;
  /* -10 %, -20 %, puis -30 % de plus, demandes par Sebastien :
     1,35/3/2,6 -> 1,22/2,7/2,34 -> 0,98/2,16/1,87 -> 0,69/1,51/1,31 */
  font-size: clamp(0.69rem, 1.51vw, 1.31rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.025em;
  /* un cran plus discrète : la scène appartient au glaçon, pas au texte */
  background: linear-gradient(180deg, #ece6f7 22%, #bda8e8 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 1.4s ease, transform 1.4s var(--vite);
}
.porte.p1 .phrase { opacity: 0.82; transform: none; }

/* LA PHRASE S'ÉCRIT, elle n'apparaît plus : trois points d'abord, comme
   un message texte qu'on est en train de rédiger, puis les lettres
   arrivent une à une à une cadence IRRÉGULIÈRE — vite, une pause, vite
   encore. La phrase se termine par trois points, pas par un point. */
.phrase {
  opacity: 0.82 !important;
  transform: none !important;
  letter-spacing: -0.025em;
  min-height: 2.4em;   /* la ligne ne saute pas quand le texte s'allonge */
}
/* le curseur qui clignote pendant la frappe */
.phrase .curseur {
  display: inline-block;
  width: 0.08em;
  height: 0.95em;
  margin-left: 0.06em;
  background: currentColor;
  vertical-align: text-bottom;
  opacity: 0.75;
}
html.anim .phrase .curseur { animation: curseur-bat 1s steps(1) infinite; }
@keyframes curseur-bat { 0%, 49% { opacity: 0.75; } 50%, 100% { opacity: 0; } }
/* les trois points « quelqu'un écrit », avant que la frappe commence */
.phrase .points { display: inline-flex; gap: 0.22em; align-items: center; }
.phrase .points i {
  width: 0.26em; height: 0.26em; border-radius: 50%;
  background: currentColor; opacity: 0.25;
}
html.anim .phrase .points i { animation: point-ecrit 1.35s ease-in-out infinite; }
html.anim .phrase .points i:nth-child(2) { animation-delay: 0.18s; }
html.anim .phrase .points i:nth-child(3) { animation-delay: 0.36s; }
@keyframes point-ecrit {
  0%, 60%, 100% { opacity: 0.22; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-0.16em); }
}

/* LE VOILE DE CHARGEMENT : noir plein écran, au-dessus du glaçon, de la
   flaque et du trou — ils existent déjà en dessous, mais on ne les révèle
   qu'une fois la page prête. Le décompte vit sur ce voile. */
/* « On va donner une transition en flou pour faire apparaitre la page
   suivante. L'image vient noire, puis on apparait le background. Ca va un
   petit peu moins vite, mais c'est plus elegant. » (2026-08-24 au soir)
   Le voile part de noir OPAQUE et FLOU, et se leve en 1,5 s au lieu de
   0,9 s. Le fond n'apparait donc pas d'un coup : il se precise. */
.voile-charge {
  position: absolute;
  inset: 0;
  z-index: 6;
  background: #05020a;
  opacity: 1;
  backdrop-filter: blur(14px);
  transition: opacity 1.5s ease, backdrop-filter 1.5s ease;
  pointer-events: none;
}
.porte.charge-fini .voile-charge { opacity: 0; backdrop-filter: blur(0px); }

/* La flaque reste FIXE à sa place : elle ne suit jamais le glaçon. */
.flaque-fixe {
  position: absolute;
  left: clamp(6%, 9vw, 12%);
  bottom: clamp(34%, 42vh, 48%);
  width: var(--flaque-accueil);
  height: auto;
  opacity: 0;
  transform: scale(0.7);
  /* +1 s : l'apparition prend son temps apres le decompte (demande Sebastien) */
  transition: opacity 2.1s ease, transform 2.2s var(--vite);
  filter: drop-shadow(0 0 5.5px rgba(168, 85, 247, 0.06));  /* -50 % puis -50 % encore, demande Sebastien */
  pointer-events: none;
}
.porte.p3 .flaque-fixe { opacity: 0.9; transform: none; }

/* Le glaçon au repos, posé sur la flaque. */
.cube-repos {
  position: absolute;
  /* centré sur la flaque : on compense la moitié de l'écart de largeur */
  left: calc(clamp(6%, 9vw, 12%) + (var(--flaque-accueil) - var(--cube-accueil)) / 2 + 5mm);
  /* LE GLACON SE POSITIONNE PAR RAPPORT A LA FLAQUE — REECRIT le 2026-08-31.
     CE QUI ETAIT FAUX : le glacon portait son PROPRE clamp vertical
     (36%/44.5vh/51%) pendant que la flaque portait le sien (34%/42vh/48%).
     Deux clamps differents ne bougent pas ensemble : l'ecart entre les deux
     objets changeait avec la hauteur de la fenetre, sans que rien ne le dise.
     Et parce que le reste de la formule etait FIXE (+1cm + la hauteur du
     cube), la reduction de taille R8 a eloigne le glacon en proportion —
     c'est ce que Sebastien a vu : « le cube [devrait] se rapprocher de la
     flaque d'eau de 20 % ».
     CE QUI EST VRAI MAINTENANT : un seul clamp, celui de la flaque, plus la
     hauteur de la flaque, plus un ecart nomme. L'ecart est donc CONSTANT a
     toute hauteur d'ecran, et se regle en une valeur (`--cube-ecart`).
     Revise E9 (le +1cm du 23) et Y7 (la hauteur de glacon du 25) : les deux
     disaient « au-dessus de la flaque, visiblement separe » — c'est
     exactement ce que 20 px d'ecart donnent, et ils ne derivent plus. */
  bottom: calc(clamp(34%, 42vh, 48%) + var(--flaque-h) + var(--cube-ecart));
  width: var(--cube-accueil);
  height: auto;
  cursor: grab;
  touch-action: none;
  -webkit-user-drag: none;
  user-select: none;
  opacity: 0;
  transform: translateX(-80px);
  transition: opacity 1.9s ease, transform 2s var(--vite);   /* +1 s */
  filter: drop-shadow(0 14px 26px rgba(0, 0, 0, 0.55));
  z-index: 4;
}
.porte.p2 .cube-repos { opacity: 1; transform: none; }
/* 1 s de retard avant le premier mouvement, demande par Sebastien */
html.anim .porte.p4 .cube-repos { animation: vibre 3.2s ease-in-out 1s infinite; }
@keyframes vibre {
  0%, 84%, 100% { transform: translate(0, 0) rotate(0deg); }
  86% { transform: translate(-2px, 1px) rotate(-1.2deg); }
  88% { transform: translate(2px, -1px) rotate(1.2deg); }
  90% { transform: translate(-2px, 0) rotate(-1deg); }
  92% { transform: translate(1px, 1px) rotate(0.8deg); }
  95% { transform: translate(-1px, 0) rotate(-0.4deg); }
}
.porte.prise .cube-repos { opacity: 0; animation: none; }

/* Le trou : réglé par le panneau. Pas de halo — flottant et discret. */
.trou {
  position: absolute;
  left: var(--trou-x);
  top: var(--trou-y);
  width: var(--trou-taille);
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0;
  transition: opacity 2.2s ease, filter 0.35s ease;   /* +1 s */
}
.porte.p3 .trou { opacity: 0.8; }
.trou .gouffre {
  position: absolute;
  left: 11%; right: 11%; top: 16%; bottom: 26%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 42%, #010004 46%, rgba(4, 2, 10, 0.85) 76%, transparent);
  z-index: 1;
}
.trou .anneau { position: relative; z-index: 3; width: 100%; height: auto; display: block; }
/* quand le cube approche : le trou s'éveille à peine, sans halo */
.trou.faim { filter: brightness(1.35); animation: trou-vibre 0.22s ease-in-out infinite; }
@keyframes trou-vibre {
  0%, 100% { transform: translate(-50%, -50%) rotate(0deg); }
  25% { transform: translate(calc(-50% - 1.5px), calc(-50% + 1px)) rotate(-0.6deg); }
  50% { transform: translate(calc(-50% + 1px), calc(-50% - 1.5px)) rotate(0.5deg); }
  75% { transform: translate(calc(-50% - 1px), calc(-50% + 1.5px)) rotate(-0.4deg); }
}

/* Le glaçon en main : translucide, avec sa traînée. */
.cube-main {
  position: absolute;
  width: var(--cube-accueil);
  height: auto;
  cursor: grabbing;
  touch-action: none;
  -webkit-user-drag: none;
  user-select: none;
  opacity: 0;
  pointer-events: none;
  z-index: 6;
  will-change: transform;
}
/* en main : le glacon, rien d'autre — plus de halo mauve (2026-08-24) */
.porte.prise .cube-main { opacity: 0.85; filter: drop-shadow(0 14px 26px rgba(0, 0, 0, 0.55)); }
.porte.chute .cube-main { opacity: 1; z-index: 2; }

.trainee {
  position: absolute;
  width: 40px;
  height: auto;
  pointer-events: none;
  z-index: 5;
  opacity: 0;
  animation: trainee-part 0.8s ease-out 1 both;
}
@keyframes trainee-part {
  0% { opacity: 0.32; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.5); }
}

/* LE DÉCOMPTE : la page est lourde, et une page lourde qui ne dit rien a
   l'air cassée. Le nombre monte au rythme du VRAI chargement — il ne
   s'invente rien, il ne dépasse jamais ce qui est réellement arrivé. */
.chargement {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 7;
  text-align: center;
  pointer-events: none;
  transition: opacity 0.9s ease, transform 1.1s var(--vite);
}
.chargement .mot {
  display: block;
  font-family: var(--mono);
  font-size: 0.68rem; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--sourd);
  margin-bottom: 1rem;
}
/* LE COMPTEUR MONTE LE LONG DU BORD DROIT — Sebastien, 2026-08-31 : « je
   veux que le chiffre soit a droite dans mon ecran et qu'il se mette a
   monter dans le haut de l'ecran. Quand il va atteindre en haut, il va
   etre rendu a 99. » Le chiffre ne se contente plus de compter : sa
   HAUTEUR dit l'avancement, comme le rail le dit en largeur.
   Il a sa propre couche, hors de `.chargement` : ce bloc-la est centre par
   un `translate(-50%,-50%)`, un enfant n'en sort pas.
   La taille reste celle d'origine (consigne E3 — reduite une fois, remise
   ensuite) : elle n'est PAS a retoucher au passage. */
.compteur-vol {
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.9s ease, transform 1.1s var(--vite);
}
.porte.lance .compteur-vol { opacity: 1; }
.porte.pret .compteur-vol { opacity: 0; transform: scale(0.94); }
.compteur-vol .nombre {
  display: block;
  position: absolute;
  right: clamp(1.4rem, 7vw, 6rem);
  /* `--montee` : 0 au depart (bas de l'ecran), 1 a 99 (haut). Elle est
     poussee image par image par accueil.js — AUCUNE transition ici, une
     transition ferait trainer le chiffre derriere son propre compte. */
  top: calc(82% - (var(--montee, 0) * 66%));
  transform: translateY(-50%);
  font-family: var(--mono);
  /* retour a la taille d'origine : Sebastien preferait le look plus imposant */
  font-size: clamp(2.4rem, 6.5vw, 4.6rem);
  font-weight: 300; line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 40px rgba(168, 85, 247, 0.5);
}
/* MOUVEMENT REDUIT : il compte, il ne voyage pas. Le deplacement est
   pilote en JS, donc le garde global (@media plus bas) ne l'atteint pas —
   il faut le neutraliser ici, en figeant la hauteur. */
@media (prefers-reduced-motion: reduce) {
  .compteur-vol .nombre { top: 50%; }
}
.chargement .rail {
  display: block; position: relative; overflow: hidden;
  width: clamp(130px, 17vw, 210px); height: 1px;
  margin: 1.3rem auto 0;
  background: rgba(255, 255, 255, 0.10);
}
.chargement .rail i {
  position: absolute; left: 0; top: 0; bottom: 0; width: 1%;
  background: linear-gradient(90deg, var(--accent), var(--accent-clair));
  box-shadow: 0 0 12px rgba(192, 132, 252, 0.8);
  transition: width 0.3s linear;
}
.porte.pret .chargement { opacity: 0; transform: translate(-50%, -50%) scale(0.94); }

/* À L'OUVERTURE, RIEN NE SE DÉVOILE : le glaçon, la flaque et le trou sont
   déjà là. Le seul temps qui passe est celui du chargement. */
.porte.direct .phrase,
.porte.direct .flaque-fixe,
.porte.direct .cube-repos,
.porte.direct .trou { transition: none !important; }

/* (Le « Passer » de la porte est parti le 2026-08-24 : un seul saut,
   « Passer l'intro », bas-droit, a 5 s.) */

.eclair { position: absolute; inset: 0; background: #e9defc; opacity: 0;
  pointer-events: none; z-index: 9; }
.porte.eclat .eclair { animation: flash 0.5s ease 1 both; }
@keyframes flash { 0% { opacity: 0; } 35% { opacity: 0.8; } 100% { opacity: 0; } }

/* La page gire au complet pour s'ouvrir. */
html.anim main.tour {
  animation: tourne-page 1.25s cubic-bezier(0.3, 0.9, 0.3, 1) 1 both;
  transform-origin: 50% 38vh;
}
@keyframes tourne-page {
  0% { transform: rotate(-360deg) scale(0.18); opacity: 0; }
  35% { opacity: 1; }
  100% { transform: none; opacity: 1; }
}

/* La goutte qui tombe. */
.goutte {
  position: fixed;
  z-index: 70;
  width: 11px;
  pointer-events: none;
  animation: tombe var(--dur, 1.4s) cubic-bezier(0.5, 0, 0.9, 0.6) 1 both;
}
@keyframes tombe {
  0% { opacity: 0; transform: translateY(0) scaleY(0.7); }
  12% { opacity: 0.9; }
  85% { opacity: 0.7; }
  100% { opacity: 0; transform: translateY(var(--chute, 60vh)) scaleY(1.5); }
}

/* ---------- le compagnon ---------- */

#compagnon {
  position: fixed;
  left: 0; top: 0;
  z-index: 34;
  width: 60px;   /* 40 % plus petit qu'avant : il ne doit pas dominer */
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.9s ease;
  will-change: transform;
}
#compagnon.la { opacity: 0.95; }
#compagnon .enveloppe { position: relative; }
#compagnon img { width: 100%; height: auto; display: block;
  filter: drop-shadow(0 12px 26px rgba(0, 0, 0, 0.5)); }
/* Un reflet traverse la glace, de temps en temps. */
#compagnon .brille {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(112deg, transparent 40%, rgba(255, 255, 255, 0.85) 50%, transparent 60%);
  background-size: 300% 100%;
  -webkit-mask-image: url("cube.webp");
  mask-image: url("cube.webp");
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
}
html.anim #compagnon .brille { animation: brille-glace 9s ease-in-out infinite; }
@keyframes brille-glace {
  0% { opacity: 0; background-position: 130% 0; }
  4% { opacity: 1; }
  13% { opacity: 0; background-position: -40% 0; }
  46% { opacity: 0; background-position: 130% 0; }
  50% { opacity: 0.9; }
  58% { opacity: 0; background-position: -40% 0; }
  100% { opacity: 0; background-position: -40% 0; }
}

/* ---------- la barre : le logo SEUL, et seulement en bas ---------- */

.topbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  padding: 0.8rem clamp(1.25rem, 3.5vw, 2.5rem);
  background: var(--glass);
  -webkit-backdrop-filter: blur(20px) saturate(1.8);
  backdrop-filter: blur(20px) saturate(1.8);
  border-bottom: 1px solid var(--hairline);
  transform: translateY(-110%);
  transition: transform 0.8s var(--vite);
}
.topbar.la { transform: none; }

/* L'ARRIVÉE DE LA BARRE, en bas de page : elle ne se contente pas de
   descendre. Un large reflet balaie le bandeau, puis un point très brillant
   file sur la ligne mauve. UNE fois — c'est une arrivée, pas une boucle. */
.topbar { overflow: hidden; }
.topbar > .p-marque { position: relative; z-index: 4; }
.eclat-barre {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none; opacity: 0;
  background: linear-gradient(100deg, transparent 32%,
    rgba(214, 190, 255, 0.45) 46%, rgba(255, 255, 255, 0.9) 51%,
    rgba(214, 190, 255, 0.45) 56%, transparent 70%);
  background-size: 260% 100%;
}
html.anim .topbar.la .eclat-barre { animation: barre-reflet 1.6s ease-out 0.3s 1 both; }
@keyframes barre-reflet {
  0% { opacity: 0; background-position: 130% 0; }
  12% { opacity: 1; }
  100% { opacity: 0; background-position: -50% 0; }
}
.ligne-barre {
  position: absolute; left: 0; right: 0; bottom: 0; height: 1px; z-index: 3;
  background: linear-gradient(90deg, transparent, rgba(168, 85, 247, 0.7) 16%,
    rgba(192, 132, 252, 0.95) 50%, rgba(168, 85, 247, 0.7) 84%, transparent);
  opacity: 0; transition: opacity 0.9s ease 0.25s;
  pointer-events: none;
}
.topbar.la .ligne-barre { opacity: 1; }
.ligne-barre::after {
  content: ""; position: absolute; top: 50%; left: 0;
  width: 110px; height: 3px; margin-top: -1.5px;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, #ffffff 55%, transparent);
  box-shadow: 0 0 16px 4px rgba(230, 210, 255, 0.9);
  opacity: 0;
}
html.anim .topbar.la .ligne-barre::after {
  animation: point-file 0.8s cubic-bezier(0.45, 0, 0.25, 1) 0.5s 1 both;
}
@keyframes point-file {
  0% { opacity: 0; transform: translateX(-160px); }
  14% { opacity: 1; }
  86% { opacity: 1; }
  100% { opacity: 0; transform: translateX(100vw); }
}
.p-marque { position: relative; display: block; line-height: 0; cursor: pointer;
  background: none; border: 0; padding: 0; }
.p-marque img { height: 38px; width: auto; display: block;
  filter: drop-shadow(0 0 12px rgba(168, 85, 247, 0.55)); }
.reflet-p::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  /* LA BANDE ETAIT UN LAVIS, PAS UN REFLET — corrige le 2026-08-31.
     Sebastien, le 31 : « il est plus gros que le P, il doit se faire
     vraiment juste sur les leds du P ». R2 avait traite le HALO (le masque
     triple) et cru le probleme regle. Il ne l'etait pas : la BANDE ELLE-MEME
     etait trop large. Mesure a l'ecran avant correctif : 38 % -> 62 % du
     degrade, sur un fond de 280 % de large, donnaient 60,4 px de blanc sur
     un P de 89,9 px — les DEUX TIERS du symbole allumes d'un coup, a 0,9
     d'opacite. Le P ne brillait pas, il blanchissait.
     46 % -> 54 % ramene la bande a 22 % de la largeur du P : un ruban qui
     passe. Et 0,55 au lieu de 0,9 laisse le violet transparaitre dessous —
     c'est un reflet sur une matiere, pas un voile par-dessus.
     CE QUI RESTE, dit franchement : le halo mauve cuit dans l'alpha de
     symbole-provolu.webp est attenue par le masque triple, pas eteint. Une
     vraie silhouette (fichier de masque net) le reglerait pour de bon. */
  background: linear-gradient(105deg, transparent 46%, rgba(255, 255, 255, 0.55) 50%, transparent 54%);
  background-size: 280% 100%;
  /* LE REFLET DEBORDAIT LE P — Sebastien, 2026-08-31 : « il est plus gros
     que le P, il doit se faire vraiment juste sur les leds du P ».
     LA CAUSE, mesuree sur le fichier et non devinee : le canal alpha de
     `symbole-provolu.webp` n'est PAS une silhouette. Son alpha non nul
     couvre le canevas ENTIER (0,0 -> 279,313), et 60,3 % de ses pixels
     visibles sont semi-transparents — c'est le halo mauve, cuit dans
     l'image. Un masque alpha laisse passer proportionnellement : le halo
     recevait donc 20 a 60 % du reflet, tout autour du P.
     LE CORRECTIF : la meme image posee TROIS fois et intersectee. Les
     alphas se multiplient, donc un pixel passe a la puissance 3 —
     0,2 -> 0,008 (le halo disparait), 0,6 -> 0,22 (la frange s'efface),
     1 -> 1 (le ruban reste entier). C'est un seuil d'alpha en CSS pur :
     aucune image de plus a produire, aucun octet de plus a telecharger,
     le navigateur ne decode qu'une fois.
     `-webkit-mask-composite: source-in` est la forme ancienne pour Safari ;
     `mask-composite: intersect` est la standard et vient APRES pour gagner
     la ou les deux existent. Si aucune n'est comprise, seule la premiere
     couche s'applique — on retombe exactement sur le comportement d'avant,
     jamais sur un carre blanc. */
  -webkit-mask-image: url("/img/symbole-provolu.webp"), url("/img/symbole-provolu.webp"), url("/img/symbole-provolu.webp");
          mask-image: url("/img/symbole-provolu.webp"), url("/img/symbole-provolu.webp"), url("/img/symbole-provolu.webp");
  -webkit-mask-size: contain, contain, contain;
          mask-size: contain, contain, contain;
  -webkit-mask-repeat: no-repeat, no-repeat, no-repeat;
          mask-repeat: no-repeat, no-repeat, no-repeat;
  -webkit-mask-position: center, center, center;
          mask-position: center, center, center;
  -webkit-mask-composite: source-in, source-in, source-in;
          mask-composite: intersect, intersect, intersect;
}
/* UN SEUL passage, deux fois plus lent qu'avant (le balayage dure ~1 s au
   lieu de 0,5 s) et il n'arrive qu'une fois par cycle — plus de doublon. */
html.anim .reflet-p::after { animation: reflet-coeur 7.2s ease-in-out infinite; }
@keyframes reflet-coeur {
  0% { opacity: 0; background-position: 120% 0; }
  4% { opacity: 1; }
  14% { opacity: 0; background-position: -40% 0; }
  100% { opacity: 0; background-position: -40% 0; }
}

/* Le portail, caché dans le coin noir. */
/* Au-DESSUS de la porte : le portail doit rester atteignable dès
   l'accueil, sans avoir à défiler ni à traverser l'expérience. */
.coin-secret {
  position: fixed;
  top: 0; right: 0;
  width: 130px; height: 90px;
  z-index: 66;
  background: none; border: 0;
  color: transparent;
  font: inherit; font-family: var(--mono);
  font-size: 0.68rem; letter-spacing: 0.18em; text-transform: uppercase;
  display: flex; align-items: center; justify-content: center;
  transition: color 0.5s ease;
}
/* AU SURVOL le libelle s'efface (le portail se revele autrement) — mais au
   CLAVIER il doit se voir : c'etait le seul acces au portail, sans aucun
   indicateur de focus (2026-08-25, audit lea — WCAG 2.4.7 / 2.4.11). */
.coin-secret:hover { color: transparent; outline: none; }
.coin-secret:focus-visible {
  color: var(--text);
  outline: 2px solid var(--accent-clair);
  outline-offset: 3px;
  border-radius: 6px;
}
.portail-surgi {
  position: fixed;
  top: 1rem; right: 1.2rem;
  z-index: 67;
  padding: 0.7rem 1.3rem;
  border: 1px solid rgba(168, 130, 255, 0.6);
  border-radius: 999px;
  background: rgba(6, 3, 11, 0.9);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  color: var(--text); text-decoration: none;
  font-family: var(--mono); font-size: 0.7rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  opacity: 0; transform: translateY(-8px) scale(0.96);
  pointer-events: none;
  transition: opacity 0.6s ease, transform 0.6s var(--vite);
}
.portail-surgi.la { opacity: 1; transform: none; pointer-events: auto; }

/* ---------- vocabulaire ---------- */

/* `.tag` et `.tag--accent` vivent dans styles.css depuis le 2026-09-14 :
   /contact/ les utilise cinq fois et ne charge pas cette feuille (le meme
   defaut que le bandeau de /ancien/, releve par lea). */
/* LES DEUX EN-TETES DEVENUES <h2> GARDENT LE RENDU DE `.tag` — 2026-08-31.
   Le correctif d'accessibilite (« Ce qu'on fait » et « Realisations » etaient
   les seules sections sans titre) avait ete annonce comme invisible. Il ne
   l'etait pas : `.section h2` de styles.css (0,1,1) bat `.tag` (0,1,0) ET
   passe en dernier, donc le titre est sorti a 25,6 px / 700 / 32 px de marge
   au lieu de 11,52 px / 400 / 0. Constate a l'ecran, pas deduit.
   `.entete h2.tag` (0,2,1) le remet exactement ou il etait. La lecon du
   depot, une fois de plus : « fait » veut dire constate a l'execution. */
/* `.entete h2.tag` : dans styles.css depuis le 2026-09-14 (l'accueil EN l'utilise). */

/* La page respire : beaucoup d'air entre les sections. */
.section {
  position: relative;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(10rem, 28vh, 22rem) clamp(1.25rem, 3.5vw, 2.5rem);
}
/* LA PAGE BASSE RESPIRE MOINS (14 sept., lea, julien ; Sebastien : « la page
   semble longue ») : un seul pas, celui de styles.css. Les plaques de l'intro
   gardent leurs 28vh. */
.vraie .section { padding: var(--pas) clamp(1.25rem, 3.5vw, 2.5rem); }
.vraie .respire-noir { height: 20vh; }
/* `.entete` : dans styles.css depuis le 2026-09-14 (l'accueil EN l'utilise). */

/* ---------- héros ---------- */

.hero {
  position: relative;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 6rem clamp(1.25rem, 3.5vw, 2.5rem) 0;
  max-width: none;
  overflow: hidden;
}
.hero-corps { max-width: 1400px; margin: 0 auto; width: 100%; position: relative; }
/* LE HERO DE LA VRAIE PAGE N'EST PAS CELUI DE L'INTRO (2026-08-25).
   Le .hero ci-dessus (flex colonne, 100vh) sert la PLAQUE #haut ; sur
   #v-haut, son align-items: stretch etirait le bouton « Nous contacter »
   sur toute la largeur — Sebastien : « il devrait etre plus petit, plus
   joli, comme sur la version qui est publiee ». On rend a la vraie page le
   modele de production : bloc simple, centre, le .cta redevient une pilule
   a sa taille (styles.css fait le reste). */
.vraie .hero {
  display: block;
  min-height: 0;
  overflow: visible;
}
.hero .surtitre { display: block; margin-bottom: 1.4rem; }
/* `.titre-plaque` = l'ancien titre de l'intro, retrograde de h1 en p le
   2026-08-25 (un seul h1 par document). Il partage tous les styles du h1 :
   chaque selecteur qui visait `.hero h1` le vise aussi, pour que l'apparence
   ne bouge pas d'un pixel. */
.hero h1, .hero .titre-plaque {
  font-size: clamp(3rem, 9vw, 8.5rem);
  line-height: 0.92;
  letter-spacing: -0.04em;
  font-weight: 800;
  color: #ffffff;
}
.hero h1 .l, .hero .titre-plaque .l { display: block; }
.hero h1 .l2, .hero .titre-plaque .l2 { padding-left: clamp(0px, 8vw, 150px); }
.hero h1 .l3, .hero .titre-plaque .l3 { padding-left: clamp(0px, 3vw, 60px); color: var(--accent); }

/* la demi-page de vide : la page respire avant la marque */
/* LES VIDES ENTRE LES SECTIONS, COUPES DE MOITIE.
   Consigne de Sebastien, 2026-08-23 : « les espaces noirs entre les sections
   comme "introduites avec soin" devraient etre coupes de 50 % ».
   55vh -> 27.5vh et 85vh -> 42.5vh. Ce sont les quatre blocs .respire /
   .respire-noir du HTML — les seuls vides VOLONTAIRES de la page. Le
   rembourrage des sections elles-memes (28vh en haut et en bas) n'est pas
   touche : ce n'est pas « entre » les sections, c'est dedans. */
.respire { height: 27.5vh; }
/* le noir profond : des phases où l'on ne voit presque rien */
/* Les zones de respiration noires : elles ne portent PLUS de fond opaque
   ni de z-index. Elles masquaient le canvas des étoiles (fixe, z-index -1)
   sur trois grandes bandes de la page. Le noir vient déjà du fond du body. */
.respire-noir { height: 42.5vh; position: relative; }

/* PROVOLU, seul, au centre d'un écran noir plein — vraiment noir, comme
   les zones .respire-noir qui l'entourent : sans ce fond propre, le halo
   de la page (body::before) traversait par les coins. */
.geant-scene {
  min-height: 100vh; min-height: 100svh;
  max-width: none;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(4rem, 10vh, 8rem) 1rem;
  /* PAS de fond opaque ici : le canvas des étoiles est en position fixe
     derrière la page (z-index -1). Un fond noir plein le masquait — les
     étoiles disparaissaient sur toute la scène PROVOLU. */
  position: relative;
}
.geant {
  display: block; width: 100%;
  font-weight: 800;
  font-size: clamp(5rem, 18vw, 16rem);
  line-height: 0.78;
  letter-spacing: -0.035em;
  text-align: center;
  white-space: nowrap;
  background: linear-gradient(180deg, #ffffff 18%, #b794f6 58%, rgba(109, 40, 217, 0.22) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  pointer-events: none;
  /* L'échelle est pilotée par le défilement (JS, fonction geant) — minuscule
     au centre, elle grossit jusqu'à sa taille pleine. transform-origin au
     centre pour qu'elle grandisse SUR PLACE, pas depuis un coin. */
  transform-origin: 50% 50%;
}
/* La promotion en couche composee ne dure QUE le temps du zoom. A pleine
   page, PROVOLU est la plus grande surface de la page : la garder promue
   alors que plus rien ne bouge occupe de la memoire graphique pour rien —
   et sur un portable, c'est la couche la plus chere de la page. */
.geant.zoome { will-change: transform; }

/* ---------- la bande : capricieuse, avec ses motifs ---------- */

.bande {
  overflow: hidden;
  padding: 1.5rem 0;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  background:
    linear-gradient(90deg, rgba(168, 130, 255, 0.09), rgba(168, 130, 255, 0.02) 40%, rgba(192, 132, 252, 0.07));
}
.bande .piste { display: flex; align-items: center; width: max-content; }
.bande span {
  font-size: clamp(1.4rem, 3.2vw, 2.6rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  padding: 0.15em 0.55em;
  margin-right: 1.6rem;
  white-space: nowrap;
  border-radius: 10px;
}
/* sept motifs, pour que rien ne se répète à l'identique */
.bande .m1 { color: var(--text); }
.bande .m2 { color: transparent; -webkit-text-stroke: 1px var(--accent-clair); }
.bande .m3 { color: #0b0714; background: var(--accent-clair); }
.bande .m4 { color: var(--muted); font-weight: 400; font-style: italic; }
.bande .m5 { color: var(--text); background: rgba(168, 130, 255, 0.16);
  border: 1px solid rgba(168, 130, 255, 0.4); }
.bande .m6 { color: transparent; -webkit-text-stroke: 1px rgba(157, 151, 180, 0.5); }
.bande .m7 { color: var(--accent-clair); text-decoration: underline;
  text-underline-offset: 8px; text-decoration-thickness: 2px; }
/* TROIS PILIERS, LE RESTE EN SECOND PLAN — Sebastien, 2026-08-31 :
   « que trois mots deviennent clairement les piliers : Comprendre ·
   Simplifier · Livrer. Les mots comme clair, durable, utile, precis peuvent
   continuer a voyager comme elements secondaires. »
   LE GESTE EST MINIMAL, ET C'EST VOULU : on ne touche ni aux sept motifs
   graphiques (m1..m7), ni aux mouvements, ni aux vides de la bande — tout
   ce qui la rend vivante reste. On ajoute UNE difference d'echelle et
   d'opacite. Un pilier est plus grand et pleinement present ; un mot
   secondaire est plus petit et plus efface, donc il passe sans reclamer.
   `em` plutot que `rem` : la taille suit le clamp de `.bande span`, donc
   le rapport tient du telephone au grand ecran sans second clamp. */
.bande .pilier { font-size: 1.16em; opacity: 1; }
.bande .second { font-size: 0.78em; opacity: 0.5; font-weight: 600; }
/* le mot en pastille pleine (m3) n'a pas besoin d'etre grossi en plus :
   son fond le porte deja. On le ramene au rang des autres piliers. */
.bande .m3.pilier { font-size: 1.04em; }

.bande .pt {
  width: 9px; height: 9px; border-radius: 999px;
  background: var(--accent);
  margin-right: 1.6rem;
  flex: none;
  box-shadow: 0 0 14px rgba(168, 85, 247, 0.9);
}

/* Elle accélère, bloque, recule, repart. Jamais régulière. */
/* LA BANDE PASSE, ET TROIS FOIS PLUS VITE — consigne de Sebastien,
   2026-08-23 : « la bande de message doit passer et doit etre trois fois
   plus rapide. Les actions doivent etre tres rapides. »
   44 s / 3 = 14,7 s pour le defilement. Et « les actions » — les mots qui
   scintillent, celui qui s'efface, le point qui bat — sont divises par
   trois eux aussi : une bande rapide avec des accents lents se serait
   dedoublee en deux rythmes qui ne se parlent plus. */
html.anim .bande .piste { animation: construction 14.7s cubic-bezier(0.45, 0, 0.55, 1) infinite; }
.bande:hover .piste { animation-play-state: paused; }
@keyframes construction {
  0%   { transform: translateX(0); }
  9%   { transform: translateX(-8%); }      /* départ rapide */
  13%  { transform: translateX(-8.4%); }    /* elle bloque */
  17%  { transform: translateX(-6.5%); }    /* et recule */
  30%  { transform: translateX(-19%); }     /* repart fort */
  34%  { transform: translateX(-19.2%); }
  46%  { transform: translateX(-24%); }     /* long ralenti */
  52%  { transform: translateX(-26%); }
  61%  { transform: translateX(-38%); }     /* nouvelle poussée */
  65%  { transform: translateX(-36.5%); }   /* petit retour */
  80%  { transform: translateX(-45%); }
  86%  { transform: translateX(-45.4%); }
  100% { transform: translateX(-50%); }
}
/* certains mots scintillent, d'autres s'effacent un instant */
html.anim .bande .m1 { animation: scintille-mot 3.7s ease-in-out infinite; }
html.anim .bande .m3 { animation: scintille-mot 3s ease-in-out infinite 0.5s; }
html.anim .bande .m7 { animation: scintille-mot 4.3s ease-in-out infinite 1s; }
@keyframes scintille-mot {
  0%, 88%, 100% { opacity: 1; }
  91% { opacity: 0.25; }
  93% { opacity: 1; }
  95% { opacity: 0.4; }
}
html.anim .bande .m4 { animation: efface-mot 5.7s ease-in-out infinite 0.7s; }
html.anim .bande .m6 { animation: efface-mot 21s ease-in-out infinite 6s; }
@keyframes efface-mot {
  0%, 70%, 100% { opacity: 1; }
  78%, 88% { opacity: 0; }
}
html.anim .bande .pt { animation: pulse-pt-bande 2s ease-in-out infinite; }
@keyframes pulse-pt-bande {
  0%, 100% { transform: scale(1); opacity: 0.9; }
  50% { transform: scale(1.75); opacity: 1; }
}

/* ---------- la démarche ---------- */

.manifeste h2 {
  font-size: clamp(2.2rem, 6vw, 5rem);
  line-height: 0.98;
  letter-spacing: -0.035em;
  font-weight: 800;
  max-width: 15ch;
}
.manifeste h2 em { font-style: normal; color: var(--accent); }
.manifeste .prose { margin-top: 2.2rem; max-width: 50ch; color: var(--muted); font-size: 1.08rem; }

/* ---------- la simplification ---------- */

.simplification { text-align: center; }
.particules-boite { position: relative; }
.particules-boite canvas { display: block; width: 100%; height: auto; }
.titre-reel {
  /* « Ca augmente la grosseur du texte Reduire au necessaire » —
     Sebastien, 2026-08-23. 6vw -> 7.2vw, 5rem -> 6rem : +20 %. */
  font-size: clamp(2.9rem, 7.2vw, 6rem);
  line-height: 1.04; letter-spacing: -0.03em; font-weight: 800;
  background: linear-gradient(180deg, #ffffff 30%, #cbb6f5 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.particules-boite.actif .titre-reel {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
/* « La phrase doit apparaitre un peu plus haut, sous le texte Reduire au
   necessaire » — Sebastien, 2026-08-23. 1,4rem -> 0,2rem, et une marge
   negative pour rattraper le blanc que le canvas laisse sous les lettres. */
.simplification .sous { color: var(--muted); font-size: 1.1rem; margin-top: -1.6rem; }

.voie { position: relative; margin-top: clamp(4rem, 10vh, 7rem); }
/* la barre a une graduation, pas une teinte plate */
.ligne {
  position: relative; height: 3px; border-radius: 999px;
  background: linear-gradient(90deg,
    rgba(109, 40, 217, 0.25) 0%, #6d28d9 14%, #8b5cf6 34%,
    var(--accent) 52%, #c084fc 72%, #ddc4ff 88%, rgba(233, 222, 252, 0.3) 100%);
  transform-origin: left;
}
html.anim .ligne { transform: scaleX(0); transition: transform 1.4s var(--vite) 0.1s; }
html.anim .scene.joue .ligne { transform: scaleX(1); }

.etapes {
  list-style: none;
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.2rem, 3vw, 2.5rem);
  margin-top: 2.6rem;
}
.etapes li { text-align: center; position: relative; }
.etapes .noeud {
  width: 15px; height: 15px; border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 14px rgba(168, 85, 247, 0.5);
  margin: -3.05rem auto 2.2rem;
  transition: box-shadow 0.4s ease, transform 0.4s ease, background 0.4s ease;
}
.etapes li.touche .noeud {
  background: var(--glace);
  box-shadow: 0 0 34px rgba(188, 216, 255, 1);
  transform: scale(1.45);
}
/* les chiffres grossissent, chacun à sa façon */
.etapes .no {
  font-family: var(--mono);
  font-size: 0.68rem; letter-spacing: 0.2em;
  color: var(--accent-clair);
  display: block; margin-bottom: 0.6rem;
  transition: transform 0.8s var(--vite), color 0.6s ease, opacity 0.6s ease;
}
.etapes li.touche .no { color: #ffffff; }
.etapes li:nth-child(1).touche .no { transform: scale(2.4) translateX(-14px); }
.etapes li:nth-child(2).touche .no { transform: scale(2.4) rotate(9deg) translateX(12px); }
.etapes li:nth-child(3).touche .no { transform: scale(2.6) translateY(-26px); }
.etapes h3 { font-size: 1.35rem; letter-spacing: -0.015em; margin-bottom: 0.5rem; }
.etapes p { font-size: 0.95rem; color: var(--muted); max-width: 30ch; margin: 0 auto; }

/* ---------- ce qu'on fait ---------- */

.cap {
  display: flex; align-items: center;
  gap: clamp(2rem, 6vw, 6rem);
  /* « Reduis les espaces aussi entre les lignes » — 12vh -> 7vh. */
  padding: clamp(2.4rem, 7vh, 4.8rem) 0;
}
/* Le trait qui sépare deux capacités : le glaçon s'y pose, et il
   s'électrifie au contact — une décharge, puis le givre. */
.cap + .cap { border-top: 1px solid var(--hairline); position: relative; }
.cap .fil-electrique {
  position: absolute;
  left: 0; right: 0; top: -1px;
  height: 2px;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(90deg, transparent, var(--glace) 30%, #ffffff 50%, var(--glace) 70%, transparent);
}
.cap.choc .fil-electrique { animation: decharge 1.1s ease-out 1 both; }
@keyframes decharge {
  0% { opacity: 0; transform: scaleX(0.1); filter: blur(0); }
  8% { opacity: 1; transform: scaleX(1); box-shadow: 0 0 22px 3px rgba(200, 228, 255, 0.9); }
  16% { opacity: 0.35; }
  24% { opacity: 1; box-shadow: 0 0 30px 4px rgba(220, 240, 255, 1); }
  40% { opacity: 0.8; box-shadow: 0 0 14px 2px rgba(188, 216, 255, 0.7); }
  100% { opacity: 0; transform: scaleX(1); box-shadow: none; }
}
/* le givre qui reste une seconde sur le trait */
.cap.choc { border-top-color: rgba(188, 216, 255, 0.85); transition: border-top-color 1.4s ease; }
.cap.droite { flex-direction: row-reverse; }
.cap .marque { flex: none; width: clamp(190px, 23vw, 310px); }
.cap .marque svg { width: 100%; height: auto; stroke: var(--accent-clair);
  filter: drop-shadow(0 0 38px rgba(168, 85, 247, 0.45)); }

/* ---------- LA LIGNE QUI S'ELECTRIFIE ET L'ICONE QUI S'ALLUME ----------
   Sebastien, 2026-08-23 : « quand ca touche a la ligne, on a un bruit
   d'electrification [...] la ligne doit faire une electrification, un petit
   ziz, ziz, [...] puis le halo qui se cree sur la ligne » et « je veux qu'il
   ait touche aussi aux icones pour que les icones s'allument ». */
.cap .halo-ligne {
  position: absolute;
  top: -1px; height: 1px;
  width: 26%;
  pointer-events: none;
  opacity: 0;
  border-radius: 50%;
  box-shadow: 0 0 22px 7px rgba(188, 216, 255, 0.55),
              0 0 60px 18px rgba(168, 85, 247, 0.35);
}
.cap.choc .halo-ligne { animation: halo-ligne 1.25s ease-out 1 both; }
@keyframes halo-ligne {
  0%   { opacity: 0;    transform: scaleX(0.25); }
  12%  { opacity: 1;    transform: scaleX(1); }
  26%  { opacity: 0.35; }
  38%  { opacity: 0.95; }                      /* la seconde reprise du « ziz » */
  100% { opacity: 0;    transform: scaleX(1.5); }
}

/* L'ICONE S'ALLUME QUAND LE GLACON PASSE. Le halo se fait DANS l'icone :
   `drop-shadow` epouse le trace du SVG, il ne halo pas un rectangle. */
.cap .marque svg { transition: filter 0.5s ease, stroke 0.5s ease; }
.cap.allumee .marque svg {
  stroke: #dbe9ff;
  filter: drop-shadow(0 0 14px rgba(219, 233, 255, 0.9))
          drop-shadow(0 0 46px rgba(168, 85, 247, 0.75))
          drop-shadow(0 0 90px rgba(124, 58, 237, 0.4));
}
@media (prefers-reduced-motion: reduce) {
  .cap.choc .halo-ligne { animation: none; }
}

.cap .texte { max-width: 52ch; }
.cap .texte .tag { display: block; margin-bottom: 0.8rem; }
.cap h3 { font-size: clamp(1.7rem, 3.4vw, 2.7rem); line-height: 1.1;
  letter-spacing: -0.02em; margin-bottom: 0.9rem; }
.cap p { color: var(--muted); font-size: 1.05rem; }

html.anim .cap { opacity: 0; transition: opacity 0.9s ease, transform 0.9s var(--vite); }
html.anim .cap.gauche { transform: translateX(-70px); }
html.anim .cap.droite { transform: translateX(70px); }
/* L'icône ne se remplit QUE lorsque son bloc atteint le milieu de l'écran */
html.anim .cap .marque { transform: scale(0.35); opacity: 0;
  transition: transform 1.15s cubic-bezier(0.34, 1.45, 0.44, 1), opacity 0.7s ease; }
html.anim .scene.joue .cap { opacity: 1; transform: none; }
/* « .cap.centree » est RETIRE (2026-08-25) : c'etait le mecanisme de
   l'ancienne plaque #faire (le glacon posait .centree sur .cap au fil de
   sa choregraphie) — supprime ce soir avec la plaque, S1. Le conteneur du
   .cap (titre + texte) se revele bien via .scene.joue, mais l'icone,
   elle, attendait EXCLUSIVEMENT .centree : sur la vraie page (#v-faire),
   qui defile sans glacon (V7), rien ne l'a jamais posee. Les trois icones
   sont restees a opacity 0 depuis la scission du 24 aout (commit 89d7b41)
   qui a cree #v-faire — « environ une journee », constate par Sebastien.
   Meme declencheur que le conteneur : .scene.joue, deja pose par
   l'IntersectionObserver de vraiePageVivante(). */
html.anim .scene.joue .cap .marque { transform: none; opacity: 1; }
html.anim .scene.joue .cap:nth-of-type(2) { transition-delay: 0.12s; }
html.anim .scene.joue .cap:nth-of-type(3) { transition-delay: 0.24s; }

/* ---------- réalisations ---------- */

.carrousel { position: relative; height: clamp(300px, 46vh, 400px); touch-action: pan-y; }
.travail {
  position: absolute; left: 50%; top: 50%;
  width: min(460px, 84vw);
  overflow: hidden; text-align: left;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 2rem 1.8rem 2.2rem;
  color: inherit; font: inherit; cursor: pointer;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.2);
  transition: transform 0.75s var(--vite), opacity 0.6s ease,
    border-color 0.5s ease, background 0.5s ease, box-shadow 0.5s ease;
}
.travail::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, #6d28d9, var(--accent), transparent 85%);
  opacity: 0.85;
  z-index: 1;   /* la barre reste AU-DESSUS du visuel qui monte jusqu'au bord */
}
/* LE VISUEL DE LA CARTE (2026-08-31) : il mange le haut — les marges
   negatives annulent le padding de .travail (2rem / 1.8rem), l'image touche
   les trois bords. `object-fit: cover` : les trois visuels n'ont pas tout a
   fait le meme ratio, la carte, elle, garde une seule hauteur. */
.travail .carte-visuel {
  display: block;
  margin: -2rem -1.8rem 1.1rem;
  height: clamp(130px, 22vh, 200px);
  overflow: hidden;
}
.travail .carte-visuel img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
}
.travail.centre {
  border-color: rgba(168, 130, 255, 0.5);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: 0 22px 70px rgba(109, 40, 217, 0.3);
}
.travail .tag { display: block; margin-bottom: 0.7rem; }
.travail h3 { font-size: 1.35rem; letter-spacing: -0.015em; margin-bottom: 0.6rem; }
.travail p { color: var(--muted); font-size: 0.95rem; max-width: 34ch; }
.travail .ouvre {
  display: inline-block; margin-top: 1.2rem;
  font-family: var(--mono); font-size: 0.68rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent-clair); opacity: 0;
  transition: opacity 0.4s ease;
}
.travail.centre .ouvre { opacity: 1; }
.travail .icone {
  position: absolute; right: 0.4rem; bottom: 0.2rem;
  width: 120px; opacity: 0;
  transform: scale(0.6) rotate(-8deg);
  transition: opacity 0.7s ease 0.1s, transform 0.7s cubic-bezier(0.34, 1.4, 0.44, 1) 0.1s;
  pointer-events: none;
}
.travail .icone svg { width: 100%; height: auto; stroke: var(--accent-clair); fill: none; stroke-width: 2; }
.travail.centre .icone { opacity: 0.24; transform: none; }

/* LES CARTES DE CÔTÉ : on en montre un bon morceau — c'est ce qui dit que
   le carrousel continue — mais leur CONTOUR s'efface presque. Un cadre net
   de chaque côté volait l'attention de la carte du centre. */
.travail.cote {
  border-color: rgba(255, 255, 255, 0.06);
  box-shadow: none;
}
.travail.cote::before { opacity: 0.16; }
.travail.cote .icone { opacity: 0; }

/* La surbrillance est BLANCHE et franche : elle doit se voir. */
.travail.givre {
  border-color: #ffffff;
  background: linear-gradient(150deg, rgba(220, 238, 255, 0.30), rgba(255, 255, 255, 0.09) 60%);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85),
    inset 0 0 60px rgba(220, 240, 255, 0.28),
    0 26px 90px rgba(180, 215, 255, 0.5);
}
.travail.givre h3 { color: #ffffff; }
.travail.givre p, .travail.givre .tag { color: #dceaff; }
.travail.givre::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(115deg, transparent 28%, rgba(255, 255, 255, 0.85) 50%, transparent 72%);
  background-size: 280% 100%;
  animation: reflet-carte 1.5s ease 1 both;
}
@keyframes reflet-carte {
  0% { background-position: 130% 0; opacity: 0; }
  16% { opacity: 1; }
  100% { background-position: -50% 0; opacity: 0; }
}

.fleches { display: flex; align-items: center; justify-content: center; gap: 1.1rem; margin-top: 2.6rem; }
.fleches button {
  font: inherit; cursor: pointer; background: none; color: var(--accent-clair);
  display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px;
  border: 1px solid rgba(168, 130, 255, 0.6);
  border-radius: 999px;
  transition: background 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}
.fleches button:hover { background: rgba(168, 130, 255, 0.16); border-color: var(--accent-clair); }
.fleches button svg { width: 16px; height: 16px; stroke: currentColor; }
/* le glaçon l'actionne : elle s'enfonce ET s'allume, halo compris */
.fleches button.presse {
  transform: scale(0.84);
  background: #ffffff;
  border-color: #ffffff;
  color: #0b0714;
  box-shadow: 0 0 0 10px rgba(255, 255, 255, 0.18), 0 0 34px 6px rgba(220, 240, 255, 0.8);
}
.fleches button.appelle { animation: clignote 1.1s ease-in-out 3; }
@keyframes clignote {
  0%, 100% { box-shadow: 0 0 0 0 rgba(192, 132, 252, 0); border-color: rgba(168, 130, 255, 0.6); }
  50% { box-shadow: 0 0 0 8px rgba(192, 132, 252, 0); border-color: #ffffff;
        background: rgba(192, 132, 252, 0.3); }
}

.biblio { text-align: center; margin-top: 3rem; position: relative; }
.biblio a { text-decoration: none; }
/* Le bouton sous le carrousel de la vraie page (2026-08-25) — « ça va donner
   envie de cliquer pour voir la page avec les différents projets ». */
.voir-plus { text-align: center; margin-top: 2.6rem; }

/* Le trou de sortie : FIXE, au centre de l'écran, entre la bibliothèque et
   « Partons du vrai besoin ». C'est là que le glaçon disparaît. */
.trou-sortie {
  position: fixed;
  left: 50%; top: 46%;
  width: clamp(180px, 20vw, 300px);
  transform: translate(-50%, -50%) scale(0.5);
  opacity: 0;
  pointer-events: none;
  z-index: 36;
  transition: opacity 0.6s ease, transform 0.8s var(--vite);
}
.trou-sortie.la { opacity: 0.92; transform: translate(-50%, -50%) scale(1); }
.trou-sortie .gouffre {
  position: absolute; left: 11%; right: 11%; top: 16%; bottom: 26%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 42%, #010004 46%, rgba(4, 2, 10, 0.85) 76%, transparent);
  z-index: 1;
}
.trou-sortie img { position: relative; z-index: 3; width: 100%; height: auto; display: block; }

.voile-noir {
  position: fixed; inset: 0; z-index: 33;
  background: #000000;
  opacity: 0; pointer-events: none;
  transition: opacity 0.7s ease;
}
.voile-noir.la { opacity: 1; }

/* ---------- modales ---------- */

dialog.modale {
  margin: auto;
  max-width: min(880px, calc(100vw - 2.5rem));
  background: #0b0714; color: var(--text);
  border: 1px solid rgba(168, 130, 255, 0.35);
  border-radius: 22px;
  padding: clamp(1.6rem, 4vw, 2.8rem);
}
dialog.modale::backdrop { background: rgba(3, 1, 8, 0.8);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.modale .tag { display: block; margin-bottom: 0.6rem; }
.modale h3 { font-size: clamp(1.5rem, 3vw, 2.2rem); letter-spacing: -0.02em; margin-bottom: 1.6rem; }
.modale .temps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.modale .temps article {
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 14px; padding: 1.3rem;
}
.modale .temps article:nth-child(2) { border-color: rgba(168, 130, 255, 0.35); }
.modale .etiquette {
  font-family: var(--mono); font-size: 0.62rem;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--accent-clair); display: block; margin-bottom: 0.6rem;
}
.modale .temps p { font-size: 0.92rem; color: var(--muted); }
.modale .pied-modale { display: flex; justify-content: space-between; align-items: center;
  margin-top: 1.8rem; gap: 1rem; flex-wrap: wrap; }
.modale .fermer {
  background: none; border: 1px solid var(--hairline); border-radius: 999px;
  color: var(--muted); font: inherit; font-family: var(--mono);
  font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
  padding: 0.6rem 1.2rem; cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.modale .fermer:hover { color: var(--text); border-color: var(--accent-clair); }

/* ---------- le final ---------- */

/* LE BAS DE PAGE : vraiment noir. Plus de halo mauve, plus d'étoiles —
   pour que le fond de la vidéo se fonde sans qu'une couture paraisse. */
.final {
  text-align: center;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding-bottom: clamp(4rem, 8vh, 7rem);
}
.final::before {
  content: "";
  position: absolute;
  left: 50%; top: 0;
  width: 100vw; height: 100%;
  transform: translateX(-50%);
  background: linear-gradient(180deg, transparent, #000000 26%, #000000);
  pointer-events: none;
  z-index: -1;
}
/* le noir gagne aussi le fond de page et éteint les étoiles */
body.au-fond::before { opacity: 0; transition: opacity 1.2s ease; }
body.au-fond .galaxie { opacity: 0; transition: opacity 1.2s ease; }
body.au-fond { background: #000000; }
.final h2 {
  font-size: clamp(2.6rem, 7vw, 6rem);
  line-height: 1;
  letter-spacing: -0.035em;
  font-weight: 800;
}
.final h2 em { font-style: normal; color: var(--accent); }
.final .sous { margin: 1.8rem auto 0; color: var(--muted); font-size: 1.1rem; max-width: 44ch; }
/* LES DEUX COLONNES DE LA FIN (2026-08-25) — voir prototype/accueil-optimale
   pour la citation complete. */
.final-corps {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(3rem, 7vw, 6rem);
  margin-top: clamp(3rem, 7vh, 5rem);
  text-align: left;
}
.final-a-propos { flex: 1 1 46ch; max-width: 52ch; }
.final-a-propos .prose { color: var(--muted); font-size: 1.05rem; line-height: 1.65; margin: 0; }
.final-a-propos .prose + .prose { margin-top: 1.1rem; }
.final-contact { flex: 0 1 auto; text-align: center; }
.final-contact .scene-video { min-height: 0; margin: 0 0 1.6rem; width: clamp(140px, 15vw, 200px); }
@media (max-width: 860px) {
  .final-corps { flex-direction: column; text-align: center; gap: 2.4rem; }
  .final-a-propos { text-align: center; max-width: 44ch; }
  /* « CE QU'ON FAIT » S'EMPILE SOUS 860 px — 2026-08-31, validation mobile.
     `.cap` etait en `display: flex` SANS AUCUNE bascule responsive : l'icone
     et le texte restaient cote a cote a toute largeur, et le texte des trois
     services etait COUPE A DROITE. Constate a l'ecran a 426 px :
     « Intelligence artificielle & automatisa… ». Six media queries a 860 px
     existaient deja dans ce fichier ; aucune ne touchait `.cap`.
     `.cap.droite` doit etre remis a `column` explicitement : sans lui, son
     `row-reverse` devient `column-reverse` et l'icone passe SOUS le texte
     pour un bloc sur deux. */
  .cap, .cap.droite {
    flex-direction: column;
    align-items: flex-start;
    gap: clamp(1.2rem, 3vh, 2rem);
  }
  /* L'entree laterale de 70 px poussait la carte hors de l'ecran etroit :
     sur petit ecran, elle monte au lieu de glisser. */
  html.anim .cap.gauche,
  html.anim .cap.droite { transform: translateY(40px); }
}
/* LA ZONE DE LA VIDÉO : un bloc noir à elle seule. Rien ne la traverse,
   rien ne la chevauche — c'est le dernier plan de l'expérience. */
.scene-video {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  width: 100%;
  min-height: clamp(320px, 42vh, 460px);
  margin: clamp(2.5rem, 6vh, 4.5rem) 0 clamp(3.5rem, 8vh, 6rem);
}

.final .courriel {
  display: inline-block; margin-top: 0;
  font-size: clamp(1rem, 2vw, 1.4rem);
  font-family: var(--mono); letter-spacing: 0.08em;
  color: var(--text); text-decoration: none;
  border-bottom: 1px solid rgba(168, 130, 255, 0.5);
  padding-bottom: 0.3rem;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.final .courriel:hover { color: var(--accent-clair); border-color: var(--accent-clair); }

.final .mot-fin {
  margin: 1.6rem auto 0;
  color: var(--sourd);
  font-size: 0.98rem;
  max-width: 40ch;
}
/* etendu a #v-haut le 2026-08-25 : meme bouton « Nous contacter » qu'au
   pied de la vraie page, repris en haut pour matcher la version en ligne. */
.final .contact,
#v-haut .contact {
  display: inline-block; margin-top: 1.5rem;
  padding: 0.85rem 1.9rem;
  border-radius: 999px;
  background: linear-gradient(135deg, #6d28d9, #9333ea);
  color: #ffffff; text-decoration: none;
  font-family: var(--mono); font-size: 0.74rem;
  letter-spacing: 0.18em; text-transform: uppercase;
  box-shadow: 0 14px 40px rgba(109, 40, 217, 0.45);
  transition: transform 0.25s var(--vite), box-shadow 0.25s ease, filter 0.25s ease;
}
.final .contact:hover {
  transform: translateY(-2px);
  filter: brightness(1.12);
  box-shadow: 0 18px 52px rgba(147, 51, 234, 0.55);
}

/* FAIRE REVIVRE LE CUBE — au pied de page, discret.
   « Redécouvrir » ne disait pas ce que ça fait. Une fois en bas, le glaçon
   a disparu dans le trou : ce bouton le ramène, et nous ramène en haut.
   Il n'apparaît QUE lorsque tout est terminé — avant, il ne veut rien dire. */
.revivre {
  display: inline-flex; align-items: center; gap: 0.7rem;
  background: none; border: 0; padding: 0.4rem 0;
  color: var(--sourd);
  font: inherit; font-family: var(--mono);
  font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase;
  cursor: pointer;
  opacity: 0; pointer-events: none;
  transform: translateY(8px);
  transition: opacity 1.4s ease, transform 1.4s var(--vite), color 0.25s ease;
}
.revivre.la { opacity: 1; pointer-events: auto; transform: none; }
.revivre img {
  width: 36px; height: auto; display: block;
  filter: drop-shadow(0 4px 14px rgba(168, 85, 247, 0.45));
  transition: transform 0.4s var(--vite), filter 0.4s ease;
}
.revivre:hover { color: var(--text); }
.revivre:hover img {
  transform: translateY(-3px) rotate(-6deg);
  filter: drop-shadow(0 8px 22px rgba(192, 132, 252, 0.75));
}

/* LE BLOC FINAL : il ne flotte plus par-dessus la page. Il vit DANS sa
   propre zone noire, au centre, et rien ne le traverse. */
.trou-final {
  position: relative;
  width: clamp(200px, 24vw, 320px);
  opacity: 0.92;
}
.trou-final .gouffre {
  position: absolute; left: 11%; right: 11%; top: 14%; bottom: 24%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 40%, #010004 45%, rgba(4, 2, 10, 0.85) 75%, transparent);
  z-index: 1;
}
.trou-final .anneau { position: relative; z-index: 3; width: 100%; height: auto; display: block; }
/* la vidéo, agrandie encore : son fond noir se fond dans la page noire */
.trou-final video {
  position: absolute;
  /* 20 % plus petite qu'avant (112 % -> 90 %), et recentrée en conséquence.
     Comme elle rétrécit depuis son coin, son centre descend aussi — ce qui
     va dans le sens demandé : la vidéo un cran plus bas. */
  left: 5%;
  top: -40%;
  width: 90%;
  height: auto;
  z-index: 2;
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 0.6s ease, transform 1s var(--vite);
  mix-blend-mode: screen;
}
.trou-final.fond video { opacity: 1; transform: none; }
/* le logo, PAR-DESSUS la section noire de la vidéo, une fois la fonte finie */
.trou-final .marque-finale {
  position: absolute;
  left: 50%; top: -44%;   /* la grande anse du P remonte */
  width: 46%;
  z-index: 4;
  background: none; border: 0; padding: 0;
  cursor: pointer;
  opacity: 0;
  transform: translate(-50%, 44px) scale(0.6);
  transition: opacity 1.2s ease, transform 1.4s var(--vite);
  filter: drop-shadow(0 0 30px rgba(168, 85, 247, 0.6));
}
.trou-final .marque-finale img { width: 100%; height: auto; display: block; }
.trou-final.revele .marque-finale { opacity: 1; transform: translate(-50%, 0); }

.footer {
  max-width: var(--maxw); margin: 0 auto;
  padding: 1.4rem clamp(1.25rem, 3.5vw, 2.5rem) 2rem;
  border-top: 1px solid var(--hairline);
  display: flex; justify-content: space-between; align-items: center;
  gap: 1rem; flex-wrap: wrap;
}
.footer .tag { flex: 1 1 0; }
.footer .tag:last-child { text-align: right; }
/* Le P discret dans le pied de page (2026-08-25) — « Provolu © 2026 ». */
.pied-marque {
  display: inline-flex; align-items: center; justify-content: flex-end;
  gap: 0.55rem;
}
.pied-marque img { width: 16px; height: auto; display: block; opacity: 0.75; }

/* ---------- la chorégraphie, dans les deux sens ---------- */

html.anim .venir {
  opacity: 0; transform: translateX(-70px);
  transition: opacity 0.7s ease, transform 0.9s var(--vite);
  transition-delay: var(--d, 0s);
}
html.anim .scene.joue .venir { opacity: 1; transform: none; }

/* la troisième ligne arrive de la DROITE : la page se construit en
   alternance, lentement, pas d'un bloc */
html.anim .depuis-droite {
  opacity: 0; transform: translateX(90px);
  transition: opacity 0.7s ease, transform 0.9s var(--vite);
  transition-delay: var(--d, 0s);
}
html.anim .scene.joue .depuis-droite { opacity: 1; transform: none; }

html.anim .up {
  opacity: 0; transform: translateY(26px);
  transition: opacity 0.85s ease, transform 0.85s var(--vite);
  transition-delay: var(--d, 0s);
}
html.anim .scene.joue .up { opacity: 1; transform: none; }

/* ---------- mobile et reduced-motion ---------- */

@media (max-width: 860px) {
  /* PLUS DE MODE REDUIT AU TELEPHONE. C'est la raison d'etre du modele
     plaques (devis du 23 aout, mesure sur why.zero.university) : rien ne
     depend d'une position de defilement, donc RIEN a degrader. La porte,
     le glacon, le carrousel et ses fleches vivent ici aussi — la pile
     verticale du 22 aout etait le repli de la page qui defilait, elle est
     partie avec elle. Seules les tailles se compriment.
     LE COIN DU PORTAIL RESTE, MEME AU DOIGT (Sebastien, 2026-08-23) : sa
     zone de touche grandit pour qu'on la trouve sans viser. */
  .coin-secret { width: 46vw; height: 20vh; max-width: 280px; max-height: 180px; }
  /* le trou reste entier a l'ecran : 66 % + 2 cm depassait le bord droit
     d'un 390 px — on le retient a une demi-largeur du bord (constate au
     telephone le 2026-08-24) */
  .trou { left: min(var(--trou-x), calc(100% - var(--trou-taille) / 2 - 14px)); }
  .hero h1 .l2, .hero h1 .l3,
  .hero .titre-plaque .l2, .hero .titre-plaque .l3 { padding-left: 0; }
  .geant { font-size: 17vw; }
  .modale .temps { grid-template-columns: 1fr; }
  .trou-final { margin: 0 auto; width: min(280px, 70vw); }
}


/* ---------- CSP : plus aucun style en ligne ----------
   La CSP du site est `style-src 'self'` (sans 'unsafe-inline') : un
   attribut style="..." dans le HTML est BLOQUE par le navigateur. Les
   cascades de delais seraient toutes tombees en meme temps, et six liens
   auraient retrouve leur soulignement. Les valeurs vivent donc ici. */
[data-d="8"]  { --d: .08s; }
[data-d="16"] { --d: .16s; }
[data-d="18"] { --d: .18s; }
[data-d="24"] { --d: .24s; }
[data-d="20"] { --d: .2s; }
[data-d="30"] { --d: .3s; }
[data-d="40"] { --d: .4s; }
[data-d="42"] { --d: .42s; }
[data-d="50"] { --d: .5s; }
[data-d="54"] { --d: .54s; }
[data-d="70"] { --d: .7s; }
[data-d="95"] { --d: .95s; }
[data-d="120"] { --d: 1.2s; }
[data-d="140"] { --d: 1.4s; }
[data-d="220"] { --d: 2.2s; }
[data-d="310"] { --d: 3.1s; }

/* ---------- LE CERVEAU de la section « La demarche » ----------
   A DROITE, EN BAS. Demandes de Sebastien, 2026-08-23 :
   « le cerveau, je le veux a droite dans cette image-la » ·
   « diminue-le de 30 % et descends-le dans le coin droit » ·
   « un leger halo tout le tour, une impulsion aux 5 secondes comme un petit
     battement de coeur, et une petite impulsion au centre, comme des etoiles
     qui s'allument et s'eteignent — pour montrer qu'il est actif ».
   AUCUN `background` opaque ici : l'image est detouree et les etoiles du
   canvas doivent passer au travers (regle 2 de CONSIGNES.md, cassee deux
   fois deja). Les degrades utilises sont transparents sur leurs bords. */
.cerveau {
  position: absolute;
  /* « Rapproche-le un peu vers la gauche, qu'il fasse plus partie
     integrante » : il colle moins au bord, il entre dans la page. */
  right: clamp(3rem, 7vw, 9rem);
  bottom: clamp(2rem, 9vh, 7rem);
  width: clamp(210px, 25.2vw, 378px);
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
}
.cerveau img {
  display: block;
  width: 100%;
  height: auto;
  /* LE HALO. `drop-shadow` epouse la forme detouree — un `box-shadow`
     aurait halo un rectangle. Il est STATIQUE : animer un drop-shadow
     coute un rendu complet a chaque frame, alors que le battement plus bas
     ne bouge qu'un `transform`, qui reste sur le compositeur. */
  /* « Il doit y avoir un petit halo, le mauve, leger autour du cerveau »
     — trois couches au lieu de deux, la plus large tres diffuse : c'est ce
     qui fait un halo AUTOUR plutot qu'un contour. */
  filter: drop-shadow(0 0 16px rgba(192, 132, 252, 0.42))
          drop-shadow(0 0 46px rgba(168, 85, 247, 0.34))
          drop-shadow(0 0 110px rgba(124, 58, 237, 0.26));
  /* le bord gauche adouci, pour que l'arete ne coupe pas net */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 100%);
  mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 100%);
}

/* LE BATTEMENT DE COEUR, toutes les 5 secondes.
   Un vrai coeur bat DEUX fois — un coup fort, un coup plus faible juste
   apres. C'est ce double temps qui fait qu'on lit « vivant » plutot que
   « ca clignote ». Les 4 premieres secondes sont au repos : l'impulsion
   arrive, puis on attend. */
/* « Le battement de coeur doit etre plus proche [...] les deux secondes,
   c'est bon » — Sebastien, 2026-08-23. 5 s -> 2 s. */
html.anim .cerveau img { animation: cerveau-bat 2s ease-in-out infinite; }
@keyframes cerveau-bat {
  0%, 74%, 100% { transform: scale(1); }
  78%  { transform: scale(1.035); }   /* le premier coup */
  82%  { transform: scale(1.005); }
  86%  { transform: scale(1.022); }   /* le second, plus faible */
  92%  { transform: scale(1); }
}

/* LES ETINCELLES AU CENTRE — « des etoiles qui s'allument et qui s'eteignent ».
   Six points de lumiere poses en degrades radiaux, chacun minuscule et
   transparent au-dela de quelques pixels. Deux cycles decales se croisent :
   c'est ce decalage qui empeche l'oeil d'y lire un clignotant regulier. */
.cerveau .etincelles {
  position: absolute;
  /* « Je vais voir des petites etoiles qui scintillent PLUS la ou il y a le
     cerveau » : la zone couvre desormais presque tout l'organe, pas juste
     son centre. */
  left: 50%; top: 47%;
  width: 78%; height: 66%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  background-repeat: no-repeat;
  background-image:
    radial-gradient(circle 2.5px at 22% 30%, rgba(233, 213, 255, 0.95), transparent 100%),
    radial-gradient(circle 2px   at 68% 22%, rgba(192, 132, 252, 0.9),  transparent 100%),
    radial-gradient(circle 3px   at 48% 58%, rgba(255, 255, 255, 0.85), transparent 100%),
    radial-gradient(circle 2px   at 80% 66%, rgba(168, 85, 247, 0.9),   transparent 100%),
    radial-gradient(circle 2.5px at 12% 72%, rgba(216, 180, 254, 0.9),  transparent 100%),
    radial-gradient(circle 2px   at 58% 88%, rgba(255, 255, 255, 0.8),  transparent 100%);
  opacity: 0;
}
html.anim .cerveau .etincelles { animation: cerveau-etincelle 3.4s ease-in-out infinite; }
@keyframes cerveau-etincelle {
  0%, 100% { opacity: 0.15; }
  18%  { opacity: 0.85; }
  34%  { opacity: 0.25; }
  52%  { opacity: 0.7; }
  68%  { opacity: 0.2; }
  84%  { opacity: 0.55; }
}
/* la seconde nappe d'etoiles, decalee — elles ne s'allument jamais ensemble */
.cerveau .etincelles::after {
  content: "";
  position: absolute; inset: 0;
  background-repeat: no-repeat;
  background-image:
    radial-gradient(circle 2px   at 36% 16%, rgba(255, 255, 255, 0.9),  transparent 100%),
    radial-gradient(circle 2.5px at 86% 40%, rgba(192, 132, 252, 0.85), transparent 100%),
    radial-gradient(circle 2px   at 8%  46%, rgba(233, 213, 255, 0.9),  transparent 100%),
    radial-gradient(circle 3px   at 62% 74%, rgba(168, 85, 247, 0.95),  transparent 100%);
  opacity: 0;
}
html.anim .cerveau .etincelles::after { animation: cerveau-etincelle 4.7s ease-in-out infinite 1.3s; }

/* une TROISIEME nappe, encore decalee : a trois cycles premiers entre eux
   (3,4 s · 4,7 s · 6,1 s), l'oeil ne retrouve jamais le meme motif. */
.cerveau .etincelles::before {
  content: "";
  position: absolute; inset: 0;
  background-repeat: no-repeat;
  background-image:
    radial-gradient(circle 2px   at 28% 54%, rgba(255, 255, 255, 0.95), transparent 100%),
    radial-gradient(circle 2.5px at 72% 12%, rgba(216, 180, 254, 0.9),  transparent 100%),
    radial-gradient(circle 2px   at 92% 78%, rgba(192, 132, 252, 0.9),  transparent 100%),
    radial-gradient(circle 3px   at 18% 24%, rgba(255, 255, 255, 0.85), transparent 100%),
    radial-gradient(circle 2px   at 50% 92%, rgba(233, 213, 255, 0.9),  transparent 100%),
    radial-gradient(circle 2.5px at 66% 48%, rgba(255, 255, 255, 0.9),  transparent 100%);
  opacity: 0;
}
html.anim .cerveau .etincelles::before { animation: cerveau-etincelle 6.1s ease-in-out infinite 0.6s; }

/* en mode complet seulement, il arrive avec la scene */
html.anim .cerveau {
  opacity: 0;
  transition: opacity 1.6s ease var(--d, 0s);
}
html.anim .scene.joue .cerveau { opacity: 0.5; }

/* le texte reste au-dessus, toujours lisible */
.manifeste .entete, .manifeste h2, .manifeste .prose { position: relative; z-index: 1; }

@media (max-width: 860px) {
  /* en pile, il passe derriere le texte et s'efface : le texte prime */
  .cerveau {
    right: 50%;
    transform: translateX(50%);
    bottom: clamp(1rem, 4vh, 3rem);
    width: min(80vw, 390px);
    opacity: 0.22;
  }
  html.anim .scene.joue .cerveau { opacity: 0.22; }
}
@media (prefers-reduced-motion: reduce) {
  html.anim .cerveau { transition: none; }
  html.anim .cerveau img,
  html.anim .cerveau .etincelles,
  html.anim .cerveau .etincelles::after,
  html.anim .cerveau .etincelles::before { animation: none; }
  .cerveau .etincelles { opacity: 0.4; }
}


/* LE REFLET DU GEANT — « la meme chose qu'on fait dans le P ».
   Le mot est peint par un degrade decoupe aux lettres
   (`background-clip: text`) : on ne peut donc pas poser un calque par-dessus
   sans le masquer a la forme des glyphes. On REDESSINE donc le mot dans un
   pseudo-element, avec le meme balayage diagonal que le P, lui aussi
   decoupe aux lettres. Meme animation, meme duree : `reflet-coeur 7.2s`,
   un seul passage par cycle (consigne F5). */
.geant { position: relative; }
.geant::after {
  content: "PROVOLU";
  position: absolute;
  left: 0; top: 0; right: 0;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.92) 50%, transparent 62%);
  background-size: 280% 100%;
  background-position: -40% 0;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  opacity: 0;
}
/* il n'apparait qu'UNE FOIS LE MOT ARRIVE A L'ECRAN — « quand le logo
   apparait une fois qu'il est a l'ecran ». `.pleine` est posee par le JS
   quand le zoom a fini sa course. */
html.anim .geant.pleine::after { animation: reflet-coeur 7.2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  html.anim .chargement .clic-son,
  html.anim .geant.pleine::after { animation: none; }
}


/* ---------- LA BANDE VIVANTE ET RESSERREE ----------
   Sebastien, 2026-08-23 : « reduis la distance entre le banner et le Provolu
   de 60 %, [...] reduis l'espace sous le banner aussi de 60 %. Le scroll
   devient trop long pour cette section-la. »
   Ce ne sont PAS tous les vides de la page : seulement les deux qui touchent
   la bande. On les vise par adjacence — celui qui suit PROVOLU, et celui qui
   suit la bande — pour ne pas resserrer le reste au passage. 42,5vh -> 17vh. */
#marque + .respire-noir,
#bande-sec + .respire-noir { height: 17vh; }

/* LES MOTS ARRIVENT, SE PLACENT, ET REPARTENT.
   « Je veux qu'il y ait des places ou le texte n'est pas arrive encore. »
   Trois mouvements, chacun avec son propre retard (`--t`). Les durees sont
   volontairement premieres entre elles — 6,1 s, 7,3 s, 8,9 s : aucune ne
   retombe sur l'autre, donc les places vides ne sont jamais les memes. */
.bande .descend, .bande .de-cote, .bande .sen-va { display: inline-block; }

html.anim .bande .descend { animation: bande-descend 6.1s ease-in-out infinite var(--t, 0s); }
@keyframes bande-descend {
  0%   { opacity: 0; transform: translateY(-140%); }
  10%  { opacity: 1; transform: translateY(0); }
  76%  { opacity: 1; transform: translateY(0); }
  86%  { opacity: 0; transform: translateY(-140%); }
  100% { opacity: 0; transform: translateY(-140%); }
}

html.anim .bande .de-cote { animation: bande-de-cote 7.3s ease-in-out infinite var(--t, 0s); }
@keyframes bande-de-cote {
  0%   { opacity: 0; transform: translateX(120px) skewX(-8deg); }
  12%  { opacity: 1; transform: translateX(0) skewX(0); }
  70%  { opacity: 1; transform: translateX(0) skewX(0); }
  82%  { opacity: 0; transform: translateX(-120px) skewX(8deg); }
  100% { opacity: 0; transform: translateX(-120px) skewX(8deg); }
}

html.anim .bande .sen-va { animation: bande-sen-va 8.9s ease-in-out infinite var(--t, 0s); }
@keyframes bande-sen-va {
  0%, 58%  { opacity: 1; transform: translateY(0); }
  70%      { opacity: 0; transform: translateY(120%); }
  88%      { opacity: 0; transform: translateY(120%); }
  100%     { opacity: 1; transform: translateY(0); }
}

/* L'ESPACEMENT N'EST PLUS REGULIER.
   « L'espace dans le banner n'est pas oblige d'etre tout centre. Ca peut
   etre vraiment comme plus special comme affichage. » Chaque motif porte sa
   propre respiration, et deux d'entre eux se decalent verticalement : la
   ligne cesse d'etre une reglure. */
.bande .m1 { margin-right: 3.4rem; }
.bande .m2 { margin-right: 1rem; transform: translateY(-0.16em); }
.bande .m3 { margin-right: 4.6rem; }
.bande .m4 { margin-right: 0.7rem; transform: translateY(0.2em); }
.bande .m5 { margin-right: 2.6rem; }
.bande .m6 { margin-right: 5.2rem; transform: translateY(-0.1em); }
.bande .m7 { margin-right: 1.3rem; }

@media (prefers-reduced-motion: reduce) {
  html.anim .bande .descend,
  html.anim .bande .de-cote,
  html.anim .bande .sen-va { animation: none; opacity: 1; transform: none; }
}

/* les retards, en attributs data : la CSP interdit style= */
[data-t="0"] { --t: 0s; }
[data-t="0-4"] { --t: 0.4s; }
[data-t="0-7"] { --t: 0.7s; }
[data-t="1-1"] { --t: 1.1s; }
[data-t="1-6"] { --t: 1.6s; }
[data-t="2-1"] { --t: 2.1s; }
[data-t="2-8"] { --t: 2.8s; }
[data-t="3-2"] { --t: 3.2s; }
[data-t="3-9"] { --t: 3.9s; }
[data-t="4-3"] { --t: 4.3s; }
[data-t="5-1"] { --t: 5.1s; }


/* (L'epinglage au defilement — .epingle, .epingle-piste, .epingle-vue,
   .piste-* — est parti avec la page qui defilait : chaque plaque est
   plein ecran et fixe, il n'y a plus rien a coller. Commit 87997a3 dans
   l'historique pour memoire.) */

/* LES TROIS CHIFFRES GROSSISSENT A TOUR DE ROLE.
   « Le chiffre 1 qui est gros quand il apparait, le 2 gros au milieu, puis
   quand je suis rendu au 3, le 3 devient gros. » Le numero grossit SUR
   PLACE — il ne bouge pas de sa colonne, comme il l a demande. */
.etapes .no { transition: transform 0.55s var(--vite), color 0.55s ease, opacity 0.55s ease; }
.etapes li.grand .no { color: #ffffff; transform: scale(2.6); }
.etapes li.grand h3 { color: var(--accent-clair); }
.etapes li h3 { transition: color 0.55s ease; }
.etapes li.grand .noeud {
  background: #ffffff;
  box-shadow: 0 0 18px 5px rgba(188, 216, 255, 0.75), 0 0 46px 14px rgba(168, 85, 247, 0.5);
}
.etapes li .noeud { transition: background 0.5s ease, box-shadow 0.5s ease; }

/* ---------- ( 03 ) : LES TROIS FACONS ENSEMBLE (2026-08-24) ----------
   Trois colonnes visibles d'un coup ; le glacon vient ACTIVER chaque icone,
   une par geste, et elle reste allumee. */

/* ---------- ( 04 ) : LE CUBE CLIQUE LES CARTES ---------- */
/* la carte reste allumee une fois visitee — « les cards restent cliquees » */
.travail.vue { box-shadow: 0 0 0 1px rgba(188, 216, 255, 0.35), 0 0 46px rgba(168, 85, 247, 0.28); }
.travail { transition: box-shadow 0.6s ease; }

/* ---------- PLAQUE 4 : PROVOLU ET LA BANDE ENSEMBLE ----------
   « Je pense sur la meme plaque on combine 3 et 4 ». Le mot occupe le haut,
   la bande passe dessous — la mise en page complete vit plus bas, dans le
   bloc « PLAQUE 4 — REFAITE AU PROPRE ». */
.plaque-marque .geant-scene { display: flex; align-items: center; justify-content: center; }
.plaque-marque .bande { width: 100vw; margin-left: calc(50% - 50vw); }

/* ---------- ( 01 ) LE CERVEAU BAT TOUT SEUL, TOUTES LES 2 S ----------
   La fiche P05 du devis (2026-08-24) a remplace le battement force par le
   defilement : le cerveau est une matiere VIVANTE, comme le glacon qui
   danse. C'est `cerveau-bat-doux 2s` (plus bas) qui bat, a moitie
   d'amplitude ; le son se cale sur l'image dans accueil.js. */


/* ---------- LA BASCULE VERS LA VRAIE PAGE, EN FONDU ----------
   Sebastien, 2026-08-23 : « on va tomber dans une nouvelle page, mais le
   client ne s'en rendra pas compte [...] bascule en fondu ».
   L'INTRO EST UN VERNIS. La vraie page vit dessous, complete et normale ;
   l'intro la recouvre. Quand elle a fini — ou qu'on appuie sur « Passer » —
   elle s'efface, et la vraie page est deja la. Aucun rechargement, aucune
   couture : c'est ce qui rend la bascule invisible.
   C'est aussi ce qui la rend SOLIDE sur telephone : la vraie page n'a
   jamais dependu d'une animation, elle est indexable et rapide, et l'intro
   se retire sans rien casser. */
.vernis {
  position: relative;
  z-index: 2;
  transition: opacity 1.1s ease, visibility 0s linear 1.1s;
}
html.vraie-page .vernis {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
/* pendant l'intro, la vraie page ne defile pas : elle attend dessous */
html:not(.vraie-page) .vraie { display: none; }

/* ---------- L'ARRIVEE SUR LA VRAIE PAGE ----------
   Sebastien, 2026-08-31 : « quand je continue de scroller, la page ne part
   pas tout de suite [...] il va y avoir un fondu et ce texte-la va
   apparaitre. » Le dernier geste de l'intro etait aussi le premier geste de
   la vraie page : on sortait du noir DEJA en train de defiler, et le titre
   « Des idees aux solutions numeriques » se levait derriere le vernis
   encore opaque — son entree etait donc depensee pour rien.
   La chronologie vit dans accueil.js (`versLaVraiePage`, bloc « L'ARRIVEE »).
   Ici, seulement les deux etats.

   1. LE DEFILEMENT EST TENU. Le selecteur porte les TROIS classes, et c'est
   la seule raison : `html.plaques.vraie-page` rend le defilement en
   `!important` un peu plus bas dans ce fichier. Une regle a deux classes
   perdait le depart au coup par coup selon l'ordre du fichier — celle-ci en
   a trois, elle gagne ou qu'elle soit ecrite. Sans ca, le verrou ne prenait
   pas et la page defilait pendant le fondu (constate le 2026-08-31). */
html.arrivee.plaques.vraie-page,
html.arrivee.plaques.vraie-page body {
  overflow: hidden !important;
  height: 100% !important;
}

/* 2. LE TEXTE DU HERO ATTEND SON TOUR.
   IL A DEJA SON ENTREE — `.hero > *` porte `animation: monte 0.8s ... both`
   avec un decalage par enfant (le h1 a 0,34 s). On ne la refait donc PAS en
   double avec des transitions d'opacite : une animation l'emporte de toute
   facon sur une opacite declaree, et la seconde couche n'aurait servi qu'a
   faire croire qu'elle agissait.
   On la MET EN PAUSE le temps que le vernis se leve, puis on la relache.
   `fill-mode: both` fait que la pause tient l'etat de depart — invisible,
   decale — sans qu'on ait a l'ecrire. */
html.arrivee:not(.arrivee-vue) .vraie .hero > * { animation-play-state: paused; }

/* Lu par les lecteurs d'ecran, invisible a l'oeil. Sert au texte de la
   phrase d'accueil, que sa couche animee ne peut pas porter (2026-08-25). */
.lecture-seule {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* MOUVEMENT REDUIT — LE GARDE GLOBAL (2026-08-25, audit lea). `html.anim`
   eteignait les @keyframes, mais PAS les transitions : le vernis a 1,1 s, le
   voile du decompte a 1,5 s, le glacon a 2 s, les cartes a 0,75 s, et le
   `scroll-behavior: smooth` continuaient de courir. Une seule regle les
   coupe toutes — celles d'aujourd'hui et celles qu'on ajoutera. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto !important; }
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
html.vraie-page { scroll-behavior: auto; }


/* ---------- L'ECRAN DE DEPART ----------
   « Le cliquer pour commencer, un ecran pour lancer le debut. »
   TOUT l'ecran est le bouton : on ne peut pas le manquer, et au doigt il n'y
   a rien a viser. Il remplace le petit mot « clic » du chargement. */
.depart {
  position: absolute;
  inset: 0;
  z-index: 40;
  /* SON PARENT `.voile-charge` porte `pointer-events: none` — c'est un voile
     decoratif, il ne doit rien intercepter. Le bouton en HERITAIT, donc le
     clic ne l'atteignait jamais : l'ecran restait muet. Il reprend la main
     explicitement. C'est le genre de panne qui ne se voit dans aucun test de
     texte : le bouton existe, il est de la bonne taille, et il ne repond
     pas. Le controle qui l'attrape lit `pointer-events` calcule. */
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.1rem;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--text);
  transition: opacity 0.7s ease, visibility 0s linear 0.7s;
}
/* LE SYMBOLE SUR LE PREMIER ECRAN (2026-08-30, audit lea). Il repond a
   « ou suis-je ». Actif deja present et deja precharge par la vraie page :
   aucun octet de plus.
   alt="" VOLONTAIRE : le nom Provolu est deja dans le <title> ; l'annoncer
   une seconde fois a un lecteur d'ecran est du bruit. Image decorative.

   DOUBLE ET RAPPROCHE — Sebastien, 2026-08-31 : « on double la grosseur du
   P et on le descend plus pres de Cliquer pour commencer ». Les trois
   valeurs de la hauteur sont exactement x2 (40/7/62 -> 80/14/124), et
   l'ecart au mot tombe de ~4,95rem a ~1,45rem : la marge de 1,6rem devient
   0,35rem, et la promesse qui s'intercalait est partie.

   LE WRAPPER N'EST PAS DECORATIF. Une <img> ne porte pas de
   pseudo-element : sans lui, `.reflet-p::after` n'aurait nulle part ou
   vivre et le reflet ne passerait jamais dans le P. */
.depart-symbole {
  display: block;
  line-height: 0;
  margin-bottom: 0.35rem;
}
.depart-marque {
  height: clamp(80px, 14vh, 124px);
  width: auto;
  opacity: 0.9;
}
/* LE REFLET CIRCULE PLUS SOUVENT ICI, ET IL PASSE DEUX FOIS PLUS LENTEMENT.
   `reflet-p` tourne a 7,2 s sur les P de la page — un passage toutes les
   sept secondes se remarque a peine sur un ecran qu'on ne regarde qu'une
   seconde ou deux. Sur la porte d'entree, ou l'on attend un geste, il
   repasse toutes les 4,4 s.
   MOITIE VITESSE — Sebastien, 2026-08-31 : « il est trop rapide, il doit
   etre fait a la moitie de la vitesse actuelle ».
   POURQUOI PAS SIMPLEMENT DOUBLER LA DUREE : dans `reflet-coeur`, le
   balayage n'occupe que les 14 premiers pour cent du cycle — le reste est
   une attente. Passer 4,4 s a 8,8 s aurait bien ralenti le reflet, mais
   aurait AUSSI double l'attente entre deux passages (3,8 s -> 7,6 s), et il
   avait demande qu'ils circulent. On etire donc la part du balayage dans le
   cycle : 14 % -> 28 %. Le reflet met 1,23 s au lieu de 0,62 s — exactement
   la moitie de la vitesse — et le rythme de retour ne bouge pas. */
html.anim .depart-symbole.reflet-p::after {
  animation-name: reflet-porte;
  animation-duration: 4.4s;
}
@keyframes reflet-porte {
  0% { opacity: 0; background-position: 120% 0; }
  4% { opacity: 1; }
  28% { opacity: 0; background-position: -40% 0; }
  100% { opacity: 0; background-position: -40% 0; }
}

.depart-mot {
  font-size: clamp(1.15rem, 2.6vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  background: linear-gradient(180deg, #ffffff 30%, #cbb6f5 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.depart-sous {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--sourd);
}
html.anim .depart .depart-mot { animation: bat-clic 2.6s ease-in-out infinite; }
.depart:hover .depart-sous, .depart:focus-visible .depart-sous { color: var(--accent-clair); }
/* AU CLIC, LA LIGNE S'ALLUME ET L'ECRAN RESPIRE UNE SECONDE (2026-08-24 au
   soir) : « quand je clique sur la page d'accueil, la ligne "le son fait
   partie de l'experience" devient mauve. La page est presente pour une
   seconde, puis un fondu nous amene vers la page suivante. » Sans cette
   seconde, le clic et le decompte se marchaient dessus. */
.depart.parti .depart-sous { color: var(--accent-clair); transition: color 0.35s ease; }
.depart.parti .depart-mot { opacity: 0.55; transition: opacity 0.6s ease; }
html.plaques #p-clic.sort { opacity: 0; filter: blur(9px); transition: opacity 0.75s ease, filter 0.75s ease; }
/* une fois lance, il s'efface et ne reprend jamais la main */
.porte.lance .depart { opacity: 0; visibility: hidden; pointer-events: none; }

/* AUCUN DEFILEMENT TANT QUE LA PORTE EST LA.
   « Il ne devrait pas y avoir de scroll par en bas, qui devrait etre
   possible a l'ouverture de la page. » `body { overflow: hidden }` ne
   suffisait pas : c'est <html> qui defile, pas <body>. La page faisait
   15 574 px de haut et se laissait descendre pendant l'ecran de depart. */
html.porte-la, html.porte-la body { overflow: hidden; height: 100%; }

/* 3. « PASSER » N'EXISTE PAS AVANT LE DEPART.
   « Le bouton Passer ne devrait pas etre present. Ca devrait commencer par
   un clic. » Il reapparait une fois l'intro lancee — il sert alors a la
   sauter, ce qui est son role. */

/* le chargement n'existe pas tant qu'on n'a pas lance */
.chargement { opacity: 0; transition: opacity 0.6s ease; }
.porte.lance .chargement { opacity: 1; }
.chargement .patience {
  display: block;
  margin-top: 0.9rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  color: var(--sourd);
  opacity: 0;
  transition: opacity 0.8s ease 0.5s;
}
.porte.lance .chargement .patience { opacity: 1; }


/* (La regle « Passer au mouvement de souris » du 23 est REMPLACEE le
   2026-08-24 par « Passer l'intro apparait a 5 s, puis reste » — voir
   html.saut-la plus bas.) */

/* ---------- LES DEUX AIDES ---------- */
.guide {
  position: absolute;
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.9s ease;
}
.porte .guide.la { opacity: 1; }
.guide-mot {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}
.guide-fleche {
  width: 2px; height: 34px;
  background: linear-gradient(180deg, transparent, var(--accent-clair));
  position: relative;
}
.guide-fleche::after {
  content: "";
  position: absolute; left: 50%; bottom: -1px;
  width: 9px; height: 9px;
  transform: translateX(-50%) rotate(45deg);
  border-right: 2px solid var(--accent-clair);
  border-bottom: 2px solid var(--accent-clair);
}
html.anim .guide.la .guide-fleche { animation: guide-pointe 1.7s ease-in-out infinite; }
@keyframes guide-pointe {
  0%, 100% { transform: translateY(0);   opacity: 0.6; }
  50%      { transform: translateY(9px); opacity: 1; }
}

/* L'IMPULSION QUI MONTE DANS LE TROU — « une petite fleche avec une
   impulsion qui monte dans le trou ». Un anneau qui s'eleve et s'efface :
   il montre la destination sans rien cacher. */
.trou .impulsion {
  position: absolute;
  left: 50%; top: 50%;
  width: 46%; height: 26%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 1px solid rgba(192, 132, 252, 0.85);
  pointer-events: none;
  opacity: 0;
}
html.anim .trou.appelle .impulsion { animation: impulsion-trou 2.1s ease-out infinite; }
@keyframes impulsion-trou {
  0%   { opacity: 0;   transform: translate(-50%, -50%) scale(0.6); }
  18%  { opacity: 0.9; }
  100% { opacity: 0;   transform: translate(-50%, -190%) scale(1.25); }
}
@media (prefers-reduced-motion: reduce) {
  html.anim .guide.la .guide-fleche,
  html.anim .trou.appelle .impulsion { animation: none; }
}

a.nu { text-decoration: none; }

/* LE PORTAIL AU PIED DE PAGE. Il double le coin secret du haut, qui n'existe
   qu'au survol et disparait sous 860 px. Discret, jamais cache. */
.lien-portail {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.lien-portail:hover,
.lien-portail:focus-visible { color: var(--accent-clair); border-color: var(--accent); }

/* ========================================================================
   L'ARCHITECTURE EN DOUZE PLAQUES — construite le 2026-08-23
   Chaque plaque est plein ecran, fixe. Un geste (molette, glissement,
   fleches) fait passer d'une plaque a la suivante — il ne deplace rien.
   Modele mesure sur why.zero.university : overflow hidden, page a la
   hauteur de l'ecran, defilement = etape.
   La liste des douze vit dans CONSIGNES.md, section « L'architecture en
   plaques ». Ne PAS changer ce compte sans y toucher aussi. */
html.plaques, html.plaques body { overflow: hidden !important; height: 100%; margin: 0; }

/* Chaque plaque est UNE surface fixe. Elle apparait en fondu quand elle
   devient active ; la precedente s'efface en meme temps. Aucune plaque
   n'est jamais deplacee — c'est le contenu qui joue dedans. */
html.plaques .plaque {
  position: fixed;
  inset: 0;
  z-index: 3;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.85s ease, visibility 0s linear 0.85s;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(2rem, 8vh, 5rem) clamp(1.25rem, 3.5vw, 2.5rem);
  max-width: none;
  min-height: 0;
}
html.plaques .plaque.active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.85s ease, visibility 0s;
  z-index: 4;
}

html.plaques .vernis .respire, html.plaques .vernis .respire-noir { display: none !important; }

/* La porte est la premiere plaque, pas un overlay separe */
html.plaques .porte { position: relative !important; z-index: auto; }

/* Une petite jauge de plaques dans le coin, discrete — comme sur Zero.
   Elle dit combien il en reste. */
.jauge {
  position: fixed;
  right: clamp(1rem, 2vw, 1.6rem);
  bottom: clamp(1rem, 2vh, 1.4rem);
  z-index: 10;
  display: flex;
  gap: 0.35rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.6s ease;
}
html.plaques.demarre .jauge { opacity: 0.55; }
.jauge .cran {
  width: 18px;
  height: 2px;
  background: var(--muted);
  opacity: 0.35;
  transition: opacity 0.4s ease, background 0.4s ease;
}
.jauge .cran.la { background: var(--accent-clair); opacity: 1; }

/* Un cue de defilement, une seule fois, quand on arrive sur une plaque
   qu'il faut faire avancer par gestes. */
.cue-suite {
  position: fixed;
  left: 50%;
  bottom: clamp(1.4rem, 3.5vh, 2.4rem);
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease;
}
html.plaques.demarre .cue-suite { opacity: 0.55; }
.cue-suite::after {
  content: "";
  width: 1px; height: 18px;
  background: linear-gradient(180deg, transparent, currentColor);
  animation: cue-bat 1.8s ease-in-out infinite;
}
@keyframes cue-bat {
  0%, 100% { transform: translateY(0);   opacity: 0.5; }
  50%      { transform: translateY(6px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  html.plaques .plaque { transition: opacity 0s, visibility 0s; }
  .cue-suite::after { animation: none; }
}

/* ========================================================================
   ADAPTATIONS SPECIFIQUES aux plaques — 2026-08-23
   ======================================================================== */

/* PROVOLU sans zoom — Sebastien : « on n'a plus besoin de faire un zoom in ».
   Le mot arrive a sa taille finale, un reflet passe dedans. On neutralise
   le transform pose par le JS. */
html.plaques .geant { transform: none !important; }
html.plaques .geant.pleine::after { animation: reflet-coeur 7.2s ease-in-out infinite; }

/* La plaque marque = PROVOLU au tiers du haut, bande au tiers du bas.
   L'espace entre les deux tiers est vide — c'est ce qui donne la respiration. */
html.plaques .plaque-marque {
  justify-content: space-between;
  padding-top: clamp(4rem, 12vh, 8rem);
  padding-bottom: clamp(4rem, 12vh, 8rem);
}
html.plaques .plaque-marque .geant-scene {
  flex: 0 0 auto;
  display: flex;
  justify-content: center;
  align-items: center;
  padding-top: 4vh;
}
html.plaques .plaque-marque .bande {
  flex: 0 0 auto;
  margin-bottom: 4vh;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}


/* La plaque cerveau : le halo autour est RETIRE (consigne 2026-08-23). Le
   drop-shadow disparait, on garde etincelles et boum-boum. */
html.plaques #demarche .cerveau img {
  filter: none;   /* le halo mauve autour, retire */
}

/* La plaque reduire : contenu centre verticalement dans la vue */
html.plaques #reduire { justify-content: center; gap: 3vh; }

/* La plaque faire : la voie devient un empilement de 3 capsules qui
   s'allument une apres l'autre. Plus de ligne entre elles. */

/* La plaque travaux : carrousel toujours actif, cartes visitees s'allument.
   LA CARTE DU CENTRE EST PLUS OPAQUE (2026-08-24) : « un peu plus blanche,
   moins translucide, c'est derangeant a l'ecran. » */
html.plaques #travaux .travail.centre {
  /* « beaucoup moins translucide [...] blanc-gris, ca va donner un pop »
     (2026-08-24 au soir). 0,13 -> 0,20. On ne monte pas plus haut : le
     texte de la carte est blanc, et au-dela il cesse de se detacher. */
  background: rgba(255, 255, 255, 0.20);
  border-color: rgba(196, 168, 255, 0.6);
}
html.plaques #travaux { justify-content: center; }
html.plaques #travaux .carrousel { height: clamp(300px, 42vh, 400px); }
html.plaques #travaux .fleches {
  position: absolute;
  bottom: 12%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 0;
}

/* (La plaque « sortie » et ses lignes de chute sont parties le 2026-08-24 :
   « je veux eliminer cette plaque-la avec le trou. J'en veux plus. » Le
   glacon finit desormais dans la video de fonte, sur la plaque finale.) */

/* ============ LA PLAQUE FINALE — fusion « Partons du vrai besoin » + la
   fonte (2026-08-24). Texte a GAUCHE ; la video et le P a DROITE. La
   sequence : le glacon-compagnon se pose sur la scene, la video le reprend
   et le fait fondre ; a la fin, la video s'efface, le premier texte aussi,
   le mot de chute et l'invitation arrivent, et le P apparait EN DERNIER. */
/* « On va rapprocher les textes du video » (2026-08-25) : colonnes au
   contenu, ensemble centre — texte et video voisinent. */
html.plaques #p-final {
  display: grid !important;
  grid-template-columns: minmax(0, 48ch) auto;
  justify-content: center;
  align-items: center;
  gap: clamp(1.6rem, 3.5vw, 3.5rem);
  padding: 0 clamp(2.5rem, 7vw, 8rem) !important;
  min-height: 0;
  text-align: left;
}
#p-final .final-gauche { display: grid; }
/* `.final-apres` A DISPARU le 2026-08-31 avec le mot de chute et le bloc de
   contact (Sebastien : « apres le cube qui fond, on devrait entrer
   directement dans le vrai site »). La grille a une seule case reste : elle
   ne coute rien et elle garde la colonne calee sur la scene video. */
#p-final .final-avant { grid-area: 1 / 1; transition: opacity 0.9s ease, visibility 0s linear 0.9s; }
#p-final .final-avant h2 {
  font-size: clamp(2.4rem, 4.6vw, 4.4rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  font-weight: 800;
}
#p-final .final-avant h2 em { font-style: normal; color: var(--accent); }
#p-final .final-avant .sous { margin-top: 1.6rem; color: var(--muted); font-size: 1.08rem; max-width: 44ch; }
/* LA DERNIERE IMAGE DE L'INTRO EST LE P, SEUL. Le texte de conclusion
   s'efface quand la video finit (`fin-arrivee`) et plus rien ne le
   remplace : l'ecran se vide, le P reste, puis la bascule. */
#p-final.fin-arrivee .final-avant { opacity: 0; visibility: hidden; }
#p-final .final-droite { display: flex; justify-content: center; }
/* la video : reduite de 50 %, et elle S'EFFACE a la fin — « je ne veux pas
   que la video reste en background » */
html.plaques #p-final .scene-video { min-height: 0; margin: 0; width: clamp(190px, 17vw, 260px); }
html.plaques #p-final .trou-final { position: relative; width: 100%; opacity: 1; }
html.plaques #p-final .trou-final video {
  position: static;
  display: block;
  width: 100%; height: auto;
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 0.8s ease, transform 1s var(--vite);
  mix-blend-mode: screen;
}
html.plaques #p-final .trou-final.fond video { opacity: 1; transform: none; }
html.plaques #p-final .trou-final.revele video { opacity: 0; transition: opacity 1.1s ease; }
/* le P : par-dessus la scene, EN DERNIER */
html.plaques #p-final .trou-final .marque-finale {
  position: absolute;
  left: 50%; top: 50%;
  width: 54%;
  transform: translate(-50%, -50%) scale(0.6);
  opacity: 0;
  transition: opacity 1.2s ease 0.6s, transform 1.4s var(--vite) 0.6s;
}
html.plaques #p-final .trou-final.revele .marque-finale {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* La porte de la plaque 2 : elle occupe tout l'ecran de la plaque, en
   position statique (pas fixed) puisqu'elle est deja dans une plaque fixe. */
html.plaques #p-charge {
  padding: 0;
  overflow: visible;
}
html.plaques #p-charge .porte {
  position: relative !important;
  width: 100%;
  height: 100vh;
  height: 100svh;
  display: block !important;
}

/* La plaque 1 (clic pour commencer) : plein ecran, contenu centre */
html.plaques #p-clic {
  padding: 0;
  align-items: center;
  justify-content: center;
  background: #06030b;
}
html.plaques #p-clic .depart {
  position: relative;
  inset: auto;
  z-index: 1;
}

/* Le canvas des etoiles reste en arriere-plan de TOUTES les plaques */
html.plaques .galaxie { z-index: 1; }

/* La topbar (barre PROVOLU) apparait a partir de la plaque hero */
html.plaques .vernis .topbar { z-index: 20; }



/* Les guides (aides) sont hors des plaques : ils flottent en surcouche */
html.plaques .guide { z-index: 25; position: fixed; }

@media (max-width: 860px) {
  /* Au telephone, le meme decoupage — c'est le modele Zero qui garantit
     que ca marche pareil. Chaque plaque tient dans UN ecran de 390 x 844 :
     on compresse, on ne retire rien. */
  html.plaques .plaque-marque {
    padding-top: clamp(2rem, 8vh, 5rem);
    padding-bottom: clamp(2rem, 8vh, 5rem);
  }
  /* plaque 7 : l'icone au-dessus du texte, en colonne */
  /* plaque 6 : les trois chiffres restent sur UNE ligne, compresses */
  html.plaques #reduire.active .etapes { gap: 1.1rem !important; padding: 0 !important; }
  html.plaques #reduire.active .etapes h3 { font-size: 1rem; }
  html.plaques #reduire.active .etapes p { font-size: 0.78rem; }
  /* plaque 5 : le texte au-dessus, le cerveau dessous — deja gere par la
     grille une colonne du bloc cerveau */
  /* plaque 8 : la carte du centre remplit l'ecran, les fleches restent */
  html.plaques #travaux .carrousel { height: clamp(280px, 40vh, 380px); }
  html.plaques #travaux .fleches { bottom: 8%; }
  /* la porte : la phrase et la flaque se resserrent */
  .phrase { max-width: 16ch; }
}

/* Le pied de page de l'intro n'existe plus dans le HTML : les plaques
   n'atteignent jamais un pied de page. « Faire revivre le cube » et le
   portail vivent dans le pied de la VRAIE page (fiche P12). */
/* SEULEMENT la barre de l'intro : la vraie page a un en-tete qui s'appelle
   aussi .topbar — le cacher lui coupait son menu (constate 2026-08-24). */
html.plaques .vernis .topbar { display: none; }

/* LE VERNIS EST UNE SURCOUCHE FIXE, PAS UN BLOC DU FLUX — decouvert le
   2026-08-24 : en `position: relative`, son ecran de hauteur restait dans
   le flux apres la bascule (l'invisibilite ne retire pas l'emprise), et la
   vraie page commencait un ecran PLUS BAS — on tombait sur du noir. Fixe
   et plein cadre, il recouvre la vraie page pendant l'intro et ne lui vole
   plus une ligne apres. Son fond coupe tout ce qui pourrait passer entre. */
html.plaques .vernis {
  position: fixed;
  inset: 0;
  background: #06030b;
}

/* Les enfants venir/up des plaques doivent apparaitre quand la plaque est
   active. Le CSS existant `.scene.joue .venir { opacity: 1 }` marche : on
   pose `.joue` en meme temps que `.active`. Verification supplementaire ici
   pour les elements NON-`.venir` qui portent aussi une entree en scene. */
html.plaques .plaque.active .up { opacity: 1; transform: none; }
html.plaques .plaque:not(.active) .up { opacity: 0; }

/* ========================================================================
   FORCE-RENDU des elements dans les plaques actives — 2026-08-23
   Les choregraphies d'origine gardent la plupart des elements caches en
   attendant un IntersectionObserver. En mode plaques, tout ce qui est dans
   la plaque active DOIT etre visible tout de suite.
   ======================================================================== */
html.plaques .plaque.active h1,
html.plaques .plaque.active h2,
html.plaques .plaque.active h3,
html.plaques .plaque.active p:not(.venir):not(.up),
html.plaques .plaque.active .biblio,
html.plaques .plaque.active .titre-reel {
  opacity: 1 !important;
  visibility: visible;
  /* ET LE TRANSFORM (2026-08-25, constate au telephone) : le h2 du cerveau
     gardait le translateX(-70px) de .venir — 330 px centres dans 375 moins
     70 = il sortait de l'ecran a gauche. Sur bureau, l'alignement a droite
     masquait le meme decalage. La revelation forcee force donc AUSSI la
     position, pas seulement l'opacite. */
  transform: none !important;
}

/* (l'aplatissement du carrousel a ete retire le 2026-08-23 :
   il tuait les fleches, les effets de carte et la trajectoire du cube.) */



/* LE TITRE EN PARTICULES EST REVENU — Sebastien, 2026-08-24 : « dans la
   version originale, c'etait beaucoup plus premium. » Le canvas peint le
   titre en points, le glacon les chasse en traversant. Le defaut du 23
   (un clip-path qui laissait un trou a la place du titre) ne revient pas :
   le canvas est ACTIF, donc il PORTE le titre. */
html.plaques #reduire.active .particules-boite { width: 100%; max-width: 1100px; margin: 0 auto; }
html.plaques #reduire.active .etapes {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  max-width: 1000px;
  /* rapprochees du titre (2026-08-24) */
  margin: 0.6rem auto 0;
}
html.plaques #reduire.active .etapes li {
  text-align: center;
  opacity: 1 !important;
  transform: none !important;
}

/* Le hero : forcer les 3 lignes visibles */
html.plaques #haut.active .venir,
html.plaques #haut.active .depuis-droite,
html.plaques #haut.active .l { opacity: 1 !important; transform: none !important; }

/* Toutes les plaques : les h2/h3/p enfants deviennent visibles */
html.plaques .plaque.active .entete,
html.plaques .plaque.active .entete p,
html.plaques .plaque.active .sous,
html.plaques .plaque.active .prose { opacity: 1 !important; transform: none !important; }

/* S'assurer qu'AUCUN contenu d'une plaque non-active ne fuit visuellement
   quand une autre est en fondu. Le opacity de la plaque cache normalement,
   mais certains descendants font des transitions individuelles qui
   depassent. */
html.plaques .plaque:not(.active) * { transition: none !important; }
html.plaques .plaque:not(.active) { pointer-events: none !important; }

/* Sur la plaque hero, forcer le rendu de TOUS les elements meme sans .joue */
html.plaques #haut.plaque {
  align-items: center; text-align: center;
}
html.plaques #haut.plaque .hero-corps {
  display: flex; flex-direction: column; align-items: center; gap: 1.5rem;
}
html.plaques #haut h1,
html.plaques #haut .titre-plaque { font-size: clamp(2.5rem, 6vw, 5.5rem); line-height: 1.05; text-align: center; margin: 0; }
html.plaques #haut h1 .l3,
html.plaques #haut .titre-plaque .l3 { color: var(--accent-clair); }

/* LE GLACON NE QUITTE PLUS L'ECRAN (T5, 2026-08-24) : il entre au hero et
   accompagne chaque plaque jusqu'a la fonte finale — « sinon on va perdre
   le glacon ». C'est le JS qui le montre et le cache (classe .la) ; ici on
   le laisse simplement exister par-dessus les plaques. */
html.plaques #compagnon { display: block; position: fixed; z-index: 25; }

/* Le trou-final de la plaque 11 : on ne veut pas le trou par-dessus, juste
   la video et le P. Le trou vit dans la plaque 9. */
html.plaques #final .trou-final .gouffre { display: none; }
html.plaques #final .trou-final .anneau { opacity: 0.6; }
html.plaques #final .scene-video { max-width: 500px; margin: 0 auto; padding: 3rem; }

/* ========================================================================
   FOUC (Flash of Unstyled Content) — au chargement, tout est cache par
   defaut. Seule la premiere plaque marquee `.active` dans le HTML apparait.
   Le moteur a plaques prendra ensuite le relais. */
html:not(.plaques) .plaque:not(.active) { opacity: 0 !important; visibility: hidden !important; }
html:not(.plaques) .porte { visibility: hidden !important; }
html:not(.plaques) #compagnon,
html:not(.plaques) .voile-noir,
html:not(.plaques) .topbar,
html:not(.plaques) .footer { visibility: hidden !important; }
/* Fond noir immediat, avant tout script */
html, body { background: #06030b; }

/* Le cue « defilez » n'apparait qu'a partir de la plaque HERO — pas sur
   « Cliquer pour commencer » ni sur le chargement. C'est trop tot avant. */
.cue-suite { display: none; }
html.plaques.demarre .plaque.active[data-pid="hero"] ~ .cue-suite,
html.plaques.demarre .plaque.active[data-pid="marque"] ~ .cue-suite,
html.plaques.demarre .plaque.active[data-pid="cerveau"] ~ .cue-suite,
html.plaques.demarre .plaque.active[data-pid="reduire"] ~ .cue-suite,
html.plaques.demarre .plaque.active[data-pid="realisations"] ~ .cue-suite,
html.plaques.demarre .plaque.active[data-pid="sortie"] ~ .cue-suite,
html.plaques.demarre .plaque.active[data-pid="partons"] ~ .cue-suite,
html.plaques.demarre .plaque.active[data-pid="final"] ~ .cue-suite { display: flex; }
/* Ce selecteur ~ ne marche que si le cue est SIBLING des plaques.
   Il est enfant du body. On simplifie : le cue est controle par JS via une
   classe .cue-visible sur html. */
.cue-suite { display: none !important; }
html.plaques.cue-visible .cue-suite { display: flex !important; }

/* « Introduite avec soin » — plus de punch, couleur plus vive.
   Sebastien, 2026-08-23. La ligne 3 du hero est mise en accent, en gras
   plus fort, taille legerement plus grande, ombre lumineuse.
   ETENDUE a la vraie page le 2026-08-25 : « rendre plus mauve, flash,
   comme on utilise ailleurs dans l'application » — c'est exactement ce
   traitement, deja ecrit pour la plaque, qu'il demande de reprendre ici. */
html.plaques #haut h1 .l3,
html.plaques #haut .titre-plaque .l3,
#v-haut h1 .l3 {
  background: linear-gradient(90deg, #c084fc 0%, #a855f7 50%, #d8b4fe 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  font-weight: 900;
  font-size: 1.15em;
  text-shadow: 0 0 40px rgba(168, 85, 247, 0.4);
  filter: drop-shadow(0 0 24px rgba(168, 85, 247, 0.35));
  letter-spacing: -0.03em;
}

/* (La glissade a la depose et sa lueur sont parties le 2026-08-24 :
   « je depose simplement, comme il y avait la au debut ».) */

/* La plaque marque : PROVOLU en tiers 1, bande en tiers 2, vide en tiers 3.
   Sebastien, 2026-08-23 : « Le Provolu devrait etre dans le premier tiers,
   dans le haut de l'ecran. Le deuxieme tiers devrait etre la barre qui
   defile rapidement. » */
html.plaques .plaque-marque {
  justify-content: flex-start !important;
  gap: 0 !important;
  padding: 0 !important;
  display: grid !important;
  grid-template-rows: 1fr 1fr 1fr;
}
html.plaques .plaque-marque .geant-scene {
  grid-row: 1;
  min-height: 0 !important;
  height: 33.33vh;
  padding: 0 !important;
  display: flex;
  align-items: center;
  justify-content: center;
}
html.plaques .plaque-marque .bande {
  grid-row: 2;
  align-self: center;
  margin: 0 !important;
  width: 100vw;
  margin-left: calc(50% - 50vw) !important;
}

/* Le reflet dans PROVOLU, 2x plus long. Sebastien : « ralentie de moitie ».
   7,2 s -> 14,4 s. */
html.plaques .geant.pleine::after {
  animation: reflet-coeur 14.4s ease-in-out infinite !important;
}

/* Mise en page pro pour la plaque cerveau (« La demarche »).
   Sebastien, 2026-08-23 : « ameliore la mise en page ici pour un look
   professionnel. » Le texte se centre verticalement en 2 colonnes, le
   cerveau prend la moitie droite, taille et poids ajustes. */
html.plaques #demarche.plaque {
  display: grid !important;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: clamp(2rem, 5vw, 4rem);
  padding: clamp(3rem, 8vh, 6rem) clamp(3rem, 6vw, 5rem) !important;
}
html.plaques #demarche.plaque .entete {
  grid-column: 1 / -1;
  align-self: start;
}
html.plaques #demarche.plaque h2 {
  grid-column: 1;
  font-size: clamp(2.2rem, 4.4vw, 4rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0;
}
html.plaques #demarche.plaque h2 em {
  font-style: normal;
  background: linear-gradient(90deg, #c084fc, #a855f7);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
html.plaques #demarche.plaque .prose {
  grid-column: 1;
  max-width: 46ch;
  font-size: clamp(1rem, 1.15vw, 1.15rem);
  line-height: 1.55;
  color: var(--muted);
  margin: 1.6rem 0 0;
}
html.plaques #demarche.plaque .cerveau {
  position: static !important;
  grid-column: 2;
  grid-row: 2 / 4;
  width: 100%;
  max-width: 480px;
  height: auto;
  bottom: auto !important;
  right: auto !important;
  transform: none !important;
  justify-self: end;
  opacity: 1 !important;
}
html.plaques #demarche.plaque .cerveau img {
  width: 100%;
  height: auto;
  -webkit-mask-image: none !important;
  mask-image: none !important;
}
@media (max-width: 860px) {
  html.plaques #demarche.plaque {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto 1fr;
    text-align: center;
  }
  html.plaques #demarche.plaque .cerveau {
    grid-column: 1; grid-row: 3;
    max-width: 320px; justify-self: center; opacity: 0.35 !important;
  }
  html.plaques #demarche.plaque h2,
  html.plaques #demarche.plaque .prose { grid-column: 1; margin-left: auto; margin-right: auto; }
}

/* ============================================================
   PLAQUE 6 « REDUIRE AU NECESSAIRE » — refaite le 2026-08-23.
   Sequence : titre en gros -> glacon traverse -> il sort a droite ->
   texte pulse -> 01 penche gauche -> 02 penche droite -> 03 tombe.
   Plus de ligne horizontale entre les points. Les chiffres grossissent
   chacun avec leur propre inclinaison. */
html.plaques #reduire.plaque {
  display: flex !important;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 3vh;
  padding: clamp(3rem, 8vh, 6rem) 5vw !important;
}
html.plaques #reduire .voie .ligne { display: none !important; }
html.plaques #reduire .voie {
  width: 100%;
  max-width: 1100px;
  margin-top: 1vh;   /* rapprochee du titre (2026-08-24) */
}
html.plaques #reduire.active .etapes {
  display: grid !important;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 3rem;
  padding: 0 2vw;
  list-style: none;
  margin: 0;
}
html.plaques #reduire.active .etapes li {
  text-align: center;
  position: relative;
  /* les pastilles mauves sont parties (2026-08-24) : « juste le texte qui
     grossit, ca rend ca clair » — la reserve au-dessus sert au chiffre
     grossi, rien d'autre */
  padding-top: 2.1rem;
}
html.plaques #reduire.active .etapes .no {
  display: block;
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  color: var(--muted);
  margin-bottom: 0.8rem;
  transition: transform 0.7s var(--vite), color 0.5s ease, font-size 0.7s ease;
  transform-origin: center bottom;
}
html.plaques #reduire.active .etapes h3 {
  font-size: clamp(1.2rem, 1.8vw, 1.6rem);
  margin-bottom: 0.6rem;
  transition: color 0.5s ease, transform 0.7s var(--vite);
}
html.plaques #reduire.active .etapes p {
  color: var(--muted);
  font-size: clamp(0.85rem, 1vw, 1rem);
  line-height: 1.5;
}
/* Angles distinctifs pour chaque chiffre en position GRAND
   1 : penche vers la gauche
   2 : penche vers la droite
   3 : tombe (rotation exagerée + descend legerement) */
html.plaques #reduire.active .etapes li:nth-child(1).grand .no {
  transform: scale(3.5) rotate(-12deg);
  color: #ffffff;
}
html.plaques #reduire.active .etapes li:nth-child(2).grand .no {
  transform: scale(3.5) rotate(11deg);
  color: #ffffff;
}
html.plaques #reduire.active .etapes li:nth-child(3).grand .no {
  transform: scale(3.5) rotate(-9deg) translateY(0.3em);
  color: #ffffff;
}
html.plaques #reduire.active .etapes li.grand h3 {
  color: var(--accent-clair);
}
/* LE TITRE PLEIN EST RETIRE (2026-08-24) — Sebastien : « retire le texte du
   haut Reduire au necessaire, grossis le texte avec les pixels. » Le bloc qui
   vit ici forcait `position: static` et `clip-path: none` sur .titre-reel,
   ce qui le rendait visible EN PLUS du canvas : deux fois le meme titre. Il
   datait d'avant le retour des particules (2026-08-24) et n'avait pas ete
   nettoye. Sans lui, `.particules-boite.actif .titre-reel` reprend la main :
   le h2 redevient un titre lu par les lecteurs d'ecran, invisible a l'oeil,
   et le canvas porte seul le titre. NE PAS le reintroduire.
   La vraie page n'est pas touchee : elle utilise #v-particules-boite. */
html.plaques #reduire.active .particules-boite {
  text-align: center;
  min-height: 0;
  position: relative;
}
/* (le canvas des particules est ALLUME depuis le 2026-08-24 — la regle qui le cachait a ete retiree, attrapee par le controle P33) */
@keyframes titre-pulse {
  0%, 100% { transform: scale(1); filter: drop-shadow(0 0 24px rgba(168, 85, 247, 0.3)); }
  50%      { transform: scale(1.03); filter: drop-shadow(0 0 40px rgba(168, 85, 247, 0.55)); }
}
html.plaques #reduire.active .sous {
  font-size: clamp(1rem, 1.15vw, 1.2rem);
  color: var(--muted);
  margin-top: 1rem;
  opacity: 1 !important;
  transform: none !important;
}

/* ============================================================
   PLAQUE 4 (PROVOLU + bande) — remise en ordre le 2026-08-23.
   Sebastien : « en plein centre de l'ecran, plus bas, il doit y avoir le
   Provolu. La barre defile centree, apparition en zoom, reduite de 20 % en
   hauteur. Quand je defile, la barre bouge. A l'arret, elle s'arrete. » */

/* PROVOLU descend un peu et n'est plus coupe */
html.plaques .plaque-marque .geant {
  font-size: clamp(3.5rem, 12vw, 9rem) !important;
  padding: 0 5vw;
  animation: geant-zoom-arrive 1s ease-out 0.2s both;
}
@keyframes geant-zoom-arrive {
  0%   { transform: scale(0.6); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

/* La bande : hauteur -20 %, contenu centre */
html.plaques .plaque-marque .bande {
  padding: 0.8rem 0 !important;    /* etait 1,5rem : -47 % de hauteur */
  animation: bande-zoom-arrive 0.9s ease-out 0.5s both;
}
@keyframes bande-zoom-arrive {
  0%   { transform: scale(0.85); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}
html.plaques .plaque-marque .bande .piste {
  justify-content: center;
  min-width: 100%;
}

/* LA BANDE BOUGE EN PERMANENCE — Sebastien, 2026-08-24, INVERSANT sa
   consigne du 23 (« a l'arret, elle ne bouge pas ») : « si je ne scrolle
   pas, la barre doit rester toujours en mouvement. » Elle rejoint les
   matieres vivantes (glacon qui danse, cerveau qui bat) : elles bougent
   seules, aucune ne fait avancer la scene. */

/* ============================================================
   PLAQUE 5 (Cerveau) — retouche 2026-08-23.
   Sebastien : « le texte est beaucoup trop loin a gauche et le cerveau
   beaucoup trop loin a droite. Le texte doit etre plus haut. Le cerveau
   legerement plus petit. Etoiles et scintillement plus visibles. Vibration
   legerement reduite. » */
html.plaques #demarche.plaque {
  padding: 6vh 0 !important;
  grid-template-columns: 1.1fr 1fr !important;
  gap: 1rem !important;
  max-width: 1400px;
  margin: 0 auto;
  align-items: start !important;
  align-content: start;
  justify-items: end;
}
html.plaques #demarche.plaque .entete {
  padding: 0 5vw !important;
  margin-bottom: 3vh;
  width: 100%;
}
html.plaques #demarche.plaque h2 {
  padding-left: 5vw !important;
  padding-right: 0 !important;
  justify-self: end;
  margin-top: 2vh !important;
  max-width: 640px;
}
/* UNE SEULE GOUTTIERE (2026-08-24, recommandation de lea et de la revue,
   approuvee par Sebastien : « les petites ameliorations qui ont ete jugees
   importantes par les agents »). Le `padding-left: 5vw` decalait le
   paragraphe d'environ 110 px par rapport au titre : ni aligne, ni
   franchement decale — ca se lisait comme mou. Titre et paragraphe
   partent maintenant de la meme colonne. */
html.plaques #demarche.plaque .prose {
  padding-left: 0 !important;
  justify-self: end;
  max-width: 480px;
  margin-top: 4vh !important;
}
/* Le cerveau : plus petit, plus pres du texte (justify-self start au lieu
   de end : il colle a la gauche de sa colonne, plus proche du texte). */
html.plaques #demarche.plaque .cerveau {
  justify-self: start !important;
  max-width: 380px !important;
  margin-top: 4vh !important;
  margin-left: 0;
}
/* LE BATTEMENT REVIENT AU GESTE — Sebastien, 2026-08-24 : « a chaque fois
   que je scrolle, ca cree le battement de coeur deux fois. Trois fois
   deux. » Un geste = UN double coup (classe .bat posee par le JS), a moitie
   d'amplitude. La vraie page, elle, garde le battement continu aux 2 s —
   matiere vivante d'une page normale. */
.vernis .cerveau img.bat { animation: cerveau-bat-un 0.9s ease-in-out 1; }
@keyframes cerveau-bat-un {
  0%, 100% { transform: scale(1); }
  26%      { transform: scale(1.017); }   /* le premier coup */
  46%      { transform: scale(1.003); }
  62%      { transform: scale(1.011); }   /* le second, plus faible */
  82%      { transform: scale(1); }
}
.vraie .cerveau img { animation: cerveau-bat-doux 2s ease-in-out infinite; }
@keyframes cerveau-bat-doux {
  0%, 74%, 100% { transform: scale(1); }
  78%           { transform: scale(1.017); }
  82%           { transform: scale(1.003); }
  86%           { transform: scale(1.011); }
  92%           { transform: scale(1); }
}
/* la prose du cerveau se tape a la dactylo, apres le premier battement */
#demarche .prose { min-height: 7.5em; }
#demarche .prose .curseur {
  display: inline-block; width: 0.08em; height: 0.95em; margin-left: 0.06em;
  background: currentColor; vertical-align: text-bottom; opacity: 0.75;
}
html.anim #demarche .prose .curseur { animation: curseur-bat 1s steps(1) infinite; }

/* Etincelles PLUS VISIBLES au coeur du cerveau. Sebastien : « des etoiles
   a l'interieur et des points qui scintillent ». On monte l'opacite base
   et la brillance. */
html.plaques .cerveau .etincelles {
  opacity: 0.65 !important;
  filter: blur(0.3px) brightness(1.3);
}
html.plaques .cerveau .etincelles::before,
html.plaques .cerveau .etincelles::after {
  opacity: 0.9;
}

/* ============================================================
   LES TROIS REPERES PERMANENTS — 2026-08-23
   Ils vivent hors des plaques, donc ils ne s'effacent jamais avec elles. */

/* 1. LE PORTAIL : INVISIBLE AU REPOS — Sebastien, 2026-08-24 : « le portail
      ne devrait pas apparaitre. Il devrait apparaitre juste quand ma souris
      va par-dessus. » Le repere permanent du 23 au soir est retire ; il ne
      reste que le coin secret (zone invisible) qui revele le lien au
      survol. Un seul objet, jamais deux. */

/* 2. LA JAUGE passe a GAUCHE et devient plus discrete.
      « La barre de defilement avec les petits points pour les steps doit
      etre un peu plus discrete. On va la mettre a gauche. » */
.jauge {
  right: auto !important;
  left: clamp(1rem, 2vw, 2rem) !important;
  gap: 0.28rem !important;
}
.jauge .cran { width: 12px !important; height: 1px !important; opacity: 0.22 !important; }
.jauge .cran.la { opacity: 0.75 !important; }
/* « on n'aurait pas besoin d'avoir les bords de defilement quand on est
   rendu dans la page complete » (2026-08-25). BUG REEL, pas un ajustement :
   .plaques et .demarre restent sur <html> apres la bascule (rien ne les
   retire), donc cette regle (3 classes, specificite 0,3,1) battait
   `html.vraie-page .jauge { opacity: 0 !important; }` (2 classes,
   specificite 0,2,1) malgre le !important des deux cotes — la specificite
   la plus haute gagne avant le !important. Le :not() exclut vraie-page
   pour de bon plutot que de rivaliser en specificite a chaque ajout futur. */
html.plaques.demarre:not(.vraie-page) .jauge { opacity: 0.4 !important; }

/* 3. LE SAUT, en bas a droite, tres discret.
      « Puis a droite dans le coin en bas. Ca va etre un skip-it, mais tres
      discret, qui va apparaitre. » */
/* LES DEUX SORTIES partagent un seul conteneur fixe : sans lui, deux
   boutons `position: fixed` sur le meme coin se recouvrent des que le
   texte de l'un change de largeur. */
.sorties {
  position: fixed;
  bottom: clamp(1rem, 2vh, 1.5rem);
  right: clamp(1rem, 2vw, 2rem);
  z-index: 90;
  display: flex;
  gap: clamp(0.9rem, 2.4vw, 1.6rem);
  align-items: center;
}

.saut {
  z-index: 90;
  font-family: var(--mono);
  /* 0,56rem (9 px) a opacite 0,3 donnait 1,51:1 sur le fond — illisible,
     et c'est la SORTIE DE SECOURS (2026-08-25, audit lea). AA demande
     4,5:1. « Discret » ne veut pas dire invisible. */
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0.4rem 0.2rem;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.7s ease, color 0.25s ease;
}
/* LES SORTIES ARRIVENT 10 s APRES LA SCENE DU GLACON — Sebastien,
   2026-08-31 : « le bouton skip, puis couper le son, dans le bas a droite,
   ne devrait pas apparaitre. Ca devrait apparaitre juste 10 secondes apres
   etre tombe sur la page d'accueil avec le cube [...] l'objectif, c'est de
   creer le feeling avec l'usager. »
   L'HISTOIRE DE CETTE LIGNE, pour ne pas la refaire une quatrieme fois :
   apparition a 5 s le 2026-08-24 (« ne pas encourager le skip, mais ne pas
   enfermer si le chargement traine »), puis presence immediate le
   2026-08-30 a la bascule en page d'accueil (audit sophie : cinq secondes
   sans issue au moment exact ou un prospect froid decide de rester).
   Ce qui change aujourd'hui, et qui repond a sophie : le compte a rebours
   ne part plus de l'OUVERTURE mais de `charge-fini` — l'instant ou la
   scene du glacon se montre. Le visiteur a deja franchi le clic et le
   decompte : il n'est plus en train de decider s'il reste.
   CE QUE CA COUTE, dit franchement : entre l'ouverture et la 10e seconde
   du glacon (~15 a 20 s au pire, filet du decompte compris), la souris n'a
   aucune sortie. Le clavier en garde une — les deux boutons restent dans
   l'ordre de tabulation, et `pointer-events` ne bloque pas le focus.
   `html.saut-la` reste le seul selecteur : la minuterie vit dans
   accueil.js, fonction `decompte`. Un seul endroit a changer. */
html.saut-la .saut { opacity: 0.62; pointer-events: auto; }   /* 1,51:1 -> ~4,6:1 (AA) */
.saut:hover, .saut:focus-visible { opacity: 0.85; color: var(--accent-clair); }
/* SOURDINE ACTIVE : l'etat se voit, il ne se devine pas. `aria-pressed`
   le dit aux lecteurs d'ecran, la couleur le dit a l'oeil. */
html.saut-la .saut-son[aria-pressed="true"] { opacity: 0.85; color: var(--accent-clair); }

/* LA SOURDINE DEVIENT UNE ICONE — Sebastien, 2026-08-31 : « ca ne sort pas
   couper le son. On va juste mettre un p'tit speaker avec un p'tit X dessus
   qu'on peut highlighter. »
   L'ICONE MONTRE LE GESTE, PAS L'ETAT — comme le faisait le texte, qui
   disait « Couper le son » quand le son jouait. Son actif : haut-parleur
   barre (l'action offerte est de couper). Son coupe : haut-parleur avec ses
   ondes (l'action offerte est de remettre). Le mot n'est pas perdu : il vit
   dans `aria-label` et dans `title`, poses par accueil.js a chaque bascule.
   `currentColor` partout : l'icone herite du survol de `.saut`, donc elle
   s'eclaire exactement comme le texte s'eclairait. */
.saut-son,
.saut-fleche { display: flex; align-items: center; padding: 0.35rem 0.25rem; }
/* LA FLECHE DU SAUT (2026-08-31) — meme taille, meme trait, meme reponse au
   survol que la sourdine : ce sont deux boutons du meme coin, ils doivent
   se lire comme une paire et non comme deux objets qui se sont trouves la.
   `stroke` en `currentColor` : la couleur d'accent du survol, deja portee
   par `.saut:hover`, traverse jusqu'au trait. */
.icone-saut {
  width: 19px; height: 19px; display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icone-son { width: 19px; height: 19px; display: block; overflow: visible; }
.icone-son .corps { fill: currentColor; stroke: none; }
.icone-son .ondes path,
.icone-son .croix path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}
.saut-son .ondes { display: none; }
.saut-son[aria-pressed="true"] .croix { display: none; }
.saut-son[aria-pressed="true"] .ondes { display: inline; }

/* PASSER L'INTRO DEMANDE UNE CONFIRMATION — Sebastien, 2026-08-31 : « on va
   dire : es-tu certain que tu veux passer l'intro ? Oui — puis ca va passer
   a la suivante. » Le bouton est une sortie de secours dans un coin qu'on
   frole : un clic distrait coutait toute l'experience, et rien ne la
   rejouait sinon le logo de la fin.
   Le panneau est en `position: absolute` DANS `.sorties` (qui est fixed,
   donc bloc conteneur) : il flotte au-dessus des deux boutons sans entrer
   dans leur ligne flex, qui garderait sa largeur sinon. */
.saut-confirme {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.8rem);
  width: max-content;
  max-width: min(76vw, 22rem);
  padding: 0.95rem 1.05rem;
  text-align: right;
  background: rgba(8, 4, 16, 0.94);
  border: 1px solid rgba(168, 85, 247, 0.28);
  border-radius: 12px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
}
.saut-confirme[hidden] { display: none; }
.saut-question {
  margin: 0 0 0.75rem;
  font-size: 0.84rem;
  line-height: 1.4;
  color: var(--text);
}
.saut-choix { display: flex; gap: 0.55rem; justify-content: flex-end; }
.saut-choix button {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: none;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.saut-choix .saut-oui { border-color: rgba(168, 85, 247, 0.5); color: var(--accent-clair); }
.saut-choix button:hover,
.saut-choix button:focus-visible { color: var(--text); border-color: rgba(255, 255, 255, 0.42); }

/* « La bibliotheque complete » n'est PAS atteignable depuis la plaque du
   carrousel. Le <p> reste : il sert d'ancre a la trajectoire du cube. */
html.plaques #travaux .biblio .hors-plaque {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}
html.plaques #travaux .biblio { min-height: 1.4rem; margin-top: 1.4rem; }

/* ============================================================
   LES TROUS — remis a la dimension du splash screen. 2026-08-23.
   Sebastien : « le trou doit etre beaucoup plus petit, la meme dimension
   que sur la page splash screen. » Le splash utilise --trou-taille (150px). */

/* PLAQUE 9 — la sortie. Le trou ou le cube tombe. */
html.plaques .trou-sortie-plaque {
  width: var(--trou-taille) !important;
  height: auto !important;
  aspect-ratio: 560 / 197;
}
html.plaques .trou-sortie-plaque .anneau { width: 100% !important; }
html.plaques .trou-sortie-plaque .gouffre {
  width: 62% !important;
  height: 44% !important;
  box-shadow:
    inset 0 0 14px 4px rgba(120, 60, 200, 0.4),
    inset 0 0 34px 14px #000 !important;
}

/* PLAQUE 11 — le final. Sebastien : « le dessin du trou devrait pas
   apparaitre. C'est une video qui doit apparaitre en background avec fond.
   La video doit etre plus petite dans l'ecran. »
   L'anneau dessine s'efface donc ici : c'est la video qui porte la scene. */
html.plaques #final .trou-final {
  width: min(340px, 62vw) !important;
  opacity: 1;
}
html.plaques #final .trou-final .anneau { opacity: 0 !important; }
html.plaques #final .trou-final .gouffre { display: none; }
html.plaques #final .trou-final video {
  left: -14%;
  top: -46%;
  width: 128%;
  opacity: 0;
  transition: opacity 0.9s ease;
}
html.plaques #final .trou-final.fond video { opacity: 1; transform: none; }
html.plaques #final .trou-final .marque-finale { width: 54%; top: -30%; }
html.plaques #final .scene-video {
  max-width: 420px;
  margin: 0 auto;
  padding: 1.5rem 1rem 2.5rem;
}

/* La jauge aussi doit passer devant une plaque a fond noir. */
.jauge { z-index: 90 !important; }

/* ============================================================
   LA BASCULE VERS LA VRAIE PAGE — le verrou se leve. 2026-08-23.
   `html.plaques` posait `overflow: hidden !important` : il survivait a la
   bascule et la vraie page restait bloquee. Sebastien : « quand je suis
   rendu au bout, je ne reussis pas a tomber en dehors des cartes avec le
   fondu, puis a voir le bouton en bas de page. » */
html.plaques.vraie-page,
html.plaques.vraie-page body {
  overflow: visible !important;
  height: auto !important;
}
/* LA PLAQUE ACTIVE S'ETEINT VRAIMENT A LA BASCULE. `visibility` et
   `pointer-events` poses par un enfant REACTIVENT ce que le parent eteint :
   le vernis etait a opacite 0, mais la plaque 11 — fixe, « visible »,
   cliquable — continuait d'intercepter les clics par-dessus la vraie page.
   Constate le 2026-08-24 : elementFromPoint retournait la plaque. Meme
   fondu (1,1 s), puis elle disparait pour de bon. */
html.vraie-page .plaque.active {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  transition: opacity 1.1s ease, visibility 0s linear 1.1s;
}
/* Les reperes de l'intro n'ont plus de raison d'etre : la vraie page porte
   son propre en-tete et son propre portail. Le coin secret du splash non
   plus — il recouvrait le lien « Portail client » du vrai en-tete. */
/* `visibility: hidden` AJOUTE le 2026-08-31 (audit lea, verifie a
   l'execution). `opacity: 0` seul ne retire pas du parcours au clavier :
   sur la vraie page, `#muet` et `#saut` restaient focusables
   (document.activeElement les recevait), sans anneau de focus — le
   `!important` d'ici battant aussi `.saut:focus-visible`. Un usager clavier
   pouvait donc activer « Passer l'intro » a l'aveugle et ouvrir sa boite de
   confirmation par-dessus la vraie page. `pointer-events: none` n'arrete
   que la souris ; c'est `visibility` qui retire du parcours. */
html.vraie-page .portail-coin,
html.vraie-page .sorties,
html.vraie-page .saut,
html.vraie-page .jauge,
html.vraie-page .cue-suite {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}
html.vraie-page .coin-secret,
html.vraie-page .portail-surgi { display: none !important; }

/* ============================================================
   PLAQUE 4 — REFAITE AU PROPRE, 2026-08-23 (2e passe).
   La grille en trois rangees laissait PROVOLU en haut a GAUCHE et la bande
   decentree. Sebastien : « en plein centre de l'ecran, plus bas, il doit y
   avoir le Provolu. Il doit y avoir la barre qui defile. Elle doit etre
   centree, elle ne devrait pas etre decentree comme en ce moment. »
   Une colonne centree, rien d'autre. Ce bloc arrive apres tous les autres :
   c'est lui qui gagne. */
html.plaques .plaque-marque {
  display: flex !important;
  flex-direction: column !important;
  align-items: center !important;
  justify-content: center !important;
  grid-template-rows: none !important;
  gap: 3vh !important;
  padding: 0 !important;
  padding-top: 6vh !important;      /* « plus bas » : le groupe descend un peu */
  max-width: none !important;
}
html.plaques .plaque-marque .geant-scene {
  grid-row: auto !important;
  height: auto !important;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
html.plaques .plaque-marque .geant {
  text-align: center !important;
  padding: 0 4vw !important;
  margin: 0 auto !important;
  /* « legerement plus gros » (2026-08-24) : +10 % */
  font-size: clamp(3.4rem, 11.6vw, 9.4rem) !important;
  line-height: 0.95;
}
/* La bande : pleine largeur d'ecran, vraiment centree, -20 % de hauteur. */
html.plaques .plaque-marque .bande {
  grid-row: auto !important;
  align-self: center !important;
  position: relative;
  left: auto !important;
  width: 100% !important;
  max-width: none !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  /* encore plus basse (2026-08-24) */
  padding: 0.5rem 0 !important;
  overflow: hidden;
  /* elle nait et meurt dans le noir : fondu aux deux bords, ce qui la fait
     LIRE centree meme a pleine largeur (2026-08-24) */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 9%, #000 91%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, #000 9%, #000 91%, transparent 100%);
}
html.plaques .plaque-marque .bande .piste {
  justify-content: center;
  width: max-content;
  margin: 0 auto;
}

/* (Les entetes de plaques sont partis le 2026-08-24 : « on focus sur un
   effet premium ». La structure 01/02/03 vit dans la vraie page.) */
html.plaques #demarche.plaque { padding-top: 2vh !important; }

/* ============================================================
   PLAQUE 7 — les trois facons se SUPERPOSENT. 2026-08-23.
   Elles s'empilaient : 1 063 px de haut dans un ecran de 745 px, l'entete
   sortait par le haut a y = -180 et tout finissait en haut a gauche.
   La liste arretee dit « une carte, trois icones qui apparaissent l'une
   apres l'autre » — donc UNE seule occupe la scene, et elles partagent la
   meme place. */



/* ============================================================
   REPRISE DU 2026-08-24 — le socle decoupe en douze plaques (C-095).
   Ce qui suit complete la reprise ; les valeurs viennent du devis
   (les douze fiches) et de CONSIGNES.md. */

/* LA JAUGE, douze traits : 0,22 a venir, 0,75 passees, pleine pour la
   plaque courante. Les valeurs de base (12 x 1 px, a gauche) vivent dans
   le bloc des trois reperes. */
.jauge .cran.courante { opacity: 1 !important; background: var(--accent-clair); }

/* AUCUNE CARTE VISIBLE DU CARROUSEL N'EST MORTE AU TOUCHER — l'heritiere
   de la garantie de la pile du 23 aout. Le JS pose pointer-events en style
   en ligne sur les cartes hors champ ; les cartes VISIBLES (centre et
   cotes) reprennent la main ici, en CSS : la garantie tient meme si le JS
   se trompe d'etat. */
.travail.centre, .travail.cote { pointer-events: auto !important; }

/* « FAIRE REVIVRE LE CUBE » et le portail, dans le pied de la VRAIE page
   (fiche P12). Pas de revelation a retarder ici : une page normale montre
   son pied de page. */
.vraie .footer-centre { display: flex; align-items: center; gap: 1.4rem; flex-wrap: wrap; justify-content: center; }
.vraie .revivre { opacity: 1; pointer-events: auto; transform: none; }
/* L'en-tete de la vraie page partage le nom .topbar avec la barre de
   l'intro : on neutralise ce que l'intro lui imposait — styles.css fait le
   reste (sticky, z-index, menu). */
.vraie .topbar { transform: none; }

/* Le P de la vraie page : statique, avec sa lueur — pas de video ici. */
.vraie .p-vraie { display: flex; justify-content: center; }
.vraie .p-vraie .marque-finale {
  position: static;
  width: clamp(160px, 18vw, 240px);
  background: none; border: 0; padding: 0; cursor: pointer;
  opacity: 1; transform: none;
  filter: drop-shadow(0 0 30px rgba(168, 85, 247, 0.6));
}
.vraie .p-vraie .marque-finale img { width: 100%; height: auto; display: block; }
/* la vraie page garde ses vides volontaires */
.vraie .respire { height: 27.5vh; }
.vraie .respire-noir { height: 42.5vh; }

/* un geste absorbe par le tempo (1 s minimum entre deux) : le cue respire
   un coup, pour dire « recu, la scene se joue » */
.cue-suite.tic { color: var(--accent-clair); }
.cue-suite.tic::after { animation: cue-bat 0.35s ease-in-out 2; }

/* LE FONDU EST LA SEULE TRANSITION ENTRE PLAQUES — Sebastien, 2026-08-24 :
   « les images apparaissent par en arriere en fade in ». Aucune plaque ne
   glisse ; la suivante apparait derriere, en fondu. C'est deja ce que fait
   `html.plaques .plaque` (transition d'opacite seule) — cette note fixe la
   consigne pour qu'aucun futur reglage n'y ajoute un deplacement. */

/* ============================================================
   LE TELEPHONE, EN DERNIER MOT. Ce bloc vit en FIN de feuille parce que
   plusieurs blocs de plaque posent des !important : a specificite egale,
   c'est l'ordre qui tranche, et le telephone doit gagner. Une plaque tient
   dans UN ecran de 390 x 844 — on compresse, on ne retire rien. */
@media (max-width: 860px) {
  /* plaque 5 : une colonne centree — le titre, la prose, le cerveau */
  html.plaques #demarche.plaque {
    grid-template-columns: 1fr !important;
    padding: 2vh 6vw 3vh !important;
    align-items: center !important;
    align-content: center !important;
    justify-items: center !important;
  }
  html.plaques #demarche.plaque .entete { padding: 0 !important; margin-bottom: 1.5vh; }
  html.plaques #demarche.plaque h2 {
    grid-column: 1 !important; grid-row: auto !important;
    padding: 0 !important; margin: 0 !important;
    justify-self: center !important; text-align: center;
    font-size: clamp(1.7rem, 8.2vw, 2.5rem) !important;
    max-width: 16ch;
  }
  html.plaques #demarche.plaque .prose {
    grid-column: 1 !important; grid-row: auto !important;
    padding: 0 !important; margin: 2vh 0 0 !important;
    justify-self: center !important; text-align: center;
    font-size: 0.95rem !important;
    max-width: 36ch;
  }
  html.plaques #demarche.plaque .cerveau {
    grid-column: 1 !important; grid-row: auto !important;
    justify-self: center !important;
    margin: 2.5vh 0 0 !important;
    max-width: min(50vw, 230px) !important;
    opacity: 1 !important;
  }
  /* plaque 4 : PROVOLU un peu plus haut, la bande respire */
  html.plaques .plaque-marque { padding-top: 0 !important; gap: 4vh !important; }
  /* plaque 6 : titre et chiffres tiennent dans l'ecran, sans se croiser.
     Les chiffres grossis a 3,5 se chevauchaient entre colonnes de 110 px —
     1,7 suffit a l'echelle du telephone, chacun garde son angle. */
  html.plaques #reduire.plaque { padding: 2vh 4vw !important; gap: 2vh !important; }
  html.plaques #reduire .voie { margin-top: 3.5vh !important; }
  html.plaques #reduire.active .etapes li:nth-child(1).grand .no { transform: scale(1.7) rotate(-12deg) !important; }
  html.plaques #reduire.active .etapes li:nth-child(2).grand .no { transform: scale(1.7) rotate(11deg) !important; }
  html.plaques #reduire.active .etapes li:nth-child(3).grand .no { transform: scale(1.7) rotate(-9deg) translateY(0.2em) !important; }
  html.plaques #reduire.active .etapes li.grand .noeud {
    box-shadow: 0 0 16px 4px rgba(255, 255, 255, 0.7), 0 0 32px 10px rgba(168, 85, 247, 0.35) !important;
  }
  /* plaque 11 : la video et les coordonnees, sans chevauchement */
  html.plaques #final .scene-video { max-width: min(320px, 78vw); padding: 1rem 0 1.5rem; }
  /* la plaque finale au telephone (2026-08-25) : les deux colonnes
     texte / video n'ont pas la place cote a cote dans 375 px — le texte se
     faisait ecraser a ~80 px. Empilees, centrees, comme le reste. */
  html.plaques #p-final {
    grid-template-columns: 1fr !important;
    justify-items: center !important;
    text-align: center !important;
    gap: 3vh !important;
    padding: 2vh 6vw !important;
  }
  html.plaques #p-final .final-gauche { justify-items: center; }
  #p-final .final-avant .sous { margin-left: auto; margin-right: auto; }
}
