/* ===========================================================================
   despontsalaplacedesmurs.com — feuille de style de production
   Valeurs reprises du paquet de design (design/site.css + ds/tokens-*.css).
   Le design est fixé sur un cadre de 1920 × 1080 : ici tout est fluidifié,
   mais les valeurs de référence sont conservées comme bornes hautes.
   =========================================================================== */

/* ---- Polices, hébergées localement -------------------------------------
   Pas d'import Google Fonts : le site doit être autonome, et l'appel au CDN
   transmettrait l'IP des visiteurs à un tiers. Oswald est une police
   variable — un seul fichier couvre les graisses 600 et 700.            */
@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 {
  /* Base monochrome froide — ne change jamais */
  --ink: #0D1518;
  --charcoal: #1C2A30;
  --slate: #495F6F;
  --mist: #ABBDC8;
  --paper: #F2F5F5;
  --line: rgba(171, 189, 200, .16);

  /* Couleurs signatures — mesurées puis calées pour le fond sombre */
  --oe-rose-raw:#9B2D4C;   --oe-rose:#E0637F;
  --oe-orange-raw:#73341D; --oe-orange:#DF6A38;
  --oe-vert-raw:#284021;   --oe-vert:#56A643;
  --oe-rouge-raw:#69241F;  --oe-rouge:#E4574A;
  --oe-or-raw:#976A25;     --oe-or:#D89F42;
  --oe-violet-raw:#6A1374; --oe-violet:#B172E8;

  /* Courbe unique du site. Aucun rebond nulle part. */
  --ease: cubic-bezier(.22,.61,.36,1);

  /* ---- Réglage du voile -------------------------------------------------
     Le design calait le dégradé latéral pour mourir à 82 % et le scrim haut
     à 250 px. À la demande d'OD (V1), le voile est décalé vers la gauche et
     vers le haut pour moins empiéter sur l'image. Ces deux valeurs sont les
     seules à toucher pour l'ajuster encore.
     ATTENTION : le design avait mesuré ses valeurs pour garantir ≥ 13:1 sur
     le texte. En réduisant le voile on réduit cette marge — elle reste
     confortable ici, mais ne pas aller beaucoup plus loin.               */
  --veil-end: 58%;        /* design 82 % → 68 → 58 (V2) */
  --topscrim-h: 150px;    /* design 250 px → 190 → 150 (V2) */

  /* Géométrie — bornes hautes = valeurs du design à 1920 */
  --marge: clamp(22px, 6.25vw, 120px);
  /* 800 px sur le cadre de 1920 du design = 41,7 vw. Garder 800 px en dur
     ferait déborder la plaque sur le repère « Défilez », centré, dès qu'on
     descend sous 1900 px de large — le design lui-même ne dégage que 5 px. */
  --plaque-w: min(800px, 41.7vw);
  --plaque-bottom: clamp(96px, 13.7vh, 148px);
  --edgescrim-w: clamp(180px, 17.7vw, 340px);
}

[data-oe="rose"]   { --oe: var(--oe-rose);   --oe-raw: var(--oe-rose-raw); }
[data-oe="orange"] { --oe: var(--oe-orange); --oe-raw: var(--oe-orange-raw); }
[data-oe="vert"]   { --oe: var(--oe-vert);   --oe-raw: var(--oe-vert-raw); }
[data-oe="rouge"]  { --oe: var(--oe-rouge);  --oe-raw: var(--oe-rouge-raw); }
[data-oe="or"]     { --oe: var(--oe-or);     --oe-raw: var(--oe-or-raw); }
[data-oe="violet"] { --oe: var(--oe-violet); --oe-raw: var(--oe-violet-raw); }

/* ---- Base -------------------------------------------------------------- */
* { box-sizing: border-box; }

html { scroll-behavior: auto; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: 'Source Sans 3', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: inherit; }

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

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

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

.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 reste visible tant que la vidéo n'a pas peint sa première image. */
.stage__media video { opacity: 0; transition: opacity .3s linear; }
.stage.is-video .stage__media video { opacity: 1; }

/* ---- Le voile : cinq couches, dans cet ordre exact --------------------- */
.floor     { position: absolute; inset: 0; background: rgba(7,12,14,.30); }
/* Les paliers du dégradé sont exprimés en fraction de --veil-end : décaler
   cette seule variable décale tout le voile, sans casser sa progression. */
.veil      { position: absolute; inset: 0;
             background: linear-gradient(90deg,
               rgba(7,12,14,.96) 0%,
               rgba(7,12,14,.90) calc(var(--veil-end) * .244),
               rgba(7,12,14,.66) calc(var(--veil-end) * .512),
               rgba(7,12,14,.24) calc(var(--veil-end) * .780),
               rgba(7,12,14,0)   var(--veil-end)); }
/* Le dégradé latéral meurt à 82 % : le scrim de rive couvre l'angle droit
   que ni lui ni le scrim haut n'atteignent, sous le rail de progression. */
.edgescrim { position: absolute; right: 0; top: 0; bottom: 0;
             width: var(--edgescrim-w);
             background: linear-gradient(270deg,
               rgba(7,12,14,.88) 0%, rgba(7,12,14,.62) 44%,
               rgba(7,12,14,0) 100%); }
.topscrim  { position: absolute; left: 0; right: 0; top: 0;
             height: var(--topscrim-h);
             background: linear-gradient(180deg,
               rgba(7,12,14,.92) 0%, rgba(7,12,14,.58) 46%,
               rgba(7,12,14,0) 100%); }
.grain     { position: absolute; inset: 0; opacity: .075;
             mix-blend-mode: overlay; pointer-events: none;
             background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>"); }

/* Production : plancher renforcé */
[data-floor="42"] .floor { background: rgba(7,12,14,.42); }

/* =========================================================================
   PAGE CLAIRE — Libérez la création. Même géométrie, valeurs inversées.
   ========================================================================= */
.clair { background: var(--paper); color: var(--ink); }
.clair .floor     { background: rgba(255,255,255,.34); }
.clair .veil      { background: linear-gradient(90deg,
                      rgba(255,255,255,.97) 0%,
                      rgba(255,255,255,.93) calc(var(--veil-end) * .244),
                      rgba(255,255,255,.72) calc(var(--veil-end) * .512),
                      rgba(255,255,255,.28) calc(var(--veil-end) * .780),
                      rgba(255,255,255,0)   var(--veil-end)); }
.clair .edgescrim { background: linear-gradient(270deg,
                      rgba(255,255,255,.94) 0%, rgba(255,255,255,.68) 44%,
                      rgba(255,255,255,0) 100%); }
.clair .topscrim  { background: linear-gradient(180deg,
                      rgba(255,255,255,.95) 0%, rgba(255,255,255,.64) 46%,
                      rgba(255,255,255,0) 100%); }
.clair .grain     { mix-blend-mode: multiply; opacity: .055; }
/* Sur la page claire le chrome est en couleur PLEINE, jamais en alpha :
   l'encre transparente ne se densifie pas et tombe sous le seuil. */
.clair .forte     { color: var(--ink); }
.clair .prolong   { color: rgba(13,21,24,.76); }
.clair .rail em   { color: #39474E; }
.clair .rail i    { background: #7C8990; }
.clair .rail i.on { background: var(--oe-raw); }
.clair .cue span  { color: rgba(13,21,24,.6); }
.clair .cue i     { background: linear-gradient(rgba(13,21,24,.6), rgba(13,21,24,0)); }
.clair .brand img { filter: invert(1) brightness(.10); }
/* La signature bascule sur sa valeur mesurée : l'or calé est illisible sur blanc. */
.clair .etq span  { color: var(--oe-raw); }
.clair .etq i     { background: var(--oe-raw); }
.clair .foot      { border-top-color: rgba(13,21,24,.14); }
.clair .foot .k   { color: #39474E; }
.clair .foot .ro  { color: rgba(13,21,24,.66); }
.clair .foot .ln a{ color: var(--ink); border-bottom-color: var(--oe-raw); }
.clair .card      { background: rgba(13,21,24,.06); }
.clair .card p    { color: rgba(13,21,24,.66); }
.clair .btn       { border-color: var(--oe-raw); color: var(--oe-raw); }
.clair .btn.solid { background: var(--oe-raw); color: var(--paper); }

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

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

/* Palier volontairement resserré : sur le dernier temps de l'accueil, la
   vidéo fait apparaître le logo complet. Une plaque pleine largeur viendrait
   le recouvrir — on la ramène à la colonne de gauche. */
.plaque.etroite { width: min(560px, 30vw); }
.plaque.etroite .prolong { max-width: 100%; }
@media (max-width: 860px) { .plaque.etroite { width: auto; } }

/* Apparition 560 ms — opacité + translateY(18px→0), en trois temps décalés.
   Sortie 340 ms — opacité seule, sans déplacement. */
.plaque > * {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .34s var(--ease), transform 0s linear .34s;
}
.plaque.is-on > * {
  opacity: 1;
  transform: none;
  transition: opacity .56s var(--ease), transform .56s var(--ease);
}
.plaque.is-on > .forte,
.plaque.is-on > .themes   { transition-delay: .09s; }
.plaque.is-on > .prolong  { transition-delay: .17s; }

.etq { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; }
.etq span {
  font: 500 clamp(12px, .73vw, 14px)/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .24em; text-transform: uppercase; color: var(--oe, var(--mist));
}
.etq i { display: block; width: 54px; height: 2px; background: var(--oe, var(--mist)); }

/* Interligne : le design posait 70/70, soit 1. En capitales accentuées —
   THÉÂTRE, L'EXPÉRIENCE, DÉCONSTRUIRE — les accents de la ligne du bas
   viennent toucher les jambages de celle du dessus. 1.09 ne suffisait pas :
   à 1.22 on obtient un vrai filet d'air, visible mais serré. Écart assumé. */
.forte {
  font: 700 clamp(32px, 3.65vw, 70px)/1.22 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .006em;
  margin: 28px 0 0; color: var(--paper); text-wrap: pretty;
}
.forte.sm { font-size: clamp(28px, 3.02vw, 58px); }
.forte.xs { font-size: clamp(26px, 2.5vw, 48px); line-height: 1.24; }

.prolong {
  font: 400 clamp(17px, 1.15vw, 22px)/1.55 'Source Sans 3', system-ui, sans-serif;
  color: rgba(242,245,245,.80); margin: 24px 0 0;
  max-width: 640px; text-wrap: pretty;
}

/* Palier 03 de l'accueil : la liste de six thèmes remplace la phrase forte. */
.themes { list-style: none; margin: 34px 0 0; padding: 0; display: grid; gap: 15px; max-width: 760px; }
.themes li {
  font: 600 clamp(19px, 1.41vw, 27px)/1.34 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .10em;
  color: rgba(242,245,245,.94); display: flex; gap: 20px; align-items: baseline;
}
.themes li b {
  font: 400 13px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .16em; color: var(--oe); flex: 0 0 30px;
}

/* =========================================================================
   CHROME — logo, rail, repère « Défilez »
   ========================================================================= */
.brand { position: absolute; left: var(--marge); top: clamp(24px, 5.5vh, 60px); z-index: 40; }
.brand img { display: block; width: clamp(132px, 10.7vw, 206px); height: auto; }

.rail {
  position: absolute; right: clamp(20px, 3.4vw, 66px); top: 50%;
  transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: flex-end; gap: 14px;
  z-index: 30;
}
.rail em {
  font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace; font-style: normal;
  letter-spacing: .18em; color: rgba(171,189,200,.75); margin-bottom: 6px;
}
.rail i {
  display: block; width: 2px; height: clamp(22px, 3.5vh, 38px);
  background: rgba(171,189,200,.56);
  transition: background .34s var(--ease);
}
.rail i.on { background: var(--oe, var(--paper)); }

.cue {
  position: absolute; left: 50%; bottom: 52px; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 13px;
  opacity: 1; transition: opacity .34s var(--ease); z-index: 30;
}
.cue.is-off { opacity: 0; pointer-events: none; }
.cue span {
  font: 500 11px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .3em; text-transform: uppercase; color: rgba(171,189,200,.66);
}
.cue i { display: block; width: 1px; height: clamp(30px, 7.8vh, 56px);
         background: linear-gradient(rgba(171,189,200,.7), rgba(171,189,200,0)); }
/* Le repère est centré sur la largeur, comme dans le design. Cette position
   ne tient que sur un cadre large : à 1920 le design ne dégage que 5 px entre
   la plaque et lui. En dessous de 1500 px il tomberait dans le texte, donc on
   l'efface plutôt que de le déplacer — c'est un indice, pas une information.
   Écart assumé par rapport au design, signalé dans le README. */
@media (max-width: 1499px), (max-height: 620px) { .cue { display: none; } }

/* Lien discret vers la grille de l'accueil, pages œuvres uniquement. */
.backlink {
  position: absolute; right: var(--marge); top: clamp(26px, 6vh, 72px);
  font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .2em; text-transform: uppercase;
  color: rgba(242,245,245,.68); text-decoration: none; z-index: 40;
  padding-bottom: 6px; border-bottom: 1px solid transparent;
}
.backlink:hover, .backlink:focus-visible {
  color: var(--paper); border-bottom-color: var(--oe);
}
.clair .backlink { color: #39474E; }
.clair .backlink:hover { color: var(--ink); border-bottom-color: var(--oe-raw); }

/* =========================================================================
   ALLER PLUS LOIN — dossier + teaser
   ========================================================================= */
.further { padding: clamp(56px, 9vh, 150px) var(--marge) clamp(40px, 6vh, 90px); }
.further > h2 {
  font: 700 clamp(30px, 3.23vw, 62px)/1.2 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .02em; margin: 0;
}
.dlrow { display: flex; gap: 30px; align-items: stretch; margin-top: 40px; flex-wrap: wrap; }

.card {
  background: var(--charcoal); padding: 38px 40px; flex: 1 1 320px;
  display: flex; flex-direction: column; justify-content: space-between; min-height: 250px;
}
.card h3 {
  font: 700 clamp(24px, 1.67vw, 32px)/1.24 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .02em; margin: 0; color: var(--paper);
}
.card p { font: 400 17px/1.5 'Source Sans 3', system-ui, sans-serif;
          color: rgba(242,245,245,.66); margin: 14px 0 0; }

.btn {
  display: inline-flex; align-items: center; gap: 14px;
  border: 1px solid var(--oe); color: var(--oe);
  padding: 15px 26px; text-decoration: none;
  font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .2em; text-transform: uppercase;
  margin-top: 30px; align-self: flex-start;
  transition: background .3s var(--ease), color .3s var(--ease);
}
.btn:hover, .btn:focus-visible { background: var(--oe); color: var(--ink); }
.btn.solid { background: var(--oe); color: var(--ink); }
.btn.solid:hover { filter: brightness(1.12); }
/* Production : le violet signature est clair, le libellé passe en noir franc
   pour détacher davantage (demande OD, V1). */
[data-oe="violet"] .btn.solid { color: #000; }

/* Teaser : vignette d'abord. L'iframe n'est injectée qu'au clic, sinon
   YouTube dépose ses traceurs sur chaque visite. */
.tzr { flex: 1.25 1 380px; position: relative; background: #1a262c;
       min-height: 250px; overflow: hidden; border: 0; padding: 0;
       cursor: pointer; display: block; width: 100%; }
.tzr img { position: absolute; inset: 0; width: 100%; height: 100%;
           object-fit: cover; opacity: .5; transition: opacity .42s var(--ease); }
.tzr:hover img, .tzr:focus-visible img { opacity: .66; }
.tzr .play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 76px; height: 76px; border: 1px solid var(--paper); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.tzr .play::after {
  content: ""; border-left: 16px solid var(--paper);
  border-top: 10px solid transparent; border-bottom: 10px solid transparent;
  margin-left: 5px;
}
.tzr .lb {
  position: absolute; left: 26px; bottom: 22px;
  font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .2em; text-transform: uppercase; color: rgba(242,245,245,.8);
}
.tzr iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* =========================================================================
   LA GRILLE DES ŒUVRES — deuxième zone de l'accueil
   ========================================================================= */
.oeuvres { padding: clamp(56px, 9vh, 150px) var(--marge) clamp(40px, 6vh, 90px); }
.oeuvres > h2 {
  font: 700 clamp(30px, 3.23vw, 62px)/1.2 'Oswald', system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .02em; margin: 0 0 40px;
}

/* minmax(0,1fr) et non 1fr : 1fr vaut minmax(auto,1fr) et laisse le contenu
   le plus large gonfler sa piste, ce qui casse l'égalité des colonnes.
   3 colonnes jusqu'à six œuvres, 4 dès la septième — rien d'autre à changer. */
.grid6 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 30px 26px; }
@media (min-width: 1200px) { .grid6.is-seven-plus { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.tile { position: relative; min-width: 0; }
.tile a { display: block; text-decoration: none; color: inherit; }
.sq { position: relative; aspect-ratio: 1; overflow: hidden; background: #101a1e; }
.sq img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: opacity .42s var(--ease), transform .52s var(--ease);
}
/* Croisement d'opacité de deux images — surtout pas un filtre CSS :
   les versions colorisées ont un travail de lumière qu'un grayscale()
   ne reproduirait pas. */
.sq .cl { opacity: 0; }
.tile:hover .cl, .tile:focus-within .cl, .tile.is-tapped .cl { opacity: 1; }
.tile:hover .sq img, .tile:focus-within .sq img, .tile.is-tapped .sq img { transform: scale(1.028); }

.sq .edge {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--oe); transform: scaleX(0); transform-origin: left;
  transition: transform .42s var(--ease);
}
.tile:hover .edge, .tile:focus-within .edge, .tile.is-tapped .edge { transform: scaleX(1); }

.sq .num {
  position: absolute; left: 20px; top: 18px;
  font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .18em; color: var(--oe); opacity: 0; transition: opacity .3s var(--ease);
}
.tile:hover .num, .tile:focus-within .num, .tile.is-tapped .num { opacity: 1; }

/* Retour au repos 25 % plus rapide, même courbe. */
.tile .sq img, .tile .edge, .tile .num { transition-duration: .315s, .39s; }
.tile:hover .sq img, .tile:hover .edge, .tile:hover .num,
.tile.is-tapped .sq img, .tile.is-tapped .edge, .tile.is-tapped .num {
  transition-duration: .42s, .52s;
}

/* La légende est hors du carré : les titres sont déjà composés dans les
   images, à des hauteurs variables — toute légende posée dessus en
   recouvrirait certains. */
.cap { padding: 17px 2px 0; }
/* Discipline : certaines images la portent déjà, d'autres non — la mention
   lève l'ambiguïté. Volontairement discrète, en retrait de la couleur
   signature qui reste au thème. */
.cap .kind {
  font: 500 10px/1.3 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .22em; text-transform: uppercase;
  color: rgba(171,189,200,.72); margin: 0 0 7px;
}
.clair .cap .kind { color: #5C6C74; }
.cap .disc {
  font: 500 11px/1.35 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .2em; text-transform: uppercase; color: var(--oe);
}
.cap .acc {
  font: 400 17px/1.38 'Source Sans 3', system-ui, sans-serif;
  color: rgba(242,245,245,.84); margin-top: 9px; text-wrap: pretty;
}
.tile:hover .cap .acc, .tile:focus-within .cap .acc { color: var(--paper); }

.tap {
  position: absolute; right: 14px; top: 12px;
  font: 500 11px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .16em; text-transform: uppercase;
  color: rgba(242,245,245,.75); border: 1px solid rgba(242,245,245,.4);
  padding: 7px 11px; display: none;
}

@media (max-width: 860px) {
  .grid6 { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  /* Pas de survol au doigt : le premier appui colorise, le second ouvre. */
  .tap { display: block; }
  .sq { outline: 1px solid transparent; }
  .tile.is-tapped .sq { outline-color: var(--oe); }
}

/* =========================================================================
   COMPTEUR D'ANNÉES — accueil, une seule fois par session
   ========================================================================= */
/* Défilement verrouillé tant que le chargeur est là : sans ça le visiteur
   descend jusqu'au menu sans jamais voir le dispositif. `overscroll-behavior`
   coupe en plus le rebond élastique d'iOS. */
html.is-loading,
html.is-loading body {
  overflow: hidden;
  height: 100%;
  overscroll-behavior: none;
  touch-action: none;
}

/* Le chargeur n'apparaît QUE si le JavaScript s'est exécuté. Sans ce garde-fou,
   un script qui échoue laisserait un écran plein cadre masquant le site à
   jamais — c'est la classe `js`, posée par un script en tête de page, qui
   l'autorise à s'afficher. */
.load { display: none; }
html.js .load {
  position: fixed; inset: 0; z-index: 100; background: var(--ink);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  transition: opacity .7s var(--ease);
}
html.js .load.is-out { opacity: 0; pointer-events: none; }
html.js .load[hidden] { display: none; }
.year {
  font: 700 clamp(96px, 15.2vw, 292px)/.82 'Oswald', system-ui, sans-serif;
  letter-spacing: -.01em; color: var(--paper); font-variant-numeric: tabular-nums;
}
.year.blur { color: rgba(242,245,245,.30); letter-spacing: .01em; }
.evt {
  font: 500 clamp(13px, 1.1vw, 21px)/1.5 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .16em; text-transform: uppercase; color: var(--mist);
  margin-top: 26px; text-align: center; max-width: 800px;
  padding: 0 var(--marge); min-height: 2.6em;
}
.rule-y { position: absolute; left: var(--marge); right: var(--marge); bottom: clamp(60px, 11vh, 120px); }
.rule-y .bar { height: 1px; background: rgba(171,189,200,.22); position: relative; }
/* Pas de transition CSS ici : la largeur est animée image par image par le
   compteur, en même temps que le chiffre. Les deux entreraient en conflit. */
.rule-y .bar b { position: absolute; top: 0; left: 0; height: 1px; background: var(--paper); }
.rule-y .tk { position: absolute; top: -7px; width: 1px; height: 15px; background: rgba(171,189,200,.4); }
.rule-y .tk.on { background: var(--paper); height: 23px; top: -11px; }
.rule-y .ends { display: flex; justify-content: space-between; margin-top: 20px;
                font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace;
                letter-spacing: .2em; color: rgba(171,189,200,.6); }

/* Mention de chargement — discrète, mais elle dit au visiteur d'attendre
   plutôt que de chercher à faire défiler. */
.load__hint {
  position: absolute;
  top: calc(50% + clamp(120px, 17vh, 210px));
  left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px;
  font: 500 11px/1 'IBM Plex Mono', ui-monospace, monospace;
  letter-spacing: .28em; text-transform: uppercase;
  color: rgba(171,189,200,.55);
  white-space: nowrap;
}
.load__hint::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--oe, var(--mist));
  animation: dpm-pulse 1.5s ease-in-out infinite;
}
@keyframes dpm-pulse { 0%,100% { opacity: .25; } 50% { opacity: 1; } }

/* La frise est finie mais la vidéo se charge encore : on appuie un peu. */
.load.is-waiting .load__hint { color: rgba(171,189,200,.85); }

@media (prefers-reduced-motion: reduce) {
  .load__hint::before { animation: none; opacity: .7; }
}

/* =========================================================================
   PIED DE PAGE CONTACT
   ========================================================================= */
.foot { padding: clamp(48px, 7vh, 74px) var(--marge) clamp(44px, 6vh, 62px);
        border-top: 1px solid var(--line); }
.foot .k { font: 500 12px/1 'IBM Plex Mono', ui-monospace, monospace;
           letter-spacing: .28em; text-transform: uppercase; color: var(--mist); }
/* Deux contacts côte à côte quand il y en a deux, l'un sous l'autre sinon. */
.pers-row { display: flex; flex-wrap: wrap; gap: clamp(28px, 5vw, 96px); }
.pers { flex: 0 1 auto; min-width: 0; }
.pers .nm { margin-top: 22px; }
@media (max-width: 860px) { .pers-row { gap: 34px; } }
.foot .nm { font: 700 clamp(28px, 2.3vw, 44px)/1.24 'Oswald', system-ui, sans-serif;
            text-transform: uppercase; letter-spacing: .02em; margin: 22px 0 0; }
.foot .ro { font: 400 18px/1.5 'Source Sans 3', system-ui, sans-serif;
            color: rgba(242,245,245,.66); margin: 8px 0 0; }
.foot .ln { font: 400 clamp(18px, 1.15vw, 22px)/1.6 'Source Sans 3', system-ui, sans-serif;
            margin: 26px 0 0; }
.foot .ln a { color: var(--paper); text-decoration: none;
              border-bottom: 1px solid var(--oe, var(--slate)); }
.foot .ln a:hover { color: var(--oe); }

/* =========================================================================
   MOBILE — le voile bascule vers le bas, le texte devient un bandeau
   ========================================================================= */
@media (max-width: 860px) {
  :root { --topscrim-h: clamp(190px, 29vh, 340px); }

  /* Sur mobile le voile monte depuis le bas. OD le veut encore plus ramassé
     que sur ordinateur : --veil-end y descend à 54 % (design : 72 %). */
  :root { --veil-end: 54%; }
  .veil { background: linear-gradient(0deg,
            rgba(7,12,14,.96) 0%,
            rgba(7,12,14,.88) calc(var(--veil-end) * .306),
            rgba(7,12,14,.42) calc(var(--veil-end) * .667),
            rgba(7,12,14,0)   var(--veil-end)); }
  .clair .veil { background: linear-gradient(0deg,
            rgba(255,255,255,.97) 0%,
            rgba(255,255,255,.90) calc(var(--veil-end) * .306),
            rgba(255,255,255,.46) calc(var(--veil-end) * .667),
            rgba(255,255,255,0)   var(--veil-end)); }
  .edgescrim { display: none; }

  .plaque {
    left: var(--marge); right: var(--marge); width: auto;
    bottom: calc(clamp(90px, 14vh, 210px) + env(safe-area-inset-bottom));
  }
  .prolong { max-width: none; }

  /* Le rail vertical devient une série de filets horizontaux sous le texte. */
  .rail {
    right: auto; left: var(--marge); top: auto;
    bottom: calc(clamp(44px, 7vh, 96px) + env(safe-area-inset-bottom));
    transform: none; flex-direction: row; align-items: center; gap: 10px;
  }
  .rail em { margin: 0 8px 0 0; }
  .rail i { width: 40px; height: 2px; }

  .cue { bottom: calc(20px + env(safe-area-inset-bottom)); }
  .cue i { height: 34px; }

  .dlrow { flex-direction: column; }
  .card { padding: 30px 26px; }
}

/* =========================================================================
   MOUVEMENT RÉDUIT — pas de vidéo, pas de transition. Le voile fonctionne
   à l'identique sur l'image fixe, les paliers restent lisibles.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .stage__media video { display: none; }
  .plaque > *, .plaque.is-on > * { transition: none; transform: none; }
  .rail i, .cue, .sq img, .btn { transition: none; }
}
