/* mlsign v7 — composants.
 *
 * Deux vitesses, et rien d'autre à retenir :
 *   .manifeste — le jour. Une affirmation par écran, 100svh, tout centré.
 *   .dossier   — la nuit. Pas de hauteur imposée, deux ou trois blocs par
 *                écran, corps à 62ch, interlignage serré.
 *
 * Aucun composant ne sait dans quelle lumière il est : il ne lit que --fond,
 * --texte, --bordure… que la zone a rebindés. Aucun hex : une valeur qui
 * manque remonte dans design/tokens.json, elle ne se repose pas ici.
 *
 * Les défauts d'élément de ce fichier sont en :where() — (0,0,1), comme dans
 * zones.css : ils habillent un gabarit sans jamais gagner un arbitrage contre
 * une classe de composant.
 */

/* --- Contrôles de formulaire : ils n'héritent rien tout seuls ------------ */
button, input, textarea, select {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}
button { background: none; border: 0; cursor: pointer; }
textarea { resize: vertical; }

/* --- Saut au contenu ----------------------------------------------------- */
.saut {
  border-radius: var(--radius-pilule);
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: -999px;
  z-index: 100;
  padding: 0.7rem 1.1rem;
  background: var(--fond);
  color: var(--texte);
  border: var(--hairline) solid var(--bordure-champ);
}
.saut:focus { inset-inline-start: 0; }

/* --- Boutons. LA PILULE. L'emphase passait par l'inversion seule, sur un
       rectangle à angle vif ; elle passe maintenant par l'inversion ET la
       forme. Le bouton reste plein d'encre, il ne prend jamais de couleur.
       LE SURVOL A CHANGÉ DE NATURE. Il repeignait le fond en --action : sur le
       jaune du jour, un aplat à 1,53:1 sous du texte blanc était illisible, et
       ce n'était de toute façon pas le geste d'Axel. Il soulève l'objet de 2 px
       (v6.css:117) et l'enfonce au clic. Un geste de position, pas de couleur :
       ça marche dans les deux lumières sans rien mesurer, et ça dit « ceci se
       presse » mieux qu'un changement de teinte. ------------------------- */
.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  min-block-size: 44px;
  padding: 0.9rem 1.875rem;
  border: var(--hairline) solid var(--texte);
  border-radius: var(--radius-pilule);
  background: var(--texte);
  color: var(--fond);
  font-weight: var(--wght-titre);
  font-size: 1rem;
  text-decoration: none;
  text-align: center;
  transition: transform 0.25s var(--ease), opacity var(--duree) var(--ease);
}
@media (prefers-reduced-motion: no-preference) {
  .bouton:hover { transform: translateY(-2px); }
  .bouton:active { transform: translateY(0) scale(0.98); }
}
.bouton[disabled] { opacity: 0.55; cursor: default; }
.bouton[disabled]:hover { transform: none; }

/* LE SEUL GESTE QUE LE SITE DEMANDE, SUR LES TREIZE PAGES, et il sortait à
   13,6 px, plus petit que le texte courant qu'il surplombe. Axel le pose à 15.
   `min-block-size` passe de 40 à 44 px : 40 est sous la cible tactile de
   WCAG 2.5.8 (24 px suffisent au critère, 44 est le plancher de confort), et
   c'est le bouton de la barre fixe, celui qu'on vise au pouce en marchant. */
.bouton--compact { min-block-size: 44px; padding: 0.625rem 1.375rem; font-size: 0.9375rem; }
/* `inline-size: 100%` A ÉTÉ RETIRÉ. Le geste de fin sortait en barre pleine de
   1000 px de large : une pilule qui traverse la page n'est plus une pilule,
   c'est un bandeau, et la forme d'Axel disparaissait à l'endroit exact où elle
   compte le plus. Il grossit sans s'étirer. */
.bouton--grand { padding: 1.125rem 2.5rem; font-size: 1.05rem; }
/* L'anneau est en `box-shadow: inset` et non en `border` : à 1,5 px, une
   bordure décalerait la boîte d'un demi-pixel contre le bouton plein posé à
   côté, et les deux pilules d'un même groupe ne s'aligneraient plus.
   La bordure reste déclarée en transparent pour que les deux gardent
   exactement la même hauteur de boîte. */
.bouton--fantome {
  background: transparent;
  border-color: transparent;
  box-shadow: inset 0 0 0 1.5px var(--texte);
  color: var(--texte);
}
.bouton--fantome:hover { background: transparent; }

/* LE SEUL ÉCHEC AA DU SITE EST RÉPARÉ ICI, ET PAS OÙ ON LE CHERCHAIT.
   Le lien nLPD du formulaire de /walkers/ sortait à 4,35 pour un plancher de
   4,5 : --action vaut braise en jour, et braise est documentée à 4,85 SUR
   PAPIER, ce lien-là est dans un .formulaire, dont le fond est le creux
   (#E9E5DC). Un demi-cran de fond plus sombre, et la ligne passe sous le seuil.
   Le rattrapage d'hier éclaircissait CE lien-là vers l'encre, avec un
   color-mix : il corrigeait la mesure d'un seul lien et laissait le motif
   intact partout ailleurs.
   Le motif était la faute. Un lien de texte courant n'a pas à changer de
   couleur pour se signaler : le soulignement le fait déjà, et c'est le
   soulignement qui porte la couleur d'action. Le texte reste à l'encre de sa
   zone, 16,16 sur papier, 11,99 sur la nuit, AAA des deux côtés, sur les
   treize pages et quelle que soit la surface sous le lien. Le contraste du
   filet, lui, n'est pas soumis à 1.4.3 : c'est de la décoration adjacente au
   texte, et il reste parfaitement visible à 4,85.
   `from-font` est gardé, le 2px d'Axel (v6.css:299) contredirait --hairline,
   qui vaut 1 dans tout le système. Le sélecteur groupe trois cibles : le pied
   bascule avec, et c'est voulu, ses liens sont du texte courant eux aussi. */
.lien,
.formulaire__nlpd a,
.pied__liens a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--action);
  text-underline-offset: 0.18em;
  /* `from-font` donnait un cheveu de 1 px sous le jaune : à 1,53:1 sur le
     blanc, un filet d'un pixel ne se voit pas, et c'est LUI qui porte
     maintenant tout le signal du lien. Le 2 px d'Axel (v6.css:300) est le
     minimum où le jaune existe. Il ne contredit plus --hairline : --hairline
     décrit un filet de structure, celui-ci est un accent. */
  text-decoration-thickness: 2px;
}
.lien:hover,
.pied__liens a:hover { text-decoration-color: var(--texte); }

/* --- La barre. Hors flux : elle porte sa propre classe de zone en dur dans
       le gabarit, elle ne compte jamais sur l'héritage. Marque, cinq liens de
       page, sélecteur de langue, un seul geste à obtenir. « Aucun menu
       d'ancres » restait écrit ici et décrivait le one-pager : le menu existe
       depuis le passage à onze pages, sa composition est plus bas. -------- */
/* LA PILULE FLOTTANTE. La barre était pleine largeur, opaque, posée contre le
   haut de la fenêtre et séparée par un filet. Elle devient l'objet d'Axel :
   centrée, détachée de 16 px du bord, arrondie, translucide, et portée par une
   ombre.
   LA TRANSLUCIDITÉ EST TENABLE MAINTENANT, ET ELLE NE L'ÉTAIT PAS HIER. Tant
   que l'accueil changeait de lumière en cours de défilement, une barre à 0,92
   d'opacité laissait transparaître la mauvaise lumière pendant tout le pivot.
   Le pivot n'existe plus, le site a une seule lumière : ce qui passe derrière
   le verre est toujours du blanc ou une bande de blanc.
   `backdrop-filter` est un enrichissement, pas une dépendance : là où il n'est
   pas supporté, le fond à 0,92 suffit à séparer la barre du texte qui glisse
   dessous, et c'est le seul cas où ce composant peut mal vieillir. */
/* LA BARRE S'EFFACE DEVANT LE HERO DE L'ACCUEIL (16.08, consigne de
   Nazaire) : au premier écran elle doublait les gestes du hero et mangeait
   le haut du plan au téléphone. Elle ne paraît qu'à partir du deuxième
   visuel. Le retrait n'est posé QUE par js/v7.js (.barre--timide) : sans
   JavaScript la barre reste — une navigation qui disparaît sans retour n'est
   pas un repli acceptable. visibility suit l'opacité pour sortir les liens
   de l'ordre de tabulation tant qu'ils sont invisibles. */
.barre--timide {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-12px);
  transition: opacity 0.45s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.45s cubic-bezier(0.16, 1, 0.3, 1),
              visibility 0s 0.45s;
}
.barre--timide.barre--la {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.45s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.45s cubic-bezier(0.16, 1, 0.3, 1),
              visibility 0s;
}
/* Sur la page du formulaire, la barre est revenue le 16.08 au soir (son
   retrait a vécu une heure) mais SANS son bouton : le CTA renvoyait à la
   page où le lead se trouve déjà, doublon d'appel. La pilule ne porte que
   la marque et les liens ; sous 900 px, les liens cachés, elle ne porte QUE
   le wordmark, centré par sa propre géométrie (fit-content + marges auto) :
   c'est le retour rapide vers l'accueil que Nazaire voulait au téléphone. */
body[data-page="demande"] .barre .bouton--compact { display: none; }
/* Le padding de la pilule est asymétrique (1.625rem à gauche du wordmark,
   0.75rem contre le bouton) : sans bouton, la marque penchait de 7 px. Ici
   la pilule n'a que la marque, elle redevient symétrique. */
body[data-page="demande"] .barre { padding-inline: 1.25rem; }
body[data-page="demande"] .barre__marque { margin-inline-end: 0; }
.barre {
  position: fixed;
  /* Sous la banderole, qui est fixe depuis le 22.08. Sans --bandeau-h (pas de
     script) la valeur retombe sur le 1rem d'origine. */
  inset-block-start: calc(var(--bandeau-h, 0px) + 1rem);
  /* inset-inline: 0 + margin auto + fit-content, et PAS left:50% : un element
     fixe ancre a 50 % ne dispose que de la moitie du viewport comme espace
     de retrait, son contenu wrappe des qu'il depasse 50vw. Vu en prod : la
     pilule cassait en deux lignes a 1440. */
  inset-inline: 0;
  margin-inline: auto;
  inline-size: fit-content;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.5rem);
  max-inline-size: calc(100vw - 2rem);
  padding: 0.625rem 0.75rem 0.625rem 1.625rem;
  background: color-mix(in srgb, var(--fond) 92%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: var(--radius-pilule);
  box-shadow: var(--ombre-flottante);
}
.barre__marque { margin-inline-end: auto; line-height: 0; }
.barre__mark { block-size: 22px; inline-size: auto; }
.barre__mark--nuit { display: none; }
.barre--nuit .barre__mark--nuit { display: block; }
.barre--nuit .barre__mark--jour { display: none; }

/* Le sélecteur : des codes posés à plat, pas un menu. Rendu vide tant qu'il
   n'y a qu'une langue — le gabarit ne pose même pas le <nav>. */
.langues {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
}
.langues__lien {
  padding-block: 0.65rem;
  color: var(--texte-secondaire);
  text-decoration: none;
}
.langues__lien:hover { color: var(--texte); }
.langues__lien--ici { color: var(--texte); font-weight: var(--wght-titre); }

@media (width < 26.25rem) {
  .barre { gap: 0.6rem; }
  .langues { gap: 0.4rem; font-size: 0.72rem; letter-spacing: 0; }
  .barre .bouton--compact { padding-inline: 0.8rem; font-size: 0.875rem; }
}

/* --- VITESSE JOUR : le manifeste ----------------------------------------
   `data-registre` NE FIGURE PLUS dans ces sélecteurs, et c'est volontaire.
   Il disait la LUMIÈRE (jour ou nuit) et il a servi d'alias à la VITESSE (la
   densité), deux choses que le site distingue partout ailleurs. Une section de
   contenu en registre jour héritait donc d'un min-block-size de 100svh
   destiné aux manifestes : jour + dossier était impossible, et
   /confidentialite/ recevait un h1 de 7 rem pour « Vos données ».
   La vitesse se déclare maintenant par sa classe, .manifeste ou .dossier, et
   par elle seule. Le registre reste un crochet sémantique. ----------------- */
/* place-content:center sur une grille à colonne auto laisse le contenu
   déborder en dessous de 400px : une colonne minmax(0, --maxw) centrée fait
   la même chose et sait rétrécir. */
.manifeste,
.manchette {
  display: grid;
  grid-template-columns: minmax(0, var(--maxw));
  justify-content: center;
  align-content: center;
  /* LE BATTEMENT COURANT, ET LUI SEUL. C'était clamp(1.25rem, 1rem + 1.5vw,
     2.5rem), soit 37,6 px À 1440 ENTRE TOUS LES FRÈRES SANS EXCEPTION : dans
     le hero, le libellé était aussi loin de son titre que les boutons l'étaient
     de la promesse. Cinq bandes également espacées, aucune information de
     groupe — les yeux mi-clos, on ne voyait plus ce qui allait avec quoi.
     La grille ne sait pas faire varier son gap d'une rangée à l'autre : le pas
     courant reste ici, et les DEUX ruptures (ce qui se colle, ce qui s'écarte)
     sont posées plus bas, en marge, sur les quelques classes qui ouvrent ou
     ferment un groupe. La marge n'espace pas des frères — elle marque une
     frontière que gap ne peut pas exprimer. */
  row-gap: var(--pas-2);
  min-block-size: 100svh;
  padding-block: calc(var(--section-y) * 0.8);
  padding-inline: var(--gutter);
}

/* LES DEUX RUPTURES DU MANIFESTE. Écrites sur les classes réelles des cinq
   formes que les gabarits rendent, jamais sur `* + *` : un manifeste compte
   deux à cinq enfants, ils sont nommés, et une règle nommée se relit.
   Le calc() retranche le pas courant déjà posé par row-gap — la somme des deux
   fait exactement le pas visé, et l'échelle reste lisible dans la déclaration. */
/* Ce qui se colle : --pas-1. Un libellé appartient au titre qu'il annonce, une
   ligne de réassurance appartient au bouton qu'elle explique. */
.manchette__texte > .etiquette + *,
.manchette__reassurance,
.manchette__indice {
  margin-block-start: calc(var(--pas-1) - var(--pas-2));
}
/* Ce qui s'écarte : --pas-3. Le groupe d'action ouvre, la devise conclut. Les
   deux autres frontières du manifeste — la grille et le geste du scan — se
   posent plus bas, à l'endroit où ces classes reçoivent déjà une marge : deux
   règles de même poids sur la même propriété, c'est l'ordre de source qui
   tranche, et le lecteur ne doit pas avoir à le calculer. */
.manchette__actions,
.probleme__devise {
  margin-block-start: calc(var(--pas-3) - var(--pas-2));
}
/* LA VITESSE JOUR COMPOSE AU CENTRE DEPUIS LE 14.08. Elle était au fer à
   gauche sur toute sa largeur : c'est la composition d'un document, celle que
   la vitesse dossier garde, et elle disait « lisez-moi ligne à ligne ». La page
   d'Axel énonce, un titre, une phrase, un geste, centrés dans une colonne
   étroite, et c'est ce que fait une page qui vend.
   La MESURE fait tout le travail, pas l'alignement : centrer sans resserrer
   donne des lignes de 1240 px dont l'œil rate le début au retour chariot. 820 px
   est la colonne d'Axel (v6.css:188), et les mesures de texte déjà posées plus
   bas la referment encore.
   LA VITESSE DOSSIER NE BOUGE PAS. /le-cadre-legal/, /confidentialite/ et le
   document de rapport restent au fer à gauche : on ne centre pas un texte long,
   et ces pages-là se lisent, elles n'énoncent pas.

   ON CENTRE PAR LES MARGES, PAS PAR `justify-items`. `justify-items: center`
   sur la grille de section a été essayé et retiré le jour même : il remplace le
   `stretch` par défaut, donc chaque enfant se dimensionne sur son CONTENU. La
   figure du sac, dont les trois calques sont en position absolue, n'a pas de
   contenu en flux : elle est sortie à 0 px de large, le hero a perdu son objet
   et il ne restait qu'un trou de la hauteur du rapport d'image. Les enfants
   gardent donc `stretch`, un plafond de mesure, et deux marges automatiques. */
:where(.manifeste, .manchette) {
  display: grid;
  text-align: center;
}
/* Le bloc de texte du hero : la grille interne que la section donnait a ses
   enfants avant qu'ils n'aient un conteneur. Sans elle, les marges negatives
   du rythme (calc(pas-x - pas-y)) se superposent en flux normal : la
   reassurance passait SOUS les boutons, vu au navigateur. */
.manchette__texte {
  display: grid;
  justify-items: center;
  /* Le battement courant : les marges de rythme des enfants sont des
     calc(pas-x - pas-2) NEGATIFS qui presupposent ce row-gap. Sans lui, la
     reassurance remontait sous les boutons de 20 px. */
  row-gap: var(--pas-2);
}

/* La figure est hors plafond : c'est l'objet du hero, il prend la colonne. */
:where(.manifeste, .manchette) > :not(.dossier__grille, figure, .constellation) {
  max-inline-size: 820px;
  margin-inline: auto;
}
/* `text-align` ne gouverne pas des enfants de flex : les deux groupes de gestes
   du site le disent eux-mêmes. */
:where(.manifeste, .manchette) .manchette__actions {
  justify-content: center;
}

/* L'ACCUEIL CENTRE AUSSI SES SECTIONS DE DOSSIER, ET LUI SEUL. Quatre de ses
   sections sont en vitesse dossier (live, atouts, delai, maison) parce qu'elles
   portent de l'explication et pas de l'affirmation ; elles sortaient donc au
   fer à gauche au milieu d'une page centrée, et la rupture se voyait à chaque
   frontière. Chez Axel, TOUTE entête de section est centrée dans 780 px
   (v6.css:269-276), quelle que soit la densité de ce qui suit.
   La portée est l'accueil : /le-cadre-legal/, /confidentialite/ et les pages
   d'offre gardent leur fer à gauche, parce qu'on ne centre pas un texte long.
   Seule l'ENTÊTE est centrée, ce qui suit (grilles, blocs, encadré) garde son
   alignement, comme les grilles des manifestes. */
body[data-page="accueil"] .dossier__entete,
body[data-page="accueil"] .live__titre {
  max-inline-size: 780px;
  margin-inline: auto;
  text-align: center;
}
body[data-page="accueil"] .dossier__entete > * { margin-inline: auto; }
/* Les mêmes alias que ci-dessus, en :where() — (0,0,1). Ça habille un
   gabarit qui n'aurait pas posé .manifeste, sans jamais gagner contre une
   classe de composant. */
:where(.manifeste, .manchette) h1 {
  font-size: var(--t-hero);
}
/* LE RAPPORT ENTRE LE TITRE DE PAGE ET LE TITRE DE SECTION. --t-h2 sort à
   64 px : plus gros que le titre de section d'Axel (58) alors que notre hero
   était 28 px plus petit que le sien. Le hero passe à 128, et sans ce cran le
   rapport hero/h2 resterait à 2,0 quand le sien est à 2,21, un manifeste dont
   les six sections crient presque aussi fort que son ouverture.
   La SURCHARGE est ici et pas sur le jeton : --t-h2 sert aussi le h1 des pages
   de dossier (ligne 688), le bandeau de fin, .live__titre et .live__section-titre.
   Descendre le jeton aurait rapetissé quatre titres de page pour régler la
   composition d'un manifeste. */
:where(.manifeste, .manchette) h2 {
  font-size: clamp(1.9rem, 1.35rem + 2.65vw, 3.6rem);
}
:where(.manifeste, .manchette) p {
  max-inline-size: var(--mesure-jour);
  font-size: var(--t-lead);
  line-height: 1.4;
}

/* --- VITESSE NUIT : le dossier ------------------------------------------- */
.dossier,
.methode,
.demande {
  padding-block: var(--section-y);
  padding-inline: var(--gutter);
  line-height: var(--lh-dossier);
}
.dossier__scene,
.dossier__entete {
  max-inline-size: var(--maxw);
  margin-inline: auto;
}
/* Le flux interne des sous-blocs. La réinitialisation met toutes les marges à
   zéro : sans ça un titre et son paragraphe se touchent partout où la section
   n'est pas elle-même la grille. */
.dossier__entete,
.bloc,
.demande__scene > :not(.formulaire) {
  display: grid;
  align-content: start;
  gap: var(--pas-1);
}

/* --- LE RYTHME INTERNE D'UNE ENTÊTE -------------------------------------
   Le titre COLLE à son corps (--pas-1), les paragraphes respirent entre eux
   (--pas-2). Sans ça, `gap` posait la même valeur aux deux endroits et le
   titre flottait au-dessus de son texte exactement comme le paragraphe suivant.

   ON A ESSAYÉ LES DEUX PISTES ICI, ET ON LES A RETIRÉES. Mettre le titre à
   gauche et le corps à droite compose très bien tant que le titre est court —
   et /le-cadre-legal/ écrit ses titres en deux phrases. Un titre de cinq
   lignes qui traverse les rangées de la grille force ces rangées à grandir :
   MESURÉ à 1440, 176 px de trou ENTRE DEUX PARAGRAPHES du même texte, et
   133 px encore en élargissant la piste du titre à 6fr. C'est la mécanique de
   la grille, pas un réglage : un élément qui traverse N rangées distribue sa
   hauteur dessus, et aucune proportion ne rend un titre plus court que le
   corps qu'il coiffe.
   Les deux pistes restent donc là où elles ont été vérifiées sans trou : sur
   LE COUPLE, dont le nom tient sur une ligne et que le filet doit mesurer.
   Une entête n'a pas de filet — le vide à droite de son corps est la mesure de
   lecture, pas une composition ratée, et son titre prend déjà la colonne
   entière. */
.dossier__entete { row-gap: var(--pas-2); }
/* `:not(:last-child)` n'est pas une précaution de style : la marge est
   NÉGATIVE, elle retranche du pas courant déjà posé par row-gap. Sur une entête
   qui n'a qu'un titre — le déroulé du Slot, la mécanique de la Loop — le titre
   est aussi le dernier enfant, et une marge basse négative sur le dernier
   enfant rétrécit la boîte : l'entête sortait 20 px plus courte que son propre
   titre, et la frise en dessous remontait d'autant. */
.dossier__entete > h2:not(:last-child) {
  margin-block-end: calc(var(--pas-1) - var(--pas-2));
}
/* min(100%, --maxw) et pas --maxw seul, à cause d'un couple précis : quand la
   grille est un ENFANT DE GRILLE — les listes de .promesse, .sorties et
   .terrains sur l'accueil sont dans des .manifeste — son `margin-inline: auto`
   annule l'étirement de la piste (une marge auto l'emporte sur `stretch`), et
   l'élément se dimensionne alors sur son max-content au lieu de la piste.
   MESURÉ à 414 px : la liste de .promesse sortait à 733 px dans une piste de
   355, sur deux colonnes de 354 — l'accueil défilait à l'horizontale sur
   téléphone, de près du double de sa largeur. 100 % se résout ici contre la
   piste et referme le débordement ; --maxw continue de plafonner en large.
   Dans un .dossier, parent de bloc, les deux formes sont équivalentes. */
.dossier__grille {
  display: grid;
  /* 19rem de plancher donnait TROIS colonnes dans une colonne de 1240 : les
     trois listes de quatre du site (la promesse et les terrains de l'accueil,
     les atouts) sortaient en 3 + 1, avec un orphelin sous une rangée pleine.
     Une liste de quatre doit se lire comme quatre. 15rem laisse auto-fit tenir
     les quatre sur une rangée (4 × 276 + 3 × 45 = 1239) sans rien changer aux
     listes de deux et de trois, qu'auto-fit continue de résoudre seul —
     le nombre de colonnes reste une conséquence du contenu, pas une consigne. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(1.5rem, 1rem + 2vw, 3rem);
  /* `inline-size` et pas seulement `max-inline-size` : dans un manifeste, la
     grille est un ENFANT DE GRILLE, et son `margin-inline: auto` annule
     l'étirement de la piste. Sans largeur demandée, elle se dimensionnait sur
     son max-content — MESURÉ à 1440 : la grille de .sorties sortait à 1235 px
     et commençait à x=102, quand le titre au-dessus commençait à x=100. Deux
     px de décalage, invisibles seuls, mais c'est la largeur de la grille qui
     dépendait de son contenu au lieu de la colonne. 100 % se résout contre la
     piste et referme l'écart ; --maxw continue de plafonner en large. */
  inline-size: min(100%, var(--maxw));
  margin-inline: auto;
  margin-block-start: var(--pas-3);
}
/* Dans un manifeste, row-gap a déjà posé --pas-2 : on ne retranche que la
   différence pour que la frontière fasse --pas-3 au total, comme en dossier. */
:where(.manifeste, .manchette) > .dossier__grille {
  margin-block-start: calc(var(--pas-3) - var(--pas-2));
  /* LA GRILLE SORT DU CENTRAGE, et c'est la règle : on centre ce qui énonce,
     jamais ce qui se lit en colonnes. Un paragraphe de carte centré sur quatre
     colonnes de 276 px donne quatre blocs en losange dont aucune ligne ne
     commence au même endroit. Axel fait exactement ce partage : sa section est
     centrée, sa grille repasse en `text-align: left` (v6.css:476). */
  text-align: start;
  justify-items: stretch;
}
:where(.manifeste, .manchette) .dossier__grille p {
  max-inline-size: none;
}

/* DEUX GRILLES QUI NE SONT PAS DES LISTES DE QUATRE. Le plancher de 15rem a été
   calibré sur les listes de quatre, la promesse, les terrains, les atouts
   pour qu'auto-fit les tienne sur une rangée. Il s'applique aussi à deux
   grilles dont le contenu n'est pas de la même nature, et il les casse par le
   bas plutôt que par le haut :
   .sorties porte Slot et Loop, deux cartes de quatre éléments chacune (nom,
   promesse, corps, lien) qui se retrouvaient côte à côte dès ~507 px de piste,
   soit deux colonnes de 231 px sur un téléphone tenu à l'horizontale. Deux
   offres qui portent chacune une page ne se lisent pas en colonnes de 231.
   .atouts empile quatre arguments de texte à 276 px de large, quand Axel les
   pose en deux colonnes de 460 (v6.css:619-627) : un argument est une phrase,
   pas une puce, et il lui faut une mesure de lecture.
   auto-fit fait le reste et remplace les points de rupture d'Axel : le nombre
   de colonnes reste une conséquence du contenu. */
:where(.sorties) > .dossier__grille {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
}
:where(.atouts) > .dossier__grille {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
}

/* LES CORPS D'UNE RANGÉE SE POSENT SUR LA MÊME LIGNE. Chaque bloc d'une grille
   empile un titre puis un corps, et chaque titre tient sur une ou deux lignes
   selon sa longueur : MESURÉ sur la promesse de l'accueil, les quatre corps
   commençaient à 533, 533, 555 et 533 px. Un décalage de 22 px sur une rangée
   de quatre se lit comme un défaut d'exécution, pas comme une composition.
   subgrid donne aux blocs les rangées de leur parent : le titre occupe la même
   hauteur partout, et les corps repartent d'une seule ligne. Gardé sur les
   blocs à DEUX enfants — les cartes de sortie en ont quatre et déborderaient
   des deux rangées. Sans subgrid, l'ancien empilement reste, simplement
   désaligné : c'est un enrichissement, pas une dépendance. */
@supports (grid-template-rows: subgrid) {
  .dossier__grille { grid-auto-rows: auto; }
  .dossier__grille > :has(> :nth-child(2):last-child) {
    grid-row: span 2;
    grid-template-rows: subgrid;
    row-gap: var(--pas-1);
  }
}

/* LES DEUX RANGS DE TITRE. Le h1 d'une page de dossier garde --t-h2 (c'est le
   titre de la page), le h2 d'une section descend d'un cran : voir le
   commentaire de --t-h2-dossier dans socle.css. */
:where(.dossier, .methode, .demande) h2 { font-size: var(--t-h2-dossier); }
:where(.dossier, .methode, .demande) h3 { font-size: var(--t-h3); }
:where(.dossier, .methode, .demande) p {
  max-inline-size: var(--mesure-nuit);
}

.bloc { display: grid; align-content: start; gap: var(--pas-1); }
.bloc__titre { font-size: var(--t-h3); }

/* ═══ LES QUATRE CARTES À INTERFACE INCRUSTÉE (accueil, bloc 2) ════════════
   Le vrai apport de composition du proto d'Axel, et la raison de le reprendre :
   il montre le service sans photo de client, sans logo, sans témoignage. C'est
   la seule illustration honnête possible tant qu'il n'y a pas de premier
   annonceur, et elle ne triche pas, ces objets ne prétendent pas être des
   captures, ils sont dessinés et ils le montrent.
   Le bloc était quatre paragraphes gris de quinze mots.

   TOUT CE QUI EST DANS .bloc__ui EST aria-hidden. Ce sont des dessins, pas de
   l'information : rien de ce qu'ils affichent n'existe ailleurs que là, et un
   lecteur d'écran qui les épellerait lirait des libellés d'interface au milieu
   d'une phrase. Le texte de la carte porte seul le sens.

   LA COULEUR Y EST TENUE COURT. Le jaune et le vert ne paraissent QUE dans ces
   quatre panneaux et dans le relevé sombre : ce sont des marques d'interface,
   pas une palette de page. Les sortir d'ici, c'est les rendre décoratifs. */
.promesse .bloc {
  gap: 0.625rem;
  padding: 1.375rem 1.5rem 1.75rem;
  background: var(--carte);
  border-radius: var(--radius);
}
.bloc__ui {
  display: grid;
  place-items: center;
  min-block-size: 170px;
  margin-block-end: 0.625rem;
  padding: 1.125rem;
  background: var(--carte-basse);
  border-radius: var(--radius-ui);
  overflow: clip;
}
.promesse .bloc > p { font-size: var(--t-petit); color: var(--texte-secondaire); }

/* La pastille : l'objet le plus petit du jeu, et celui qui revient partout. */
.ui-pastille {
  padding: 0.375rem 0.75rem;
  background: var(--fond);
  border-radius: var(--radius-pilule);
  box-shadow: var(--ombre-ui);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.ui-pastille--signal { background: var(--signal); color: var(--encre-jour); }

/* 1. La créa : une maquette en cours, sa vignette et deux lignes de texte. */
.ui-crea {
  position: relative;
  inline-size: 100%;
  max-inline-size: 160px;
  display: grid;
  gap: 0.5rem;
  padding: 0.75rem;
  background: var(--fond);
  border-radius: 12px;
  box-shadow: var(--ombre-ui);
}
.ui-crea__vignette {
  block-size: 64px;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--nuit) 0 55%, var(--tribune) 55%);
}
.ui-crea__lignes { display: grid; gap: 5px; }
.ui-crea__lignes i { display: block; block-size: 6px; border-radius: 3px; background: var(--carte-basse); }
.ui-crea__lignes i:last-child { inline-size: 60%; }
.ui-crea .ui-pastille { position: absolute; inset-inline-end: -10px; inset-block-end: 14px; }

/* 2. L'itinéraire. Le tracé reprend la grammaire de la marque de donnée : le
      segment plein est un relevé, le point est l'arrivée. */
.ui-plan { position: relative; inline-size: 100%; max-inline-size: 190px; }
.ui-plan svg {
  inline-size: 100%;
  background: var(--fond);
  border-radius: 12px;
  box-shadow: var(--ombre-ui);
}
.ui-plan__rues { stroke: var(--bordure); stroke-width: 2; fill: none; }
.ui-plan__chemin {
  stroke: var(--texte);
  stroke-width: 3;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ui-plan__point { fill: var(--signal); stroke: var(--texte); stroke-width: 2; }
.ui-plan .ui-pastille { position: absolute; inset-inline-start: 50%; inset-block-end: -8px; translate: -50% 0; }

/* 3. Les deux statuts de l'autorisation. La première ligne est en retrait :
      elle est passée, la seconde est l'état courant. */
.ui-statut { display: grid; gap: 0.625rem; inline-size: 100%; max-inline-size: 220px; }
.ui-statut__ligne {
  position: relative;
  padding: 0.5625rem 0.875rem 0.5625rem 2rem;
  background: var(--fond);
  border-radius: var(--radius-pilule);
  box-shadow: var(--ombre-ui);
  font-family: var(--font-mono);
  font-size: 11px;
}
.ui-statut__ligne::before {
  content: "";
  position: absolute;
  inset-inline-start: 12px;
  inset-block-start: 50%;
  inline-size: 12px;
  block-size: 7px;
  margin-block-start: -2px;
  border-inline-start: 2px solid var(--valide);
  border-block-end: 2px solid var(--valide);
  rotate: -45deg;
  translate: 0 -50%;
}
.ui-statut__ligne:first-child { opacity: 0.55; }

/* 4. L'aperçu du relevé. LE SEUL OBJET SOMBRE DE LA PAGE avec le pied, et il
      porte sa zone : posé dans une page blanche, il ne peut pas compter sur
      l'héritage pour retrouver l'encre de la nuit.
      SES DEUX HORAIRES SONT CEUX DU PILOTE, pas les chiffres d'Axel. Son proto
      affiche « 412 diffusions », « 11,8 km », « 2 400 à 3 700 » : aucune de ces
      valeurs n'existe dans la copy, et un objet qui a la forme exacte d'un
      relevé de campagne ne se désamorce pas avec le mot EXEMPLE en petit. La
      forme est reprise, les nombres viennent de contenu/specimen.json. */
.ui-releve {
  inline-size: 100%;
  max-inline-size: 200px;
  display: grid;
  gap: 0.5rem;
  padding: 0.75rem 0.875rem;
  background: var(--fond);
  border-radius: 12px;
  box-shadow: var(--ombre-ui);
  font-family: var(--font-mono);
  font-size: 11px;
}
.ui-releve__tete { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }
.ui-releve__ligne { display: flex; gap: 0.5rem; color: var(--texte-secondaire); }
.ui-releve__ligne i { font-style: normal; color: var(--signal); }
.ui-releve__exemple {
  padding: 2px 7px;
  background: var(--signal);
  color: var(--encre-jour);
  border-radius: 4px;
  font-size: 10px;
  letter-spacing: 0.12em;
}

/* --- 1. La manchette. Typographique et une figure : le sac de js/sac.js, posé
       par accueil.html. Le commentaire disait « ni vidéo, ni image, ni canvas,
       on n'ouvre pas la page sur notre point faible », c'était vrai du texte
       seul, et faux depuis que la séquence du sac ouvre l'accueil. -------- */
.manchette { padding-block-start: calc(var(--barre-h) + var(--section-y) * 0.6); }
/* Le seul titre du site qui atteint 128 px, donc le seul où l'interligne par
   défaut se voit. 1,02 et -0,015em sont les valeurs d'Axel (v6.css:207-209) :
   au-delà de 100 px, l'espace entre deux lignes et l'espace entre deux lettres
   ne se lisent plus comme du confort, ils se lisent comme du relâchement.
   `padding-block-end` n'est pas de la marge : à 1,02, la boîte de ligne est
   plus courte que la fonte, et les jambages d'Instrument Serif, le p et le q
   de « pub », le g de « écran qui », sortaient rognés par le bas. */
.manchette__titre {
  font-size: var(--t-hero);
  line-height: 1.02;
  letter-spacing: -0.015em;
  padding-block-end: 0.08em;
}
.manchette__ligne { display: block; }
/* La seconde voix du titre : même graisse, un ton en dessous. 7,12 sur
   papier, elle reste du texte courant AAA. */
.manchette__ligne--douce { color: var(--texte-secondaire); }
/* 34ch et non 42 : le chapeau se lit SOUS un hero qui fait maintenant 128 px.
   Une ligne de chapeau presque aussi large que le titre qu'elle explique met
   les deux au même rang. Axel la pose à 34 (v6.css:212-216) et la phrase tient
   en trois lignes dans les deux cas, ce qui change est le rapport de largeur,
   pas le nombre de lignes.
   Ne PAS toucher --mesure-nuit au passage : ses 66ch ont été mesurés au
   navigateur sur du texte de dossier, pas déduits d'un chapeau. */
.manchette__sous { max-inline-size: 34ch; font-size: var(--t-lead); line-height: 1.35; }
.manchette__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }
/* L'indice est la ligne fine qui suit les gestes, du même registre que
   .manchette__reassurance : elle nomme sa couleur ici parce que le secondaire
   ne tombe plus tout seul sur un p (zones.css, partie 4). La sous-ligne du
   hero, elle, ne la nomme pas : c'est le chapeau de la page. */
.manchette__indice {
  font-size: var(--t-petit);
  line-height: 1.4;
  color: var(--texte-secondaire);
}
/* A 390, l'audit mesurait 660 px de texte avant le plan : le fond ouvrait
   sous le pli. Le padding haut retombe a la barre reelle, les gaps se
   serrent, le plan remonte dans le premier ecran. */
@media (width < 35rem) {
  body[data-page="accueil"] .manchette {
    padding-block-start: calc(var(--barre-h) + var(--pas-2));
  }
  body[data-page="accueil"] .manchette__texte { row-gap: var(--pas-1); }

  .manchette__actions { display: grid; }
}

/* --- 2. La différence. Deux lignes EMPILÉES — jamais deux colonnes, jamais
       un tableau comparatif. ---------------------------------------------- */
.difference__corps { max-inline-size: 44ch; }
.difference__lignes { display: grid; gap: var(--pas-1); }
.difference__eux {
  font-size: var(--t-h3);
  color: var(--texte-secondaire);
}
.difference__nous {
  font-size: var(--t-h3);
  font-weight: var(--wght-titre);
  color: var(--texte);
}

/* --- 3. La rue. (Le dimensionnement de .preuve vivait ici du temps de la
       vignette « contenue, jamais plein cadre » ; la refonte du 15.08 au soir
       en a fait une saignée, ses règles vivent avec la section preuves plus
       haut. Une inline-size posée ici rétrécirait la figure en timbre sous
       900 px : c'est exactement le bug qui a été payé.) ------------------- */
/* --- LE HERO PLEIN ÉCRAN (accueil) ----------------------------------------
   La manchette prend le viewport entier : le texte en haut sur le blanc, et
   tout le reste de l'écran est le plan, plein bord. Deux rangées de grille,
   la seconde est le fond ; min-block-size et pas block-size, le texte ne se
   fait jamais rogner sur un petit écran.
   LE FOND TOURNE : trois .rue__plan empilés en absolu, un seul porte .est-la,
   js/v7.js fait le fondu (opacity 900 ms) toutes les 7 s. Sans script, sans
   `anim`, sous mouvement réduit : le premier poster est l'image définitive,
   les deux autres ne pèsent rien (preload none, posters non chargés tant que
   le navigateur ne les peint pas... les posters SE CHARGENT, eux : trois
   posters ≈ 320 Ko, c'est le prix du fondu, assumé).
   Les fondus blancs sont DES BORDS DE CADRE, pas un voile : le cœur du plan
   reste pleine luminance (acquis de la spec, « jamais voilées »). */
/* SCOPE A L'ACCUEIL, ET CE N'EST PAS UN DETAIL : dix autres pages ont une
   .manchette SANS le conteneur .manchette__texte. La regle globale leur
   mettait le 1fr sur leur deuxieme enfant et le start a la place du centre :
   dix heros casses d'un coup. Constat de l'audit, verifie sur slot/loop/
   rapport/walkers. Le hero plein ecran est un dessin de l'accueil. */
/* PLEIN CADRE, TEXTE PAR-DESSUS (consigne de Nazaire, 15.08 au soir). Le plan
   prend l'écran ENTIER, la manchette s'écrit en blanc dessus : une seule
   rangée, les deux enfants dans la même cellule, le texte au-dessus par
   z-index. C'est la seule surface du site où le texte est blanc : il est posé
   SUR le contenu diffusé, pas sur le papier — le projecteur, littéralement.
   La lecture est garantie par le voile sombre du ::before du fond, pas par la
   chance du footage. */
body[data-page="accueil"] .manchette {
  grid-template-rows: 1fr;
  min-block-size: 100svh;
  /* zéro padding vertical : le plan monte jusqu'au bord et passe SOUS la
     barre flottante ; l'air du texte vit dans .manchette__texte. */
  padding-block: 0;
  align-content: stretch;
  /* --marque-l vit sur la SECTION : le wordmark (dans le texte) et le trait
     blanc (sur le fond) sont des cousins, la variable doit atteindre les
     deux. Et c'est la section qui ROGNE le socle : le wordmark plonge de
     30 % sous la coupure, overflow: clip le coupe au cordeau. */
  --marque-l: min(58vw, 50rem);
  overflow: clip;
}
@media (width < 40rem) {
  body[data-page="accueil"] .manchette { --marque-l: 92vw; }
}
/* LES COINS OPPOSÉS (15.08 soir, référence Eladio Dieste, choix de Nazaire) :
   « L'écran » s'ancre en haut à gauche, « qui marche. » en bas à droite, et
   le plan vit entre les deux. Le bloc texte prend le viewport entier (il
   annule le centrage de colonne comme le fond), se compose en grille, et le
   h1 passe en display: contents pour que ses deux moitiés deviennent des
   ancres de cette grille sans casser sa lecture d'une traite. */
body[data-page="accueil"] .manchette__texte {
  grid-area: 1 / 1;
  position: relative;
  z-index: 1;
  /* la vitesse manifeste plafonne ses enfants à 820 px : les coins sont ceux
     du viewport, le plafond saute avec le centrage. */
  max-inline-size: none;
  margin-inline: calc(-1 * max(var(--gutter), (100vw - var(--maxw)) / 2));
  block-size: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  /* LA UNE DE JOURNAL (16.08, layout choisi sur maquettes) : kicker, titre
     REGROUPÉ à gauche, ressort, et le wordmark GÉANT en socle — les gestes
     tiennent la colonne droite du ressort. Le socle est HORS FLUX (absolu au
     bas de la section) : en rangée, sa hauteur plus celle du pied gonflaient
     la manchette à 1157 px et le hero perdait son écran unique. Le padding
     bas lui réserve sa place, la même formule que le trait du fond. */
  grid-template-rows: auto auto auto 1fr;
  align-content: stretch;
  /* la grille de base du bloc centre ses enfants : ici tout s'ancre au bord. */
  justify-items: start;
  text-align: start;
  /* La réserve du socle rend elle aussi les pixels de la banderole (21.08).
     Retrancher --bandeau-h de la hauteur minimale ne suffit pas : au grand
     écran c'est le CONTENU qui pilote, pas le minimum — la réserve vaut 275 px
     à 1440 — et le hero restait plus haut que la fenêtre d'exactement la
     banderole. On la retranche donc là où la hauteur se fabrique vraiment. Les
     deux règles ne se cumulent jamais : celle du minimum ne parle que quand le
     contenu est plus court, celle-ci que quand il est plus long. */
  padding: clamp(1.75rem, 4svh, 2.5rem) clamp(1.25rem, 3vw, 3rem)
           calc(var(--marque-l) * 0.314 + 1.5rem - var(--bandeau-h, 0px));
  color: var(--projecteur);
}
/* LE WORDMARK EN SOCLE : géant, centré, COUPÉ PAR L'ANGLE au repos — et il
   REMONTE AVEC LE TRAIT (16.08, consigne de Nazaire : « qu'il ne fasse pas
   bizarre d'être posé sur la fin du hero ») : la même variable de scrub le
   fait émerger de la coupure et venir se caler AU CENTRE de la bande entre
   la ligne blanche et la fin du hero. Le facteur 0,68 n'est pas un goût :
   c'est (bande - marges) / hauteur du wordmark, et il est constant parce
   que bande et wordmark suivent tous deux --marque-l. Origine en bas : il
   se condense vers la coupure dont il sort. Sans anim, --trait-hero vaut 0,
   la pose plongée du repos. */
body[data-page="accueil"] .manchette__marque {
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  margin-inline: auto;
  inline-size: var(--marque-l);
  block-size: auto;
  transform-origin: bottom center;
  transform: translateY(calc((1 - var(--trait-hero, 0)) * 30% - var(--trait-hero, 0) * 0.75rem))
             scale(calc(1 - var(--trait-hero, 0) * 0.32));
  filter: drop-shadow(0 1px 24px rgb(0 0 0 / 0.35));
}
body[data-page="accueil"] .manchette__kicker {
  grid-area: 1 / 1 / 2 / 3;
  color: rgb(255 255 255 / 0.82);
}
body[data-page="accueil"] .manchette__titre { display: contents; }
body[data-page="accueil"] .manchette__titre-haut,
body[data-page="accueil"] .manchette__titre-bas {
  font-size: clamp(3.25rem, 7.5vw, 6.75rem);
  line-height: 0.98;
  color: var(--projecteur);
  text-shadow: 0 1px 28px rgb(0 0 0 / 0.35);
}
body[data-page="accueil"] .manchette__titre-haut { grid-area: 2 / 1; }
/* Le titre se REGROUPE : « qui marche. » quitte son coin et s'empile sous
   « L'écran », même fer à gauche — la une se lit d'un bloc, le socle porte
   la marque. */
body[data-page="accueil"] .manchette__titre-bas {
  grid-area: 3 / 1;
}
/* Les gestes tiennent la colonne droite du ressort, centrés dans sa
   hauteur : la moitié droite du plan les porte pendant que la gauche lit. */
body[data-page="accueil"] .manchette__pied {
  grid-area: 4 / 2;
  align-self: center;
  justify-self: end;
  display: grid;
  justify-items: start;
  gap: 1.1rem;
  max-inline-size: 46ch;
}
body[data-page="accueil"] .manchette__sous {
  color: var(--projecteur);
  text-shadow: 0 1px 24px rgb(0 0 0 / 0.35);
  margin: 0;
}
body[data-page="accueil"] .manchette__actions { justify-content: start; }
body[data-page="accueil"] .manchette__reassurance {
  color: rgb(255 255 255 / 0.88);
  text-shadow: 0 1px 18px rgb(0 0 0 / 0.35);
}
/* Le fantôme dessinait son filet à l'encre : invisible sur le voile. Il passe
   au blanc ; la pilule pleine, encre sous étiquette blanche, tient déjà sur
   n'importe quel footage. */
body[data-page="accueil"] .manchette__actions .bouton--fantome {
  box-shadow: inset 0 0 0 1.5px rgb(255 255 255 / 0.85);
  color: var(--projecteur);
}
@media (width < 40rem) {
  /* Les coins tiennent au téléphone : « L'écran » sous la pilule, « qui
     marche. » à droite au-dessus du pied, qui reprend toute la largeur. */
  body[data-page="accueil"] .manchette__texte {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto 1fr;
  }
  body[data-page="accueil"] .manchette__titre-bas { grid-area: 3 / 1; }
  /* Les gestes reviennent à gauche en bas du ressort ; le padding calculé du
     bloc les tient au-dessus du socle absolu. */
  body[data-page="accueil"] .manchette__pied {
    grid-area: 4 / 1;
    align-self: end;
    justify-self: start;
    max-inline-size: none;
  }
}

/* --- LE TÉLÉPHONE COUCHÉ (18.08) -----------------------------------------
   Mesuré à 844 × 390 : la manchette faisait 711 px de haut pour 390 px de
   fenêtre, et « Diffuser ma pub » tombait 32 px SOUS la ligne de flottaison.
   Le seul geste du premier écran était invisible sans défiler.

   AUCUN PALIER NE COUVRAIT CE CAS, et c'est structurel : les seuils du site
   sont TOUS des largeurs. En paysage la largeur est confortable pendant que la
   hauteur ne l'est plus, donc `max-width: 640px` ne se déclenche pas et le
   hero se compose comme sur un bureau dans 390 px de haut.

   LA FAUSSE PISTE, notée pour qu'elle ne se rejoue pas : --marque-l réserve
   `--marque-l * 0.314 + 1.5rem` de padding bas, soit 177,7 px ici, et il est
   tentant d'y voir le coupable. Ce padding est SOUS les gestes. Mesuré aux
   quatre valeurs (58vw, 46svh, 35svh, 25svh) : la section passe de 711 à
   588 px et le CTA ne bouge pas d'un pixel. Ce qui coûte est AU-DESSUS, rangée
   par rangée : 28 de padding + 17 de kicker + 2 × 62 de titre + 76 de
   gouttières = 245 px avant même que le ressort commence.

   D'où les quatre leviers ci-dessous, dans l'ordre de ce qu'ils rendent : le
   titre (−60), les gouttières (−46), les gestes côte à côte (−65), le padding
   haut (−12). Le socle rétrécit aussi, non pour le CTA mais pour que la
   section cesse de faire 1,8 écran.
   Résultat : manchette 711 → 428, CTA 32 px sous la ligne → 81 px au-dessus,
   et le hero entier (jusqu'à la réassurance) tient dans la fenêtre. Vérifié
   aussi à 667 × 375. Portrait et bureau ne bougent pas d'un pixel : la règle
   ne s'y déclenche pas.

   32rem plutôt que 512px : un utilisateur qui grossit sa police a un écran
   relativement plus court, il doit entrer dans ce palier plus tôt. */
@media (orientation: landscape) and (height < 32rem) {
  body[data-page="accueil"] .manchette { --marque-l: min(58vw, 40svh); }
  body[data-page="accueil"] .manchette__texte {
    row-gap: 0.625rem;
    padding-block-start: 1rem;
  }
  /* La serif ne suit pas la largeur ici, elle suit la hauteur : c'est elle qui
     manque. Le plancher de 2rem est celui sous lequel Instrument Serif se lit
     comme une coquille. */
  body[data-page="accueil"] .manchette__titre-haut,
  body[data-page="accueil"] .manchette__titre-bas {
    font-size: clamp(2rem, 9svh, 2.75rem);
  }
  /* Les gestes sont dans la colonne `auto` du ressort : à cette largeur elle
     est trop étroite pour deux boutons, et `flex-wrap: wrap` (ligne 711) les
     empilait, ce qui coûtait 65 px de hauteur pour du blanc à droite. */
  body[data-page="accueil"] .manchette__actions { flex-wrap: nowrap; }
}

/* --- Les règles du défilement (accueil, 16.08) ---------------------------
   Une ligne d'encre en tête de chaque section de l'accueil, tirée par le
   défilement sur DEUX TIERS de la largeur, une fois depuis la droite, une
   fois depuis la gauche (consigne de Nazaire). Le remplissage est scrubbé
   par js/v7.js (--regle, 0 à 1) ; sans lui, sans anim, les lignes sont
   posées pleines — une règle figée reste une séparation. scaleX et jamais
   inline-size : le remplissage ne coûte aucun layout. DEUX exclusions : la
   manchette (le hero a SON trait, blanc) et les preuves — leur tête touche
   la coupure du hero, une règle d'encre y doublerait le trait blanc au même
   pixel et se noierait dans le footage. La maison est sortie le 16.08 sur
   consigne de Nazaire : une règle juste avant la vue éclatée parasitait
   l'entrée de l'objet. L'alternance commence au problème, depuis la
   droite. */
body[data-page="accueil"] main > section:not(.manchette):not(.preuves):not(.maison) { position: relative; }
body[data-page="accueil"] main > section:not(.manchette):not(.preuves):not(.maison)::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  block-size: 3px;
  inline-size: 66.666%;
  background: var(--texte);
  pointer-events: none;
  transform: scaleX(1);
}
html.anim body[data-page="accueil"] main > section:not(.manchette):not(.preuves):not(.maison)::before {
  transform: scaleX(var(--regle, 0));
}
body[data-page="accueil"] main > section:nth-of-type(odd)::before {
  inset-inline-end: 0;
  transform-origin: right;
}
body[data-page="accueil"] main > section:nth-of-type(even)::before {
  inset-inline-start: 0;
  transform-origin: left;
}
/* .manchette__fond ET PAS .rue : « rue » est un nom de VITESSE du site
   (.manifeste, .manchette, .difference, .rue, .creneau) depuis la v7 d'origine.
   Nommer la figure .rue lui a fait heriter toute la grammaire de section,
   colonne 1240 centree, 100svh, plafond de mesure sur ses enfants : le fond
   du hero sortait en vignette de 820 px. Trouve au navigateur, en prod.
   La section compose sur UNE colonne minmax(0, --maxw) centree : l'offset
   lateral vaut max(gouttiere, (100vw - --maxw) / 2), et le fond l'annule en
   marge negative pour toucher les bords. Le 100vw compte la barre de
   defilement : socle.css pose overflow-x clip sur html, la garde globale. */
.manchette__fond {
  position: relative;
  grid-area: 1 / 1;
  margin-inline: calc(-1 * max(var(--gutter), (100vw - var(--maxw)) / 2));
  block-size: 100%;
  overflow: clip;
}
.manchette__fond > video {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  max-inline-size: none;
  block-size: 100%;
  object-fit: cover;
  object-position: center 38%;
  opacity: 0;
  transition: opacity 900ms var(--ease);
}
.manchette__fond > video.est-la { opacity: 1; }
/* Deux calques sur le plan : le VOILE qui paie la lecture du blanc (sombre en
   haut, encore présent au centre où le texte vit, éteint au dernier quart),
   et le fondu blanc du bas, la couture vers la page. Le voile est le prix de
   la consigne « texte par-dessus » : sans lui, un footage de plein soleil
   mange la manchette au premier plan clair. */
.manchette__fond::before,
.manchette__fond::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  pointer-events: none;
}
.manchette__fond { --voile-plancher: 0.55; }
.manchette__fond::before {
  inset-block: 0;
  /* LE PLANCHER (19.08). Les quatre dégradés ci-dessous FAÇONNENT la lumière,
     ils ne la garantissent pas : ils tombent tous à zéro entre 42 et 55 %,
     c'est-à-dire exactement là où vivent le sous-titre et la réassurance.
     Mesuré au navigateur sur le plan le plus dur (rue en plein soleil), texte
     masqué pour photographier le fond, contraste calculé pixel par pixel :
     sous-titre 1,20, deuxième ligne du titre 1,99, réassurance 2,01. Trois
     éléments sur cinq sous le seuil, dont le seul paragraphe du premier écran.
     Simulé de 0 à 0,55 sur l'image du fond : 0,45 laisse encore le sous-titre
     à 3,90, 0,55 fait passer tout le monde (sous-titre 5,43, titre bas 7,74,
     réassurance 6,83, kicker 12,45). C'est la valeur ici, et c'est le seul
     nombre à tourner — les quatre dégradés gardent leur dessin.
     Ce n'est pas une concession arrachée au design : Nazaire l'a demandé
     assombri, « vu la qualité médiocre des footages pour le moment ». Le jour
     où le footage portera, ce nombre baisse. */
  /* le voile suit les TEXTES, renforcé le 16.08 (consigne de Nazaire : « que
     les textes ressortent plus ») : fort en haut (le kicker et « L'écran »),
     fort en bas (le pied et « qui marche. »), et un troisième dégradé depuis
     la GAUCHE — c'est le flanc où vivent le titre, la marque, le sous-titre
     et les gestes depuis le passage au Z. Le cœur droit du plan garde sa
     luminance : un dégradé n'est pas un aplat. */
  background:
    linear-gradient(rgb(0 0 0 / 0.55), rgb(0 0 0 / 0) 42%),
    linear-gradient(0deg, rgb(0 0 0 / 0.6), rgb(0 0 0 / 0) 50%),
    linear-gradient(90deg, rgb(0 0 0 / 0.45), rgb(0 0 0 / 0) 55%),
    linear-gradient(270deg, rgb(0 0 0 / 0.35), rgb(0 0 0 / 0) 45%),
    linear-gradient(rgb(0 0 0 / var(--voile-plancher)), rgb(0 0 0 / var(--voile-plancher)));
}
/* LA COUTURE N'EST PLUS UN FONDU (16.08, consigne de Nazaire : « hero à
   angle comme les marques de tech ») : le hero se termine au cordeau, et la
   séparation est un TRAIT blanc qui se déroule de gauche à droite avec le
   défilement — js/v7.js scrubbe --trait-hero de 0 à 1, plein aux deux tiers
   de la traversée du hero. scaleX et jamais inline-size : zéro layout.
   Sans anim, le trait est posé plein : une séparation figée reste une
   séparation. Les fondus blancs INTÉRIEURS (constellation, cadre preuve) ne
   bougent pas, arbitrage du 16.08 : on durcit l'entrée, pas toute la page. */
.manchette__fond::after {
  /* au-dessus du SOCLE : le wordmark géant occupe le pied du hero (sa part
     visible vaut 0.314 fois sa largeur — ratio 177/394, moins le plongeon
     de 30 %), le trait flotte juste au-dessus de lui. Flush avec le bord, le
     blanc se fondait dans le blanc de la page qui suit. */
  inset-block-end: calc(var(--marque-l, 60vw) * 0.314 + 1.25rem);
  block-size: 3px;
  background: var(--fond);
  transform-origin: left;
  transform: scaleX(1);
}
html.anim .manchette__fond::after {
  transform: scaleX(var(--trait-hero, 0));
}

/* REFONTE du 15.08 au soir : le cadre n'est plus un objet posé, c'est une
   SAIGNÉE. Le plan du 12.08, portrait natif, prend la hauteur et sort du
   cadre à droite ; il n'a ni rayon ni chrome, il émerge du papier par les
   mêmes bords fondus que le hero (des bords de cadre, pas un voile : le cœur
   du plan reste pleine luminance). La légende se pose sur le fondu bas. */
.preuve { position: relative; }
.preuve__cadre {
  position: relative;
  /* En base (mobile) : une bande couverte, bornée par la hauteur. Le 9:16
     n'est posé qu'à 900+, où la hauteur commande la largeur de la saignée ;
     en pleine largeur il ferait 1077 px de haut à 606 de large. */
  inline-size: 100%;
  block-size: min(78svh, 42rem);
  overflow: clip;
  /* L'écran reste noir même quand la page est claire : c'est vrai. */
  background: var(--nuit);
}
.preuve__cadre > img,
.preuve__cadre > video {
  inline-size: 100%;
  max-inline-size: none;
  block-size: 100%;
  object-fit: cover;
}
/* LES BORDS FONDUS SONT PARTIS (21.08). Quatre dégradés blancs mangeaient les
   bords du plan pour le faire « émerger du papier ». À l'écran ça ne donnait
   pas un objet qui émerge, ça donnait un autocollant mal détouré — et au
   téléphone, où le cadre ne fait que 390 px de large, le fondu prenait une
   fraction énorme de l'image.
   Trois raisons de trancher plutôt que de régler :
   1. DESIGN.md, section Forme : « Jamais d'ombre portée ni de dégradé
      décoratif, des deux côtés. » Un fondu blanc sur le bord d'une image est
      un dégradé décoratif. C'est la loi du projet, pas un avis.
   2. Le hero a déjà tranché le 16.08 : coupure nette, « marque tech ». La page
      se contredisait, entrée dure et intérieur mou.
   3. Le fondu bas servait de fond à .preuve__legende, qui n'existe plus dans le
      gabarit depuis le 16.08. Il ne soutenait plus rien.
   Le cadre prend à la place le rayon des autres objets de la page : il devient
   un objet du même langage que les cartes, au lieu d'un rectangle posé. */
.preuve__cadre { border-radius: var(--radius); overflow: hidden; }
.preuve__legende {
  position: absolute;
  inset-block-end: 1.1rem;
  inset-inline-start: max(var(--gutter), 1.25rem);
  max-inline-size: 34ch;
  font-size: var(--t-petit);
  line-height: 1.4;
  color: var(--texte-secondaire);
}
/* Mobile : la figure prend le viewport, la fiche des faits reste une barre. */
.preuves .preuve { margin: var(--pas-2) calc(-1 * var(--gutter)) 0; }
@media (width >= 56.25rem) {
  /* RECOMPOSÉE le 15.08 au soir (Nazaire : « trop d'espace vide, et la vidéo
     collée à droite fait pas sens ») : la saignée n'avait plus de raison
     d'être depuis que le hero est plein cadre. La scène tient dans la colonne
     du site : les quatre faits se DÉPLOIENT sur toute la hauteur du plan, une
     rangée par fait, et c'est le plan qui donne la hauteur — plus de vide, la
     fiche EST la structure. Le plan est centré dans sa colonne et fond au
     blanc sur ses quatre bords : il émerge du papier, il ne s'accroche plus
     au viewport. */
  .preuves__scene {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    align-items: stretch;
    column-gap: clamp(2.5rem, 5vw, 5.5rem);
  }
  /* Le parent dans le sélecteur n'est pas du zèle : les règles de base de
     .preuves__liste arrivent PLUS BAS dans cette feuille, et à spécificité
     égale elles regagneraient la partie. */
  .preuves__scene .preuves__liste {
    flex-direction: column;
    gap: 0;
    border-block: 0;
    padding-block: 0;
    block-size: 100%;
  }
  .preuves__scene .preuves__item {
    flex: 1;
    display: flex;
    align-items: center;
    font-size: clamp(1.35rem, 1.05rem + 1.1vw, 2rem);
    font-weight: 500;
    color: var(--texte);
    border-block-end: var(--hairline) solid var(--bordure);
  }
  .preuves__scene .preuves__item:last-child { border-block-end: 0; }
  .preuves .preuve {
    margin: 0;
    display: grid;
    justify-items: center;
  }
  .preuve__cadre {
    aspect-ratio: 9 / 16;
    block-size: min(74svh, 46rem);
    inline-size: auto;
  }
  .preuve__legende {
    inset-inline: 2rem 2rem;
    text-align: center;
    max-inline-size: none;
  }
}

/* .bande::before/::after retirés le 21.08 : aucun gabarit ne pose .bande,
   ces deux règles ne peignaient rien depuis un moment. */


/* --- 4. Le créneau. Trois temps, numérotés par le CSS pour que le gabarit
       n'ait pas à écrire « 01 » dans le JSON. --------------------------- */
.etapes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(1.25rem, 1rem + 1.5vw, 2.5rem);
  counter-reset: etape;
}
.etape {
  counter-increment: etape;
  padding-block-start: 0.9rem;
  border-block-start: var(--hairline) solid var(--bordure);
}
.etape::before {
  content: counter(etape, decimal-leading-zero);
  display: block;
  margin-block-end: var(--pas-1);
  font-size: var(--t-micro);
  font-weight: var(--wght-titre);
  letter-spacing: 0.12em;
  color: var(--texte-secondaire);
}
.etape__titre { font-size: var(--t-h3); }
.etape__corps { margin-block-start: var(--pas-1); max-inline-size: 34ch; }

/* --- Les cotes : la clé murmure, la valeur répond. L'air remplace les
       filets — pas de table, pas de colonnes. ----------------------------- */
.fiche { display: grid; }
.fiche__ligne {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.55rem;
  border-block-start: var(--hairline) solid var(--bordure);
}
.fiche__ligne dt {
  font-size: var(--t-petit);
  font-weight: var(--wght-texte);
  color: var(--texte-secondaire);
}
.fiche__ligne dd {
  font-weight: var(--wght-titre);
  color: var(--texte);
}
/* Filet de sécurité : une valeur videe dans contenu/fr.json (les horaires du
   pilote, par exemple) ne doit pas laisser une ligne vide derrière elle. */
.fiche__ligne:has(dd:empty) { display: none; }

/* --- Méthode : refus / garantie en deux temps empilés, jamais un tableau
       à deux colonnes. ------------------------------------------------------ */
/* Le filet appartient au couple qui le suit : 12 px au-dessus du nom, --pas-3
   en dessous de la réponse. Le rapport était de 14 à 32 — assez pour qu'on
   hésite sur ce que le trait sépare. À 12 contre 60, il n'y a plus d'hésitation. */
.paires { display: grid; gap: var(--pas-3); }
.paire {
  display: grid;
  gap: var(--pas-1);
  padding-block-start: var(--pas-1);
  border-block-start: var(--hairline) solid var(--bordure);
}
.paire__refus { color: var(--texte-secondaire); }
.paire__garantie { font-weight: var(--wght-titre); color: var(--texte); }

/* --- La demande. On ne demande les coordonnées qu'après avoir prouvé. ---- */
.demande__scene {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: clamp(2rem, 1.5rem + 3vw, 4.5rem);
  align-items: start;
  max-inline-size: var(--maxw);
  margin-inline: auto;
}
@media (width < 56.25rem) {
  .demande__scene { grid-template-columns: 1fr; }
}
.formulaire {
  border-radius: var(--radius);
  padding: clamp(1.4rem, 1rem + 1.5vw, 2.25rem);
  background: var(--surface);
  border: var(--hairline) solid var(--bordure);
}
.champ { margin-block-start: 1.1rem; }
.champ > label {
  display: block;
  margin-block-end: 0.35rem;
  font-size: var(--t-petit);
  color: var(--texte-secondaire);
}
/* --radius-ui et non --radius : 28 px sur un champ de saisie d'une ligne fait
   une gélule, et une gélule ne se lit plus comme une zone où l'on écrit. 16 px
   suit la famille sans la caricaturer. Même règle partout : le grand rayon
   appartient aux objets qui portent du contenu, pas aux contrôles. */
.champ input,
.champ textarea {
  inline-size: 100%;
  padding: 0.85rem 1rem;
  background: var(--fond);
  color: var(--texte);
  border: var(--hairline) solid var(--bordure-champ);
  border-radius: var(--radius-ui);
}
.champ input:focus-visible,
.champ textarea:focus-visible { outline-offset: 0; }
.champ textarea { min-block-size: 6.5rem; }

/* Le piège à robots. Clippé, pas déporté à -9999px : un décalage horizontal
   sur une page en grille finit toujours par ouvrir une barre de défilement. */
.pot {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.formulaire__bouton { margin-block-start: 1.5rem; }
/* La mention nLPD sous le bouton : une mention légale, pas une explication.
   Elle nomme son secondaire, le lien qu'elle porte garde sa couleur d'action
   (plus haut dans ce fichier). */
.formulaire__nlpd {
  margin-block-start: 0.9rem;
  font-size: var(--t-petit);
  line-height: 1.45;
  color: var(--texte-secondaire);
}

/* Les crochets attendus par js/devis.js : [data-accuse] + .est-la + [data-echec]. */
/* Le succès prend le même mix que l'échec, et plus --action : l'action est le
   jaune depuis le 14.08, à 1,52:1 sur le papier du formulaire : « C'est reçu »
   sortait illisible à l'endroit exact où il doit rassurer. Le mix part de
   --valide (le vert) vers l'encre de la zone : 9,57:1 en jour, et la couleur
   dit toujours l'état. Latent aujourd'hui (/api/walkers n'existe pas encore),
   corrigé avant que l'endpoint n'arrive. */
.formulaire__accuse {
  margin-block-start: 1rem;
  color: color-mix(in srgb, var(--valide) 55%, var(--texte));
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 400ms var(--ease), transform 400ms var(--ease);
}
.formulaire__accuse.est-la { opacity: 1; transform: none; }
/* Braise brute : 3,33 sur nuit, 2,9 sur fosse — illisible. Éclaircie vers
   l'encre de la zone, elle fait 5,18 en nuit et 8,17 en jour. */
.formulaire__accuse[data-echec] {
  color: color-mix(in srgb, var(--alerte) 55%, var(--texte));
}

/* --- Le pied ------------------------------------------------------------- */
/* RECOMPOSÉ LE 16.08 : trois étages typographiques sur la nuit, pas une barre.
   La signature prend la voix display — le socle du document a le rang
   éditorial, même règle que le bandeau — et c'est elle qui fait le pied,
   pas une grille de colonnes. Le filet acier ne sépare que la signature des
   liens : la ligne de fin se distingue par la taille et la luminance,
   deuxième filet superflu. */
.pied {
  display: grid;
  justify-items: start;
  /* aminci le 16.08 (consigne de Nazaire : il prenait trop de place,
     surtout sous le formulaire) : les trois étages restent, l'air entre
     eux se resserre d'un bon tiers. */
  gap: 1.4rem;
  padding-block: 2.5rem max(2rem, env(safe-area-inset-bottom));
  padding-inline: var(--gutter);
}
.pied > * {
  inline-size: 100%;
  max-inline-size: var(--maxw);
  margin-inline: auto;
}
/* Le lockup : le wordmark dessiné puis la devise en serif, empilés sur le
   même axe. La marque mène, la devise suit un demi-ton plus bas. */
.pied__signature {
  display: grid;
  justify-items: start;
  gap: 0.8rem;
}
.pied__marque {
  display: block;
  inline-size: clamp(6.5rem, 5vw + 4rem, 9rem);
  block-size: auto;
}
.pied__devise {
  font-family: var(--font-display);
  font-weight: var(--wght-display);
  font-size: clamp(1.3rem, 1rem + 1.4vw, 1.9rem);
  line-height: 1.1;
  letter-spacing: 0.005em;
  color: var(--texte);
  text-wrap: balance;
}
.pied__liens {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 2.25rem;
  padding-block-start: 1.4rem;
  border-block-start: var(--hairline) solid var(--bordure);
  font-weight: var(--wght-emphase, 500);
}
/* Le pas vertical fait la cible tactile : des liens en ligne n'ont pas 44 px
   de haut, c'est l'espace autour qui les rend prenables au pouce. */
.pied__liens a { padding-block: 0.35rem; }
.pied__fin {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1.75rem;
  font-size: var(--t-petit);
  color: var(--texte-secondaire);
}
/* Les liens du pied ne se soulignent plus (16.08, consigne de Nazaire) : le
   soulignement jaune reste la langue des liens DANS le texte courant, mais
   ici les liens SONT le contenu, rangée par rangée — rien à distinguer. Le
   jaune revient au survol, seule trace de l'affordance. */
.pied__liens a,
.pied__fin a {
  color: inherit;
  text-decoration: none;
}
.pied__liens a:hover,
.pied__fin a:hover {
  text-decoration: underline;
  text-decoration-color: var(--action);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 2px;
}
.pied__fin a { padding-block: 0.35rem; }
/* Le crédit du studio se glisse au bout de la ligne, ferré à droite : présent,
   jamais en avant — l'anti-référence de PRODUCT.md tient, c'est une mention,
   pas un costume. */
.pied__studio { margin-inline-start: auto; }

/* --- WhatsApp flottant. Hors flux : classe de zone en dur dans le gabarit.
       Crochets attendus par js/whatsapp.js : [data-wa], [data-wa-lien],
       .bat, .saute, et un pied en .pied à mesurer. ----------------------- */
.wa {
  position: fixed;
  inset-inline-end: max(1rem, env(safe-area-inset-right));
  inset-block-end: max(1rem, env(safe-area-inset-bottom));
  z-index: 15;
}
/* SEUL composant du site qui ignore sa zone, et pour une raison physique :
   il survole les DEUX lumières sans jamais être repeint. Une pastille qui
   suivrait --fond disparaîtrait sur le fond dont elle prend la couleur —
   papier sur papier au jour, nuit sur nuit à la nuit. Une plaque de nuit à
   filet de craie tient les deux : 16,16 de plaque contre le papier, 11,99 de
   glyphe contre la nuit. */
.wa__lien {
  border-radius: var(--radius-pilule);
  display: grid;
  place-items: center;
  inline-size: 48px;
  block-size: 48px;
  background: var(--nuit);
  color: var(--craie);
  border: var(--hairline) solid var(--craie);
  text-decoration: none;
}
@keyframes wa-battement {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.06); }
}
@keyframes wa-saut {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
/* WCAG 2.2.2 : tout mouvement automatique qui dure PLUS DE CINQ SECONDES doit
   pouvoir être arrêté par l'utilisateur. `infinite` dépassait le seuil, et le
   site n'offre aucune commande de mouvement, prefers-reduced-motion ne compte
   pas, c'est un réglage système que le critère ne reconnaît pas comme la
   commande qu'il exige, et le :hover ci-dessous n'existe pas au doigt.
   Un seul cycle : 3,2 s pour le battement, 1,1 s pour le saut, sous le seuil
   des deux côtés. Le geste attire l'œil une fois, ce qu'il est censé faire, et
   ne bat plus en permanence dans le coin de treize pages.
   Un vrai bouton d'arrêt global reste un chantier séparé et plus large que ce
   bloc : la classe `anim` ne gouverne que les révélations ci-dessous et
   v7.js:26, tandis que whatsapp.js et sac.js lisent matchMedia une seule
   fois au chargement, un retrait de classe ne les atteindrait pas. */
@media (prefers-reduced-motion: no-preference) {
  .wa__lien.bat { animation: wa-battement 3.2s 1; }
  .wa__lien.saute { animation: wa-saut 1.1s 1; }
  .wa__lien.bat:hover, .wa__lien.saute:hover { animation: none; }
}

/* --- Révélations. Un seul geste, le plus discret des possibles : la page en
       porte des dizaines. Rien n'est masqué sans la classe `anim`, que
       l'amorçage ne pose que sous (prefers-reduced-motion: no-preference) —
       donc sans JS, sans amorçage, tout est là au premier octet. ---------- */
/* Contrat de js/v7.js, au caractère près : l'auteur pose [data-revele], le
   script pose [data-vu]. La feuille disait [data-reveler]/.vu — deux
   vocabulaires pour un seul geste, et rien ne se révélait jamais. */
/* 24 px et 900 ms depuis le 14.08, les valeurs d'Axel. GSAP les rejoue en
   power3.out et écrase ces déclarations en style inline dès qu'il prend la
   main ; elles restent la vérité du repli, quand ScrollTrigger n'est pas là et
   que c'est l'IntersectionObserver qui pose l'attribut. Les deux chemins
   doivent rendre le même geste, sinon le repli se voit. */
html.anim [data-revele]:not([data-vu]) { opacity: 0; transform: translateY(24px); }
html.anim [data-revele][data-vu] {
  opacity: 1;
  transform: none;
  transition: opacity 900ms var(--ease), transform 900ms var(--ease);
}

/* --- Impression : le one-pager n'est pas le livrable, seul le rapport
       s'imprime. On retire le chrome et on rend la page au papier. -------- */
@media print {
  .barre, .wa, .saut { display: none; }
  .manifeste,
  .manchette, .difference, .rue, .creneau {
    min-block-size: 0;
    padding-block: 1.5rem;
  }
}

/* --- LE BANDEAU DE FIN ---------------------------------------------------
   Identique sur toutes les pages sauf /walkers/ et /scan/, et c'est le sujet :
   un visiteur qui a lu trois pages doit retrouver le même geste au même
   endroit. Aucune variante de libellé, une seule clé de copie.
   SA LUMIÈRE : jour, treize fois sur treize depuis le 14.08. Le mécanisme
   genere.registreFin existe toujours mais FIN_NUIT (scripts/build.mjs) est
   vide : le pivot est parti avec la bascule sur la DA d'Axel, plus aucune page
   ne vit à la nuit, l'exception de l'accueil est tombée avec lui. L'arbitrage
   complet, l'historique du 13.08 compris, est écrit dans
   template/partie/bandeau.html ; le pied, lui, est nuit EN DUR (pied.html),
   il ne suit plus le bandeau.
   RIEN ICI NE NOMME UNE COULEUR, et c'est la preuve que la zone fait son
   travail : ces règles lisent --texte, --texte-secondaire et --fond, et
   suivraient une autre lumière sans être touchées. ----------------------- */
.bandeau {
  display: grid;
  grid-template-columns: minmax(0, var(--maxw));
  justify-content: center;
  row-gap: clamp(0.9rem, 0.7rem + 1vw, 1.6rem);
  padding-block: var(--section-y);
  padding-inline: var(--gutter);
  text-align: center;
}
.bandeau__question {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--wght-display);
  font-size: var(--t-h2);
  line-height: 1.15;
  text-wrap: balance;
}
/* Les deux gestes sur une ligne qui sait se casser : le bouton d'abord, le
   lien WhatsApp ensuite, jamais deux boutons côte à côte. Un seul appel à
   l'action a le droit d'être un bouton. */
.bandeau__gestes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(0.9rem, 0.7rem + 1vw, 1.75rem);
  margin: 0;
}
.bandeau__wa { color: var(--texte-secondaire); }
.bandeau__wa:hover { color: var(--texte); }
/* LE REFRAIN, ET C'EST ICI QU'IL TOMBE. « Pas d'emplacement. Pas de liste
   d'attente. On marche. » ferme les treize pages. Il sortait à 17 px en texte
   secondaire, c'est-à-dire au rang le plus bas de la page qu'il conclut.
   L'italique de la serif est sa voix, aux deux endroits où il paraît, ici et
   sur .probleme__devise. C'est la seule italique du site et elle a son propre
   fichier : sans lui le navigateur en synthétiserait une oblique géométrique.
   Il reste en secondaire et à la taille du corps : une signature n'est pas un
   titre, elle se dit en sortant. C'est la VOIX qui le distingue du texte
   courant, pas le volume. */
.bandeau__signature {
  margin: 0;
  font-family: var(--font-display);
  font-style: italic;
  color: var(--texte-secondaire);
  text-wrap: balance;
}

/* Le h1 en vitesse dossier. En sortant data-registre des sélecteurs de vitesse,
   plus rien ne donnait sa taille au titre d'une page de dossier : le seul
   endroit qui posait une taille de h1 était la liste du manifeste, et un titre
   de page sortait donc à la taille du texte courant sur cinq pages d'un coup.
   La vitesse doit porter sa hiérarchie comme elle porte sa densité. */
:where(.dossier, .methode, .demande) h1 { font-size: var(--t-h2); line-height: 1.15; }


/* ═══════════════════════════════════════════════════════════════════════════
   LES PAGES
   ═══════════════════════════════════════════════════════════════════════════

   Ce qui suit habille les classes que les onze gabarits RENDENT et que la
   feuille ne connaissait pas — 106 au relevé du 13.08. Elles ne sont pas
   traitées une par une : la moitié d'entre elles sont le même objet sous un
   autre nom, et c'est l'objet qui est écrit, pas le nom.

   TROIS OBJETS PORTENT TOUTE LA SECTION :
     le COUPLE   — un nom, ce qu'il y a dessous, un filet au-dessus. Il
                   s'appelle .paire à la méthode, .question aux questions,
                   .confid__bloc à la nLPD, .terrain aux terrains.
     la COLONNE  — .dossier ne pose que sa gouttière ; la largeur et le
                   centrage vivent sur .dossier__entete et .dossier__grille.
                   Tout enfant direct qui n'est ni l'un ni l'autre sortait en
                   pleine largeur : cinq pages affichaient DEUX bords gauches.
     l'ÉTIQUETTE — le registre des micro-capitales de socle.css. C'est là que
                   descendent les repères de lecture, pour que le contenu garde
                   le sommet (DESIGN.md, loi 2).

   AUCUN HEX, aucune ombre, aucun dégradé, aucun radius : filets 1 px en
   --bordure, et l'emphase par la luminance — un mot qui compte remonte de
   --texte-secondaire à --texte, il ne change pas de couleur.

   RIEN ICI NE CONNAÎT SA LUMIÈRE. Pas un sélecteur de zone, pas un
   data-registre : les deux jeux de rôles sont déjà rebindés par zones.css, et
   les mêmes règles tiennent le papier et la nuit. */

/* --- La colonne ---------------------------------------------------------- */
/* Mesuré à 1440 : le titre de /questions/ commençait à 100 px (colonne de
   1240 centrée, via .dossier__entete) et ses quatre familles à 39 px (pleine
   largeur). Deux bords gauches sur une même page, sur cinq pages.
   CETTE LISTE EST LA DÉFINITION DE « colonne » : tout ce qu'un dossier pose
   directement y figure, y compris les quatre blocs qui la tenaient déjà par
   leur classe voisine (.dossier__entete, .dossier__grille, .paires). On la
   relit d'un seul endroit, et un gabarit qui perdrait la classe voisine ne
   perdrait pas sa largeur avec elle. */
.dossier > .confid__entete,
.dossier > .confid__liste,
.dossier > .confid__maj,
.dossier > .questions__entete,
.dossier > .questions__famille,
.questions__famille > .questions__liste,
.dossier > .terrains__entete,
.terrains__ecart > .terrains__cas,
.dossier > .terrain,
.dossier > .terrains__ecart,
.dossier > .encadre {
  max-inline-size: var(--maxw);
  margin-inline: auto;
}

/* --- Le rythme ----------------------------------------------------------- */
/* Un .dossier pose var(--section-y) en haut ET en bas. Empilés — six sections
   sur /le-slot/, quatre sur /la-loop/, quatre à la nuit de l'accueil — ils en
   font le double, et il y avait une fenêtre et demie entre deux paragraphes
   qui se répondent. Deux dossiers qui se suivent ne respirent qu'une fois ; le
   premier de la page garde son entrée, le sélecteur ne vise que le suivant. */
.dossier + .dossier { padding-block-start: 0; }
/* SAUF QUAND UNE BANDE COMMENCE OU FINIT. Le repli ci-dessus a ete ecrit quand
   tous les dossiers d'une page partageaient le meme fond : effacer l'entree du
   suivant ne coutait rien, la frontiere etait invisible. Depuis l'alternance
   du 15.08, la frontiere se VOIT : un dossier en bande dont l'entree est a
   zero fait demarrer son texte au ras du bord gris, et le blanc qui suit une
   bande colle pareil. Chaque changement de fond rend donc son entree ; deux
   voisins du meme fond continuent de ne respirer qu'une fois. */
.dossier + .dossier.zone--creux,
.dossier.zone--creux + .dossier:not(.zone--creux) {
  padding-block-start: var(--section-y);
}

/* --- Le couple ----------------------------------------------------------- */
/* Même composition que .paire (la méthode), sous les deux autres noms que les
   gabarits lui donnent. .question porte déjà .paire, elle n'est pas ici. */
.confid__bloc,
.terrain {
  display: grid;
  align-content: start;
  gap: var(--pas-1);
  padding-block-start: var(--pas-1);
  border-block-start: var(--hairline) solid var(--bordure);
}

/* --- LES PLANS DE TERRAIN (accueil bloc 4 et /ou-on-marche/) --------------
   Les quatre vidéos marcheur du proto d'Axel, dans son cadre : portrait 3/4
   taillé au cover dans une source 1280x720 (v6.css:517-523), donc les deux
   sources d'un même plan, webm paysage et mp4 portrait, sortent identiques à
   l'écran. Rayon d'interface, pas de carte : le plan est un objet DANS la
   carte, comme les fausses interfaces du bloc 2. Le fond de carte tient
   l'attente du poster. Son rayon 20 à lui n'entre pas : le jeu n'a que trois
   rayons, et 16 est son rang. */
.terrain__plan {
  inline-size: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--radius-ui);
  background: var(--carte-basse);
}
/* Sur /ou-on-marche/ le terrain est un couple à deux pistes : le plan prend
   TOUTE la colonne du titre depuis le 15.08 (« la c'est pas bon aussi »,
   Axel) — la vignette de 18rem retombait dans le travers que l'accueil vient
   de quitter. Borné par la hauteur pour que le 3:4 ne fasse pas d'étage. */
.dossier .terrain .terrain__plan {
  max-inline-size: none;
  inline-size: 100%;
  block-size: min(58svh, 34rem);
  object-fit: cover;
}

/* --- LE CARROUSEL (accueil, bloc 4) ---------------------------------------
   Une bande à crans, plein bord, CSS seul : overflow + scroll-snap, aucun
   script. Le padding-inline recale la première carte sur la colonne du site
   (le max() choisit entre la gouttière et le bord calculé de --maxw), et la
   bande déborde du viewport des deux côtés : on voit qu'il y a une suite, ce
   qu'une grille de carrés ne dira jamais.
   Les cartes de terrain gardent leur texte sous le plan ; les ambiances du
   tournage n'ont que le plan. Le couple filet + retrait de .terrain n'a pas
   de sens dans une bande : il tombe ici. */
/* --- LA CONSTELLATION (accueil, bloc 4) -----------------------------------
   REFONTE du 15.08 au soir, référence Christie Hemm Klok, choix de Nazaire ;
   Axel avait rendu son verdict sur le carrousel (« les gens ne vont jamais
   swipe »). Plus rien à swiper : les preuves sont POSÉES sur le blanc dans un
   champ que le scroll vertical traverse, tailles et hauteurs décalées, comme
   des tirages sur une table. Zéro chrome, zéro rayon : le footage à nu sur le
   papier, la grammaire de la page. Les décalages sont des marges hautes, pas
   des positions : le champ reste un flux, il se replie tout seul. */
.constellation {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: clamp(1rem, 2vw, 2rem);
  row-gap: clamp(2.5rem, 6svh, 4.5rem);
  margin-block-start: var(--pas-3);
  text-align: start;
}
.constellation > li {
  display: grid;
  align-content: start;
  gap: 0.6rem;
}
.constellation .terrain__plan,
.constellation img {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 0;
  background: var(--carte-basse);
}
.constellation > .terrain {
  border-block-start: 0;
  padding-block-start: 0;
}
.constellation .terrain__corps { max-inline-size: 36ch; }
/* Le champ à 900+ : deux preuves par rangée visuelle, jamais à la même
   hauteur, les ambiances plus petites entre elles. L'ordre du DOM reste
   l'ordre de lecture : terrain, ambiance, terrain, terrain, ambiance,
   terrain. */
@media (width >= 56.25rem) {
  .constellation > li:nth-child(1) { grid-column: 1 / 6; }
  .constellation > li:nth-child(2) { grid-column: 8 / 11; margin-block-start: 24svh; }
  .constellation > li:nth-child(3) { grid-column: 7 / 12; margin-block-start: -10svh; }
  .constellation > li:nth-child(4) { grid-column: 2 / 6; margin-block-start: -18svh; }
  .constellation > li:nth-child(5) { grid-column: 6 / 9; margin-block-start: 14svh; }
  .constellation > li:nth-child(6) { grid-column: 9 / 13; }
}
/* Sous 900 : un flux qui alterne les rives, les ambiances plus étroites. */
@media (width < 56.25rem) {
  .constellation > li { grid-column: 1 / 11; }
  .constellation > li:nth-child(even) { grid-column: 3 / 13; }
  .constellation > .terrain--ambiance { grid-column: 4 / 10; }
}

/* --- /conditions-generales/ ----------------------------------------------
   La page des CGV n'invente rien : des dossiers, des entêtes, la mesure de
   lecture. Le numéro d'article est en mono, comme toute donnée du site : un
   texte contractuel se cite par son numéro, c'est sa seule mesure. La liste
   des définitions reprend la composition du couple de /confidentialite/. */
.cgv__numero { color: var(--texte-secondaire); }
.cgv__definitions {
  display: grid;
  gap: var(--pas-2);
  margin-block-start: var(--pas-1);
}
.cgv__definition {
  display: grid;
  gap: 0.2rem;
  max-inline-size: var(--mesure-nuit);
}
.cgv__definition dt { font-weight: var(--wght-titre); }
.cgv__definition dd { color: var(--texte-secondaire); }



/* LE COUPLE EN DEUX PISTES, et le filet redevient honnête.
   MESURÉ sur /confidentialite/ à 1440 : le filet courait sur 1240 px et la
   réponse en dessous sur 615. La moitié droite de chaque trait ne montrait
   rien — dix fois de suite, sur la page qu'un visiteur ouvre justement parce
   qu'il se méfie. Un filet mesure ce qu'il introduit ; ici il mesurait le vide.
   Le nom passe à gauche, ce qu'il y a dessous passe à droite, et le trait
   couvre enfin une vraie composition. Même geste pour les quatorze questions,
   les paires de la méthode et les quatre terrains : c'est un seul objet sous
   quatre noms, le fichier le dit déjà, il est temps qu'il le montre.
   Le premier enfant EST le nom dans les trois gabarits (dt, h2 ou h3) : la
   règle se pose sur la position, pas sur la balise, et un gabarit qui changerait
   de balise ne perdrait pas sa composition.
   .paire NU N'Y EST PAS, et c'est délibéré : le bloc de la méthode porte
   l'arbitrage « refus / garantie en deux temps EMPILÉS, jamais un tableau à
   deux colonnes », et sa copie n'est pas écrite — les six dt/dd de
   /comment-on-estime/ sont encore des [à écrire]. Tant qu'on ne sait pas si
   ces paires nomment un signal ou opposent deux positions, l'interdit écrit
   l'emporte. .question, elle, porte .paire mais a sa copie : c'est une
   question et sa réponse, un nom et ce qu'il y a dessous, pas une opposition. */
@media (width >= 56.25rem) {
  .question,
  .confid__bloc,
  .dossier > .terrain {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(2rem, 1.5rem + 2vw, 4rem);
    row-gap: var(--pas-2);
    align-items: start;
  }
  .question > :first-child,
  .confid__bloc > :first-child,
  .dossier > .terrain > :first-child {
    grid-column: 1;
    grid-row: 1 / -1;
  }
  .question > :not(:first-child),
  .confid__bloc > :not(:first-child),
  .dossier > .terrain > :not(:first-child) {
    grid-column: 2;
  }
}

/* --- Les ancres de page --------------------------------------------------
   Sections nommées par leur page et rien d'autre : la vitesse donne la
   densité, la zone donne la lumière, .dossier__entete donne la colonne. Elles
   ne peignent RIEN, et pour .tait c'est une consigne — le bloc qui dit ce que
   le rapport ne mesure pas reste au rang typographique du bloc qui le précède,
   l'encadrer le ferait lire comme une clause (css/rapport.css le documentait
   déjà pour .dedans, .tait et .arrivee).
   Ce qu'elles portent est leur seul rôle commun : elles sont des cibles de
   lien, y compris depuis une autre page, et une cible atterrit sous la barre
   fixe. html porte bien un scroll-padding, mais il se perd dès qu'un
   conteneur intermédiaire défile ; scroll-margin voyage avec la cible. */
.slot__pourquoi,
.slot__deroule,
.slot__compris,
.slot__minimum,
.slot__rapport,
.loop__pourquoi,
.loop__mecanique,
.loop__plafond,
.loop__exclusivite,
.loop__compris,
.loop__lancement,
.tait,
.arrivee,
.probleme,
.promesse,
.sorties,
.atouts,
.delai,
.maison,
.live,
.confid,
.questions,
.terrains,
.preuves,
.scan,
.question {
  scroll-margin-block-start: calc(var(--barre-h) + 1rem);
}

/* --- Les titres de section nommés ----------------------------------------
   Aucune taille ici : .manifeste et .dossier la donnent déjà à h1, h2 et h3.
   Ces classes existent pour que le gabarit puisse nommer sa ligne, et deux
   d'entre elles servent sur deux pages à la fois (.terrains__titre est un h2
   de l'accueil et le h1 des terrains). Leur seul besoin commun est la mesure :
   un titre de dix mots ne court pas sur 1240 px. */
.probleme__titre,
.promesse__titre,
.sorties__titre,
.terrains__titre,
.atouts__titre,
.delai__titre,
.maison__titre,
.questions__titre,
.confid__titre,
.scan__titre {
  max-inline-size: 24ch;
}

/* --- Les chapeaux et les lignes de sortie -------------------------------- */
/* Un chapeau se lit d'un souffle : mesure du manifeste, interligne serré. */
.questions__sous,
.terrains__sous,
.confid__chapeau,
.scan__corps {
  max-inline-size: var(--mesure-jour);
  font-size: var(--t-lead);
  line-height: 1.35;
}
/* La punchline de /walkers/ n'est pas un titre : c'est un strong à la taille
   du chapeau, la copy l'écrit ainsi — trois verbes qui tiennent sur une ligne,
   donc pas de mesure, elle n'en a jamais besoin. Le gras vient de la balise,
   la zone lui donne déjà --texte. */
.walkers__punch {
  font-size: var(--t-lead);
  line-height: 1.35;
}

/* Le lien qui ferme un bloc. Il suit un paragraphe, il ne colle pas dessous. */
.promesse__lien,
.maison__lien,
.terrains__lien,
.encadre__lien,
.carte__lien,
.live__ligne,
.scan__second {
  margin-block-start: 0.6rem;
  font-size: var(--t-base);
  line-height: var(--lh-texte);
}

/* --- La devise, la chute, la pointe --------------------------------------
   Les fins de bloc que la copy écrit pour qu'on s'en souvienne.

   ELLES SE DISTINGUAIENT PAR LA LUMINANCE, ELLES SE DISTINGUENT MAINTENANT
   PAR LA GRAISSE. Le cran qu'elles gagnaient, remonter de --texte-secondaire
   à --texte, n'existe plus : le texte courant se lit désormais à --texte
   partout (voir zones.css, partie 4), et ces quatre règles seraient devenues
   quatre déclarations sans effet, avec un commentaire qui aurait menti.
   La chute reprend donc son cran sur l'axe qui reste libre, celui que
   .terrain__pointe utilise déjà juste dessous pour exactement le même objet :
   graisse 500, l'emphase que DESIGN.md réserve au texte. Le contraste n'est
   plus obtenu en éteignant l'explication qui précède.

   .terrain__amorce A QUITTÉ CETTE LISTE : ce n'est pas une chute, c'est le
   chapeau d'un terrain, la ligne qui ouvre le bloc et l'explique. Elle est
   au rang de son corps, et c'est la règle : dans un bloc, l'explication et le
   texte qui la suit se lisent au même volume. */
.probleme__chute,
.encadre__chute,
.delai__chute,
.terrain__pointe {
  font-weight: var(--wght-medium);
}
/* Le refrain de l'accueil — « Pas d'emplacement. Pas de liste d'attente. On
   marche. », revient mot pour mot en fin de page. LE COMMENTAIRE D'HIER SE
   TROMPAIT D'ENDROIT : il disait que .bandeau__question le posait en display,
   alors que .bandeau__question porte une autre phrase et que le refrain sort
   sur .bandeau__signature. Les deux occurrences étaient donc basses, et le
   refrain descendait en fin de page au lieu de revenir.
   Les deux prennent maintenant la même voix, l'italique de la serif, et la
   même règle : ni l'une ni l'autre ne concurrence le h2 de son bloc, c'est le
   changement de voix qui les distingue du texte courant. Ici le refrain garde
   un cran de taille en plus, c'est sa première apparition, celle qui doit
   rester en mémoire jusqu'au bas de la page. */
.probleme__devise {
  max-inline-size: none;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--wght-display);
  font-size: var(--t-h3);
  line-height: 1.2;
  color: var(--texte);
}

/* --- Les corps ------------------------------------------------------------
   Dans un manifeste, :where(.manifeste…) p pose var(--t-lead) à TOUT
   paragraphe : c'est la voix d'une affirmation par écran, et c'est la mauvaise
   dans une grille de quatre cartes, où 23 px sur une colonne de 280 px cassent
   la ligne tous les trois mots. Ces deux corps-là redescendent au texte
   courant ; les autres gardent la voix de leur vitesse. */
.carte__corps,
.terrain__corps {
  font-size: var(--t-base);
  line-height: var(--lh-texte);
}

/* LA MESURE D'UN CORPS NOMMÉ. :where(.dossier…) p la pose déjà, mais elle rate
   tout ce qui n'est pas un p : les dix réponses de la nLPD sont des dd, et
   elles sortaient sans borne d'aucune sorte. Écrite sur le nom du bloc, elle
   ne dépend plus de la balise — et les deux vitesses se relisent côte à côte.
   Le tri se fait sur la vitesse de la section, jamais sur sa lumière. */
.confid__val,
.question__reponse,
.encadre__corps,
.delai__corps,
.maison__corps { max-inline-size: var(--mesure-nuit); }
.probleme__corps,
.promesse__corps { max-inline-size: var(--mesure-jour); }

/* --- La barre de preuve de l'accueil -------------------------------------
   Quatre faits, une bande fine, jamais un écran : la section n'a ni .manifeste
   ni .dossier, et c'est voulu. Deux filets en font une bande ; sans eux elle
   flotte entre deux hauteurs de fenêtre. */
.preuves {
  padding-block: clamp(1rem, 0.8rem + 1vw, 1.75rem);
  padding-inline: var(--gutter);
}
.preuves__scene {
  max-inline-size: var(--maxw);
  margin-inline: auto;
}
.preuves__liste {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem clamp(1.25rem, 0.9rem + 2vw, 3rem);
  padding-block: 0.9rem;
  border-block: var(--hairline) solid var(--bordure);
}
/* CES QUATRE LIGNES SONT LE PRODUIT. « Écran 1920 × 1080 », « Lisible à
   3 mètres », « Trajet géolocalisé », « Rapport en fin de créneau » : ce sont
   les seuls faits vérifiables de la page, les seuls qu'un concurrent ne peut
   pas recopier, et les deux derniers sont la promesse entière du site. Ils
   sortaient en `--t-petit` sur `--texte-secondaire`, c'est-à-dire dans la
   composition d'une mention légale, sur une bande de 1240 px. Au téléphone ils
   se rangeaient en 2 × 2 à 13 px et se lisaient comme une note de bas de page.
   Ils passent au corps de texte, en encre pleine. La bande ne devient pas un
   titre pour autant : les filets et le pas restent, c'est le rang qui change. */
.preuves__item {
  font-size: var(--t-base);
  color: var(--texte);
}

/* --- La carte de sortie (accueil, bloc 3) --------------------------------
   Deux cartes de même poids, chacune cliquable en entier. Le gabarit demande
   explicitement que le lien s'étire par le CSS plutôt que d'imbriquer la carte
   dans une ancre : un lecteur d'écran annoncerait sinon tout le texte comme
   libellé de lien. Le titre sortait à 17 px, sous son propre corps. */
/* LES DEUX OFFRES. Elles étaient cernées d'un filet sur un angle vif ; elles
   deviennent les deux grandes cartes arrondies d'Axel (v6.css:480-490), pleines
   et sans bordure. Le filet a disparu parce qu'il n'a plus rien à faire : à
   rayon 28 sur un aplat, c'est la FORME qui découpe l'objet, et un trait
   par-dessus ne fait que redire le bord.
   --carte-basse et non --carte : ces deux-là sont posées sur le blanc de la
   page, pas sur une bande, donc elles se retirent au lieu de remonter.
   Le survol soulève, comme les boutons, et pour la même raison : plus rien
   dans cette page ne dit « actif » par la couleur. */
.carte {
  position: relative;
  display: grid;
  align-content: start;
  gap: 0.875rem;
  padding: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  background: var(--carte-basse);
  border-radius: var(--radius);
  transition: transform 0.3s var(--ease);
}
@media (prefers-reduced-motion: no-preference) {
  .carte:hover,
  .carte:focus-within { transform: translateY(-4px); }
}
.carte__promesse { font-size: var(--t-h3); }

/* --- /la-loop/ EST LA PAGE SOMBRE DU SITE (23.08) -------------------------
   Le <body> ouvre en zone-jour dans la tete commune, que les treize pages
   partagent : on ne peut pas le basculer par page sans lui donner un crochet.
   On peint donc la RACINE, comme le rapport le fait deja
   (`html:has(.rapport-page)`), sinon le papier de <html> reparait entre les
   sections et sous le pied. Meme motif, meme raison, ecrit au meme endroit que
   les autres exceptions de page. */
html:has(body[data-page="loop"]) { background-color: var(--nuit); }
body[data-page="loop"] { background: var(--nuit); }

/* --- LA CARTE DE L'OFFRE PASSE EN NUIT (22.08) ----------------------------
   La largeur disait déjà laquelle des deux porte l'offre. La lumière le dit
   maintenant : sur une page blanche de bout en bout, UN SEUL objet est sombre,
   et il tombe à l'endroit exact où le visiteur choisit.
   C'est la loi 3 de DESIGN.md appliquée, pas une exception : « la couleur est
   un événement, jamais des fonds ». Un événement, c'est une petite surface qui
   arrive une fois. Et ce n'est pas un précédent : l'aperçu de relevé du bloc 2
   et le pied sont déjà des objets de nuit posés dans le jour.
   ELLE NE SE PEINT PAS À LA MAIN. `.zone-nuit` rebinde les treize jetons d'un
   coup — fond, texte, filets, action, alerte — donc le fond de carte, la
   couleur du corps, le soulignement du lien et le liseré de la pastille
   suivent sans qu'aucune valeur soit écrite ici. Peindre à la main aurait
   marché aujourd'hui et divergé au premier changement de palette. */
.carte--offre {
  /* --nuit et pas --carte-basse : la fosse est le fond d'une carte POSÉE SUR
     une bande de nuit. Ici la carte est l'événement, elle prend le noir plein.
     16,97:1 contre le papier de la page. */
  background: var(--nuit);
}
/* Le badge s'inverse : écrit en nuit sur craie, il devenait illisible sur la
   nuit de sa carte. En jaune il fait ce pour quoi le jaune existe — et c'est
   le seul endroit du site où il a le droit de porter du texte, 11,19:1. */
.zone-nuit .badge-lancement {
  background: var(--signal);
  color: var(--nuit);
}
/* Le liseré de la pastille suit sa carte, pas la carte claire d'à côté. */
.carte--offre .pastille--carte { box-shadow: 0 0 0 3px var(--nuit); }

/* --- LES DEUX SORTIES NE SONT PAS JUMELLES (21.08) ------------------------
   Elles sortaient identiques : même largeur, même aplat, même gris, même
   micro-étiquette, même titre gras, même flèche soulignée. Deux cartes égales
   côte à côte, c'est la grille de cartes que tout gabarit produit, et elle
   tombait pile au moment où le visiteur CHOISIT. Une page qui ne penche pas
   ne décide pas à sa place, elle le laisse peser lui-même deux pavés de texte.
   Le déséquilibre n'est pas décoratif, il est vrai : la Loop est l'offre qu'on
   lance, celle qui revient tous les mois, celle qui porte le badge. Le Slot
   reste entier, il cesse juste de prétendre au même poids.
   Sept colonnes contre cinq : assez pour que l'œil sache où aller, pas assez
   pour que le Slot ait l'air d'un reste. En dessous du palier, l'ordre du
   gabarit reprend la main et les deux s'empilent à égalité — sur une colonne,
   c'est la position qui hiérarchise, pas la largeur. */
@media (width >= 56.25rem) {
  #sorties .dossier__grille { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  /* PAS DE SECOND APLAT. Essayé, mesuré, retiré : `--carte` vaut le blanc de
     la page en zone jour, et la carte lourde devenait blanc sur blanc — elle
     disparaissait au lieu de ressortir. La largeur et le badge suffisent à
     dire laquelle des deux porte l'offre ; un gris de plus n'aurait fait
     qu'ajouter une valeur à une page qui en a déjà assez. */
}
.carte__lien a::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* --- La section « live » de l'accueil (bloc 5, la nuit) -------------------
   Son h2 est porté par le pivot juste au-dessus : la section reprend donc au
   niveau en dessous, et ses deux intertitres sont des h3. Sans règle, ils
   sortaient à var(--t-h3) — c'est-à-dire à la taille exacte des .bloc__titre
   qu'ils coiffent, portés eux par des h4. Le titre d'une section pesait autant
   qu'un titre de puce.
   Le premier ouvre la section : il prend le rang de ses voisines de page
   (.atouts, .delai, .maison ouvrent toutes sur var(--t-h2)). Le second est une
   addition — « En plus, si votre campagne a un QR code » ne pèse pas ce que
   pèse « Ce que mlsign live enregistre » — et il reste au rang du sous-bloc. */
/* LA VOIX SUIT LE RANG, PAS LA BALISE. C'est un h3 par la structure du
   document, et socle.css donne Switzer aux h3. Il est au rang h2 par la
   composition, comme le dit le paragraphe ci-dessus, et il sortait donc en
   suisse 700 à 64 px au milieu d'une page où tout ce qui pèse ce poids est en
   serif : le seul titre du site à démentir sa propre échelle. La règle est
   nommée ici plutôt que dans socle.css parce que c'est une exception de
   composition, pas une loi d'élément. */
/* IL REDESCEND D'UN RANG LE 14.08. Il prenait --t-h2 parce que le pivot portait
   le titre de la section depuis l'extérieur : sans lui, la section ouvrait sur
   un h3 et il fallait bien que quelqu'un pèse. Le pivot est parti, sa copy est
   revenue dans la section sous un vrai h2, et deux titres au même rang à six
   lignes d'écart se lisaient comme deux sections.
   Il garde la voix éditoriale, c'est un titre, pas un intertitre de bloc, et
   c'est le corps qui le range sous le h2. */
.live__titre {
  font-family: var(--font-display);
  font-weight: var(--wght-display);
  font-size: var(--t-h2-dossier);
  line-height: 1.15;
  margin-block-start: var(--pas-3);
}
/* Le second garde donc la taille du .bloc__titre qu'il coiffe, et c'est le
   filet et l'air qui les séparent : deux tailles voisines se lisent moins
   bien qu'un trait. C'est le couple, encore une fois. */
.live__qr {
  gap: var(--pas-1);
  margin-block-start: var(--pas-3);
  padding-block-start: var(--pas-2);
  border-block-start: var(--hairline) solid var(--bordure);
}
/* Le second redescend au rang du sous-bloc, donc il rend aussi la voix : à
   --t-h3, la serif se lit comme une coquille, pas comme une hiérarchie. */
.live__qr .live__titre {
  font-family: var(--font-texte);
  font-weight: var(--wght-titre);
  font-size: var(--t-h3);
}

/* --- LA MARQUE DE LA DONNÉE ----------------------------------------------
   La seule couleur de l'accueil sous le pivot, et le seul endroit du site où
   l'on répond « oui » à la question « qu'est-ce qui, ici, est une donnée qui
   vit ? ». Les trois autres sections de nuit (#atouts, #delai, #maison) ne
   portent aucun relevé : ce sont des arguments et une présentation, elles
   restent en craie. Si tout se colorait, plus rien ne serait un événement
   (DESIGN.md, loi 3).

   L'ATOME EST CELUI DE LA FRISE DU RAPPORT, au pixel près : 1,75 rem sur 8 px,
   les dimensions de .frise__puce::before dans css/rapport.css. Le lecteur qui
   ouvre ensuite /le-rapport/ retrouve la même forme sur les pistes ; la page
   d'accueil lui a appris la grammaire sans lui en parler. Ce n'est pas une
   puce de liste : c'est une période de diffusion, en petit.

   TROIS MARQUES, TROIS NATURES :
   · segment plein en halo — un relevé. Le trajet et la diffusion horodatée
     sont enregistrés, ils ont eu lieu.
   · segment creux et rayé — le potentiel d'exposition. C'est TraceMark, un
     calcul, pas un enregistrement, et le creux est exactement le traitement
     que .frise__creneau--nonattribue donne dans le rapport à ce qui n'est pas
     prouvé. L'encadré d'honnêteté le dit en toutes lettres juste dessous : la
     marque n'annonce rien qui ne soit écrit, elle ne fait que le montrer plus
     tôt.
   · le point braise du scan a EXISTÉ ici (un scan est un instant, pas une
     période) ; Axel l'a fait retirer le 15.08 (« faut virer le machin ») :
     centré dans l'entête du bloc QR, il se lisait comme un débris, pas comme
     une grammaire. Les deux segments restent ; le bloc scan n'a plus de
     marque.

   Contrastes MESURÉS sur --fond nuit #0C1620 : halo 6,44:1 et braise 3,33:1 —
   au-dessus du 3:1 que WCAG 1.4.11 demande à un élément graphique porteur de
   sens. Aucune des trois ne porte d'information absente du texte : ce sont des
   ::before à contenu vide, ils ne s'annoncent pas et n'ont rien à annoncer.

   Zéro rayon, y compris sur le point : le registre brand n'en a pas
   (DESIGN.md, « Forme »). Une pastille ronde ici serait du registre produit. */
.live__signal::before {
  content: "";
  display: block;
  block-size: 8px;
}

/* LA MARQUE EST UN TROISIÈME ENFANT DANS UNE GRILLE QUI EN COMPTE DEUX.
   .dossier__grille donne ses rangées aux blocs à deux enfants (subgrid, plus
   haut dans ce fichier) pour que les corps d'une rangée partent tous de la même
   ligne. Un ::before ne compte pas pour :nth-child — le bloc reste éligible et
   garde ses DEUX rangées, mais il a maintenant trois éléments : le titre et le
   corps tombaient dans la même, superposés. Relevé au navigateur à 1440 avant
   correction, sur les trois blocs de la section.
   Trois rangées, donc, et les trois blocs de #live les prennent ensemble : les
   marques s'alignent comme les titres et les corps. Sous @supports, comme la
   règle qu'elle prolonge — sans subgrid, .bloc empile déjà ses trois éléments
   tout seul et n'a besoin de rien. */
@supports (grid-template-rows: subgrid) {
  .live > .dossier__grille > .live__signal { grid-row: span 3; }
}
.live__signal::before {
  inline-size: 1.75rem;
  background: var(--donnee);
}
/* Même spécificité que la règle ci-dessus, elle gagne par l'ordre de source. */
.live__signal--estime::before {
  background: var(--survol);
  outline: var(--hairline) dashed var(--bordure);
  outline-offset: calc(var(--hairline) * -1);
}

/* --- L'encadré d'honnêteté (accueil, bloc 5) ------------------------------
   Le seul encadré du site, et il ferme le bloc qui promet : il dit ce que la
   mesure n'est pas. Un filet, de l'air, rien d'autre — pas de fond, la couleur
   est un événement et un aplat n'en est pas un. */
/* SON FILET N'EST PAS DÉCORATIF, DONC IL NE PREND PAS --bordure. C'est le bloc
   qui dit ce que la mesure n'est pas, « TraceMark n'observe aucun regard »
   celui qui nous protège le jour où un annonceur lit le chiffre comme une
   audience. Il sortait cerné d'acier à 2,21:1 sur la nuit, une valeur que
   zones.css:64-65 qualifie lui-même de « filet décoratif SEULEMENT ».
   L'encre de la zone le pose à 11,99 : le cadre se voit, donc le contenu se lit
   comme encadré. Épaisseur inchangée, c'est la couleur qui manquait, pas le
   trait, et --hairline vaut 1 partout. Même geste que .rapport__mention. */
.encadre {
  border-radius: var(--radius);
  display: grid;
  align-content: start;
  gap: 0.5rem;
  margin-block-start: clamp(1.75rem, 1.25rem + 2vw, 3rem);
  padding: clamp(1.25rem, 1rem + 1.5vw, 2rem);
  border: var(--hairline) solid var(--texte);
}
.encadre__titre { font-size: var(--t-h3); }

/* --- LE SAC QUI SE FRACTIONNE (accueil : hero et bloc 8) -------------------
   42 images de 1280 × 720, le sac fermé qui pivote et s'ouvre sur ses pièces,
   entraînées au défilement par js/sac.js.

   IL EST INCRUSTÉ, PAS POSÉ DANS UNE BOÎTE, et c'est tout l'effet : aucun
   cadre, aucune surface sous lui, rien qui le contienne. La séquence porte une
   VRAIE couche alpha, fabriquée en amont (voir le gabarit) — l'objet se pose
   donc aussi bien sur le papier du hero que sur la nuit du bloc 8, sans mode de
   fusion et sans rien savoir de son fond.

   IL Y A EU UN `mix-blend-mode: screen` ICI, ET IL N'Y EST PLUS. Il résolvait
   le noir du rendu contre un fond sombre, ce qui marchait — mais seulement sur
   la nuit, et au prix de trois propriétés interdites sur tout ancêtre (opacity,
   transform, isolation : chacune crée un contexte d'empilement, le fusionnement
   retombe sur du blanc et le rectangle noir réapparaît). Le détourage supprime
   la règle ET sa fragilité : ne pas le remettre, il délaverait maintenant
   l'objet sur le papier.

   PAS DE HAUTEUR IMPOSÉE, pas de `object-fit`. L'image porte son width et son
   height dans le gabarit : le rapport est connu avant le décodage, la page ne
   sursaute pas, et la figure prend simplement la largeur de sa colonne. */
.sac {
  min-inline-size: 0;
  /* La figure est un objet, pas une illustration de paragraphe : elle se cale
     sur la colonne et n'hérite pas de la mesure de lecture du dossier. */
  margin-block-start: var(--pas-3);
}

/* --- LE PLAN DU HERO ------------------------------------------------------
   Le dessin n'est pas peint, il est DÉCOUPÉ : le fichier ne porte aucune
   couleur, tout son tracé vit dans sa couche alpha, et on l'applique en masque
   sur un aplat de `currentColor`. Le plan prend donc l'encre de sa zone tout
   seul — un seul fichier pour les deux lumières, aucun mode de fusion, aucun
   second export à tenir à jour. C'est le même principe que le logotype : une
   forme, pas une image.

   LE @supports N'EST PAS UNE POLITESSE. Sans masque, `background: currentColor`
   tout seul peint un RECTANGLE D'ENCRE PLEINE de neuf cents pixels de haut en
   travers du hero. Un navigateur qui ne sait pas masquer doit donc ne rien
   voir, pas voir un bloc noir : le fond et le masque se posent ensemble, sous
   la même condition, ou pas du tout.

   L'alpha est quantifiée à 16 niveaux à la fabrication : sur du trait, c'est
   invisible à 200 % et le fichier passe de 407 à 172 Ko — l'anticrénelage était
   tout le coût. */
@supports ((mask-image: url("#")) or (-webkit-mask-image: url("#"))) {
  .plan {
    background: currentColor;
    -webkit-mask: url("/assets/image/plan-sac2.94196a71.svg") center / contain no-repeat;
            mask: url("/assets/image/plan-sac2.94196a71.svg") center / contain no-repeat;
  }
}

/* --- LE PLAN QUI DEVIENT L'OBJET (hero) -----------------------------------
   Deux calques dans la MÊME boîte : le plan technique et le rendu
   photoréaliste. Ils se superposent parce que c'est le même objet éclaté dans
   la même pose, et parce que le recadrage est cuit dans plan-sac.webp, déjà
   posé dans le repère du rendu. Aucun calage ici, et c'est voulu : un calage en
   CSS se décorrélerait le jour où l'un des deux fichiers change.
   MESURÉ : 93,6 % du trait du plan dans la silhouette du rendu sans marge.

   UN SAC 3D QUI TOURNAIT A OCCUPÉ CETTE PLACE ET EN EST PARTI. Il gagnait la
   netteté sur Retina, mais le mesh venait d'une reconstruction depuis une seule
   image : sangles en lambeaux et texture tachée. Le gain reste valable, il
   demande un vrai modèle. */
.sac--calques { position: relative; aspect-ratio: 1600 / 1118; }
/* Sur un téléphone, la vue éclatée tenait dans les marges de la colonne : un
   timbre pour la seule pièce de la page qui montre le produit lui-même. Elle
   prend le bord à bord ; le ratio ne bouge pas, il vient du gabarit, et le
   canvas suit sa boîte sans se déformer. */
@media (width < 40rem) {
  .maison .sac--calques { margin-inline: calc(50% - 50vw); }
}
.sac--calques > .plan,
.sac--calques > .sac__vue,
.sac--calques > .sac__toile {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
}
.sac--calques > .plan { opacity: 0; }
/* Sous .anim, l'état peint AVANT que js/sac.js ne s'exécute est « plan seul ».
   Sans la seconde règle, les deux calques sortent opaques le temps d'un rendu
   et l'on voit l'objet en transparence derrière son propre plan. */
.anim .sac--calques > .plan { opacity: 1; }
.anim .sac--calques > .sac__vue { opacity: 0; }

/* L'objet du hero prend toute la colonne et part du même axe que le titre :
   plafonné et centré, il flottait à 108 px du bord pendant que cinq lignes
   au-dessus étaient ferrées à gauche. */
.manchette__objet { margin-block-start: var(--pas-3); }

/* L'OBJET DU HERO. Aucun fond, aucun rembourrage, aucun cadre — il est incrusté
   dans le papier de la manchette. Une SCÈNE SOMBRE A ÉTÉ ESSAYÉE ICI ET
   REJETÉE : elle rendait l'objet à une illustration dans un rectangle, et le
   rectangle est exactement ce que l'incrustation supprime.

   IL PREND TOUTE LA COLONNE et part du même axe que le titre. Plafonné à 64rem
   et centré, il flottait à 108 px du bord gauche pendant que le kicker, le
   titre, le chapeau, les boutons et la réassurance sont tous ferrés sur le même
   axe : un objet centré sous cinq lignes ferrées se lit comme un élément
   rapporté.

   MESURÉ sur la séquence : l'objet occupe 65 % de la largeur du cadre et 88 %
   de sa hauteur. Aucun recadrage à faire — il n'y a rien à gagner en hauteur, et
   rogner les côtés le couperait dès qu'il s'ouvre. Les marges latérales sont
   maintenant transparentes : elles ne coûtent rien à personne. */
.manchette__objet {
  margin-block-start: var(--pas-3);
}
.sac__vue,
.sac__toile {
  inline-size: 100%;
  block-size: auto;
}

/* LA RELÈVE PAR LE CANVAS. js/sac.js fabrique le canvas et pose .sac--toile sur
   la figure quand les images sont décodées — pas avant : tant que la séquence
   n'est pas tenue, c'est l'image du gabarit qui est juste, et un canvas vide ne
   remplacerait une image correcte que pour faire un trou.
   Le canvas existe parce que changer le `src` d'une <img> vide sa boîte le
   temps du décodage : à vingt-sept images qui défilent, ça CLIGNOTE. drawImage
   peint depuis une image déjà décodée, il n'y a plus de trou possible.
   Les deux nœuds ne coexistent jamais à l'écran, et l'alt reste dans le
   gabarit : le canvas en fait son aria-label à l'exécution. */
.sac--toile .sac__vue { display: none; }

/* LE COUPLE TEXTE / OBJET A ETE DEFAIT LE 14.08, et son argument est tombe
   avec la composition de la page. Il posait le texte a gauche sur sa mesure de
   lecture et l'objet a droite, pour « occuper le vide que .maison__corps
   laissait a droite ». Depuis que la page compose au centre, ce vide n'existe
   plus : le texte est centre dans 780 px, ses marges sont symetriques, et la
   demi-colonne de droite n'etait plus un vide a remplir mais une asymetrie
   posee au milieu d'une page qui n'en a aucune autre.
   La section empile donc comme toutes les autres : entete centree, objet en
   dessous sur la colonne entiere. Le sac y gagne, il passe d'une demi-colonne a
   la pleine largeur, et c'est la section qui dit « le materiel et le logiciel
   faits maison » : les pieces se voient mieux grandes.
   .dossier__scene reste le conteneur, pour la raison qui n'a pas change : une
   section de zone peint `background: var(--fond)` sur elle-meme, lui poser une
   largeur maximale plafonnerait sa bande et le fond de <html> reviendrait de
   chaque cote. */
.maison__scene > .sac { margin-block-start: var(--pas-3); }

/* --- /confidentialite/ ---------------------------------------------------
   Dix couples question/réponse. La <dl> courait sur 1704 px : une ligne de
   plus de 200 caractères, sur la page qu'un visiteur lit justement parce
   qu'il se méfie. Aucune mono ici, le gabarit le verrouille — Fragment Mono
   reste au rapport. */
.confid__entete {
  display: grid;
  align-content: start;
  gap: var(--pas-1);
}
.confid__retour {
  justify-self: start;
  font-size: var(--t-petit);
  color: var(--texte-secondaire);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}
.confid__retour:hover { color: var(--texte); }
.confid__liste {
  display: grid;
  gap: var(--pas-3);
  margin-block-start: clamp(2rem, 1.5rem + 2vw, 3.5rem);
}
.confid__cle { font-size: var(--t-h3); }
/* Le bloc qui dit que les coordonnées quittent la Suisse. Il ne se colore pas
   et ne s'encadre pas : son filet monte à l'encre de la page et sa réponse
   prend la graisse d'emphase. Deux crans, zéro pigment.
   Le second cran ÉTAIT une luminance — la réponse remontait de
   --texte-secondaire à --texte pendant que les neuf autres restaient
   éteintes. Les dix réponses se lisent maintenant au texte courant, comme
   toute réponse du site : sur la page qu'on ouvre justement parce qu'on se
   méfie, aucune des dix ne pouvait rester en demi-teinte. Le cran passe donc
   à la graisse, et le bloc reste le seul des dix à se signaler. */
.confid__bloc--fort { border-block-start-color: var(--texte); }
.confid__bloc--fort .confid__val { font-weight: var(--wght-medium); }
.confid__maj {
  margin-block-start: clamp(2rem, 1.5rem + 2vw, 3.5rem);
  font-size: var(--t-petit);
  color: var(--texte-secondaire);
}
.confid__date { color: var(--texte); }

/* --- /questions/ ---------------------------------------------------------
   Quatorze questions, quatre familles, rien de replié. Le titre de famille
   sortait à la taille exacte du h1 de la page : « L'offre » pesait autant que
   « Les questions qu'on nous pose. ». Il descend au registre de l'étiquette —
   quatre familles sont un repère de lecture, le contenu ce sont les
   questions, et le sommet appartient au contenu. */
/* UNE FAMILLE EST UN CRAN AU-DESSUS D'UNE QUESTION. Les quatorze questions se
   séparent par --pas-3 (60 px), les quatre familles se séparaient par 68 : huit
   pixels d'écart entre « question suivante » et « autre famille », c'est-à-dire
   aucune frontière lisible. Le pas de famille passe au-dessus, sous le pas de
   section : 12 · 60 · 90 · 112, et chaque rang se voit. */
.questions__famille { margin-block-start: clamp(3.5rem, 2.6rem + 3.4vw, 6rem); }
/* Le quatrième h2 du site composé en micro-étiquette, après les deux du
   document de rapport et .live__qr : il nomme la famille de questions pour un
   lecteur d'écran et se compose en capitales espacées de 12 px. Il rend donc
   la serif, comme les autres, et pour la même raison. */
.questions__famille-titre {
  margin-block-end: 1.1rem;
  font-family: var(--font-texte);
  font-size: var(--t-micro);
  font-weight: var(--wght-titre);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--texte-secondaire);
}
/* Une question est une ligne courte. Sans mesure, « Est-ce que je peux avoir
   le sac pour moi tout seul ? » s'étalait sur la colonne entière, et la
   réponse dessous s'arrêtait à 62ch : le titre était plus long que son texte.
   .question porte .paire (le filet), .question__titre porte .bloc__titre (la
   taille), .question__reponse est un p du dossier (la mesure) — le reste est
   déjà composé. */
.question__titre { max-inline-size: 34ch; }

/* --- /ou-on-marche/ ------------------------------------------------------
   Quatre terrains, puis le bloc qui disqualifie. Les h2 des terrains sortaient
   à var(--t-h2), c'est-à-dire à la taille du h1 : la page n'avait plus de
   hiérarchie. Ils descendent au rang de sous-bloc, celui de .bloc__titre et
   de .etape__titre, et c'est l'air qui porte la séparation.
   .terrain__titre porte AUSSI .etiquette sur l'accueil, où le même mot nomme
   une carte de quatre : le sélecteur est donc gardé par la vitesse dossier,
   sinon deux règles de même poids se disputeraient la taille. */
/* La voix descend avec la taille, comme sur .live__qr et les deux h2 du
   document de rapport : un h2 au rang de sous-bloc rend la serif à Switzer,
   sinon la page a cinq titres de 23 px en voix éditoriale et son h1 ne se
   distingue plus que par le corps. */
:where(.dossier) .terrain__titre,
.terrains__ecart-titre {
  font-family: var(--font-texte);
  font-weight: var(--wght-titre);
}
:where(.dossier) .terrain__titre { font-size: var(--t-h3); }
.dossier > .terrain { margin-block-start: var(--pas-3); }
/* Une note de bas de bloc, pas une explication : elle garde le secondaire que
   le chapeau et le corps du terrain viennent de quitter. */
.terrain__note { font-size: var(--t-petit); color: var(--texte-secondaire); }
.terrains__actions { margin-block-start: var(--pas-1); }
.terrains__ecart { margin-block-start: clamp(3rem, 2rem + 3vw, 5rem); }
.terrains__ecart-titre { font-size: var(--t-h3); }

/* --- /le-slot/ : la frise du déroulé -------------------------------------
   La copy demande cinq étapes sur une LIGNE DE TEMPS verticale. .etapes range
   en colonnes auto-fit : à 1440 px on lisait 1-2-3-4, puis 5 seule à la ligne
   suivante — un déroulé qui s'interrompt n'est plus un déroulé.
   Le modificateur ne peut pas venir du gabarit, le markup est figé : c'est la
   section qui le porte, et .slot__deroule ne nomme rien d'autre au monde.
   Le numéro chevauche le filet et le masque avec le fond de la zone : c'est
   ce qui fait lire la ligne comme une chronologie et non comme une bordure. */
.slot__deroule .etapes {
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
}
.slot__deroule .etape {
  position: relative;
  padding-block: 1.35rem;
  padding-inline-start: clamp(2.25rem, 1.75rem + 2vw, 3.25rem);
  border-block-start: 0;
}
.slot__deroule .etape::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: var(--hairline);
  background: var(--bordure);
}
.slot__deroule .etape:first-child::after { inset-block-start: 1.35rem; }
.slot__deroule .etape:last-child::after { inset-block-end: 1.35rem; }
/* z-index, sans quoi le filet passe DEVANT le numéro : les deux sont des
   pseudo-éléments du même .etape, ::after est peint après ::before, et le
   trait coupait le zéro en deux. Le numéro interrompt la ligne, il ne se fait
   pas traverser par elle. */
.slot__deroule .etape::before {
  position: absolute;
  z-index: 1;
  inset-block-start: 1.35rem;
  inset-inline-start: 0;
  margin: 0;
  padding-block: 0.15rem;
  padding-inline-end: 0.7rem;
  background: var(--fond);
}
/* 34ch est la mesure d'une étape dans une rangée de quatre. En frise, la
   colonne est entière : le corps reprend la respiration du manifeste. */
.slot__deroule .etape__corps { max-inline-size: var(--mesure-jour); }

/* --- /scan/ --------------------------------------------------------------
   Lue debout, dans la rue, dix secondes après avoir visé un QR. Un pouce, un
   geste. Le bouton fait 100 % de large (.bouton--grand) : sur un téléphone
   c'est juste, sur un écran de bureau il traversait un mètre. */
/* Le geste ouvre le groupe d'action de la page : --pas-3 au total, dont
   --pas-2 est déjà posé par le row-gap du manifeste. */
.scan__geste {
  max-inline-size: 26rem;
  margin-block-start: calc(var(--pas-3) - var(--pas-2));
}
.scan__note {
  display: grid;
  justify-items: start;
  gap: 0.3rem;
  margin-block-start: clamp(2rem, 1.5rem + 2vw, 3.5rem);
  font-size: var(--t-petit);
  color: var(--texte-secondaire);
}
.scan__lien,
.scan__note a {
  color: var(--texte-secondaire);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}
.scan__lien:hover,
.scan__note a:hover { color: var(--texte); }
/* La seule cible tactile de la page, visée au pouce, dehors, parfois avec des
   gants. 56 px est le plancher que DESIGN.md fixe à l'app marcheur, et pour
   exactement la même raison : c'est la même main. */
.scan__wa { min-block-size: 56px; }

/* --- /walkers/ et /diffuser-ma-pub/ --------------------------------------
   La colonne de texte qui accompagne un formulaire. .demande__scene la pose
   déjà en deux colonnes ; il lui manquait le flux interne. */
.demande__texte {
  display: grid;
  align-content: start;
  gap: var(--pas-1);
}

/* --- Le kicker et la réassurance de la manchette -------------------------
   Deux micro-titres du même registre, celui de .etiquette (socle.css) : le nom
   d'une carte et le kicker du hero. La couleur est redite ici pour qu'ils se
   relisent ensemble — ce sont les deux seules capitales de l'accueil. */
.carte__nom,
.manchette__kicker { color: var(--texte-secondaire); }
/* La réassurance est la ligne fine sous les deux gestes : elle ne prend pas le
   corps du manifeste, sinon elle pèse autant que la promesse. */
.manchette__reassurance {
  max-inline-size: var(--mesure-jour);
  font-size: var(--t-petit);
  line-height: 1.45;
  color: var(--texte-secondaire);
}

/* --- La barre de tête ----------------------------------------------------
   LE MENU EXISTE, ET IL A LONGTEMPS SORTI NU. Ce commentaire annonçait
   « AUCUN gabarit ne rend ce menu » : template/partie/barre.html rend bien les
   cinq liens depuis le passage à onze pages, mais il les émettait en <a> sans
   classe. Les règles ci-dessous étaient donc écrites, correctes, et ne
   touchaient rien, les cinq liens de la première chose que voit un visiteur
   sortaient en lien de navigateur par défaut. Le gabarit pose maintenant
   .barre__lien ; ne pas retirer la classe sans retirer ces règles.
   La marque garde son margin-inline-end:auto ; le menu se pose donc à droite,
   contre le bouton, et se retire sous 900 px où il volerait la ligne. */
.barre__nav {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: clamp(0.9rem, 0.6rem + 1vw, 1.75rem);
  font-size: 0.9rem;
}
.barre__lien {
  padding-block: 0.7rem;
  color: var(--texte-secondaire);
  text-decoration: none;
}
.barre__lien:hover { color: var(--texte); }
.barre__lien[aria-current] {
  color: var(--texte);
  font-weight: var(--wght-medium);
}
/* --- L'OFFRE DE LANCEMENT DE LA LOOP (21.08) ------------------------------
   Trois objets pour une seule annonce : le bandeau qui la dit en arrivant, le
   badge qui la rappelle là où on choisit son produit, la pastille qui la tient
   dans une barre où il n'y a pas la place d'une phrase.

   LE BLEU EST `--halo`, ET C'EST UN EMPRUNT ASSUMÉ. Dans le système, halo veut
   dire « un relevé » : c'est la couleur d'une mesure enregistrée, sur la nuit.
   Ici elle sert un objet marketing, temporaire, sur le jour. Axel a demandé
   « un truc bleu » et c'est le seul bleu de la palette ; l'inventer ailleurs
   aurait coûté une couleur de plus. Le jour où l'offre s'arrête, ces trois
   règles partent ensemble et halo retrouve son seul sens.
   `--encre-jour` sur `--halo` : 6,59, mesuré. Le jaune était exclu (« pas
   abusif, jaune, attention, warning », ses mots) et il ne porte de toute façon
   pas de texte sur clair. */
/* IL PARLE LA LANGUE DU SITE, IL N'EN AJOUTE PAS UNE (repris le 21.08).
   Première version : un aplat `--halo` bleu pâle avec un lien souligné. Vu en
   place, ça ne ressemblait pas au site, ça ressemblait à une barre de
   notification de navigateur posée dessus. La nuit, elle, est déjà du
   vocabulaire : le pied la porte, l'aperçu de relevé la porte. Et c'est LE SEUL
   ENDROIT OÙ LE JAUNE A LE DROIT DE PORTER DU TEXTE — sur clair il tombe à
   1,53:1, sur la nuit il est l'accent d'action du système.

   ELLE DÉFILE, ET ELLE NE POUSSE PLUS LE HERO (21.08, deux défauts signalés
   par Nazaire).
   Pas assez visible : elle était statique, en petit, sur trois lignes au
   téléphone. Elle passe sur UNE ligne qui circule — le mot d'Axel — au corps
   du texte et non en petit. Le mouvement fait le travail que la taille seule
   ne faisait pas, sans crier en jaune d'alerte, ce qu'il avait exclu.
   Et elle décalait le socle : posée dans le flux au-dessus d'une manchette en
   `100svh`, elle poussait tout d'un cran et le wordmark géant, ancré au bas du
   hero, passait sous la ligne de flottaison. Sur une bande à hauteur variable
   (elle se rangeait sur trois lignes à 390 px) aucun calcul CSS ne pouvait la
   rattraper. Une seule ligne a une hauteur CONNUE : js/v7.js la mesure et la
   pose en --bandeau-h, la manchette la retranche. Sans script la variable vaut
   zéro et on retombe exactement sur l'état d'avant. */
.bandeau-lancement {
  /* FIXE, SUR TOUTES LES PAGES (22.08). Elle etait dans le flux et sur le seul
     accueil : vue a l'arrivee puis partie. Axel la veut presente partout, donc
     elle prend le haut de la fenetre et ne le rend plus. Z-index au-dessus de
     la pilule (20), qui se decale sous elle. */
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 21;
  display: block;
  overflow: hidden;
  padding-block: 0.75rem;
  /* LA FOSSE ET PAS LA NUIT (23.08). Elle était au noir plein, ce qui marchait
     tant que toutes les pages étaient blanches. Sur /la-loop/, passée en nuit,
     elle devenait noir sur noir : plus aucune frontière, la banderole se
     dissolvait dans la page. La fosse est un cran au-dessus du fond de nuit,
     donc elle se détache là-bas, et contre le papier d'une page claire l'écart
     avec le noir plein ne se voit pas. Une seule valeur pour les deux mondes.
     Le survol monte alors d'un cran de plus, aux gradins. */
  background: var(--fosse);
  color: var(--craie);
  font-size: var(--t-base);
  line-height: 1.3;
  text-decoration: none;
}
/* Ce que la banderole prend, la page le reserve : sans cette ligne le premier
   ecran de chaque page passerait dessous. --bandeau-h est mesuree par
   js/v7.js ; sans script elle vaut zero, la banderole n'est plus fixe faute de
   mesure fiable, et on retombe sur une bande en flux (regle plus bas). */
body { padding-block-start: var(--bandeau-h, 0px); }
html:not(.js) .bandeau-lancement { position: static; }
.bandeau-lancement__piste {
  display: flex;
  inline-size: max-content;
}
.bandeau-lancement__ex {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding-inline-end: 3rem;
  white-space: nowrap;
}
.bandeau-lancement__lien {
  color: var(--jaune);
  font-weight: var(--wght-titre);
}
/* ELLE S'ARRÊTE ET ELLE LE DIT (22.08). La pause au survol existait déjà et
   fonctionnait — verifié au navigateur, zéro déplacement sur 1,4 s — mais rien
   ne la signalait : une banderole qui s'immobilise sans changer d'aspect se lit
   comme un bégaiement, pas comme une invitation. Le fond s'éclaircit d'un cran
   et le lien se souligne : l'objet répond, donc on comprend qu'on peut le
   viser.
   `:focus-within` autant que `:hover` : sans lui, l'utilisateur au clavier
   tabule sur un lien qui continue de défiler sous ses doigts.
   Toute la bande est un <a> vers /la-loop/, donc il n'y a pas de cible à
   atteindre : on clique où on veut. Le soulignement dit où ça mène, il ne
   délimite pas une zone. */
.bandeau-lancement:hover,
.bandeau-lancement:focus-within { background: var(--gradins); }
.bandeau-lancement:hover .bandeau-lancement__lien,
.bandeau-lancement:focus-within .bandeau-lancement__lien {
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 2px;
}
/* La piste porte DEUX exemplaires : translater de -50 % la ramène pile sur le
   second, donc la boucle n'a pas de couture. Durée liée à la longueur du texte
   plutôt qu'un nombre rond : la vitesse doit être lisible, pas régulière. */
/* On translate d'UN exemplaire, pas d'un pourcentage : le pourcentage dépend du
   nombre de copies, que js/v7.js recalcule à chaque largeur. --ex-w ne dépend
   que du texte.
   LA DURÉE VIENT DU SCRIPT, ET ELLE NE PEUT PAS VENIR D'ICI : on ne dérive pas
   un temps d'une longueur en CSS. `calc(var(--ex-w) / 600 * 9s)` est invalide,
   ce qui invalidait la propriété entière — la banderole ne bougeait plus du
   tout, et rien ne le disait. js/v7.js connaît déjà la largeur, il pose la
   durée avec, à vitesse constante : environ 65 px par seconde, la vitesse à
   laquelle une ligne se lit sans effort. Une durée fixe ferait ramper un texte
   court et courir un texte long. */
@media (prefers-reduced-motion: no-preference) {
  .anim .bandeau-lancement__piste {
    animation: circule var(--ex-dur, 9s) linear infinite;
  }
  .bandeau-lancement:hover .bandeau-lancement__piste,
  .bandeau-lancement:focus-within .bandeau-lancement__piste { animation-play-state: paused; }
}
@keyframes circule {
  from { transform: translateX(0); }
  to { transform: translateX(calc(-1 * var(--ex-w, 50%))); }
}
/* SANS JAVASCRIPT LA PILULE NE S'EFFACE PAS devant le hero — son retrait est
   posé par js/v7.js et par lui seul. Elle recouvrirait la banderole, qui est le
   premier objet de la page. On lui réserve sa hauteur. */
html:not(.js) .bandeau-lancement { padding-block-start: calc(var(--barre-h) + 1.5rem); }
/* LA MANCHETTE REND AU HERO CE QUE LA BANDEROLE LUI PREND. --bandeau-h est
   posée par js/v7.js, mesurée, et vaut zéro sans script : on retombe alors
   exactement sur le comportement d'avant la banderole. */
body[data-page="accueil"] .manchette { min-block-size: calc(100svh - var(--bandeau-h, 0px)); }
/* Sous mouvement réduit rien ne défile : la ligne se centre et le second
   exemplaire disparaît, sinon on lirait l'annonce deux fois. */
@media (prefers-reduced-motion: reduce) {
  .bandeau-lancement__piste { inline-size: 100%; justify-content: center; }
  .bandeau-lancement__ex + .bandeau-lancement__ex { display: none; }
  .bandeau-lancement__ex { white-space: normal; padding-inline: var(--gutter); }
}

.badge-lancement {
  display: inline-block;
  margin-inline-start: 0.5rem;
  padding: 0.15em 0.5em;
  border-radius: var(--radius-pilule);
  background: var(--nuit);
  color: var(--craie);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* Le porteur est une micro-étiquette déjà espacée : le badge reprend sa
     propre chasse, sinon il hérite d'un interlettrage de titre. */
  white-space: nowrap;
}

/* La barre n'a pas la place d'une phrase : la pastille dit qu'il se passe
   quelque chose, et le texte pour lecteur d'écran, lui, le dit en entier. */
/* Le lien reserve la place de sa pastille a droite : sans cette marge elle
   deborde sur le lien suivant, et au telephone elle sortait de la boite qui
   defile. */
.barre__lien--marque { position: relative; margin-inline-end: 0.5rem; }
/* LA PASTILLE VEND. Elle était un point de 7 px, gris-jaune, poli. Sur un site
   qui vend de la publicité, l'objet qui annonce l'offre ne peut pas être le
   plus discret de la page.
   BRAISE, et c'est le système qui le dit : DESIGN.md range #B54432 dans les
   événements, « l'humain, le live, l'alerte — pastilles, jamais d'aplats ».
   C'est littéralement le jeton des pastilles ; le jaune est l'accent d'action,
   pas un signal de vie.
   Elle bat. Un anneau part d'elle et se dissout, le geste d'un voyant qui
   émet — deux fois plus large, une fois toutes les 2,4 s, assez lent pour ne
   pas harceler. `transform` et `opacity` seuls, sur un ::after, donc zéro
   layout et rien à repeindre autour. Sous mouvement réduit l'anneau ne part
   pas : la pastille reste, plus grande et rouge, et se voit quand même. */
/* EN PASTILLE DE NOTIFICATION (22.08, demande d'Axel : « une pastille de
   notification sur l'offre pour vraiment attirer l'oeil, un peu a la facon
   Higgsfield sans etre autant agressif »).
   Elle etait un point pose APRES le mot, sur la ligne de base : une puce
   typographique, que l'oeil lit comme de la ponctuation. Une notification se
   reconnait a sa POSITION avant sa couleur — accrochee au coin haut-droit de
   ce qu'elle signale, en dehors du flux du texte. C'est ce que fait une
   application, et c'est ce qui la rend impossible a confondre avec un point.
   « Sans etre aussi agressif » : elle reste en braise, un rouge brique mat, pas
   un rouge d'alerte sature ; elle ne porte pas de compteur ; et son anneau part
   toutes les 2,4 s, pas toutes les secondes. Le geste dit « il y a quelque
   chose ici », il ne dit pas « urgence ». */
.pastille {
  position: absolute;
  /* Le lien a 0,7rem de padding vertical : ancree au haut de SA BOITE, la
     pastille flottait au-dessus du mot au lieu de s'y accrocher. On la pose a
     la hauteur de capitale. */
  inset-block-start: 0.5rem;
  inset-inline-end: -0.45rem;
  inline-size: 0.55rem;
  block-size: 0.55rem;
  border-radius: 999px;
  background: var(--braise);
  /* Un lisere de la couleur de la pilule : la pastille se detache meme quand
     elle tombe sur le mot suivant ou sur le bord du verre. */
  box-shadow: 0 0 0 2px var(--fond);
}
.pastille::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--braise);
}
/* SUR LA CARTE DE LA LOOP (22.08). Le meme objet, a l'echelle de son hote : la
   pastille de la barre fait 0,55rem parce qu'elle marque un mot de 14 px, celle
   de la carte marque un bloc de 400 px de large et se perdrait a cette taille.
   Posee DANS l'angle plutot qu'a cheval dessus : la carte a un rayon de 28, et
   une pastille a moitie dehors sur un coin rond se lit comme un defaut de
   decoupe, pas comme un badge. */
.pastille--carte {
  inset-block-start: 1.4rem;
  inset-inline-end: 1.4rem;
  inline-size: 0.75rem;
  block-size: 0.75rem;
  box-shadow: 0 0 0 3px var(--carte-basse);
}
@media (prefers-reduced-motion: no-preference) {
  .anim .pastille::after { animation: emet 2.4s var(--ease) infinite; }
}
@keyframes emet {
  0%   { transform: scale(1); opacity: 0.9; }
  70%  { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

/* LA BULLE (mots d'Axel : « une espèce de bulle au-dessus qui bouge un peu »).
   Elle respire, et seulement sous `anim` : le socle coupe tout mouvement sous
   prefers-reduced-motion, et une annonce n'est pas une raison d'y déroger.
   `transform` et `opacity` seuls, zéro layout. */
.bulle-lancement {
  display: inline-block;
  margin-block-start: var(--pas-1);
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius-pilule);
  background: var(--nuit);
  color: var(--craie);
  font-size: var(--t-petit);
  font-weight: var(--wght-titre);
}
/* Sur une page de nuit, la bulle était nuit sur nuit : elle ne se lisait plus
   comme un objet, juste comme une ligne en gras. Elle monte à la surface et
   prend un filet — le geste des blocs posés sur la nuit ailleurs sur le site.
   Elle ne prend pas le clair : le seul objet clair de la page doit rester le
   bouton, sinon la page a deux gestes de même poids. */
.zone-nuit .bulle-lancement {
  background: var(--surface);
  border: var(--hairline) solid var(--bordure);
}
@media (prefers-reduced-motion: no-preference) {
  .anim .bulle-lancement { animation: respire 3.2s var(--ease) infinite; }
}
@keyframes respire {
  0%, 100% { transform: none; }
  50% { transform: translateY(-3px); }
}

/* --- LES CINQ LIENS DESCENDENT DANS LA PILULE (18.08) ---------------------
   Ils étaient simplement `display: none` sous le palier, et le commentaire du
   composant l'assumait : au téléphone la pilule ne portait que le wordmark,
   « le retour rapide vers l'accueil ». Le prix, lui, n'était écrit nulle part :
   les dix autres pages n'avaient PLUS AUCUN chemin, sauf le pied — à douze
   mille pixels de défilement sur l'accueil. Les cinq liens sortaient aussi de
   l'ordre de tabulation, donc la navigation au clavier disparaissait avec eux.

   Ce qui rend le retour tenable maintenant : la pilule se retire au défilement
   (js/v7.js). Une rangée de plus en permanence aurait coûté 40 px de fenêtre
   sur toute la lecture ; elle ne coûte plus que le temps qu'on la regarde.

   DEUX RANGÉES, et la pilule prend une largeur DÉFINIE. En `fit-content`, la
   rangée de liens n'aurait eu à sa disposition que la largeur de la rangée du
   dessus — 227 px mesurés — et les cinq liens auraient défilé dans un hublot.
   Les liens débordent quand même à 390 (≈421 px pour 358 disponibles) : ils
   défilent, le dernier est coupé, et c'est le seul indice honnête qu'il y a une
   suite. Pas de fondu de bord : il mentirait dès que la rangée tient.

   Aucun texte neuf : ce sont les cinq liens de la copy d'Axel, dans son ordre,
   déjà écrits dans template/partie/barre.html.

   PAS DE tabindex SUR LE CONTENEUR : un conteneur qui défile et dont le
   contenu est focusable est déjà atteignable par ses liens, l'ajouter créerait
   un arrêt de tabulation qui ne mène nulle part.
   EN REVANCHE LE NAVIGATEUR NE RAMÈNE PAS LE FOCUS DANS LA BOÎTE. Vérifié à
   la vraie touche Tab, pas au focus() programmatique : le focus atterrit sur
   « Questions » de 360 à 426 px pendant que la boîte s'arrête à 362, et
   scrollLeft ne bouge pas. Soixante-quatre pixels du lien et sa bague de focus
   restent dehors. C'est js/v7.js qui le ramène. */
@media (width < 56.25rem) {
  .barre {
    flex-wrap: wrap;
    inline-size: calc(100vw - 2rem);
    column-gap: 1rem;
    row-gap: 0.25rem;
    padding: 0.5rem 0.75rem 0.5rem 1.25rem;
  }
  .barre__nav {
    order: 3;
    flex-basis: 100%;
    min-inline-size: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    gap: 1.1rem;
  }
  .barre__nav::-webkit-scrollbar { display: none; }
  /* Le tunnel garde sa pilule nue. Le CTA en a été retiré le 16.08 (il renvoie
     à la page où le prospect est déjà) et le pied s'en est allé le même soir :
     y redescendre cinq liens rouvrirait la sortie que ces deux décisions
     fermaient. La marque seule, centrée, comme avant. */
  body[data-page="demande"] .barre__nav { display: none; }
  /* Et elle reprend sa géométrie d'avant : sans les liens, la largeur définie
     et le padding resserré ci-dessus l'étiraient en bandeau plein de 38 px de
     haut là où le 16.08 voulait une pilule compacte autour du seul wordmark.
     `fit-content` la fait de nouveau tenir à son contenu, les marges auto la
     recentrent. */
  body[data-page="demande"] .barre {
    inline-size: fit-content;
    padding: 0.625rem 1.25rem;
  }
}

/* --- L'OUVERTURE DU BLOC 5 ------------------------------------------------
   Ces deux règles habillaient .bascule__titre et .bascule__corps, le titre et
   le chapeau du pivot. Le pivot est parti le 14.08 ; sa copy, elle, ne se
   réécrit pas et ouvre maintenant la section live. Les règles la suivent sous
   son nouveau nom : c'est le même texte, au même rang, il ne devait pas
   retomber à 17 px en changeant de porteur.
   `padding-block-end` pour la même raison qu'au hero : à 1,08 d'interligne sur
   un titre de 64 px, les jambages de la serif sortent de la boîte de ligne. */
.live__section-titre { font-size: var(--t-h2); padding-block-end: 0.12em; }
.live__chapeau {
  max-inline-size: var(--mesure-jour);
  font-size: var(--t-lead);
  line-height: 1.35;
}

/* .terrain__amorce, l'énumération concrète sous chaque terrain (« Centres
   commerciaux, halls de gare, salons… »). Elle a été retirée de la liste des
   textes éteints, à raison : c'est ce qui rend le terrain reconnaissable, pas
   une chute. Mais elle est restée sans règle, donc rendue quatre fois et
   stylée nulle part. Elle prend le corps du texte, à la mesure de lecture :
   son rôle est d'être lue en entier, pas survolée. L'emphase reste à
   .terrain__pointe, qui la suit. */
.terrain__amorce {
  max-inline-size: var(--mesure-nuit, 62ch);
  font-size: var(--t-base);
  line-height: var(--lh-texte);
}
