/* ============================================================================
   MAISON SERVICE — styles propres à ce site.

   Règle tenue partout ici : aucune couleur, aucune taille de texte écrite en
   dur. Tout passe par les variables de `theme.css`. Si une valeur manque, on
   l'ajoute au thème.

   Les composants repris du socle sont signalés par leur nom de fichier. Ce
   qui a été écrit pour ce site seulement porte la mention « propre au site ».
   ========================================================================= */

/* --- Bandeau de maquette ---------------------------------------------------
   À retirer, avec le `noindex`, le jour où le site est commandé et livré.
   `Préparer la livraison.command` le fait. */
.maquette {
  background: var(--accent-soft);
  color: var(--accent-dark);
  text-align: center;
  padding: 8px var(--marge-page);
  font-size: var(--t-petit);
}

/* --- En-tête : _socle/composants/entete.html ------------------------------
   ÉCART ASSUMÉ AVEC LE SOCLE, ET C'EST UN DÉFAUT DU SOCLE QU'IL CORRIGE.

   Le squelette pose l'en-tête en `position: fixed; top: 0`, juste après le
   bandeau de maquette laissé dans le flux. Résultat, mesuré en capture sur ce
   site : l'en-tête recouvre intégralement le bandeau, et la seule chose qui
   dit qu'un site n'est pas le site officiel d'une entreprise réelle devient
   invisible. Le défaut existe sur tout site bâti sur le squelette.

   `sticky` règle les deux d'un coup : l'en-tête reste dans le flux, donc le
   bandeau s'affiche et défile normalement, puis elle colle en haut dès
   qu'elle l'atteint. Aucun décalage à calculer, et rien à réparer sans
   JavaScript. Le masquage à la descente fonctionne à l'identique. */
.entete {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px); border-bottom: 1px solid var(--line);
  transition: transform var(--transition);
}
.entete--masque { transform: translateY(-100%); }
.entete__barre { display: flex; align-items: center; justify-content: space-between;
  gap: var(--pas); min-height: 64px; }
.entete__nom { font-family: var(--font-titre); font-size: 1.25rem; color: var(--ink); text-decoration: none; }
.entete__nav { display: flex; align-items: center; gap: 28px; }
.entete__burger { display: none; align-items: center; justify-content: center;
  width: 44px; height: 44px; padding: 0; background: none;
  border: 1px solid var(--line-strong); border-radius: var(--arrondi);
  cursor: pointer; color: var(--ink); }
.entete__burger span { display: block; width: 18px; height: 1.5px; background: currentColor; position: relative; }
.entete__burger span::before, .entete__burger span::after {
  content: ''; position: absolute; left: 0; width: 18px; height: 1.5px; background: currentColor; }
.entete__burger span::before { top: -6px; }
.entete__burger span::after { top: 6px; }
.nav-link[aria-current="page"] { color: var(--accent); }
.nav-link[aria-current="page"]::after { transform: scaleX(1); }
@media (max-width: 900px) {
  .entete__burger { display: flex; }
  .entete__nav { position: absolute; top: 100%; left: 0; right: 0; flex-direction: column;
    align-items: stretch; gap: 0; background: var(--bg); border-bottom: 1px solid var(--line);
    padding: 8px var(--marge-page) 20px; }
  .entete__nav[hidden] { display: none; }
  .entete__nav .nav-link { padding: 14px 0; border-bottom: 1px solid var(--line); font-size: var(--t-texte); }
}

/* --- Apparition au défilement : _socle/composants/apparition-au-scroll.html */
.js [data-apparait] { opacity: 0; transform: translateY(22px);
  transition: opacity .7s cubic-bezier(.2,.8,.2,1), transform .7s cubic-bezier(.2,.8,.2,1); }
.js [data-apparait].est-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js [data-apparait] { opacity: 1; transform: none; transition: none; }
}

/* --- Révélation par volets : _socle/composants/revelation-par-volets.html -- */
.volet__mot {
  display: inline-block; overflow: hidden; vertical-align: bottom;
  padding: 0.16em 0; margin: -0.16em 0;
}
.volet__mot > span { display: inline-block; }
.volets [data-volet] .volet__mot > span {
  transform: translateY(108%);
  transition: transform 460ms cubic-bezier(0.2, 1.06, 0.35, 1);
}
.volets [data-volet].est-ouvert .volet__mot > span { transform: none; }

/* --- Titres en dégradé : _socle/composants/titres-en-degrade.html ----------
   LE COMPOSANT SIGNATURE DE CE SITE. Il ne se remet nulle part ailleurs dans
   le parc, c'est ce qui en fait une signature. Choisi parce que les deux
   signatures du parti pris « Maison douce », `motif-arcades` et
   `blocs-empiles`, ne tiennent pas ici : la première est déjà sur Terra Rossa,
   la seconde repose entièrement sur un arrondi de coin, et le client a choisi
   des formes anguleuses. */
.titre-degrade { color: var(--ink); }
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .titre-degrade {
    background-image: linear-gradient(178deg, var(--ink) 0%, var(--titre-degrade-bas) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  .section-sombre .titre-degrade,
  .aurore--sombre .titre-degrade {
    background-image: linear-gradient(178deg, var(--on-panel) 0%, var(--titre-degrade-bas-clair) 100%);
  }
}
/* Un titre en dégradé et une révélation par volets ne se posent jamais sur le
   MÊME titre : le découpage insère des `span`, et le dégradé découpé à la
   forme des lettres se recalculerait alors mot par mot. */
.titre-degrade em {
  font-style: italic;
  color: var(--accent);
  -webkit-text-fill-color: var(--accent);
}
/* LE MOT D'ACCENT CHANGE DE COULEUR SUR FOND SOMBRE, et le composant du socle
   ne le prévoit pas : il ne traite que le dégradé. Trouvé en capture sur la
   section « Demander un repas », où « repas » sortait en --accent sur --panel,
   soit 2,90 de contraste, c'est-à-dire illisible.

   AXE-CORE NE PEUT PAS VOIR CE DÉFAUT : le texte est en `color: transparent`
   avec un `-webkit-text-fill-color`, et le moteur abandonne la mesure dans ce
   cas au lieu de la signaler. Un contrôle vert ne prouve que ce qu'il
   regarde. L'accent doux de la palette donne 9,67 sur le même fond. */
.section-sombre .titre-degrade em,
.aurore--sombre .titre-degrade em {
  color: var(--accent-clair);
  -webkit-text-fill-color: var(--accent-clair);
}
@media print {
  .titre-degrade { color: var(--ink) !important; -webkit-text-fill-color: currentColor; }
}

/* --- Marqueur de section : _socle/composants/marqueur-de-section.html ------ */
.marque {
  display: flex; align-items: center; gap: 16px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--muted);
  margin: 0 0 clamp(18px, 2.6vw, 28px);
}
.marque__no { color: var(--accent); }
.marque__trait { flex: 0 1 160px; height: 1px; background: var(--line-strong); }
.section-sombre .marque { color: var(--on-panel); }
.section-sombre .marque__no { color: var(--accent-clair); }
.section-sombre .marque__trait { background: rgb(251 246 239 / 0.3); }

/* --- Ouverture : _socle/composants/hero-expansion.html ---------------------
   Choix du client, champ `hero` = `image`.

   CE QU'IL FAUT SAVOIR AVANT DE LE RETOUCHER : le bloc qui grandit ne contient
   AUCUNE image. Le client a déposé six fichiers, tous des captures d'écran,
   dans un seau fermé à la lecture publique auquel la chaîne n'a pas accès.
   Poser une image tierce à leur place est interdit par la maison ; poser une
   image inventée serait pire. Le bloc est donc un dégradé pris dans les
   couleurs du thème, avec un cartouche qui dit franchement ce qu'il attend.

   Le jour où les photos sont contrôlées, il n'y a qu'à remettre le `<img>` du
   composant d'origine à la place de `.hero-media__vide`. Rien d'autre ne
   change : la mécanique de l'expansion ne regarde pas ce qu'elle agrandit. */
.hero-expansion {
  --repos-l: min(700px, 86vw);
  --repos-h: min(466px, 57vw);
  position: relative;
  height: 180vh;
}
.hero-expansion__fixe { position: sticky; top: 0; height: 100vh; overflow: hidden; }
.hero-expansion__media {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: calc(var(--repos-l) + (100vw - var(--repos-l)) * var(--pp, 0));
  height: calc(var(--repos-h) + (100vh - var(--repos-h)) * var(--pp, 0));
  overflow: hidden;
  border-radius: var(--arrondi-carte);
  --fondu: calc(clamp(20px, 3.8vw, 54px) * (1 - var(--pp, 0)));
  -webkit-mask-image:
    linear-gradient(to right,  transparent 0, #000 var(--fondu), #000 calc(100% - var(--fondu)), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 var(--fondu), #000 calc(100% - var(--fondu)), transparent 100%);
  mask-image:
    linear-gradient(to right,  transparent 0, #000 var(--fondu), #000 calc(100% - var(--fondu)), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 var(--fondu), #000 calc(100% - var(--fondu)), transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
/* Propre au site : l'emplacement de photo, en attendant les vraies.

   L'ÉTIQUETTE EST EN HAUT DU BLOC, PAS EN BAS, et c'est une correction faite
   sur capture. Posée en bas, elle venait se coller sous le titre du hero et
   recouvrait la fin du paragraphe : le composant prévient que le texte ne
   doit jamais se retrouver sur l'image, et une étiquette opaque au milieu du
   bloc produit exactement le même défaut à l'envers. Le haut du bloc est la
   seule zone que le texte centré n'atteint jamais. */
.hero-media__vide {
  width: 100%; height: 100%;
  display: flex; align-items: flex-start; justify-content: center;
  padding: clamp(14px, 2vw, 24px);
  background:
    radial-gradient(120% 90% at 22% 18%, var(--accent-soft) 0%, transparent 62%),
    radial-gradient(110% 80% at 82% 84%, var(--accent) 0%, transparent 58%),
    var(--bg-alt);
}
.hero-media__etiquette {
  margin: 0; max-width: 52ch;
  background: var(--card); color: var(--ink);
  border: 1px dashed var(--accent);
  padding: 8px 14px;
  font-size: var(--t-petit); line-height: 1.45; text-align: center;
}
.hero-expansion__texte {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  width: min(var(--largeur-texte), 86vw);
  text-align: center;
  opacity: var(--opacite-texte, 1);
  pointer-events: none;
}
.hero-expansion__texte h1 { margin: 0 0 var(--pas); font-size: var(--t-geant); }
.hero-expansion__texte p { margin: 0 auto; max-width: 46ch; }
@media (prefers-reduced-motion: reduce) {
  .hero-expansion { height: auto; }
  .hero-expansion__fixe { position: relative; height: auto; padding: var(--section) 0; }
  .hero-expansion__media { position: relative; left: auto; top: auto; transform: none; margin: 0 auto; }
  .hero-expansion__texte { position: relative; left: auto; top: auto; transform: none; margin: 0 auto var(--pas); }
}
@media print {
  .hero-expansion { height: auto !important; }
  .hero-expansion__fixe { position: relative !important; height: auto !important; }
  .hero-expansion__media { position: relative !important; left: auto !important; top: auto !important; transform: none !important; margin: 0 auto; }
  .hero-expansion__texte { position: relative !important; left: auto !important; top: auto !important; transform: none !important; opacity: 1 !important; }
}

/* --- En-tête des pages intérieures (propre au site) ------------------------
   Un seul hero par site, et il est sur l'accueil. Les quatre autres pages
   ouvrent sur un titre posé, pas sur une seconde ouverture. */
.page-tete { padding: calc(96px + var(--section)) 0 var(--section); }
.page-tete h1 { max-width: 20ch; }
.page-tete p { font-size: var(--t-sous-titre); max-width: 52ch; color: var(--body); }

/* --- La mosaïque (propre au site) ------------------------------------------
   Choix du client, champ `disposition` = `bento`.

   LA CONSIGNE INTERDIT LA MOSAÏQUE AU-DESSOUS DE CINQ BLOCS DE CONTENU : une
   grille à trous est pire qu'une liste. Il y en a six ici, et les six sont
   factuels, c'est-à-dire tirés mot pour mot de la demande : les repas faits
   maison, les horaires, le prix de départ, ce qu'on peut demander, Nice, et
   l'année 2009. Aucun bloc de remplissage.

   Douze colonnes, et chaque bloc dit combien il en prend. Sous 760 px la
   grille se défait en une colonne : une mosaïque sur un téléphone n'est plus
   une mosaïque, c'est une pile. */
.bento {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--pas);
}
.bento__bloc {
  grid-column: span 4;
  display: flex; flex-direction: column; justify-content: flex-end;
  gap: 8px;
  min-height: 190px;
  padding: var(--pas);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--arrondi-carte);
}
/* Les largeurs sont nommées par leur nombre de colonnes, et les trois lignes
   font 7+5, 4+8, 5+7 : jamais deux blocs de même taille côte à côte, sinon ce
   n'est plus une mosaïque mais une grille. */
.bento__bloc--sept   { grid-column: span 7; }
.bento__bloc--huit   { grid-column: span 8; }
.bento__bloc--cinq   { grid-column: span 5; }
.bento__bloc--quatre { grid-column: span 4; }
.bento__bloc--haut   { min-height: 290px; }
.bento__bloc--accent { background: var(--accent-soft); border-color: var(--accent); }
.bento__bloc h2, .bento__bloc h3 { margin: 0; }
.bento__bloc p { margin: 0; max-width: 42ch; }
.bento__chiffre {
  font-family: var(--font-titre);
  font-size: clamp(2.2rem, 4.4vw, 3.4rem);
  line-height: 1;
  color: var(--ink);
}
.bento__mention { font-size: var(--t-petit); color: var(--muted); }
@media (max-width: 1000px) {
  .bento__bloc,
  .bento__bloc--sept, .bento__bloc--huit,
  .bento__bloc--cinq, .bento__bloc--quatre { grid-column: span 6; }
}
@media (max-width: 760px) {
  .bento__bloc,
  .bento__bloc--sept, .bento__bloc--huit,
  .bento__bloc--cinq, .bento__bloc--quatre { grid-column: span 12; }
  .bento__bloc, .bento__bloc--haut { min-height: 0; }
}

/* --- Fond d'aurore : _socle/composants/fond-aurore.html --------------------
   Variante CLAIRE, puisque le client a choisi un fond clair. Opacité de
   groupe 0,14, jamais montée : mesurée sur CETTE palette, le pire cas est
   --muted posé au point le plus dense de la nappe --accent, soit 6,37. La
   marge est large parce que la terre cuite du client est plus claire que
   l'accent du socle, qui ne laissait que 0,11 de marge. */
.aurore {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: var(--section) var(--marge-page);
}
.aurore__champ {
  position: absolute; inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.14;
  --d: 0.5;
}
.aurore__nappe {
  position: absolute;
  top: 50%;
  width: 62%; height: 260%;
  border-radius: 50%;
  filter: blur(46px);
  will-change: transform;
}
.aurore__nappe--une {
  left: -14%;
  background: radial-gradient(closest-side, var(--accent) 0%, transparent 78%);
  transform: translate3d(0, calc(-50% + var(--d) * -70px), 0);
}
.aurore__nappe--deux {
  right: -18%;
  background: radial-gradient(closest-side, var(--accent-soft) 0%, transparent 76%);
  transform: translate3d(calc(var(--d) * 60px), calc(-50% + var(--d) * 46px), 0);
}
.aurore__nappe--trois {
  left: 26%;
  width: 52%; height: 200%;
  background: radial-gradient(closest-side, var(--bg-alt) 0%, transparent 80%);
  transform: translate3d(calc(var(--d) * -52px), calc(-50% + var(--d) * -34px), 0) scale(calc(0.92 + var(--d) * 0.16));
}
.aurore__dedans {
  position: relative; z-index: 1;
  max-width: var(--largeur-max); margin: 0 auto;
}
@media (max-width: 700px) {
  .aurore__nappe { width: 96%; filter: blur(34px); }
  .aurore__nappe--trois { width: 86%; }
}
@media (prefers-reduced-motion: reduce) {
  .aurore__champ { --d: 0.5 !important; }
  .aurore__nappe { transition: none; }
}
@media print { .aurore__champ { display: none; } }

/* --- Citation (propre au site) ---------------------------------------------
   La seule phrase du client sur son métier, citée telle qu'elle a été écrite.
   Un filet d'accent plutôt que des guillemets typographiques seuls : un
   `blockquote` sans marque visuelle se lit comme un paragraphe ordinaire. */
.citation { margin: 0 0 var(--pas); padding-left: var(--pas); border-left: 3px solid var(--accent); }
.citation p { font-size: var(--t-sous-titre); color: var(--ink); margin: 0; }

/* --- Les étapes (propre au site) ------------------------------------------- */
.etapes { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--pas); margin-top: var(--pas); }
.etape { padding-top: var(--pas); border-top: 2px solid var(--accent); }
.etape__no { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--accent); }
.etape h3 { margin: 8px 0 8px; }
.etape p { margin: 0; }
/* Le paragraphe qui suit la grille doit s'en détacher, sinon il se lit comme
   la suite de la première étape : vu en capture, la phrase sur l'absence de
   créneau semblait appartenir à « Vous dites ce qu'il vous faut ». */
.etapes + p { margin-top: clamp(30px, 4.5vw, 56px); }

/* --- Horaires : _socle/composants/tableau-horaires.html -------------------- */
.horaires { margin: 0 0 var(--pas); max-width: 34rem; }
.horaires__jour {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: 4px 16px; padding: 9px 0;
  border-top: 1px solid var(--line);
}
.horaires__jour:first-child { border-top: 0; padding-top: 0; }
.horaires dt { color: var(--ink); letter-spacing: 0.02em; }
.horaires dd { margin: 0; color: var(--body); font-variant-numeric: tabular-nums; }
.horaires__plage { white-space: nowrap; }
.horaires__ferme { color: var(--accent); }
.horaires--cascade .horaires__jour {
  opacity: 0; transform: translateY(10px);
  transition: opacity 420ms ease, transform 420ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.horaires--cascade .horaires__jour.est-visible { opacity: 1; transform: none; }
.horaires__jour--aujourdhui { position: relative; }
.horaires__jour--aujourdhui dt { color: var(--accent); }
.horaires__jour--aujourdhui::before {
  content: ''; position: absolute; left: -14px; top: 50%;
  width: 0; height: 2px; background: var(--accent);
  transform: translateY(-50%);
  transition: width 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.horaires--repere .horaires__jour--aujourdhui::before { width: 8px; }
@media (prefers-reduced-motion: reduce) {
  .horaires--cascade .horaires__jour { opacity: 1; transform: none; transition: none; }
  .horaires__jour--aujourdhui::before { transition: none; }
}

/* --- Formulaire : _socle/composants/formulaire-conforme.html --------------- */
.form { display: flex; flex-direction: column; gap: 16px; max-width: 34rem; }
.form__champ { display: flex; flex-direction: column; gap: 6px; }
.form__champ label { font-size: var(--t-petit); }
.form__champ input,
.form__champ textarea {
  min-height: 44px; padding: 10px 14px;
  border: 1px solid var(--line-strong); border-radius: var(--arrondi);
  background: var(--card); color: var(--ink); font: inherit;
}
.form__champ textarea { min-height: 120px; resize: vertical; }
.form__mention { margin: 0; font-size: var(--t-petit); color: var(--muted); }
.form__reponse { margin: 0; font-size: var(--t-petit); color: var(--accent-dark); }
.section-sombre .form__reponse { color: var(--accent-clair); }
/* Le champ en défaut se signale par DEUX signaux, le filet et le texte
   d'erreur, jamais par la couleur seule : critère RGAA 3.1. */
.form__champ input[aria-invalid="true"],
.form__champ textarea[aria-invalid="true"] { border-width: 2px; border-color: var(--accent); }

/* --- Les trous factuels (propre au site) -----------------------------------
   TOUT CE QUE LE CLIENT N'A PAS DIT RESTE VISIBLE DANS LA PAGE. C'est la règle
   de l'atelier, et c'est ce qui empêche qu'un numéro de téléphone plausible ou
   une zone de livraison vraisemblable finisse en ligne. Chaque occurrence est
   listée dans CONTENU.md.

   Le soulignement en pointillé ne porte pas l'information tout seul : le texte
   entre crochets la dit déjà, et `title` la répète pour qui survole. */
.trou {
  text-decoration: underline dotted var(--accent);
  text-underline-offset: 0.22em;
  text-decoration-thickness: 2px;
  color: var(--body);
}
.section-sombre .trou { color: var(--on-panel); text-decoration-color: var(--accent-clair); }
.encart-trou {
  border: 1px dashed var(--accent);
  padding: var(--pas);
  margin: 0 0 var(--pas);
  background: var(--card);
  max-width: var(--largeur-texte);
}
.encart-trou p:last-child { margin-bottom: 0; }
.encart-trou h3 { margin-top: 0; }

/* --- Pied de page : _socle/composants/signature-en-pied.html --------------- */
.pied { border-top: 1px solid var(--line); padding: var(--section) 0; background: var(--bg-alt); }
.pied__liens { display: flex; flex-wrap: wrap; gap: var(--pas); align-items: center; }
.pied p.pied__signature {
  max-width: 1180px; margin: clamp(44px, 6vw, 84px) auto 0;
  font-family: var(--font-titre); font-weight: 400;
  font-size: clamp(2.2rem, 12vw, 9rem); line-height: 0.8;
  letter-spacing: 0.01em; text-align: center; white-space: nowrap;
  color: color-mix(in srgb, var(--muted) 78%, var(--bg-alt));
}
@media print { .pied p.pied__signature { display: none; } }

/* --- Pages de texte long (mentions, confidentialité) ----------------------- */
.texte-long { max-width: 74ch; }
.texte-long h2 { margin-top: var(--section); }
.texte-long h2:first-of-type { margin-top: var(--pas); }
.texte-long ul { padding-left: 1.2em; max-width: var(--largeur-texte); }
.texte-long li { margin-bottom: 8px; }

/* L'image de l'ouverture. Reprise du composant `hero-expansion.html` du socle :
   elle avait été retirée quand la chaîne a construit le site sans photo, et
   elle revient à l'identique le jour où les photos arrivent. */
.hero-expansion__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 46%;
  display: block;
}

/* Les images des trois étapes. `aspect-ratio` plutôt qu'une hauteur fixe :
   les six fichiers déposés n'ont pas le même format, et une hauteur en dur
   déformerait les uns ou rognerait les autres. */
.etape__image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  margin: 0 0 clamp(14px, 1.6vw, 22px);
  border-radius: var(--arrondi-carte);
}

/* Les images des pages intérieures. Les fichiers déposés font entre 178 et
   344 pixels de large : on borne donc leur affichage plutôt que de les étirer,
   une image agrandie au-delà de sa définition étant une image floue. */
.page-tete__image,
.section__image {
  display: block;
  width: 100%;
  max-width: 420px;
  height: auto;
  margin: clamp(20px, 2.4vw, 32px) 0 0;
  border-radius: var(--arrondi-carte);
}

/* LE VOILE DE L'OUVERTURE : IL EST SOUS LE TEXTE, PAS SUR LA PHOTO.
   ================================================================

   Il n'est pas décoratif, il est la condition pour que le titre soit lisible.
   Mesuré le 19/09/2026, sans lui : contraste 1,00:1 sur le titre, c'est-à-dire
   aucun contraste, pour un seuil de 3:1.

   axe-core ne voit RIEN de ce défaut : il ne connaît que les couleurs
   déclarées en CSS, et le fond d'une photo n'y est pas. Le contrôle rendait
   « 0 violation » sur un titre illisible. C'est la limite documentée au lot
   L47 de Palier, et la mesure se fait avec
   `outils/chaine-web/contraste-sur-image.mjs`, qui lit les vrais pixels.

   TROIS ESSAIS, ET SEUL LE TROISIÈME TIENT. C'est ce qui vaut d'être retenu.

   1. Voile CRÈME sur la photo, pour garder le texte brun du site. Passait à
      4,37:1, et il fallait le pousser si fort que la photo disparaissait :
      un titre lisible sur un rectangle beige, et plus aucune raison d'avoir
      mis une photo.
   2. Voile SOMBRE sur la photo, texte clair. Bien meilleur sur grand écran,
      4,63:1 à 1280 pixels. Mais à 320 et 390 pixels, le texte devient plus
      HAUT que la photo et déborde sur le fond crème de la page : le texte
      clair y tombait à 1,10:1. Une régression que seule la mesure à plusieurs
      largeurs a montrée.
   3. Voile sous le TEXTE. Il suit le texte partout où il va, quelle que soit
      la largeur d'écran, et il ne peut pas se désynchroniser de lui. La photo
      reste entière et lumineuse en dehors.

   Le voile s'efface avec l'expansion : `--pp` va de 0 au repos à 1 en plein
   écran, et à ce moment-là le texte a déjà disparu. */
.hero-expansion__texte {
  width: min(560px, 82vw);
  padding: clamp(20px, 2.6vw, 34px) clamp(18px, 2.4vw, 32px);
  border-radius: var(--arrondi-carte);
  background: rgb(24 15 10 / 0.72);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

/* Le texte de l'ouverture passe en clair, puisqu'il vit sur un fond sombre.
   Il n'y a que là : le reste du site garde son brun sur crème. */
.hero-expansion__texte .eyebrow { color: #F7DEAC; }
.hero-expansion__texte h1 {
  background-image: linear-gradient(178deg, #FFFFFF 0%, #FBF1E6 100%);
}
.hero-expansion__texte h1 em { color: #F6CE92; -webkit-text-fill-color: #F6CE92; }
.hero-expansion__texte p { color: #F7F2EC; }
