/* ================= LES TRAVAUX RÉCENTS =================

   La première chose qu'on rencontre en descendant. Elle commence à 89 sous
   la barre de chat — la barre est fixée à 34 du bas, la bande démarre donc
   55 après le premier écran : 34 + 55 = 89, deux termes de la suite qui
   s'additionnent pour en donner un troisième. C'est la suite qui place la
   bande, pas un chiffre choisi.

   ---- LA MÉCANIQUE : UNE SEULE CARTE, UN FILM DEDANS ----

   Il n'y a QU'UNE carte. Elle se cale au centre de l'écran et n'en bouge
   plus. Ce qui défile, c'est le FILM à l'intérieur : les images sont
   empilées sur une bande verticale, et c'est la bande qui monte derrière
   l'ouverture. L'image suivante pousse la précédente hors du cadre — le
   cadre, lui, ne bouge pas d'un pixel.

   C'est la différence avec une pile de cartes, et c'est toute la différence :
   on ne change pas d'objet, on regarde le même objet changer de contenu.

   Le calage est fait par `position: sticky` — donc par le navigateur, donc
   rien ne peut se désynchroniser. Le film, lui, a besoin d'une mesure : le
   script écrit --pf (l'avancée du film, de 0 à 1), et le CSS en déduit deux
   choses — la position du film et celle du curseur de la graduation. Une
   variable, aucune propriété de mise en page touchée : le compositeur seul
   travaille.

   ---- LA MATIÈRE ----

   L'image n'est pas dans un cadre : elle est DERRIÈRE UNE VITRE. Filet blanc
   d'un cheveu, coin de 3, un reflet qui suit le curseur — la matière de la
   barre de chat, exactement. La vitre reste nette pendant que le film glisse
   dessous : on ne regarde pas des images, on regarde à travers quelque
   chose. C'est la thèse du site entier. */

.travaux {
  position: relative;
  z-index: 6;
  /* 100vh, c'est le premier écran ; +55 pour tomber à 89 sous la barre. */
  margin-top: calc(100vh + var(--f-55));
  padding-bottom: var(--f-144);

  --vx: 50%;
  --vy: 50%;
  /* --elan : la vitesse du geste, adoucie, entre -1 (on remonte) et 1 (on
     descend). Écrite par travaux.js à chaque image tant que ça bouge, revient
     à 0 toute seule. C'est elle qui anime la carte ci-dessous. */
  --elan: 0;
  /* --p : l'avancée BRUTE du geste, de 0 à 1. Plus rien ne la lit depuis que
     la jauge a laissé la place à la graduation, mais travaux.js continue de
     l'exposer : c'est la mesure honnête du geste, et tout ce qui voudrait
     suivre la MAIN plutôt que le film doit partir de là. */
  --p: 0;
  /* --pf : l'avancée du FILM. Elle court après --p sans jamais la rattraper
     (voir LA BOUCLE dans le script) : c'est ce retard, et lui seul, qui fait
     la glisse. Le film la lit. */
  --pf: 0;
  /* --cran : le CHECKPOINT courant, un entier de 0 à --vues. Le curseur de la
     graduation ne lit que lui — il ne suit pas le film, il va d'un projet au
     suivant. Écrit par travaux.js au franchissement seulement, donc quelques
     fois par défilement : c'est ce qui autorise une transition CSS ici, là où
     le film, lui, en interdit une. */
  --cran: 0;
  /* Le nombre d'images MOINS UNE : la course du film. Écrit par le script
     d'après le nombre de vues réellement présentes ; la valeur ici n'est qu'un
     repli pour la première image. C'est elle qui règle la translation du film
     ET la hauteur de la course, donc elle ne peut pas rester en dur. */
  --vues: 2;

  /* La carte : sa largeur, sa hauteur, et la marge qu'elle laisse à gauche.
     La hauteur est déduite du rapport 16/10 plutôt que laissée à
     `aspect-ratio` : le film a besoin d'une longueur en pixels pour se
     déplacer, et un pourcentage se rapporterait à sa propre hauteur, pas à
     celle de l'ouverture. */
  --carte: var(--rail);
  --carte-h: calc(var(--carte) * 10 / 16);
  --carte-marge: calc((100vw - var(--carte)) / 2);
}

/* ---- LE RAIL : LA BANDE DE LA GRADUATION ----
   La graduation ne s'arrête pas avec les travaux, elle CONTINUE dans la
   vitrine vidéo. Pour qu'on lise un seul instrument et non deux règles qui se
   ressemblent, elle doit occuper exactement la même bande à l'écran des deux
   côtés : même abscisse (--brand-inset), même hauteur, même centrage.

   D'où ces deux variables posées sur LES DEUX sections. --rail est la largeur
   dont tout découle ; la carte des travaux la reprend telle quelle plutôt que
   de redéclarer 55vw dans son coin. Une seule source : si le rail change, la
   carte suit, et la vitrine aussi. */
.travaux,
.vv,
.rail {
  --rail: 55vw;
  --rail-h: calc(var(--rail) * 10 / 16);
  /* Le décalage du haut : la hauteur exacte du pavé noir, recomposée depuis
     les tokens de l'étiquette. La graduation part sous lui, ici comme
     là-bas. */
  --rail-tete: calc(var(--l-18) + var(--f-2) * 2);
  /* L'écart entre deux petits traits, en PIXELS. C'était une division de la
     bande (--vues × 16) : la trame se redimensionnait avec elle. Maintenant
     qu'elle traverse l'écran entier et le déborde, elle n'a plus de longueur de
     référence — un écart fixe est la seule mesure qui ait un sens, et c'est
     aussi ce qui garantit qu'elle ait exactement le même grain partout. */
  --rail-espace: var(--f-13);
}

/* Le genre : le pavé de l'en-tête, sans une retouche — même fond, même
   encre, même coin, même largeur minimale. On ne réinvente pas un mot qu'on
   a déjà. Il coiffe le titre dans la colonne de gauche. */
.travaux-genre {
  /* flex, et non un bloc : le pavé est un inline-block, et la ligne du
     paragraphe qui le porte lui ajoutait 5px de demi-interligne au-dessus —
     le badge tombait 5 sous le haut de la carte au lieu d'être à sa hauteur
     exacte. En flex, il n'y a plus de ligne, donc plus de décalage. */
  display: flex;
  margin: 0 0 var(--f-13);
  pointer-events: auto;
}
.travaux-genre .etiquette { min-width: var(--etiquette-min); }

/* ---- LA COURSE ----
   Un écran pour que la carte se cale, puis 89vh par image à faire défiler.
   C'est la seule valeur à toucher pour régler le rythme : plus haut, le film
   glisse plus lentement. */
.travaux-course { height: calc(100vh + var(--vues) * 89vh + 89vh); }

/* ---- LE CALE ----
   Exactement un écran, collé en haut : c'est lui qui immobilise la carte au
   centre. `place-items: center` fait le reste — la carte est centrée dans la
   fenêtre sans qu'on ait à connaître sa hauteur. */
.travaux-cale {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  place-items: center;
}

/* ---- LA CARTE : L'OUVERTURE ----
   `overflow: hidden` est la pièce maîtresse : c'est elle qui fait que le
   film existe. Sans elle, les images déborderaient au lieu d'être coupées
   par le cadre. */
.travaux-scene {
  position: relative;
  width: var(--carte);
  height: var(--carte-h);
  overflow: hidden;
  border-radius: var(--radius-xs);
  /* L'ÉLAN — le successeur du bond, qui était tout ou rien. Deux mouvements,
     tous deux proportionnels à la VITESSE du geste (--elan, écrit par
     travaux.js) :

     — l'avancée : translateZ pousse la carte vers la caméra. --elan est mis
       au carré pour rester positif dans les deux sens ET pour que seuls les
       gestes francs la fassent avancer — un frôlement de molette ne compte
       pas. À pleine vitesse, 13px sous une perspective de 987 : 1.3% de
       plus, l'ordre de grandeur de l'ancien bond (1.2%).

     — la courbure : rotateX incline la carte d'un souffle, le bord haut vers
       la caméra quand on descend, le bas quand on remonte — elle se penche
       DANS le sens du film, comme entraînée par lui. 2.618 degrés au
       maximum (φ²) : on sent la carte vivre, on ne la voit jamais tourner.

     Aucune transition : travaux.js adoucit l'élan lui-même, image par image,
     et une transition par-dessus donnerait ce flottement mou des carrousels
     ratés. */
  transform: translateZ(calc(var(--elan) * var(--elan) * var(--f-13)))
             rotateX(calc(var(--elan) * -2.618deg));
  will-change: transform;
}

/* ---- LE FILM ----
   Les images bout à bout, et une seule translation pour toutes. Pas de
   transition : le lissage est DÉJÀ dans --pf, que travaux.js amène vers le
   geste image par image. Une transition par-dessus rejouerait sa propre
   courbe sur celle-là et rendrait tout mou. */
.travaux-film {
  position: absolute;
  inset: 0;
  transform: translate3d(0, calc(var(--pf) * var(--vues) * var(--carte-h) * -1), 0);
  will-change: transform;
}
.travaux-vue {
  position: absolute;
  left: 0;
  right: 0;
  height: var(--carte-h);
  margin: 0;
  overflow: hidden;
}
/* Le rang de chaque vue est écrit par le script (--i), pas par un nth-child.
   Trois règles en dur voulaient dire trois vues, ni plus ni moins : ajouter un
   mockup cassait le film sans un mot. */
.travaux-vue { top: calc(var(--i, 0) * var(--carte-h)); }
.travaux-vue img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ---- LA VITRE ----
   Posée par-dessus le film, elle ne capte rien. Elle NE BOUGE PAS pendant
   que les images passent dessous : c'est ce contraste qui fait qu'on lit une
   vitre et pas un simple cadre. */
.travaux-verre {
  position: absolute;
  inset: 0;
  z-index: 2;
  border: var(--border-hair) solid var(--color-text);
  border-radius: var(--radius-xs);
  pointer-events: none;
  background:
    radial-gradient(60% 60% at var(--vx) var(--vy),
      rgba(255, 255, 255, 0.16), transparent 70%);
}

/* ---- LES GRADUATIONS ----
   Il n'y a QU'UN dessin : une colonne de traits, tous à la même abscisse et
   tous de la même épaisseur d'un cheveu. Ce qui distingue un checkpoint d'un
   petit trait, c'est sa LONGUEUR, rien d'autre.

   Une version précédente posait un point de 5 à côté de la colonne : on lisait
   un gros trait, un vide, puis une ligne fine — deux objets différents au lieu
   d'une règle. Le checkpoint est DANS la graduation, il en est une
   graduation.

   Trois états, trois longueurs :
     à venir  13, encre pâle   — un repère qu'on n'a pas encore atteint
     franchi  21, encre pleine  — le chemin parcouru reste lisible
     courant  34, encre pleine  — la position, la plus longue de toutes

   L'épaisseur ne change JAMAIS : elle vaut le cheveu de la trame. C'est ce
   qui garantit qu'on lit un seul instrument. */
.travaux-regle {
  position: absolute;
  inset: 0;
  color: var(--etiquette-fond, #000000);
}
.travaux-regle span {
  position: absolute;
  left: var(--f-13);
  top: var(--y);
  width: var(--f-8);
  height: var(--rail-filet, var(--border-hair));
  background-color: currentColor;
  opacity: 0.38;
  transition: width 377ms cubic-bezier(0.22, 1, 0.36, 1),
              opacity 377ms linear;
}
/* LA SPEC, ET RIEN D'AUTRE. Quatre tirets discrets, puis un cinquième
   légèrement plus marqué : c'est LUI le checkpoint — pas un objet posé
   par-dessus, le trait lui-même. Franchi, il passe à l'encre pleine ;
   courant, il s'allonge UN PEU (13 → 21, un cran de la suite). C'est tout. */
.travaux-regle span[data-gras] { width: var(--f-13); opacity: 0.55; }
.travaux-regle span[data-passe] { width: var(--f-13); opacity: 1; }
/* Le checkpoint COURANT : le même trait, allongé un peu (13 → 21). La marque
   SAUTE de trait gras en trait gras au passage de l'aiguille — les traits, eux,
   ne quittent JAMAIS leur place dans la grille. Une version précédente retenait
   le trait courant au niveau du pavé : il sortait de la grille, laissait un
   trou à son emplacement et se posait entre deux graduations. */
.travaux-regle span[data-actuel] { width: var(--f-21); opacity: 1; }
}

/* ---- LA CARTE EST LE LIEN ----
   L'ancien « Voir le projet » était un pavé posé sous les prestations : il
   fallait le VISER. Ici c'est l'ouverture entière qui est cliquable, et la
   bulle ne fait que rendre la chose visible — on ne vise plus rien, on clique
   l'image qu'on regarde.

   Le lien enveloppe la carte sans rien lui prendre : il ne porte ni fond ni
   dimension propre, c'est la scène à l'intérieur qui les tient. `position:
   relative` seulement, pour que la bulle ait un repère. */
.travaux-lien {
  /* LA CAMÉRA DE L'ÉLAN. Sans perspective, le rotateX de la carte n'est qu'un
     écrasement vertical. 987px — assez loin pour que l'inclinaison reste une
     suggestion, pas un effet de foire.

     Elle était sur le CALAGE, et c'était une faute lourde : une perspective
     sur un ancêtre transforme tout `position: fixed` descendant en `absolute`
     — silencieusement, sans que rien ne signale l'erreur. Le bloc de texte,
     pourtant déclaré fixe, se retrouvait ancré au calage et repartait avec lui
     dès que la section s'achevait. La caméra n'a rien à faire là : elle doit
     être sur le parent DIRECT de ce qu'elle regarde, et ce parent, c'est le
     lien qui enveloppe la carte. */
  perspective: 987px;
  /* SANS CECI, RIEN NE SE PASSE AU SURVOL. La section 2 qui contient toute
     cette bande est en `pointer-events: none` (styles.css) — un squelette qui
     ne doit pas voler les clics du rail sous lui — et la règle y est que
     chaque élément rétablisse le pointeur POUR LUI SEUL. Le badge le faisait
     déjà, et l'ancien « Voir le projet » en héritait sans le savoir : c'était
     une .etiquette, et .etiquette porte `pointer-events: auto`. En devenant
     une carte-lien, il a perdu cet héritage — et avec lui le survol, la bulle
     et le zoom, qui ne se déclenchaient plus jamais. */
  pointer-events: auto;
  position: relative;
  display: block;
  text-decoration: none;
  /* PAS DE CURSEUR SUR LA CARTE. Le disque EST le pointeur ; la main générique
     par-dessus ferait deux pointeurs pour un seul geste, et c'est elle qu'on
     regarderait — la plus petite des deux, et la seule qu'on connaisse déjà.
     Le disque ne double pas la main, il la congédie.

     La main revient sous mouvement réduit : là, la bulle ne suit plus la
     pointe (travaux.js n'écrit --cx/--cy qu'en dehors de ce mode), et cacher
     le curseur laisserait la personne sans aucun pointeur. Voir le bloc
     `prefers-reduced-motion` en bas de fichier. */
  cursor: none;
}

/* ---- LE ZOOM ----
   5 % : assez pour que la carte réponde, pas assez pour qu'on voie l'image
   grandir. C'est `.travaux-vue` qui la coupe (overflow: hidden), donc le cadre
   ne bouge pas
   d'un pixel — seule la matière dedans respire. La vitre non plus ne bouge
   pas : c'est ce qui fait qu'on lit un zoom DERRIÈRE une vitre, et non une
   carte qui gonfle.

   610 ms à l'aller comme au retour, la courbe du site : un zoom qui claque
   trahit un effet ; un zoom qui s'installe se confond avec une intention. */
.travaux-vue img {
  transform: scale(1);
  transition: transform 610ms cubic-bezier(0.22, 1, 0.36, 1);
}
.travaux-lien:hover .travaux-vue img,
.travaux-lien:focus-visible .travaux-vue img {
  transform: scale(1.05);
}

/* ---- LA BULLE ----
   Elle SUIT le curseur — --cx et --cy, écrites par travaux.js en pixels
   depuis le coin de la carte. Le reflet de la vitre, lui, se contente de
   --vx/--vy en pourcentage de la bande entière : bon assez pour une lueur
   diffuse, beaucoup trop imprécis pour un objet qui doit tomber SOUS la
   pointe.

   Deux éléments, et c'est la seule façon de faire proprement : le calque
   extérieur suit la pointe SANS transition (une transition sur la position
   ferait traîner la bulle derrière le curseur), le pavé intérieur fait
   l'apparition. On ne peut pas animer l'une sans l'autre si les deux vivent
   sur le même `transform`.

   Elle ne prend pas le pointeur : c'est le lien dessous qui reçoit le clic,
   et une bulle qui intercepterait son propre survol clignoterait. */
.travaux-bulle {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 5;
  pointer-events: none;
  transform: translate(calc(var(--cx, 50%) - 50%), calc(var(--cy, 50%) - 50%));
}
.travaux-bulle b {
  /* UN VRAI DISQUE : largeur et hauteur égales, rayon à 50 %. La version
     précédente était une pastille — un rectangle à bouts ronds dont la forme
     dépendait de la longueur du texte. Ici la forme est fixée d'abord, et
     c'est le texte qui s'y range. 144 de diamètre : un tiers de la hauteur de
     la carte, assez pour être un objet et non une infobulle. */
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--f-8);
  width: var(--f-144);
  height: var(--f-144);
  border-radius: 50%;
  background-color: var(--etiquette-fond, #000000);
  color: var(--etiquette-encre, #FFFFFF);
  text-align: center;
  font-size: var(--text-sm);
  line-height: var(--l-18);
  font-weight: var(--fw-light);
  /* Capitales espacées : dans un disque, une ligne de bas-de-casse flotte,
     alors qu'une capitale espacée tient le centre. C'est le seul endroit du
     site où l'étiquette prend cette casse, et c'est la forme qui l'impose. */
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);

  /* IL GRANDIT. Depuis zéro, donc on VOIT l'objet naître — un départ à 0.72
     donnait un simple fondu à peine gonflé. Le point de fuite est son centre,
     donc le point exact où se trouve la pointe.

     CE QUI EST DÉCLARÉ ICI GOUVERNE LA SORTIE. Elle s'efface en 610, avec la
     même courbe que l'entrée : le disque rétrécit jusqu'à disparaître, aussi
     lentement qu'il avait grandi. Il partait en 233 auparavant, au motif
     qu'un objet qui traîne après le geste gêne — mais un objet qui naît
     lentement et s'évanouit d'un coup n'est pas le même objet à l'aller et au
     retour, et ça se voit.

     L'opacité prend 610 elle aussi, là où elle n'en prend que 377 à l'entrée.
     L'asymétrie est le point : à l'aller l'encre arrive AVANT la fin de la
     course, pour qu'on lise une croissance ; au retour elle reste jusqu'au
     bout, pour qu'on voie le disque rétrécir jusqu'à n'être plus rien au lieu
     de s'éteindre à mi-chemin.

     Pas de retard au retour : les 89 ms de l'entrée servent à ignorer les
     frôlements, un départ n'a rien à ignorer. */
  opacity: 0;
  transform: scale(0);
  transition: opacity 610ms cubic-bezier(0.33, 1, 0.68, 1),
              transform 610ms cubic-bezier(0.33, 1, 0.68, 1);
}
/* Le texte se coupe en deux lignes : une seule ligne traverserait le disque
   d'un bord à l'autre et toucherait la courbe. 89 le force à se plier. */
.travaux-bulle em {
  font-style: normal;
  max-width: var(--f-89);
}
/* La flèche, sous le texte : elle dit le sens sans un mot de plus. */
.travaux-bulle i {
  font-style: normal;
  line-height: 1;
}
/* L'ENTRÉE DU DISQUE.

   LE RETARD, 89 ms. Sans lui, le disque saute dès que la pointe effleure le
   bord de la carte — y compris quand on ne fait que traverser l'image pour
   aller ailleurs. Le retard laisse passer les frôlements : on ne déclenche
   que si l'intention dure. C'est court, on ne le compte pas, mais il change
   ce que le geste veut dire.

   LA COURBE. Le site anime tout en cubic-bezier(0.22, 1, 0.36, 1) : départ
   sec, longue décélération. Sur une masse qui se pose — la carte, le
   curseur de la graduation — c'est juste. Sur un objet qui NAÎT, c'est un
   pop : au cinquième du temps elle a déjà parcouru 67 % de la course, et 96 %
   à la moitié — le disque saute à sa taille puis fait du surplace. La courbe
   cubique (0.33, 1, 0.68, 1) donne 49 % et 87 % aux mêmes instants : elle
   part plus doucement et étale vraiment la croissance.

   610 ms sur l'échelle, 377 sur l'encre : le disque finit d'apparaître bien
   avant d'avoir fini de grandir, donc on lit une CROISSANCE et non un
   fondu. */
.travaux-lien:hover .travaux-bulle b,
.travaux-lien:focus-visible .travaux-bulle b {
  opacity: 1;
  transform: scale(1);
  transition: opacity 377ms cubic-bezier(0.33, 1, 0.68, 1) 89ms,
              transform 610ms cubic-bezier(0.33, 1, 0.68, 1) 89ms;
}

/* ---- LE BLOC : LA LÉGENDE DE LA CARTE ----
   Calé sur la carte, de sa hauteur exacte, et DANS son calage : il s'épingle
   avec elle puis s'en va vers le haut quand la section s'achève. Le texte
   appartient à sa carte et la suit ; la graduation, elle, a son propre sort.

   NOTE DE CHANTIER, après l'avoir efface deux fois : ce bloc a déjà été
   emporté par deux remplacements « de la graduation » qui découpaient le
   fichier entre deux commentaires-repères. Il vit désormais ICI, après la
   carte-lien et juste avant les paliers — hors de tout tronçon que les
   retouches de la graduation découpent. Ne pas le redéplacer.

   Il PART de --brand-inset, la ligne de texte du site, et déborde sur la
   carte : la marge libre ne fait que 144 sur un écran de 1280, et 144 ne
   pardonne pas un titre d'affiche. Les 55 de retrait à gauche laissent passer
   la graduation — 34 pour elle, 21 d'air.

   `pointer-events: none` : le bloc couvre une partie de l'ouverture, il ne
   doit rien intercepter. Le badge, lui, les rétablit pour rester cliquable. */
.travaux-texte,
.vv-texte {
  position: absolute;
  left: var(--brand-inset);
  width: var(--f-610);
  top: calc(50% - var(--rail-h) / 2);
  height: var(--rail-h);
  padding-left: calc(var(--f-34) + var(--f-21));
  z-index: 4;
  pointer-events: none;
}

/* ---- LES FICHES ----
   Une fiche par projet, toutes sur la MÊME case de la grille : la suivante
   prend la place de la précédente au lieu de la pousser.

   `visibility` n'est pas un doublon de l'opacité : une fiche à 0 d'opacité
   reste FOCUSABLE. Elle est masquée pour de bon, mais seulement une fois le
   fondu terminé — d'où le délai de 377 ms à l'extinction, 0 s à l'allumage. */
.travaux-titres { display: grid; }
.travaux-titres > * {
  grid-area: 1 / 1;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(var(--f-8));
  transition: opacity 377ms cubic-bezier(0.22, 1, 0.36, 1),
              transform 377ms cubic-bezier(0.22, 1, 0.36, 1),
              visibility 0s linear 377ms;
}
.travaux-titres > [data-actif] {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 377ms cubic-bezier(0.22, 1, 0.36, 1),
              transform 377ms cubic-bezier(0.22, 1, 0.36, 1),
              visibility 0s;
}

/* ---- LE TITRE COMME UNE AFFICHE ----
   Capitales, corps 34, graisse légère. C'est le débordement sur l'image qui
   lui donne son échelle, pas le corps. L'interlignage est 34 + 5, deux termes
   additionnés comme le reste du site. La casse est faite en CSS : le HTML
   garde « Galerie Lucie Monet » écrit normalement, donc les lecteurs d'écran
   et les moteurs lisent un nom propre, pas un sigle. */
.travaux-projet h2 {
  margin: 0;
  font-size: var(--f-34);
  line-height: calc(var(--f-34) + var(--f-5));
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-tight);
  text-transform: uppercase;
  color: var(--etiquette-fond, #000000);
}

/* ---- LES PRESTATIONS ----
   Étiquettes CREUSES : même famille que le pavé du genre, même coin, même
   corps, mais un filet à la place de l'aplat. Le filet est un `box-shadow`
   interne et non une bordure : une bordure ajouterait 2 à la boîte et
   désalignerait la rangée. Ce ne sont pas des liens, elles ne prennent pas le
   pointeur. */
.travaux-prestations {
  display: flex;
  flex-wrap: wrap;
  gap: var(--f-5);
  margin: var(--f-21) 0 0;
}
.travaux-prestations .etiquette {
  pointer-events: none;
  background-color: transparent;
  color: var(--etiquette-fond, #000000);
  box-shadow: inset 0 0 0 var(--border-hair) currentColor;
  padding-left: var(--f-8);
  padding-right: var(--f-8);
}

/* ---- PALIER TABLETTE ----
   La carte prend toute la largeur utile, et le texte passe AU-DESSUS d'elle
   au lieu de la chevaucher : sous 987, il n'y a plus la place de superposer
   sans rendre le titre illisible. La course se raccourcit — sur un écran
   haut et étroit, 89vh par image est interminable. */
@media (max-width: 987px) {
  .travaux { --carte: calc(100vw - var(--menu-inset) * 2); }
  /* La règle disparaît : le bloc de texte passe AU-DESSUS de la carte et
     s'étale sur toute la largeur, la colonne verticale qu'elle prolongeait
     n'existe plus. La garder en ferait un ornement posé là faute de mieux. */
  .rail { display: none; }
  .travaux-course { height: calc(100vh + var(--vues) * 55vh + 55vh); }
  .travaux-sur { padding-left: var(--menu-inset); }
  .travaux-cale { align-content: center; }
  .travaux-texte,
  .vv-texte {
    position: static;
    max-width: none;
    margin: 0 var(--menu-inset) var(--f-21);
    /* La règle disparaissant, le bloc redevient un simple paragraphe : ni
       largeur imposée, ni hauteur de carte, ni retrait pour une graduation
       qui n'est plus là. */
    width: auto;
    height: auto;
    padding-left: 0;
  }
  /* La colonne s'étale sur toute la largeur : le titre n'a plus le mot le
     plus long pour contrainte, mais il n'a plus non plus de raison de crier
     aussi fort au-dessus d'une carte pleine largeur. */
  .travaux-titres > * {
    font-size: var(--f-21);
    line-height: var(--l-29);
  }
}

/* Mouvement réduit : ni bond, ni reflet. Le film et le calage RESTENT — ce ne
   sont pas des animations, c'est la mise en page qui suit le défilement, et
   la supprimer laisserait une carte vide. */
@media (prefers-reduced-motion: reduce) {
  .travaux-scene { transform: none; will-change: auto; }
  .travaux-titres > * { transition: none; }
  /* Le curseur CHANGE toujours de checkpoint — c'est une information — mais
     il s'y rend sans glisser. */
  .travaux-regle b { transition: none; }
  /* LA MAIN REVIENT. Sans le suivi de la bulle, cacher le curseur laisserait
     la personne sans le moindre pointeur sur la carte. */
  .travaux-lien { cursor: pointer; }
  /* Le zoom et le gonflement de la bulle disparaissent ; la bulle, elle,
     RESTE — c'est elle qui dit que la carte est cliquable. */
  .travaux-vue img { transition: none; }
  .travaux-lien:hover .travaux-vue img,
  .travaux-lien:focus-visible .travaux-vue img { transform: none; }
  .travaux-bulle b { transition: none; transform: none; }
  .travaux-verre { background: none; }
}

/* ---- LE RAIL ----
   Ancré dans la PAGE : il commence au bas du pavé noir (position écrite par
   le script) et défile avec elle, pixel pour pixel. Rien au-dessus de son
   premier trait, et il se prolonge d'un écran sous le dernier projet pour
   sortir du champ sans montrer son bout. Pas d'allumage : étant dans le flux,
   il entre et sort de l'écran tout seul. */
.rail {
  position: absolute;
  left: var(--brand-inset);
  top: var(--rail-y, 0);
  height: var(--rail-hauteur, 0);
  width: var(--f-34);
  z-index: 7;
  pointer-events: none;
  color: var(--etiquette-fond, #000000);
}



