/* ==========================================================================
   L'ART SCÈNE THÉÂTRE — feuille de style du thème
   Typos : Franxurter (logo) · Humane (titres display) · Sofia Pro (texte)
   ========================================================================== */

/* ---------- Polices ---------- */
@font-face {
  font-family: 'Franxurter';
  src: url('../fonts/Franxurter.woff') format('woff');
  font-weight: 400;
  font-display: block;
}
@font-face {
  font-family: 'Humane';
  src: url('../fonts/Humane-Bold-2.woff2') format('woff2');
  font-weight: 700;
  font-display: block;
}
@font-face {
  font-family: 'Humane';
  src: url('../fonts/Humane-SemiBold-2.woff2') format('woff2');
  font-weight: 600;
  font-display: block;
}
@font-face {
  font-family: 'Super Blocky';
  src: url('../fonts/SuperBlocky.ttf') format('truetype');
  font-weight: 400;
  font-display: block;
}
@font-face {
  font-family: 'Sofia Pro';
  src: url('../fonts/SofiaPro-Regular.woff') format('woff');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Sofia Pro';
  src: url('../fonts/SofiaPro-Italic.woff') format('woff');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Sofia Pro';
  src: url('../fonts/SofiaPro-Medium.woff') format('woff');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'Sofia Pro';
  src: url('../fonts/SofiaPro-SemiBold.woff') format('woff');
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: 'Sofia Pro';
  src: url('../fonts/SofiaPro-Bold.woff') format('woff');
  font-weight: 700;
  font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  /* L'orange officiel de L'Art Scène (#F08C2A, cahier des charges + logo).
     Sur les écrans modernes (P3), la même teinte est affichée dans un
     espace de couleur plus large pour gagner en éclat sans changer d'identité. */
  --orange: #f08c2a;
  --orange-deep: #cf711a;
  /* L'encre CHAUDE, assumée : en grand aplat elle tire vers le brun, et
     c'est voulu. Le 2026-08-01, deux encres neutres ont été essayées à la
     demande de Nicolas (#17181d puis #21232a éclaircie) avant qu'il tranche :
     « on peut remettre la sorte de marron, c'était pas si mal ». Ne pas
     rejouer ce débat sans lui. Seuls les FONDS des bandeaux d'images
     (billets, éphéméride) restent neutres : c'est là que le brun le gênait.
     Les rgb(28 18 6 / x) codés en dur dans la feuille sont la déclinaison
     translucide de cette encre (bordures, ombres). */
  --ink: #1c1206;
  --ink-soft: #2b1d0e;
  --paper: #f5f0e8;
  --white: #ffffff;

  /* Noir de cinéma, utilisé par la page L'Art Scène (.trav) : encore un cran
     plus profond que l'encre, pour les fonds de récit. */
  --noir: #08090c;

  /* Bandes de fermeture des fonds photo de cette page.
     ------------------------------------------------------------------
     Écrire un dernier arrêt « var(--noir) 100% » ne SUFFIT PAS : l'opacité
     pleine n'est alors atteinte que sur la dernière ligne de pixels, et
     l'avant-dernière laisse déjà transparaître l'image (mesuré : 0,28 % à 1 px
     du bord pour Le lieu, 1,3 % à 8 px pour L'esprit). Sur une photo claire,
     cela suffit à dessiner le trait de jointure — c'est ce que je prenais à
     tort pour corrigé en vérifiant seulement la présence de la règle.
     Ces deux couches, exprimées en PIXELS et non en pourcentages, garantissent
     une bande de noir strictement opaque en haut et en bas, quelle que soit la
     hauteur de la section. Elles se placent en PREMIER dans le raccourci
     background, donc au-dessus des autres dégradés. */
  --ferme-haut: linear-gradient(180deg, #08090c 0 14px, rgb(8 9 12 / 0) 30px);
  --ferme-bas: linear-gradient(0deg, #08090c 0 14px, rgb(8 9 12 / 0) 30px);

  /* Les trois marches orange (l'escalier du logo), repère de section.
     ------------------------------------------------------------------
     TOUT est en PIXELS ENTIERS, et c'est le point essentiel : en rem, les
     valeurs tombaient à 3,52 px d'épaisseur pour 1,92 px d'écart. Les écarts
     étaient pourtant égaux sur le papier, mais chaque barre se posait
     différemment sur la grille de pixels, si bien qu'aucune n'avait la même
     épaisseur ni le même écart à l'écran : le motif paraissait « pas net ».
     L'épaisseur, l'écart et le pas de largeur sont désormais identiques et
     entiers, donc le rendu est rigoureusement régulier. */
  /* Teintes du voile de header, choisies pour chaque type de section. Le
     script les combine au défilement : voir --voile-haut / --voile-bas. */
  --voile-sombre: rgb(10 11 15 / .82);
  --voile-clair: rgb(245 240 232 / .9);
  --voile-orange: rgb(240 140 42 / .94);

  --marche-ep: 3px;        /* épaisseur d'une marche */
  --marche-gap: 3px;       /* écart entre deux marches */
  --marche-l1: 12px;       /* largeur de la première */
  --marche-pas: 10px;      /* allongement d'une marche à la suivante */

  --font-logo: 'Franxurter', 'Sofia Pro', sans-serif;
  --font-display: 'Humane', 'Arial Narrow', sans-serif;
  --font-body: 'Sofia Pro', 'Segoe UI', sans-serif;
}
/* La police d'UN titre, choisie individuellement dans l'admin (champ
   « Police du titre » des pages et des sections de l'accueil, demande de
   Nicolas : « les choses individuellement », pas de réglage global). La
   classe est portée par le titre lui-même ; humane = la police du site,
   déclarée aussi pour rester vraie quel que soit le contexte. Les tailles
   restent calibrées pour la Humane : avec une police plus large, un titre
   long passe sur deux lignes, c'est un outil d'essai. La Super Blocky n'est
   proposée QUE pour « Les stages » de l'accueil (capitales trop larges pour
   les titres longs), avec ses formules dédiées. */
.tp--humane { font-family: 'Humane', 'Arial Narrow', sans-serif; }
.tp--franxurter { font-family: 'Franxurter', 'Arial Black', sans-serif; }
.tp--sofia { font-family: 'Sofia Pro', 'Segoe UI', sans-serif; }
:root {

  --pad: clamp(1.25rem, 4vw, 4rem);
  /* Hauteur du header, zone système des iPhone (encoche) comprise : le
     header est en box-sizing border-box, son padding-top système vit DANS
     cette hauteur. */
  --header-h: calc(4.5rem + env(safe-area-inset-top, 0px));
  --ease-out: cubic-bezier(.16, 1, .3, 1);
}
@supports (color: color(display-p3 1 1 1)) {
  :root {
    --orange: color(display-p3 0.937 0.56 0.21);
  }
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* Les hauteurs rendues sont fractionnaires (pied de page mesuré à 504,859 px)
     alors que la hauteur du document est arrondie à l'entier supérieur : il
     reste donc jusqu'à 1 px sous le dernier élément. Sans fond ici, celui du
     body se propage à toute la toile et ce résidu apparaissait en crème sous
     le pied de page sombre — le liseré visible en bas de chaque page. En le
     posant en encre, il devient invisible : toutes les pages, home comprise,
     se terminent sur cette couleur. */
  background: var(--ink);
}
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
h1, h2, h3 { line-height: 1.05; margin: 0 0 .5em; }
:focus-visible { outline: 3px solid var(--orange); outline-offset: 3px; }
::selection { background: var(--orange); color: var(--white); }

.display {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .01em;
}
.kicker {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: .8rem;
  letter-spacing: .28em;
  text-transform: uppercase;
  margin: 0 0 1rem;
  opacity: .75;
}

/* ---------- Logo en escalier (construction officielle) ----------
   Métriques mesurées sur le logo officiel (logo-artscene-transparent.png) :
   interligne = 115 % de la hauteur des capitales, interlettrage ≈ 11 %.
   Avec la Franxurter (capitales à 59 % du corps) : line-height .68, spacing .065em. */
.logo-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  font-family: var(--font-logo);
  color: var(--orange);
  text-transform: uppercase;
  line-height: .68;
  letter-spacing: .065em;
}
.logo-stack > span { display: block; }
/* Petite taille : rendu DIRECT à sa taille (1.15rem), plus de scale(.5).
   L'ancien rendu « 2× puis réduit » affichait sur iPhone un logo en relief
   pixelisé pendant une fraction de seconde avant de se lisser (Safari
   rasterise d'abord la couche transformée à basse résolution), retour de
   Nicolas. L'interligne et l'interlettrage étant en em, la géométrie est
   strictement la même ; les navigateurs modernes positionnent les lignes au
   sous-pixel, les interlignes restent réguliers. */
.logo-stack--sm {
  font-size: 1.15rem;
}

/* ---------- Boutons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  padding: .9em 1.8em;
  font: 600 .95rem/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  text-decoration: none;
  border: 2px solid var(--orange);
  border-radius: 999px;
  background: var(--orange);
  color: var(--white);
  cursor: pointer;
  transition: transform .25s var(--ease-out), background .25s, color .25s, border-color .25s;
}
.btn:hover { background: var(--orange-deep); border-color: var(--orange-deep); transform: translateY(-2px); }
.btn--ghost { background: transparent; color: currentColor; border-color: currentColor; }
.btn--ghost:hover { background: var(--orange); border-color: var(--orange); color: var(--white); }
.btn--ink { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.btn--ink:hover { background: var(--ink-soft); border-color: var(--ink-soft); }

/* ---------- Intro / animation logo ---------- */
#intro {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  background: var(--white);
  transition: transform .7s var(--ease-out);
  will-change: transform;
}
#intro .intro-mark { font-size: clamp(3rem, 10vw, 6.5rem); }
#intro .intro-mark > span { display: block; overflow: hidden; }
#intro .intro-mark i {
  display: inline-block;
  font-style: normal;
  transform: translateY(112%);
}
#intro .intro-line {
  width: 0;
  height: 4px;
  background: var(--orange);
  margin-top: 1.4rem;
}
#intro.play .intro-mark > span:nth-child(1) i { animation: intro-rise .6s var(--ease-out) .15s forwards; }
#intro.play .intro-mark > span:nth-child(2) i { animation: intro-rise .6s var(--ease-out) .28s forwards; }
#intro.play .intro-mark > span:nth-child(3) i { animation: intro-rise .6s var(--ease-out) .41s forwards; }
#intro.play .intro-line { animation: intro-line .55s var(--ease-out) .8s forwards; }
#intro.done { transform: translateY(-100%); pointer-events: none; }
#intro.off { display: none; }
@keyframes intro-rise { to { transform: translateY(0); } }
@keyframes intro-line { to { width: 100%; } }

/* ---------- Header ---------- */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-h);
  padding: 0 var(--pad);
  /* Avec viewport-fit=cover, la barre d'état des iPhone recouvre le haut de
     la page : le logo y était mordu (retour de Nicolas). La marge haute
     reprend la hauteur de cette zone système (nulle ailleurs) ; --header-h
     l'inclut, donc tout ce qui se cale sous le header suit sans retouche. */
  padding-top: env(safe-area-inset-top, 0px);
  color: var(--paper);
  transition: background .35s ease, color .35s ease, box-shadow .35s ease,
              backdrop-filter .35s ease;
}

/* ---- Pages annexes : le header s'estompe, il ne se pose pas ----
   Transparent, il laissait le texte défiler derrière le logo et le menu, qui
   devenaient illisibles. Une bande pleine réglait la lisibilité mais coupait
   la page d'un trait net, « trop abrupt ». Le voile est donc porté par un
   pseudo-élément dont le fond ET le flou s'éteignent vers le bas : il n'y a
   aucune arête, on ne peut pas dire où le header finit.
   Il n'apparaît qu'une fois défilé (classe .scrolled, posée à 30 px) : en
   arrivant sur la page, rien ne trouble le bandeau ni sa photo. La home est
   exclue, sa composition est validée. */
body:not(.home) .site-header::before {
  content: '';
  position: absolute;
  /* Le voile DÉBORDE de 2 rem sous le header : la zone dense couvre ainsi
     toute la hauteur du logo, et le fondu se fait en dessous, dans le vide.
     Avec un fondu commençant dans le header, le texte redevenait net juste
     derrière le logo — c'était le défaut constaté. */
  inset: 0 0 -2rem;
  /* Derrière le contenu du header, devant la page. */
  z-index: -1;
  /* La teinte suit EXACTEMENT ce qui passe dessous. Quand la frontière entre
     deux sections traverse le header, le voile se coupe au même endroit
     qu'elle : le changement de couleur devient littéralement invisible,
     puisqu'il se produit sur la ligne de séparation elle-même. Les trois
     variables sont posées au défilement par site.js ; hors JavaScript, la
     valeur par défaut suffit (le voile n'apparaît qu'une fois défilé).
     C'est le masque qui crée le fondu, et il éteint du même coup le FLOU :
     sans lui, le flou s'arrêterait net sur une ligne horizontale. */
  background: linear-gradient(180deg,
    var(--voile-haut, var(--voile-sombre)) 0 var(--voile-front, 100%),
    var(--voile-bas, var(--voile-sombre)) var(--voile-front, 100%) 100%);
  backdrop-filter: blur(16px) saturate(1.08);
  -webkit-backdrop-filter: blur(16px) saturate(1.08);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 68%, rgb(0 0 0 / 0) 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 68%, rgb(0 0 0 / 0) 100%);
  opacity: 0;
  transition: opacity .5s ease;
  pointer-events: none;
}
body:not(.home) .site-header.scrolled::before { opacity: 1; }
/* MENU OUVERT : le voile s'efface, sans condition ni exception. Sans cela, le
   rideau orange s'ouvrait sous une bande sombre floutée, avec son dégradé de
   fondu en travers.
   Le premier sélecteur reprend EXACTEMENT celui qui allume le voile, plus
   « .nav-open » : écrit plus court, il pesait (0,2,2) contre (0,3,2) et ne
   l'emportait jamais, quelle que soit sa position dans la feuille. Le second
   couvre les autres cas (accueil, header pas encore défilé).
   Transition coupée : le rideau monte en .4 s, un voile qui met .5 s à
   s'effacer resterait visible pendant toute l'ouverture. */
body.nav-open:not(.home) .site-header.scrolled::before,
body.nav-open .site-header::before {
  opacity: 0;
  transition: none;
}
/* Sans flou d'arrière-plan, le dégradé seul suffit : il est simplement plus
   dense, et reste sans bord net. */
/* Sans flou, les teintes se densifient : le texte doit rester masqué. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  :root {
    --voile-sombre: rgb(10 11 15 / .96);
    --voile-clair: rgb(245 240 232 / .97);
    --voile-orange: rgb(240 140 42 / .98);
  }
}
/* Sur la page L'Art Scène, le sombre reprend le noir de cinéma de la page. */
body.page-trav { --voile-sombre: rgb(8 9 12 / .84); }
/* Sur un voile SOMBRE (zones sombres et aplats orange), logo et burger doivent
   rester clairs : sans cette règle, « header-over-flat » mettait le burger en
   encre, invisible sur le voile. Les zones claires en sont exclues, elles ont
   un voile crème et gardent leur burger en encre. Le menu ouvert garde la main
   (:not(.nav-open)), son rideau orange impose un logo blanc. */
body:not(.home):not(.nav-open):not(.header-over-light):not(.header-over-flat) .site-header.scrolled .logo-stack {
  color: var(--orange);
  filter: none;
}
body:not(.home):not(.nav-open):not(.header-over-light):not(.header-over-flat) .site-header.scrolled .nav-toggle i {
  background: var(--white);
  filter: none;
}

/* Header toujours transparent : logo et burger portent une ombre légère
   pour rester lisibles sur n'importe quel fond */
.site-header .logo-stack,
.nav-toggle i { filter: drop-shadow(0 1px 6px rgb(0 0 0 / .4)); }
/* La couleur du logo suit l'ouverture du menu : la transition est calée sur
   le rideau orange (ouverture .65s), à l'aller comme au retour. */
.site-header .logo-stack { transition: color .4s ease .12s; }
/* Menu ouvert : le logo passe TOUJOURS en blanc, quel que soit l'état du
   header en dessous (orange sur encre, encre sur aplat orange...). Le fond du
   menu étant orange, un logo resté orange y disparaissait. Déclaré après les
   règles d'état (header-over-*) et sur un sélecteur plus long : il gagne. */
body.nav-open .site-header .logo-stack,
body.nav-open.header-over-flat .site-header .logo-stack,
body.nav-open.header-over-light .site-header .logo-stack,
body.nav-open.header-over-orange .site-header .logo-stack {
  color: var(--white);
  filter: none;
}
/* Au-dessus d'une zone orange, le logo passe en blanc */
body.header-over-orange .site-header .logo-stack { color: var(--white); }
/* Au-dessus d'une zone claire : plus d'ombre, barres du menu en encre */
body.header-over-light .site-header .logo-stack { filter: none; }
body.header-over-light .nav-toggle i { filter: none; background: var(--ink); }
/* Aplat orange plein : le logo orange s'y perdrait, il passe en encre */
body.header-over-flat .site-header .logo-stack { color: var(--ink); filter: none; }
body.header-over-flat .nav-toggle i { filter: none; background: var(--ink); }
body.page-light .site-header:not(.scrolled) { color: var(--ink); }
.brand { text-decoration: none; display: inline-flex; transition: opacity .3s; }
/* Sur la landing, le grand logo du hero suffit : le petit s'efface
   tant qu'on n'a pas défilé (desktop comme mobile) */
body.home .site-header:not(.scrolled) .brand { opacity: 0; pointer-events: none; }
.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  /* Alignement et LARGEURS EXPLICITES des barres : Safari iOS applique mal
     l'étirement automatique des enfants d'un <button> en flex, les barres
     sans largeur disparaissaient (constaté sur iPhone : seule la barre à
     70 % restait visible). Plus aucun calcul automatique ici. */
  align-items: flex-end;
  justify-content: center;
  gap: 6px;
  width: 46px;
  height: 46px;
  padding: 10px;
  background: none;
  border: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.nav-toggle i {
  display: block;
  width: 26px;
  height: 3px;
  background: var(--white);
  border-radius: 3px;
  transition: transform .35s var(--ease-out), opacity .25s, width .35s var(--ease-out), background .25s;
}
.nav-toggle i:nth-child(2) { width: 18px; }
body.nav-open .nav-toggle i { background: var(--ink); }
body.nav-open .nav-toggle i:nth-child(1) { transform: translateY(8px) rotate(45deg); }
body.nav-open .nav-toggle i:nth-child(2) { opacity: 0; }
body.nav-open .nav-toggle i:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

/* ---------- Menu plein écran ---------- */
.site-nav {
  position: fixed;
  inset: 0;
  /* Hauteur DYNAMIQUE : un panneau fixé avec inset:0 se cale sur la grande
     hauteur d'iOS, et son bas (la newsletter du menu) passait sous la barre
     de Safari quand elle était visible (« le bas de l'accès rapide est
     toujours coupé », retour de Nicolas). En dvh, le panneau suit la hauteur
     réellement visible, instant par instant : le bas est toujours à l'écran.
     Redimensionner un aplat orange ne coûte rien, contrairement aux sections
     à contenu. Le défilement interne est un filet pour les petits écrans en
     paysage, et la marge basse réserve la barre de geste. */
  height: 100dvh;
  bottom: auto;
  z-index: 90;
  background: var(--orange);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* « safe » : si le contenu dépasse la boîte (petit écran en paysage), le
     centrage cède la place à un alignement haut, sinon le haut du menu
     serait rogné inaccessiblement. */
  justify-content: safe center;
  overflow-y: auto;
  padding: calc(var(--header-h) + 2rem) var(--pad) calc(1.4rem + env(safe-area-inset-bottom, 0px));
  clip-path: circle(0 at calc(100% - 3.4rem) 2.2rem);
  visibility: hidden;
  transition: clip-path .65s var(--ease-out), visibility 0s .65s;
}
body.nav-open .site-nav {
  clip-path: circle(150% at calc(100% - 3.4rem) 2.2rem);
  visibility: visible;
  transition: clip-path .65s var(--ease-out);
}
.site-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-nav li { overflow: hidden; }
.site-nav a.nav-link {
  font-family: var(--font-display);
  font-weight: 700;
  /* dvh et non vh : sur iPhone, vh vaut la GRANDE hauteur (barre repliée)
     alors que le panneau du menu suit la hauteur visible. Calibrés en vh,
     les liens débordaient du menu quand la barre était affichée et la
     newsletter du bas se faisait couper (retour de Nicolas). */
  font-size: clamp(2.6rem, 7.5vh, 4.6rem);
  font-size: clamp(2.6rem, 7.5dvh, 4.6rem);
  line-height: 1.02;
  text-transform: uppercase;
  text-decoration: none;
  display: inline-block;
  transform: translateY(110%);
  transition: transform .55s var(--ease-out), color .12s;
}
/* Deux délais distincts, dans l'ordre des propriétés : l'entrée en cascade ne
   retarde QUE le mouvement. Avec un délai unique, il s'appliquait aussi à la
   couleur : au survol, le blanc arrivait jusqu'à 0,4 s en retard, la latence
   remarquée par Nicolas. */
body.nav-open .site-nav a.nav-link {
  transform: translateY(0);
  transition-delay: calc(.1s + var(--i) * .04s), 0s;
}
.site-nav a.nav-link:hover, .site-nav a.nav-link[aria-current] { color: var(--white); }
/* Coordonnées puis newsletter, empilées à gauche sur TOUS les écrans : rejetée
   à l'autre bout d'un grand écran, la newsletter se faisait oublier. */
.site-nav .nav-foot {
  margin-top: 2.5rem;
  font-size: .9rem;
  font-weight: 500;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.6rem;
  opacity: 0;
  transition: opacity .4s ease .35s;
}
body.nav-open .site-nav .nav-foot { opacity: 1; }
.nav-coord { display: flex; flex-direction: column; gap: .15rem; }
/* Écrans bas (petits téléphones, ou barre Safari affichée) : le menu se
   resserre pour que TOUT tienne sans coupure, newsletter comprise. Mesuré :
   à 745 px de haut, l'ancien réglage débordait de 19 px. Placé APRÈS les
   règles de base, sinon elles l'emporteraient à spécificité égale. */
@media (max-height: 780px) {
  .site-nav a.nav-link {
    /* Relevé de 6.2 à 6.8dvh (« un peu petit », retour de Nicolas) : depuis
       le verrou de page, les barres de Safari ne bougent plus, le dvh est
       stable et la marge de sécurité d'antan peut revenir aux liens. Mesuré :
       à 7dvh, il ne restait que 5 px de marge à 705 px de haut, trop juste
       pour la barre de geste des iPhone. */
    font-size: clamp(2.1rem, 6.8vh, 3.6rem);
    font-size: clamp(2.1rem, 6.8dvh, 3.6rem);
  }
  .site-nav { padding-top: calc(var(--header-h) + 1.1rem); }
  .site-nav .nav-foot { margin-top: 1.3rem; }
  .nav-coord { gap: .05rem; }
}
/* Et un cran de plus pour les iPhone SE et consorts. */
@media (max-height: 700px) {
  .site-nav a.nav-link {
    font-size: clamp(1.9rem, 6.3vh, 3.2rem);
    font-size: clamp(1.9rem, 6.3dvh, 3.2rem);
  }
  .site-nav .nav-foot { margin-top: 1rem; }
}
.nav-coord strong {
  font: 600 .78rem/1.4 var(--font-body);
  letter-spacing: .22em;
  text-transform: uppercase;
}
.nav-coord a { text-decoration: none; }
/* Inscription rapide à la newsletter, sur l'aplat orange : champ et bouton en
   encre, mêmes angles francs que le reste du site. */
.nav-newsletter { width: min(26rem, 100%); }
.nav-newsletter label {
  display: block;
  font: 600 .78rem/1.4 var(--font-body);
  letter-spacing: .22em;
  text-transform: uppercase;
  margin-bottom: .45rem;
}
/* Deux pilules pleines et distinctes, comme partout ailleurs sur le site :
   la capsule scindée en deux demi-lunes donnait une forme bâtarde. */
.nav-newsletter-ligne { display: flex; flex-wrap: wrap; gap: .6rem; }
/* Le sélecteur porte le type : sinon la règle générale des formulaires,
   écrite plus bas à spécificité égale, imposerait son arrondi de .8rem. */
.nav-newsletter input[type='email'] {
  flex: 1 1 12rem;
  min-width: 0;
  padding: .75em 1.2em;
  font: 500 .95rem var(--font-body);
  color: var(--ink);
  background: var(--paper);
  border: 2px solid var(--ink);
  border-radius: 999px;
  outline-offset: -2px;
}
.nav-newsletter input::placeholder { color: rgb(28 18 6 / .45); }
.nav-newsletter button {
  flex: none;
  padding: .75em 1.5em;
  font: 700 .82rem/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 999px;
  cursor: pointer;
  transition: background .2s, color .2s, transform .25s var(--ease-out);
}
.nav-newsletter button:hover { background: var(--ink-soft); transform: translateY(-2px); }
body.nav-open { overflow: hidden; }

/* ---------- Sections plein écran (home) ----------
   Défilement par section sur TOUS les écrans (souhait du cahier des charges).
   Chaque section fait exactement un écran ; sur mobile, les grilles trop
   larges deviennent des carrousels horizontaux à l'intérieur de la section.

   LE VERROU DE PAGE, fin de la saga des barres de Safari. Épisodes
   précédents : svh laissait un vide sous les sections quand la barre se
   repliait ; dvh redimensionnait tout en saccadant ; lvh était stable mais
   la barre recouvrait le bas des sections et le recalage de l'aimantage
   « débloquait » la page en sautant (retours de Nicolas). La vraie réponse,
   celle des sites plein écran professionnels : la PAGE ne défile plus DU
   TOUT, c'est <main> qui défile à l'intérieur. Safari ne replie ses barres
   que sur un défilement de page : ici elles ne bougent JAMAIS, la hauteur
   visible est constante, les sections s'y calent au pixel, pour toujours.
   La classe html.snap n'est posée que sur l'accueil (sections multiples). */
html.snap, html.snap body { height: 100%; overflow: hidden; }
html.snap main {
  height: 100svh;
  height: 100dvh;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  overscroll-behavior-y: none;
}
.panel {
  position: relative;
  /* La hauteur visible, constante grâce au verrou de page ci-dessus. */
  height: 100svh;
  height: 100dvh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--header-h) + 1rem) var(--pad) 2.5rem;
  overflow: hidden;
}
@media (max-width: 899px) {
  .panel { padding: calc(var(--header-h) + .5rem) 1.25rem 1.5rem; }
}
/* Invite à faire défiler, en bas de chaque section sauf le hero (qui a déjà sa
   propre flèche, plus affirmée) et sauf la dernière (rien après). Simple
   chevron tracé au filet, bien plus discret que celui du hero, et en
   currentColor : il devient sombre sur les sections claires, clair sur les
   sombres, sans règle par section. En pseudo-élément absolu, donc il ne prend
   aucune place dans le flux — plusieurs de ces sections n'ont plus un pixel
   de marge en hauteur. */
main > .panel:not(.hero):not(:last-child)::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: .7rem;
  z-index: 4;
  width: .5rem;
  height: .5rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateX(-50%) rotate(45deg);
  opacity: .32;
  pointer-events: none;
  animation: chevron-souffle 3.6s ease-in-out infinite;
}
@keyframes chevron-souffle {
  0%, 100% { transform: translateX(-50%) rotate(45deg) translate(0, 0); opacity: .28; }
  50%      { transform: translateX(-50%) rotate(45deg) translate(3px, 3px); opacity: .55; }
}
@media (prefers-reduced-motion: reduce) {
  main > .panel:not(.hero):not(:last-child)::after { animation: none; }
}
/* Sous 800px de haut ces sections sont pleines à ras bord — mesuré en 375×667,
   le dernier bouton n'est plus qu'à 7px du bas, et en 1280×720 il manque 9 à
   14px. La flèche ne pourrait que chevaucher le contenu : on la retire.
   Même sélecteur que ci-dessus, sinon la règle serait moins spécifique et
   n'aurait aucun effet — et elle effacerait au passage le ::after du hero,
   qui est un voile, pas une flèche. */
@media (max-height: 799px) {
  main > .panel:not(.hero):not(:last-child)::after { content: none; }
}
/* « Les ateliers » en desktop : son contenu descend à 2,5px du bas de section
   (le défaut de place déjà signalé sur cette section), il n'y a donc pas de
   quoi loger la flèche sans la superposer au bouton. Elle reste affichée en
   mobile, où la section respire. Sélecteur aligné sur celui du dessus, sinon
   il serait moins spécifique et sans effet. */
@media (min-width: 900px) {
  main > .panel.tiles-sec:not(.hero):not(:last-child)::after { content: none; }
}

/* Jointure entre deux sections plein écran.
   Surtout PAS de margin-top négative : la section suivante démarrerait 1 px
   avant la fin de la précédente et, peinte après elle, laisserait voir une
   ligne d'elle-même en bas de chaque écran. C'est l'inverse qu'il faut : la
   section déborde d'1 px vers le BAS par son ombre portée, dans sa propre
   couleur. L'ombre ne prend aucune place dans le flux, la section suivante la
   recouvre entièrement, et elle ne devient visible que si un arrondi de
   sous-pixel ouvrait un jour une fente — qu'elle bouche alors à l'identique. */
.panel { box-shadow: 0 1px 0 0 var(--panel-bg, transparent); }
/* Écrans très bas (téléphone en paysage) : le plein écran strict n'a plus de sens */
@media (max-height: 480px) {
  html.snap main { scroll-snap-type: y proximity; }
  .panel { height: auto; min-height: 100svh; min-height: 100dvh; overflow: visible; }
}
.panel--ink { background: var(--ink); color: var(--paper); --panel-bg: var(--ink); }
.panel--paper { background: var(--paper); color: var(--ink); --panel-bg: var(--paper); }
.panel--orange { background: var(--orange); color: var(--white); --panel-bg: var(--orange); }
.panel--orange .kicker { opacity: .9; }
.panel--orange .section-title { text-shadow: 0 2px 14px rgb(140 62 8 / .35); }
.panel--orange .btn--ghost { border-color: var(--white); color: var(--white); }
.panel--orange .btn--ghost:hover { background: var(--white); color: var(--orange-deep); border-color: var(--white); }

/* Révélations au scroll */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .8s ease, transform .8s var(--ease-out); }
.reveal.in { opacity: 1; transform: none; }
.reveal:nth-child(2) { transition-delay: .08s; }
.reveal:nth-child(3) { transition-delay: .16s; }
.reveal:nth-child(4) { transition-delay: .24s; }

/* Pastilles de navigation latérale */
.section-dots {
  position: fixed;
  right: 1.4rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 80;
  display: none;
  flex-direction: column;
  gap: .8rem;
}
/* Les pastilles valent aussi sur téléphone et tablette : c'est là qu'on a le
   moins de repères sur l'avancement dans la page. Simplement réduites et
   rapprochées du bord pour ne pas empiéter sur le contenu. */
.home .section-dots { display: flex; }
@media (max-width: 899px) {
  .section-dots { right: .5rem; gap: .55rem; }
  .section-dots button { width: 8px; height: 8px; border-width: 1.5px; }
  .section-dots button.active { transform: scale(1.3); }
}
.section-dots button {
  width: 10px; height: 10px;
  border-radius: 50%;
  border: 2px solid var(--orange);
  background: transparent;
  padding: 0;
  cursor: pointer;
  transition: background .25s, transform .25s;
}
.section-dots button.active { background: var(--orange); transform: scale(1.35); }

/* ---------- HERO : socle commun des 5 variantes ---------- */
.hero { justify-content: center; }
.hero .hero-layout { position: relative; z-index: 2; width: 100%; }
.hero .hero-main { display: flex; flex-direction: column; align-items: flex-start; text-align: left; }
.hero .hero-logo { margin: 0 0 1.6rem; }
.hero .hero-logo .logo-stack { font-size: clamp(4.2rem, 13vw, 10.5rem); }
.hero .hero-tagline {
  max-width: 30rem;
  margin: 0 0 1.8rem;
  font-size: clamp(1.02rem, 1.4vw, 1.25rem);
  font-weight: 500;
  line-height: 1.5;
}
.hero .hero-ctas { display: flex; gap: .9rem; flex-wrap: wrap; }
.hero .hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center 30%;
}

/* V1 — Plein feu : typographique, halo de projecteur */
.hero--v1 {
  background:
    radial-gradient(ellipse 58% 46% at 38% 30%, rgb(240 140 42 / .16), transparent 70%),
    var(--ink);
}
.hero--v1 .hero-logo .logo-stack { font-size: clamp(4.6rem, 16vw, 13rem); }
.hero--v1 .hero-tagline { color: var(--paper); }
@media (min-width: 900px) {
  .hero--v1 .hero-main { flex-direction: row; align-items: flex-end; gap: 4rem; }
  .hero--v1 .hero-logo { flex: 0 0 auto; margin: 0; }
  .hero--v1 .hero-tagline { margin-bottom: 1.2rem; }
}

/* V2 — Scène : photo plein écran */
.hero--v2 .hero-bg { opacity: 1; }
.hero--v2::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to top, rgb(15 8 0 / .88) 0%, rgb(15 8 0 / .35) 45%, rgb(15 8 0 / .25) 100%);
}
.hero--v2 { justify-content: flex-end; }
.hero--v2 .hero-tagline { color: var(--paper); }

/* V3 — Triptyque : les 3 activités côte à côte */
.hero--v3 .hero-layout {
  display: grid;
  gap: 2rem;
  height: 100%;
  align-items: center;
}
.hero--v3 .hero-triptyque {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .7rem;
  height: 100%;
}
.hero--v3 .hero-pane {
  background-size: cover;
  background-position: center;
  border-radius: .9rem;
  filter: saturate(.92);
}
@media (min-width: 900px) {
  .hero--v3 { padding-right: 0; padding-bottom: 0; padding-top: 0; }
  .hero--v3 .hero-layout { grid-template-columns: 5fr 7fr; gap: 3rem; }
  .hero--v3 .hero-main { padding: calc(var(--header-h) + 1rem) 0 2.5rem; }
  .hero--v3 .hero-triptyque { border-radius: 0; gap: 0; }
  .hero--v3 .hero-pane { border-radius: 0; }
  .hero--v3 .hero-pane:nth-child(2) { transform: none; }
  .hero--v3 .scroll-cue { left: 21%; }
}
@media (max-width: 899px) {
  .hero--v3 .hero-layout { grid-template-rows: auto 1fr; height: 100%; }
  .hero--v3 .hero-logo .logo-stack { font-size: clamp(3.2rem, 17vw, 4.6rem); }
  .hero--v3 .hero-tagline { margin-bottom: 1.2rem; }
  .hero--v3 .hero-triptyque { min-height: 0; }
}
.hero--v3 .hero-tagline { color: var(--paper); }

/* V4 — Affiche : panneau d'annonce modulable sur fond orange éclairé */
.hero--v4 {
  color: var(--ink);
  background:
    radial-gradient(ellipse 75% 65% at 18% 8%, rgb(255 197 110 / .65), transparent 62%),
    radial-gradient(ellipse 60% 50% at 85% 95%, rgb(140 62 8 / .28), transparent 65%),
    linear-gradient(160deg, #f7a04a 0%, #f08c2a 48%, #dd7a1c 100%);
}
.hero--v4 .hero-logo .logo-stack { color: var(--ink); }
.hero--v4 .hero-layout {
  display: grid;
  gap: 2.5rem;
  align-items: center;
}
.hero--v4 .hero-affiche {
  position: relative;
  display: block;
  justify-self: center;
  max-width: min(38svh, 20rem);
  transform: rotate(2.5deg);
  transition: transform .35s var(--ease-out);
}
.hero--v4 .hero-affiche:hover { transform: rotate(0deg) scale(1.02); }
.hero--v4 .hero-affiche img {
  border-radius: .8rem;
  box-shadow: 0 24px 60px rgb(28 18 6 / .35);
}
.hero--v4 .hero-affiche-badge {
  position: absolute;
  left: 50%;
  bottom: -1rem;
  transform: translateX(-50%);
  white-space: nowrap;
  background: var(--ink);
  color: var(--paper);
  font: 600 .8rem/1 var(--font-body);
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .6em 1.1em;
  border-radius: 999px;
}
@media (min-width: 900px) {
  .hero--v4 .hero-layout { grid-template-columns: 7fr 5fr; }
  .hero--v4 .hero-affiche { max-width: min(62svh, 24rem); }
}
@media (max-width: 899px) {
  .hero--v4 .hero-layout { gap: 1.1rem; }
  .hero--v4 .hero-logo { margin-bottom: .9rem; }
  .hero--v4 .hero-logo .logo-stack { font-size: clamp(2.7rem, 13vw, 3.8rem); }
  .hero--v4 .hero-tagline { font-size: .95rem; margin-bottom: 1rem; }
  .hero--v4 .hero-affiche { max-width: min(24svh, 11rem); margin-bottom: 1.2rem; }
}

/* Diaporama de fond (variantes Saison et Mix) — le conteneur porte la
   première image en secours : le fond n'est jamais noir, même au chargement */
.hero-slides {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center;
  background-color: var(--ink);
}
.hero-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.2s ease;
}
.hero-slide.show { opacity: 1; }
.hero-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* Invisible tant que la photo n'est pas décodée EN ENTIER : un grand JPEG
     se peint ligne à ligne pendant son décodage, et la frontière entre la
     partie peinte et le fond de secours (dérivé 1400 px du conteneur)
     dessinait une fine ligne horizontale à travers le hero. Le script pose
     .est-la après img.decode() ; sans JavaScript, le fond de secours affiche
     de toute façon la première photo. */
  opacity: 0;
  transition: opacity .45s ease;
}
.hero-slide img.est-la { opacity: 1; }
.hero--v5::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(ellipse 70% 55% at 12% 88%, rgb(10 5 0 / .55), transparent 70%),
    linear-gradient(to top, rgb(10 5 0 / .92) 0%, rgb(10 5 0 / .45) 45%, rgb(10 5 0 / .34) 100%);
}
.hero--v5 { justify-content: flex-end; }
.hero--v5 .hero-tagline { color: var(--paper); text-shadow: 0 1px 12px rgb(0 0 0 / .5); }
.hero--v5 .hero-logo .logo-stack { filter: drop-shadow(0 3px 22px rgb(0 0 0 / .55)); }
/* Mobile : le logo respire en haut, l'accroche et les boutons ancrés en bas */
@media (max-width: 899px) {
  .hero--v5 { justify-content: stretch; }
  .hero--v5 .hero-layout { flex: 1; display: flex; }
  .hero--v5 .hero-main { flex: 1; width: 100%; }
  .hero--v5 .hero-logo { margin-top: 1.2rem; }
  .hero--v5 .hero-tagline { margin-top: auto; }
}

/* V6 — Mix : diaporama de fond + bandeau d'annonce en bas */
.hero--v6::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(ellipse 70% 50% at 15% 85%, rgb(10 5 0 / .4), transparent 68%),
    linear-gradient(to top, rgb(10 5 0 / .74) 0%, rgb(10 5 0 / .26) 45%, rgb(10 5 0 / .16) 100%);
}
.hero--v6 { justify-content: flex-end; }
.hero--v6 .hero-tagline { color: var(--paper); text-shadow: 0 1px 12px rgb(0 0 0 / .5); }
.hero--v6 .hero-logo .logo-stack {
  filter: drop-shadow(0 2px 5px rgb(0 0 0 / .6)) drop-shadow(0 12px 36px rgb(0 0 0 / .55));
}
/* Alignement optique du bord gauche (desktop). Les trois boîtes partent bien
   du même x, mais la Franxurter a une approche gauche de 0,018em : l'encre du
   logo commençait 3 px à droite de celle de l'accroche et du bord des pilules,
   mesuré au balayage de pixels. Correction en em pour qu'elle suive le corps
   du logo à toutes les tailles. */
@media (min-width: 900px) {
  .hero--v6 .hero-logo .logo-stack { margin-left: -.018em; }
}
/* Composition verticale du hero : logo ancré en haut, texte et boutons en bas.
   Elle vaut pour les téléphones ET pour les tablettes en portrait — y compris
   la Surface Pro 7, large de 912px, qui basculait sinon en composition desktop
   et se retrouvait avec les boutons à 12px du bord, sur la flèche. La condition
   de hauteur écarte les tablettes en paysage, larges et basses, qui restent en
   composition desktop. */
@media (max-width: 899px), (max-width: 1199px) and (min-height: 900px) {
  /* Le logo du hero EST le logo principal : ancré en haut, pas flottant.
     Texte et boutons remontés au-dessus de la flèche de défilement. */
  .hero--v6 { padding-top: 1.4rem; }
  .hero--v6 .hero-layout { flex: 1; display: flex; flex-direction: column; padding-bottom: 6rem; }
  .hero--v6 .hero-main { display: contents; }
  .hero--v6 .hero-logo { order: 1; margin-top: 0; }
  .hero--v6 .hero-logo .logo-stack { font-size: clamp(3rem, 14.5vw, 4.2rem); }
  .hero--v6 .hero-tagline {
    order: 2;
    margin-top: auto;
    font-size: .95rem;
    margin-bottom: 1.1rem;
    align-self: center;
    text-align: center;
  }
  .hero--v6 .hero-ctas { order: 3; align-self: center; justify-content: center; }
}

/* Tablettes en portrait : réglage propre, entre le téléphone et le desktop.
   Le plafond de 4.2rem du logo était calibré pour un téléphone ; il ne lui
   laissait que 32 % de la largeur sur iPad Air, d'où le grand vide central.
   11,6vw le porte à ~46 % quelle que soit la tablette. Texte et boutons
   passent à gauche, sur la verticale du logo, et remontent nettement. */
@media (min-width: 768px) and (max-width: 1199px) and (min-height: 900px) {
  /* La marge latérale du panneau vaut 1.25rem sous 900px : une valeur de
     téléphone, soit 20px seulement sur une tablette de 820px de large. Logo,
     accroche et boutons s'y retrouvaient collés au bord. On la porte à ~5 %
     de la largeur, pour le hero seul — les autres sections gardent la leur. */
  .hero--v6 { padding-inline: clamp(2.2rem, 5.2vw, 3.75rem); }
  .hero--v6 .hero-layout { padding-bottom: 9rem; }
  .hero--v6 .hero-logo .logo-stack { font-size: clamp(4.2rem, 11.6vw, 7.5rem); }
  /* Accroche et boutons restent CENTRÉS, comme sur téléphone : le centrage
     vient du bloc de composition verticale, on ne surcharge donc que les
     tailles — celles du téléphone sont illisibles sur une dalle de 1024 px. */
  .hero--v6 .hero-tagline {
    font-size: 1.4rem;
    max-width: 38rem;
    margin-bottom: 1.9rem;
  }
  /* Les deux boutons doivent tenir sur UNE ligne jusqu'à la plus étroite des
     tablettes (768 px), sans quoi ils se répartissent sur deux lignes ici et
     sur une seule ailleurs — l'incohérence entre tablettes qu'on corrige.
     On resserre la pilule plutôt que le texte, que l'on veut justement plus
     lisible. Calibré pour garder ~14 px de réserve en 768 px, barre de
     défilement comprise — sur une vraie tablette il y en a 15 de plus. */
  .hero--v6 .hero-ctas { gap: 1rem; }
  .hero--v6 .hero-ctas .btn { font-size: 1.18rem; padding: .95em 1.35em; }
}

/* Pile d'annonces (variantes Affiche et Mix) : cartes superposées, rotation en fondu */
.hero-annonces { display: grid; }
.hero-annonces .hero-affiche {
  grid-area: 1 / 1;
  position: relative;
  display: block;
  max-width: min(52svh, 22rem);
  opacity: 0;
  transform: translateY(10px) rotate(1.5deg);
  transition: opacity .8s ease, transform .8s var(--ease-out);
  pointer-events: none;
}
.hero-annonces .hero-affiche.active {
  opacity: 1;
  transform: translateY(0) rotate(0deg);
  pointer-events: auto;
}
.hero-annonces .hero-affiche img {
  border-radius: .8rem;
  box-shadow: 0 24px 60px rgb(0 0 0 / .45);
}
.hero-annonces .hero-affiche .hero-affiche-badge {
  position: absolute;
  left: 50%;
  bottom: -.9rem;
  transform: translateX(-50%);
  white-space: nowrap;
  max-width: 96%;
  overflow: hidden;
  text-overflow: ellipsis;
  background: var(--orange);
  color: var(--white);
  font: 600 .78rem/1.2 var(--font-body);
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .55em 1.1em;
  border-radius: 999px;
  box-shadow: 0 6px 18px rgb(0 0 0 / .35);
}
@media (max-width: 899px) {
  .hero-annonces .hero-affiche { max-width: min(34svh, 14.5rem); }
}

/* Header sur fond orange (variante Affiche) : logo et burger en encre */
body:has(.hero--v4) .site-header:not(.scrolled) { color: var(--ink); }
body:has(.hero--v4) .site-header:not(.scrolled) .logo-stack { color: var(--ink); }
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 1.6rem;
  transform: translateX(-50%);
  z-index: 3;
  background: none;
  border: 0;
  color: var(--paper);
  cursor: pointer;
  animation: cue-bounce 2.2s ease-in-out infinite;
}
.scroll-cue svg { width: 30px; height: 30px; }
@keyframes cue-bounce {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(10px); }
}

/* ---------- Agenda / À l'affiche ---------- */
/* Fond immersif : les visuels des cartes, floutés et assombris. Le flou est
   dans l'image elle-même (fabriquée par le serveur, voir vignetteFloue dans le
   thème) : un filter: blur sur toute la surface se rendait par tuiles sur
   téléphone, avec un trait de jointure au milieu au premier affichage. */
.agenda-bg { position: absolute; inset: 0; z-index: 0; background: var(--ink); overflow: hidden; }
.agenda-bg-slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center 30%;
  filter: brightness(.68) saturate(1.15);
  opacity: 0;
  transition: opacity 1s ease;
}
.agenda-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgb(20 12 4 / .45), transparent 55%);
}
.agenda-bg-slide.show { opacity: 1; }
.agenda-inner { position: relative; z-index: 2; display: flex; flex-direction: column; justify-content: center; min-height: 0; }
.agenda .section-title { color: var(--white); text-shadow: 0 2px 8px rgb(0 0 0 / .55), 0 6px 24px rgb(0 0 0 / .4); text-align: center; margin-bottom: 1.6rem; }
@media (max-width: 899px) {
  .agenda .section-title { font-size: clamp(3.8rem, 15vw, 4.8rem); }
}
.agenda-more { display: block; text-align: center; margin: 1.6rem 0 0; }

.agenda-head { display: flex; align-items: baseline; justify-content: center; gap: 1rem; flex-wrap: wrap; }
.section-title { font-size: clamp(3.4rem, 9vw, 7rem); margin: 0 0 1.2rem; }
.agenda-grid {
  display: grid;
  justify-content: center;
  gap: 1.1rem;
}
/* Sur ordinateur : des cartes de largeur FIXE, centrées en flex avec retour
   à la ligne. Quel que soit leur nombre (1, 3, 5...), chaque rangée est
   parfaitement centrée et symétrique ; au-delà de 4, une seconde rangée se
   forme, centrée elle aussi (maximum pratique : 2 rangées). L'ancienne grille
   à 4 colonnes figées laissait une colonne vide et décalait tout à gauche
   dès qu'on retirait une carte (retour de Nicolas). */
@media (min-width: 900px) {
  .agenda-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: stretch;
  }
  .agenda-grid .event-card { flex: 0 0 16rem; width: 16rem; }
}
@media (min-width: 1200px) {
  /* 17rem et non 18 : à 1280 px de large (1163 px de grille), quatre cartes
     de 18rem + 3 gouttières réclament 1205 px et la 4e tombait seule sur
     une 2e rangée (mesuré au banc). À 17rem, quatre tiennent ensemble. */
  .agenda-grid .event-card { flex-basis: 17rem; width: 17rem; }
}
@media (min-width: 1400px) {
  .agenda-grid .event-card { flex-basis: 18rem; width: 18rem; }
}
.event-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  aspect-ratio: 3 / 4;
  max-height: 56svh;
  border-radius: 1rem;
  overflow: hidden;
  color: var(--white);
  text-decoration: none;
  background: var(--ink-soft) center/cover no-repeat;
  isolation: isolate;
  transition: transform .35s var(--ease-out), box-shadow .35s;
}
.event-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to top, rgb(10 5 0 / .94) 18%, rgb(10 5 0 / .55) 42%, rgb(10 5 0 / .08) 68%);
  transition: background .3s;
}
.event-card:hover { transform: translateY(-6px); box-shadow: 0 18px 40px rgb(28 18 6 / .35); }
.event-card .ec-body { padding: 1.3rem; }
.event-card .ec-date {
  display: inline-block;
  background: var(--orange);
  color: var(--white);
  font: 700 .78rem/1 var(--font-body);
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: .5em .9em;
  border-radius: 999px;
  margin-bottom: .8rem;
}
.event-card h3 {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 2.7rem;
  margin: 0 0 .2em;
  color: var(--white);
  text-shadow: 0 2px 6px rgb(0 0 0 / .85), 0 5px 18px rgb(0 0 0 / .55);
}
.event-card .ec-meta { font-size: .88rem; opacity: .95; font-weight: 500; text-shadow: 0 1px 5px rgb(0 0 0 / .8); }
/* Couleurs de pastille (choisies dans l'admin) — orange = défaut */
.event-card .ec-date--noir { background: var(--ink); color: var(--white); }
.event-card .ec-date--blanc { background: var(--white); color: var(--ink); }
/* Fenêtres intermédiaires (grille sur 2 rangées) : cartes plafonnées pour tenir dans l'écran */
@media (min-width: 900px) and (max-width: 1199px) {
  .event-card { max-height: 32svh; }
}

/* ---------- Tuiles ateliers : capsules horizontales arrondies ---------- */
.panel--white { background: var(--white); color: var(--ink); --panel-bg: var(--white); }
.tiles-inner { position: relative; z-index: 2; display: flex; flex-direction: column; justify-content: center; min-height: 0; }
.tiles-sec .kicker,
.tiles-sec .section-title { text-align: center; }
/* Le titre-affiche : très grand, sa base passe derrière la première capsule */
.tiles-sec .section-title {
  font-size: clamp(4rem, min(12vw, 18svh), 10rem);
  margin-bottom: -.14em;
  position: relative;
  z-index: 1;
}
.tiles-sec .tiles-grid { position: relative; z-index: 2; }
.tiles-more { text-align: center; margin: 1.4rem 0 0; }
.tile-badge {
  display: inline-block;
  background: var(--orange);
  color: var(--white);
  font: 700 .72rem/1 var(--font-body);
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: .5em 1em;
  border-radius: 999px;
  margin-bottom: 1rem;
  box-shadow: 0 4px 14px rgb(0 0 0 / .3);
}

.tiles-grid {
  display: flex;
  flex-direction: column;
  gap: clamp(.8rem, 2svh, 1.3rem);
}
.tile {
  position: relative;
  display: flex;
  align-items: center;
  height: clamp(7rem, 20svh, 13rem);
  border-radius: 999px;
  overflow: hidden;
  text-decoration: none;
  color: var(--white);
  background: var(--ink);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .28),
    inset 0 -1px 0 rgb(0 0 0 / .25),
    0 10px 34px rgb(28 18 6 / .16);
  transition: transform .35s var(--ease-out), box-shadow .35s;
}
.tile:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .35),
    inset 0 -1px 0 rgb(0 0 0 / .25),
    0 22px 50px rgb(28 18 6 / .26);
}
/* Au survol : un contour blanc se trace progressivement autour de la capsule */
.tile .tile-outline {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 3;
  pointer-events: none;
}
.tile .tile-outline rect {
  x: 3px;
  y: 3px;
  width: calc(100% - 6px);
  height: calc(100% - 6px);
  fill: none;
  stroke: var(--orange);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 1.1s var(--ease-out);
}
.tile:hover .tile-outline rect { stroke-dashoffset: 0; }
@media (prefers-reduced-motion: reduce) {
  .tile .tile-outline rect { transition: none; }
}
/* Écrans tactiles : le doigt remplace la souris. Au toucher, la capsule ne
   doit PAS se déplacer (le translateY du survol bougeait l'élément sous le
   doigt et Safari annulait le clic : « je casse les boutons des ateliers »,
   retour de Nicolas). On garde l'animation orange, jouée au toucher via
   :active, et l'ombre ; le lien suit immédiatement. */
@media (hover: none) {
  .tile:hover, .tile:active { transform: none; }
  .tile:active .tile-outline rect { stroke-dashoffset: 0; transition-duration: .5s; }
  .tile:active::after { background: rgb(15 8 0 / .3); }
  .tile:hover .tile-photo, .tile:active .tile-photo { transform: none; }
}
.tile .tile-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s var(--ease-out);
}
.tile::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgb(15 8 0 / .42);
  transition: background .3s;
}
.tile:hover::after { background: rgb(15 8 0 / .3); }
.tile:hover .tile-photo { transform: scale(1.04); }
.tile .tile-body {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 clamp(2.5rem, 8vw, 5rem);
}
.tile h3 {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(3rem, 6.5vw, 5.4rem);
  letter-spacing: .02em;
  margin: 0;
  line-height: .95;
  text-shadow: 0 2px 8px rgb(0 0 0 / .7), 0 6px 26px rgb(0 0 0 / .5);
}
.tile p {
  margin: .4rem 0 0;
  font-weight: 500;
  font-size: .92rem;
  opacity: .92;
  max-width: 34rem;
  text-shadow: 0 1px 8px rgb(0 0 0 / .5);
}
.tile .tile-arrow {
  position: absolute;
  right: clamp(1.2rem, 3vw, 2.2rem);
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--orange);
  color: var(--white);
  transition: transform .35s var(--ease-out);
}
.tile:hover .tile-arrow { transform: translateY(-50%) scale(1.15); }
/* Desktop : capsules moins étirées et centrées, bouton d'inscription
   SOUS les capsules, comme en mobile. L'ordre du DOM est déjà celui-là :
   plus aucun « order » ici, sinon le titre et le surtitre, qui en portaient,
   repasseraient derrière les éléments restés à la valeur par défaut. */
/* Ce qui décide de la part de photo visible dans une capsule, c'est son RAPPORT
   largeur/hauteur, pas sa taille. À 1184 × 115 (10:1) il n'en passait que 15 %
   en hauteur et les visages étaient coupés ; à 5:1 il en passe 31 %, de quoi
   contenir un visage, comme sur téléphone où la capsule fait déjà 2,75:1.
   Le rapport est donc figé, et c'est la LARGEUR qui s'ajuste à la hauteur de
   l'écran : trois capsules, un titre, un surtitre et un bouton doivent tenir
   dans un écran, sinon le bouton d'inscription passe sous le pli.
   La formule 140svh − 283px est le résultat de ce budget ; elle est bornée à
   66rem pour ne pas dominer les grands écrans. Une seule formule continue, donc
   aucun saut entre deux tailles d'écran. Toute retouche de la hauteur du titre,
   des marges ou du retrait de section ci-dessous se paie sur cette constante :
   remesurer plutôt que réajuster à l'œil. */
@media (min-width: 900px) {
  .tiles-sec { padding-block: 3.5rem 1.5rem; }
  .tiles-sec .tiles-grid {
    width: min(100%, clamp(32rem, 140svh - 283px, 66rem));
    margin-inline: auto;
    gap: clamp(.5rem, 1.4svh, 1rem);
    flex-shrink: 0;
  }
  .tiles-sec .tile { aspect-ratio: 5 / 1; height: auto; }
  .tiles-sec .kicker { margin-bottom: .6rem; }
  .tiles-sec .section-title { font-size: min(9vw, 10svh); margin-bottom: .06em; }
  .tiles-sec .tiles-more { margin: 1.2rem 0 0; }
}

@media (max-width: 899px) {
  .tile { height: clamp(6rem, 15svh, 9rem); }
  .tile p { display: none; }
  .tile h3 { font-size: clamp(2.7rem, 12.5vw, 3.4rem); }
  /* Un seul groupe centré verticalement, espacements fixes et réguliers */
  .tiles-sec .section-title { font-size: clamp(4.2rem, min(19vw, 12svh), 5.6rem); margin-bottom: .1em; }
  .tiles-sec .kicker { margin-bottom: .5rem; }
  .tiles-sec .tiles-grid { margin-top: 1.2rem; }
  .tile-badge { font-size: .62rem; margin-bottom: .9rem; }
  .tiles-sec .tiles-more { margin-top: 1.3rem; }
}

/* Mobile : « À l'affiche » se feuillette comme une roue de cartes —
   la courante devant, les voisines visibles en retrait, fondu et rotation */
@media (max-width: 899px) {
  .agenda-more { margin-top: 1.1rem; }
  .agenda-grid {
    display: grid;
    justify-items: center;
    /* Pas de touch-action : c'est le script qui tranche, au premier
       mouvement du doigt, entre tourner la roue et faire défiler la page
       (voir « À l'affiche » dans site.js). */
  }
  .agenda-grid .event-card {
    grid-area: 1 / 1;
    width: min(72vw, 42svh);
    max-height: none;
    opacity: 0;
    transform: scale(.72);
    transition: transform .6s var(--ease-out), opacity .6s ease, filter .6s ease;
    pointer-events: none;
    will-change: transform, opacity;
  }
  .agenda-grid .event-card.pos-current {
    opacity: 1;
    transform: none;
    z-index: 3;
    pointer-events: auto;
    filter: none;
  }
  .agenda-grid .event-card.pos-next {
    opacity: .6;
    transform: translateX(24%) translateY(3%) scale(.84) rotate(4deg);
    z-index: 2;
    pointer-events: auto;
    filter: brightness(.8);
  }
  .agenda-grid .event-card.pos-prev {
    opacity: .6;
    transform: translateX(-24%) translateY(3%) scale(.84) rotate(-4deg);
    z-index: 2;
    pointer-events: auto;
    filter: brightness(.8);
  }
  .agenda-grid .event-card.pos-back {
    opacity: 0;
    transform: translateY(6%) scale(.72);
    z-index: 1;
  }
  .agenda-grid .event-card h3 { font-size: 2.4rem; }
  .agenda-grid .event-card .ec-body { padding: 1rem; }
  .agenda-grid .event-card .ec-meta { font-size: .8rem; }
}
.agenda-dots { display: flex; justify-content: center; gap: .55rem; margin-top: 1.1rem; }
.agenda-dots button {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 2px solid var(--orange);
  background: transparent;
  padding: 0;
  cursor: pointer;
  transition: background .25s, transform .25s;
}
.agenda-dots button.active { background: var(--orange); transform: scale(1.3); }
@media (min-width: 900px) { .agenda-dots { display: none; } }
/* ==========================================================================
   SECTION « LES STAGES » — Le projecteur
   Le triptyque plein écran est le décor ET l'interface : survoler ou toucher
   un format allume le panneau correspondant et éteint les deux autres.
   Aucune boîte, aucune carte : rien que de la typographie sur la photo.
   ========================================================================== */
/* Le panneau réserve « header + 1rem » en haut et 2,5rem en bas : le bloc
   centré tombait 25 px trop bas dans la bande réellement visible. On aligne la
   marge basse sur le seul dépassement au-dessus du header (1rem) pour que l'air
   au-dessus du titre égale celui sous les boutons. */
.stages-sec { text-align: left; padding-bottom: 1rem; }

/* ---- Le triptyque, plein écran, en biais ---- */
.stages-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--ink);
  overflow: hidden;
}
.stages-bg-tilt {
  position: absolute;
  inset: -18%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  transform: rotate(-8deg);
}
.stages-pane { position: relative; overflow: hidden; }
.stages-pane img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--cadrage, center 45%);
  filter: grayscale(1) brightness(.34) contrast(1.05);
}
/* Le premier panneau seul est éclairé, de façon FIXE : plus de projecteur
   qui se déplace ni de zoom (demande de Nicolas). */
.stages-pane.is-lit img {
  filter: grayscale(1) brightness(.82) contrast(1.02);
}
/* Bichromie orange, identique au reste du site */
.stages-pane::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--orange);
  mix-blend-mode: color;
}
/* Voile de lisibilité : dégradé vertical + rideau latéral côté texte,
   pour que le petit texte du format actif ne tombe jamais sur une zone claire */
.stages-bg::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(100deg, rgb(12 7 1 / .82) 0%, rgb(12 7 1 / .62) 38%, rgb(12 7 1 / .12) 72%, transparent 100%),
    linear-gradient(180deg, rgb(14 8 1 / .3) 0%, rgb(14 8 1 / .5) 60%, rgb(14 8 1 / .7) 100%);
}

/* ---- Le contenu : trois registres, beaucoup d'air ---- */
.stages-inner {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  /* Bloc centré. C'était impossible tant que le dépliement d'un format faisait
     varier la hauteur de la liste : titre et boutons se déplaçaient à chaque
     clic. Maintenant que les panneaux se compensent exactement (voir
     .stg-detail-boite), la hauteur ne bouge plus d'un pixel et le centrage
     est de nouveau sûr — sans coller le titre au header ni les boutons au bas
     de l'écran, ce que faisait space-between. */
  justify-content: center;
  gap: clamp(1rem, 2.4svh, 1.8rem);
  /* Ancrés aux deux bords, titre et boutons collaient au header et au bas de
     l'écran (8 px mesurés en 375×667) : on leur rend de l'air. */
  padding-block: clamp(.5rem, 2svh, 1.75rem);
  height: 100%;
  width: 100%;
  /* Sans plafond, sur un écran de 1893 px il restait jusqu'à 1537 px de vide
     entre la ligne d'âge et le chevron, rejeté au bord opposé. */
  max-width: 44rem;
  margin-inline: auto;
  min-height: 0;
  color: var(--white);
}
.stages-tete { flex: 0 0 auto; }
/* Hors mobile l'espaceur n'existe pas : en display: block il créerait une
   gouttière de flex supplémentaire et décalerait la composition desktop. */
.stages-espace { display: none; }
.stages-sec .kicker { color: var(--white); opacity: .82; }

/* ---- Le titre : horizontal, centré, en tête de section ----
   Super Blocky, seule occurrence sur le site : c'est ce contraste de police
   qui détache le titre des noms de formats, restés en Humane. Ses capitales
   sont carrées (.60em de large pour .70 de haut) là où celles de la Humane
   sont 2,9× plus hautes que larges — d'où un dimensionnement propre : le mot
   « LES STAGES » fait 5,34em de large ici contre 1,96em en Humane, reprendre
   les valeurs de l'ancienne le ferait déborder de l'écran. */
.stages-titre {
  font-family: 'Super Blocky', 'Arial Black', sans-serif;
  font-weight: 400;
  /* « LES STAGES » fait 5,34em de large en Super Blocky. On conserve la
     hauteur de capitale validée — ~9 % de plus que celle des noms de formats —
     et c'est le mot qui s'allonge : il occupe alors 71 à 87 % du bloc. Le
     plafond de 7.4rem l'empêche de dépasser 90 % sur les très grands écrans. */
  font-size: clamp(2.6rem, min(9.5vw, 13svh), 7.4rem);
  line-height: 1;
  text-transform: uppercase;
  text-align: center;
  color: var(--white);
  margin: 0 0 .35rem;
  text-shadow: 0 2px 14px rgb(0 0 0 / .45);
}
/* Sur téléphone, la formule de base laissait le titre au plancher (41,6 px
   à 375 de large) : trop discret au goût de Nicolas. Un cran au-dessus,
   borné pour que les 5,34em de large de « LES STAGES » tiennent encore à
   320 px (280 px disponibles / 5,34 = 52 px de corps maximum). Placée AVANT
   les variantes de police : à spécificité égale, elles gardent le dernier
   mot et cette taille ne vaut que pour la Super Blocky de base. */
@media (max-width: 899px) {
  .stages-titre { font-size: clamp(3.2rem, 13.5vw, 4.6rem); }
}

/* Variantes de police du titre, choisies dans l'admin (champ « Police du
   titre » de la section). Chaque police a SA formule de taille : « LES
   STAGES » va de 1,96em de large en Humane à 5,34em en Super Blocky, une
   formule commune déborderait avec l'une ou rapetisserait l'autre.
   --blocky = la base ci-dessus, sans surcharge. */
.stages-titre--humane {
  /* La Humane en dur, PAS var(--font-display) : le réglage global de la
     Configuration ne doit pas faire mentir l'option « Humane » de cette
     section, qui a son propre sélecteur. */
  font-family: 'Humane', 'Arial Narrow', sans-serif;
  font-weight: 700;
  font-size: clamp(4rem, min(28vw, 24svh), 14rem);
}
.stages-titre--franxurter {
  font-family: var(--font-logo);
  font-weight: 400;
  font-size: clamp(2.4rem, min(10.5vw, 13svh), 7rem);
}
.stages-titre--sofia {
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: .02em;
  font-size: clamp(2.2rem, min(8.5vw, 11svh), 6rem);
}
.stages-lead {
  max-width: 30rem;
  margin: 0 auto;
  text-align: center;
  font-weight: 500;
  font-size: clamp(.95rem, 1.1vw, 1.12rem);
  color: rgb(255 255 255 / .92);
  text-shadow: 0 1px 8px rgb(0 0 0 / .5);
}

/* ---- Les trois formats : du texte nu, rien d'autre ---- */
.stages-liste {
  /* Hauteur dictée par son contenu : c'est la compensation des panneaux qui
     garantit qu'elle ne varie pas, plus l'absorption de l'espace libre — qui
     collerait de nouveau le titre et les boutons aux bords. */
  flex: 0 0 auto;
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
}
.stg-tete {
  display: flex;
  align-items: center;
  gap: clamp(.7rem, 2vw, 1.6rem);
  width: 100%;
  padding: clamp(.35rem, 1svh, .7rem) 0;
  background: none;
  border: 0;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
/* Les noms restent en Humane (via la classe .display) : l'essai en Super
   Blocky, la police du titre, a été refusé — il faisait disparaître le
   contraste de police qui distingue justement le titre des catégories. */
.stg-nom {
  font-size: clamp(3rem, min(8.5vw, 12svh), 7rem);
  line-height: .9;
  color: rgb(255 255 255 / .52);
  text-shadow: 0 2px 14px rgb(0 0 0 / .5);
  transition: color .4s ease, transform .5s var(--ease-out);
}
.stg-age {
  font: 700 clamp(.8rem, 1vw, .95rem)/1 var(--font-body);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .5);
  transition: color .35s ease;
}
/* Le chevron : signal d'ouverture, évident et universel */
.stg-chevron {
  margin-left: auto;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: clamp(2.4rem, 3.4vw, 3rem);
  height: clamp(2.4rem, 3.4vw, 3rem);
  border: 2px solid rgb(255 255 255 / .45);
  border-radius: 50%;
  color: var(--white);
  transition: transform .45s var(--ease-out), background .35s ease, border-color .35s ease;
}
.stg-chevron svg { width: 55%; height: 55%; }
/* Format actif : le nom s'allume, le chevron devient orange et pivote */
.stg-ligne.is-active .stg-nom { color: var(--white); transform: translateX(.35rem); }
.stg-ligne.is-active .stg-age { color: var(--orange); }
.stg-ligne.is-active .stg-chevron {
  transform: rotate(180deg);
  background: var(--orange);
  border-color: var(--orange);
}
@media (hover: hover) {
  .stg-tete:hover .stg-nom { color: var(--white); }
  .stg-tete:hover .stg-chevron { border-color: var(--white); }
}
.stg-tete:focus-visible { outline: 3px solid var(--orange); outline-offset: 4px; }

/* Le détail n'apparaît que pour le format actif.
   L'animation porte sur la piste de grille, PAS sur max-height : avec
   max-height: 5em pour un texte de ~43 px, le panneau qui s'ouvre atteignait
   sa hauteur pleine avant que celui qui se ferme ait commencé à diminuer.
   Les deux étaient pleins simultanément au milieu de la transition et la
   liste gonflait de 43 px, ce qui repoussait les boutons du bas. En 0fr → 1fr
   la hauteur rendue est exactement celle du texte : ce qui s'ouvre et ce qui
   se ferme se compensent, la liste ne bouge plus. */
/* Les trois textes empilés dans la même cellule donnent à chaque boîte la
   hauteur du plus haut, identique partout : ouverture et fermeture se
   compensent donc exactement, à chaque instant de la transition. Se caler sur
   la hauteur propre à chaque texte ne suffisait pas — en mobile ADOS tient sur
   une ligne (38 px) quand les deux autres en prennent deux (63 px), et changer
   de format déplaçait titre et boutons de 25 px.
   minmax(0, …) et non 0fr seul : « 0fr » vaut « minmax(auto, 0fr) », dont le
   minimum automatique retient le padding du paragraphe (14 px mesurés), que ni
   min-height: 0 ni overflow: hidden ne compriment. */
.stg-detail-boite {
  display: grid;
  grid-template-rows: minmax(0, 0fr);
  transition: grid-template-rows .5s var(--ease-out);
}
.stg-ligne.is-active .stg-detail-boite { grid-template-rows: minmax(0, 1fr); }
.stg-detail-pile {
  display: grid;
  min-height: 0;
  overflow: hidden;
}
.stg-detail-pile > .stg-detail { grid-area: 1 / 1; }
/* Gabarits : ils occupent la place mais ne se voient ni ne s'énoncent. */
.stg-detail--gabarit { visibility: hidden; }
.stg-detail {
  margin: 0;
  opacity: 0;
  padding-bottom: clamp(.6rem, 1.6svh, 1.1rem);
  font-size: clamp(.95rem, 1.15vw, 1.15rem);
  font-weight: 600;
  color: var(--white);
  text-shadow: 0 1px 3px rgb(0 0 0 / .9), 0 2px 14px rgb(0 0 0 / .7);
  transition: opacity .4s ease;
}
.stg-detail span { opacity: .82; font-weight: 500; }
.stg-detail span::before { content: ' · '; }
.stg-ligne.is-active .stg-detail { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .stages-pane img, .stg-nom, .stg-detail, .stg-detail-boite { transition: none; }
}

/* ---- Pied ---- */
.stages-pied {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: .9rem;
}
.stages-note {
  margin: 0;
  font-size: clamp(.8rem, .95vw, .95rem);
  font-weight: 500;
  color: rgb(255 255 255 / .88);
  text-shadow: 0 1px 8px rgb(0 0 0 / .5);
}
.stages-ctas { display: flex; gap: .8rem; flex-wrap: wrap; justify-content: center; }

/* ---- Mobile ---- */
@media (max-width: 899px) {
  /* En mobile le panneau réserve « header + .5rem » : même raisonnement. */
  .stages-sec { padding-bottom: .5rem; }
  /* Gouttière remise à zéro et rendue aux marges des blocs réels : les trois
     espaceurs ci-dessous sont eux aussi des enfants flex, et la gouttière
     s'appliquerait autour d'eux — 5 espacements au lieu de 2, soit 63 px de
     mou perdus, précisément celui qu'on veut redistribuer. */
  .stages-inner { gap: 0; }
  .stages-tete  { margin-bottom: clamp(.8rem, 2svh, 1.4rem); }
  .stages-liste { margin-bottom: clamp(.8rem, 2svh, 1.4rem); }

  /* Répartition pondérée de l'espace libre, 1 : 1 : 2 — au-dessus du titre,
     entre le sous-titre et la liste, sous les boutons. Le titre remonte donc
     nettement pendant que les boutons restent bas dans l'écran.
     Ces espaceurs ne font que partager le mou existant : sur un petit écran où
     il n'y en a pas, ils valent zéro et ne peuvent rien faire déborder. */
  .stages-inner::before,
  .stages-inner::after,
  .stages-espace { content: ''; display: block; }
  .stages-inner::before { flex: 1 1 0; }
  .stages-espace        { flex: 1 1 0; }
  .stages-inner::after   { flex: 2 1 0; }
  /* 15vw × 5,34em ≈ 90 % de la largeur utile. Le mot étant 57 % plus long que
     « STAGES », garder les 18,4vw d'avant le ferait déborder de l'écran. */
  .stages-titre { font-size: clamp(2rem, min(15vw, 9svh), 4.4rem); }
  .stages-lead { font-size: .92rem; }
  .stg-nom { font-size: clamp(2.9rem, 14.5vw, 4.2rem); }
  .stg-age { font-size: .72rem; letter-spacing: .1em; }
  .stg-chevron { width: 2.5rem; height: 2.5rem; border-width: 2px; }
  .stg-detail { font-size: .92rem; }
  .stages-pied { gap: .8rem; }
  .stages-ctas .btn { padding: .95em 1.55em; font-size: .95rem; }
}
@media (max-width: 899px) and (max-height: 750px) {
  .stages-lead { display: none; }
  .stg-nom { font-size: clamp(2.6rem, 13vw, 3.4rem); }
  .stg-chevron { width: 2.2rem; height: 2.2rem; }
  .stages-note { font-size: .78rem; }
  .stages-ctas .btn { padding: .85em 1.4em; font-size: .88rem; }
}

/* ---------- Sections split (stages / présentation) ---------- */
.split { display: grid; gap: 2.5rem; align-items: center; }
/* min-width: 0 OBLIGATOIRE : sans lui, le défilé des partenaires (via le
   max-width de .partn, 34rem) impose 544px de largeur MINIMALE à la colonne
   (min-width:auto des éléments de grille), et sur téléphone toute la section
   se mettait en page à 544px, rognée par le panel : textes coupés au bord
   droit. Troisième fois que ce piège frappe (interrupteur segmenté, pilules),
   le voici documenté au niveau de la grille. */
.split > * { min-width: 0; }
@media (min-width: 900px) {
  .split { grid-template-columns: 1fr 1fr; }
  .split.flip > .split-media { order: 2; }
}
.split-media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 1.2rem;
  box-shadow: 0 24px 60px rgb(28 18 6 / .25);
}
@media (max-width: 899px) {
  .split { gap: 1.2rem; }
  .split-media img { aspect-ratio: 16 / 9; max-height: 28svh; }
  .split-text .lead { font-size: 1rem; }
  /* Le bouton seul se centre sur téléphone (demande de Nicolas, 8 sept.) ;
     surtitre, titre et texte restent alignés à gauche. */
  .split-text .split-bouton { text-align: center; }
}
.split-text .lead { font-size: clamp(1.05rem, 1.3vw, 1.25rem); max-width: 32rem; }

/* ---------- Newsletter + footer intégré (dernier écran de la home) ---------- */
.newsletter {
  text-align: center;
  justify-content: space-between;
  padding-bottom: 0;
  padding-left: 0;
  padding-right: 0;
}
.newsletter .section-title { color: var(--orange); }
.newsletter-inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 0 var(--pad);
  width: 100%;
}
.newsletter-texte {
  max-width: 34rem;
  margin: 0 auto 1.6rem;
  font-size: clamp(1rem, 1.3vw, 1.2rem);
  font-weight: 500;
  color: var(--paper);
}
/* Champ puis bouton, empilés et centrés, à toutes les tailles. Côte à côte,
   le bouton s'alignait sur le milieu du groupe « label + champ » et tombait
   donc plus haut que le champ lui-même : un décalage visible sur desktop. */
.newsletter form {
  display: flex;
  flex-direction: column;
  gap: .65rem;
  max-width: 34rem;
  margin: 0 auto;
  align-items: center;
}
/* .form-field, et non .form-group : c'est la classe que génère Grav. Sa marge
   basse de 19,2px s'ajoutait à la gouttière du formulaire, d'où 32px entre le
   champ et le bouton. */
.newsletter form .form-field { margin: 0; width: 100%; max-width: 22rem; }
.newsletter input[type='email'] {
  width: 100%;
  padding: 1em 1.4em;
  font: 500 1rem var(--font-body);
  border: 2px solid rgb(245 240 232 / .25);
  border-radius: 999px;
  background: rgb(245 240 232 / .07);
  color: var(--paper);
}
.newsletter input[type='email']::placeholder { color: rgb(245 240 232 / .5); }
.newsletter .site-footer { width: 100%; }

/* Boutons de formulaires (plugin Forms) : même style que les .btn */
form button,
form .button,
form input[type='submit'] {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  padding: .9em 1.8em;
  font: 600 .95rem/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  border: 2px solid var(--orange);
  border-radius: 999px;
  background: var(--orange);
  color: var(--white);
  cursor: pointer;
  transition: transform .25s var(--ease-out), background .25s, border-color .25s;
}
form button:hover,
form .button:hover,
form input[type='submit']:hover {
  background: var(--orange-deep);
  border-color: var(--orange-deep);
  transform: translateY(-2px);
}
form .buttons { display: flex; justify-content: center; }

/* ==========================================================================
   Entrée des pages intérieures
   Le contenu se posait d'un coup à l'ouverture d'une page annexe, titres
   compris. Il monte désormais en fondu, une seule fois : à l'ARRIVÉE sur la
   page. Volontairement PAS d'observateur de défilement ici — tout est lancé au
   chargement, y compris ce qui est plus bas, si bien qu'en descendant on ne
   déclenche plus rien. Et au retour arrière, le script du gabarit pose
   « sans-entree » et rien ne rejoue.
   `backwards` est essentiel : l'élément n'est masqué que PENDANT son délai
   d'attente, et reprend son style normal à la fin de l'animation. Il ne peut
   donc pas rester invisible une fois l'animation passée.
   Tout est conditionné à `html.js` : sans JavaScript, aucune animation n'est
   déclarée et la page s'affiche telle quelle.
   ========================================================================== */
@keyframes ast-entree {
  from { opacity: 0; transform: translateY(14px); }
}
html.js body:not(.home) .page-hero > :not(.page-hero-fond),
html.js body:not(.home) .page-body > *,
html.js .atl-hero-inner > *,
html.js .atl-public,
html.js .atl-inscription-inner > * {
  animation: ast-entree .62s var(--ease-out) backwards;
}
/* Cascade courte : le bandeau, puis le corps. Au-delà du troisième bloc, le
   délai n'augmente plus, sinon le bas de page attendrait pour rien. */
html.js body:not(.home) .page-hero > :nth-child(2) { animation-delay: 60ms; }
html.js body:not(.home) .page-hero > :nth-child(3) { animation-delay: 120ms; }
html.js body:not(.home) .page-hero > :nth-child(n+4) { animation-delay: 170ms; }
html.js body:not(.home) .page-body > :nth-child(1) { animation-delay: 200ms; }
html.js body:not(.home) .page-body > :nth-child(2) { animation-delay: 260ms; }
html.js body:not(.home) .page-body > :nth-child(n+3) { animation-delay: 310ms; }
html.js .atl-hero-inner > :nth-child(2) { animation-delay: 70ms; }
html.js .atl-hero-inner > :nth-child(3) { animation-delay: 140ms; }
html.js .atl-hero-inner > :nth-child(n+4) { animation-delay: 210ms; }
html.js .atl-public:nth-of-type(2) { animation-delay: 80ms; }
html.js .atl-public:nth-of-type(n+3) { animation-delay: 140ms; }

/* Retour arrière, filet de sécurité du script, ou mouvement réduit : plus
   aucune animation, le contenu est simplement là.
   Les sélecteurs reprennent EXACTEMENT ceux qui déclenchent l'animation, à
   « sans-entree » près. C'est indispensable : écrits plus court, ils étaient
   moins spécifiques et ne l'emportaient jamais, si bien que le contenu
   serait resté masqué au retour arrière. À spécificité égale, c'est la
   dernière règle écrite qui gagne, d'où leur position ici. */
html.sans-entree body:not(.home) .page-hero > :not(.page-hero-fond),
html.sans-entree body:not(.home) .page-body > *,
html.sans-entree .atl-hero-inner > *,
html.sans-entree .atl-public,
html.sans-entree .atl-inscription-inner > * { animation: none; }
@media (prefers-reduced-motion: reduce) {
  html.js body:not(.home) .page-hero > :not(.page-hero-fond),
  html.js body:not(.home) .page-body > *,
  html.js .atl-hero-inner > *,
  html.js .atl-public,
  html.js .atl-inscription-inner > * { animation: none; }
}

/* ---------- Pages intérieures ---------- */
.page-hero {
  position: relative;
  background: var(--ink);
  color: var(--paper);
  padding: calc(var(--header-h) + 4rem) var(--pad) 3rem;
  overflow: hidden;
}
/* Variante avec visuel : l'image (affiche du spectacle, photo de la page)
   occupe tout le bandeau sous un voile d'encre, le titre orange par-dessus.
   Le cadrage vertical est réglable page par page dans l'admin. */
.page-hero--visuel {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: clamp(21rem, 52svh, 34rem);
  padding-top: calc(var(--header-h) + 2.5rem);
  padding-bottom: 2.6rem;
}
.page-hero-fond {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: var(--bandeau-pos, center 30%);
}
.page-hero-fond::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Voile NOIR et nettement plus dense qu'à l'origine : sur les affiches très
     colorées des spectacles, l'image en couleurs quasi pleines se battait avec
     le titre orange (demande de Nicolas : « un voile noir, pas la couleur
     originale »). Neutre et non teinté encre, pour ne pas virer marron. */
  background: linear-gradient(180deg,
    rgb(5 6 9 / .68) 0%,
    rgb(5 6 9 / .52) 42%,
    rgb(5 6 9 / .9) 100%);
}
.page-hero > :not(.page-hero-fond) { position: relative; z-index: 1; }
.page-hero .kicker { color: var(--paper); opacity: .85; }
.page-hero .display { font-size: clamp(3.2rem, 9.5vw, 8.5rem); color: var(--titre-hero, var(--orange)); margin: 0; }
.page-hero--visuel .display { text-shadow: 0 2px 18px rgb(0 0 0 / .5); }
.page-hero .page-intro { max-width: 40rem; font-size: 1.1rem; font-weight: 500; margin-bottom: 0; }
.page-hero--visuel .page-intro { text-shadow: 0 1px 10px rgb(0 0 0 / .55); }

.page-body { padding: 3.2rem var(--pad) 5rem; max-width: 72rem; margin: 0 auto; width: 100%; }
.page-body h2 { font-family: var(--font-display); text-transform: uppercase; font-size: clamp(2.2rem, 5vw, 3.6rem); margin: 2.4rem 0 1rem; }
/* Trois marches orange devant chaque titre : l'escalier du logo en repère de
   section. Bords vifs, alignées à gauche et s'élargissant vers le bas, comme
   L'ART / SCENE / THEATRE.
   Les positions verticales sont posées explicitement (0, ep+gap, 2×(ep+gap))
   plutôt qu'avec top/center/bottom : l'écart reste strictement égal même si
   la hauteur de la boîte change un jour. Voir les variables --marche-* . */
.page-body h2::before,
.atl-public-tete::before {
  content: '';
  display: block;
  width: calc(var(--marche-l1) + var(--marche-pas) * 2);
  height: calc(var(--marche-ep) * 3 + var(--marche-gap) * 2);
  margin-bottom: 1.1rem;
  background:
    linear-gradient(var(--orange), var(--orange))
      0 0
      / var(--marche-l1) var(--marche-ep) no-repeat,
    linear-gradient(var(--orange), var(--orange))
      0 calc(var(--marche-ep) + var(--marche-gap))
      / calc(var(--marche-l1) + var(--marche-pas)) var(--marche-ep) no-repeat,
    linear-gradient(var(--orange), var(--orange))
      0 calc((var(--marche-ep) + var(--marche-gap)) * 2)
      / calc(var(--marche-l1) + var(--marche-pas) * 2) var(--marche-ep) no-repeat;
}
.page-body h2:first-child { margin-top: 0; }
/* Puces carrées orange : cohérentes avec les jalons, jamais de rond mou. */
.page-body ul:not([class]) { list-style: square; padding-left: 1.3rem; }
.page-body ul:not([class]) li { margin-bottom: .4rem; }
.page-body ul:not([class]) li::marker { color: var(--orange); }
/* Tableaux (horaires des stages, etc.) */
/* display block + overflow : sur les très petits écrans (mesuré : +33px de
   débordement à ~350px), le tableau défile horizontalement au lieu de pousser
   toute la page. */
.page-body table { display: block; width: 100%; max-width: 100%; overflow-x: auto; border-collapse: collapse; margin: 1.4rem 0 1.8rem; }
.page-body th {
  text-align: left;
  font: 600 .76rem/1.3 var(--font-body);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--orange-deep);
  padding: .5rem 1rem .5rem 0;
  border-bottom: 2px solid rgb(28 18 6 / .3);
}
.page-body td { padding: .6rem 1rem .6rem 0; border-bottom: 1px solid rgb(28 18 6 / .12); font-weight: 500; }

/* ---- Briques éditoriales des pages intérieures ---- */
/* Chiffres clés : le nombre en Humane orange, la légende en Sofia — le
   dispositif typographique du site, aucun encadré. */
.chiffres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(9.5rem, 40vw), 1fr));
  gap: 2rem 2rem;
  margin: 2.2rem 0 1.2rem;
  padding: 0;
  list-style: none;
}
.chiffres .nombre {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.8rem, 5.5vw, 4.6rem);
  line-height: .9;
  color: var(--orange);
}
.chiffres .legende {
  display: block;
  margin-top: .45rem;
  font: 600 .78rem/1.35 var(--font-body);
  letter-spacing: .13em;
  text-transform: uppercase;
  opacity: .72;
}

/* Équipements du lieu : plaques blanches à bords vifs, valeur en orange. */
.equipements { display: flex; flex-wrap: wrap; gap: .7rem; margin: 1.6rem 0; padding: 0; list-style: none; }
.equipements li {
  background: var(--white);
  padding: .7rem 1.05rem;
  font: 600 .92rem/1.3 var(--font-body);
  box-shadow: 0 8px 26px rgb(28 18 6 / .07);
}
.equipements strong { color: var(--orange-deep); font-weight: 700; }

/* ---- Entrées en cascade ----
   Chaque élément monte et apparaît à son tour, décalé de 90 ms via --i.
   Le filet de sécurité de site.js les révèle d'office si l'observateur ne
   se déclenche pas : la page reste lisible quoi qu'il arrive. */
.anim {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .72s var(--ease-out), transform .72s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.anim.vu { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .anim { opacity: 1; transform: none; transition: none; }
}

/* Appel final des pages intérieures. */
.page-cta { margin: 3.4rem 0 0; text-align: center; }
.page-cta p { max-width: 34rem; margin: 0 auto 1.4rem; font-weight: 500; }
.page-cta .btn + .btn { margin-left: .8rem; }

/* ==========================================================================
   Page L'Art Scène : « La traversée 2006-2026 »
   La seule page du site qui casse le gabarit intérieur. Un récit continu sur
   fond d'encre : un titre géant dont la dernière ligne est coupée par le pli
   (on comprend qu'il faut descendre), puis une année géante fixée derrière le
   texte qui avance de 2006 à 2026 avec le lecteur. Les photos n'apparaissent
   qu'aux moments clés, en scènes qui s'éclairent.
   ========================================================================== */

.trav {
  background: var(--noir);
  color: var(--paper);
  overflow-x: clip;
  /* Taille du titre géant. « DE SCÈNE » fait environ 1,6 em de large en
     Humane (mesure de référence : « LES STAGES » = 1,96 em pour 10
     caractères), d'où la borne en vw. La borne en svh garantit que le haut
     de page + les deux lignes ENTIÈRES tiennent dans 88 svh : le titre n'est
     jamais coupé (version coupée essayée puis refusée), c'est le début de
     l'édito qui affleure sous le pli et invite à descendre. Le max() évite
     une taille négative sur une fenêtre absurdement basse.
     Le diviseur = nombre de lignes x interligne (2 x 0,90). */
  --titre-fs: max(2.4rem, min(28rem, 55vw, (88svh - 16rem) / 1.8));
}
/* Avec les pastilles d'accès direct dans le hero, la formule leur réserve
   leur hauteur (~7rem avec leurs marges), sinon elles débordaient du premier
   écran de la hauteur exacte qu'aucune constante ne leur avait donnée. */
.trav--portes { --titre-fs: max(2.4rem, min(28rem, 55vw, (88svh - 23rem) / 1.8)); }
.trav ::selection { background: var(--orange); color: var(--ink); }

/* ---- Premier écran : le titre coupé par le pli ---- */
.trav-hero {
  /* 88 svh et non 100 : les 12 svh restants laissent affleurer les premières
     lignes de l'édito sous le titre, au bord de l'écran. C'est cette amorce
     qui dit qu'un récit commence en dessous (la version « titre coupé par le
     pli » a été essayée puis refusée). min-height et non height : sur un très
     petit écran (320 x 568 mesuré), intro + titre débordaient d'un écran fixe
     et chevauchaient le prologue ; en laissant l'écran grandir, rien ne se
     chevauche jamais. */
  min-height: 88svh;
  position: relative;
  display: flex;
  flex-direction: column;
  padding: calc(var(--header-h) + 2.2rem) var(--pad) 0;
}
/* La photo de la landing : plein cadre sous un voile d'encre, fondue dans le
   fond uni vers le bas pour que l'amorce de l'édito reste sur l'encre pure.
   Le dernier arrêt du dégradé est opaque : aucune couture visible entre la
   photo et la suite de la page. */
.trav-hero-fond {
  position: absolute;
  inset: 0 0 -1px;
  background-size: cover;
  /* Cadrage horizontal mesuré sur la photo, pas estimé : le sujet (bras levé
     compris) occupe x 445 à 900 sur 1500, soit 455 px de large. En plein
     cadre sur un téléphone, la fenêtre visible fait 461 px de la source : il
     faut donc caler à 42 % pour que la main entre dans le cadre (à 50 %, le
     bras était coupé). Vérifié de 320 à 414 px de large.
     Le cadrage vertical, lui, reste réglable dans l'admin. */
  background-position: var(--hero-pos-x, 42%) var(--hero-pos-y, 15%);
}
.trav-hero-fond::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    var(--ferme-haut),
    var(--ferme-bas),
    linear-gradient(180deg,
      rgb(2 3 5 / .45) 0%,
      rgb(2 3 5 / .18) 42%,
      var(--noir) 97%);
}
/* Desktop : la photo devient un panneau à droite. Le sujet se retrouve autour
   de 70 % de la largeur et le titre géant dispose de toute la partie gauche.
   Le bord gauche du panneau est fondu dans le noir par un dégradé horizontal
   (et non un masque) : aucune ligne de coupe, et aucune dépendance à la prise
   en charge de mask-image.
   Gain de netteté au passage : dans ce panneau (1190 px de large sur un écran
   de 1920) l'export en 1500 px est affiché RÉDUIT, alors qu'en plein cadre il
   était agrandi de 28 %. */
/* La condition de proportion écarte les tablettes en PORTRAIT : le titre y est
   très grand et le panneau deviendrait une bande étroite où la photo serait
   agrandie. Elles gardent le plein cadre, comme les téléphones. */
@media (min-width: 900px) and (min-aspect-ratio: 1/1) {
  .trav-hero-fond {
    /* Le panneau commence APRÈS le titre : garantie structurelle plutôt que
       valeur calibrée à la main. 1,7 em est la largeur de la ligne la plus
       longue en Humane (mesurée : 1,657 em pour « de scène », à deux tailles
       différentes). Un titre beaucoup plus long saturerait le calcul, d'où la
       borne à 52 % : la photo revient alors sous le texte, ce qui reste le
       comportement voulu quand il n'y a réellement plus la place. */
    left: clamp(38%, calc(var(--pad) + 1.7 * var(--titre-fs) + clamp(1rem, 3vw, 3rem)), 52%);
    /* Le panneau est moins large que haut par rapport à la photo : c'est donc
       la hauteur qui commande, la photo est vue entière de haut en bas (main
       levée comprise) et c'est la largeur qui déborde de quelques dizaines de
       pixels. On garde « cover » plutôt qu'une hauteur imposée pour qu'une
       fenêtre très large et basse ne laisse jamais de vide sur le côté.
       Le cadrage vertical réglé dans l'admin n'a donc pas de prise ici : il
       agit sur mobile et tablette. */
    background-size: cover;
    background-position: var(--hero-pos-x, 42%) center;
  }
  .trav-hero-fond::after {
    background:
      var(--ferme-haut),
      var(--ferme-bas),
      linear-gradient(90deg, var(--noir) 0%, rgb(8 9 12 / 0) 34%),
      linear-gradient(180deg,
        rgb(2 3 5 / .3) 0%,
        rgb(2 3 5 / 0) 38%,
        var(--noir) 99%);
  }
}
/* Écrans larges mais serrés (900 à 1199 px) : le titre occupe déjà presque
   toute la place, le panneau est repoussé à sa borne. On décale alors le
   cadrage pour que le sujet parte du côté droit du panneau au lieu de
   commencer contre le texte. Dégagement mesuré entre la fin du titre et le
   début du bras : 78 px en 904 x 832, 82 px en 985 x 870, contre un
   chevauchement avant correction. */
@media (min-width: 900px) and (max-width: 1199px) and (min-aspect-ratio: 1/1) {
  .trav-hero-fond { --hero-pos-x: 32%; }
}
.trav-hero > :not(.trav-hero-fond) { position: relative; z-index: 1; }
.trav-hero-haut { margin-bottom: clamp(1.5rem, 4svh, 3rem); }
.trav-hero .kicker { color: var(--orange); opacity: 1; margin-bottom: .8rem; }
.trav-intro {
  max-width: 30rem;
  margin: 0;
  font-size: clamp(1.05rem, 1rem + .4vw, 1.3rem);
  font-weight: 500;
  line-height: 1.55;
  opacity: .92;
}
/* Le groupe titre + pastilles se pose au bas des 88 svh d'un seul tenant. */
.trav-hero-bas { margin-top: auto; }
.trav-titre {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--titre-fs);
  /* 0,90 et non 0,84 : mesuré au canvas, l'accent grave de « È » monte à
     0,855 em au-dessus de la ligne de base quand la capitale n'en fait que
     0,70 ; avec un interligne de 0,84 il dépassait donc de 0,015 em dans la
     ligne du dessus et venait toucher « 20 ANS ». À 0,90 il tient dans son
     étage avec un peu d'air, quelle que soit la ligne qui porte l'accent. */
  line-height: .9;
  letter-spacing: .01em;
  text-transform: uppercase;
  color: var(--orange);
}
.trav-titre span { display: block; }

/* ---- Prologue : l'édito, puis la citation en exergue ---- */
.trav-prologue {
  /* Positionnée comme toutes les sections de cette page : les fonds photo sont
     en absolu, donc peints après les blocs NON positionnés. Sans cela, une
     section ordinaire peut se retrouver sous le débord de la photo qui la
     précède. */
  position: relative;
  max-width: 46rem;
  margin-inline: auto;
  /* Petit dégagement seulement : l'édito doit commencer AVANT le pli du
     premier écran (le titre s'arrête à 88 svh), c'est l'amorce qui invite
     à descendre. */
  padding: clamp(1.6rem, 3.5svh, 3rem) var(--pad) 14svh;
}
.trav-lede p {
  margin: 0 0 1em;
  font-size: clamp(1.15rem, 1.05rem + .7vw, 1.55rem);
  line-height: 1.65;
  font-weight: 500;
}
.trav-lede p:last-child { margin-bottom: 0; }
.trav-citation {
  margin: 14svh 0 0;
  padding-left: clamp(1.4rem, 4vw, 2.4rem);
  border-left: .35rem solid var(--orange);
}
.trav-citation p {
  margin: 0;
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.25rem, 1.1rem + 1vw, 1.85rem);
  line-height: 1.5;
}
.trav-citation footer {
  margin-top: 1.2rem;
  font: 600 .8rem/1 var(--font-body);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--orange);
}

/* ---- Scènes : une photo plein écran qui s'éclaire à l'entrée ----
   Le fond démarre presque éteint (comme un plateau avant le lever) et monte
   en lumière quand la scène entre dans l'écran (.vu, posé par le même
   observateur que .anim, avec le même filet de sécurité de 2,5 s). */
.scene {
  position: relative;
  overflow: hidden;
  /* Même choix que les .panel de l'accueil : grande hauteur FIXE (lvh),
     ni vide sous la section ni redimensionnement saccadé sur iPhone. */
  min-height: 100vh;
  min-height: 100lvh;
  display: flex;
  align-items: flex-end;
  padding: calc(var(--header-h) + 3rem) var(--pad) clamp(3rem, 9svh, 5.5rem);
}
.scene-fond {
  position: absolute;
  /* Déborde d'un pixel en bas : les sections ont des hauteurs fractionnaires
     (mesuré : 1026,031 px, 643,547 px…), donc la frontière tombe au milieu
     d'un pixel. Ce débord garantit que ce pixel est couvert en entier. */
  inset: 0 0 -1px;
  background-size: cover;
  background-position: var(--fond-pos, center 40%);
}
/* La montée en lumière se fait par une COUCHE noire qui s'efface, et non par
   filter: brightness() sur le fond. Un filtre s'applique aussi au voile porté
   par ::after : le noir censé fermer le bas de la photo en sortait assombri
   (#08090c filtré à .85 devient #07080a), donc différent du fond de la page,
   et c'est cette différence qu'on voyait comme un trait à la fin de la photo.
   Le repère se déplaçant avec la hauteur d'écran, il sautait aux yeux sur
   téléphone. Ici la couche est SOUS le voile : le voile garde ses couleurs
   exactes. */
.scene-fond::before {
  content: '';
  position: absolute;
  inset: 0;
  background: #000;
  opacity: .58;
  transition: opacity 1.6s ease;
}
.scene.vu .scene-fond::before { opacity: .1; }
.scene-fond::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Voile neutre : le voile chaud d'origine faisait virer les photos au
     marron, ce que la page a justement chassé.
     Le premier arrêt est opaque et s'efface en 12 % : la photo émerge du noir
     de la page au lieu d'y apparaître sur une ligne franche, qui se remarquait
     à l'entrée de la section. */
  /* Le dernier arrêt DOIT être le noir opaque : à .86, la photo transparaissait
     encore sur le pixel de jointure et dessinait le trait clair signalé entre
     les sections. Le fondu final est court, l'image n'y perd rien. */
  background:
    var(--ferme-haut),
    var(--ferme-bas),
    linear-gradient(180deg,
      var(--noir) 0%,
      rgb(2 3 5 / .5) 6%,
      rgb(2 3 5 / .32) 45%,
      rgb(2 3 5 / .86) 93%,
      var(--noir) 100%);
}
.scene-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 46rem;
  margin-inline: auto;
}

/* ---- Titres de section et prose de la traversée ---- */
.trav-t {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.6rem, 6vw, 4.6rem);
  line-height: .95;
  text-transform: uppercase;
  margin: 0 0 1.2rem;
}
.trav-prose p { margin: 0 0 1em; font-size: clamp(1.02rem, 1rem + .3vw, 1.2rem); line-height: 1.7; }
.trav-prose p:last-child { margin-bottom: 0; }

/* ---- Le fondateur : la photo occupe l'écran, le texte est décollé dessous ----
   La photo garde un plein écran franc, presque sans voile sur sa moitié haute
   (les visages restent nets et colorés), puis le noir monte pour devenir plein
   avant que le texte ne commence. Le texte n'est donc jamais posé sur l'image :
   il repose sur du noir dense, et il peut s'allonger autant que l'éditeur le
   souhaite sans jamais remonter sur les visages, puisque la photo est ancrée en
   haut et haute de 100 svh, indépendamment de la longueur du texte. */
.trav-fondateur {
  display: block;
  min-height: 0;
  padding: 0 var(--pad) clamp(3rem, 10svh, 6rem);
}
.trav-fondateur .scene-fond {
  height: 100svh;
  bottom: auto;
}
/* La photo émerge du noir au lieu d'y être posée d'un coup : le premier arrêt
   est opaque et s'efface en 15 %, ce qui supprime la ligne franche à l'entrée
   de la section. La zone claire est calée sur le haut de l'image, là où sont
   les visages, puis le noir remonte tôt pour dégager la place du texte. */
.trav-fondateur .scene-fond::after {
  background:
    var(--ferme-haut),
    var(--ferme-bas),
    linear-gradient(180deg,
      var(--noir) 0%,
      rgb(2 3 5 / .42) 7%,
      rgb(2 3 5 / .05) 16%,
      rgb(2 3 5 / .12) 34%,
      rgb(2 3 5 / .78) 56%,
      var(--noir) 70%);
}
/* Le texte commence à 74 svh, juste après que le dégradé a atteint le noir
   plein (70 %) : il repose donc sur du noir franc, sans être posé sur l'image,
   tout en restant visible dès qu'on arrive sur la section. Le poser sous la
   photo entière le renvoyait beaucoup trop bas. */
.trav-fondateur .scene-inner { padding-top: 74svh; }

/* Le fondateur : portrait à gauche si une photo est fournie. */
.trav-fondateur-grid { display: grid; gap: 2rem; }
@media (min-width: 760px) {
  .trav-fondateur-grid { grid-template-columns: minmax(12rem, 1fr) 2.2fr; align-items: start; }
}
.trav-fondateur-grid img { width: 100%; box-shadow: 0 18px 50px rgb(0 0 0 / .45); }
.trav-fondateur-grid p { margin: 0 0 1em; line-height: 1.7; }
.trav-fondateur-grid p:last-child { margin-bottom: 0; }

/* ---- La frise : l'année géante suit le lecteur ----
   L'année est collée au centre de l'écran (sticky sur toute la hauteur, la
   marge négative rend sa place au flux) et le récit défile par-dessus. Le
   texte affiché est purement décoratif (aria-hidden) : chaque jalon porte sa
   propre année, lisible sans JS et par les lecteurs d'écran. */
.trav-frise { position: relative; }
.trav-annee {
  position: sticky;
  top: 0;
  height: 100svh;
  margin-bottom: -100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.trav-annee-txt {
  font-family: var(--font-display);
  font-weight: 700;
  /* 85vw et non 92 : les cellules de largeur fixe portent l'année à 1,08 em
     de large contre 0,96 auparavant, et à 92vw les chiffres touchaient les
     bords de l'écran (373 px mesurés pour 375 disponibles). */
  font-size: min(62rem, 85vw, 115svh);
  line-height: 1;
  /* Une année ne se replie jamais : un repli doublerait sa hauteur et casserait
     le raccord entre ses deux moitiés. */
  white-space: nowrap;
  letter-spacing: .015em;
  color: var(--orange);
  opacity: .13;
}
/* Chiffres de largeur fixe. La Humane n'a pas de chiffres tabulaires (vérifié
   au canvas : « 0000 » et « 1111 » ne mesurent pas pareil), donc
   font-variant-numeric ne sert à rien ici. Sans cette cellule, passer de
   « 2011 » (0,88 em) à « 2006 » (0,96 em) élargissait le nombre de 0,08 em,
   soit 66 px à la taille affichée : centré, il se décalait de 33 px de chaque
   côté à chaque changement d'année. La cellule vaut le chiffre le plus large
   (0,252 em) plus un filet d'air. */
.trav-annee-txt i {
  display: inline-block;
  width: .27em;
  font-style: normal;
  text-align: center;
}
.trav-annee-txt.pulse { animation: trav-pulse 1.1s ease; }
@keyframes trav-pulse {
  30% { opacity: .32; }
}
.trav-corps {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  /* Écart resserré : à 44 svh, deux dates voisines étaient séparées de plus
     d'un écran et la traversée traînait. À 26 svh il reste un temps mort net
     entre deux jalons sans que le lecteur attende. */
  gap: clamp(8rem, 26svh, 15rem);
  padding: 14svh 0 16svh;
}
.trav-frise-tete { text-align: center; padding: 0 var(--pad); }
.trav-frise-tete .trav-t {
  font-size: clamp(4.2rem, 10vw, 6.5rem);
  margin-bottom: 0;
}
.trav-jalon {
  max-width: 34rem;
  margin-inline: auto;
  padding: 0 var(--pad);
  text-align: center;
}
.trav-jalon-annee {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  line-height: 1;
  text-transform: uppercase;
  color: var(--orange);
  margin: 0 0 .7rem;
}
.trav-jalon p {
  margin: 0;
  font-size: clamp(1.05rem, 1rem + .4vw, 1.28rem);
  line-height: 1.65;
  font-weight: 500;
  text-shadow: 0 1px 14px rgb(4 3 1 / .85);
}
.trav-jalon-photo { margin: 1.8rem 0 0; }
.trav-jalon-photo img { width: 100%; box-shadow: 0 18px 50px rgb(0 0 0 / .45); }

/* Le lieu, raconté au passage de son année : la scène photo couvre l'année
   géante le temps d'une visite, puis la traversée reprend. */
.trav-lieu .equipements { margin-bottom: 0; }
/* Deux « slides » dans la traversée : le lieu, et l'arrivée en chiffres.
   La page défile librement, mais quand le défilement s'arrête aux abords de
   l'une de ces deux sections, l'écran vient s'aimanter dessus plein cadre,
   comme un panneau de l'accueil ; ensuite le défilement redevient libre.
   L'aimant est de PROXIMITÉ (pas mandatory : avec deux zones d'accroche sur
   toute la page, un aimant obligatoire rappellerait l'écran vers elles depuis
   n'importe où). La classe est posée par le script quand la page contient les
   sections. */
html.snap-traversee { scroll-snap-type: y proximity; }
.trav-lieu, .trav-arrivee { scroll-snap-align: start; }

/* ---- L'arrivée : aujourd'hui, en chiffres ----
   Seule rupture claire du récit : après le noir continu, la page s'ouvre sur
   le crème. La grille des chiffres EST le damier, les cases orange étant
   posées en quinconce ; il n'y a donc aucun motif décoratif ajouté par-dessus,
   et le damier reste juste quel que soit le nombre de chiffres saisis. */
.trav-arrivee {
  /* La taille d'une case découle de la hauteur disponible, pas de la largeur :
     c'est ce qui fait tenir le titre ET les deux lignes du damier dans un même
     écran. La seconde borne empêche le damier de déborder en largeur sur les
     fenêtres basses et étroites. Réserve de 19rem = paddings + tête.
     Vaut pour 6 chiffres sur 3 colonnes ; au-delà de deux lignes, la section
     redevient plus haute qu'un écran (le défilement reste libre). */
  --case: clamp(6.5rem, min((100svh - 21.5rem) / 2, (100vw - 2 * var(--pad)) / 3), 17rem);
  --damier-l: calc(var(--case) * 3);
  position: relative;
  /* Au moins un écran de haut : la moitié claire de l'année fait 100 svh, et un
     élément collé ne peut pas déborder de son conteneur. Dans une section plus
     courte, il était donc contraint et les deux moitiés se désalignaient
     (159 px d'écart mesurés en 375 x 812, alors qu'elles coïncidaient déjà en
     1280 x 720 où la section était presque aussi haute qu'un écran). */
  min-height: 100svh;
  /* Découpe la moitié basse de l'année géante exactement sur la frontière.
     clip-path et non overflow: hidden — un ancêtre en overflow devient le
     conteneur de défilement de référence et empêche purement et simplement
     ses enfants de se coller (mesuré : la copie suivait le flux au lieu de
     rester en haut de l'écran). clip-path découpe sans rien changer au
     collage. */
  clip-path: inset(0);
  background: var(--paper);
  color: var(--ink);
  /* Le retrait vertical vit sur le corps, pour que celui-ci puisse remplir
     l'écran et centrer son contenu. flow-root est indispensable : sans padding
     haut, la marge négative de la copie claire de l'année fusionnait avec celle
     de la section et remontait la SECTION au lieu de l'année, ce qui doublait
     sa hauteur (1624 px mesurés pour 812 attendus). */
  display: flow-root;
  padding: 0 var(--pad);
}
.trav-arrivee-corps {
  min-height: 100vh;
  min-height: 100lvh;
  /* En haut, le header fixe passe au-dessus de la section quand la slide
     s'aimante plein écran : le rembourrage lui réserve sa place, sinon il
     écrasait le titre « 2026 » (retour de Nicolas). La réserve de la formule
     --case en tient compte. */
  padding-block: calc(var(--header-h) + 1.4rem) clamp(2.2rem, 7svh, 4.2rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* La copie claire de l'année : même boîte que celle de la frise, mais sa
   position naturelle est un écran PLUS HAUT (margin-top négatif), si bien
   qu'elle est déjà collée en haut de l'écran quand la frontière y entre. Les
   deux moitiés se rejoignent donc pixel pour pixel, sans aucun calcul. */
.trav-annee--clair {
  margin-top: -100svh;
  margin-bottom: 0;
  /* Annule le retrait latéral de la section : sans cela, la boîte est plus
     étroite que dans la frise (335 px contre 375 en mobile), l'année s'y
     replie sur deux lignes et les deux moitiés ne coïncident plus du tout
     (159 px d'écart vertical mesurés, soit exactement la moitié de la ligne
     surnuméraire). */
  margin-inline: calc(-1 * var(--pad));
}
.trav-annee--clair .trav-annee-txt { opacity: .2; }
.trav-arrivee-tete {
  position: relative;
  z-index: 1;
  width: var(--damier-l);
  max-width: 100%;
  margin: 0 auto clamp(.8rem, 2.5svh, 1.7rem);
}
.trav-arrivee-annee {
  margin: 0 0 .1rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: min(8rem, 20vw, 16svh);
  line-height: .9;
  color: var(--orange);
}
.trav-arrivee .trav-t { font-size: clamp(1.5rem, 3vw, 2.4rem); color: var(--ink); margin: 0; }

.trav-damier {
  /* Au-dessus de l'année en filigrane, qui passe donc derrière les cases. */
  position: relative;
  z-index: 1;
  width: max-content;
  max-width: 100%;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  display: grid;
  /* Trois colonnes : un nombre IMPAIR suffit à ce que nth-child(even) dessine
     un vrai damier, l'alternance se décalant d'elle-même à chaque ligne. */
  grid-template-columns: repeat(3, var(--case));
  justify-content: center;
  gap: 0;
}
.trav-damier li {
  width: var(--case);
  height: var(--case);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: clamp(.6rem, calc(var(--case) * .09), 1.6rem);
  background: var(--paper);
}
.trav-damier li:nth-child(even) { background: var(--orange); }
/* Texte en encre sur les DEUX couleurs : sur l'orange, le crème ne donne que
   2,5:1 alors que l'encre monte à 7,4:1. C'est le choix déjà retenu pour
   l'aplat orange de la section « Les stages ». */
/* Les corps de texte suivent la taille de la case : une valeur en vw seule
   débordait des petites cases sur les fenêtres basses. */
.trav-damier .nombre {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(var(--case) * .34);
  line-height: .82;
  color: var(--ink);
}
.trav-damier .legende {
  display: block;
  margin-top: .45rem;
  font: 600 clamp(.6rem, calc(var(--case) * .062), .78rem)/1.35 var(--font-body);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: .78;
}
@media (max-width: 700px) {
  /* Deux colonnes et trois lignes : la réserve de hauteur change, et avec un
     nombre PAIR de colonnes nth-child(even) empilerait les cases orange en
     colonnes — le damier demande alors une période de 4. */
  .trav-arrivee {
    --case: clamp(4.6rem, min((100svh - 17.5rem) / 3, (100vw - 2 * var(--pad)) / 2), 11rem);
    --damier-l: calc(var(--case) * 2);
  }
  .trav-damier { grid-template-columns: repeat(2, var(--case)); }
  .trav-damier li:nth-child(even) { background: var(--paper); }
  .trav-damier li:nth-child(4n+2),
  .trav-damier li:nth-child(4n+3) { background: var(--orange); }
}

/* ---- L'esprit : la photo au fond, le texte dans un panneau de verre ---- */
.trav-esprit {
  position: relative;
  /* Moins d'air en bas qu'en haut : l'appel final enchaîne directement sur la
     conclusion, sans écran de vide entre les deux. */
  padding: 16svh var(--pad) 7svh;
}
.trav-esprit:not(.trav-esprit--photo) { max-width: 46rem; margin-inline: auto; }
/* La photo se fond dans le noir sur ses quatre bords : aucune arête visible,
   elle affleure au milieu de la page. Les arrêts transparents sont écrits en
   rgb(8 9 12 / 0) et non « transparent », qui interpole vers un noir pur et
   ferait apparaître un halo gris sur les côtés. */
.trav-esprit-fond {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: var(--fond-pos, center 40%);
}
.trav-esprit-fond::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    var(--ferme-haut),
    var(--ferme-bas),
    linear-gradient(180deg, var(--noir) 0%, rgb(8 9 12 / 0) 22%),
    linear-gradient(0deg,   var(--noir) 0%, rgb(8 9 12 / 0) 22%),
    linear-gradient(90deg,  var(--noir) 0%, rgb(8 9 12 / 0) 16%),
    linear-gradient(270deg, var(--noir) 0%, rgb(8 9 12 / 0) 16%),
    /* Plus dense en haut et en bas, là où du texte nu repose sur la photo ;
       plus clair au milieu, derrière le panneau, qui porte son propre flou. */
    linear-gradient(180deg,
      rgb(2 3 5 / .66) 0%,
      rgb(2 3 5 / .42) 30%,
      rgb(2 3 5 / .34) 58%,
      rgb(2 3 5 / .62) 100%);
}
.trav-esprit-fond { inset: 0 0 -1px; }
/* Titre, introduction et conclusion vivent directement sur la photo : le
   panneau ne garde que les piliers, ce qui le raccourcit nettement et laisse
   voir l'image au-dessus, autour et en dessous, y compris sur téléphone où il
   occupait sinon tout l'écran. L'ombre portée sécurise la lisibilité quelle
   que soit la photo choisie dans l'admin. */
.trav-esprit-tete {
  position: relative;
  z-index: 1;
  max-width: 44rem;
  margin-inline: auto;
  text-shadow: 0 2px 18px rgb(2 3 5 / .85), 0 1px 4px rgb(2 3 5 / .7);
}
/* Le titre de cette section est plus grand que les autres : il porte seul, sur
   la photo, sans plaque derrière lui. */
.trav-esprit-tete .trav-t {
  /* Borne basse relevée : c'est elle qui s'applique sur téléphone (8,5vw ne
     valait que 32px en 375 de large), et le titre y paraissait petit. */
  font-size: clamp(4.6rem, 11vw, 7.5rem);
  margin-bottom: 1rem;
}
.trav-esprit-fin { margin-top: clamp(1.6rem, 4svh, 2.6rem); }

/* Un seul panneau pour les quatre piliers : une grille de quatre cartes ferait
   exactement le rendu de gabarit qu'on cherche à éviter. */
.trav-esprit-bloc {
  position: relative;
  z-index: 1;
  max-width: 44rem;
  margin: clamp(1.4rem, 4svh, 2.4rem) auto 0;
  padding: clamp(1.2rem, 3.5vw, 2.4rem) clamp(1.4rem, 4vw, 2.8rem);
  background: rgb(6 7 10 / .55);
  backdrop-filter: blur(22px) saturate(1.2);
  -webkit-backdrop-filter: blur(22px) saturate(1.2);
  /* Bords travaillés : un contour fin sur tout le pourtour, une arête claire en
     haut et une plus sourde en bas, comme une vraie tranche de verre éclairée
     par le dessus. L'ombre portée large décolle le panneau de la photo. */
  border: 1px solid rgb(255 255 255 / .1);
  border-radius: clamp(1rem, 2.4vw, 1.7rem);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .22),
    inset 0 -1px 0 rgb(255 255 255 / .05),
    0 34px 90px rgb(0 0 0 / .5);
}
/* Sans flou d'arrière-plan, le panneau se referme sur une teinte opaque :
   le texte reste lisible, il perd seulement la transparence. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .trav-esprit-bloc { background: rgb(6 7 10 / .93); }
}
/* Piliers : une colonne, séparés par des filets. Les numéros 01 à 04 ont été
   retirés (jugés « AI slop »), le titre en orange suffit à ouvrir chaque item. */
.trav-piliers {
  list-style: none;
  display: block;
  margin: 0;
  padding: 0;
}
/* Aucun filet entre les piliers : c'est l'écart qui sépare, et le titre orange
   qui ouvre chaque item. Quatre traits alignés donnaient un air de tableau. */
.trav-piliers li + li { margin-top: clamp(1.5rem, 3.4vw, 2.2rem); }
.trav-piliers h3 {
  font: 700 .95rem/1.35 var(--font-body);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--orange);
  margin: 0 0 .4rem;
}
.trav-piliers p { margin: 0; opacity: .9; line-height: 1.6; }

/* L'année géante de la frise est un élément POSITIONNÉ (sticky) : elle est donc
   peinte après tous les blocs non positionnés qui la suivent, et transparaissait
   à travers les sections d'après, où l'on voyait redescendre le « 2022 » du
   dernier jalon. Il suffit que ces sections soient positionnées à leur tour :
   elles reviennent alors dans la même couche et l'ordre du DOM les fait passer
   devant. Le passage à l'année d'arrivée devient invisible par construction. */
.trav-partenaires,
.trav-libre,
.trav-cta { position: relative; }

/* ---- Partenaires et contenu libre ---- */
.trav-partenaires,
.trav-libre {
  max-width: 46rem;
  margin-inline: auto;
  padding: 0 var(--pad) 10svh;
}

/* Plaques (équipements, partenaires) sur l'encre : verre discret, valeur orange. */
.trav .equipements li { background: rgb(245 240 232 / .1); color: var(--paper); box-shadow: none; }
.trav .equipements strong { color: var(--orange); }

/* ---- L'appel final ---- */
.trav-cta {
  text-align: center;
  padding: 7svh var(--pad) 14svh;
}

/* Cette page ne contient AUCUN marron, pied de page compris : l'encre y était
   la dernière trace de chaleur et elle se voyait. Trois surfaces à traiter, en
   plus des sections elles-mêmes : le corps du document, le pied de page global
   et la toile (html), dont le fond apparaît sur la fraction de pixel qui reste
   sous le dernier élément quand les hauteurs sont fractionnaires. */
body.page-trav { background: var(--noir); }
body.page-trav .site-footer {
  background: var(--noir);
  /* Pas de filet supérieur : c'était un trait clair pleine largeur sur du noir,
     donc exactement l'artefact de jointure qu'on traque ailleurs. */
  border-top: 0;
}
html:has(.page-trav) { background: var(--noir); }
.trav-cta .logo-stack { font-size: clamp(2.2rem, 5vw, 3.4rem); margin-bottom: 2.2rem; }
.trav-cta p {
  max-width: 30rem;
  margin: 0 auto 1.8rem;
  font-size: clamp(1.05rem, 1rem + .4vw, 1.3rem);
  font-weight: 500;
}
.trav-cta-btns { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center; }

/* ---- Mobile : la traversée reste le même récit, resserré ---- */
@media (max-width: 700px) {
  /* Le premier écran se resserre pour que l'amorce de l'édito reste
     réellement visible sous le titre (10 px seulement mesurés en 375 x 812
     avant ces ajustements : illisible comme signal). */
  .trav { --titre-fs: max(2.4rem, min(28rem, 52vw, (88svh - 16rem) / 1.8)); }
  .trav--portes { --titre-fs: max(2.4rem, min(28rem, 52vw, (88svh - 23rem) / 1.8)); }
  .trav-hero { padding-top: calc(var(--header-h) + 1.2rem); }
  .trav-hero-haut { margin-bottom: 1.2rem; }
  .trav-corps { gap: clamp(6.5rem, 22svh, 11rem); }
  .trav-citation { margin-top: 10svh; }
  .trav-esprit, .trav-cta { padding-top: 12svh; padding-bottom: 12svh; }
}

/* Tablettes en PORTRAIT : le titre y atteignait son plafond (448 px de corps,
   deux lignes de 752 px) et le premier écran dépassait la hauteur de l'écran,
   si bien que l'amorce de l'édito passait entièrement dessous (0 px visible
   mesuré en 820 x 1180) : l'invitation à défiler disparaissait. La réserve
   passe de 16 à 20 rem, ce qui correspond au haut de page réellement occupé
   quand la phrase d'introduction se replie sur trois lignes.
   Les téléphones sont exclus (leur largeur commande déjà la taille du titre,
   la réserve les rétrécirait sans raison). */
@media (min-width: 701px) and (max-aspect-ratio: 1/1) {
  /* 23vw au lieu du plafond de 28rem : à sa taille de grand écran, le titre
     occupait 73 % de la largeur d'un iPad Pro (744 px sur 1024), la photo
     repassait donc en plein cadre et le titre tombait sur le visage. Bridé à
     23vw, il tient dans 40 % de la largeur (1,66 em de large par ligne,
     mesuré) et laisse la place au panneau photo. */
  .trav { --titre-fs: max(2.4rem, min(23vw, (88svh - 20rem) / 1.8)); }
  .trav--portes { --titre-fs: max(2.4rem, min(23vw, (88svh - 27rem) / 1.8)); }
  /* L'introduction doit s'arrêter avant le panneau, qui commence à 45 % de la
     largeur : une valeur fixe ne suffit pas (à 24rem elle le dépassait encore
     de 76 px sur un iPad 768). La borne en vw la tient sur tous les formats. */
  .trav-intro { max-width: min(24rem, 38vw); }
  /* Le panneau photo tient à droite comme sur grand écran, mais il ne descend
     pas jusqu'en bas : à pleine hauteur, une image horizontale dans une bande
     verticale est agrandie au point que le bras levé sort du cadre. À 75 svh,
     le sujet entier tient dans le panneau sur les trois formats de tablette
     (vérifié en 768 x 1024, 820 x 1180 et 1024 x 1366). Le titre occupe le bas
     à gauche, sur le noir. */
  .trav-hero-fond {
    left: 45%;
    height: 75svh;
    bottom: auto;
    background-size: cover;
    background-position: var(--hero-pos-x, 42%) center;
  }
  .trav-hero-fond::after {
    background:
      linear-gradient(90deg, var(--noir) 0%, rgb(8 9 12 / 0) 34%),
      linear-gradient(180deg,
        rgb(2 3 5 / .25) 0%,
        rgb(2 3 5 / 0) 42%,
        rgb(2 3 5 / .45) 74%,
        var(--noir) 100%);
  }
}

/* ---- Mouvement réduit : tout est posé, rien ne clignote ---- */
@media (prefers-reduced-motion: reduce) {
  .scene-fond::before { opacity: .1; transition: none; }
  .trav-annee-txt.pulse { animation: none; }
}

/* ---- Fiche spectacle : texte à gauche, affiche et réservation à droite ---- */
/* Trois cases nommées : le lieu vit DANS la grille, sous le texte et à côté
   de l'affiche. Posé après elle, il partait sous la colonne la plus longue
   et laissait un trou. Sur téléphone : texte, affiche, lieu. */
.event-grid {
  display: grid;
  gap: 2.6rem;
  align-items: start;
  grid-template-areas:
    'texte'
    'cote'
    'lieu';
}
.event-texte { grid-area: texte; min-width: 0; }
.event-cote { grid-area: cote; }
.event-grid .event-lieu { grid-area: lieu; }
@media (min-width: 900px) {
  .event-grid {
    grid-template-columns: minmax(0, 1.6fr) minmax(16rem, 1fr);
    gap: 2.6rem 3.5rem;
    grid-template-areas:
      'texte cote'
      'lieu  cote';
  }
  /* align-self: start est OBLIGATOIRE pour un sticky en grille : étirée sur
     la hauteur de sa case, la colonne n'aurait aucune marge de déplacement.
     Le top ci-dessous n'est qu'un repli sans JS : le script le recale pour
     que le BAS de la colonne (bouton Réserver) reste visible quand elle est
     plus haute que l'écran (retour de Nicolas : le bouton passait sous le
     pli). */
  .event-cote { position: sticky; align-self: start; top: calc(var(--header-h) + 1.5rem); }
}
.event-cote { display: flex; flex-direction: column; gap: 1.3rem; }
.event-affiche { margin: 0; }
.event-affiche img {
  width: 100%;
  border-radius: 1.1rem;
  box-shadow: 0 18px 50px rgb(28 18 6 / .22);
}
/* align-self: stretch : la carte reprend exactement la largeur de l'affiche.
   La définition de base de .info-card porte align-self: start (utile dans la
   grille des ateliers), qui la resserrait ici sur son contenu : 257 px pour
   une affiche de 382, l'écart signalé par Nicolas. */
.event-cote .info-card { position: static; align-self: stretch; }

/* ---- Le lieu : adresse cliquable + carte ----
   Sous le texte du spectacle : un bouton-adresse qui ouvre Google Maps, et la
   carte intégrée en dessous. Mêmes coins et même ombre que l'affiche. */
/* Le lieu vient après la grille : sur téléphone il tombe donc après l'affiche
   et le bouton de réservation. Sur grand écran, il reprend la largeur de la
   colonne de texte pour rester aligné avec elle. */
.event-lieu { margin-top: .4rem; }
.event-adresse { margin-bottom: 1.1rem; }
.event-map iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  border: 0;
  border-radius: 1.1rem;
  box-shadow: 0 14px 40px rgb(28 18 6 / .14);
}

/* ==========================================================================
   Pages ateliers : « un public, une scène »
   Tous les âges sur la même page sans se mélanger : un bandeau photo plein
   écran qui donne accès direct à chaque public, puis une partie par public,
   alignée alternativement à gauche et à droite, avec ses horaires dans un
   volet dépliant. La bande orange d'inscription referme la page.
   ========================================================================== */

.atl-hero {
  position: relative;
  min-height: 82svh;
  display: flex;
  align-items: flex-end;
  padding: calc(var(--header-h) + 2rem) var(--pad) clamp(2rem, 5svh, 3.2rem);
  background: var(--ink);
  color: var(--paper);
}
/* Une seule discipline, donc pas de sommaire : le bandeau se raccourcit au
   lieu de laisser un grand vide sous l'accroche (cas de l'improvisation). */
.atl-hero--simple { min-height: 62svh; }
/* Bandeau compact (page Les stages) : même gabarit de hauteur que les heros
   des pages Billetterie et Programmation, le grand format photo faisait
   « beaucoup trop gros » (Nicolas) pour un visuel illustratif. */
.atl-hero--compact { min-height: clamp(21rem, 52svh, 34rem); }
.atl-hero-fond {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: var(--fond-pos, center 30%);
}
.atl-hero-fond::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgb(5 6 9 / .62) 0%,
    rgb(5 6 9 / .38) 40%,
    rgb(5 6 9 / .9) 100%);
}
/* Sur téléphone, le bandeau est étroit : la photo y est bien plus agrandie et
   un sujet clair (une robe blanche, un projecteur) se retrouve juste sous le
   titre. Mesuré sur les trois disciplines, le contraste du titre orange y
   tombait entre 1,98 et 2,56 pour 1, sous le seuil de 3 pour du grand texte.
   Le voile devient donc dense dès 65 % de la hauteur, là où le titre commence,
   et laisse les visages du haut intacts. Contraste obtenu : 3,9 à 4,9 pour 1. */
@media (max-width: 899px) {
  .atl-hero-fond::after {
    background: linear-gradient(180deg,
      rgb(5 6 9 / .62) 0%,
      rgb(5 6 9 / .38) 40%,
      rgb(5 6 9 / .82) 65%,
      rgb(5 6 9 / .9) 100%);
  }
}
.atl-hero-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 72rem;
  margin-inline: auto;
}
.atl-hero .kicker { color: var(--paper); opacity: .8; }
.atl-titre {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3.6rem, 11vw, 9rem);
  line-height: .9;
  text-transform: uppercase;
  color: var(--orange);
  margin: 0 0 .35rem;
}
.atl-accroche {
  max-width: 34rem;
  margin: 0;
  font-size: clamp(1.08rem, 1rem + .5vw, 1.4rem);
  font-weight: 500;
  text-shadow: 0 1px 12px rgb(5 6 9 / .7);
}

/* Accès direct à chaque public : des pastilles sur une seule ligne. Les
   grandes lignes nues d'avant ne se lisaient pas comme cliquables et prenaient
   trois fois la hauteur nécessaire ; ces pastilles reprennent le langage des
   filtres de la programmation, immédiatement compris. */
.atl-portes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: clamp(1.1rem, 3svh, 1.8rem);
}
/* Les mêmes pastilles dans le hero de la page L'Art Scène : sous le titre
   (posé au bas du hero par sa margin auto), avec un peu d'air avant l'amorce
   de l'édito qui affleure en dessous. Les sections visées gardent le header
   hors du champ à l'arrivée. */
.trav-portes { position: relative; z-index: 2; margin: .85rem 0 1rem; }
#histoire, #esprit { scroll-margin-top: calc(var(--header-h) + .5rem); }
/* Le lieu se cale au ras de l'écran, comme un panneau de l'accueil : son
   padding interne loge déjà le header. La marge d'ancrage vaut pour la
   pastille « Aller à » ET pour l'aimant du défilement (le snap la lit aussi),
   les deux arrivées donnent donc exactement le même cadrage. */
#lieu { scroll-margin-top: 0; }
.atl-portes-libelle {
  font: 600 .72rem/1 var(--font-body);
  letter-spacing: .22em;
  text-transform: uppercase;
  opacity: .7;
  margin-right: .2rem;
}
.atl-porte {
  display: inline-flex;
  align-items: baseline;
  gap: .45em;
  padding: .55em 1.05em;
  font: 600 .84rem/1 var(--font-body);
  letter-spacing: .06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--paper);
  background: rgb(245 240 232 / .1);
  border: 1px solid rgb(245 240 232 / .38);
  border-radius: 999px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.atl-porte-tranche {
  font-size: .74em;
  font-weight: 500;
  letter-spacing: .08em;
  opacity: .72;
}
.atl-porte:hover,
.atl-porte:focus-visible {
  background: var(--orange);
  border-color: var(--orange);
  color: var(--ink);
}
.atl-porte:hover .atl-porte-tranche,
.atl-porte:focus-visible .atl-porte-tranche { opacity: .8; }
/* Sur téléphone, la tranche d'âge dans la pastille faisait passer le sommaire
   sur trois lignes (107 px mesurés) : seul le nom du public est conservé, la
   tranche restant affichée en tête de sa section. */
@media (max-width: 700px) {
  .atl-porte-tranche { display: none; }
  .atl-porte { padding: .55em 1.2em; }
  /* Deuxième essai après refus des pastilles pleine largeur empilées
     (« je n'aime pas du tout ce format ») : les pastilles gardent leur
     taille naturelle de pilule et se CENTRENT, le libellé « Aller à »
     au-dessus, centré aussi. Si elles ne tiennent pas sur une ligne, le
     retour à la ligne reste centré : jamais d'étirement, jamais de bord à
     bord. */
  .atl-portes { justify-content: center; }
  .atl-portes-libelle { flex: 0 0 100%; text-align: center; margin: 0 0 .15rem; }
}

/* ---- Une partie par public ---- */
.atl-corps { background: var(--paper); color: var(--ink); padding: clamp(1.2rem, 4svh, 2.5rem) var(--pad); }
.atl-public {
  max-width: 72rem;
  margin: 0 auto;
  display: grid;
  gap: 1.4rem 4rem;
  padding: clamp(2.6rem, 8svh, 5rem) 0;
  scroll-margin-top: calc(var(--header-h) + .5rem);
}
/* min-width: 0 : sans lui, le bouton « S'inscrire · Enfants et adolescents »
   (ligne insécable) imposait 345 px de large minimum à toute la grille, et
   la page Stages débordait sur les écrans de 320 px (mesuré au banc).
   Quatrième fois que ce piège des grilles frappe le projet. */
.atl-public > * { min-width: 0; }
.atl-public + .atl-public { border-top: 1px solid rgb(28 18 6 / .14); }
/* Les trois marches du logo ouvrent chaque partie : le motif est défini une
   seule fois, avec celui des titres de pages intérieures. */
.atl-tranche {
  display: inline-block;
  margin: 0 0 .7rem;
  padding: .38rem .65rem;
  background: var(--orange);
  color: var(--ink);
  font: 600 .74rem/1 var(--font-body);
  letter-spacing: .16em;
  text-transform: uppercase;
}
.atl-nom {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 7.5vw, 5.4rem);
  line-height: .92;
  text-transform: uppercase;
  margin: 0 0 .5rem;
}
.atl-exergue {
  margin: 0;
  font-weight: 600;
  color: var(--orange-deep);
  font-size: clamp(1.02rem, 1.4vw, 1.25rem);
  line-height: 1.45;
}
/* Le bandeau « inscriptions ouvertes » : une bande orange pleine largeur
   juste sous le hero, texte et bouton sur une ligne, empilés sur téléphone. */
.atl-annonce {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .7rem 1.6rem;
  padding: .95rem var(--pad);
  background: var(--orange);
  color: var(--ink);
  text-align: center;
}
.atl-annonce p { margin: 0; font-weight: 700; font-size: 1.02rem; }
.atl-annonce .btn { flex: none; }

/* Bouton d'inscription d'un public. Le nom du public suit le verbe, séparé par
   un point médian comme les horaires, pour qu'on voie d'un coup d'œil que ce
   n'est pas le même appel que la bande orange du bas. */
.atl-public-action { margin-top: .2rem; }
/* La colonne descend à 16rem sur les écrans moyens : un nom de public un peu
   long (« Adolescents ») y débordait de 24 px. Le bouton se replie donc au lieu
   de sortir, ce qui vaut aussi pour un libellé plus long saisi dans l'admin. */
.atl-public-action .btn {
  max-width: 100%;
  white-space: normal;
  text-align: center;
  line-height: 1.25;
  /* Un cran sous le bouton de la bande orange, qui reste l'appel principal.
     C'est aussi ce qui fait tenir « S'inscrire · Adolescents » dans la colonne
     à 900 px de large, où le texte empiétait sinon sur les bords arrondis. */
  font-size: .84rem;
  padding-inline: 1.25rem;
}
.atl-action-sep { margin: 0 .1em 0 .25em; opacity: .55; }
.atl-action-public { font-weight: 600; white-space: nowrap; }
/* Sur les écrans étroits, le bouton se replie : « S'inscrire · » sur une
   ligne, le nom du public (insécable) sur la suivante. Sans repli, sa ligne
   unique fixait la largeur minimale de toute la page. Inoffensif ailleurs :
   tant que la ligne tient, rien ne se replie. */
.atl-public-action .btn { flex-wrap: wrap; justify-content: center; }
.atl-texte p { margin: 0 0 1em; line-height: 1.7; }
.atl-texte p:last-child { margin-bottom: 0; }
.atl-programme { margin-top: 1.5rem; }
.atl-programme h3 {
  font: 600 .8rem/1 var(--font-body);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--orange-deep);
  margin: 0 0 .7rem;
}
.atl-programme ul { list-style: square; margin: 0; padding-left: 1.3rem; }
.atl-programme li { margin-bottom: .4rem; font-weight: 500; }
.atl-programme li::marker { color: var(--orange); }

/* Desktop : la tête (tranche, nom, accroche) d'un côté, le corps de l'autre,
   et l'alternance gauche/droite donne le rythme de lecture de la page. */
@media (min-width: 900px) {
  /* Placement explicite plutôt que « order » : le corps occupe les deux lignes
     de sa colonne, ce qui libère sous la tête la place où se loge le bouton
     d'inscription. Avec des positions explicites, « order » n'aurait plus
     aucun effet, d'où l'inversion écrite ici colonne par colonne. */
  .atl-public { grid-template-columns: minmax(16rem, .9fr) 1.6fr; }
  .atl-public-tete { grid-column: 1; grid-row: 1; }
  .atl-public-corps { grid-column: 2; grid-row: 1 / span 2; }
  /* Pas de « justify-self » ici : la case doit occuper toute la colonne pour
     que le bouton puisse s'y replier. Sinon elle se réduit à sa taille et le
     « max-width: 100% » du bouton n'a plus rien à quoi se limiter. */
  .atl-public-action { grid-column: 1; grid-row: 2; align-self: start; }

  .atl-public--droite { grid-template-columns: 1.6fr minmax(16rem, .9fr); }
  .atl-public--droite .atl-public-tete { grid-column: 2; grid-row: 1; text-align: right; }
  .atl-public--droite .atl-public-corps { grid-column: 1; grid-row: 1 / span 2; }
  .atl-public--droite .atl-public-action { grid-column: 2; text-align: right; }
  /* Escalier inversé quand la partie est alignée à droite : mêmes mesures,
     les marches s'appuient sur le bord droit. */
  .atl-public--droite .atl-public-tete::before {
    margin-left: auto;
    background:
      linear-gradient(var(--orange), var(--orange))
        100% 0
        / var(--marche-l1) var(--marche-ep) no-repeat,
      linear-gradient(var(--orange), var(--orange))
        100% calc(var(--marche-ep) + var(--marche-gap))
        / calc(var(--marche-l1) + var(--marche-pas)) var(--marche-ep) no-repeat,
      linear-gradient(var(--orange), var(--orange))
        100% calc((var(--marche-ep) + var(--marche-gap)) * 2)
        / calc(var(--marche-l1) + var(--marche-pas) * 2) var(--marche-ep) no-repeat;
  }
}

/* ---- Les horaires : un volet qui se déplie ----
   Même mécanique éprouvée que les détails des stages : une piste de grille
   qui passe de 0fr à 1fr, aucune hauteur mesurée. Ouvert dans le HTML (le
   contenu reste lisible sans JavaScript), replié par le script au chargement
   sauf pour la première partie ou celle visée par l'ancre. */
/* Le filet orange court sur TOUT le bloc, pas seulement sur l'en-tête : posé
   sur l'en-tête seul, il obligeait à décaler la liste pour l'aligner dessous,
   et le contenu se retrouvait à 45 px du bord gauche contre 39 à droite. Le
   décalage se voyait sur téléphone. Ici, les retraits intérieurs sont
   rigoureusement symétriques. */
.atl-horaires {
  margin-top: 1.8rem;
  background: var(--white);
  border-left: .35rem solid var(--orange);
  box-shadow: 0 10px 34px rgb(28 18 6 / .08);
}
.atl-horaires-tete {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /* Le retrait droit intègre la largeur du filet : sinon celui-ci pousse tout
     le contenu et le bloc paraît décentré (44 px à gauche contre 39 à droite,
     ce que Nicolas a repéré sur téléphone). */
  padding: 1rem calc(1.2rem + .35rem) 1rem 1.2rem;
  font: 600 .82rem/1 var(--font-body);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink);
  background: none;
  border: 0;
  cursor: pointer;
}
.atl-horaires-tete i {
  width: .55rem;
  height: .55rem;
  border-right: 2px solid var(--orange-deep);
  border-bottom: 2px solid var(--orange-deep);
  transform: rotate(45deg);
  transition: transform .3s var(--ease-out);
  flex: none;
}
.atl-horaires.ferme .atl-horaires-tete i { transform: rotate(-45deg); }
.atl-horaires-boite {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  transition: grid-template-rows .45s var(--ease-out);
}
.atl-horaires.ferme .atl-horaires-boite { grid-template-rows: minmax(0, 0fr); }
.atl-horaires-liste {
  overflow: hidden;
  min-height: 0;
  margin: 0;
  padding: 0 calc(1.2rem + .35rem) 0 1.2rem;
  list-style: none;
}
.atl-horaires-liste li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .2rem 1.2rem;
  padding: .8rem 0;
  border-top: 1px solid rgb(28 18 6 / .1);
}
.atl-horaires-liste li:last-child { padding-bottom: 1.1rem; }
.atl-horaires-liste strong { font-weight: 700; }
.atl-horaire-note { font-weight: 500; opacity: .85; }
/* Téléphone : la précision (niveau, représentation...) passe TOUJOURS sous
   l'horaire, alignée à gauche. Avec « space-between », une note courte
   (« Confirmé ») restait à droite sur la même ligne et une longue
   (« Débutant et intermédiaire ») tombait dessous : deux lignes voisines ne
   se ressemblaient pas (retour de Nicolas : symétrie). */
@media (max-width: 700px) {
  .atl-horaires-liste li { flex-direction: column; align-items: flex-start; gap: .15rem; }
}
/* Séparateur entre le jour et l'horaire, sans espace insécable dans le texte. */
.atl-sep { margin: 0 .45em; opacity: .45; }

.atl-libre { max-width: 72rem; margin: 0 auto; padding: 1rem 0 2rem; }

/* ---- L'inscription : bande orange pleine largeur ---- */
.atl-inscription { background: var(--orange); color: var(--ink); padding: clamp(3rem, 10svh, 5.5rem) var(--pad); }
.atl-inscription-inner { max-width: 72rem; margin: 0 auto; }
.atl-inscription h2 { font-size: clamp(2.6rem, 6vw, 4.4rem); margin: 0 0 .6rem; }
.atl-inscription p { max-width: 38rem; margin: 0 0 .5rem; font-weight: 500; }
.atl-inscription .atl-lieu { font-weight: 700; }
.atl-inscription-btns { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.6rem; }

@media (prefers-reduced-motion: reduce) {
  .atl-horaires-boite, .atl-horaires-tete i, .atl-porte-nom { transition: none; }
}

/* Fiche atelier */
.atelier-grid { display: grid; gap: 3rem; }
@media (min-width: 900px) { .atelier-grid { grid-template-columns: 1.6fr 1fr; } }
.info-card {
  background: var(--white);
  border-radius: 1.2rem;
  padding: 1.8rem;
  box-shadow: 0 10px 40px rgb(28 18 6 / .08);
  align-self: start;
  position: sticky;
  top: calc(var(--header-h) + 1.5rem);
}
.info-card dl { margin: 0; }
.info-card dt {
  font: 600 .75rem/1 var(--font-body);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--orange-deep);
  margin-top: 1.1rem;
}
.info-card dt:first-child { margin-top: 0; }
.info-card dd { margin: .35rem 0 0; font-weight: 500; }
.info-card .btn { margin-top: 1.6rem; width: 100%; justify-content: center; }
/* Sous le bouton Réserver : la porte discrète vers le formulaire pré-rempli */
.event-question {
  display: block;
  margin-top: .9rem;
  text-align: center;
  font: 600 .88rem/1.4 var(--font-body);
  color: var(--orange-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.event-question:hover { color: var(--ink); }

/* Cartes listing (ateliers parent) : mêmes capsules que la home */
.cards-list { display: flex; flex-direction: column; gap: 1rem; padding: 0; list-style: none; margin: 0 0 2rem; }

/* Programmation : trois réglages, chacun sous son intitulé et séparé du
   suivant par un filet, pour qu'on voie du premier coup d'œil qu'il y en a
   bien trois (dont la bascule Affiches / Calendrier). */
/* Les trois groupes se suivent simplement, alignés sur la même ligne de base.
   Pas de « margin-left: auto » pour pousser le dernier à droite : dès que la
   place manquait, il partait seul à la ligne suivante et l'intitulé se
   retrouvait décalé sous les autres. */
/* Deux menus déroulants et la bascule d'affichage : compact, et les trois
   réglages restent visiblement distincts. En rangées de pastilles, ils ne
   tenaient pas sur la largeur et se lisaient comme un seul bloc. */
.prog-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .8rem; margin: 0 0 2.2rem; }

/* Un champ de filtre : l'intitulé et la valeur dans la même pilule d'encre,
   le menu natif posé dessus en transparence pour garder son comportement. */
.prog-champ {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: .6rem;
  padding: .75rem 2.6rem .75rem 1.3rem;
  background: var(--white);
  border: 2px solid rgb(28 18 6 / .14);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color .2s, box-shadow .25s, transform .25s var(--ease-out);
}
.prog-champ:hover { border-color: var(--ink); transform: translateY(-1px); box-shadow: 0 8px 20px rgb(28 18 6 / .1); }
.prog-champ:focus-within { border-color: var(--orange); box-shadow: 0 0 0 3px rgb(240 140 42 / .25); }
.prog-champ-tag {
  font: 700 .68rem/1 var(--font-body);
  letter-spacing: .16em;
  text-transform: uppercase;
  opacity: .5;
}
/* La valeur reste dans la police courante : la Humane condensée détonnait
   dans une pilule de cette taille. */
.prog-champ-val {
  font: 700 .92rem/1.1 var(--font-body);
  text-transform: uppercase;
  letter-spacing: .05em;
  white-space: nowrap;
}
.prog-champ-fleche {
  position: absolute;
  right: 1.2rem;
  top: 50%;
  width: .5rem;
  height: .5rem;
  margin-top: -.35rem;
  border-right: 2.5px solid var(--orange);
  border-bottom: 2.5px solid var(--orange);
  transform: rotate(45deg);
  transition: transform .2s var(--ease-out);
}
.prog-champ:hover .prog-champ-fleche { transform: rotate(45deg) translate(1px, 1px); }
/* Le vrai menu, invisible mais bien là : c'est lui qui reçoit le clic, le
   focus et le clavier. */
.prog-champ select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
  font-size: 1rem; /* sous 16px, les navigateurs mobiles zooment à l'ouverture */
}

/* La bascule d'affichage : un seul bloc, avec une pastille orange qui glisse
   d'un côté à l'autre. */
.prog-vue {
  position: relative;
  display: flex;
  /* Pas d'espace entre les deux moitiés : la pastille se cale sur une demie
     exacte, sinon elle rate le bouton d'un cheveu en glissant. */
  gap: 0;
  margin-left: auto;
  padding: .3rem;
  background: var(--white);
  border: 2px solid rgb(28 18 6 / .14);
  border-radius: 999px;
}
.prog-vue-curseur {
  position: absolute;
  top: .3rem;
  bottom: .3rem;
  left: .3rem;
  width: calc(50% - .3rem);
  background: var(--orange);
  border-radius: 999px;
  transition: transform .32s var(--ease-out);
}
.prog-vue.sur-calendrier .prog-vue-curseur { transform: translateX(100%); }
.prog-vue-btn {
  position: relative;
  z-index: 1;
  /* base 0 ET min-width 0 : sans ce dernier, un élément flex refuse de
     descendre sous la largeur de son contenu et les deux moitiés restent
     inégales (117 contre 137 px), la pastille rate alors sa cible. */
  flex: 1 1 0;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .55em 1.1em;
  background: transparent;
  border: 0;
  border-radius: 999px;
  color: var(--ink);
  font: 700 .76rem/1 var(--font-body);
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .25s;
}
.prog-vue-btn.active { color: var(--white); }
.prog-vue-btn svg { flex: none; }
.prog-vue-btn:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

@media (max-width: 780px) {
  /* Les deux filtres se partagent la ligne, la bascule prend celle du dessous */
  .prog-champ { flex: 1 1 12rem; }
  .prog-vue { margin-left: 0; flex: 1 1 100%; }
}
@media (max-width: 420px) {
  .prog-champ { flex-direction: column; align-items: flex-start; gap: .25rem; padding-block: .6rem; }
}
.prog-vue .chip.active { background: var(--orange); border-color: var(--orange); color: var(--white); }

/* Vue calendrier : le fil des dates. Chaque date de représentation est un
   bloc typographique fort, les spectacles s'y accrochent en mini-cartes ;
   plusieurs le même soir se rangent côte à côte sous la même date.
   Le « display » explicite écraserait le masquage navigateur de l'attribut
   hidden : la règle [hidden] doit donc être redite. */
.prog-calendrier { display: block; max-width: 64rem; }
.prog-calendrier[hidden] { display: none; }
.agdx-mois { margin: 0 0 3rem; }
.agdx-mois-titre {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(2.4rem, 4.6vw, 3.4rem);
  line-height: 1;
  margin: 0 0 1.2rem;
  color: var(--orange-deep);
}
.agdx-jour {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 1.6rem;
  align-items: start;
  padding: 1.3rem 0;
  border-top: 1px solid rgb(28 18 6 / .14);
}
.agdx-jour:last-child { border-bottom: 1px solid rgb(28 18 6 / .14); }
.agdx-date { display: flex; flex-direction: column; align-items: center; gap: .15rem; padding-top: .1rem; }
.agdx-num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 3.8rem;
  line-height: .9;
}
.agdx-sem {
  font: 700 .78rem/1 var(--font-body);
  letter-spacing: .14em;
  text-transform: uppercase;
  opacity: .6;
}
.agdx-evts { display: flex; flex-wrap: wrap; gap: .9rem; }
.agdx-evt {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  min-width: min(100%, 21rem);
  flex: 1 1 21rem;
  max-width: 29rem;
  padding: .8rem 1.3rem .8rem .8rem;
  background: var(--white);
  border-radius: 1rem;
  box-shadow: 0 8px 24px rgb(28 18 6 / .09);
  text-decoration: none;
  transition: transform .25s var(--ease-out), box-shadow .25s;
}
.agdx-evt:hover { transform: translateY(-3px); box-shadow: 0 14px 32px rgb(28 18 6 / .18); }
.agdx-evt img {
  flex: none;
  width: 4.2rem;
  aspect-ratio: 160 / 214;
  object-fit: cover;
  border-radius: .6rem;
}
.agdx-evt-corps { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.agdx-evt-titre {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  /* Un cran au-dessus (1.7 -> 2.1rem, mobile 1.4 -> 1.85rem) : « pas assez
     lisible », retour de Nicolas. La Humane est étroite, elle supporte. */
  font-size: 2.1rem;
  line-height: .95;
}
.agdx-evt-meta { font-size: .92rem; font-weight: 500; opacity: .7; }
@media (max-width: 480px) {
  .agdx-jour { grid-template-columns: 4.2rem 1fr; gap: 1rem; }
  .agdx-num { font-size: 2.7rem; }
  .agdx-evt-titre { font-size: 1.85rem; }
}

.prog-filters { display: flex; flex-wrap: wrap; gap: .6rem; margin: 0 0 2rem; }
.chip {
  border: 2px solid var(--ink);
  background: transparent;
  color: var(--ink);
  font: 600 .82rem/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: .6em 1.2em;
  border-radius: 999px;
  cursor: pointer;
  transition: background .2s, color .2s, border-color .2s;
}
.chip.active, .chip:hover { background: var(--ink); color: var(--paper); }
/* Les affiches à venir : les mêmes cartes que l'accueil, en grille.
   Sur un écran étroit, une seule colonne : l'affiche se lit en grand. */
.prog-grid {
  display: grid;
  gap: 1.4rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
}
.prog-grid .event-card { max-height: none; }
.prog-grid .event-card h3 { font-size: clamp(1.9rem, 2.6vw, 2.4rem); }
.prog-vide { font-size: 1.05rem; opacity: .8; max-width: 42rem; }

/* Déjà joué cette saison : des lignes discrètes, la saison reste vivante
   sans voler la vedette aux dates à venir. */
.prog-passes { margin-top: clamp(2.5rem, 7svh, 4.5rem); }
.prog-passes h2 { font-size: clamp(2.2rem, 4.5vw, 3.2rem); margin: 0 0 1rem; }
.prog-passes-liste { list-style: none; margin: 0; padding: 0; }
.prog-passes-liste li { border-top: 1px solid rgb(28 18 6 / .14); }
.prog-passes-liste li:last-child { border-bottom: 1px solid rgb(28 18 6 / .14); }
.prog-passes-liste a {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: .1rem 1.2rem;
  align-items: baseline;
  padding: .9rem 0;
  text-decoration: none;
  transition: padding-left .3s var(--ease-out);
}
.prog-passes-liste a:hover { padding-left: .8rem; }
.pp-date { font: 700 .82rem/1.3 var(--font-body); letter-spacing: .06em; text-transform: uppercase; color: var(--orange-deep); }
.pp-titre { font-family: var(--font-display); font-weight: 700; text-transform: uppercase; font-size: 1.5rem; line-height: 1; }
.pp-meta { grid-column: 2; font-size: .85rem; font-weight: 500; opacity: .65; }
@media (max-width: 640px) {
  .prog-passes-liste a { grid-template-columns: 1fr; }
  .pp-meta { grid-column: 1; }
}

/* Les saisons récentes en affiches */
.prog-retro { margin-top: clamp(2.5rem, 7svh, 4.5rem); }
.prog-retro h2 { font-size: clamp(2.2rem, 4.5vw, 3.2rem); margin: 0 0 .4rem; }
/* Le défilé d'affiches : bandeau d'encre pleine largeur, nettement séparé de
   la saison en cours. Deux rangées d'affiches de même hauteur, donc
   parfaitement alignées, glissent en continu, chacune dans son sens ; le
   survol met en pause. Chaque rangée contient sa série deux fois : glisser
   d'une série exacte (-50 %) puis reboucler ne laisse aucune couture. */
.prog-retro {
  background: var(--ink);
  color: var(--paper);
  padding: clamp(2.8rem, 8svh, 4.5rem) 0 clamp(2.4rem, 7svh, 4rem);
  overflow: hidden;
}
.prog-retro-tete {
  width: min(100% - 2 * var(--pad, 1.5rem), 72rem);
  margin: 0 auto clamp(1.6rem, 4svh, 2.6rem);
}
.prog-retro-tete .kicker { color: var(--orange); }
.prog-retro-tete h2 { font-size: clamp(2.4rem, 5vw, 3.6rem); margin: 0 0 .35rem; color: var(--paper); }
.prog-retro-intro { margin: 0; opacity: .75; max-width: 42rem; }

.retro-defileur {
  /* Défilement par scrollLeft (script) et non par translation CSS : la bande
     entière (une cinquantaine d'affiches en double, ~8000 px) animée en
     transform devenait UNE seule couche composée, au-delà des limites de
     texture des iPhone : Safari finissait par l'abandonner, le carrousel
     « cassait et disparaissait » (retour de Nicolas). Une zone de défilement
     native est tuilée par le navigateur, sans limite de largeur ; bonus : la
     bande se fait aussi glisser au doigt. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  /* Les affiches naissent et meurent en fondu sur les bords, au lieu d'être
     tranchées net par le cadre de l'écran */
  mask-image: linear-gradient(90deg, transparent, #000 3.5rem, #000 calc(100% - 3.5rem), transparent);
}
.retro-defileur::-webkit-scrollbar { display: none; }
.retro-defileur + .retro-defileur { margin-top: 1rem; }
.retro-bande {
  display: flex;
  width: max-content;
}
.retro-serie {
  display: flex;
  gap: .9rem;
  padding: 0 .45rem;
  margin: 0;
  list-style: none;
}
.retro-voir {
  position: relative;
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: .6rem;
  overflow: hidden;
  background: var(--ink-soft);
  box-shadow: 0 8px 22px rgb(0 0 0 / .4);
  cursor: zoom-in;
  transition: transform .3s var(--ease-out), box-shadow .3s;
}
.retro-voir:hover { transform: translateY(-4px); box-shadow: 0 16px 36px rgb(0 0 0 / .55); }
.retro-voir:focus-visible { outline: 3px solid var(--orange); outline-offset: 3px; }
/* Tactile : à la fermeture de la visionneuse, le focus revient sur l'affiche
   et iOS le traite comme un focus clavier, d'où « ces parenthèses oranges
   horribles » (retour de Nicolas). Sans clavier, le contour n'a pas de sens. */
@media (hover: none) {
  .retro-voir:focus-visible, .retro-voir:focus { outline: none; }
}
.retro-voir img {
  display: block;
  height: clamp(10rem, 22svh, 14rem);
  width: auto;
}
/* La légende n'existe qu'au survol : un voile monte du bas de l'affiche avec
   la date et le titre. Le reste du temps, l'affiche parle seule. */
.retro-legende {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: .1rem;
  padding: .7rem .75rem;
  background: linear-gradient(to top, rgb(8 9 12 / .92) 0%, rgb(8 9 12 / .55) 45%, rgb(8 9 12 / 0) 75%);
  color: var(--paper);
  text-align: left;
  opacity: 0;
  transition: opacity .25s;
}
.retro-voir:hover .retro-legende,
.retro-voir:focus-visible .retro-legende { opacity: 1; }
.retro-legende-date {
  font: 700 .62rem/1.2 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--orange);
}
.retro-legende-titre {
  font: 700 .8rem/1.25 var(--font-body);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Mouvement réduit demandé : le script n'anime pas, les rangées se font
   défiler à la main (la zone de défilement est déjà native). */

.prog-avenir-titre { font-size: clamp(2.4rem, 5vw, 3.6rem); margin: 0 0 1rem; }

/* ---------- Les partenaires : silhouettes en défilé sous le bouton ----------
   Les logos passent tous en encre par filtre (ils sont sur fond transparent),
   discrets au repos, pleins au survol. Même mécanique de boucle que le mur
   d'affiches : deux séries identiques, translation d'une série exacte. */
.partn { margin-top: clamp(1.4rem, 4svh, 2.2rem); max-width: 34rem; }
.partn-titre {
  margin: 0 0 .7rem;
  font: 700 .68rem/1 var(--font-body);
  letter-spacing: .18em;
  text-transform: uppercase;
  opacity: .5;
}
.partn-defileur {
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 2rem, #000 calc(100% - 2rem), transparent);
}
/* Boucle par translation d'une série exacte (les images-clés vivaient avec
   l'ancien défilé d'affiches : supprimées avec lui, les partenaires
   s'étaient figés). */
@keyframes retro-defile {
  to { transform: translateX(-50%); }
}
.partn-bande {
  display: flex;
  width: max-content;
  animation: retro-defile var(--duree, 30s) linear infinite;
  /* Le glissement se joue sur le compositeur : sans cette annonce, les
     iPhone rendaient le défilé saccadé (filtres sur chaque logo). */
  will-change: transform;
}
/* Sur téléphone : le défilé était trop lent (la durée est calibrée pour un
   grand écran) et flottait dans la colonne. Il prend toute la largeur de
   l'écran, bien calé au centre, avec un titre centré et un rythme plus vif.
   La durée directe l'emporte sur le var(--duree) posé dans le gabarit. */
@media (max-width: 899px) {
  /* La marge basse éloigne le défilé de la barre de Safari ; la hauteur
     qu'elle coûte est reprise sur la photo (28 -> 24svh) et sur la marge
     haute, sinon la section dépassait l'écran de 5 px et se faisait rogner
     (mesuré au banc). */
  .partn { max-width: none; margin-top: .9rem; margin-bottom: 1.3rem; }
  .partn-titre { text-align: center; }
  .partn-defileur { margin-inline: -1.25rem; }
  .partn-bande { animation-duration: 16s; }
  .split .split-media img { max-height: 24svh; }
}

/* Depuis le verrou de page, la barre de Safari ne recouvre plus jamais le
   bas des sections : les sections font exactement la hauteur visible. La
   petite marge du bouton des ateliers reste, elle aère la fin de section. */
@media (max-width: 899px) {
  .tiles-more { margin-bottom: 1.6rem; }
}
.partn-bande:hover { animation-play-state: paused; }
.partn-serie {
  display: flex;
  align-items: center;
  gap: 2.2rem;
  padding: 0 1.1rem;
  margin: 0;
  list-style: none;
}
/* Chaque logo vit dans une BOÎTE DE TAILLE IDENTIQUE (7 × 2.2rem) et s'y
   inscrit en entier : les proportions vont de 2:1 (ABE) à 5:1 (Abelio), à
   hauteur commune l'un paraissait énorme et l'autre minuscule (retour de
   Nicolas : « tous les logos à la même taille »). Boîtes fixes = les deux
   séries de la boucle font exactement la même largeur, donc la glissade de
   50 % retombe au pixel près : plus de saut visible à la couture sur mobile. */
.partn-serie li { flex: 0 0 auto; }
.partn-serie img {
  display: block;
  width: 7rem;
  height: 2.2rem;
  object-fit: contain;
  object-position: center;
  filter: brightness(0);
  opacity: .55;
  transition: opacity .25s;
}
.partn-serie a { display: block; }
.partn-serie a:hover img, .partn-serie a:focus-visible img { opacity: 1; }
/* Le fichier du logo Idoane embarque du vide autour du dessin : à boîte
   égale, il paraissait bien plus petit que les autres (retour de Nicolas).
   L'agrandissement par transform ne change PAS la mise en page : les deux
   séries de la boucle gardent des largeurs identiques au pixel. */
.partn-serie img[src*="idoane"] { transform: scale(1.45); }
@media (prefers-reduced-motion: reduce) {
  .partn-bande { animation: none; }
  .partn-defileur { overflow-x: auto; }
}

/* La visionneuse d'affiches (dialog natif) */
.affiche-vue {
  width: min(92vw, 60rem);
  max-width: none;
  max-height: 92svh;
  padding: 0;
  border: 0;
  border-radius: 1rem;
  background: transparent;
  overflow: visible;
}
.affiche-vue::backdrop { background: rgb(8 9 12 / .88); backdrop-filter: blur(4px); }
.affiche-vue figure { margin: 0; display: flex; flex-direction: column; align-items: center; gap: .9rem; }
.affiche-vue img {
  display: block;
  max-width: 100%;
  max-height: 78svh;
  width: auto;
  border-radius: .6rem;
  box-shadow: 0 30px 70px rgb(0 0 0 / .6);
}
.affiche-vue figcaption { text-align: center; color: var(--paper); }
.affiche-vue-date {
  display: block;
  font: 700 .78rem/1.3 var(--font-body);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--orange);
}
.affiche-vue-titre { display: block; margin-top: .2rem; font-weight: 600; font-size: 1.05rem; }
.affiche-vue-fermer,
.affiche-vue-nav {
  position: fixed;
  display: grid;
  place-items: center;
  width: 2.9rem;
  height: 2.9rem;
  border: 0;
  border-radius: 50%;
  background: rgb(245 240 232 / .14);
  color: var(--paper);
  cursor: pointer;
  transition: background .2s, transform .2s var(--ease-out);
}
.affiche-vue-fermer:hover,
.affiche-vue-nav:hover { background: var(--orange); }
.affiche-vue-fermer { top: 1.1rem; right: 1.1rem; }
.affiche-vue-nav { top: 50%; transform: translateY(-50%); }
.affiche-vue-nav:hover { transform: translateY(-50%) scale(1.08); }
.affiche-vue-prec { left: 1.1rem; }
.affiche-vue-suiv { right: 1.1rem; }
@media (max-width: 700px) {
  /* Sur téléphone les flèches passent sous l'affiche : sur les côtés, elles
     mordraient dessus. */
  .affiche-vue-nav { top: auto; bottom: 1.1rem; transform: none; }
  .affiche-vue-nav:hover { transform: scale(1.08); }
  .affiche-vue-prec { left: 25%; }
  .affiche-vue-suiv { right: 25%; }
  .affiche-vue img { max-height: 64svh; }
}

/* L'intro de la rétrospective (l'ancienne section archives chiffrées a été
   retirée : ses données attendent dans RESSOURCES/archives_saisons_2006-2026.yaml) */
.prog-archives-intro { margin: 0 0 1.6rem; opacity: .8; max-width: 42rem; }

/* ---------- Portail d'inscription en ligne (HelloAsso) ---------- */
.pay-body { max-width: 56rem; }
.pay-etape { padding: clamp(1.6rem, 5svh, 3rem) 0; outline: none; }
.pay-etape + .pay-etape { border-top: 2px solid rgb(28 18 6 / .12); }
.pay-num {
  margin: 0 0 .5rem;
  font: 700 .78rem/1 var(--font-body);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--orange-deep);
}
.pay-etape h2 { font-size: clamp(2.1rem, 4.5vw, 3rem); margin: 0 0 .5rem; }
.pay-texte { max-width: 40rem; line-height: 1.65; margin: 0 0 1.4rem; }
.pay-choix { display: flex; flex-wrap: wrap; gap: .8rem; }
.pay-choix .btn.active { outline: 3px solid var(--ink); outline-offset: 2px; }

/* Le panneau « pas encore » : sombre, pour marquer l'arrêt sans gronder */
.pay-alerte {
  margin-top: 1.4rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: 1.2rem;
  padding: 1.6rem;
}
.pay-alerte h3 { font-family: var(--font-display); text-transform: uppercase; font-size: 2.4rem; line-height: .95; margin: 0 0 .6rem; }
.pay-alerte p { margin: 0 0 1.2rem; line-height: 1.6; opacity: .92; }
.pay-alerte-btns { display: flex; flex-wrap: wrap; gap: .8rem; }

/* Les cartes d'ateliers : une par discipline, l'orange marque le choix */
.pay-ateliers { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }
.pay-atelier {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .3rem;
  padding: 1.2rem 3rem 1.2rem 1.2rem;
  background: var(--white);
  border: 2px solid rgb(28 18 6 / .16);
  border-radius: 1rem;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--ink);
  transition: border-color .2s, transform .25s var(--ease-out), box-shadow .25s;
}
.pay-atelier:hover { border-color: var(--orange); transform: translateY(-3px); box-shadow: 0 12px 30px rgb(28 18 6 / .12); }
.pay-atelier.active { border-color: var(--orange); background: var(--orange); color: var(--white); }
.pay-atelier-nom { font-family: var(--font-display); font-weight: 700; text-transform: uppercase; font-size: 2.5rem; line-height: .95; }
.pay-atelier-note { font-size: .85rem; font-weight: 500; opacity: .72; }
.pay-atelier.active .pay-atelier-note { opacity: .95; }
.pay-atelier-fleche {
  position: absolute;
  right: 1rem;
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--orange);
  color: var(--white);
  transition: transform .25s var(--ease-out);
}
.pay-atelier.active .pay-atelier-fleche { background: var(--white); color: var(--orange-deep); }
.pay-atelier:hover .pay-atelier-fleche { transform: translateY(-50%) scale(1.12); }

/* Le widget : hauteur réservée à l'avance (une iframe ne s'adapte pas à son
   contenu), réglable dans l'admin si HelloAsso change ses formulaires */
/* Une seule ligne de texte : pas de flex ici, le point doit rester collé
   au nom de l'atelier. */
.pay-recap { display: block; }
.pay-changer {
  border: 0;
  background: none;
  padding: 0;
  margin-left: .45rem;
  font: 600 .88rem/1 var(--font-body);
  color: var(--orange-deep);
  text-decoration: underline;
  cursor: pointer;
}
.pay-widget {
  background: var(--white);
  border-radius: 1.2rem;
  box-shadow: 0 10px 40px rgb(28 18 6 / .08);
  overflow: hidden;
}
.pay-widget iframe { display: block; width: 100%; height: var(--pay-h, 1500px); border: 0; }
@media (max-width: 700px) {
  .pay-widget iframe { height: var(--pay-h-mobile, 2200px); }
}
.pay-securite { margin-top: 1.2rem; font-size: .92rem; opacity: .78; max-width: 40rem; line-height: 1.6; }
.pay-securite a { color: var(--orange-deep); text-decoration: underline; text-underline-offset: .15em; }
.pay-noscript ul { margin: .6rem 0 0; padding-left: 1.2rem; }

/* Embed (billetterie / don) */
.embed-wrap {
  background: var(--white);
  border-radius: 1.2rem;
  box-shadow: 0 10px 40px rgb(28 18 6 / .08);
  overflow: hidden;
}
.embed-wrap iframe { display: block; width: 100%; min-height: 78vh; border: 0; }
/* Version pleine largeur (billetterie) : l'intégration occupe toute la largeur
   sous le bandeau, sans carte ni arrondi, pour qu'on croie à notre page.
   ------------------------------------------------------------------
   HAUTEUR : surtout PAS « un écran », comme c'était le cas au départ. Une
   iframe ne grandit pas avec son contenu : dès qu'elle est plus courte que
   lui, Billetweb ouvre SA PROPRE barre de défilement, et la molette ne fait
   plus bouger la page quand le curseur est au-dessus. C'est le double
   défilement signalé par Nicolas.
   Le script officiel de redimensionnement de Billetweb (export.js) a été
   essayé : sur cette page multi-événements, l'iframe n'émet aucun message de
   hauteur, il ne sert donc à rien ici.
   La hauteur est donc réservée à l'avance, à partir du contenu réellement
   mesuré : 874 px de haut à 1200 px de large et au-delà, 914 px à 768,
   1316 px à 375. On ajoute de quoi absorber un ou deux spectacles de plus
   (environ 175 px pièce), et la valeur reste réglable dans l'admin. */
.embed-plein { background: var(--white); }
.embed-plein iframe {
  display: block;
  width: 100%;
  height: var(--embed-h, 1080px);
  border: 0;
}
@media (max-width: 699px) {
  .embed-plein iframe { height: var(--embed-h-mobile, 1560px); }
}
/* Intégrations : aucun défilement INTERNE, jamais. Le script cale chaque
   iframe sur la hauteur annoncée par son contenu ; si un contenu dépassait
   malgré tout, on préfère qu'il soit rogné plutôt que de rouvrir le piège du
   double défilement sur mobile. La fenêtre de paiement plein écran de
   Billetweb (« fullscreen_on ») recouvre la page, comme sur leur propre
   script. */
.embed-plein iframe, .embed-wrap iframe, .pay-widget iframe { overflow: hidden; }
/* Page Don : le module HelloAsso, calé sur sa hauteur annoncée, sous le bandeau ;
   un fond blanc jusqu'au pied de page. */
.embed-don { padding-bottom: 2rem; }
.iframe-plein-ecran {
  position: fixed !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  z-index: 1000 !important;
}
body.integration-plein-ecran { overflow: hidden; }
.page-body--avant-embed { padding-bottom: 2rem; }

/* Formulaires (plugin Forms) */
form .form-group, form .form-field { margin-bottom: 1.2rem; }
form label { display: block; font-weight: 600; margin-bottom: .4rem; }
form .checkboxes label { display: flex; align-items: center; gap: .5em; font-weight: 500; margin-bottom: .35rem; }
form input[type='text'], form input[type='email'], form input[type='tel'],
form select, form textarea {
  width: 100%;
  padding: .9em 1.1em;
  font: 500 1rem var(--font-body);
  color: var(--ink);
  background: var(--white);
  border: 2px solid rgb(28 18 6 / .15);
  border-radius: .8rem;
  transition: border-color .2s;
}
form input:focus, form select:focus, form textarea:focus { border-color: var(--orange); outline: none; }
form textarea { min-height: 9rem; resize: vertical; }
.form-honeypot { position: absolute; left: -9999px; }

/* ---------- Formulaire de contact : parcours progressif ----------
   Sans JavaScript, tout est visible d'un bloc : les règles de masquage sont
   suspendues à html.js, le formulaire reste donc utilisable partout. */
html.js form[name='contact'] .cond:not(.montre),
html.js form[name='contact'] .suite:not(.montre),
html.js form[name='contact']:not(.ouvert) .buttons { display: none; }
form[name='contact'] .cond.montre,
form[name='contact'] .suite.montre { animation: champ-entre .45s var(--ease-out) backwards; }
form[name='contact'].sans-anim .cond.montre,
form[name='contact'].sans-anim .suite.montre { animation: none; }
@keyframes champ-entre {
  from { opacity: 0; transform: translateY(10px); }
}
@media (prefers-reduced-motion: reduce) {
  form[name='contact'] .cond.montre,
  form[name='contact'] .suite.montre { animation: none; }
}

/* Les menus déroulants du formulaire en pilule, comme tout le reste du site :
   fermés en rectangle, ils juraient à côté des pastilles rondes. La liste
   ouverte est arrondie plus bas, quand le navigateur sait la styler. */
form[name='contact'] select {
  appearance: none;
  -webkit-appearance: none;
  border-radius: 999px;
  padding: .8em 2.8em .8em 1.25em;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23f08c2a' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 1.2em center;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
/* La première question, celle qui commande tout le reste : un cran plus
   présente que les autres champs. */
form[name='contact'] select[name='data[sujet]'] {
  font-size: 1.05rem;
  font-weight: 600;
  border-color: rgb(28 18 6 / .3);
}
form[name='contact'] select[name='data[sujet]']:focus { border-color: var(--orange); }

/* La liste OUVERTE des menus déroulants, arrondie et aux couleurs du site
   (« customizable select »). Amélioration progressive : les navigateurs qui
   ne connaissent pas ::picker gardent la liste système d'aujourd'hui, et le
   clavier comme le tactile restent ceux du menu natif. Vaut pour le
   formulaire ET pour les deux menus de la barre de la programmation. */
@supports selector(::picker(select)) {
  form[name='contact'] select,
  .prog-champ select {
    appearance: base-select;
    -webkit-appearance: base-select;
  }
  form[name='contact'] select::picker(select),
  .prog-champ select::picker(select) {
    appearance: base-select;
    /* Blanc franc, PAS le crème du fond de page : ouvert par-dessus la page
       crème, le panneau se confondait avec elle (retour de Nicolas). */
    background: var(--white);
    color: var(--ink);
    border: 2px solid rgb(28 18 6 / .3);
    border-radius: 1.1rem;
    padding: .4rem;
    margin-top: .4rem;
    box-shadow: 0 16px 44px rgb(0 0 0 / .2);
  }
  /* base-select ajoute sa propre flèche au bouton fermé : la nôtre est déjà
     dessinée en fond, on masque la sienne pour ne pas en avoir deux. */
  form[name='contact'] select::picker-icon,
  .prog-champ select::picker-icon { display: none; }
  form[name='contact'] option,
  .prog-champ option {
    font: 500 1rem var(--font-body);
    padding: .55em .9em;
    border-radius: .75rem;
    cursor: pointer;
  }
  form[name='contact'] option:hover,
  form[name='contact'] option:focus-visible,
  .prog-champ option:hover,
  .prog-champ option:focus-visible { background: rgb(240 140 42 / .18); }
  form[name='contact'] option:checked,
  .prog-champ option:checked { font-weight: 700; }
  form[name='contact'] option::checkmark,
  .prog-champ option::checkmark { color: var(--orange); }
}

/* Les activités en pastilles, mêmes réflexes que les filtres du site */
.pastilles .checkboxes { display: flex; flex-wrap: wrap; gap: .6rem; }
/* Le plugin Form dessine sa propre case en ::before du label, avec un « ✓ »
   à l'état coché : dans une pastille, ce glyphe parasite n'a rien à faire. */
.pastilles .checkboxes label::before,
.pastilles .checkboxes input[type='checkbox']:checked + label::before { content: none; }
.pastilles .checkboxes input[type='checkbox'] {
  /* display rétabli : le plugin les met en display:none, ce qui les sortait
     du clavier. Invisibles mais focalisables. */
  display: inline-block;
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.pastilles .checkboxes input[type='checkbox'] + label {
  display: inline-flex !important;
  align-items: center;
  margin: 0;
  padding: .6em 1.1em;
  background: transparent;
  border: 2px solid rgb(28 18 6 / .35);
  border-radius: 999px;
  cursor: pointer;
  font: 600 .85rem/1.2 var(--font-body);
  letter-spacing: .04em;
  transition: border-color .2s, background .2s, color .2s;
  /* Cliquer vite sélectionnait le texte de la pastille : rien à sélectionner
     dans un bouton. */
  -webkit-user-select: none;
  user-select: none;
}
.pastilles .checkboxes input[type='checkbox'] + label:hover { border-color: var(--ink); }
.pastilles .checkboxes input[type='checkbox']:checked + label {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}
.pastilles .checkboxes input[type='checkbox']:focus-visible + label {
  outline: 3px solid var(--orange);
  outline-offset: 2px;
}

/* Les intertitres du formulaire (« Vos coordonnées », « Votre message ») */
.form-entete { margin: 2.2rem 0 1rem; }
.form-entete h4 {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  /* 1.65 -> 2.3rem : « plus lisible », retour de Nicolas. */
  font-size: 2.3rem;
  line-height: .95;
  letter-spacing: .01em;
  margin: 0;
  padding-top: 1.4rem;
  border-top: 2px solid rgb(28 18 6 / .12);
}

/* Le bouton d'envoi, au niveau du reste du site */
form[name='contact'] .buttons { justify-content: flex-start; margin-top: 1.6rem; }
form[name='contact'] .buttons button,
form[name='contact'] .buttons input[type='submit'] {
  display: inline-block;
  background: var(--orange);
  color: var(--white);
  border: 0;
  border-radius: 999px;
  padding: .95em 2.2em;
  font: 700 .95rem/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .2s, transform .25s var(--ease-out), box-shadow .25s;
}
form[name='contact'] .buttons button:hover,
form[name='contact'] .buttons input[type='submit']:hover {
  background: var(--orange-deep);
  transform: translateY(-2px);
  box-shadow: 0 12px 30px rgb(240 140 42 / .35);
}

/* .notices (pluriel) : la classe du plugin Form ; .notice et .alert restent
   pour les messages posés à la main dans les contenus. */
.notice, .notices, .alert { padding: 1em 1.3em; border-radius: .8rem; margin: 1rem 0; font-weight: 500; }
.notices p { margin: 0; }
.notice.success, .notices.success, .notices.green, .alert.success { background: #e6f4e6; color: #1d5c1d; }
.notice.error, .notices.error, .notices.red, .alert.error { background: #fdeaea; color: #8c1c1c; }
.notices.yellow { background: #fdf3e0; color: #7a4c10; }

/* Bloc newsletter de la page contact */
.contact-newsletter {
  margin-top: 3rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: 1.2rem;
  padding: 2.2rem;
  text-align: center;
}
.contact-newsletter h2 {
  text-transform: uppercase;
  color: var(--orange);
  font-size: clamp(2rem, 4vw, 2.8rem);
  margin: 0 0 .4rem;
}
.contact-newsletter p { margin: 0 auto 1.2rem; max-width: 34rem; }
.contact-newsletter form {
  display: flex;
  gap: .8rem;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  max-width: 34rem;
  margin: 0 auto;
}
.contact-newsletter form .form-field { margin: 0; flex: 1 1 14rem; }
.contact-newsletter input[type='email'] {
  width: 100%;
  padding: 1em 1.4em;
  font: 500 1rem var(--font-body);
  border: 2px solid rgb(245 240 232 / .25);
  border-radius: 999px;
  background: rgb(245 240 232 / .07);
  color: var(--paper);
}
.contact-newsletter input[type='email']::placeholder { color: rgb(245 240 232 / .5); }

/* ---------- Footer ---------- */
.site-footer {
  background: var(--ink);
  color: var(--paper);
  padding: 3.5rem var(--pad) 2rem;
}
/* Version compacte, intégrée au dernier écran de la home */
.newsletter .site-footer {
  padding: 1.8rem var(--pad) 1.1rem;
  border-top: 1px solid rgb(245 240 232 / .12);
  text-align: left;
  font-size: .92rem;
}
.newsletter .site-footer .footer-grid { gap: 1.2rem; }
.newsletter .site-footer .footer-legal { margin-top: 1.2rem; padding-top: .9rem; font-size: .78rem; }
.newsletter .site-footer li { margin-bottom: .3rem; }
/* Icônes du footer : toutes au même gabarit, blanches, sans décor.
   Le libellé vit dans l'aria-label du lien. */
.footer-icone {
  display: inline-flex;
  width: 1.6rem;
  height: 1.6rem;
  color: var(--paper);
  opacity: .85;
  transition: opacity .25s ease, transform .25s var(--ease-out);
}
.footer-icone svg { width: 100%; height: 100%; display: block; }
.footer-icone:hover, .footer-icone:focus-visible { opacity: 1; transform: translateY(-2px); }
.footer-reseaux { display: flex; gap: 1rem; align-items: center; }
.footer-reseaux li { margin-bottom: 0; }
.footer-icone-texte { font-size: .9rem; }
@media (max-width: 899px) {
  /* Dernière section : depuis le verrou de page, la barre de Safari ne
     recouvre plus le pied ; seule la barre de geste de l'iPhone (safe-area)
     reste à réserver. */
  .newsletter .site-footer {
    padding: 1.2rem 1.25rem calc(.9rem + env(safe-area-inset-bottom, 0px));
    font-size: .85rem;
  }
  /* Gouttière resserrée : à 2,5rem la colonne Contact tombait à 156px et
     l'adresse se coupait en plein milieu. */
  /* Les deux colonnes restent sur une ligne : les laisser se replier ajoutait
     98 px et faisait déborder la section en 320×568. Contact peut rétrécir,
     son texte se replie ; la colonne d'icônes garde sa largeur. */
  .newsletter .site-footer .footer-grid { gap: 1.1rem 1.5rem; flex-wrap: nowrap; }
  .newsletter .site-footer .footer-grid > div:first-child { display: none; }
  .newsletter .site-footer h4 { margin-bottom: .5rem; }
  .newsletter .site-footer .footer-legal { flex-direction: column; gap: .2rem; margin-top: .9rem; padding-top: .7rem; }
}
/* Chaque colonne est serrée sur son contenu et le groupe est centré. En pistes
   égales, « Nous suivre » n'avait que 112 px d'encre pour une piste de 571 :
   459 px de vide à sa droite, soit 28 % de la largeur du footer perdue. */
.footer-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 2rem clamp(2.5rem, 6vw, 6rem);
}
.footer-grid > div { flex: 0 1 auto; }
/* Sous 900px les colonnes finissent par se replier les unes sous les autres
   (mesuré : vers 348px de large). Alignées à gauche, elles donnaient alors une
   pile bancale : on centre leur contenu pour que le repli reste dans l'axe,
   qu'elles tiennent sur une ligne ou non. */
@media (max-width: 899px) {
  .site-footer .footer-grid { text-align: center; }
  .site-footer .footer-grid .brand { justify-content: center; }
  .site-footer .footer-reseaux { justify-content: center; }
  .site-footer .footer-legal { text-align: center; align-items: center; }
}
/* Seule la colonne de marque a besoin d'un plafond : sans lui, sa phrase
   s'étirerait sur une seule ligne et rouvrirait le déséquilibre. */
.footer-grid > div:first-child { max-width: 26rem; }
/* Le logo est dans un lien : sans cette règle il héritait de l'opacité .85
   des liens du pied de page, ce qui ternissait l'orange officiel et brouillait
   le tracé des lettres. Le logo se donne toujours à pleine intensité. */
.site-footer .brand { opacity: 1; }
.site-footer .brand .logo-stack {
  font-size: 1.3rem;
  margin-bottom: .8rem;
  color: var(--orange);
}
.site-footer .brand:hover .logo-stack { color: var(--orange); }
/* Orange officiel, comme partout ailleurs : ces titres étaient les seuls du
   site à utiliser une variante « gold » plus jaune (#ffb627), sans raison. */
.site-footer h4 { font: 600 .78rem/1 var(--font-body); letter-spacing: .24em; text-transform: uppercase; color: var(--orange); margin: 0 0 1rem; }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-bottom: .5rem; }
.site-footer a { text-decoration: none; opacity: .85; }
.site-footer a:hover { opacity: 1; color: var(--orange); }
.footer-legal {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgb(245 240 232 / .12);
  display: flex;
  /* Centré, comme le reste du footer. C'était « space-between », hérité de
     l'époque où cette ligne portait deux blocs à écarter aux deux bouts ;
     depuis le retrait des mentions légales elle n'en a plus qu'un, qui
     restait donc collé à gauche. */
  justify-content: center;
  text-align: center;
  flex-wrap: wrap;
  gap: 1rem;
  font-size: .82rem;
  opacity: .6;
}
/* Les pages légales : une ligne à part, plus petite encore, sous le
   copyright, un point médian entre les deux liens. */
.footer-legal-liens {
  flex-basis: 100%;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: .4rem .8rem;
  font-size: .74rem;
  letter-spacing: .02em;
}
.footer-legal-liens a + a::before { content: '·'; margin-right: .8rem; opacity: .7; }
.site-footer .footer-legal-liens a { opacity: .75; }
.site-footer .footer-legal-liens a:hover { opacity: 1; }

/* ---------- Divers ---------- */
.skip-link {
  position: absolute;
  left: -9999px;
  z-index: 300;
  background: var(--orange);
  color: var(--white);
  padding: .8em 1.4em;
  border-radius: 0 0 .8rem 0;
}
.skip-link:focus { left: 0; top: 0; }

/* Petits téléphones (écran bas) : sections Présentation et Newsletter resserrées.
   Ce bloc doit rester en FIN de feuille pour surcharger les règles mobiles de base. */
@media (max-width: 899px) and (max-height: 750px) {
  .split { gap: .8rem; }
  .split-media img { max-height: 20svh; }
  .split-text .lead { font-size: .92rem; }
  .newsletter-texte { margin-bottom: 1rem; font-size: .92rem; }
  .newsletter .site-footer { padding: .9rem 1.25rem .7rem; font-size: .8rem; }
  .newsletter .site-footer h4 { margin-bottom: .35rem; }
  .newsletter .site-footer li { margin-bottom: .2rem; }
  .newsletter .site-footer .footer-legal { margin-top: .6rem; padding-top: .5rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  .reveal { opacity: 1; transform: none; }
  #intro { display: none; }
}

/* =====================================================================
   TACTILE : aucun élément cliquable ne se DÉPLACE au toucher.
   Sur iPhone, le survol se déclenche au premier contact du doigt ; si
   l'élément glisse à cet instant (translateY du :hover), Safari considère
   que le doigt a bougé et ANNULE le clic. C'était la cause des boutons
   « cassés » sur mobile (capsules ateliers, « Découvrir les ateliers »,
   cartes de l'agenda, cartes du portail HelloAsso, bouton newsletter).
   Couleurs et ombres du survol sont conservées, seul le déplacement saute.
   Déclaré en fin de feuille pour l'emporter sur chaque règle de survol.
   ===================================================================== */
@media (hover: none) {
  .btn:hover,
  .nav-newsletter button:hover,
  .event-card:hover,
  .prog-champ:hover,
  .agdx-evt:hover,
  .retro-voir:hover,
  .pay-atelier:hover { transform: none; }
  .affiche-vue-nav:hover { transform: translateY(-50%); }
  .pay-atelier:hover .pay-atelier-fleche { transform: translateY(-50%); }
}

/* =====================================================================
   RELECTURE DU 27/08 (Nicolas) : lisibilité des titres Humane, page des
   stages en listes dépliantes, HelloAsso en pleine page.
   ===================================================================== */

/* ---- « Aérer la police » : la Humane est très condensée ; les lettres
   s'écartent, les titres sur photo gagnent un halo serré (lisible comme un
   contour, sans l'aspect grossier d'un vrai trait). ---- */
.event-card h3 {
  letter-spacing: .035em;
  font-size: 2.85rem;
  line-height: .98;
  text-shadow: 0 0 1px rgb(0 0 0 / .9), 0 1px 2px rgb(0 0 0 / .9), 0 3px 8px rgb(0 0 0 / .7), 0 10px 26px rgb(0 0 0 / .5);
}
.event-card .ec-meta { font-size: .92rem; letter-spacing: .01em; }
.site-nav a.nav-link { letter-spacing: .03em; }
.prog-avenir-titre { letter-spacing: .035em; }
.agdx-evt-titre { letter-spacing: .03em; }
.trav-t { letter-spacing: .03em; }
.trav-fondateur .trav-prose p,
.trav-fondateur-grid p {
  font-size: clamp(1.08rem, 1rem + .4vw, 1.25rem);
  line-height: 1.8;
  letter-spacing: .012em;
}

/* ---- La page des stages ---- */
.sta-corps { background: var(--paper); color: var(--ink); padding: clamp(2rem, 6svh, 4rem) var(--pad) clamp(3rem, 8svh, 5rem); }
.sta-inner { max-width: 60rem; margin: 0 auto; }
.sta-choix { margin-bottom: 2rem; }
.sta-question {
  font: 600 .8rem/1 var(--font-body);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--orange-deep);
  margin: 0 0 .9rem;
}
.sta-filtres { display: flex; flex-wrap: wrap; gap: .6rem; }
.sta-filtre {
  border: 2px solid var(--ink);
  background: transparent;
  color: var(--ink);
  font: 600 .86rem/1 var(--font-body);
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .75em 1.25em;
  border-radius: 999px;
  cursor: pointer;
  transition: background .2s, color .2s;
}
.sta-filtre-tranche { font-weight: 500; letter-spacing: .02em; text-transform: none; opacity: .75; margin-left: .3em; }
.sta-filtre:hover { background: rgb(28 18 6 / .07); }
.sta-filtre.active { background: var(--ink); color: var(--white); }
.sta-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: .9rem; }
.sta-item { background: var(--white); border-left: .35rem solid var(--orange); box-shadow: 0 10px 34px rgb(28 18 6 / .08); }
.sta-item[hidden] { display: none; }
.sta-tete {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.2rem 1.4rem 1.2rem 1.3rem;
  border: 0;
  background: none;
  color: inherit;
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.sta-tete-texte { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.sta-publics { font: 600 .74rem/1.3 var(--font-body); letter-spacing: .16em; text-transform: uppercase; color: var(--orange-deep); }
.sta-tranche {
  display: inline-block;
  margin-left: .5em;
  padding: .3em .55em;
  background: var(--orange);
  color: var(--ink);
  border-radius: .3rem;
  letter-spacing: .1em;
}
.sta-nom {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.4rem, 5.5vw, 3.6rem);
  line-height: .92;
  text-transform: uppercase;
  letter-spacing: .03em;
}
.sta-prochain { font-size: .95rem; font-weight: 500; opacity: .8; }
.sta-prochain-plus { opacity: .7; }
.sta-chevron {
  width: .7rem;
  height: .7rem;
  border-right: 2.5px solid var(--orange-deep);
  border-bottom: 2.5px solid var(--orange-deep);
  transform: rotate(45deg);
  transition: transform .3s var(--ease-out);
  flex: none;
  margin: 0 .3rem 0 0;
}
.sta-item.ouvert .sta-chevron { transform: rotate(-135deg) translate(-.15rem, -.15rem); }
/* Le volet : une piste de grille qui passe de 0fr à 1fr, aucune hauteur
   mesurée. Sans script (html sans .sta-js), tout reste déplié. */
.sta-boite { display: grid; grid-template-rows: minmax(0, 1fr); transition: grid-template-rows .45s var(--ease-out); }
.sta-js .sta-item:not(.ouvert) .sta-boite { grid-template-rows: minmax(0, 0fr); }
.sta-detail { overflow: hidden; min-height: 0; }
.sta-detail-inner {
  margin: 0 1.4rem 0 1.3rem;
  padding: 1.4rem 0 1.8rem;
  border-top: 1px solid rgb(28 18 6 / .1);
  display: grid;
  gap: 1.8rem;
}
/* Le détail d'un volet se met en deux colonnes selon sa propre largeur, pas
   celle de l'écran : entre 900 et 1200 px le volet n'occupe qu'une moitié de page
   et les dates en Humane y passaient toutes sur deux lignes. */
.sta-detail { container-type: inline-size; }
@container (min-width: 35rem) {
  .sta-sessions { grid-template-columns: 1fr 1fr; }
}
@container (min-width: 42rem) {
  .sta-detail-inner { grid-template-columns: 1.15fr 1fr; gap: 2.4rem; }
  .sta-sessions { grid-template-columns: 1fr; }
}
.sta-exergue { margin: 0 0 .8rem; font-weight: 600; color: var(--orange-deep); font-size: 1.1rem; line-height: 1.45; }
.sta-texte p { margin: 0 0 1em; line-height: 1.7; }
.sta-texte p:last-child { margin-bottom: 0; }
.sta-programme, .sta-horaires { margin-top: 1.4rem; }
.sta-programme h3, .sta-horaires h3, .sta-colonne--dates h3 {
  font: 600 .78rem/1 var(--font-body);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--orange-deep);
  margin: 0 0 .7rem;
}
.sta-programme ul { list-style: square; margin: 0; padding-left: 1.3rem; }
.sta-programme li { margin-bottom: .4rem; font-weight: 500; }
.sta-programme li::marker { color: var(--orange); }
.sta-horaires ul { list-style: none; margin: 0; padding: 0; }
.sta-horaires li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .2rem 1.2rem;
  padding: .6rem 0;
  border-top: 1px solid rgb(28 18 6 / .1);
}
.sta-horaire-note { font-weight: 500; opacity: .85; }
.sta-sessions { list-style: none; margin: 0; padding: 0; display: grid; gap: .8rem; }
.sta-session {
  background: var(--paper);
  border-radius: .8rem;
  padding: 1rem 1.1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: .3rem;
  align-items: flex-start;
}
.sta-session-periode { font: 600 .72rem/1 var(--font-body); letter-spacing: .16em; text-transform: uppercase; color: var(--orange-deep); }
.sta-session-dates {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2.2rem;
  line-height: .95;
  text-transform: uppercase;
  letter-spacing: .07em;
}
.sta-session-qui { font-size: .92rem; font-weight: 500; opacity: .85; }
.sta-session-note { margin: .4rem 0 0; font-size: .92rem; line-height: 1.55; }
.sta-session-btn { margin-top: .7rem; }
.sta-session--vide { border: 2px dashed rgb(28 18 6 / .18); background: transparent; }
@media (max-width: 360px) { .sta-session-dates { font-size: 1.95rem; } }
.sta-aucun { margin: 1.5rem 0 0; font-weight: 500; line-height: 1.6; }
.sta-aucun a { color: var(--orange-deep); text-decoration: underline; text-underline-offset: .15em; }
@media (max-width: 700px) {
  .sta-tete { padding: 1rem; }
  .sta-detail-inner { margin: 0 1rem; padding: 1.1rem 0 1.4rem; }
  .sta-horaires li { flex-direction: column; align-items: flex-start; gap: .1rem; }
}

/* ---- Stages, version « trois disciplines » : le nom et le texte de la
   discipline restent visibles, les volets par tranche d'âge se déplient. ---- */
/* La grille des ateliers se centre par margin: 0 auto : ne pas l'écraser
   (le bloc « Théâtre » collait au bord gauche, capture de Nicolas). */
.sta-disc.atl-public { margin: 0 auto; }
.sta-disc { scroll-margin-top: calc(var(--header-h) + 1rem); }
.sta-disc-tete { margin: 0 0 1.2rem; }
.sta-disc-nom {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 7vw, 5rem);
  line-height: .92;
  text-transform: uppercase;
  letter-spacing: .03em;
  margin: 0 0 .6rem;
}
.sta-disc-texte { max-width: 44rem; margin: 0; font-size: 1.05rem; line-height: 1.65; }
.sta-ligne { display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem .7rem; }
/* Humane écrite petit : plus grande et plus aérée (demande du 4 sept. 2026). */
.sta-item .sta-nom { font-size: clamp(2.3rem, 4.6vw, 2.9rem); letter-spacing: .07em; }
.sta-item .sta-tranche { margin-left: 0; font: 600 .74rem/1 var(--font-body); letter-spacing: .12em; text-transform: uppercase; }

/* ---- Stages V3 : mise en page des pages d'ateliers (escalier orange, titre
   tantôt à gauche tantôt à droite, volets en face) + pastilles de filtre. ---- */
.sta-corps.atl-corps { padding-top: 0; }
.sta-filtres-barre { max-width: 72rem; margin: 0 auto; padding: clamp(1.8rem, 5svh, 3rem) 0 0; }
.sta-disc[hidden] { display: none; }
.atl-public-tete .sta-disc-texte { margin: 1rem 0 0; font-size: 1.02rem; line-height: 1.65; }
.atl-public--droite .atl-public-tete .sta-disc-texte { margin-left: auto; }
.sta-disc .sta-liste { margin: 0; }
@media (min-width: 900px) {
  .atl-public--droite .atl-public-tete .sta-disc-texte { max-width: 26rem; }
  .atl-public-tete .sta-disc-texte { max-width: 26rem; }
}

/* ---- Le voile HelloAsso (don, inscription) : un écran par-dessus la page,
   le module défile en lui-même, un seul ascenseur. ---- */
.voile {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  background: var(--white);
}
.voile[hidden] { display: none; }
.voile-barre {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: calc(.7rem + env(safe-area-inset-top, 0px)) var(--pad) .7rem;
  background: var(--ink);
  color: var(--paper);
}
.voile-titre { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.voile-titre strong {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.7rem;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--orange);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.voile-note { font-size: .82rem; opacity: .75; }
.voile-fermer {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  border: 2px solid var(--paper);
  background: transparent;
  color: var(--paper);
  font: 600 .84rem/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: .7em 1.1em;
  border-radius: 999px;
  cursor: pointer;
}
.voile-fermer:hover, .voile-fermer:focus-visible { background: var(--paper); color: var(--ink); }
.voile iframe { flex: 1; width: 100%; min-height: 0; border: 0; background: var(--white); }
body.voile-ouvert { overflow: hidden; }
@media (max-width: 520px) {
  .voile-titre strong { font-size: 1.35rem; }
  .voile-fermer span { display: none; }
  .voile-fermer { padding: .6em; }
}


/* =====================================================================
   HUMANE SUR MOBILE (Nicolas, 4 sept. 2026 : « presque tous les titres sont
   petits et manquent de lisibilité ; revoir TOUTES les utilisations de cette
   police, l'aérer quand c'est nécessaire, renforcer sa présence sur mobile »).
   Règle : plus la Humane est petite, plus on l'écarte (.02em au-delà de 60 px,
   .03em entre 40 et 60, .04em entre 30 et 40, .05em et plus en dessous) ; et
   la borne basse des clamp() monte d'un cran, ce qui ne touche que les petits
   écrans (sur ordinateur, c'est la borne haute qui s'applique).
   ===================================================================== */
.page-hero .display { font-size: clamp(4.2rem, 12vw, 8.5rem); letter-spacing: .02em; }
.embed-scene .page-hero .display { font-size: clamp(3.6rem, 6.2vw, 5rem); }
.atl-titre { font-size: clamp(4.2rem, 12vw, 9rem); letter-spacing: .02em; }
.section-title { letter-spacing: .02em; }
.tile h3 { letter-spacing: .03em; }
.stg-nom { letter-spacing: .02em; }
.atl-nom { font-size: clamp(3.2rem, 7.5vw, 5.4rem); letter-spacing: .03em; }
.page-body h2 { font-size: clamp(2.7rem, 5.5vw, 3.6rem); letter-spacing: .035em; }
.atl-inscription h2 { letter-spacing: .03em; }
.prog-passes h2, .prog-retro h2 { font-size: clamp(2.6rem, 4.5vw, 3.2rem); letter-spacing: .035em; }
.prog-retro-tete h2 { font-size: clamp(2.7rem, 5vw, 3.6rem); letter-spacing: .035em; }
.prog-avenir-titre { font-size: clamp(2.8rem, 5vw, 3.6rem); }
.prog-grid .event-card h3 { font-size: clamp(2.3rem, 2.6vw, 2.6rem); letter-spacing: .045em; }
.agdx-mois-titre { font-size: clamp(2.6rem, 4.6vw, 3.4rem); letter-spacing: .03em; }
.agdx-num { letter-spacing: .02em; }
.agdx-evt-titre { letter-spacing: .045em; }
.pp-titre { font-size: 1.9rem; letter-spacing: .05em; }
.form-entete h4 { font-size: 2.5rem; letter-spacing: .04em; }
.newsletter h2.display { font-size: clamp(2.6rem, 5vw, 3.2rem); letter-spacing: .035em; }
.pay-etape h2 { font-size: clamp(2.6rem, 4.5vw, 3rem); letter-spacing: .035em; }
.pay-alerte h3 { letter-spacing: .04em; }
.pay-atelier-nom { letter-spacing: .04em; }
.trav-t { font-size: clamp(2.9rem, 6vw, 4.6rem); }
.trav-jalon-annee { font-size: clamp(2.5rem, 5vw, 3.4rem); letter-spacing: .03em; }
.trav-arrivee .trav-t { font-size: clamp(1.9rem, 3vw, 2.4rem); letter-spacing: .05em; }
.chiffres .nombre { letter-spacing: .02em; }
.voile-titre strong { letter-spacing: .05em; }
@media (max-width: 899px) {
  .agenda-grid .event-card h3 { font-size: 2.7rem; letter-spacing: .04em; }
}
@media (max-width: 480px) {
  .agdx-evt-titre { font-size: 2.2rem; }
}
@media (max-width: 520px) {
  .voile-titre strong { font-size: 1.7rem; }
}

/* ---- Logo du hero sur téléphone : plus de filter: drop-shadow (Nicolas, 4 sept.
   2026 : « on voit les bordures du logo »). Sur iPhone, le second drop-shadow
   (12 px, flou 36 px) est coupé aux limites du calque du filtre : la zone
   assombrie s'arrête net sous « THEATRE », en une ligne. text-shadow se rend
   glyphe par glyphe, sans calque ni limite. ---- */
.hero--v6 .hero-logo .logo-stack { filter: none; }
.hero--v6 .hero-logo .logo-stack > span { text-shadow: 0 2px 5px rgb(0 0 0 / .6), 0 12px 36px rgb(0 0 0 / .55); }

/* ---- Newsletter : la confirmation remplace les champs, là où on a saisi
   l'adresse (menu, bas de l'accueil, page contact). ---- */
.nl-confirmation { margin: .2rem 0 0; font-weight: 600; line-height: 1.5; }
.nl-confirmation--erreur { margin-top: .6rem; font-weight: 500; }
.nav-newsletter .nl-confirmation { font-size: 1.02rem; }
.newsletter-inner .nl-confirmation, .contact-newsletter .nl-confirmation { font-size: 1.15rem; max-width: 34rem; margin: 0 auto; }
form.nl-envoi button[type='submit'] { opacity: .6; cursor: progress; }

/* ---- Stages de l'accueil sur téléphone : ouverture d'un format plus fluide
   (« animation pas fluide quand on clique sur les différents niveaux »,
   relecture du 4 sept. 2026). La couleur d'un titre à halo ne s'anime plus
   (elle repeignait le titre à chaque image), le détail passe sur sa propre
   couche (will-change) et les durées raccourcissent. ---- */
@media (max-width: 899px) {
  .stg-nom { transition: transform .35s var(--ease-out); }
  .stg-detail { transition-duration: .3s; will-change: opacity; }
  .stg-detail-boite { transition-duration: .35s; }
  .stg-chevron { transition: transform .35s var(--ease-out); }
  .stg-age { transition: none; }
}

/* ---- VERROU DE PAGE SUR TOUT LE SITE (relecture du 4 sept. 2026 : « la barre
   ne se verrouille que sur la page d'accueil »). Même recette que l'accueil :
   la page ne défile pas, c'est .site-scroll (main + pied de page) qui défile ;
   Safari ne replie ses barres que sur un défilement de page, elles restent
   donc visibles partout. La classe html.verrou est posée par le script, sur
   toutes les pages sauf l'accueil (qui garde html.snap sur main). ---- */
html.verrou, html.verrou body { height: 100%; overflow: hidden; }
html.verrou .site-scroll {
  height: 100svh;
  height: 100dvh;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior-y: none;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) { html.verrou .site-scroll { scroll-behavior: auto; } }

/* ---- Cartes de l'agenda : un liseré clair apparaissait aux coins arrondis (le
   voile ::after et le fond de la carte ne sont pas lissés au même pixel).
   Le voile déborde d'un pixel et reprend l'arrondi ; le masque force Safari à
   découper proprement la carte, même transformée au survol. ---- */
.event-card::after { inset: -1px; border-radius: inherit; }
.event-card { -webkit-mask-image: -webkit-radial-gradient(white, black); background-clip: padding-box; }

/* ---- Stages de l'accueil, la vraie cause du saccadé sur téléphone : le
   triptyque est teinté par un mode de fusion (mix-blend-mode) sur des photos
   filtrées ; à chaque image de l'animation de la liste, le téléphone refondait
   tout l'écran. Le fond passe sur sa propre couche, isolée : la liste peut
   bouger, le fond n'est plus recalculé. ---- */
.stages-bg { isolation: isolate; will-change: transform; contain: paint; }
.stages-pane img { will-change: filter; }
@media (max-width: 899px) {
  .stg-liste, .stages-pied { will-change: transform; }
}

/* ---- Inscription sur ordinateur : titres en Humane plus grands (retour de
   Nicolas, 4 sept. 2026). Le téléphone garde ses tailles. ---- */
@media (min-width: 900px) {
  .voile-titre strong { font-size: 2.6rem; }
  .voile-note { font-size: .95rem; }
  .pay-etape h2 { font-size: clamp(3.4rem, 3.6vw, 4rem); }
  .pay-atelier-nom { font-size: 3.1rem; }
  .pay-alerte h3 { font-size: 2.9rem; }
}

/* ---- Contact : les horaires d'accueil en petite liste jours / heures
   (retour de Nicolas, 4 sept. 2026 : « pas très joli » en phrase). ---- */
.horaires { list-style: none; margin: .1rem 0 0; padding: 0; display: grid; gap: .3rem; }
.horaires li { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding-bottom: .3rem; border-bottom: 1px solid rgb(28 18 6 / .1); }
.horaires li:last-child { border-bottom: 0; }
.h-jours { font-weight: 600; }
.h-heures { text-align: right; white-space: nowrap; }

/* =====================================================================
   SCÈNE D'INTÉGRATION (mode « plein écran » du gabarit embed, plus utilisé
   par aucune page depuis que la page Don est redevenue une page qui défile).
   Un écran d'application : l'en-tête du site, le bandeau de la page, puis le
   module (HelloAsso, Billetweb) qui remplit tout le reste de l'écran et
   défile EN LUI-MÊME. La page ne défile pas et le pied de page est masqué :
   un seul ascenseur. Pourquoi pas une page qui défile ? Ces modules
   n'annoncent pas leur hauteur au site (HelloAsso : vérifié, aucun message),
   et leur bouton d'action est fixé en bas de leur cadre : un cadre à hauteur
   de page perdrait ce bouton et ferait un second défilement (toutes les
   autres formules ont été essayées et refusées, septembre 2026).
   Ce bloc remplace les cinq blocs d'essais successifs qu'il a fallu empiler.
   ===================================================================== */
.embed-scene { display: flex; flex-direction: column; height: 100svh; height: 100dvh; min-height: 0; }
.embed-scene .page-hero { flex: 0 0 auto; padding-top: calc(var(--header-h) + 1.2rem); padding-bottom: 1.3rem; }
.embed-scene .page-hero--visuel { min-height: clamp(10rem, 26vh, 15rem); }
.embed-scene .page-hero .display { font-size: clamp(3.6rem, 6.2vw, 5rem); margin-bottom: .3rem; }
.embed-scene .page-hero .page-intro { font-size: 1rem; }
.embed-scene .embed-ecran { flex: 1; min-height: 0; overflow: hidden; background: var(--white); }
.embed-scene .embed-ecran iframe { display: block; width: 100%; height: 100%; border: 0; }
body:has(.embed-scene) .site-scroll { overflow: hidden; scrollbar-width: none; }
body:has(.embed-scene) .site-scroll::-webkit-scrollbar { display: none; }
body:has(.embed-scene) .site-footer { display: none; }
/* Écran bas (petit téléphone, paysage) : le texte du bandeau cède la place au
   module, le titre suffit. */
@media (max-height: 700px) { .embed-scene .page-hero .page-intro { display: none; } }
/* Sans adresse de module : un message à la place du cadre. */
.don-vide { display: flex; align-items: center; justify-content: center; padding: 2rem var(--pad); text-align: center; line-height: 1.6; }
.don-vide a { color: var(--orange-deep); text-decoration: underline; text-underline-offset: .15em; }

