/* ===========================================================================
   allume-toi.com — feuille de style de production
   ---------------------------------------------------------------------------
   Charte reprise de l'affiche « Ligne Allume-toi » : papier gris clair, encre
   noire au pinceau, rouge signature, plaques de station, ligne verticale.
   Les éléments signés ne sont pas redessinés — ils sont découpés dans
   l'affiche elle-même (voir tools/build-img.py).
   =========================================================================== */

/* ---- Polices, hébergées localement --------------------------------------
   Pas d'import Google Fonts : l'appel au CDN transmettrait l'IP des visiteurs
   à un tiers, ce qui a valu des condamnations en Europe. Oswald est une
   police variable — un seul fichier couvre toutes les graisses.            */
@font-face {
  font-family: 'Oswald';
  src: url('../assets/fonts/oswald-var-latin.woff2') format('woff2-variations');
  font-weight: 200 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Source Sans 3';
  src: url('../assets/fonts/sourcesans3-400-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('../assets/fonts/ibmplexmono-500-latin.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}

/* ---- Jetons -------------------------------------------------------------- */
:root {
  /* Mesurés sur l'affiche : papier #E2DED8 → #EFECE6 une fois éclairci pour
     tenir le contraste du texte, encre #000, rouge #D50000.                */
  --papier:      #EFECE6;
  --papier-fonce:#E2DED8;
  --encre:       #0B0B0B;
  --encre-douce: #3A3A38;
  --rouge:       #D40000;   /* 5,5:1 sur le papier — au-dessus du seuil AA */
  --rouge-sombre:#A00000;
  --blanc:       #FFFFFF;

  --ease: cubic-bezier(.22,.61,.36,1);

  --marge: clamp(20px, 5.2vw, 96px);

  /* Réglage du voile. Le dégradé part de la gauche et meurt à --voile-fin ;
     --haut-h est la hauteur du voile sous le logo. Ce sont les deux seules
     valeurs à toucher pour laisser respirer davantage la vidéo.
     V2 : ramenés de 64 % à 48 % et de 190 px à 130 px, et les opacités
     baissées d'environ un cinquième — le dessin du wagon reprend la main
     sans que les plaques ni la ligne perdent en lisibilité.               */
  --voile-fin: 48%;
  --haut-h: 130px;

  --plaque-w: min(880px, 53vw);
  --rail-w: clamp(70px, 7.4vw, 120px);
}

* { box-sizing: border-box; }
html { scroll-behavior: auto; }

body {
  margin: 0;
  background: var(--papier);
  color: var(--encre);
  font-family: 'Source Sans 3', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  /* `clip` et surtout PAS `hidden` : `overflow-x: hidden` fait du <body> un
     conteneur de défilement, et une scène en `position: sticky` cesse alors
     de coller — la vidéo disparaissait dès le premier palier. `clip` rogne
     sans créer de conteneur. */
  overflow-x: clip;
}
a { color: inherit; }
img { max-width: 100%; }

.visuallyhidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Le grain du papier : deux turbulences superposées — une fine pour la fibre,
   une large pour les taches. Fait en CSS plutôt qu'en image : c'est sans
   couture, ça pèse zéro octet, et ça s'adapte à toutes les densités d'écran. */
.papier-grain {
  position: absolute; inset: 0; pointer-events: none;
  mix-blend-mode: multiply; opacity: .5;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='f'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4'/><feColorMatrix type='saturate' values='0'/></filter><rect width='220' height='220' filter='url(%23f)' opacity='.55'/></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='700' height='700'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='.011' numOctaves='3'/><feColorMatrix type='saturate' values='0'/></filter><rect width='700' height='700' filter='url(%23g)' opacity='.30'/></svg>");
  background-size: 220px 220px, 700px 700px;
}

/* =========================================================================
   LE DÉFILEUR — la vidéo est fixe, les stations s'inscrivent par-dessus
   ========================================================================= */
.scroller { position: relative; }

.stage {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  overflow: hidden;
  background: var(--papier);
}

.stage__media { position: absolute; inset: 0; }
.stage__media img,
.stage__media video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
/* L'affiche fixe reste visible tant que la vidéo n'a pas peint sa première
   image — surtout sur iPhone, où elle peut ne jamais y arriver. */
.stage__media video { opacity: 0; transition: opacity .3s linear; }
.stage.is-video .stage__media video { opacity: 1; }

/* ---- Le voile : cinq couches, dans cet ordre --------------------------- */
/* 1. plancher — ramène toute la vidéo dans la même plage de valeurs claires
      AVANT le dégradé, sinon les passages sombres du wagon assombrissent le
      côté gauche de façon irrégulière. */
.plancher  { position: absolute; inset: 0; background: rgba(255,255,255,.10); }
/* 2. dégradé latéral depuis le bord gauche, qui meurt avant le bord droit */
.voile     { position: absolute; inset: 0;
             background: linear-gradient(90deg,
               rgba(239,236,230,.90) 0%,
               rgba(239,236,230,.80) calc(var(--voile-fin) * .26),
               rgba(239,236,230,.50) calc(var(--voile-fin) * .54),
               rgba(239,236,230,.16) calc(var(--voile-fin) * .80),
               rgba(239,236,230,0)   var(--voile-fin)); }
/* 3. rive droite, sous la ligne de métro */
.rive      { position: absolute; right: 0; top: 0; bottom: 0;
             width: clamp(150px, 16vw, 300px);
             background: linear-gradient(270deg,
               rgba(239,236,230,.97) 0%, rgba(239,236,230,.76) 44%,
               rgba(239,236,230,0) 100%); }
/* 4. bandeau haut, sous le logo */
.bandeau   { position: absolute; left: 0; right: 0; top: 0; height: var(--haut-h);
             background: linear-gradient(180deg,
               rgba(239,236,230,.82) 0%, rgba(239,236,230,.40) 46%,
               rgba(239,236,230,0) 100%); }
/* 5. le grain, par-dessus tout — c'est lui qui recolle la vidéo au papier */

/* Exception : le palier de présentation. Les neuf stations posent leur titre
   sur une plaque noire, qui tient sur n'importe quel fond ; celui-ci pose un
   paragraphe de dix lignes à même l'image. Le voile allégé demandé pour les
   stations le rendait illisible dès que la rame passe sur les passagers.
   Ce palier-là — et lui seul — garde un voile dense. */
.stage.is-intro { --voile-fin: 66%; }
.stage.is-intro .voile {
  background: linear-gradient(90deg,
    rgba(239,236,230,.975) 0%,
    rgba(239,236,230,.95)  calc(var(--voile-fin) * .30),
    rgba(239,236,230,.74)  calc(var(--voile-fin) * .58),
    rgba(239,236,230,.28)  calc(var(--voile-fin) * .82),
    rgba(239,236,230,0)    var(--voile-fin));
}
.stage.is-intro .plancher { background: rgba(255,255,255,.20); }

/* =========================================================================
   LE LOGO
   ========================================================================= */
.marque { position: absolute; left: var(--marge); top: clamp(14px, 3vh, 34px); z-index: 40; }
.marque img { display: block; width: clamp(168px, 17.5vw, 310px); height: auto; }
.marque a { display: block; }

/* =========================================================================
   LES PLAQUES DE STATION
   ========================================================================= */
.plaques { position: absolute; inset: 0; pointer-events: none; }

.plaque {
  position: absolute;
  left: var(--marge);
  bottom: clamp(76px, 12vh, 132px);
  width: var(--plaque-w);
  margin: 0;
  opacity: 0; visibility: hidden; pointer-events: none;
}
.plaque.is-on { visibility: visible; opacity: 1; pointer-events: auto; }

/* Entrée en trois temps décalés, sortie en fondu seul. */
.plaque > * {
  opacity: 0; transform: translateY(16px);
  transition: opacity .3s var(--ease), transform 0s linear .3s;
}
.plaque.is-on > * {
  opacity: 1; transform: none;
  transition: opacity .52s var(--ease), transform .52s var(--ease);
}
.plaque.is-on > *:nth-child(2) { transition-delay: .08s; }
.plaque.is-on > *:nth-child(3) { transition-delay: .15s; }
.plaque.is-on > *:nth-child(4) { transition-delay: .21s; }

/* ---- la plaque au pinceau ------------------------------------------------
   Le fond est le coup de pinceau découpé dans l'affiche, étiré aux deux
   dimensions. Étirer plutôt que répéter : un raccord serait visible dans le
   grain, alors qu'un changement d'échelle du grain ne se voit pas. En
   revanche il faut tenir le RAPPORT : la plaque de l'affiche fait 4 pour 1,
   et en dessous de 6 pour 1 à l'écran le pinceau s'écrase et perd son geste.
   C'est ce qui fixe la hauteur ci-dessous, pas le confort du texte. */
.pl-row { display: flex; align-items: center; }
.pl {
  display: inline-flex; align-items: center; gap: clamp(12px, 1.4vw, 24px);
  padding: clamp(18px, 2.7vh, 36px) clamp(32px, 3.3vw, 58px)
           clamp(22px, 3.3vh, 44px) clamp(24px, 2.4vw, 44px);
  background: url('../assets/img/plaque.png') no-repeat center / 100% 100%;
  max-width: 100%;
  transform: rotate(-.5deg);
}
/* Boîte carrée et `object-fit: contain` plutôt qu'une hauteur libre : les
   icônes n'ont pas du tout le même rapport — la bouche fait deux de large
   pour un de haut, le poing levé un pour deux. Réglées en hauteur, la bouche
   déborderait la plaque et le poing serait minuscule ; dans une boîte carrée,
   chacune occupe la même place. */
.pl__ico { width: clamp(38px, 4.05vw, 58px); height: clamp(38px, 4.05vw, 58px);
           object-fit: contain; flex: none; display: block; }
.pl__num {
  font: 500 clamp(11px, .82vw, 15px)/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .18em; color: var(--rouge); flex: none;
}
.pl__t {
  font: 700 clamp(22px, 2.68vw, 48px)/1.04 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .012em;
  color: var(--blanc); margin: 0; text-wrap: balance;
}

/* Le tiret de raccord vers la ligne, comme sur l'affiche. */
.raccord {
  display: block; flex: none; width: clamp(28px, 3.4vw, 62px); height: 6px;
  background: var(--encre); margin-left: -6px;
  transform: rotate(-.5deg);
  clip-path: polygon(0 14%, 96% 0, 100% 76%, 3% 100%);
}

.sous {
  font: 500 clamp(11px, .82vw, 14px)/1.5 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .2em; text-transform: uppercase; color: var(--encre);
  margin: 16px 0 0 clamp(24px, 2.4vw, 42px);
}
.sous b { color: var(--rouge); font-weight: 500; }
.sous b::after { content: "·"; color: rgba(11,11,11,.34); margin: 0 13px; }

/* ---- le bouton d'écoute -------------------------------------------------- */
.actions { display: flex; flex-wrap: wrap; gap: 12px;
           margin: clamp(16px, 2.4vh, 26px) 0 0 clamp(24px, 2.4vw, 42px); }

.btn {
  display: inline-flex; align-items: center; gap: 12px;
  border: 0; cursor: pointer;
  background: var(--rouge); color: var(--blanc);
  padding: 14px 24px; text-decoration: none;
  font: 500 clamp(11px, .78vw, 13px)/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .22em; text-transform: uppercase;
  transform: rotate(-.5deg);
  transition: background .26s var(--ease), color .26s var(--ease);
}
.btn::before { content: "\25B6"; font-size: 1.05em; line-height: 1; }
.btn:hover, .btn:focus-visible { background: var(--encre); color: var(--blanc); }
.btn--ligne { background: transparent; color: var(--encre);
              box-shadow: inset 0 0 0 2px var(--encre); }
.btn--ligne::before { content: "\2193"; }
.btn--ligne:hover, .btn--ligne:focus-visible { background: var(--encre); color: var(--papier); }

/* =========================================================================
   PALIER D'INTRODUCTION
   ========================================================================= */
.plaque--intro { width: min(880px, 52vw); bottom: clamp(80px, 14vh, 168px); }
.kicker { margin: 0 0 clamp(14px, 2vh, 24px); }
.kicker span {
  display: inline-block;
  padding: 9px 22px 12px 18px;
  background: url('../assets/img/plaque.png') no-repeat center / 100% 100%;
  color: var(--blanc); transform: rotate(-.7deg);
  font: 500 clamp(9px, .74vw, 12px)/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .24em; text-transform: uppercase;
}
.intro__t {
  font: 700 clamp(30px, 4.1vw, 78px)/1.14 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .008em;
  margin: 0; color: var(--encre); text-wrap: balance;
}
.intro__t b { color: var(--rouge); font-weight: inherit; }
.intro__p {
  font: 400 clamp(15px, 1.08vw, 20px)/1.58 'Source Sans 3', system-ui, sans-serif;
  color: var(--encre-douce); margin: clamp(16px, 2.2vh, 26px) 0 0; max-width: 60ch;
  text-wrap: pretty;
}

/* =========================================================================
   LA LIGNE — plan de métro vertical, à droite
   -------------------------------------------------------------------------
   C'est un plan : les neuf titres sont écrits en clair à côté des anneaux,
   tout le temps. En gris pâle au repos, en noir et agrandis pour la station
   courante et au survol. L'agrandissement se fait en `transform: scale` et
   non en `font-size` : à cette taille un changement de corps ferait sauter
   toute la colonne d'un pixel ou deux à chaque station.
   ========================================================================= */
.ligne {
  position: absolute; right: clamp(14px, 2.4vw, 48px); top: 50%;
  transform: translateY(-50%); z-index: 30;
  --anneau: clamp(26px, 2.6vw, 42px);
  --trait:  clamp(11px, 1.15vw, 19px);
}
.ligne__titre {
  display: block; width: max-content; margin: 0 0 clamp(18px, 3vh, 36px) auto;
  padding: 7px 15px 9px;
  background: url('../assets/img/plaque.png') no-repeat center / 100% 100%;
  color: var(--blanc); text-align: center;
  font: 500 clamp(8px, .64vw, 11px)/1.4 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .16em; text-transform: uppercase; white-space: nowrap;
  transform: rotate(-1.4deg);
}
.ligne ol {
  list-style: none; margin: 0; padding: 0; position: relative;
  display: flex; flex-direction: column; align-items: flex-end;
  gap: clamp(13px, 2.6vh, 30px);
}
/* Le trait rouge court derrière les anneaux, du premier au dernier. */
.ligne ol::before,
.ligne ol::after {
  content: ""; position: absolute;
  right: calc((var(--anneau) - var(--trait)) / 2);
  top: 16px; width: var(--trait);
  background: url('../assets/img/ligne.png') repeat-y center / 100% 92px;
}
.ligne ol::before { bottom: 16px; z-index: 0; opacity: .42; }
/* … et la portion déjà parcourue reprend sa pleine densité. */
.ligne ol::after  { height: var(--parcouru, 0px); z-index: 1;
                    transition: height .3s linear; }
.ligne li { position: relative; z-index: 2; }

.ligne button {
  -webkit-appearance: none; appearance: none; border: 0; padding: 0;
  background: transparent; cursor: pointer;
  display: flex; align-items: center; justify-content: flex-end;
  gap: clamp(10px, 1vw, 18px);
}
.ligne .anneau {
  display: block; flex: none;
  width: var(--anneau); aspect-ratio: 1;
  background: url('../assets/img/station.png') no-repeat center / contain;
  opacity: .74;
  transition: transform .34s var(--ease), opacity .34s var(--ease);
}
.ligne li.on  .anneau { opacity: 1; }
.ligne li.now .anneau { transform: scale(1.5); opacity: 1; }
.ligne button:hover .anneau,
.ligne button:focus-visible .anneau { opacity: 1; transform: scale(1.28); }
.ligne li.now button:hover .anneau { transform: scale(1.5); }

.ligne .lb {
  font: 600 clamp(9px, .76vw, 13px)/1.15 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .05em;
  color: rgba(11,11,11,.5); white-space: nowrap; text-align: right;
  transform-origin: 100% 50%;
  /* Un halo de papier autour des lettres plutôt qu'un voile plus épais
     derrière : le dessin du wagon reste visible entre les mots, et les titres
     tiennent aussi bien sur la manche blanche que sur un manteau noir. */
  text-shadow: 0 0 3px rgba(239,236,230,.95), 0 0 11px rgba(239,236,230,.85);
  transition: color .3s var(--ease), transform .3s var(--ease);
}
.ligne .lb b { font-weight: 600; color: rgba(212,0,0,.62); margin-right: 9px;
               transition: color .3s var(--ease); }
.ligne li.now .lb,
.ligne button:hover .lb, .ligne button:focus-visible .lb {
  color: var(--encre); transform: scale(1.3);
}
.ligne li.now .lb b,
.ligne button:hover .lb b, .ligne button:focus-visible .lb b { color: var(--rouge); }

/* =========================================================================
   LE REPÈRE DE DÉFILEMENT
   -------------------------------------------------------------------------
   Le geste à faire doit se voir : un compteur de station, le mot, et une
   flèche qui descend en boucle. Il reste pendant les trois premières
   stations, le temps que le geste soit compris, puis s'efface.
   ========================================================================= */
.cue {
  position: absolute; left: 50%; bottom: clamp(20px, 3.4vh, 40px);
  transform: translateX(-50%);
  margin: 0; display: flex; flex-direction: column; align-items: center; gap: 9px;
  z-index: 30; pointer-events: none;
  transition: opacity .4s var(--ease);
}
.cue.is-off { opacity: 0; }
.cue__n {
  font: 700 clamp(15px, 1.25vw, 22px)/1 'Oswald', system-ui, sans-serif;
  letter-spacing: .04em; color: rgba(11,11,11,.44);
  font-variant-numeric: tabular-nums;
}
.cue__n b { color: var(--encre); font-weight: 700; }
.cue__l {
  font: 500 clamp(9px, .72vw, 11px)/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .32em; text-transform: uppercase; color: var(--encre);
}
/* La flèche : un chevron rouge qui redescend toutes les 1,6 s. */
.cue__f {
  display: block; width: 15px; height: 15px; margin-top: 3px;
  border-right: 3px solid var(--rouge); border-bottom: 3px solid var(--rouge);
  transform: rotate(45deg);
  animation: at-descend 1.6s var(--ease) infinite;
}
@keyframes at-descend {
  0%   { transform: rotate(45deg) translate(0, 0);      opacity: .25; }
  45%  { transform: rotate(45deg) translate(5px, 5px);  opacity: 1; }
  100% { transform: rotate(45deg) translate(11px, 11px); opacity: 0; }
}

/* =========================================================================
   LE LECTEUR — une seule barre, qui survit au défilement
   -------------------------------------------------------------------------
   Un vrai <audio> : la lecture part au clic sur « Écouter ». Le dock reste
   monté, donc on peut lancer un morceau et continuer à descendre la ligne.
   ========================================================================= */
.dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
  background: var(--encre); color: var(--papier);
  padding: 11px var(--marge) calc(11px + env(safe-area-inset-bottom));
  display: flex; align-items: center; gap: clamp(12px, 1.5vw, 24px);
  transform: translateY(105%); transition: transform .42s var(--ease);
  box-shadow: 0 -12px 40px rgba(11,11,11,.20);
}
.dock.is-up { transform: none; }
.dock[hidden] { display: none; }

.dock button {
  -webkit-appearance: none; appearance: none; border: 0; background: transparent;
  color: var(--papier); cursor: pointer; flex: none; padding: 0;
  display: flex; align-items: center; justify-content: center;
  transition: color .25s var(--ease), background .25s var(--ease);
}

/* Lecture / pause — le seul bouton plein, en rouge signature.
   Sélecteur doublé : `.dock button` ci-dessus vaut une classe + un type, il
   l'emporterait sinon sur une classe seule et le carré resterait noir. */
.dock button.dock__pp {
  width: 42px; height: 42px; background: var(--rouge); color: var(--blanc);
}
.dock button.dock__pp:hover { background: var(--blanc); color: var(--encre); }
.dock__pp::before {
  content: ""; border-left: 13px solid currentColor;
  border-top: 8px solid transparent; border-bottom: 8px solid transparent;
  margin-left: 4px;
}
.dock.is-play .dock__pp::before {
  border: 0; width: 12px; height: 15px; margin: 0;
  background: linear-gradient(90deg, currentColor 0 4px, transparent 4px 8px, currentColor 8px 12px);
}

.dock__t {
  margin: 0; flex: 0 1 auto; min-width: 0;
  font: 700 clamp(12px, 1.05vw, 18px)/1.2 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .03em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dock__t b { color: var(--rouge); font-weight: 700; margin-right: 11px; }

/* La barre de position. Zone de clic haute de 18 px pour un trait de 4 px :
   viser un trait de 4 px à la souris est une épreuve. */
.dock__bar {
  flex: 1 1 120px; min-width: 60px; height: 18px; position: relative;
  cursor: pointer; display: flex; align-items: center; touch-action: none;
}
.dock__bar::before {
  content: ""; position: absolute; left: 0; right: 0; height: 4px;
  background: rgba(242,239,233,.24);
}
.dock__bar i {
  position: relative; display: block; height: 4px; width: 0;
  background: var(--rouge); pointer-events: none;
}
.dock__bar i::after {
  content: ""; position: absolute; right: -5px; top: -3px;
  width: 10px; height: 10px; background: var(--blanc);
  opacity: 0; transition: opacity .2s var(--ease);
}
.dock__bar:hover i::after, .dock__bar:focus-visible i::after { opacity: 1; }
.dock__bar:focus-visible { outline: 2px solid var(--rouge); outline-offset: 3px; }

.dock__tm {
  margin: 0; flex: none; display: flex; gap: 7px;
  font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace;
  color: rgba(242,239,233,.72); font-variant-numeric: tabular-nums;
}
.dock__tm .dock__dur::before { content: "/ "; opacity: .5; }

/* Précédent / suivant : deux chevrons, dessinés en CSS. */
.dock__pv, .dock__nx { width: 30px; height: 30px; }
.dock__pv::before, .dock__nx::before {
  content: ""; width: 9px; height: 9px;
  border-top: 2px solid currentColor; border-right: 2px solid currentColor;
}
.dock__pv::before { transform: rotate(-135deg); margin-left: 3px; }
.dock__nx::before { transform: rotate(45deg); margin-right: 3px; }
.dock__pv:hover, .dock__nx:hover, .dock__x:hover { color: var(--rouge); }

.dock__x { width: 30px; height: 30px;
           font: 500 15px/1 'IBM Plex Mono', ui-monospace, monospace; }

/* Le dock masque le bas de la scène et le bas de la page : on remonte les
   plaques d'autant, et on dégage le pied du bloc contact. */
body.a-dock .plaque  { bottom: clamp(140px, 19vh, 200px); }
body.a-dock .cue     { opacity: 0; }
body.a-dock .contact { padding-bottom: calc(clamp(30px, 5vh, 60px) + 72px); }

/* Le bouton d'une station en cours d'écoute. */
.btn.is-cur { background: var(--encre); }
.btn.is-cur::before { content: "\2193"; }
.btn.is-playing::before {
  content: ""; width: 10px; height: 12px;
  background: linear-gradient(90deg, currentColor 0 3px, transparent 3px 7px, currentColor 7px 10px);
}

/* =========================================================================
   CONTACT — après la ligne, au bout du défilement
   ========================================================================= */
.contact {
  position: relative; background: var(--papier);
  padding: clamp(48px, 8vh, 116px) var(--marge) clamp(30px, 5vh, 60px);
  border-top: 4px solid var(--encre);
  overflow: hidden;
}
.contact h2 {
  font: 700 clamp(34px, 5.4vw, 100px)/1.02 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .006em; margin: 0; max-width: 14ch;
}
.contact h2 b { color: var(--rouge); font-weight: inherit; }
.contact__p {
  font: 400 clamp(16px, 1.15vw, 21px)/1.58 'Source Sans 3', system-ui, sans-serif;
  color: var(--encre-douce); margin: clamp(18px, 2.4vh, 30px) 0 0; max-width: 58ch;
}

.cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: clamp(26px, 3.4vw, 60px); margin-top: clamp(30px, 4.6vh, 58px);
  align-items: start; max-width: 1000px;
}
/* Le lecteur d'album est large et haut : mis en colonne avec les deux blocs
   de contact, il creusait un vide de plusieurs centaines de pixels sous eux.
   Il a sa propre rangée, sur la largeur de la première colonne. */
.ecoute { margin-top: clamp(34px, 5vh, 66px); max-width: 620px; }
.bloc { min-width: 0; }
/* Sur `.k` seul et non `.bloc .k` : l'intitulé « L'EP en entier » a quitté sa
   colonne quand le tampon d'avertissement a été retiré, et il perdait sa
   composition en passant hors de `.bloc`. */
.k {
  font: 500 11px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .28em; text-transform: uppercase; color: var(--encre-douce);
  margin: 0 0 16px;
}
.bloc .gros {
  font: 700 clamp(19px, 1.6vw, 30px)/1.3 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .02em; margin: 0 0 6px;
  overflow-wrap: anywhere;
}
.bloc .gros a { text-decoration: none; border-bottom: 3px solid var(--rouge); }
.bloc .gros a:hover { color: var(--rouge); }
.bloc p { font: 400 16px/1.55 'Source Sans 3', system-ui, sans-serif;
          color: var(--encre-douce); margin: 0 0 8px; }
.bloc .btn { margin-top: 18px; }

/* L'album complet — fond blanc, comme le lecteur Bandcamp qu'il accueille.
   L'iframe n'est injectée qu'au clic : sinon Bandcamp dépose ses traceurs
   sur chaque visite, pour un lecteur que personne n'a demandé. */
.album { position: relative; background: var(--blanc); min-height: 168px;
         box-shadow: inset 0 0 0 2px var(--encre);
         display: flex; align-items: center; justify-content: center; }
.album.is-on { box-shadow: none; min-height: 0; }
.album button {
  -webkit-appearance: none; appearance: none; border: 0; cursor: pointer;
  background: transparent; color: var(--encre); padding: 40px 24px;
  font: 500 12px/1.6 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .22em; text-transform: uppercase; text-align: center; width: 100%;
  transition: background .26s var(--ease);
}
.album button:hover { background: rgba(212,0,0,.06); }
.album button strong {
  display: block; color: var(--rouge); margin-bottom: 10px;
  font: 700 26px/1.1 'Oswald', system-ui, sans-serif; letter-spacing: .02em;
}
.album iframe { display: block; width: 100%; height: 470px; border: 0;
                background: var(--blanc); }

.mentions {
  margin: clamp(40px, 6vh, 78px) 0 0; max-width: 62ch;
  padding-top: clamp(20px, 3vh, 34px); border-top: 2px solid rgba(11,11,11,.14);
  font: 400 13px/1.6 'Source Sans 3', system-ui, sans-serif; color: var(--encre-douce);
}
.mentions a { color: var(--encre); }

/* =========================================================================
   LE CHARGEUR — le logo se dévoile de gauche à droite
   -------------------------------------------------------------------------
   Le dévoilement suit le TÉLÉCHARGEMENT RÉEL de la vidéo, pas une durée
   décidée à l'avance : quand le logo est entier, le site est vraiment prêt.
   ========================================================================= */
/* Tant que le chargeur est là, le défilement est interdit — sinon le visiteur
   descend jusqu'au bas de page sans jamais voir le dispositif. `overflow`
   seul ne suffit pas sur iOS, il faut aussi bloquer le geste tactile. */
html.charge, html.charge body {
  overflow: hidden; height: 100%; overscroll-behavior: none; touch-action: none;
}

/* Le chargeur n'apparaît QUE si le JavaScript s'exécute. Sans ce garde-fou,
   un script en erreur laisserait un écran plein cadre masquant le site à
   jamais — c'est la classe `js`, posée en tête de page, qui l'autorise. */
.load { display: none; }
html.js .load {
  position: fixed; inset: 0; z-index: 100; background: var(--papier);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: var(--marge); transition: opacity .6s var(--ease);
}
html.js .load.is-out { opacity: 0; pointer-events: none; }
html.js .load[hidden] { display: none; }

.load__logo { position: relative; width: min(76vw, 720px); }
.load__logo img { display: block; width: 100%; height: auto; }
/* Le fantôme : le logo entier, à peine visible, pour que le dévoilement ait
   une destination lisible plutôt que d'émerger du vide. */
.load__logo .fantome { opacity: .07; }
.load__logo .plein {
  position: absolute; inset: 0; opacity: 1;
  clip-path: inset(0 calc(100% - var(--reveal, 0%)) 0 0);
}
/* Le bord vif du dévoilement : un trait rouge qui avance avec lui. */
.load__bord {
  position: absolute; top: -3%; bottom: -3%; width: 5px;
  left: var(--reveal, 0%); transform: translateX(-2px);
  background: var(--rouge); opacity: .9;
  clip-path: polygon(20% 0, 100% 3%, 74% 100%, 0 96%);
}
.load.is-full .load__bord { opacity: 0; transition: opacity .3s linear; }

.load__hint {
  display: flex; align-items: center; gap: 12px;
  margin-top: clamp(26px, 5vh, 54px);
  font: 500 11px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .3em; text-transform: uppercase; color: var(--encre-douce);
}
.load__hint::before {
  content: ""; width: 7px; height: 7px; background: var(--rouge);
  animation: at-pulse 1.4s ease-in-out infinite;
}
.load__hint b { font-weight: 500; color: var(--encre); font-variant-numeric: tabular-nums; }
@keyframes at-pulse { 0%,100% { opacity: .22; } 50% { opacity: 1; } }

/* =========================================================================
   MOBILE — le voile monte du bas, la ligne se resserre contre le bord
   ========================================================================= */
@media (max-width: 900px) {
  :root { --voile-fin: 58%; --haut-h: clamp(150px, 22vh, 250px); --plaque-w: auto; }
  /* Le palier d'introduction porte un paragraphe entier. Sur téléphone il
     déborde du voile monté du bas et le dessin repasse au travers : même à
     93 % d'opacité, les lettres géantes « ANTI-REP » restent lisibles derrière
     le texte. Pour ce palier-là, le bas de l'écran devient franchement du
     papier, et la vidéo garde le tiers haut. */
  .stage.is-intro .voile {
    background: linear-gradient(0deg,
      rgba(239,236,230,.995) 0%,
      rgba(239,236,230,.985) 62%,
      rgba(239,236,230,.58)  84%,
      rgba(239,236,230,0)    100%);
  }

  .voile { background: linear-gradient(0deg,
             rgba(239,236,230,.97) 0%,
             rgba(239,236,230,.92) calc(var(--voile-fin) * .32),
             rgba(239,236,230,.46) calc(var(--voile-fin) * .68),
             rgba(239,236,230,0)   var(--voile-fin)); }
  .rive { display: none; }

  .marque img { width: clamp(150px, 44vw, 230px); }

  .plaque {
    left: var(--marge); right: calc(var(--marge) + clamp(34px, 11vw, 60px));
    width: auto; bottom: calc(clamp(28px, 5vh, 60px) + env(safe-area-inset-bottom));
  }
  .plaque--intro { right: var(--marge); }
  .pl { padding: 11px 22px 13px 18px; gap: 11px; }
  .pl__t { font-size: clamp(19px, 5.4vw, 30px); }
  .pl__ico { width: 26px; }
  .raccord { display: none; }
  .sous, .actions { margin-left: 18px; }

  /* Les neuf titres sont écrits à côté des anneaux sur téléphone aussi — même
     lecture du plan que sur ordinateur, en plus petit et plus pâle.
     Deux conditions pour que ça tienne sur 390 px de large :
       - le rail est accroché en HAUT et non centré. Centré, il descendait
         jusque dans la plaque dès que le lecteur est ouvert et que la plaque
         remonte, et les titres passaient par-dessus le nom de la station ;
       - les titres s'effacent sur le palier de présentation, dont le
         paragraphe prend toute la largeur. */
  .ligne { right: 11px; top: clamp(112px, 19vh, 190px); transform: none;
           --anneau: 18px; --trait: 8px; }
  .ligne__titre { display: none; }
  .ligne ol { gap: clamp(7px, 1.7vh, 16px); }
  /* À 8,5 px il faut plus de contraste et un halo plus large qu'à 13 px :
     sinon les titres disparaissent sur la manche blanche du personnage. */
  .ligne .lb { font-size: 8.5px; letter-spacing: .03em; color: rgba(11,11,11,.6);
               text-shadow: 0 0 2px rgba(239,236,230,1),
                            0 0 5px rgba(239,236,230,.95),
                            0 0 12px rgba(239,236,230,.8); }
  .ligne .lb b { color: rgba(212,0,0,.75); }
  .ligne .lb b { margin-right: 6px; }

  .ligne button { gap: 7px; }
  .ligne li.now .lb,
  .ligne button:hover .lb, .ligne button:focus-visible .lb { transform: scale(1.22); }
  .stage.is-intro .ligne .lb { opacity: 0; }
  .ligne .lb { transition: color .3s var(--ease), transform .3s var(--ease),
                           opacity .3s var(--ease); }

  body.a-dock .plaque { bottom: calc(clamp(86px, 15vh, 130px) + env(safe-area-inset-bottom)); }

  /* Le lecteur passe sur deux rangs : le titre au-dessus, les commandes
     en dessous. Sur 390 px de large, tout aligner écraserait la barre de
     position à quelques pixels. */
  .dock { flex-wrap: wrap; gap: 6px 12px; padding-top: 9px; }
  .dock__t { order: -1; flex: 1 1 100%; font-size: 13px; }
  .dock__tm { font-size: 11px; }
  .dock__pv { display: none; }
  .load__logo { width: 84vw; }
}

/* =========================================================================
   MOUVEMENT RÉDUIT — l'affiche fixe remplace la vidéo, tout reste lisible
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .stage__media video { display: none; }
  .plaque > *, .plaque.is-on > * { transition: none; transform: none; }
  .ligne .anneau, .ligne .lb, .cue, .btn, .dock { transition: none; }
  .cue__f { animation: none; opacity: .8; }
  .load__hint::before { animation: none; opacity: .7; }
}

/* Sous 1200 px, le repère centré tomberait dans la plaque : il va se loger
   dans l'angle libre en bas à droite, sous la ligne, et se réduit au
   compteur et à la flèche. */
@media (max-width: 1199px) {
  .cue { left: auto; right: clamp(10px, 2.4vw, 48px); transform: none;
         bottom: calc(clamp(14px, 2.4vh, 28px) + env(safe-area-inset-bottom)); }
  .cue__l { display: none; }
}

/* Impression : la ligne, en clair. */
@media print {
  .stage__media, .plancher, .voile, .rive, .bandeau, .papier-grain,
  .cue, .dock, .ligne, .load { display: none !important; }
  .scroller, .stage { height: auto; position: static; }
  .plaque { position: static; opacity: 1; visibility: visible; page-break-inside: avoid;
            margin: 0 0 18px; width: auto; }
  .plaque > * { opacity: 1; transform: none; }
}
