*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

/* Le defilement est pilote par Lenis, jamais par le natif : `scroll-behavior`
   resterait en concurrence avec lui et les deux se marcheraient dessus. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

body {
  background: var(--paper);
  transition: background-color var(--t-etat) var(--e-in),
              color var(--t-etat) var(--e-in);
  color: var(--ink);
  font-family: var(--f-corps);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

/* Focus : jamais supprimé, toujours remplacé. Seul repère du clavier. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
.sur-nuit :focus-visible { outline-color: var(--orange); }

.saut-contenu {
  position: absolute; left: -9999px;
  background: var(--accent); color: var(--accent-on);
  padding: 12px 20px; border-radius: var(--bord); z-index: 60;
}
.saut-contenu:focus { left: 16px; top: 16px; }

/* ── Enveloppes ─────────────────────────────────────────────────────────── */
.enveloppe { width: min(100% - 2 * var(--u) * 3, var(--max)); margin-inline: auto; }
@media (min-width: 760px) { .enveloppe { width: min(92%, var(--max)); } }

.section { padding-block: 40px; }
@media (min-width: 760px) { .section { padding-block: 56px; } }

/* ── La carte de section ─────────────────────────────────────────────────
   « Tout élément visuel dans une card aux bords arrondis, de format
   légèrement rectangulaire, plutôt qu'en bande pleine largeur. » Les
   sections ne touchent donc plus les bords de l'écran : chacune est un
   panneau posé sur le papier. Bordure 1 px, pas d'ombre — registre
   éditorial. */
/* Le panneau du premier jet a disparu avec lui : chaque section a maintenant
   son propre traitement — le ticket, l'auvent, le collage. Un conteneur
   générique arrondi était précisément ce qui rendait la page anonyme. */

/* Filet court — ponctue, ne coupe pas la page */
.filet { width: 40px; height: 3px; background: var(--ink); border: 0; }
.filet--nuit { background: var(--orange); }

/* ── Typographie ────────────────────────────────────────────────────────── */
.sur-titre {
  font-size: 12px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--mute);
}
.sur-titre--nuit { color: var(--orange); }

.display {
  font-family: var(--f-display); font-weight: 400;
  /* Plus de capitales. Anton n'existait qu'en capitales ou presque ; une
     égyptienne grasse en capitales sur trois lignes devient un mur. En bas de
     casse, les hampes et les jambages redonnent un relief au bloc, et le texte
     redevient une phrase qu'on lit plutôt qu'un panneau qui hurle. */
  line-height: .95; letter-spacing: -.01em;
}
/* Plancher à 2,15rem et non 2,6 : Alfa Slab est 68 % plus large qu'Anton, et
   à 2,6rem « Chichi churros » revenait à la ligne DANS son masque dès 360 px —
   première ligne mesurée à 91 px contre 51 pour les autres. Un retour à la
   ligne dans un bloc qui monte d'un seul tenant n'est pas un titre sur deux
   lignes, c'est un masque qui coupe.

   Révisé le 15/09 quand le titre est devenu « Chaque semaine, une autre
   place. » : des lignes plus longues qu'« les vrais » demandent un corps plus
   petit. 9,2vw est la plus grande valeur qui tienne une ligne par masque de
   320 à 1920 px, mesurée à huit largeurs. Toute réécriture du titre oblige à
   refaire cette mesure — c'est le prix d'un titre découpé en lignes fixes. */
h1.display { font-size: clamp(1.9rem, 9.2vw, 6.5rem); }
h2.display { font-size: clamp(2rem, 7vw, 3.6rem); }

.mesure { max-width: 58ch; }
/* Deux paragraphes de suite se touchaient : sans écart, ils se lisent comme un
   seul bloc et le lecteur ne voit pas qu'on change de sujet. */
.mesure + .mesure { margin-top: 1em; }

/* ── Boutons ────────────────────────────────────────────────────────────── */
.bouton {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: var(--cible); padding: 0 22px;
  font: inherit; font-weight: 600; text-decoration: none;
  border-radius: var(--bord); border: 1px solid transparent;
  cursor: pointer; background: transparent; color: var(--ink);
  transition: background-color var(--t-micro) var(--e-in),
              border-color var(--t-micro) var(--e-in),
              color var(--t-micro) var(--e-in);
}
/* UNE seule emphase forte sur toute la page : l'itinéraire. */
.bouton--primaire {
  min-height: var(--cible-prim);
  background: var(--accent); color: var(--accent-on);
  border-color: var(--accent); padding-inline: 28px;
}
.bouton--primaire:hover { background: var(--accent-survol); border-color: var(--accent-survol); }

.bouton--second { border-color: var(--rule); }
.bouton--second:hover { border-color: var(--ink); background: var(--paper-2); }

.bouton--nuit { color: var(--encre-nuit); border-color: var(--rule-nuit); }
.bouton--nuit:hover { border-color: var(--orange); color: var(--orange); }

.bouton[aria-busy="true"] { pointer-events: none; opacity: .72; }

/* ── 1. Hero : film piloté au défilement ───────────────────────────────── */
/* 400vh, pas 260 : la course determine combien de pixels de defilement valent
   une frame. A 260vh, 235 frames tenaient dans 1440 px — 6,1 px la frame, donc
   un defilement ordinaire reclamait 200 frames par seconde et ni le lisseur ni
   le decodeur ne suivaient. A 400vh la frame vaut le double de pixels, et la
   demande tombe de moitie a vitesse egale. */
/* Le hero est la SEULE section bord à bord.
   Les autres restent des panneaux encastrés — c'est la règle du projet. Ici le
   film doit remplir l'écran : un cadre encastré le réduit à une vignette et
   casse l'immersion que toute la page construit. */
.hero { position: relative; height: 400vh; padding: 0; }
.hero__cadre {
  position: sticky; top: 0;
  height: 100vh;
  overflow: hidden; background: var(--nuit);
}
.hero__toile,
.hero__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.hero__poster { z-index: 0; }
.hero__toile  { z-index: 1; opacity: 0; transition: opacity var(--t-entree) var(--e-in); }
.hero__toile[data-pret="1"] { opacity: 1; }

/* Voile en bande basse, pas un aplat : le fond reste visible.
   Il ne monte pas plus haut que le texte. */
.hero__voile {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(28,10,6,.55) 0%, rgba(28,10,6,.16) 22%,
    rgba(28,10,6,.58) 58%, rgba(28,10,6,.93) 100%);
}
.hero__contenu {
  position: absolute; inset: auto 0 0 0; z-index: 3;
  padding-bottom: clamp(40px, 9vh, 88px);
}
.hero__titre { color: var(--encre-nuit); }
/* Le titre mal calé, comme une affiche imprimée de travers.
   Le rose de la marque n'apparaissait nulle part dans le hero, alors qu'il
   porte toute la page. Il entre ici en DÉCALAGE derrière les lettres, pas en
   couleur de texte : c'est le hors-registre d'une impression foraine, et ça
   détoure le titre du fond brun, qui était le vrai problème de lisibilité.

   Décalage en em et pas en pixels : il doit suivre le corps, sinon il devient
   une ombre timide à 6,5rem et une bavure à 2,1rem.

   Zéro flou. Un décalage net est un défaut d'impression assumé ; un décalage
   flou est un « glow », que la direction artistique interdit — et il coûterait
   une re-rastérisation, ce qu'on vient précisément de chasser du hero. */
.hero__titre .ligne__i {
  text-shadow: .055em .045em 0 var(--accent);
}
/* L'orange reste, mais il ne se débrouille plus seul. Sur la friture brune il
   était boueux — même famille chaude, aucune séparation. Détouré de rose, il
   se détache enfin. L'emphase tient donc par la couleur ET par le contour :
   jamais la couleur seule, c'est ce que demande Von Restorff. */
.hero__titre em { font-style: normal; color: var(--orange); }
/* La ligne peinte de l'enseigne.
   Fraunces avec SOFT et WONK poussés : terminaisons molles et italique de
   travers, c'est le plus proche d'un lettrage à la main que donne la page —
   et c'est le seul rôle que Fraunces tient ici, celui des mots qu'on dirait
   à l'oral.

   Le basculement passe par `rotate`, pas par `transform` : le rideau d'entrée
   utilise déjà `transform` sur ce même élément, et les deux s'écraseraient.
   Les propriétés de transformation individuelles existent pour ça. */
.hero__enseigne {
  margin-top: 12px;
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-style: italic; font-weight: 800;
  font-size: clamp(1.15rem, 3.2vw, 1.95rem);
  line-height: 1.1;
  /* Crème et non orange, pour deux raisons qui vont dans le même sens.
     Sur la remorque, le slogan n'est pas de la couleur du grand lettrage.
     Et posé en orange juste sous « une autre place », qui l'est déjà, il
     faisait deux emphases fortes collées l'une à l'autre : elles s'annulent.
     Le même décalage rose que le titre le rattache à la même impression. */
  color: var(--encre-nuit);
  text-shadow: .05em .04em 0 var(--accent);
  rotate: -1.6deg;
  transform-origin: left center;
}
.hero__accroche { margin-top: 18px; color: var(--paper-mute); max-width: 34ch; }

/* Sous 430 px, l'accroche allait se glisser sous la guirlande : mesuré, elle
   mordait de 33 px à 390 et de 34 à 360. On lui réserve la largeur de
   l'invite plutôt que de déplacer l'invite — elle est en bas à droite parce
   que c'est là qu'un pouce la trouve. Le titre n'est pas touché : ses lignes
   s'arrêtent avant, et lui rogner la place le ferait revenir à la ligne. */
@media (max-width: 430px) {
  .hero__accroche, .hero__actions { max-width: calc(100% - 54px); }
}
.hero__actions { margin-top: var(--gap-inter); display: flex; flex-wrap: wrap; gap: var(--gap-intra); }

/* Moteur arrete : le hero cesse d'etre un long defilement pilote et redevient
   une section de hauteur normale. Rester epingle sur 400vh d'image fixe, c'est
   ce qui donne l'impression que le defilement est casse. */
.hero[data-degrade="1"] { height: 100vh; }

/* ── Le texte du hero : entrée, sortie, et rien qui coûte cher ───────────
   Le flou piloté à l'image est parti, et ce n'est pas un arbitrage de goût.
   Mesuré au banc, defilement scripté sur le hero, images au-delà de 32 ms :

     tel quel, rayon de flou variable ......... 58,0 %   médiane 33,3 ms
     rayon figé à blur(0px) ................... 24,2 %   médiane 16,7 ms
     sans filtre du tout ...................... 16,3 %   médiane 16,7 ms

   Ce n'est pas le filtre qui coûte, c'est le RAYON qui change : chaque valeur
   force une re-rastérisation complète du bloc de texte. La page tournait à
   30 images par seconde, et tout ce qui bougeait autour — la marquise en
   premier — tremblait pour cette seule raison.

   Ce qui le remplace ne touche que `transform` et `opacity`, les deux seules
   propriétés que le compositeur sait animer sans rien demander au fil
   principal. L'effet est plus fort et il est gratuit.

   À l'arrivée   chaque ligne monte de derrière son propre bord, décalée de
                 90 ms sur la précédente. C'est le rideau qui se lève, pas un
                 bloc qui apparaît.
   En descendant le texte s'en va vers le haut et s'efface, et laisse le film
                 seul. Il ne disparaît qu'après la moitié de la course : avant,
                 on est encore en train de le lire.
   ───────────────────────────────────────────────────────────────────────── */
.hero__titre { display: block; }
.hero__titre .ligne {
  display: block; overflow: hidden;
  /* Le masque doit laisser passer les accents et les jambages, sinon le Ç et
     le É se font couper. On l'élargit du débord réel, et on reprend la place
     en marge négative pour que l'interligne ne bouge pas. */
  padding-block: .14em; margin-block: -.14em;
}
.hero__titre .ligne__i {
  /* 820 ms, et le gate Barthez le signale — à raison de le signaler, à tort
     de le refuser. Le seuil des 400 ms de Doherty porte sur la RÉPONSE À UNE
     ACTION : au-delà, on passe de « faire » à « attendre ». Personne n'attend
     ici, personne n'a rien demandé. C'est un rideau qui se lève à l'arrivée,
     et un rideau qui se lève en 400 ms est un rideau qu'on arrache.
     Aucune action de la page ne dépasse 400 ms : les boutons, les plaques et
     le ticket restent sur --t-etat. */
  display: block;
  transform: translateY(112%);
  transition: transform 820ms var(--e-rideau);
  transition-delay: calc(var(--r, 0) * 1ms);
}
.sur-titre--nuit,
.hero__enseigne,
.hero__accroche,
.hero__actions {
  opacity: 0; transform: translateY(14px);
  transition: opacity 520ms var(--e-in), transform 520ms var(--e-rideau);
  transition-delay: calc(var(--r, 0) * 1ms);
}
.hero[data-leve="1"] .hero__titre .ligne__i { transform: none; }
.hero[data-leve="1"] .sur-titre--nuit,
.hero[data-leve="1"] .hero__enseigne,
.hero[data-leve="1"] .hero__accroche,
.hero[data-leve="1"] .hero__actions { opacity: 1; transform: none; }

/* La sortie, pilotée par la position dans le film. `--sortie` va de 0 à 1 et
   n'est posé qu'après la moitié de la course : ni transition ni retard ici,
   la valeur suit le doigt image par image. */
.hero__contenu {
  --sortie: 0;
  transform: translate3d(0, calc(var(--sortie) * -72px), 0);
  opacity: calc(1 - var(--sortie) * .92);
  will-change: transform, opacity;
}

/* Le chargement du film. Le titre ne peut plus servir de jauge — c'était le
   flou qui la portait — donc l'attente se dit en toutes lettres, juste
   au-dessus, et le bloc reste en retrait tant que rien n'est prêt. */
.hero[data-chargement="1"] .hero__contenu { opacity: calc(.4 + var(--net, 1) * .6); }

@media (prefers-reduced-motion: reduce) {
  /* Pas de rideau : tout est déjà en place. La sortie au défilement reste,
     c'est une position dans la page, pas une animation décorative. */
  .hero__titre .ligne__i,
  .sur-titre--nuit, .hero__enseigne, .hero__accroche, .hero__actions {
    transform: none; opacity: 1; transition: none;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   DIRECTION ARTISTIQUE — « la fête foraine », pas la page de restaurant

   Le premier jet était juste : lisible, contrasté, conforme. Et sans aucune
   joie — des panneaux arrondis les uns sous les autres, ce que produit
   n'importe quel gabarit. Le client, lui, vend de la barbe à papa sous une
   guirlande d'ampoules.

   Quatre motifs portent la refonte, tous issus de son propre monde :

     la marquise   — le bandeau lumineux qui court au-dessus d'un comptoir
     l'auvent      — le feston rayé d'un stand de foire
     le ticket     — la contremarque qu'on déchire à l'entrée
     le cliché     — les photos punaisées de travers, pas alignées au cordeau

   Rien de décoratif au sens interdit : chaque motif dit quelque chose. La
   marquise énumère ce qu'on vend, le ticket dit que l'adresse est datée et
   qu'elle expire, le feston sépare le dehors du dedans, et le désalignement
   des clichés dit qu'un stand n'est pas une boutique.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Titres de section ────────────────────────────────────────────────────
   Anton reste au hero. Ici le titre est en Fraunces, dont les axes SOFT et
   WONK donnent des terminaisons molles et un italique de travers : c'est le
   mot prononcé, pas le mot imprimé. Un seul mot par titre le prend. */
.entete { max-width: 42ch; }
.titre {
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1, "opsz" 144;
  font-weight: 800;
  font-size: clamp(2.6rem, 8vw, 5rem);
  line-height: .95;
  letter-spacing: -.02em;
  margin-top: 6px;
  color: var(--ink);
}
.titre em {
  font-style: italic;
  color: var(--accent);
  /* L'italique de Fraunces penche déjà ; on lui donne un peu d'air à droite
     pour que la lettre suivante ne vienne pas la percuter. */
  padding-right: .06em;
}
.titre--nuit { color: var(--encre-nuit); }
.titre--nuit em { color: var(--orange); }

.entete__note {
  margin-top: 14px; color: var(--mute); max-width: 34ch;
}

/* ── La marquise ──────────────────────────────────────────────────────────
   Deux pistes identiques qui défilent de -50 % : c'est le seul montage qui
   boucle sans couture visible. Les ampoules courent au-dessus et au-dessous,
   et s'allument en décalé — comme une vraie guirlande, jamais toutes en même
   temps. */
.marquise {
  position: relative; z-index: 5;
  background: var(--accent);
  color: var(--accent-on);
  overflow: hidden;
  border-block: 2px solid var(--ink);
}
.marquise__voie { overflow: hidden; }
/* Le cortège encaisse la réaction au défilement, les pistes gardent leur boucle.
   Séparer les deux n'est pas cosmétique : la boucle reste une animation CSS à
   durée constante, donc le compositeur la joue sans rien demander au fil
   principal — et elle continue toute seule pendant que le décodeur travaille. */
.marquise__cortege {
  display: flex; width: max-content;
  transform: translate3d(calc(var(--pousse, 0) * 1px), 0, 0);
  will-change: transform;
}
.marquise__piste {
  display: flex; align-items: center; gap: 22px;
  list-style: none; padding: 13px 11px 13px 0; margin: 0;
  flex: 0 0 auto; white-space: nowrap;
  font-family: var(--f-display);
  text-transform: uppercase; font-size: clamp(.95rem, 2.4vw, 1.3rem);
  letter-spacing: .04em;
  /* Durée FIXE, et elle ne doit jamais être réécrite en cours de route.
     Changer la durée d'une animation qui tourne re-mappe son temps écoulé sur
     la nouvelle durée : la progression saute. Fait à chaque image, comme
     c'était le cas jusqu'au 15/09, l'enseigne ne saccade pas — elle tremble.
     Et une animation constamment retimée quitte le compositeur. */
  animation: defile 26s linear infinite;
}
.marquise__piste li[aria-hidden] { color: var(--orange); font-size: .8em; }
@keyframes defile { to { transform: translateX(-100%); } }

.marquise__ampoules {
  height: 9px;
  /* Ce dégradé ne décore pas : il DESSINE les ampoules. Un radial répété est
     la façon la plus légère de poser une guirlande de points réguliers, et
     aucune image ne ferait mieux. */
  background-image: radial-gradient(circle at 50% 50%,
                    var(--orange) 0 2.6px, transparent 2.8px);
  background-size: 22px 9px;
  animation: guirlande 1.6s steps(2) infinite;
}
.marquise__ampoules:last-child { animation-delay: .8s; }
@keyframes guirlande { 50% { opacity: .45; } }

@media (prefers-reduced-motion: reduce) {
  .marquise__piste { animation: none; }
  .marquise__ampoules { animation: none; }
}

/* ── L'auvent ─────────────────────────────────────────────────────────────
   Le feston d'un stand de foire : des demi-cercles taillés dans le bord haut
   d'une section sombre. Fait au masque, donc il découpe vraiment le fond au
   lieu de poser une frise par-dessus — ce qui compte quand une image passe
   dessous. */
.auvent {
  position: absolute; inset: 0 0 auto 0; height: 26px; z-index: 3;
  background: var(--nuit);
  --dent: 34px;
  /* Un masque ne lit que le canal alpha : la couleur opaque n'a aucune
     importance, d'où un jeton plutôt qu'un noir pur qui n'en serait pas un. */
  mask-image: radial-gradient(circle at 50% 0,
              transparent 0 calc(var(--dent) / 2), var(--nuit) calc(var(--dent) / 2 + 1px));
  mask-size: var(--dent) 100%;
  mask-repeat: repeat-x;
  mask-position: 0 100%;
}
.auvent--pied { background: var(--nuit); }

/* ── Le ticket ────────────────────────────────────────────────────────────
   L'objet central de la page : l'adresse de la semaine. Elle est datée, elle
   expire, on la présente à l'entrée — un ticket dit tout ça sans une phrase.

   Les encoches sont deux dégradés radiaux posés en fond, pas des pseudo-
   éléments : ils suivent la hauteur réelle du bloc, qui change avec le
   contenu chargé. */
.ticket {
  position: relative;
  margin-top: var(--gap-inter);
  background: var(--wash);
  overflow: hidden;
  border-radius: var(--bord-carte);
  padding: clamp(26px, 5vw, 52px);
  color: var(--ink);
}
.ticket__cachet {
  position: absolute; top: 18px; right: clamp(20px, 5vw, 46px);
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-weight: 900; font-size: .84rem; letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  border: 2px solid var(--accent); border-radius: 6px;
  padding: 5px 11px;
  transform: rotate(-9deg);
  opacity: .62;
}
.ticket__label {
  font-family: var(--f-corps);
  font-size: 11px; font-weight: 800; letter-spacing: .16em;
  text-transform: uppercase; color: var(--mute);
}
/* `wrap` et `min-width: 0`, sinon la rangée refuse de se replier et pousse son
   contenu hors du ticket, qui le rogne en silence — il est en `overflow: hidden`
   pour ses encoches. Mesuré à 320 px : ticket large de 272 px, adresse courant
   jusqu'à 341, numéro de série entier hors champ à 373. Un élément flexible ne
   descend pas sous la largeur de son contenu tant qu'on ne l'y autorise pas. */
.ticket__haut {
  display: flex; flex-wrap: wrap;
  justify-content: space-between; gap: var(--gap-intra) var(--gap-inter);
  align-items: flex-start;
}
.ticket__haut > * { min-width: 0; }
.ticket__commune {
  font-family: var(--f-display);
  text-transform: uppercase; line-height: .86; letter-spacing: -.02em;
  font-size: clamp(2.8rem, 11vw, 6rem);
  color: var(--accent);
  margin-top: 8px;
}
.ticket__adresse { margin-top: var(--gap-intra); font-size: 1.06rem; max-width: 38ch; }
.ticket__maj { margin-top: 8px; font-size: .88rem; color: var(--mute); }
.ticket__serie {
  font-family: var(--f-display); font-size: 1.4rem; line-height: .95;
  text-align: right; color: var(--rule); flex: 0 0 auto;
  /* Le cachet occupe le coin haut droit : la série descend sous lui. */
  align-self: flex-end;
}
.ticket__actions {
  margin-top: var(--gap-inter); display: flex; flex-wrap: wrap; gap: var(--gap-intra);
}

/* La souche, détachée par une ligne de perforations.
   Les encoches sont portées par CETTE ligne, pas par le fond du ticket : un
   ticket se déchire là où il est encoché, et une position en dur dans un
   dégradé se décale dès que l'adresse tient sur une ligne de plus. */
.ticket__souche {
  position: relative;
  margin-top: var(--gap-inter);
  padding-top: var(--gap-inter);
  border-top: 2px dashed var(--rule);
}
.ticket__souche::before,
.ticket__souche::after {
  content: ""; position: absolute; top: -14px;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--paper);
}
.ticket__souche::before { left: calc(-1 * clamp(26px, 5vw, 52px) - 13px); }
.ticket__souche::after  { right: calc(-1 * clamp(26px, 5vw, 52px) - 13px); }

/* ── Les séances ──────────────────────────────────────────────────────────
   Pas un tableau d'horaires : une grille de séances, comme au cinéma
   forain. Le jour d'aujourd'hui porte une pastille, jamais la couleur seule. */
.horaires { margin-top: var(--gap-intra); }
.horaires__ligne {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--rule);
  font-variant-numeric: tabular-nums;
}
.horaires__ligne:last-child { border-bottom: 0; }
.horaires__ligne[data-aujourdhui="1"] { font-weight: 800; }
.horaires__ligne[data-aujourdhui="1"] .horaires__jour::before {
  content: "●"; color: var(--accent); margin-right: 8px; font-size: .7em;
  vertical-align: middle;
}
.horaires__ligne[data-ferme="1"] { color: var(--mute); }
.horaires__ligne[data-ferme="1"] .horaires__jour { text-decoration: line-through;
  text-decoration-color: var(--rule); text-decoration-thickness: 1px; }

/* État vide / erreur : une phrase ET l'action suivante, jamais une image seule */
.repli p { color: var(--mute); margin-top: var(--gap-intra); }
.repli .bouton { margin-top: var(--gap-inter); }

/* Squelette de chargement (Doherty : retour immédiat au-delà de 400 ms) */
.squelette { background: rgba(42,12,27,.09); border-radius: 6px; height: 1em; }
.squelette--titre { height: clamp(2.8rem, 11vw, 6rem); max-width: 9ch; margin-top: var(--gap-intra); }
.squelette--ligne { max-width: 36ch; margin-top: var(--gap-intra); }

/* ── Le menu, sous l'auvent ───────────────────────────────────────────── */
.menu {
  position: relative; overflow: hidden;
  background: var(--nuit); color: var(--encre-nuit);
  padding-block: 74px 64px;
}
@media (min-width: 760px) { .menu { padding-block: 96px 84px; } }
.menu__fond {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .26;
}
.menu__voile { position: absolute; inset: 0; background: rgba(28,10,6,.58); }
.menu__dedans { position: relative; z-index: 4; }

.plaques {
  list-style: none; margin: var(--gap-inter) 0 0; padding: 0;
  display: grid; gap: var(--gap-intra);
  grid-template-columns: 1fr;
}
@media (min-width: 680px) {
  .plaques {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--gap-inter);
    /* `start`, sinon une plaque ouverte étire sa voisine à sa hauteur : la
       grille remplit toujours la rangée. On se retrouvait avec une grande
       boîte vide à côté de celle qu'on vient d'ouvrir. */
    align-items: start;
  }
}

/* La plaque de prix : une ardoise vissée sous l'auvent.

   Elle OUVRE. La version précédente affichait une flèche au survol qui ne
   menait nulle part : sur un téléphone, où il n'y a pas de survol, l'affordance
   mentait deux fois. Une flèche qui ne fait rien est pire qu'une plaque muette.

   Chaque plaque est donc un vrai bouton qui déplie une photo du produit et une
   phrase sur la façon dont il se fait. Le menu cesse d'être une liste de mots
   pour devenir ce qu'on regarde avant de commander. */
.plaque {
  position: relative;
  border: 1px solid var(--rule-nuit);
  border-radius: var(--bord-carte);
  background: rgba(251,239,230,.05);
  overflow: hidden;
  transition: border-color var(--t-micro) var(--e-in),
              background-color var(--t-micro) var(--e-in);
}
.plaque:hover, .plaque:focus-within { border-color: var(--orange); background: rgba(250,170,72,.10); }
.plaque[data-ouvert="1"] { border-color: var(--orange); background: rgba(250,170,72,.12); }

.plaque__ouvrir {
  display: grid;
  grid-template-columns: 64px 1fr 34px;
  grid-template-areas: "num nom signe" "num quoi signe";
  align-items: start; gap: 4px 12px;
  width: 100%; padding: 24px 20px 24px 16px;
  background: none; border: 0; cursor: pointer;
  font: inherit; color: inherit; text-align: left;
  min-height: var(--cible);
}
.plaque__num {
  grid-area: num; align-self: start;
  font-family: var(--f-display); font-size: 2.5rem; line-height: .9;
  color: var(--orange); opacity: .85;
}
.plaque__nom {
  grid-area: nom;
  font-family: var(--f-display); font-weight: 400; text-transform: uppercase;
  font-size: clamp(1.35rem, 3.4vw, 1.8rem); line-height: .94;
  color: var(--encre-nuit);
}
.plaque__quoi { grid-area: quoi; margin-top: 8px; color: var(--paper-mute); font-size: .95rem; }

/* Le signe dit l'état, et il le dit par la FORME : une croix qui pivote en
   moins. La couleur seule ne porte jamais une information (B6). */
.plaque__signe {
  grid-area: signe; align-self: center; justify-self: end;
  position: relative; width: 22px; height: 22px;
}
.plaque__signe::before, .plaque__signe::after {
  content: ""; position: absolute; inset: 50% 0 auto 0;
  height: 2px; background: var(--orange); border-radius: 2px;
  transition: transform var(--t-etat) var(--e-in);
}
.plaque__signe::after { transform: rotate(90deg); }
.plaque[data-ouvert="1"] .plaque__signe::after { transform: rotate(0deg); }

/* Le volet. La hauteur est animée par une variable posée en JS : `auto` ne
   s'anime pas, et une hauteur en dur se périmerait à chaque changement de
   texte ou de largeur. */
.volet {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-entree) var(--e-in);
}
.plaque[data-ouvert="1"] .volet { grid-template-rows: 1fr; }
.volet > * { min-height: 0; }
.volet__dedans { overflow: hidden; }
.volet img {
  /* `height: auto` n'est pas décoratif : sans lui, l'attribut `height="750"`
     du balisage l'emporte sur `aspect-ratio` et l'image s'affiche trois fois
     trop haute. Mesuré : 340 x 750 au lieu de 340 x 255.
     Et un plafond en `vh`, pour qu'un volet ouvert n'avale jamais l'écran. */
  width: 100%; height: auto; aspect-ratio: 4 / 3;
  max-height: 38vh; object-fit: cover; display: block;
  border-top: 1px solid var(--rule-nuit);
}
.volet__dire {
  padding: 16px 20px 22px;
  color: var(--encre-nuit); font-size: .97rem; line-height: 1.5;
}

@media (prefers-reduced-motion: reduce) {
  .volet { transition: none; }
  .plaque__signe::before, .plaque__signe::after { transition: none; }
}

/* ── Le stand : un collage, pas une grille ────────────────────────────
   Première version calée sur `grid-auto-rows: 8px` et des `span` comptés à la
   main : deux clichés sur quatre n'apparaissaient pas, et la moindre
   variation de contenu cassait tout. Des spans de colonnes explicites et un
   ratio par image donnent le même désalignement, sans arithmétique fragile. */
.stand__jeu { display: grid; gap: var(--gap-inter); grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .stand__jeu { grid-template-columns: repeat(12, 1fr); align-items: start; }
  .stand__dire { grid-column: 1 / 5; grid-row: 1 / 3; position: sticky; top: 96px; }
  .cliche--1 { grid-column: 5 / 10;  grid-row: 1; aspect-ratio: 4 / 3; }
  .cliche--2 { grid-column: 10 / 13; grid-row: 1; aspect-ratio: 3 / 4; margin-top: 56px; }
  .cliche--3 { grid-column: 5 / 8;   grid-row: 2; aspect-ratio: 3 / 4; }
  .cliche--4 { grid-column: 8 / 13;  grid-row: 2; aspect-ratio: 4 / 3; margin-top: 40px; }
}
.stand__texte { margin-top: var(--gap-inter); max-width: 38ch; color: var(--ink); }

/* Le cliché : punaisé de travers. Les angles alternent, faibles — au-delà de
   trois degrés on ne lit plus une photo posée mais une erreur de mise en page. */
.cliche {
  margin: 0; position: relative;
  border: 1px solid var(--rule);
  border-radius: var(--bord-carte);
  overflow: hidden;
  background: var(--paper-2);
  transition: transform var(--t-etat) var(--e-in);
}
.cliche img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cliche figcaption {
  position: absolute; left: 10px; bottom: 10px;
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-style: italic; font-weight: 700; font-size: .84rem;
  color: var(--accent-on); background: var(--accent);
  padding: 4px 10px; border-radius: 20px;
}
@media (min-width: 900px) {
  .cliche--1 { transform: rotate(-1.6deg); }
  .cliche--2 { transform: rotate(2.2deg); }
  .cliche--3 { transform: rotate(1.4deg); }
  .cliche--4 { transform: rotate(-2deg); }
  .cliche:hover { transform: rotate(0deg) scale(1.015); z-index: 2; }
}

/* La note, en pastille cousue — un autocollant sur la vitre. */
.pastille {
  display: inline-flex; align-items: baseline; gap: 8px;
  margin-top: var(--gap-inter);
  padding: 10px 18px;
  background: var(--wash);
  border: 2px solid var(--accent);
  border-radius: 999px;
  transform: rotate(-2.5deg);
}
.pastille strong {
  font-family: var(--f-display); font-size: 1.7rem; line-height: 1;
  color: var(--accent);
}
.pastille span[aria-hidden] { color: var(--accent); }
.pastille__dit { font-size: .86rem; color: var(--mute); }

/* ── Le pied ──────────────────────────────────────────────────────────── */
.pied {
  position: relative;
  background: var(--nuit); color: var(--encre-nuit);
  padding-block: 74px 40px;
  overflow: hidden;
}
.pied__dedans { position: relative; z-index: 2; }
.pied a { color: var(--encre-nuit); }
.pied__tel {
  font-family: var(--f-display); text-transform: uppercase; letter-spacing: -.01em;
  font-size: clamp(2rem, 8vw, 4rem); line-height: 1; text-decoration: none;
  display: inline-flex; align-items: center; gap: 14px;
  margin-top: var(--gap-intra); min-height: var(--cible);
  transition: color var(--t-micro) var(--e-in);
}
.pied__tel span { color: var(--orange); font-size: .6em; }
.pied__tel:hover { color: var(--orange); }
.pied__promesse {
  margin-top: var(--gap-inter); color: var(--paper-mute); max-width: 40ch;
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-style: italic; font-size: 1.1rem; line-height: 1.5;
}
.pied__bas {
  margin-top: var(--gap-inter); padding-top: 20px;
  border-top: 1px solid var(--rule-nuit);
  display: flex; flex-wrap: wrap; gap: var(--gap-intra) var(--gap-inter);
  justify-content: space-between; color: var(--paper-mute); font-size: .88rem;
}
/* Fitts : un lien de texte reste un lien de texte, mais sa ZONE tactile
   descend au plancher de 44 px. C'est la zone qui compte, pas le trait. */
.pied__bas a {
  display: inline-flex; align-items: center;
  min-height: var(--cible); padding-block: 12px;
}
/* ── Mouvement : entree des blocs et reaction au curseur ────────────────
   Barthez interdit l'animation qui ne signifie rien, et le `translateY` de
   survol uniforme sur une grille — la signature des interfaces generees.
   Ce qui suit signifie donc quelque chose : l'entree marque l'arrivee d'un
   bloc dans le champ, le survol marque LEQUEL est designe (bordure + fleche),
   et la parallaxe du titre repond au curseur sans deplacer personne d'autre.
   ───────────────────────────────────────────────────────────────────────── */
[data-entree] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--t-entree) var(--e-in),
              transform var(--t-entree) var(--e-in);
  transition-delay: var(--retard, 0ms);
}
[data-entree][data-vu="1"] { opacity: 1; transform: none; }

/* Le survol ne souleve pas : il designe. La bordure passe a l'accent, le
   numero avance, la carte se teinte de 2 %. Une seule carte change a la fois. */
/* Le survol des plaques et des clichés est défini avec eux, plus haut :
   chacun désigne l'élément pointé au lieu de soulever toute la grille. */

/* Parallaxe du titre : amplitude en pixels, pilotee par le curseur. */
.hero__contenu .enveloppe {
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0);
  transition: transform 240ms var(--e-in);
}

@media (prefers-reduced-motion: reduce) {
  [data-entree] { opacity: 1; transform: none; transition: none; }
  .cliche, .cliche:hover { transform: none; }
  .pastille, .ticket__cachet { transform: none; }
  .hero__contenu .enveloppe { transform: none; }
}
@media (hover: none) {
  .hero__contenu .enveloppe { transform: none; }
}


/* Contenu réservé aux technologies d'assistance. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Fitts : un lien de texte reste un lien de texte, mais sa ZONE tactile
   descend au plancher de 44 px. C'est la zone qui compte, pas le trait. */
.pied__bas a {
  display: inline-flex; align-items: center;
  min-height: var(--cible); padding-block: 12px;
}

/* État de chargement du film. Le titre du hero sert de jauge, en se précisant ;
   cette ligne dit ce qui se charge. Elle disparaît dès que le film est prêt, et
   ne s'affiche jamais si l'attente est restée sous 400 ms. */
.hero__chargement {
  position: absolute; z-index: 4; top: 14px; left: 16px;
  margin: 0; font-family: var(--f-corps); font-size: 12px; font-weight: 600;
  letter-spacing: .04em; color: var(--orange);
  opacity: 0; transition: opacity var(--t-etat) var(--e-in);
  pointer-events: none;
}
.hero[data-chargement="1"] .hero__chargement { opacity: 1; }

/* ══════════════════════════════════════════════════════════════════════════
   FAIT DEVANT VOUS — la promesse, démontrée

   C'était un sur-titre décoratif au-dessus du menu. C'est maintenant une
   section, parce que c'est le seul argument qu'un rayon de supermarché ne
   peut pas copier : le délai entre la pâte et la main.

   Quatre temps sur une ligne, avec le chrono qui court. La ligne se remplit
   à mesure que les temps entrent dans le champ — le mouvement raconte
   exactement ce que la section dit.
   ══════════════════════════════════════════════════════════════════════════ */
.devant { background: var(--paper-2); }

.temps {
  list-style: none; margin: var(--gap-inter) 0 0; padding: 0;
  display: grid; gap: var(--gap-inter);
  grid-template-columns: 1fr;
  position: relative;
}
@media (min-width: 820px) {
  .temps { grid-template-columns: repeat(4, 1fr); gap: var(--gap-intra); }
  /* Le fil qui relie les quatre temps. Il se remplit quand ils entrent. */
  .temps::before {
    content: ""; position: absolute; left: 0; right: 0; top: 21px; height: 2px;
    background: var(--rule);
  }
  .temps::after {
    content: ""; position: absolute; left: 0; top: 21px; height: 2px;
    width: 0; background: var(--accent);
    transition: width 1.1s var(--e-in) .2s;
  }
  .temps[data-rempli="1"]::after { width: 100%; }
}

.temps__pas { position: relative; padding-top: 58px; }
.temps__num {
  position: absolute; top: 0; left: 0;
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--f-display); font-size: 1.3rem; line-height: 1;
  color: var(--accent-on); background: var(--accent);
  border: 3px solid var(--paper-2);
}
.temps__titre {
  font-family: var(--f-display); font-weight: 400; text-transform: uppercase;
  font-size: clamp(1.1rem, 2.6vw, 1.35rem); line-height: .98; color: var(--ink);
}
.temps__quoi { margin-top: 10px; color: var(--mute); font-size: .95rem; max-width: 26ch; }
.temps__duree {
  display: inline-block; margin-top: var(--gap-intra);
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-style: italic; font-weight: 800; font-size: 1.05rem;
  color: var(--accent);
}
/* Le dernier temps est celui qui compte : c'est lui qu'on retient (B7). */
.temps__pas--fin .temps__duree {
  background: var(--accent); color: var(--accent-on);
  padding: 3px 12px; border-radius: 999px;
}

.devant__chute {
  margin-top: var(--gap-inter);
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-size: clamp(1.15rem, 3vw, 1.6rem); line-height: 1.35;
  max-width: 30ch; color: var(--ink);
}
.devant__chute em { font-style: italic; color: var(--accent); }

/* ── Le ticket qui arrive ─────────────────────────────────────────────────
   Déclenché par `data-arrive`, posé quand la donnée est chargée ET contrôlée.
   Le cachet se tamponne, la commune s'inscrit par le bas. Rien ne bouge si la
   requête échoue : il n'y aurait rien à annoncer. */
.ticket[data-arrive="1"] .ticket__cachet {
  animation: tamponner .42s var(--e-in) both;
}
@keyframes tamponner {
  0%   { opacity: 0; transform: rotate(-9deg) scale(2.1); }
  70%  { opacity: .72; transform: rotate(-9deg) scale(.94); }
  100% { opacity: .62; transform: rotate(-9deg) scale(1); }
}
.ticket[data-arrive="1"] .ticket__commune {
  animation: sinscrire .5s var(--e-in) both .06s;
}
@keyframes sinscrire {
  from { opacity: 0; transform: translateY(.22em); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .ticket[data-arrive="1"] .ticket__cachet,
  .ticket[data-arrive="1"] .ticket__commune { animation: none; }
}

/* ── Le chrono ────────────────────────────────────────────────────────────
   Les durées étaient écrites en dur : « 0 min », « +30 s », « 3 min ». Du
   texte pour dire un temps qui passe, alors que la section entière parle de
   vitesse. Un chronomètre qui court dit la même chose et la démontre.

   Il part quand la section entre dans le champ, franchit 3:00 en moins de
   trois secondes, et allume chaque temps au passage de sa seconde. */
.chrono {
  display: flex; align-items: baseline; gap: 14px;
  margin-top: var(--gap-inter);
}
.chrono__cadran {
  font-family: var(--f-display);
  font-size: clamp(3.4rem, 13vw, 6.5rem); line-height: .82;
  letter-spacing: -.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.chrono__dit {
  font-family: var(--f-fantaisie);
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-style: italic; font-size: 1.05rem; color: var(--mute);
}

/* Un temps qu'on n'a pas encore atteint reste en retrait. Il s'allume quand le
   chrono le dépasse : l'ordre de lecture devient l'ordre des opérations. */
.temps__pas { opacity: .34; transition: opacity var(--t-etat) var(--e-in); }
.temps__pas[data-atteint="1"] { opacity: 1; }
.temps__num {
  background: var(--rule);
  transition: background-color var(--t-etat) var(--e-in),
              transform var(--t-etat) var(--e-in);
}
.temps__pas[data-atteint="1"] .temps__num { background: var(--accent); }
.temps__duree { opacity: 0; transform: translateY(6px);
  transition: opacity var(--t-etat) var(--e-in), transform var(--t-etat) var(--e-in); }
.temps__pas[data-atteint="1"] .temps__duree { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .temps__pas, .temps__duree { opacity: 1; transform: none; transition: none; }
  .temps__pas .temps__num { background: var(--accent); }
}

/* ── L'invite à descendre : une guirlande d'ampoules ──────────────────────
   Une souris stylisée qui rebondit, c'est l'invite de tout le monde, et elle
   ne dit rien à quelqu'un qui n'a pas de souris. Un trait de progression avec
   un curseur non plus : c'est un tableau de bord, pas une fête foraine.

   Ici c'est la marquise du comptoir tournée à la verticale — un câble, sept
   ampoules. Le même objet, le même orange, le même geste de dessin (la
   marquise pose ses ampoules avec un radial répété ; celles-ci sont des
   éléments réels parce qu'il faut pouvoir les allumer séparément).

   Deux régimes, et un seul mécanisme :

   au repos   la lumière court vers le bas, ampoule après ampoule. Elle ne
              mesure rien, elle montre une direction ;
   en route   la cascade s'arrête et la guirlande s'allume depuis le haut,
              proportionnellement à la position dans le film. Sept ampoules
              font sept crans : on sent la progression par paliers, ce qu'un
              curseur qui glisse ne donne pas.

   Elle s'efface une fois le hero parcouru. Elle n'invite plus à rien.

   L'allumage est calculé en CSS pur, sans une ligne de script par ampoule :
   chaque ampoule connaît son rang (--i), la guirlande connaît la progression
   (--part), et `clamp()` transforme leur différence en un fondu de 0 à 1.
   Multiplier par 1.7 resserre ce fondu : l'ampoule courante s'allume pendant
   qu'on la traverse, au lieu de s'éclairer mollement sur tout son cran. */
@property --part  { syntax: "<number>"; inherits: true;  initial-value: 0; }
@property --allume { syntax: "<number>"; inherits: false; initial-value: 0; }

.guide {
  position: absolute; right: clamp(6px, 2.4vw, 32px); bottom: clamp(20px, 5vh, 56px);
  z-index: 4;
  --n: 7;
  /* Le câble fait 1 px de large : c'est un dessin, pas une cible. Le padding
     porte la zone tactile au-delà du plancher Fitts sans épaissir le trait. */
  /* 22 px ici contre 11 px entre ampoules : le mot est un libellé, les
     ampoules sont un groupe. Règle 1:2, l'écart entre groupes vaut au moins
     le double de l'écart interne. À 13 px, le mot avait l'air d'être la
     première ampoule. */
  display: flex; flex-direction: column; align-items: center; gap: 22px;
  padding: 10px 17px;
  color: var(--paper-mute); text-decoration: none;
  transition: opacity var(--t-etat) var(--e-in), color var(--t-etat) var(--e-in);
}
.guide[data-fini="1"] { opacity: 0; pointer-events: none; }
.guide:hover, .guide:focus-visible { color: var(--orange); }
.guide:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; border-radius: var(--bord); }

.guide__mot {
  font-family: var(--f-corps); font-size: 10px; font-weight: 800;
  letter-spacing: .18em; text-transform: uppercase;
  writing-mode: vertical-rl;
  transition: opacity var(--t-etat) var(--e-in);
}
/* Une fois qu'on descend, le mot a fini son travail : la guirlande reste seule
   et devient une jauge. Laisser « Descendez » allumé pendant qu'on descend,
   c'est répéter une consigne déjà suivie. */
.guide[data-parti="1"] .guide__mot { opacity: 0; }

.guide__guirlande {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 11px;
  padding-block: 3px;
}
/* Le câble, derrière les ampoules. Il les relie : sans lui ce sont sept points
   dans le vide, avec lui c'est une guirlande. */
.guide__guirlande::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%;
  width: 1px; margin-left: -.5px;
  background: var(--rule-nuit);
}
/* Le clou auquel elle pend. Un trait de 9 px, et la guirlande cesse de flotter
   pour être accrochée à quelque chose. C'est le genre de détail qui fait la
   différence entre « des points alignés » et un objet. */
.guide__guirlande::after {
  content: ""; position: absolute; top: 0; left: 50%;
  width: 9px; height: 1px; margin-left: -4.5px;
  background: var(--rule-nuit);
}

.guide__ampoule {
  /* 0 quand l'ampoule est encore devant nous, 1 quand elle est passée, et le
     fondu entre les deux pendant qu'on la traverse. */
  --allume: clamp(0, (var(--part) * var(--n) - var(--i)) * 1.7, 1);
  width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
  /* Éteinte, l'ampoule reste visible : une guirlande noire ne se lit pas comme
     une guirlande, elle se lit comme un bug d'affichage. */
  background: color-mix(in oklab,
              var(--orange) calc(var(--allume) * 100%), rgba(251, 239, 230, .22));
  transform: scale(calc(.78 + var(--allume) * .32));
  /* Un anneau net, pas un halo flou : l'interdit porte sur le glow décoratif.
     Ici la lumière EST le sujet, et elle est dessinée au trait. */
  box-shadow: 0 0 0 calc(var(--allume) * 3px) rgba(250, 170, 72, .15);
}

/* Au repos seulement. Le décalage croît avec le rang : la lumière part du haut
   et tombe. Cycle plus long que la cascade elle-même, pour que le noir entre
   deux passages se voie — une guirlande qui clignote sans répit est une alarme. */
.guide:not([data-parti="1"]) .guide__ampoule {
  animation: cascade 1.8s var(--e-in) infinite;
  animation-delay: calc(var(--i) * .12s);
}
@keyframes cascade {
  0%, 42%, 100% {
    background: rgba(251, 239, 230, .22);
    transform: scale(.78);
    box-shadow: 0 0 0 0 rgba(250, 170, 72, 0);
  }
  13% {
    background: var(--orange);
    transform: scale(1.1);
    box-shadow: 0 0 0 3px rgba(250, 170, 72, .15);
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Pas de cascade, mais rien à remplacer : la guirlande éteinte se voit déjà,
     et --allume continue de l'allumer au défilement. */
  .guide:not([data-parti="1"]) .guide__ampoule { animation: none; }
}
/* Sous 420 px de haut, le hero est déjà serré : l'invite prend une place
   qu'on n'a pas. */
@media (max-height: 420px) { .guide { display: none; } }
