/* =========================================================================
   Reliance au cheval : Thomas Ploton
   Refonte moderne & audacieuse. Chaleureux, terracotta golden-hour.
   Beaucoup d'animation. Zéro tiret cadratin dans le contenu.
   Design tokens FIRST. Aucune couleur en dur hors de :root.
   ========================================================================= */

/* -------- Fonts (self-hosted, Fontsource woff2, OFL) --------------------- */
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/fraunces-latin-wght-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Fraunces";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/fraunces-latin-wght-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin-wght-normal.woff2") format("woff2");
}

/* =========================================================================
   TOKENS — voir tokens.css

   Le bloc :root a été DÉPLACÉ dans tokens.css, qui est désormais la source de
   vérité unique de la charte et doit être chargé AVANT cette feuille :

       <link rel="stylesheet" href="tokens.css" />
       <link rel="stylesheet" href="styles.css" />

   Ne redéclarez aucun token ici : une redéclaration gagnerait dans la cascade
   et rendrait tokens.css silencieusement inerte.
   Contrôle : `node site/charte-check.mjs`.
   ========================================================================= */

/* -------- Reset léger --------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%; scroll-behavior: smooth;
  /* Parenthèses et tirets alignés sur la capitale : supprime un « tell » de
     typo web non travaillée. */
  font-feature-settings: "case" on;
}
body {
  margin: 0;
  background: var(--c-paper);
  color: var(--c-ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  font-weight: var(--w-body);
  letter-spacing: var(--ls-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img { max-width: 100%; height: auto; display: block; }
/* .field, .presta-modal__tag… posent un display qui l'emporterait sur la règle
   [hidden] du navigateur (même spécificité, mais feuille auteur prioritaire).
   Sans ce !important, masquer un bloc en JS via .hidden = true n'a aucun effet. */
[hidden] { display: none !important; }

/* -------- Application de l'échelle typographique ------------------------- */
h1, .t-display {
  margin: 0; font-family: var(--font-display); font-size: var(--t-display);
  font-weight: var(--w-display); line-height: var(--lh-display);
  letter-spacing: var(--ls-display); text-wrap: balance; overflow-wrap: break-word;
  /* Alignement optique : un display à fleur de grille PARAÎT rentré. */
  margin-left: -0.03em;
}
h2, .t-title {
  margin: 0; font-family: var(--font-display); font-size: var(--t-title);
  font-weight: var(--w-title); line-height: var(--lh-title);
  letter-spacing: var(--ls-title); text-wrap: balance; overflow-wrap: break-word;
}
h3, h4, .t-card {
  margin: 0; font-family: var(--font-display); font-size: var(--t-card);
  font-weight: var(--w-title); line-height: var(--lh-card);
  letter-spacing: var(--ls-card); overflow-wrap: break-word;
}
p, li { font-size: var(--t-body); line-height: var(--lh-body); text-wrap: pretty; }
p { margin: 0; max-width: var(--measure); }
a { color: inherit; }
.num-prose { font-variant-numeric: oldstyle-nums; }
.num-ui    { font-variant-numeric: tabular-nums; }
::selection { background: var(--c-accent); color: var(--c-on-accent); }

/* -------- Utilitaires --------------------------------------------------- */
/* Le header est fixe et ne se masque jamais : les ancres doivent s'arrêter
   sous lui, sinon le haut de chaque section passe dessous. */
:target, section[id] { scroll-margin-top: 5.5rem; }
.wrap        { width: min(100% - 2 * var(--gutter), var(--wrap));       margin-inline: auto; }
.wrap-wide   { width: min(100% - 2 * var(--gutter), var(--wrap-full));  margin-inline: auto; }
.wrap-narrow { width: min(100% - 2 * var(--gutter), var(--wrap-prose)); margin-inline: auto; }

/* MICRO-LABEL : une seule classe pour un seul rôle. .eyebrow, .step__meta,
   .footer-col h3, .p-card__tag… partagent désormais taille, graisse et
   interlettrage. */
.eyebrow {
  font-family: var(--font-body);
  font-size: var(--t-micro);
  line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--c-accent-ink);
  font-weight: var(--w-label);
  margin: 0 0 var(--sp-2);
  /* L'interlettrage ajoute de l'espace APRÈS le dernier glyphe : sans cette
     compensation le label n'est pas optiquement à fleur de la colonne. */
  margin-right: calc(-1 * var(--ls-micro));
  display: inline-flex; align-items: center; gap: 0.75rem;
}
.eyebrow::before { content: ""; flex: none; width: 2.6rem; height: 1px; background: linear-gradient(90deg, currentColor, transparent); }
/* Titre de section : max-width en ch pour FORCER la casse en 2-3 lignes.
   La pile EST la composition. */
.section-title { font-size: var(--t-title); max-width: 16ch; letter-spacing: var(--ls-title); font-weight: var(--w-title); line-height: var(--lh-title); text-wrap: balance; }
.lede { font-size: var(--t-lede); color: var(--c-ink-soft); max-width: 44ch; line-height: var(--lh-lede); margin-top: var(--sp-3); }
.italic-accent { font-style: italic; color: var(--c-accent-ink); }
.skip-link {
  position: absolute; left: var(--sp-2); top: -100%;
  background: var(--c-ink); color: var(--c-on-night);
  padding: 0.75rem 1.25rem; z-index: 300; border-radius: var(--r-hair);
}
.skip-link:focus { top: var(--sp-2); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

:where(a, button, input, textarea, select, summary):focus-visible {
  outline: var(--focus); outline-offset: var(--focus-offset); border-radius: var(--r-hair);
}

/* -------- Boutons ------------------------------------------------------- */
/* La surface ne « pop » pas : elle s'éclaire, et l'ombre s'allonge vers la
   droite. Pas de scale(), pas de dégradé radial ambre, pas d'ombre teintée. */
.btn {
  --btn-bg: var(--c-ink); --btn-fg: var(--c-on-night);
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  min-height: 3.25rem; padding: 0.95rem 1.8rem;
  background: var(--btn-bg); color: var(--btn-fg);
  font-family: var(--font-body); font-size: var(--t-body); font-weight: var(--w-label);
  letter-spacing: var(--ls-body); text-decoration: none; border: 1px solid transparent;
  border-radius: var(--r-pill); cursor: pointer;
  transition: background-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover), box-shadow var(--d-micro) var(--e-hover), border-color var(--d-micro) var(--e-hover);
}
.btn > * { position: relative; z-index: 1; }
.btn--primary { --btn-bg: var(--c-accent); --btn-fg: var(--c-on-accent); }
.btn--primary:hover { background: var(--c-accent-deep); box-shadow: var(--shadow-lift); }
.btn--ghost {
  --btn-bg: transparent; --btn-fg: var(--c-ink);
  border-color: var(--c-ink);
}
.btn--ghost:hover { background: var(--c-ink); color: var(--c-paper); }
.btn--onnight { --btn-fg: var(--c-on-night); border-color: var(--c-line-night); }
.btn--onnight:hover { background: var(--c-on-night); color: var(--c-night); }
.btn--lg { min-height: 3.6rem; padding: 1.05rem 2.1rem; font-size: var(--t-lede); }
.btn__arrow { transition: transform var(--d-micro) var(--e-hover); display: inline-block; }
/* Paires de CTA (hero, contact) : même hauteur ET même largeur, quel que soit
   le libellé. Sans largeur commune, "Réserver un échange" et "Voir comment ça
   se passe" s'alignent en hauteur mais restent visiblement dépareillés. */
.hero__actions .btn,
.contact__actions .btn { width: 19rem; max-width: 100%; flex: none; }
/* justify-items: start empêche la grille d'étirer les boutons à toute la
   largeur de la colonne : sans ça, width est ignoré au profit du stretch. */
.contact__actions { display: grid; gap: var(--sp-3); justify-items: start; }
@media (max-width: 30rem) {
  .hero__actions { display: grid; }
  .contact__actions { justify-items: stretch; }
  .hero__actions .btn,
  .contact__actions .btn { width: 100%; }
}
.btn:hover .btn__arrow { transform: translateX(4px); }

/* =========================================================================
   Header
   ========================================================================= */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  background: transparent;
  transition: background-color var(--d-ui) var(--e-hover), backdrop-filter var(--d-ui) var(--e-hover), box-shadow var(--d-ui) var(--e-hover), transform var(--d-ui) var(--e-hover);
}
.site-header[data-scrolled="true"] {
  background: color-mix(in srgb, var(--c-paper) 86%, transparent);
  backdrop-filter: saturate(1.2) blur(14px);
  /* Le filet bas était écrit comme une couche d'ombre `0 1px 0` : ce n'est pas
     une ombre portée mais une bordure, et à offset-x nul elle contredisait la
     règle du contre-jour. Exprimée comme la bordure qu'elle est. */
  border-bottom: 1px solid var(--c-line);
  box-shadow: 6px 10px 30px -24px rgb(var(--rgb-ink) / 0.6);
}
/* Header toujours visible : aucun masquage au défilement. */
.site-header__inner { display: flex; align-items: center; justify-content: space-between; min-height: 4.75rem; }
/* min-height : la hauteur du lien venait du plus grand enfant (.brand__logo,
   2,4rem = 38px) et restait sous le seuil tactile, en en-tête comme en pied de
   page. Les enfants restent centrés par align-items, l'en-tête impose déjà
   4,75rem : seul le pied de page mobile gagne 6px. */
.brand { display: flex; align-items: center; gap: 0.7rem; text-decoration: none; color: var(--c-ink); transition: opacity var(--d-micro) var(--e-hover); min-height: 2.75rem; }
.brand:hover { opacity: 0.78; }
.brand__mark { width: 2.15rem; height: 2.15rem; flex: none; transition: transform var(--d-ui) var(--e-hover); }
.brand:hover .brand__mark { transform: rotate(-8deg) scale(1.05); }
.brand__name { font-family: var(--font-display); font-size: var(--t-lede); font-weight: var(--w-title); letter-spacing: var(--ls-card); line-height: 1; }
.brand__sub { display: block; font-family: var(--font-body); font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--c-ink-mute); font-weight: var(--w-label); margin-top: 2px; transform: scale(0.86); transform-origin: left center; }

/* état "sur hero sombre" : header transparent en clair sur photo */
.site-header:not([data-scrolled="true"]) .brand,
.site-header:not([data-scrolled="true"]) .nav__links a { color: var(--c-on-night); }
.site-header:not([data-scrolled="true"]) .brand__sub { color: var(--c-on-night-mute); }

.nav { display: flex; align-items: center; gap: var(--sp-3); }
.nav__links { display: flex; gap: 1.1rem; list-style: none; margin: 0; padding: 0; }
.nav__links a { text-decoration: none; font-size: var(--t-small); color: var(--c-ink-soft); position: relative; padding: 0.35rem 0; font-weight: var(--w-label); transition: color var(--d-micro) var(--e-hover); }
/* Le filet se déroule depuis la gauche, en scaleX et non en width : une
   largeur animée relance le layout à chaque image, une transformation non. */
.nav__links a::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 2px;
  background: var(--c-brand); border-radius: var(--r-hair);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-ui) var(--e-enter);
}
.nav__links a:hover::after, .nav__links a:focus-visible::after { transform: scaleX(1); }
/* Le CTA du header n'est pas le CTA du hero : ici il accompagne des liens de
   14 px, pas une affiche. On le ramène à l'échelle de la barre — 2,5rem de haut
   au lieu de 3,25 — ce qui libère aussi la largeur dont la nav a besoin pour
   tenir sur une ligne avec un lien de plus (Newsletter). */
.nav__cta {
  display: inline-flex;
  min-height: 2.5rem; padding: 0.42rem 1.05rem;
  font-size: var(--t-small); gap: 0.4rem;
}
.site-header:not([data-scrolled="true"]) .nav__cta.btn--ghost { border-color: rgb(var(--rgb-paper) / 0.55); color: var(--c-on-night); }
.site-header:not([data-scrolled="true"]) .nav__cta.btn--ghost:hover { background: var(--c-on-night); color: var(--c-night); }

/* Burger mobile.
   Bascule à 78rem (1248px), pas 48rem : avec 7 liens + CTA, la nav complète
   a besoin de ~78.5rem pour tenir sur une ligne (mesuré) ; entre 48rem et
   78rem elle retombait sur plusieurs lignes et le CTA débordait du header. */
.nav-toggle { display: none; }

/* =========================================================================
   Hero : plein écran, photo + typo géante animée
   ========================================================================= */
/* PLEIN ÉCRAN, À TOUTES LES TAILLES. min-height (jamais height) : sur un écran
   plus court que le contenu — portable 720p, mobile en paysage — la section
   s'allonge au lieu de rogner le CTA. svh et non vh : sur mobile, vh se calcule
   barre d'URL RÉTRACTÉE, et le bas du hero passait donc sous la barre à
   l'ouverture de la page. La ligne vh reste comme repli pour les moteurs qui
   ignorent svh. */
.hero {
  position: relative; color: var(--c-on-night); background: var(--c-night); overflow: hidden;
  display: flex; flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}
.hero__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
/* Pas de will-change ici : rien ne transforme cette image, et une promesse de
   transformation non tenue coûte une couche GPU plein écran pour rien. */
.hero__media img { width: 100%; height: 115%; object-fit: cover; object-position: 42% center; }
/* Contre-jour : la lumière vient de gauche, hors-champ. Le voile est donc
   plus dense à gauche (là où la colonne de texte est posée) et se rouvre vers
   le centre-droit. Aucun halo ambre dessiné : la lumière est déduite. */
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(90deg,
      rgb(var(--rgb-night) / 0.90) 0%,
      rgb(var(--rgb-night) / 0.60) 40%,
      rgb(var(--rgb-night) / 0.10) 75%,
      rgb(var(--rgb-night) / 0.40) 100%),
    var(--scrim-read);
}
/* Le grain reste : c'est le seul effet de matière conservé. À 0,18, pas 0,5.
   L'opacité est portée par un PSEUDO-ÉLÉMENT, pas par la boîte : un bloc de
   816 px figé à opacity 0.18 est indistinguable, pour un outil d'audit comme
   pour un lecteur d'écran, d'une révélation restée bloquée à mi-course. */
.hero__grain { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.hero__grain::before {
  content: ""; position: absolute; inset: 0; opacity: 0.18; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}
/* La colonne occupe toute la hauteur restante du hero, quelle qu'elle soit :
   plus de min-height chiffrée, qui débordait sous 40rem de haut et laissait du
   vide au-delà de 51,25rem. 4,75rem = la hauteur réelle du header fixe.
   Le padding bas réserve la place de la flèche : elle est posée en absolu et ne
   doit jamais recouvrir les boutons. */
.hero__inner {
  position: relative; z-index: 2;
  width: min(100% - 2 * var(--gutter), var(--wrap-full)); margin-inline: auto;
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-top: calc(4.75rem + var(--sp-4));
  padding-bottom: clamp(4.75rem, 3.25rem + 5vh, 7rem);
}
.hero__inner > * { min-width: 0; max-width: 100%; }
.hero__eyebrow {
  color: var(--c-accent-night); font-weight: var(--w-label); letter-spacing: var(--ls-micro);
  text-transform: uppercase; font-size: var(--t-micro); line-height: var(--lh-micro);
  margin-bottom: var(--sp-3); display: flex; align-items: center; gap: 0.8rem; max-width: 100%;
}
.hero__eyebrow::before { content: ""; flex: none; width: 2.4rem; height: 2px; background: currentColor; border-radius: var(--r-hair); }
.hero h1 { font-size: var(--t-display); font-weight: var(--w-display); letter-spacing: var(--ls-display); line-height: var(--lh-display); max-width: 15ch; text-wrap: balance; }
.hero h1 em { font-style: italic; color: var(--c-accent-night); font-weight: var(--w-display); }
.hero__sub { margin-top: var(--sp-3); max-width: 44ch; font-size: var(--t-lede); color: var(--c-on-night-mute); line-height: var(--lh-lede); }
.hero__actions { margin-top: var(--sp-4); display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }
.hero__note { font-size: var(--t-small); color: var(--c-on-night-mute); display: inline-flex; align-items: center; gap: 0.5rem; }

/* Le hero est la seule séquence d'ouverture de la page : ses mots montent sur
   --d-hero, tous les autres titres sur --d-block. */
.js .hero h1 { --word-dur: var(--d-hero); }
.js .hero:not(.is-in) .hero__eyebrow,
.js .hero:not(.is-in) .hero__sub,
.js .hero:not(.is-in) .hero__actions { opacity: 0; transform: translateY(24px); }
.hero__eyebrow, .hero__sub, .hero__actions { transition: opacity var(--d-block) var(--e-enter), transform var(--d-block) var(--e-enter); transition-delay: 0.5s; }
.hero.is-in .hero__sub { transition-delay: 0.65s; }
.hero.is-in .hero__actions { transition-delay: 0.8s; }

/* -------- Invite à poursuivre ------------------------------------------
   Une flèche, centrée, sans cartouche ni cercle : le geste suffit. Elle
   arrive en DERNIER (après le CTA) et s'efface dès les 40 premiers pixels de
   défilement — un indicateur « faites défiler » encore là après le défilement
   n'indique plus rien. */
.hero__scroll {
  position: absolute; z-index: 3;
  left: 50%; bottom: clamp(1rem, 2.4vh, 2.25rem); transform: translateX(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 3rem; height: 3rem;              /* cible tactile, pas une décoration */
  color: var(--c-on-night); text-decoration: none;
  opacity: 0;
  transition: opacity var(--d-block) var(--e-enter);
  transition-delay: 1.1s;
}
.hero.is-in .hero__scroll { opacity: 1; }
/* Défilement commencé : l'invite s'en va, sans délai et sans rester cliquable. */
.hero.is-scrolled .hero__scroll { opacity: 0; pointer-events: none; transition-delay: 0s; }
.hero__scroll-arrow {
  display: block; line-height: 0;
  animation: hero-bob 2.6s var(--e-hover) infinite;
}
.hero__scroll svg { width: 1.6rem; height: 1.6rem; display: block; }
.hero__scroll:hover .hero__scroll-arrow,
.hero__scroll:focus-visible .hero__scroll-arrow { animation-play-state: paused; transform: translateY(4px); opacity: 1; }
/* Amplitude volontairement courte (7px) : au-delà, ça fait bannière clignotante. */
@keyframes hero-bob {
  0%, 100% { transform: translateY(-3px); opacity: 0.5; }
  50%      { transform: translateY(4px);  opacity: 1; }
}

/* FENÊTRE COURTE : portable 720p, mobile en paysage, fenêtre non maximisée.
   Le hero garde min-height (il s'allonge plutôt que de rogner le CTA), mais à
   768px de haut il dépassait de ~63px : la flèche tombait sous la ligne de
   flottaison, et une invite « poursuivre » qu'il faut d'abord faire défiler
   pour voir ne sert à rien.
   On reprend ces pixels là où ils ne coûtent rien — les respirations et le
   logo, purement iconique — jamais sur le titre ni sur les boutons. */
@media (max-height: 48rem) {
  /* 4,5rem, pas 4 : la flèche fait 3rem de haut et se pose à ~1,1rem du bas.
     À 4rem, son sommet arrivait 1px SOUS le bas des boutons. */
  .hero__inner {
    padding-top: calc(4.75rem + var(--sp-1));
    padding-bottom: 4.5rem;
  }
  .hero__logo { max-height: 12vh; margin-bottom: var(--sp-2); }
  .hero__sub { margin-top: var(--sp-2); }
  .hero__actions { margin-top: var(--sp-3); }
  .hero__eyebrow { margin-bottom: var(--sp-2); }
}
/* Plus court encore : téléphone en paysage (~390px de haut). Là, aucune
   respiration ne suffit — c'est la TYPO d'affiche qui ne rentre pas. On la
   ramène à une échelle de lecture et on retire le logo, purement iconique : le
   titre, le sous-titre et les deux boutons, eux, restent tous les quatre. Rien
   n'est masqué, tout est resserré. */
@media (max-height: 30rem) {
  .hero { min-height: 100vh; min-height: 100svh; }
  .hero__logo { display: none; }
  .hero h1 { font-size: var(--t-title-s); max-width: 24ch; }
  .hero__sub { font-size: var(--t-small); margin-top: var(--sp-2); max-width: 52ch; }
  .hero__eyebrow { margin-bottom: var(--sp-1); }
  .hero__actions { margin-top: var(--sp-2); }
  .hero__actions .btn { min-height: 2.75rem; padding: 0.6rem 1.4rem; }
  .hero__inner { padding-bottom: var(--sp-3); }
  /* Plus la place pour l'invite sans recouvrir les boutons — et sur un écran de
     390px, le bas de page est de toute façon à un geste. */
  .hero__scroll { display: none; }
}

/* =========================================================================
   Sections génériques
   ========================================================================= */
/* RYTHME VERTICAL : le padding de section ALTERNE. Séquence appliquée sur la
   page d'accueil (voir index.html) : sm, md, md, lg, lg, sm, md, sm, sm.
   Deux sections consécutives au même padding ne sont acceptées que si leurs
   fonds diffèrent. --pad-md est la valeur par défaut. */
.section { padding-block: var(--pad-md); position: relative; }
.section--lg    { padding-block: var(--pad-lg); }
.section--sm,
.section--tight { padding-block: var(--pad-sm); }
.section--paper2 { background: var(--c-paper-2); }
/* La chaleur directionnelle : c'est ce qui empêche la nuit d'être plate sans
   qu'on voie un effet. */
.section--night { background: var(--c-night) var(--wash-sun); color: var(--c-on-night); }
.section--night .eyebrow { color: var(--c-on-night-mute); }
.section--night .lede { color: var(--c-on-night-mute); }
.section--night .section-title { color: var(--c-on-night); }

/* Section dont le fond EST une photographie plein cadre. Le voile n'est pas un
   aplat : un dégradé qui pèse en bas (là où se pose le formulaire) et s'allège
   en haut, pour que l'image reste une image et pas une texture. isolation crée
   le contexte d'empilement, sans quoi le z-index négatif du fond passerait
   sous la section elle-même. */
.section--photo { isolation: isolate; overflow: hidden; }
.section__bg { position: absolute; inset: 0; z-index: -1; }
.section__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 72% 56%; }
.section__bg::after {
  content: ""; position: absolute; inset: 0;
  background:
    /* Axe du soleil : le voile se densifie vers le bas-droite, jamais
       uniformément vers le bas. Un `to bottom` nu contredit le contre-jour. */
    linear-gradient(var(--sun-angle),
      color-mix(in srgb, var(--c-night) 62%, transparent) 0%,
      color-mix(in srgb, var(--c-night) 80%, transparent) 55%,
      color-mix(in srgb, var(--c-night) 88%, transparent) 100%);
}

/* Section qui respire : le sas newsletter porte à lui seul une image plein
   cadre, il lui faut la hauteur d'un vrai palier, pas d'un entre-deux. */
.section--tall { padding-block: clamp(6rem, 3.5rem + 12vw, 12rem); }

/* Contenu centré : la FAQ, seule section où la lecture est une liste de
   questions et non un propos suivi — l'axe d'encre n'a rien à y tenir.
   text-align va sur le CONTENEUR : .eyebrow est un inline-flex, se centrer
   soi-même par text-align ne marche pas, c'est le parent qui le place. */
.section--centered .wrap { text-align: center; }
.section--centered .section-title,
.section--centered .lede { margin-inline: auto; }
/* Le filet de l'eyebrow devient symétrique une fois centré : un seul tiret à
   gauche déséquilibrerait le label. */
.section--centered .eyebrow { margin-right: 0; }
.section--centered .eyebrow::after {
  content: ""; flex: none; width: 2.6rem; height: 1px;
  background: linear-gradient(270deg, currentColor, transparent);
}
/* La FAQ se recentre en bloc, mais son contenu reste aligné à gauche :
   des questions de longueurs inégales centrées se lisent mal. */
.section--centered .faq { margin-inline: auto; text-align: left; }

/* LA LIGNE D'HORIZON : le seul séparateur du site. Un filet rasant, plein
   cadre, qui s'éteint vers la droite. Ni ombre, ni trait décoratif centré. */
.section + .section::before {
  content: ""; position: absolute; inset-inline: 0; top: 0; height: 1px;
  background: var(--rule-horizon); pointer-events: none;
}
/* Le filet est peint SUR la section qui le porte : c'est donc son propre fond
   qui décide de sa couleur, pas celui de la section précédente. */
.section + .section--night::before { background: var(--rule-horizon-night); }

/* -------- Effet miroir : gros texte éditorial + carte flottante --------- */
.mirror { display: grid; gap: var(--sp-6); grid-template-columns: 1fr; align-items: center; }
.mirror__body p + p { margin-top: var(--sp-3); }
.mirror__body .drop::first-letter {
  font-family: var(--font-display); font-size: var(--t-dropcap); line-height: 0.78; float: left;
  padding: 0.06em 0.14em 0 0; color: var(--c-accent-ink); font-weight: var(--w-title);
}
.mirror__quote {
  position: relative; border-left: 3px solid var(--c-accent); padding: var(--sp-2) 0 var(--sp-2) var(--sp-4);
  font-family: var(--font-display); font-size: var(--t-title-s); line-height: 1.28;
  color: var(--c-ink); font-style: italic; letter-spacing: -0.01em;
}
/* Le guillemet ornemental était en --c-accent-tint, à 1,05:1 du fond
   --c-paper-2 de la section : il n'a jamais été visible. Teinte de marque
   diluée, qui se lit sans devenir un second titre. */
.mirror__quote::before { content: "\201C"; position: absolute; top: -0.35em; left: 0.15em; font-size: var(--t-display); line-height: var(--lh-flush); color: color-mix(in srgb, var(--c-brand) 26%, transparent); z-index: -1; }
.mirror__quote cite { display: block; margin-top: var(--sp-3); font-style: normal; font-family: var(--font-body); font-size: var(--t-small); letter-spacing: 0.06em; color: var(--c-ink-mute); text-transform: uppercase; }

/* -------- Déroulé d'une séance : une FRISE, quatre temps -----------------
   Les quatre filets indépendants deviennent UNE ligne continue, tracée au fil
   du défilement, et chaque temps s'allume quand la ligne l'atteint. C'est le
   seul endroit du site où la chronologie EST l'information : elle mérite d'être
   dessinée plutôt que sous-entendue par quatre traits parallèles.

   Verticale sous 64rem, horizontale au-delà. Le 2 x 2 intermédiaire est
   supprimé : une frise repliée en deux rangs se lit à l'envers (le temps 3
   revient à gauche, sous le temps 1).

   --rail = le rayon de la pastille : c'est ce qui aligne la ligne sur le CENTRE
   des pastilles, en vertical comme en horizontal. */
.steps {
  --rail: 0.6875rem;                    /* 11px = moitié de la pastille */
  --dot: 1.375rem;
  position: relative; list-style: none; padding: 0;
  margin: var(--sp-5) 0 0;
  display: grid; grid-template-columns: 1fr; gap: var(--sp-4) var(--grid-gap);
}
/* Le rail creux, puis le rail plein par-dessus. Deux pseudo-éléments en absolu :
   ils sortent donc de la grille et ne comptent pas comme colonnes. */
.steps::before,
.steps::after {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  left: var(--rail); top: var(--rail); bottom: var(--rail); width: 1px;
  margin-left: -0.5px;
}
.steps::before { background: var(--c-line); }
/* --p vaut 1 par défaut : sans JS, la frise est simplement déjà tracée. */
.steps::after {
  background: linear-gradient(var(--sun-angle), var(--c-accent), var(--c-accent-deep));
  transform: scaleY(var(--p, 1)); transform-origin: top;
}

.step {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: var(--dot) minmax(0, 1fr);
  gap: 0 var(--sp-3);
  padding: 0; background: none; border: 0;
}
/* La pastille EST le numéro : un rond posé sur le rail, opaque pour l'interrompre.
   Le fond reprend celui de la section (--c-paper-2), sinon le rail traverse. */
.step__num {
  width: var(--dot); height: var(--dot); flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--c-line); background: var(--c-paper-2);
  font-family: var(--font-display); font-size: var(--t-micro); line-height: 1;
  font-weight: var(--w-title); font-variant-numeric: lining-nums; letter-spacing: 0;
  color: var(--c-ink-mute); margin: 0;
  transition:
    background-color var(--d-block) var(--e-enter), border-color var(--d-block) var(--e-enter),
    color var(--d-block) var(--e-enter), transform var(--d-block) var(--e-enter);
}
/* Plus de "0" postiche : dans un rond de 22px, "01" est illisible. */
.step__num::before { content: none; }
.step[data-active="true"] .step__num {
  background: var(--c-accent); border-color: var(--c-accent); color: var(--c-on-accent);
  transform: scale(1.14);
}

/* Le texte suit la ligne : il n'entre que lorsque la pastille s'allume.
   data-timeline="on" est posé PAR LE JS. Sans lui — pas de JS, mise en place en
   échec, mouvement réduit — aucune de ces trois règles ne s'applique et les
   quatre temps sont lisibles d'emblée. */
.js .steps[data-timeline="on"] .step__body {
  opacity: 0; transform: translate3d(var(--rise-x), var(--rise-y), 0);
  transition: opacity var(--d-block) var(--e-enter), transform var(--d-block) var(--e-enter);
}
.js .steps[data-timeline="on"] .step[data-active="true"] .step__body {
  opacity: 1; transform: none;
}
.step__title { font-family: var(--font-display); font-size: var(--t-card); font-weight: var(--w-title); line-height: var(--lh-card); margin-bottom: var(--sp-1); letter-spacing: var(--ls-card); }
.step__meta {
  font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro);
  text-transform: uppercase; color: var(--c-ink-mute); margin-bottom: var(--sp-1);
  font-weight: var(--w-label); margin-right: calc(-1 * var(--ls-micro));
}
.step__text { color: var(--c-ink-soft); font-size: var(--t-small); }

/* -------- Piliers (pour qui / objectifs) : grille de cards -------------- */
.pillars { display: grid; gap: var(--sp-3); grid-template-columns: 1fr; margin-top: var(--sp-6); }
.pillar {
  position: relative; overflow: hidden;
  padding: var(--sp-4); border: 1px solid var(--c-line); border-radius: var(--r-0);
  background: color-mix(in srgb, var(--c-paper) 60%, transparent);
  transition: box-shadow var(--d-ui) var(--e-hover), background-color var(--d-ui) var(--e-hover), border-color var(--d-ui) var(--e-hover);
}
/* La surface ne « pop » pas : elle S'ÉCLAIRE. Le fond gagne en luminosité et
   l'ombre s'allonge vers la droite, du côté opposé au soleil. Pas de lift. */
.pillar:hover, .pillar:focus-within { box-shadow: var(--shadow-lift); background: var(--c-paper); border-color: var(--c-brand); }
.pillar__num { position: absolute; top: 0.4rem; right: var(--sp-3); font-family: var(--font-display); font-size: var(--t-title-s); color: var(--c-ink-mute); font-weight: var(--w-title); line-height: 1; pointer-events: none; }
.pillar h3 { position: relative; z-index: 1; font-size: var(--t-card); margin: 0 0 var(--sp-1); }
.pillar p { position: relative; z-index: 1; color: var(--c-ink-soft); font-size: var(--t-body); }

.audience-tags { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: var(--sp-5); }
.audience-tags li { list-style: none; }
.audience-tags span, .tag-list li {
  display: inline-flex; border: 1px solid var(--c-line); border-radius: var(--r-pill);
  padding: 0.5rem 1.1rem; font-size: var(--t-small); color: var(--c-ink-soft); background: var(--c-paper);
  transition: border-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover), background-color var(--d-micro) var(--e-hover);
}
.audience-tags span:hover { border-color: var(--c-brand); color: var(--c-accent-ink); background: var(--c-paper); }
.tag-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.6rem; }

/* -------- Citation pleine page (parallaxe) ------------------------------ */
.pullquote { position: relative; color: var(--c-on-night); background: var(--c-night); overflow: hidden; }
/* position:absolute doit gagner sur .media-reveal{position:relative} (même spécificité,
   déclarée plus bas) : sinon l'image repasse dans le flux et pousse la citation hors du visuel.
   inset en % se résoudrait sur la LARGEUR : on étire en px pour couvrir toute la hauteur. */
.pullquote .pullquote__media { position: absolute; inset: -6rem 0; z-index: 0; }
/* Le zoom de réserve n'est PAS un effet : c'est la marge de débordement dont
   la parallaxe a besoin pour ne jamais découvrir un bord de l'image. */
.pullquote__media img { width: 100%; height: 100%; object-fit: cover; object-position: 62% 34%; --p-zoom: 1.06; }
/* Scrim de lecture : plus opaque en bas-droite, jamais un voile uniforme.
   Le second dégradé suit --sun-angle pour asseoir la colonne de texte à gauche. */
/* La citation est désormais CENTRÉE dans le cadre : le voile ne peut donc plus
   être un dégradé latéral (il asseyait une colonne de gauche qui n'existe plus).
   Il densifie le centre et les deux bords, et laisse la lumière du pré
   respirer dans les angles. */
.pullquote__scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    /* Le halo elliptique centré est SUPPRIMÉ : une lumière dessinée, et le
       seul endroit du site où l'on pouvait pointer « le soleil » du doigt.
       Remplacé par un voile sur l'axe du soleil, à densité équivalente. */
    linear-gradient(var(--sun-angle),
      rgb(var(--rgb-night) / 0.22) 0%,
      rgb(var(--rgb-night) / 0.52) 45%,
      rgb(var(--rgb-night) / 0.72) 100%),
    linear-gradient(90deg,
      rgb(var(--rgb-night) / 0.45) 0%,
      rgb(var(--rgb-night) / 0.05) 45%,
      rgb(var(--rgb-night) / 0.35) 100%),
    var(--scrim-read);
}
/* La révélation se joue MOT À MOT au défilement : il faut donc de la course.
   65vh de haut, c'est ~500px de scroll pendant lesquels la phrase s'écrit. */
.pullquote__inner {
  position: relative; z-index: 2; padding-block: var(--pad-sm);
  display: flex; justify-content: center; align-items: center;
  min-height: min(78vh, 38rem);
}
.pullquote blockquote { margin: 0; width: min(100%, 34ch); text-align: center; }
.pullquote q { display: block; font-family: var(--font-display); font-size: var(--t-title); font-weight: var(--w-title); line-height: var(--lh-title); font-style: italic; quotes: "«\00a0" "\00a0»"; letter-spacing: var(--ls-title); overflow-wrap: break-word; text-wrap: balance; }
.pullquote__by { margin-top: var(--sp-3); font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro); text-transform: uppercase; font-weight: var(--w-label); color: var(--c-on-night); opacity: 0; transform: translateY(14px); transition: opacity var(--d-block) var(--e-enter), transform var(--d-block) var(--e-enter); transition-delay: 0.5s; }
.pullquote blockquote[data-shown="true"] .pullquote__by { opacity: 1; transform: translateY(0); }

/* -------- Formats & cadre (image + liste) ------------------------------- */
/* LE CONTREPOIDS : 5/7, jamais 6/6, et les deux blocs ne partagent pas de
   ligne de base. Le 6/6 à sommets alignés est la signature WordPress. */
.formats { display: grid; grid-template-columns: 1fr; gap: var(--grid-gap); align-items: start; }
.formats__media { position: relative; border-radius: var(--r-0); overflow: hidden; aspect-ratio: 3 / 2; background: var(--c-night-soft); box-shadow: var(--shadow-media); }
/* top: -4% (et non inset: 0) : la réserve de 8 % est répartie en HAUT ET EN
   BAS. Ancrée en haut, la parallaxe descendante découvrait le bord supérieur. */
.formats__media img { position: absolute; top: -5%; left: 0; right: 0; bottom: auto; width: 100%; height: 110%; object-fit: cover; }
.format-grid { display: grid; grid-template-columns: 1fr; gap: 0; margin-top: var(--sp-4); border-top: 1px solid var(--c-line-night); }
.format-item { padding-block: var(--sp-2); border-bottom: 1px solid var(--c-line-night); display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3); align-items: baseline; }
.format-item dt { font-family: var(--font-display); font-size: var(--t-card); font-weight: var(--w-title); line-height: var(--lh-card); min-width: 7rem; color: var(--c-on-night); }
.format-item dd { margin: 0; color: var(--c-on-night-mute); font-size: var(--t-small); }
.section--night .tag-list li { background: var(--c-night-soft); border-color: var(--c-night-soft); color: var(--c-on-night-mute); }

/* -------- LE CONTRE-JOUR : traitement commun de toutes les images ---------
   Trois ratios pour tout le site, et un seul voile de lecture autorisé, posé
   uniquement quand du texte se pose sur l'image. Aucun flou de fond, aucun
   voile noir uniforme, aucun rayon dessiné. */
.media { position: relative; overflow: hidden; border-radius: var(--r-0); background: var(--c-paper-2); }
.media > img, .media > video { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: var(--r-0); }
.media--read::after { content: ""; position: absolute; inset: 0; background: var(--scrim-read); pointer-events: none; }
.media--band      { aspect-ratio: 21 / 9; }
.media--editorial { aspect-ratio: 3 / 2;  }
.media--portrait  { aspect-ratio: 5 / 7;  }

/* LA BANDE HORIZON : respiration pleine largeur entre le cadre et les
   prestations. Aucun texte, donc aucun voile. Elle remplace aussi le filet
   de séparation entre ces deux sections : une image pleine largeur est déjà
   une ligne d'horizon. */
.horizon-band {
  width: 100%; max-width: 100%;
  aspect-ratio: 21 / 9; max-height: 22rem;
  background: var(--c-night);
}
.horizon-band img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%; }

/* -------- FAQ (accordéon) ------------------------------------------------ */
/* La FAQ reprend l'axe d'encre du site (elle flottait dans .wrap-narrow) mais
   garde une mesure lisible : un intitulé de question sur 1296px ne se lit pas. */
.faq { margin-top: var(--sp-4); border-top: 1px solid var(--c-line); max-width: 52rem; }
.faq details { border-bottom: 1px solid var(--c-line); }
.faq summary { list-style: none; cursor: pointer; padding: var(--sp-2) 0; display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3); font-family: var(--font-display); font-size: var(--t-card); font-weight: var(--w-title); line-height: var(--lh-card); letter-spacing: var(--ls-card); transition: color var(--d-micro) var(--e-hover); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--c-accent-ink); }
.faq summary .plus { flex: none; width: 1.5rem; height: 1.5rem; position: relative; transition: transform var(--d-ui) var(--e-panel); }
.faq summary .plus::before, .faq summary .plus::after { content: ""; position: absolute; top: 50%; left: 50%; background: var(--c-brand); border-radius: var(--r-hair); transform: translate(-50%, -50%); }
.faq summary .plus::before { width: 1.1rem; height: 2px; }
.faq summary .plus::after { width: 2px; height: 1.1rem; transition: transform var(--d-ui) var(--e-panel); }
.faq details[open] summary .plus::after { transform: translate(-50%, -50%) scaleY(0); }
.faq details[open] summary { color: var(--c-accent-ink); }
.faq__body { overflow: hidden; }
.faq__body p { padding-bottom: var(--sp-3); color: var(--c-ink-soft); max-width: var(--measure); }

/* -------- CTA final + formulaire ---------------------------------------- */
.contact { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); align-items: end; }
.contact .section-title { max-width: 14ch; }
.contact .lede { font-size: var(--t-body); }
.contact__intro .lede { color: var(--c-on-night-mute); }
.contact__aside { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
.contact__reassure { color: var(--c-on-night-mute); font-size: var(--t-small); max-width: 44ch; }
.lowfriction { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.lowfriction a {
  display: inline-flex; align-items: center; gap: 0.55rem; min-height: 3rem;
  padding: 0.7rem 1.2rem; border: 1px solid var(--c-line-night);
  border-radius: var(--r-pill); text-decoration: none; color: var(--c-on-night);
  font-size: var(--t-body); transition: background-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover);
}
.lowfriction a:hover { background: var(--c-on-night); color: var(--c-night); }
/* Le numéro s'affiche mais ne se clique pas à la souris : sur desktop un tel:
   ouvre une application tierce, ce qui n'est jamais ce que la personne voulait.
   Le lien reste actionnable au clavier et sur mobile — là où il a du sens.
   D'où la garde (hover: hover) and (pointer: fine) : sans elle, le doigt est
   lui aussi un pointeur, et pointer-events: none rendait le numéro
   INTOUCHABLE sur téléphone — exactement l'écran où l'appeler a du sens. */
@media (hover: hover) and (pointer: fine) {
  .lowfriction a[href^="tel:"] { pointer-events: none; }
}
.lowfriction svg { width: 1.1rem; height: 1.1rem; }

.form { background: var(--c-paper); color: var(--c-ink); border-radius: var(--r-0); padding: var(--sp-4); box-shadow: var(--shadow-media); }
.form__row { display: grid; gap: var(--sp-3); grid-template-columns: 1fr; }
.field { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: var(--sp-3); }
.field label { font-size: var(--t-small); font-weight: var(--w-label); letter-spacing: var(--ls-body); color: var(--c-ink); }
.field label .req { color: var(--c-accent-ink); }
.field input, .field textarea, .field select {
  font: inherit; font-size: var(--t-body); color: var(--c-ink);
  background: var(--c-paper-2); border: 1px solid var(--c-line); border-radius: var(--r-hair);
  padding: 0.85rem 0.95rem; min-height: 3rem; width: 100%;
  transition: border-color var(--d-micro) var(--e-hover), background-color var(--d-micro) var(--e-hover), box-shadow var(--d-micro) var(--e-hover);
}
.field textarea { min-height: 7rem; resize: vertical; }
.field input:focus, .field textarea:focus, .field select:focus { border-color: var(--c-brand); background: var(--c-paper); box-shadow: var(--shadow-focus); }
.field[data-invalid="true"] input, .field[data-invalid="true"] textarea { border-color: var(--c-error); }
.field__error { font-size: var(--t-small); color: var(--c-error); min-height: 1.1em; }
.field--honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.consent { display: grid; grid-template-columns: auto 1fr; gap: 0.7rem; align-items: start; margin-block: var(--sp-3); }
.consent input { width: 1.5rem; height: 1.5rem; margin-top: 0.1rem; accent-color: var(--c-brand); flex: none; }
.consent label { font-size: var(--t-small); color: var(--c-ink-soft); line-height: var(--lh-lede); }
.consent a { color: var(--c-accent-ink); text-underline-offset: 2px; }
.form__rgpd { font-size: var(--t-micro); color: var(--c-ink-mute); line-height: var(--lh-lede); margin-top: var(--sp-2); }
.form__submit { width: 100%; margin-top: var(--sp-2); }

.form__success { display: none; text-align: center; padding: var(--sp-4) var(--sp-2); }
.form[data-sent="true"] .form__fields { display: none; }
.form[data-sent="true"] .form__success { display: block; animation: pop 0.5s var(--e-enter); }
@keyframes pop { from { opacity: 0; transform: scale(0.92); } to { opacity: 1; transform: scale(1); } }
.form__success svg { width: 3rem; height: 3rem; color: var(--c-ok); margin-inline: auto; margin-bottom: var(--sp-3); }
.form__success h3 { font-size: var(--t-card); margin-bottom: var(--sp-2); }
.form__success p { color: var(--c-ink-soft); max-width: 40ch; margin-inline: auto; }

/* =========================================================================
   Footer
   ========================================================================= */
.site-footer { background: var(--c-night) var(--wash-sun); color: var(--c-on-night-mute); padding-block: var(--pad-sm) var(--sp-3); font-size: var(--t-small); }
.site-footer__top { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
.site-footer .brand { color: var(--c-on-night); }
.footer-blurb { margin-top: var(--sp-3); max-width: 34ch; color: var(--c-on-night-mute); font-size: var(--t-small); }
.site-footer .brand__sub { color: var(--c-on-night-mute); }
.footer-col h3 { font-family: var(--font-body); font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--c-on-night); margin: 0 0 var(--sp-2); font-weight: var(--w-label); margin-right: calc(-1 * var(--ls-micro)); }
.footer-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.3rem; }
.footer-col li { font-size: var(--t-small); }
/* La colonne "Le site" a beaucoup de liens : sur 2 colonnes, elle n'impose
   plus la hauteur de tout le pied de page. */
.footer-col--links ul { grid-template-columns: 1fr 1fr; gap: 0.3rem var(--sp-3); }
.footer-col a { color: var(--c-on-night-mute); text-decoration: none; transition: color var(--d-micro) var(--e-hover); }
.footer-col a:hover { color: var(--c-on-night); }
/* Lien Google (fiche établissement) : logo couleur sur fond nuit, donc posé
   sur une pastille claire pour rester lisible. */
.footer-google {
  display: inline-flex; align-items: center; gap: 0.55rem; margin-top: var(--sp-3);
  padding: 0.45rem 0.9rem 0.45rem 0.5rem; border: 1px solid rgb(var(--rgb-paper) / 0.18);
  border-radius: var(--r-pill); color: var(--c-on-night-mute); text-decoration: none;
  font-size: var(--t-small); transition: color var(--d-micro) var(--e-hover), border-color var(--d-micro) var(--e-hover), background var(--d-micro) var(--e-hover);
}
/* Le disque sous le logo Google reste dans la palette : --c-paper, pas un
   blanc pur, qui serait la seule couleur hors système de toute la feuille. */
.footer-google svg { width: 1.15rem; height: 1.15rem; flex: none; background: var(--c-paper); border-radius: 50%; padding: 0.15rem; }
.footer-google:hover { color: var(--c-on-night); border-color: rgb(var(--rgb-paper) / 0.4); background: rgb(var(--rgb-paper) / 0.06); }

/* Même bouton Google, posé sur fond clair (section « Le cadre »). */
.google-link {
  display: inline-flex; align-items: center; gap: 0.55rem; margin-top: var(--sp-3);
  padding: 0.45rem 0.9rem 0.45rem 0.5rem; border: 1px solid var(--c-line);
  border-radius: var(--r-pill); color: var(--c-ink-mute); text-decoration: none;
  font-size: var(--t-small); transition: color var(--d-micro) var(--e-hover), border-color var(--d-micro) var(--e-hover), background var(--d-micro) var(--e-hover);
}
.google-link svg { width: 1.15rem; height: 1.15rem; flex: none; }
.google-link:hover { color: var(--c-ink); border-color: var(--c-ink-mute); background: rgb(var(--rgb-ink) / 0.04); }

/* Adresse cliquable : renvoie vers Google Maps, souligné discret pour signaler
   que c'est un lien sans casser le rythme du texte autour. */
.map-link {
  color: inherit; text-decoration: underline; text-decoration-color: var(--c-line);
  text-underline-offset: 0.2em; transition: text-decoration-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover);
}
.map-link:hover { color: var(--c-accent-ink); text-decoration-color: currentColor; }
/* LE PLACEHOLDER : une annotation, pas une couleur de marque en italique.
   Sur nuit comme sur clair, il se lit comme une réserve à remplir. */
.footer-placeholder { color: var(--c-accent-night); font-style: italic; }
.section:not(.section--night) .footer-placeholder,
.p-card .footer-placeholder,
.presta-modal .footer-placeholder { color: var(--c-accent-ink); }
.site-footer__bottom { margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--c-line-night); display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); justify-content: space-between; font-size: var(--t-micro); }
.site-footer__legal { display: inline-flex; gap: var(--sp-3); }
.site-footer__legal a {
  color: var(--c-on-night-mute); text-decoration: none; transition: color var(--d-micro) var(--e-hover);
  /* Zone tapable de 44px sans déplacer un pixel : le rembourrage gonfle la
     boîte, la marge négative de même valeur la rend invisible au layout. */
  padding-block: 0.75rem; margin-block: -0.75rem;
}
.site-footer__legal a:hover { color: var(--c-on-night); }
.site-footer__credit { color: var(--c-accent-night); text-decoration: none; text-underline-offset: 2px; transition: color var(--d-micro) var(--e-hover); }
.site-footer__credit:hover { color: var(--c-on-night); text-decoration: underline; }

/* =========================================================================
   CTA sticky mobile
   ========================================================================= */
.sticky-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  padding: 0.7rem 1rem calc(0.7rem + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--c-paper) 92%, transparent);
  backdrop-filter: blur(10px); border-top: 1px solid var(--c-line);
  display: none;
  transform: translateY(120%); transition: transform var(--d-ui) var(--e-hover);
}
.sticky-cta[data-visible="true"] { transform: translateY(0); }
.sticky-cta .btn { width: 100%; }

/* =========================================================================
   Pages légales
   ========================================================================= */
.legal { padding-block: var(--pad-md); padding-top: calc(var(--pad-md) + 4rem); }
.legal h1 { font-size: var(--t-title); margin-bottom: var(--sp-2); margin-left: 0; }
.legal h2 { font-family: var(--font-display); font-size: var(--t-title-s); margin: var(--sp-5) 0 var(--sp-2); }
.legal p, .legal li { color: var(--c-ink-soft); max-width: var(--measure); }
/* Sans cette règle, `a { color: inherit }` rendait les liens en ligne des pages
   légales strictement indistinguables du corps de texte : couleur identique,
   seul un soulignement à 1,81:1 les signalait. Échec WCAG 1.4.1.
   Un lien porte désormais une couleur ET un soulignement. */
.legal p a, .legal li a { color: var(--c-link); text-decoration: underline; text-underline-offset: 0.15em; text-decoration-color: color-mix(in srgb, var(--c-link) 45%, transparent); transition: text-decoration-color var(--d-micro) var(--e-hover); }
.legal p a:hover, .legal li a:hover { text-decoration-color: currentColor; }
.legal ul { padding-left: 1.2rem; }
/* Le fond du placeholder vaut désormais --c-paper-2 : sur une section claire
   il se confondrait avec la surface. Un filet le détache sans le rendre plus
   voyant que le texte qui l'entoure : une annotation reste neutre. */
.legal .placeholder-inline { background: var(--c-paper-2); border: 1px solid var(--c-line); color: var(--c-accent-deep); padding: 0.05em 0.4em; border-radius: var(--r-hair); font-weight: var(--w-label); font-style: normal; }
.legal__back {
  display: inline-flex; align-items: center; gap: 0.5rem; text-decoration: none;
  color: var(--c-link); font-size: var(--t-small);
  /* 44px de zone tapable, rythme vertical préservé : la marge basse est
     réduite du rembourrage ajouté, la marge haute l'absorbe. */
  padding-block: 0.7rem; margin-top: -0.7rem; margin-bottom: calc(var(--sp-4) - 0.7rem);
}

/* =========================================================================
   RÉVÉLATION AU SCROLL
   -------------------------------------------------------------------------
   Une seule loi : le contenu entre depuis le BAS-GAUCHE, il arrive avec la
   lumière. Une seule courbe (--e-enter), une seule durée (--d-block), une
   seule distance (--rise-x / --rise-y).

   Règle de sûreté, non négociable : ces styles ne masquent le contenu QUE
   sous .js, et le JS garantit par balayage géométrique (indépendant de
   IntersectionObserver) que tout bloc atteignant le viewport reçoit
   data-shown. Aucun contenu ne peut rester invisible.

   Quatre variantes, parce qu'empiler deux animations sur le même bloc est
   exactement ce qui produisait des titres flous et semi-transparents :
     .reveal              fondu + montée
     .reveal--soft        fondu seul (le bloc contient des mots découpés)
     .reveal--words       rien (ses mots montent sous masque, c'est tout)
     .reveal--nested      rien (relaie seulement l'état à ses enfants)
   ========================================================================= */
.js .reveal {
  opacity: 0;
  transform: translate3d(var(--rise-x), var(--rise-y), 0);
  transition: opacity var(--d-block) var(--e-enter), transform var(--d-block) var(--e-enter);
  transition-delay: calc(var(--g, 0) * var(--stag-block));
}
.js .reveal[data-shown="true"] { opacity: 1; transform: none; }

/* Un conteneur dont le titre est découpé en mots ne prend QUE le fondu :
   deux translations imbriquées désalignent le masque et floutent le texte. */
.js .reveal.reveal--soft { transform: none; }
/* L'élément découpé lui-même ne s'anime pas : ses mots le font pour lui. */
.js .reveal.reveal--words { opacity: 1; transform: none; }
/* Une révélation imbriquée dans une autre ne s'anime jamais seule : elle ne
   fait que porter data-shown pour ses mots et ses enfants. */
.js .reveal.reveal--nested { opacity: 1; transform: none; }
/* Image : le balayage de .media-reveal EST la révélation. Pas de second effet. */
.js .reveal.media-reveal { opacity: 1; transform: none; }

/* CASCADE : les enfants entrent l'un après l'autre, jamais en bloc. */
.js .reveal--stagger > * {
  opacity: 0;
  transform: translate3d(var(--rise-x), var(--rise-y), 0);
  transition: opacity var(--d-block) var(--e-enter), transform var(--d-block) var(--e-enter);
  /* Plafonnée : une liste longue ne doit pas finir d'entrer après le scroll. */
  transition-delay: calc(min(var(--i, 0), 6) * var(--stag-block));
}
.js .reveal--stagger[data-shown="true"] > * { opacity: 1; transform: none; }

/* =========================================================================
   Motion avancé : barre de progression, scroll-spy, spotlight, split-titres
   ========================================================================= */
/* Barre de progression de lecture dans le header */
.scroll-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: transparent; }
/* Le rasant du soleil sur une ligne d'horizon : le filet s'éteint vers la droite. */
.scroll-progress span { display: block; height: 100%; width: 100%; transform: scaleX(0); transform-origin: left; background: linear-gradient(90deg, var(--c-brand), var(--c-accent-night)); }

/* Scroll-spy : lien de nav de la section courante */
.nav__links a[aria-current="true"] { color: var(--c-accent-night); }
.nav__links a[aria-current="true"]::after { transform: scaleX(1); }
.site-header[data-scrolled="true"] .nav__links a[aria-current="true"] { color: var(--c-accent-ink); }
.site-header:not([data-scrolled="true"]) .nav__links a[aria-current="true"] { color: var(--c-accent-night); }

/* Le spotlight radial au curseur sur .step / .pillar est SUPPRIMÉ : la lumière
   n'est jamais dessinée, elle est déduite. Voir la direction artistique. */

/* =========================================================================
   MICRO-PARALLAXE
   -------------------------------------------------------------------------
   Le JS ne pose PLUS de transform en ligne : il n'écrit que --py. Sans ça,
   son style en ligne écrasait la transformation de révélation de la même
   image, qui ne se jouait donc jamais.

   L'amplitude est MESURÉE, jamais devinée : elle est plafonnée à la réserve
   de débordement réelle de l'image (4 % de sa hauteur), donc aucun bord ne
   peut être découvert, à aucune vitesse de défilement.
   ========================================================================= */
.js [data-parallax] {
  transform: translate3d(0, var(--py, 0px), 0) scale(var(--p-zoom, 1));
  /* L'origine est posée sur le BORD DROIT, et c'est structurel, pas esthétique.
     Un conteneur `overflow: hidden` masque le débordement à l'œil mais conserve
     une zone défilable : avec une origine centrée, la réserve de zoom dépassait
     de 3 % à droite et gonflait le scrollWidth de la section sur les 13 formats.
     Ni `overflow: clip` ni `contain: paint` n'y changent quoi que ce soit (vérifié).
     En débordant vers la gauche — côté inline-start, ignoré par le calcul — la
     réserve reste entière sans jamais être mesurable. La composante verticale
     reste à 50 % : la marge dont la parallaxe a besoin est symétrique, intacte. */
  transform-origin: 100% 50%;
  will-change: transform;
}

/* Reveal en masque (clip) pour titres et images */
.js .reveal-clip { clip-path: inset(0 0 100% 0); transition: clip-path var(--d-block) var(--e-enter); }
.js .reveal-clip[data-shown="true"] { clip-path: inset(0 0 0 0); }
.media-reveal { position: relative; }
/* SOUS .js, IMPÉRATIVEMENT. Ce pseudo-élément est un cache opaque qui couvre
   l'image à 100 % et n'est retiré que par data-shown, lequel n'est posé que par
   le JS. Hors .js — JS absent, bloqué, ou en échec — il restait donc en place :
   chaque photo du site s'affichait en aplat terracotta. Le voile ne doit exister
   que là où quelqu'un est capable de le lever. */
.js .media-reveal::after {
  content: ""; position: absolute; inset: 0; z-index: 3; background: var(--c-accent-deep);
  transform: scaleX(1); transform-origin: right; transition: transform var(--d-block) var(--e-enter); border-radius: inherit;
}
.js .media-reveal[data-shown="true"]::after { transform: scaleX(0); }

/* =========================================================================
   MONTÉE PAR MOT
   -------------------------------------------------------------------------
   UNE seule règle pour le hero, les titres de section et la citation : trois
   jeux de sélecteurs quasi identiques cohabitaient, avec trois durées et
   trois cadences différentes pour un seul et même geste.

   padding-bottom + marge négative égale : la zone de clip descend sous la
   ligne de base, sinon le masque rogne les jambages (p, j, q, g, y) pendant
   ET après l'animation.
   ========================================================================= */
.js .word {
  display: inline-block; overflow: hidden; vertical-align: top;
  padding-bottom: 0.3em; margin-bottom: -0.3em;
}
.js .word > span {
  display: inline-block;
  transform: translate3d(0, 110%, 0);
  transition: transform var(--word-dur, var(--d-block)) var(--e-enter);
  /* Cadence plafonnée : sur un titre long, le dernier mot ne doit pas entrer
     une seconde après le premier. */
  transition-delay: calc(min(var(--i, 0), 10) * var(--stag-word));
}
/* Le drapeau peut être porté par l'élément découpé lui-même (titre de section)
   ou par son conteneur révélé (la citation, portée par son blockquote). */
.js [data-shown="true"] .word > span,
.js .hero.is-in .word > span { transform: none; }

/* =========================================================================
   Hero : vidéo de fond + logo
   ========================================================================= */
.hero__video {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: center 60%;
  /* Bascule sans fondu : le cadrage de la vidéo diffère légèrement de celui
     de la photo de repli (--c-on-night/42%… vs 60%), un fondu croisé entre
     les deux laissait voir un flash — les deux images se superposaient un
     instant à mi-fondu. Une coupe franche, elle, est imperceptible : le
     repli tient déjà le cadre à l'identique jusqu'à la dernière milliseconde. */
  opacity: 0;
}
.hero__video.is-ready { opacity: 1; }
.hero__media img { visibility: visible; }
.hero__media[data-video-ready="true"] img { opacity: 0; visibility: hidden; }

/* Logo en grand dans le hero */
.hero__logo {
  /* Se réduit quand le hero manque de hauteur : le CTA doit rester visible */
  width: clamp(7rem, 5rem + 9vw, 13rem);
  max-height: 22vh; object-fit: contain; object-position: left center;
  height: auto; margin-bottom: var(--sp-3);
  /* Décalage positif en x : la lumière vient de gauche, l'ombre tombe à droite. */
  filter: drop-shadow(10px 12px 40px rgb(var(--rgb-night) / 0.55));
}

/* Le logo remplace le picto SVG dans le header */
.brand__logo { width: 2.4rem; height: 2.4rem; flex: none; object-fit: contain; transition: transform var(--d-ui) var(--e-hover); }
.brand:hover .brand__logo { transform: rotate(-6deg) scale(1.06); }

/* =========================================================================
   Citation posée SUR la photo (ex-pullquote, texte par-dessus le cheval)
   ========================================================================= */
/* Assez large pour ne pas casser en colonne étroite sur la photo */
.pullquote blockquote { width: min(100%, 38rem); margin-inline: auto; position: relative; z-index: 1; }
.pullquote__by { text-align: center; }

/* -------- La phrase s'écrit au défilement --------------------------------
   Chaque mot s'allume à son tour, la progression étant PILOTÉE PAR LA POSITION
   de la citation dans la fenêtre (--p, de 0 à 1, posé par main.js), pas par une
   transition à durée fixe. On peut donc s'arrêter au milieu du geste, ou
   remonter, et la phrase suit.

   --p est LISSÉ EN JS (interpolation image par image), pas ici : une transition
   CSS sur une valeur réécrite à chaque image du défilement retarde le rendu
   sans jamais l'adoucir.

   L'opacité de chaque mot est une rampe : 0,12 tant que le front d'écriture ne
   l'a pas atteint, 1 une fois dépassé, sur une largeur de ~2,5 mots. Le "+4"
   allonge la course pour que le DERNIER mot finisse d'entrer avant p = 1.

   data-scrollwords="on" est posé PAR LE JS : sans JS, ou si la mise en place
   échoue, aucune de ces règles ne s'applique et la citation reste pleinement
   lisible. */
   LE DRAPEAU EST SUR LE BLOC, PAS SUR LA CITATION : les mots de la citation et
   ceux de l'attribution (« Le sens de l'effet miroir ») sont réindexés d'un
   bout à l'autre du blockquote par main.js. Ils forment donc UNE seule rampe,
   et l'attribution s'écrit naturellement après le dernier mot de la phrase —
   au lieu d'apparaître d'un bloc, en retard fixe de 0,5 s. */
.js .pullquote [data-scrollwords="on"] .word { overflow: visible; }
.js .pullquote [data-scrollwords="on"] .word > span {
  --t: calc((var(--p, 0) * (var(--n, 1) + 4) - var(--i, 0)) / 2.5);
  opacity: clamp(0.12, var(--t), 1);
  transform: translate3d(0, calc((1 - clamp(0, var(--t), 1)) * 0.42em), 0);
  transition: none;
  transition-delay: 0s;
}
/* L'attribution portait son PROPRE fondu, déclenché par data-shown : il aurait
   écrasé la rampe de ses mots (le bloc entier à opacity 0 jusqu'à la
   révélation). On le neutralise, ses mots font tout le travail. */
.js .pullquote [data-scrollwords="on"] .pullquote__by {
  opacity: 1; transform: none; transition: none;
}
/* Les guillemets sont posés par le navigateur (propriété quotes) : ce ne sont
   pas des mots, ils échappaient donc à la rampe. Le fermant restait à pleine
   opacité au bout d'une phrase encore à moitié éteinte, et flottait seul à
   droite du dernier mot. On les rattache aux extrémités de la CITATION —
   --qend, l'indice de son dernier mot, et non --n qui couvre aussi
   l'attribution : sinon le guillemet fermant attendrait la fin de celle-ci. */
.js .pullquote [data-scrollwords="on"] q::before {
  opacity: clamp(0.12, calc(var(--p, 0) * (var(--n, 1) + 4) / 2.5), 1);
}
.js .pullquote [data-scrollwords="on"] q::after {
  opacity: clamp(0.12, calc((var(--p, 0) * (var(--n, 1) + 4) - var(--qend, 0)) / 2.5), 1);
}

/* =========================================================================
   Qui je suis (parcours) : texte + image, repères chiffrés
   ========================================================================= */
/* align-items: start, jamais center : deux blocs qui partagent une ligne de
   base médiane produisent du vide sous le plus court. */
.about { display: grid; grid-template-columns: 1fr; gap: var(--grid-gap); align-items: start; }
.about__media { position: relative; border-radius: var(--r-0); overflow: hidden; min-height: 20rem; box-shadow: var(--shadow-media); }
.about__media img { position: absolute; inset: 0; width: 100%; height: 108%; object-fit: cover; }
/* Portrait : bord NET. Le masque en dégradé (halo de 29px sur les côtés,
   34px en haut/bas) se lisait comme un artefact de détourage.
   margin-inline: auto est retiré : il faisait basculer le bloc en fit-content
   et décalait le portrait de 117px vers l'intérieur, alors que toutes les
   autres sections démarrent leur encre au même x. */
/* La source fait 327 px de large. Au-delà, le navigateur l'agrandit et c'est
   CE flou de bord qu'on lisait comme un halo, pas un masque : le bloc est donc
   plafonné à la largeur native (20,4375rem = 327px) et rendu au 1:1. */
.about__media--portrait {
  overflow: hidden; min-height: 0; border-radius: var(--r-0);
  box-shadow: var(--shadow-media);
  width: min(100%, 20.4375rem); max-width: 20.4375rem; margin-inline: 0;
  aspect-ratio: 5 / 7; background: var(--c-paper-2);
}
/* Pas de fondu propre à l'image : le bloc .reveal qui la porte fait déjà
   exactement ce fondu. Empilés, les deux opacités se multiplient et le
   portrait traîne visiblement derrière le reste de la section. */
.about__media--portrait img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 22%; will-change: auto;
  border-radius: var(--r-0);
  /* Même raison que la parallaxe : le `scale(1.08 -> 1)` de la révélation
     dépassait de 4 % à droite tant que le bloc n'était pas ouvert, et ce
     débordement, bien que clippé, restait compté dans le scrollWidth du bloc
     sur tous les écrans. Ancré à droite, l'agrandissement part vers la gauche,
     côté qui n'entre pas dans le calcul. Origine calée sur 22 %, la même ligne
     focale que object-position : le portrait se pose EN CONVERGEANT sur le
     visage. Le cadrage AU REPOS est inchangé : à la fin de la course l'échelle
     vaut 1, l'origine n'a plus d'effet. */
  transform-origin: 100% 22%;
}
/* -------- Entrée de la section, LIÉE AU DÉFILEMENT -----------------------
   Le fondu de 0,6 s posé à l'entrée du bloc était invisible en pratique : il
   se déclenche quand le sommet du bloc franchit 90 % de la fenêtre, et il est
   terminé avant que la section soit vraiment sous les yeux. Ici comme pour la
   citation et la frise, la révélation SUIT la position dans la fenêtre : on la
   voit se faire, on peut l'arrêter au milieu, on peut la rembobiner.

   --p (0 à 1) est écrit par main.js sur .about. data-scrollreveal="on" est posé
   par le même code : sans lui, aucune de ces règles ne s'applique. */

/* Le portrait se découvre par le balayage du site, mais tiré par le défilement
   au lieu d'une durée fixe. x2,2 : entièrement ouvert à p = 0,45, pour que
   l'image ne traîne pas derrière le texte qui l'accompagne. */
.js .about[data-scrollreveal="on"] .about__media::after {
  transform: scaleX(clamp(0, calc(1 - var(--p, 0) * 2.2), 1));
  transition: none;
}
/* Et il se pose : 8 % trop grand au départ, à l'échelle une fois découvert.
   C'est ce qui donne de la profondeur au bloc — un fondu seul n'en a aucune. */
.js .about[data-scrollreveal="on"] .about__media--portrait img {
  transform: scale(calc(1.08 - 0.08 * clamp(0, calc(var(--p, 0) * 2.2), 1)));
  transition: none;
}

/* Les cinq blocs de texte montent l'un après l'autre, sur la même rampe que les
   mots de la citation : chacun est en retard d'un cran sur le précédent, et le
   dernier a fini d'entrer avant la fin de la course (p ≈ 0,73). */
.js .about[data-scrollreveal="on"] .about__body > * {
  --t: calc((var(--p, 0) * (var(--n, 1) + 2.5) - var(--i, 0)) / 1.5);
  --e: clamp(0, var(--t), 1);
  opacity: var(--e);
  transform: translate3d(calc((1 - var(--e)) * var(--rise-x)),
                         calc((1 - var(--e)) * var(--rise-y)), 0);
  transition: none;
}
/* Le titre est découpé en mots par splitTitles et monterait DONC une seconde
   fois, sous son propre masque, à l'intérieur d'un bloc déjà en translation :
   deux transformations imbriquées, soit exactement le défaut qui produisait des
   titres flous ailleurs sur le site. Ses mots restent au repos, la rampe porte
   le bloc entier. */
.js .about[data-scrollreveal="on"] .section-title .word > span {
  transform: none; transition: none;
}

.about__body p + p, .about__body h2 + p { margin-top: var(--sp-3); }
/* :not(.eyebrow) : sans cette exclusion, .about__body p (0,1,1) l'emportait sur
   .eyebrow (0,1,0) et le micro-label de cette seule section perdait l'accent. */
.about__body p:not(.eyebrow) { color: var(--c-ink-soft); }

/* =========================================================================
   Équicoaching : définition (ce que c'est / ce que ce n'est pas) + public
   ========================================================================= */
.def { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); margin-top: var(--sp-6); }
.def-card {
  position: relative; overflow: hidden; padding: var(--sp-5) var(--sp-4);
  border: 1px solid var(--c-line); border-radius: var(--r-0); background: var(--c-paper);
  transition: box-shadow var(--d-ui) var(--e-hover), border-color var(--d-ui) var(--e-hover);
}
.def-card:hover, .def-card:focus-within { box-shadow: var(--shadow-lift); border-color: var(--c-brand); }
.def-card--is { border-color: var(--c-accent-tint); }
.def-card--isnt { background: color-mix(in srgb, var(--c-paper-2) 70%, transparent); }
.def-card__head { display: flex; align-items: center; gap: 0.7rem; margin-bottom: var(--sp-3); }
.def-card__icon { width: 2rem; height: 2rem; flex: none; border-radius: 50%; display: grid; place-items: center; }
.def-card__icon svg { width: 1.05rem; height: 1.05rem; stroke-width: 2.4; }
.def-card--is .def-card__icon { background: color-mix(in srgb, var(--c-accent) 16%, transparent); color: var(--c-accent-ink); }
.def-card--isnt .def-card__icon { background: color-mix(in srgb, var(--c-ink-mute) 14%, transparent); color: var(--c-ink-mute); }
.def-card__head h3 { font-size: var(--t-card); font-weight: var(--w-title); }
.def-card ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.75rem; }
.def-card li { display: grid; grid-template-columns: auto 1fr; gap: 0.7rem; align-items: start; color: var(--c-ink-soft); font-size: var(--t-body); }
.def-card li::before { content: ""; width: 6px; height: 6px; border-radius: 50%; margin-top: 0.62em; background: var(--c-brand); }
.def-card--isnt li::before { background: var(--c-ink-mute); opacity: 0.5; }

/* =========================================================================
   Slider prestations : horizontal, auto + manuel
   ========================================================================= */
.slider { margin-top: var(--sp-4); position: relative; }
/* Pas de mask-image sur le viewport : le fondu de bord effaçait la 4e carte
   au lieu de suggérer la suite, et il rongeait aussi la 1re. */
.slider__viewport {
  /* proximity, pas mandatory : avec plusieurs cartes visibles à la fois, la
     dernière position de scroll n'est jamais un point d'ancrage valide, et
     mandatory renvoyait la piste en arrière juste après l'avoir atteinte. */
  overflow-x: auto; overflow-y: hidden; scroll-snap-type: x proximity;
  scrollbar-width: none; -ms-overflow-style: none;
}
.slider__viewport::-webkit-scrollbar { display: none; }
.slider__track { display: flex; gap: var(--grid-gap); padding: var(--sp-1) 0 var(--sp-3); width: max-content; }
/* CARTE PLEINE IMAGE. La photo n'est plus une vignette au-dessus d'un bloc de
   texte : elle EST la carte, et le texte se pose dessus sur un voile. D'où la
   pile en trois couches — image, voile, contenu — et non plus deux blocs
   empilés. Le contenu est volontairement pauvre (titre, une phrase, deux faits,
   deux boutons) : tout le détail est dans la modale "Plus d'infos". */
.p-card {
  /* scroll-snap-align: start, et non center : le JS positionne le viewport sur
     i x pas-de-carte, ce qui aligne la carte à GAUCHE. Avec center, le snap du
     navigateur corrigeait aussitôt la position calculée par le JS. */
  position: relative; overflow: hidden; scroll-snap-align: start; flex: none;
  width: min(84vw, 30rem);
  /* Format paysage-portrait, nettement plus bas que l'ancienne carte 5/7 +
     corps de texte. min/max bornent le ratio aux largeurs extrêmes : sous
     ~22rem de large la carte deviendrait trop courte pour son contenu, au-delà
     de ~34rem elle redeviendrait une affiche. */
  aspect-ratio: 5 / 4; min-height: 25rem; max-height: 32rem;
  display: flex; flex-direction: column; justify-content: flex-end;
  border: 1px solid var(--c-line); border-radius: var(--r-card);
  background: var(--c-night); color: var(--c-on-night);
  transition: box-shadow var(--d-ui) var(--e-hover), border-color var(--d-ui) var(--e-hover), transform var(--d-ui) var(--e-hover);
}

/* LARGEUR DE CARTE DÉRIVÉE DU VIEWPORT, pas devinée.
   Le compte de cartes visibles est ici FRACTIONNAIRE et assumé : à 2,5, la
   troisième carte est coupée en son milieu, ce qui annonce la suite du
   carrousel bien mieux qu'une rangée de cartes qui tombe pile. La formule reste
   la même — on retire les gouttières avant de diviser — donc la carte partielle
   du bord droit est toujours coupée exactement où on l'a décidé. */
@supports (container-type: inline-size) {
  .slider__viewport { container-type: inline-size; }
  .slider__track { --cards: 1.12; }
  .p-card {
    width: calc((100cqi - (var(--cards) - 1) * var(--grid-gap)) / var(--cards));
  }
  @media (min-width: 48rem) { .slider__track { --cards: 1.6; } }
  @media (min-width: 64rem) { .slider__track { --cards: 2.1; } }
  @media (min-width: 88rem) { .slider__track { --cards: 2.5; } }
}
/* La surface ne « pop » pas : elle s'éclaire, et l'ombre s'allonge vers la droite. */
.p-card:hover, .p-card:focus-within { box-shadow: var(--shadow-lift); border-color: var(--c-brand); }
/* La PHOTO s'éclaire aussi : le voile de lecture se retire un peu. C'est la
   seule façon d'« allumer » une image sans dessiner de lumière, et sans le
   zoom au survol que la direction artistique proscrit. */
.p-card__media::after { transition: opacity var(--d-ui) var(--e-hover); }
.p-card:hover .p-card__media::after,
.p-card:focus-within .p-card__media::after { opacity: 0.82; }
/* Couche 1 + 2 : la photo occupe toute la carte, le voile la couvre entièrement.
   Le voile est plus dense que le --scrim-read commun du site : ici le texte
   descend plus bas sur l'image et doit rester lisible sur des photos claires
   (chaume doré, crinière blonde) comme sombres. */
.p-card__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: var(--c-paper-2); border-radius: inherit; }
.p-card__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.p-card__media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to top,
      rgb(var(--rgb-night) / 0.92)  0%,
      rgb(var(--rgb-night) / 0.78) 34%,
      rgb(var(--rgb-night) / 0.34) 68%,
      rgb(var(--rgb-night) / 0.20) 100%);
}
.p-card__tag {
  position: absolute; z-index: 2; top: var(--sp-3); left: var(--sp-3);
  font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro);
  text-transform: uppercase; font-weight: var(--w-onmedia);
  color: var(--c-on-accent); background: color-mix(in srgb, var(--c-accent) 92%, transparent);
  padding: 0.25rem 0.6rem; border-radius: var(--r-pill); backdrop-filter: blur(4px);
  transform: scale(0.86); transform-origin: left top;
}
/* Couche 3 : le contenu, calé en bas de la carte par le justify-content du
   parent. Plus de flex:1 ni de réserves de lignes — les cartes ne s'alignent
   plus par le haut de leur texte mais par leur bord bas, qui est commun. */
.p-card__body { position: relative; z-index: 1; padding: var(--sp-3); }
.p-card__title {
  font-family: var(--font-display); font-size: var(--t-card); font-weight: var(--w-title);
  line-height: var(--lh-card); letter-spacing: var(--ls-card); color: var(--c-on-night);
}
/* Deux lignes maximum : la phrase d'accroche donne l'intention, pas le détail.
   Le reste est dans la modale. */
.p-card__desc {
  margin-top: var(--sp-1); color: rgb(var(--rgb-paper) / 0.88); font-size: var(--t-small);
  /* Assez large pour que les accroches, calibrées pour deux lignes, ne se
     fassent pas couper en plein milieu d'une phrase par le line-clamp. */
  max-width: 46ch;
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--desc-lines, 2); overflow: hidden;
}
/* Un NOMBRE DE LIGNES fixe n'est pas une mesure responsive : « deux lignes »
   est calibré sur une carte large. Sur un téléphone la carte fait ~250px, la
   même phrase demande cinq lignes — et le clamp à 2 coupait cinq des six
   accroches en plein milieu, sans même le point de suspension pour le dire.
   Sous 48rem on rend donc à la phrase les lignes dont elle a besoin : la carte
   fait 25rem de haut minimum et son contenu est calé en bas, la place est là.
   Au-dessus, la carte est assez large pour que deux lignes suffisent, et le
   rythme voulu par la direction artistique reprend la main. */
@media (max-width: 47.99rem) {
  .p-card { --desc-lines: 5; }
}
/* Deux faits, en ligne, séparés par un point médian : la durée et le format.
   Le lieu et le tarif ont rejoint la modale. */
.p-card__meta {
  list-style: none; margin: var(--sp-2) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.9rem;
}
.p-card__meta li { display: inline-flex; align-items: center; gap: 0.4rem; font-size: var(--t-micro); color: var(--c-on-night-mute); }
.p-card__meta svg { width: 0.9rem; height: 0.9rem; color: var(--c-accent-night); flex: none; }

/* Prix d'appel « À partir de X€ », posé sur la carte entre les deux faits et les
   boutons. Le « À partir de » reste discret (texte de méta sur sombre) et le
   montant prend l'accent-night — le seul accent qui tient le contraste sur le
   fond nuit de la carte (6,49:1). C'est une accroche, pas le tarif ferme : le
   détail et la mention « selon le format » vivent dans la modale (.p-card__price,
   stylée par .presta-modal__price). */
.p-card__from {
  margin-top: var(--sp-2); font-size: var(--t-small); color: var(--c-on-night-mute);
}
.p-card__from strong {
  font-family: var(--font-display); font-weight: var(--w-title); color: var(--c-accent-night);
}

/* -------- Actions dans la carte ----------------------------------------- */
.p-card__actions { margin-top: var(--sp-3); display: grid; gap: 0.5rem; grid-template-columns: 1fr 1fr; }
.btn--sm { min-height: 2.6rem; padding: 0.55rem 0.9rem; font-size: var(--t-small); gap: 0.4rem; }
.p-card__actions .btn { width: 100%; }
.p-card__actions .btn svg { width: 0.95rem; height: 0.95rem; flex: none; }
/* Le bouton fantôme du site est dessiné pour le papier : posé sur la photo, son
   filet d'encre disparaissait. Sur la carte il devient un verre dépoli clair. */
.p-card__actions .btn--ghost {
  color: var(--c-on-night); border-color: var(--c-line-night);
  background: rgb(var(--rgb-night) / 0.42); backdrop-filter: blur(6px);
}
.p-card__actions .btn--ghost:hover {
  color: var(--c-night); background: var(--c-on-night); border-color: var(--c-on-night);
}

/* -------- Badge de disponibilité sur la vignette ------------------------- */
.p-card__avail {
  position: absolute; z-index: 2; top: var(--sp-3); right: var(--sp-3);
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro);
  text-transform: uppercase; font-weight: var(--w-onmedia);
  padding: 0.25rem 0.55rem; border-radius: var(--r-pill); backdrop-filter: blur(4px);
  transform: scale(0.8); transform-origin: right top;
}
.p-card__avail svg { width: 0.78rem; height: 0.78rem; flex: none; }
/* Dates imposées : on reprend l'encre sombre, pour ne pas rivaliser avec le
   tag terracotta posé à gauche sur la même image. */
.p-card__avail--fixed {
  color: var(--c-on-night); background: rgb(var(--rgb-night) / 0.78);
  border: 1px solid var(--c-line-night);
}
.p-card__avail--free {
  color: var(--c-on-night); background: rgb(var(--rgb-night) / 0.55);
  border: 1px solid var(--c-line-night);
}

/* -------- Contrôles du slider ------------------------------------------- */
/* Les flèches sont posées à gauche et à droite des cartes. Encre pleine et non
   papier : sur une rangée de cartes désormais toutes sombres, le bouton clair
   se lisait comme un trou dans la bande.
   HAUTEUR : 30 % et non 50 %. Centrée, la flèche tombait pile sur le titre de
   la carte, qui est calé en bas depuis que la photo occupe toute la carte. Le
   bloc de texte commence vers 46 % de la hauteur de carte : à 30 %, la flèche
   tient entièrement dans la zone de photo, au-dessus du texte. */
.slider__btn {
  position: absolute; top: 30%; transform: translateY(-50%); z-index: 5;
  width: 3.4rem; height: 3.4rem; flex: none; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--c-line-night); background: rgb(var(--rgb-night) / 0.82);
  color: var(--c-on-night); backdrop-filter: blur(6px);
  display: grid; place-items: center; box-shadow: var(--shadow-lift);
  transition: background-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover), border-color var(--d-micro) var(--e-hover);
}
.slider__btn svg { width: 1.25rem; height: 1.25rem; }
.slider__btn:hover { background: var(--c-accent); color: var(--c-on-accent); border-color: var(--c-accent); }
.slider__btn--prev { left: var(--sp-2); }
.slider__btn--next { right: var(--sp-2); }
/* Sur mobile, la flèche est un doublon nuisible : on fait défiler au doigt, et
   posée sur une carte qui occupe presque tout l'écran elle ne peut que masquer
   du contenu. Les points de navigation restent, eux. */
@media (max-width: 47.99rem) {
  .slider__btn { display: none; }
}

.slider__controls { display: flex; align-items: center; justify-content: center; margin-top: var(--sp-2); }
.slider__dots { display: flex; gap: 0.45rem; flex-wrap: wrap; justify-content: center; }
.slider__dot {
  width: 0.5rem; height: 0.5rem; padding: 0; border-radius: var(--r-pill); cursor: pointer;
  border: 0; background: var(--c-line); overflow: hidden;
  transition: background-color var(--d-micro), width var(--d-micro) var(--e-enter);
}
/* Le point actif s'allonge et se remplit au rythme de l'autoplay :
   remplace l'ancien bouton "Lecture auto", qui n'est plus affiché. */
/* Rail du point actif : --c-accent-tint le rendait invisible sur le fond
   --c-paper-2 de la section. Il doit se lire, c'est lui qui porte la
   progression de l'autoplay. */
.slider__dot[aria-current="true"] { width: 1.6rem; background: color-mix(in srgb, var(--c-brand) 30%, transparent); }
.slider__dot-fill { display: block; height: 100%; width: 100%; transform-origin: left; transform: scaleX(0); background: var(--c-brand); }
.slider__dot[aria-current="true"] .slider__dot-fill { transform: scaleX(1); transition: transform var(--d-ui) var(--e-enter); }
.slider[data-playing="true"] .slider__dot[aria-current="true"] .slider__dot-fill {
  transition: none; animation: slideProgress var(--slide-dur, 4.5s) linear forwards;
}
@keyframes slideProgress { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* Flèches SORTIES des cartes. Le seuil est 101rem (1616 px) et non la largeur
   du conteneur (87,75rem) : à 1440 px, les marges de part et d'autre du wrap ne
   font que 54 px, et le bouton sorti de 4,3rem débordait de la fenêtre. Il faut
   la largeur du wrap PLUS deux fois la place d'un bouton pour les sortir. */
@media (min-width: 101rem) {
  .slider__btn--prev { left: -4.3rem; }
  .slider__btn--next { right: -4.3rem; }
}

/* =========================================================================
   Modale "Voir plus d'infos" d'une prestation
   ========================================================================= */
.presta-modal {
  position: fixed; inset: 0; z-index: 200; display: grid; place-items: center;
  padding: var(--sp-3);
  opacity: 0; visibility: hidden; transition: opacity var(--d-ui) var(--e-panel), visibility var(--d-ui) var(--e-panel);
}
.presta-modal[data-open="true"] { opacity: 1; visibility: visible; }
.presta-modal__overlay { position: absolute; inset: 0; background: rgb(var(--rgb-night) / 0.72); backdrop-filter: blur(3px); }
/* Panneau DÉFILANT. Il était statique tant que la carte portait l'essentiel et
   que la modale n'était qu'un complément : le texte était alors comprimé
   jusqu'à tenir dans la fenêtre. La carte ne dit plus que l'intention, la
   modale porte TOUTE l'information — on ne peut plus la comprimer, donc elle
   défile, et le texte reprend une taille de lecture normale. */
.presta-modal__panel {
  position: relative; z-index: 1; width: min(100%, 46rem);
  max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
  background: var(--c-paper); color: var(--c-ink); border-radius: var(--r-0);
  padding: var(--sp-5) var(--sp-4) var(--sp-4); box-shadow: var(--shadow-lift);
  transform: translateY(18px) scale(0.98); transition: transform var(--d-ui) var(--e-panel);
  /* La police du panneau pilote toutes ses marges (exprimées en em). Elle ne
     dépend plus de la hauteur de fenêtre — le panneau défile — mais de la
     largeur, et son plancher est une vraie taille de lecture (17px) et non
     plus le minimum tolérable. */
  font-size: var(--t-lede);
}
.presta-modal[data-open="true"] .presta-modal__panel { transform: none; }
.presta-modal__close {
  position: absolute; top: var(--sp-2); right: var(--sp-2); z-index: 2;
  width: 2.6rem; height: 2.6rem; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--c-line); background: var(--c-paper); color: var(--c-ink);
  display: grid; place-items: center; transition: background-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover);
}
.presta-modal__close svg { width: 1.1rem; height: 1.1rem; }
.presta-modal__close:hover { background: var(--c-ink); color: var(--c-paper); }
/* Les marges internes sont exprimées en em : elles suivent le clamp de police
   du panneau, donc tout le bloc se compacte d'un coup quand la fenêtre est
   basse, au lieu de déborder. */
.presta-modal__media { margin: 0 0 1.1em; border-radius: var(--r-0); overflow: hidden; height: 18vh; max-height: 11em; background: var(--c-paper-2); }
.presta-modal__media:empty { display: none; }
.presta-modal__media img { width: 100%; height: 100%; object-fit: cover; }
.presta-modal__tag {
  display: inline-block; font-size: var(--t-micro); letter-spacing: var(--ls-micro); text-transform: uppercase;
  font-weight: var(--w-onmedia); color: var(--c-on-accent); background: var(--c-accent);
  padding: 0.25rem 0.6rem; border-radius: var(--r-pill); margin-bottom: var(--sp-2);
  transform: scale(0.86); transform-origin: left center;
}
.presta-modal__title { font-family: var(--font-display); font-size: var(--t-title); font-weight: var(--w-title); letter-spacing: var(--ls-title); max-width: 20ch; line-height: var(--lh-card); }
.presta-modal__foot .btn { min-height: 2.6em; padding: 0.7em 1.4em; font-size: var(--t-body); }
.presta-modal__body { margin-top: 0.8em; }
/* La modale a sa propre échelle (clamp sur vh) : la mesure globale de 64ch
   y créerait un fer à gauche ragé au milieu du panneau. */
.presta-modal__body p, .presta-modal__body li { color: var(--c-ink-soft); max-width: none; font-size: 1em; }
.presta-modal__body p + p { margin-top: 0.7em; }
.presta-modal__body h4 { font-family: var(--font-display); font-size: var(--t-card); font-weight: var(--w-title); margin: 1em 0 0.45em; }
.presta-modal__body ul { list-style: none; margin: 0.7em 0 0; padding: 0; display: grid; gap: 0.5em; }
.presta-modal__body li { display: grid; grid-template-columns: auto 1fr; gap: 0.7rem; align-items: start; color: var(--c-ink-soft); }
.presta-modal__body li::before { content: ""; width: 6px; height: 6px; border-radius: var(--r-hair); margin-top: 0.62em; background: var(--c-brand); }
.presta-modal__facts { list-style: none; margin: 1em 0 0; padding: 0.75em 0 0; border-top: 1px solid var(--c-line); display: grid; gap: 0.4em; }
.presta-modal__facts li { display: grid; grid-template-columns: auto 1fr; gap: 0.55rem; align-items: center; font-size: var(--t-small); color: var(--c-ink-mute); }
.presta-modal__facts svg { width: 0.95em; height: 0.95em; color: var(--c-brand); flex: none; }
.presta-modal__foot { margin-top: 1em; padding-top: 0.8em; border-top: 1px solid var(--c-line); display: flex; flex-wrap: wrap; gap: 0.9em; align-items: center; justify-content: space-between; }
.presta-modal__price { font-family: var(--font-display); font-size: var(--t-title-s); font-weight: var(--w-title); color: var(--c-accent-ink); }
.presta-modal__price small { display: block; font-family: var(--font-body); font-size: var(--t-small); font-weight: var(--w-body); color: var(--c-ink-mute); }
/* Renvoi vers le planning, pour les prestations à dates fixes. Il vivait sur la
   carte ; il est ici parce que la carte ne porte plus que l'intention. Le JS le
   montre ou le masque selon data-fixed-dates. */
.presta-modal__schedule {
  margin-top: 1em; padding: 0.9em 1.1em; border-radius: var(--r-hair);
  background: var(--c-paper-2); font-size: var(--t-small); color: var(--c-ink-soft);
}
.presta-modal__planning {
  font: inherit; color: var(--c-accent-ink); background: none; border: 0; padding: 0;
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
  font-weight: var(--w-label);
}
.presta-modal__planning:hover { color: var(--c-accent-deep); }
body[data-modal-open="true"] { overflow: hidden; }

/* -------- Modale "Planning" (prestation à dates fixes) ------------------- */
.planning-modal__sub { margin-top: 0.35em; color: var(--c-ink-mute); font-size: var(--t-small); }
/* Seule zone défilante du site en modale : la liste des dates peut être longue
   et, contrairement au texte d'une fiche, elle ne se compacte pas. Le panneau
   lui-même reste fixe. */
.planning-modal__list {
  margin-top: 1em; padding-right: 0.3em;
  max-height: 46vh; overflow-y: auto;
  display: grid; gap: 1em;
}
.planning-group__title {
  font-family: var(--font-display); font-size: var(--t-lede); font-weight: var(--w-label);
  text-transform: capitalize; color: var(--c-ink);
  padding-bottom: 0.3em; border-bottom: 1px solid var(--c-line);
}
.planning-group__list { list-style: none; margin: 0.55em 0 0; padding: 0; display: grid; gap: 0.4em; }
.planning-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1em;
  padding: 0.45em 0.6em; border-radius: var(--r-hair);
  background: var(--c-paper-2); font-size: var(--t-small);
}
.planning-row__day { font-weight: var(--w-label); text-transform: capitalize; color: var(--c-ink); }
.planning-row__time { color: var(--c-ink-mute); font-variant-numeric: tabular-nums; white-space: nowrap; }
.planning-modal__hint { font-size: var(--t-small); color: var(--c-ink-mute); max-width: 24ch; }
.planning-modal__empty { color: var(--c-ink-soft); }

@media (min-width: 48rem) {
  .presta-modal__panel { padding: 2.4em 2em 1.9em; }
}

/* Fenêtre basse : on rend la vignette moins gourmande et on resserre le titre.
   Plus aucun bloc n'est MASQUÉ ici — la modale est désormais le seul endroit où
   l'information complète existe, la cacher reviendrait à la perdre. Le panneau
   défile, c'est lui qui absorbe le manque de place. */
@media (max-height: 54rem) {
  .presta-modal__media { height: 14vh; }
  .presta-modal__title { font-size: var(--t-title-s); }
}
@media (max-height: 44rem) {
  .presta-modal__body h4 { margin-top: 0.7em; }
}
/* .detail-secondary n'est plus masqué sur écran étroit. Ces paragraphes de
   développement étaient sacrifiables tant que la carte portait déjà l'essentiel
   du propos ; maintenant que la carte se limite à une phrase, les cacher sur
   mobile priverait la moitié des visiteurs du contenu réel de la prestation. */

/* =========================================================================
   Newsletter : inscription opt-in explicite (RGPD)
   ========================================================================= */
/* Deux colonnes, alignées à gauche comme tout le reste de la page : la
   colonne centrée coûtait 240px et cassait l'axe d'encre du site. */
.newsletter { display: grid; gap: var(--sp-4) var(--grid-gap); align-items: start; }
.newsletter__head .lede { margin-top: var(--sp-3); max-width: 34ch; }
.newsletter__form { margin-top: 0; }
@media (min-width: 64rem) {
  .newsletter { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; }
  .newsletter__head  { grid-column: 1 / 7; }
  .newsletter__form  { grid-column: 7 / 13; }
}

/* Deux champs par ligne, empilés en dessous de 34rem. */
.newsletter__row { display: grid; grid-template-columns: 1fr; gap: 0.9rem; margin-bottom: var(--sp-3); }
.newsletter__row .field { margin: 0; }
/* Le champ ne pose plus un aplat gris sur la photo : il la laisse passer,
   floutée. Le fond reste assez dense pour que la saisie garde son contraste,
   assez transparent pour qu'on lise l'aube derrière. backdrop-filter n'est
   pas garanti partout : le color-mix seul suffit déjà à assurer la lisibilité. */
.newsletter__form .field label {
  color: var(--c-on-night-mute);
}
.newsletter__form .field label .req { color: var(--c-accent-night); }
.newsletter__form .field label .opt {
  font-weight: var(--w-body); text-transform: none; letter-spacing: 0;
  color: color-mix(in srgb, var(--c-on-night-mute) 70%, transparent);
}
.newsletter__form .field input {
  background: color-mix(in srgb, var(--c-night) 42%, transparent);
  -webkit-backdrop-filter: blur(12px) saturate(1.15);
  backdrop-filter: blur(12px) saturate(1.15);
  border-color: color-mix(in srgb, var(--c-on-night) 32%, transparent);
  color: var(--c-on-night);
  width: 100%;
}
.newsletter__form .field input::placeholder { color: color-mix(in srgb, var(--c-on-night-mute) 65%, transparent); }
.newsletter__form .field input:focus {
  border-color: var(--c-accent-night);
  background: color-mix(in srgb, var(--c-night) 58%, transparent);
  box-shadow: var(--shadow-focus);
}
.newsletter__form .field__error:not(:empty) { display: block; margin-top: 0.4rem; color: var(--c-error-night); }
.newsletter__form .field[data-invalid="true"] input { border-color: var(--c-error-night); }
.newsletter__submit { width: 100%; justify-content: center; }

.newsletter__form .consent { margin-block: var(--sp-2) 0; }
.newsletter__form .consent label { color: var(--c-on-night-mute); font-size: var(--t-small); }
.newsletter__form .consent a { color: var(--c-accent-night); }

/* Réassurance en puces courtes, pas en paragraphe. */
.newsletter__perks {
  list-style: none; margin: var(--sp-4) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem;
  font-size: var(--t-micro); color: var(--c-on-night-mute);
}
.newsletter__perks li { display: flex; align-items: center; gap: 0.45rem; }
.newsletter__perks li::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%; flex: none;
  background: var(--c-accent-night);
}

/* RGPD : accessible mais replié, pour ne pas noyer le formulaire. */
.newsletter__legal { margin-top: var(--sp-3); border-top: 1px solid var(--c-line-night); padding-top: var(--sp-2); }
.newsletter__legal summary {
  cursor: pointer; font-size: var(--t-micro); color: var(--c-on-night-mute);
  list-style: none; display: flex; align-items: center; gap: 0.4rem;
}
.newsletter__legal summary::-webkit-details-marker { display: none; }
.newsletter__legal summary::before {
  content: "+"; font-size: var(--t-small); line-height: 1; color: var(--c-accent-night);
}
.newsletter__legal[open] summary::before { content: "–"; }
.newsletter__legal summary:hover { color: var(--c-on-night); }
.newsletter__legal p {
  margin-top: var(--sp-2); font-size: var(--t-micro); line-height: var(--lh-body);
  color: color-mix(in srgb, var(--c-on-night-mute) 85%, transparent);
}
.newsletter__legal a { color: var(--c-accent-night); text-underline-offset: 2px; }

.newsletter__success { display: none; text-align: center; padding: var(--sp-4) var(--sp-2); }
.newsletter__form[data-sent="true"] .newsletter__fields { display: none; }
.newsletter__form[data-sent="true"] .newsletter__success { display: block; animation: pop 0.5s var(--e-enter); }
.newsletter__success svg { width: 2.6rem; height: 2.6rem; color: var(--c-accent-night); margin-inline: auto; margin-bottom: var(--sp-2); }
.newsletter__success h3 { font-size: var(--t-card); margin-bottom: var(--sp-1); color: var(--c-on-night); }
.newsletter__success p { color: var(--c-on-night-mute); max-width: 40ch; margin-inline: auto; font-size: var(--t-small); }

@media (min-width: 34rem) {
  .newsletter__row { grid-template-columns: 1fr auto; gap: 0.7rem; }
  .newsletter__row--split { grid-template-columns: 1fr 1fr; }
}

/* =========================================================================
   Page rendez-vous : calendrier + créneaux + confirmation

   RAYONS : le reste du site est à angle vif (--r-0 / --r-hair). Cette page
   fait exception, comme les cartes de prestation : un formulaire de 15 champs
   lu d'une traite a besoin que chaque bloc se referme sur lui-même, et l'angle
   vif y empile des rectangles sans hiérarchie. Les rayons sont donc déclarés
   ICI, en tokens locaux à .rdv-form, et nulle part ailleurs.
   ========================================================================= */
.rdv-head { text-align: center; max-width: 46rem; margin-inline: auto; }
.rdv-head .eyebrow { justify-content: center; }
.rdv-head .section-title { max-width: none; margin-inline: auto; font-size: var(--t-title); }
.rdv-head .lede { margin: var(--sp-2) auto 0; font-size: var(--t-body); }

.rdv-form {
  max-width: 46rem; margin: var(--sp-4) auto 0;
  --rdv-r-xl: 1.75rem;  /* la carte formulaire      */
  --rdv-r-lg: 1.25rem;  /* blocs internes           */
  --rdv-r-md: 0.85rem;  /* champs                   */
  --rdv-r-sm: 0.7rem;   /* jours du calendrier      */
}

/* La carte : un halo chaud très diffus par-dessus l'ombre du site, pour que
   le formulaire se pose sur la page au lieu d'y être découpé. */
.rdv-form .form {
  padding: clamp(1.25rem, 0.6rem + 2.4vw, 2.25rem);
  border: 1px solid var(--c-line-soft);
  border-radius: var(--rdv-r-xl);
  /* --wash-sun remplace le halo radial terracotta : même chaleur, posée sur
     l'axe du soleil au lieu d'être un cercle centré sur un angle. */
  background: var(--wash-sun), var(--c-paper);
  box-shadow: var(--shadow-media), 0 1px 0 rgb(var(--rgb-paper) / 0.8) inset;
}

/* Page rendez-vous : beaucoup de champs, on resserre les espacements pour
   limiter le défilement sans changer la structure du formulaire. */
.rdv-form .field { margin-bottom: var(--sp-2); gap: 0.35rem; }
.rdv-form .form__row { gap: var(--sp-2); }
.rdv-form .field label { color: var(--c-ink-soft); }

.rdv-form .field input,
.rdv-form .field select,
.rdv-form .field textarea {
  border-radius: var(--rdv-r-md);
  border-color: var(--c-line-soft);
  background: color-mix(in srgb, var(--c-paper-2) 55%, var(--c-paper));
  transition: border-color var(--d-micro) var(--e-hover),
              background-color var(--d-micro) var(--e-hover),
              box-shadow var(--d-micro) var(--e-hover);
}
.rdv-form .field input, .rdv-form .field select { min-height: 2.8rem; padding: 0.65rem 0.95rem; }
.rdv-form .field textarea { min-height: 5rem; padding: 0.7rem 0.95rem; }
.rdv-form .field input:hover:not(:focus),
.rdv-form .field select:hover:not(:focus),
.rdv-form .field textarea:hover:not(:focus) { border-color: var(--c-line); }
.rdv-form .field input:focus,
.rdv-form .field select:focus,
.rdv-form .field textarea:focus {
  box-shadow: var(--shadow-focus);
}

/* Chevron du select : dessiné en CSS sur un conteneur, pas en SVG encodé en
   dur, pour ne pas figer une couleur hors de :root. */
.select-wrap { position: relative; display: block; }
/* Sélecteur volontairement aussi spécifique que la règle de padding ci-dessus,
   sinon la réserve pour le chevron est écrasée et la flèche chevauche le texte. */
.rdv-form .field .select-wrap select {
  width: 100%; padding-right: 2.75rem;
  appearance: none; -webkit-appearance: none;
}
.select-wrap::after {
  content: ""; position: absolute; right: 1.1rem; top: 50%; pointer-events: none;
  width: 0.5rem; height: 0.5rem; margin-top: -0.2rem;
  border-right: 2px solid var(--c-ink-mute); border-bottom: 2px solid var(--c-ink-mute);
  border-radius: 0 0 var(--r-hair) 0;
  transform: translateY(-50%) rotate(45deg);
  transition: border-color var(--d-micro) var(--e-hover);
}
.select-wrap:hover::after { border-color: var(--c-accent-ink); }

/* Consentements : chaque case devient un bloc cliquable qui se teinte une fois
   coché. Deux cases côte à côte en texte nu se lisaient comme un paragraphe. */
.rdv-form .consent {
  margin-block: 0 var(--sp-2); gap: 0.75rem; align-items: start;
  padding: 0.9rem 1.05rem;
  border: 1px solid var(--c-line-soft); border-radius: var(--rdv-r-lg);
  background: color-mix(in srgb, var(--c-paper-2) 40%, var(--c-paper));
  transition: border-color var(--d-micro) var(--e-hover), background-color var(--d-micro) var(--e-hover);
}
.rdv-form .consent:hover { border-color: var(--c-line); }
.rdv-form .consent:has(input:checked) {
  border-color: var(--c-accent-tint);
  background: color-mix(in srgb, var(--c-accent) 6%, var(--c-paper));
}
.rdv-form .consent input { width: 1.25rem; height: 1.25rem; margin-top: 0.15rem; border-radius: var(--r-hair); }
/* Lien inline dans la phrase de consentement : sur un inline non remplacé, le
   rembourrage vertical agrandit la boîte tapable sans modifier la line-height,
   donc sans décaler le texte autour. */
.consent label a { padding-block: 0.8rem; }

.rdv-form .cal__header { margin-bottom: var(--sp-2); }
.rdv-form .cal__label { font-size: var(--t-lede); }
/* 2,75rem et non 2,1rem : cette surcharge de confort visuel écrasait le
   plancher de la règle de base et faisait tomber TOUTE la grille de dates à
   34px de haut. On garde l'intention (aspect-ratio: auto, donc des cellules
   larges et non carrées sur grand écran) au seuil tactile. */
.rdv-form .cal__day { min-height: 2.75rem; aspect-ratio: auto; }
.rdv-form .cal__note { margin-top: var(--sp-1); font-size: var(--t-micro); }
.rdv-form #rdv-slots-wrap .cal__note { margin-top: 0.6rem; }
.rdv-form .form__rgpd { margin-top: var(--sp-2); font-size: var(--t-micro); }
.rdv-form .form__submit { margin-top: var(--sp-2); min-height: 3.25rem; }
.rdv-error-global {
  border: 1px solid color-mix(in srgb, var(--c-error) 45%, transparent);
  border-radius: var(--rdv-r-lg);
  background: color-mix(in srgb, var(--c-error) 8%, transparent);
  color: var(--c-error); padding: 0.9rem 1.1rem; margin-bottom: var(--sp-3); font-size: var(--t-small);
}

/* -------- Calendrier ----------------------------------------------------- */
.cal {
  border: 1px solid var(--c-line-soft); border-radius: var(--rdv-r-lg, var(--r-0));
  background: color-mix(in srgb, var(--c-paper-2) 45%, var(--c-paper));
  padding: clamp(0.85rem, 0.5rem + 1.2vw, 1.25rem);
}
.cal__header { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-bottom: var(--sp-3); }
/* Chrome de champ (libellé de mois entre deux boutons) : sans, pas serif. */
.cal__label { font-family: var(--font-body); font-size: var(--t-card); font-weight: var(--w-label); text-transform: capitalize; }
.cal__nav {
  width: 2.5rem; height: 2.5rem; flex: none; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--c-line); background: var(--c-paper); color: var(--c-ink);
  display: grid; place-items: center; transition: background-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover), opacity var(--d-micro) var(--e-hover);
}
.cal__nav svg { width: 1rem; height: 1rem; }
.cal__nav:hover:not([disabled]) { background: var(--c-ink); color: var(--c-paper); }
/* État désactivé rendu par la COULEUR, pas par l'opacité : une opacité globale
   sur un contrôle est indistinguable d'un bloc resté bloqué en cours de
   révélation, et elle rend le contraste final impossible à garantir. */
.cal__nav[disabled] {
  cursor: default;
  color: color-mix(in srgb, var(--c-ink-mute) 45%, var(--c-paper));
  border-color: color-mix(in srgb, var(--c-line) 45%, var(--c-paper));
}
.cal__weekdays, .cal__days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.3rem; }
.cal__weekdays { margin-bottom: 0.4rem; }
.cal__weekdays span { text-align: center; font-size: var(--t-micro); letter-spacing: 0.1em; text-transform: uppercase; color: var(--c-ink-mute); font-weight: var(--w-label); }
.cal__day {
  aspect-ratio: 1; min-height: 2.75rem; display: grid; place-items: center; cursor: pointer;
  border: 1px solid transparent; border-radius: var(--rdv-r-sm, var(--r-hair)); background: var(--c-paper);
  font: inherit; font-size: var(--t-small); color: var(--c-ink);
  transition: background-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover), border-color var(--d-micro) var(--e-hover), transform var(--d-micro) var(--e-hover), box-shadow var(--d-micro) var(--e-hover);
}
.cal__day:hover:not([disabled]) {
  border-color: var(--c-brand); color: var(--c-accent-ink);
  transform: translateY(-1px); box-shadow: var(--shadow-lift);
}
.cal__day[disabled] { background: transparent; color: color-mix(in srgb, var(--c-ink-mute) 46%, var(--c-paper-2)); cursor: not-allowed; }
.cal__day[aria-pressed="true"] {
  background: var(--c-accent); color: var(--c-on-accent); border-color: var(--c-accent);
  font-weight: var(--w-label); box-shadow: var(--shadow-lift);
}
/* Le survol est plus spécifique que l'état sélectionné : sans ce rappel, le
   jour choisi passe en texte terracotta sur fond terracotta tant que la souris
   reste dessus, donc illisible juste après le clic. */
.cal__day[aria-pressed="true"]:hover:not([disabled]) { color: var(--c-on-accent); border-color: var(--c-accent-deep); background: var(--c-accent-deep); }
.cal__day--today:not([aria-pressed="true"]) { border-color: var(--c-accent-tint); font-weight: var(--w-label); }
.cal__day--empty { visibility: hidden; }
/* Date de session (prestation à dates fixes) : pastille sous le chiffre pour
   distinguer d'un coup d'œil les rares jours ouverts du reste du mois. */
.cal__day--session:not([aria-pressed="true"]) {
  border-color: var(--c-accent-tint);
  background: color-mix(in srgb, var(--c-accent) 9%, var(--c-paper));
  font-weight: var(--w-label);
}
.cal__day--session { position: relative; }
.cal__day--session::after {
  content: ""; position: absolute; bottom: 0.3rem; left: 50%; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%; background: var(--c-brand);
}
.cal__day--session[aria-pressed="true"]::after { background: var(--c-on-accent); }

/* Bandeau "cette prestation a des dates imposées", au-dessus du calendrier. */
.rdv-fixed-banner {
  margin: 0 0 var(--sp-2); padding: 0.8rem 1rem;
  border: 1px solid var(--c-accent-tint); border-radius: var(--rdv-r-lg, var(--r-hair));
  background: color-mix(in srgb, var(--c-accent) 8%, transparent);
  color: var(--c-ink-soft); font-size: var(--t-small); line-height: 1.5;
}
.rdv-fixed-banner[hidden] { display: none; }
.cal__note { margin-top: var(--sp-3); font-size: var(--t-micro); color: var(--c-ink-mute); }

/* -------- Créneaux ------------------------------------------------------- */
.slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(5.2rem, 1fr)); gap: 0.5rem; }
/* Créneau imposé (session à dates fixes) : une seule pastille, qui porte une
   plage horaire complète. Elle a besoin de plus que la colonne de 5,2rem
   prévue pour un simple « 09:30 », sinon l'horaire se casse en deux lignes. */
.slots[data-single="true"] { grid-template-columns: auto; justify-content: start; }
.slots[data-single="true"] .slot { padding-inline: 1.1rem; white-space: nowrap; }
.slot {
  min-height: 2.9rem; cursor: pointer; font: inherit; font-size: var(--t-small);
  border: 1px solid var(--c-line-soft); border-radius: var(--r-pill); background: var(--c-paper); color: var(--c-ink);
  transition: background-color var(--d-micro) var(--e-hover), color var(--d-micro) var(--e-hover), border-color var(--d-micro) var(--e-hover), transform var(--d-micro) var(--e-hover), box-shadow var(--d-micro) var(--e-hover);
}
.slot:hover:not([disabled]) {
  border-color: var(--c-brand); color: var(--c-accent-ink);
  transform: translateY(-1px); box-shadow: var(--shadow-lift);
}
.slot[aria-pressed="true"] {
  background: var(--c-accent); color: var(--c-on-accent); border-color: var(--c-accent);
  font-weight: var(--w-label); box-shadow: var(--shadow-lift);
}
/* Même raison que pour .cal__day : l'état sélectionné doit gagner au survol. */
.slot[aria-pressed="true"]:hover:not([disabled]) { color: var(--c-on-accent); border-color: var(--c-accent-deep); background: var(--c-accent-deep); }
.slot[disabled] {
  cursor: not-allowed; text-decoration: line-through;
  color: color-mix(in srgb, var(--c-ink-mute) 55%, var(--c-paper));
  border-color: color-mix(in srgb, var(--c-line) 45%, var(--c-paper));
}
.slots-empty { font-size: var(--t-small); color: var(--c-ink-mute); }

/* -------- Confirmation --------------------------------------------------- */
.rdv-confirm { display: none; text-align: center; }
.rdv-form[data-sent="true"] .rdv-confirm { display: block; animation: pop 0.5s var(--e-enter); }
.rdv-form[data-sent="true"] .form { display: none; }
.rdv-confirm__icon { width: 3.6rem; height: 3.6rem; border-radius: 50%; background: var(--c-ok); display: grid; place-items: center; margin: 0 auto var(--sp-3); }
.rdv-confirm__icon svg { width: 1.7rem; height: 1.7rem; color: var(--c-paper); }
.rdv-confirm__title { font-size: var(--t-title-s); font-weight: var(--w-title); }
.rdv-confirm__card {
  margin-top: var(--sp-4); text-align: left; padding: var(--sp-4);
  background: color-mix(in srgb, var(--c-paper-2) 50%, var(--c-paper));
  border: 1px solid var(--c-line-soft); border-radius: var(--rdv-r-xl, var(--r-0));
  box-shadow: var(--shadow-lift);
  display: grid; gap: var(--sp-2);
}
.rdv-confirm__row { display: grid; grid-template-columns: auto 1fr; gap: 0.75rem; align-items: center; color: var(--c-ink-soft); }
.rdv-confirm__row svg { width: 1.1rem; height: 1.1rem; color: var(--c-accent-ink); flex: none; }
.rdv-confirm__note { margin-top: var(--sp-3); font-size: var(--t-small); color: var(--c-ink-mute); max-width: 46ch; margin-inline: auto; }

/* Sur petit écran, 7 colonnes carrées + les paddings du formulaire et de la
   carte ne tiennent plus dans la largeur : la colonne du dimanche sortait du
   cadre (invisible, car body a overflow-x:hidden). On resserre les marges. */
@media (max-width: 30rem) {
  /* Un rayon de 1,75rem sur une carte quasi pleine largeur mange la première
     lettre de la première ligne : on le resserre avec la carte. */
  .rdv-form { --rdv-r-xl: 1.25rem; --rdv-r-lg: 1rem; }
  .rdv-form .form { padding: var(--sp-3) var(--sp-2); }
  /* Le calendrier récupère le rembourrage de la carte : 7 colonnes tactiles
     (44px) ne tiennent pas autrement sous 480px. Le gain vient de la largeur
     rendue à la grille, pas d'un resserrement de la typo — les jours et les
     flèches remontent au seuil tactile au lieu de descendre à 36px. */
  .cal { padding: 0.5rem; margin-inline: calc(-1 * var(--sp-2)); }
  .cal__weekdays, .cal__days { gap: 0.15rem; }
  .cal__day { min-height: 2.75rem; font-size: var(--t-micro); }
  .cal__nav { width: 2.75rem; height: 2.75rem; }
  .cal__label { font-size: var(--t-lede); }
}
/* Sous 360px, même en récupérant la carte il manque encore 6px par colonne :
   le calendrier passe pleine largeur (il annule aussi la gouttière du wrap).
   C'est le seul moyen géométrique d'atteindre 44px sur 7 colonnes à 320px. */
@media (max-width: 22.5rem) {
  .cal { margin-inline: calc(-1 * (var(--sp-2) + var(--gutter))); border-radius: 0; border-inline-width: 0; padding-inline: 0.5rem; }
}

/* -------- Emplacement anti-robot (à brancher) ---------------------------- */
.captcha-slot {
  /* width: le bloc est un <p>, qui hérite du plafond de mesure de la prose et
     se retrouvait plus étroit que les champs juste au-dessus. */
  width: 100%; max-width: none;
  border: 1px dashed var(--c-line); border-radius: var(--rdv-r-lg, var(--r-hair));
  background: color-mix(in srgb, var(--c-paper-2) 40%, var(--c-paper));
  padding: var(--sp-3); text-align: center; font-size: var(--t-small); color: var(--c-ink-mute);
}

/* =========================================================================
   Responsive
   ========================================================================= */
@media (min-width: 48rem) {   /* 768 : demi-système, 6 colonnes */
  .about   { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  /* align-self: center : le portrait est plafonné à sa largeur native, donc à
     une hauteur fixe (aspect-ratio 5/7), tandis que la colonne de texte s'est
     allongée (quatre paragraphes). Avec le align-items: start du bloc, l'image
     restait collée en haut et laissait une grande zone de papier vide en
     dessous ; centrée sur la hauteur de la ligne, elle se pose au milieu du
     texte et l'ensemble retrouve son équilibre. */
  .about__media { grid-column: 1 / 3; align-self: center; }
  .about__body  { grid-column: 3 / 7; }
  .formats { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .formats__media { grid-column: 1 / 4; }
  .formats__body  { grid-column: 4 / 7; }
  .def { grid-template-columns: 1fr 1fr; }
  /* La largeur des cartes est calculée depuis le viewport du slider (voir
     @supports container-type) : plus de largeur fixe qui tomberait à côté. */
  .mirror { grid-template-columns: 1.4fr 1fr; gap: var(--sp-6); }
  /* .steps reste sur UNE colonne jusqu'à 64rem : c'est une frise, un 2 x 2 la
     ferait repartir à gauche au temps 3. Voir la bascule horizontale plus bas. */
  .pillars { grid-template-columns: repeat(2, 1fr); }
  .format-item dt { min-width: 9rem; }
  .form__row { grid-template-columns: 1fr 1fr; }
  .contact { grid-template-columns: 1.2fr 1fr; gap: var(--sp-4); }
  .site-footer__top { grid-template-columns: 1.6fr 1fr 1fr; gap: var(--sp-4); }
}
/* 1024 : le système complet, 12 colonnes.
   LE CONTREPOIDS : 5/7, jamais 6/6, et un décalage vertical pour que les deux
   blocs ne partagent pas de ligne de base. */
@media (min-width: 64rem) {
  .about   { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  /* 4 / 8, pas 5 / 7 : le portrait est plafonné à sa largeur native (327 px),
     une colonne de 5 rangs lui laisserait 200 px de papier vide à droite et il
     paraîtrait perdu. Sur 4 rangs, le vide résiduel devient une gouttière. */
  /* align-self: center, comme au demi-système : la colonne de texte est plus
     haute que le portrait à hauteur fixe, le centrage remet l'image au milieu
     du bloc plutôt que collée en haut. Voir le commentaire à 48rem. */
  .about__media { grid-column: 1 / 5; align-self: center; }
  .about__body  { grid-column: 5 / 13; padding-top: var(--sp-6); }

  .formats { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  /* La photo prend la hauteur de la colonne de texte : sans ça, un ratio fixe
     laissait ~300px de nuit vide sous l'image.
     aspect-ratio: auto est INDISPENSABLE ici : align-self: stretch rend la
     hauteur définie, et un aspect-ratio conservé recalculerait alors la
     LARGEUR depuis cette hauteur (981px au lieu de 526), l'image passant
     par-dessus la colonne de texte. */
  .formats__media { grid-column: 1 / 6; align-self: stretch; aspect-ratio: auto; }
  .formats__body  { grid-column: 7 / 13; padding-top: var(--sp-5); }

  /* Quatre temps sur UNE ligne : c'est le plus gros gain de hauteur du site.
     La frise bascule à l'horizontale — le rail devient une règle, tracée de
     gauche à droite. */
  .steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--grid-gap); }
  .steps::before,
  .steps::after {
    left: 0; right: 0; width: auto;
    top: var(--rail); bottom: auto; height: 1px;
    margin-left: 0; margin-top: -0.5px;
  }
  .steps::after { transform: scaleX(var(--p, 1)); transform-origin: left; }
  /* La pastille repasse AU-DESSUS du texte : la colonne est trop étroite pour
     la garder à sa gauche. */
  .step { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .step__num { margin-bottom: var(--sp-3); }
  .pillars { grid-template-columns: repeat(3, 1fr); }
  .contact { grid-template-columns: 1.05fr 1fr; }
}
/* Menu plein écran mobile : styles d'overlay indépendants du breakpoint,
   car le burger qui le déclenche bascule à 78rem (voir plus bas), pas 48rem. */
.mobile-menu {
  position: fixed; inset: 0; z-index: 99; background: var(--c-night); color: var(--c-on-night);
  display: none; flex-direction: column; justify-content: center; gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-5);
  /* En paysage (390px de haut) les 6 entrées dépassent l'écran : « Présentation »
     partait au-dessus du cadre et le CTA en dessous, tous deux inatteignables car
     un panneau fixed ne défile pas. `safe center` recentre tant que ça tient et
     retombe sur un alignement en haut dès que ça déborde ; auto rend le reste
     accessible. Aucun effet à la taille où le menu tenait déjà. */
  justify-content: safe center;
  overflow-y: auto; overscroll-behavior: contain;
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity var(--d-ui) var(--e-panel), transform var(--d-ui) var(--e-panel), visibility var(--d-ui) var(--e-panel);
}
.mobile-menu[data-open="true"] { opacity: 1; visibility: visible; transform: none; }
/* Navigation : sans, jamais serif (CHARTE-GRAPHIQUE.md §3.1). La taille
   reste --t-title : c'est un menu plein écran, sa présence vient du corps. */
.mobile-menu a { font-family: var(--font-body); font-size: var(--t-title); color: var(--c-on-night); text-decoration: none; font-weight: var(--w-label); letter-spacing: var(--ls-title); }
/* .mobile-menu a (0,1,1) l'emportait sur .btn (0,1,0) : le CTA du menu perdait
   sa couleur de texte sur accent et retombait à 4,55:1 au lieu de 4,98:1. */
/* `.btn` porte overflow:hidden (arrondi de la pilule) : comprimé comme flex-item
   du menu, il rognait son propre libellé sans rien faire déborder — muet pour
   l'audit. flex:none lui rend sa hauteur intrinsèque. */
.mobile-menu a.btn { font-family: var(--font-body); font-size: var(--t-lede); margin-top: var(--sp-3); color: var(--btn-fg); flex: none; padding-inline: 1.2rem; text-wrap: balance; }
/* Écrans courts (téléphone en paysage) : le menu plein écran garde son parti pris
   — sans, gras, aligné à gauche — mais descend d'un cran typographique pour que
   les six entrées tiennent d'un coup d'œil au lieu d'imposer un défilement. */
@media (max-height: 30rem) {
  .mobile-menu { padding-block: var(--sp-3); gap: var(--sp-1); }
  .mobile-menu a { font-size: var(--t-lede); letter-spacing: var(--ls-body); }
  .mobile-menu a.btn { margin-top: var(--sp-2); min-height: 2.75rem; padding-block: 0.55rem; }
}
body[data-menu-open="true"] { overflow: hidden; }

@media (max-width: 47.99rem) {
  .sticky-cta { display: block; }
  .hero h1 { max-width: 100%; }
  /* Scrim plus dense en bas sur mobile : lisibilité du sous-titre par-dessus la robe claire */
  .hero__scrim { background:
    linear-gradient(to top, rgb(var(--rgb-night) / 0.90) 0%, rgb(var(--rgb-night) / 0.55) 42%, rgb(var(--rgb-night) / 0.20) 100%),
    linear-gradient(90deg, rgb(var(--rgb-night) / 0.70) 0%, rgb(var(--rgb-night) / 0.20) 100%); }
  /* Cible tactile conservée (36px + le gap = ~44px d'espacement réel entre liens)
     sans empiler 8 blocs de 44px qui feraient un pied de page plus haut qu'un écran. */
  .footer-col a, .footer-col li { display: inline-flex; align-items: center; min-height: 36px; }
  .footer-col ul { gap: 0.15rem; }
  .site-footer { padding-bottom: calc(var(--sp-3) + 4.5rem); }
}

/* Nav desktop / burger : bascule à 78rem, indépendamment des autres breakpoints
   (768/1024) qui gèrent la mise en page du contenu, pas le header. */
@media (max-width: 77.99rem) {
  .nav__links, .nav__cta { display: none; }
  .nav-toggle {
    display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
    width: 2.75rem; height: 2.75rem; background: transparent; border: 0; cursor: pointer; color: inherit;
  }
  .nav-toggle .bar { display: block; width: 22px; height: 2px; background: currentColor; border-radius: var(--r-hair); transition: transform var(--d-ui) var(--e-hover), opacity var(--d-ui) var(--e-hover); }
  .nav-toggle .bar + .bar { margin-top: 5px; }
  .site-header:not([data-scrolled="true"]) .nav-toggle { color: var(--c-on-night); }
  .site-header[data-scrolled="true"] .nav-toggle { color: var(--c-ink); }
  .mobile-menu { display: flex; }
}

/* =========================================================================
   prefers-reduced-motion
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Aucun contenu masqué, aucune distance à parcourir : l'état final est
     l'état initial. Rien ne dépend alors de JS pour être lisible. */
  .reveal, .reveal--stagger > * { opacity: 1 !important; transform: none !important; }
  .word > span { transform: none !important; }
  [data-parallax] { transform: none !important; will-change: auto !important; }
  .reveal-clip { clip-path: none !important; }
  .media-reveal::after { transform: scaleX(0) !important; }
  .hero__eyebrow, .hero__sub, .hero__actions { opacity: 1 !important; transform: none !important; }
  /* La flèche reste — c'est un repère, pas un ornement — mais elle ne bouge plus.
     .hero.is-in n'étant posé que par JS, on la rend visible sans lui. */
  .hero__scroll { opacity: 1 !important; }
  .hero__scroll-arrow { animation: none !important; transform: none !important; opacity: 1 !important; }
  /* Frise et citation : état final d'emblée. Le JS ne pose ni data-timeline ni
     data-scrollwords dans ce mode, ces règles ne sont qu'une seconde barrière. */
  .steps::after { transform: scaleY(1) !important; }
  .step__body { opacity: 1 !important; transform: none !important; }
  .pullquote q .word > span { opacity: 1 !important; }
  .sticky-cta { transform: translateY(0); }
  /* Pas d'autoplay ni de remplissage animé : le slider reste 100 % manuel,
     piloté par les flèches. Le point actif reste plein pour rester lisible. */
  .slider[data-playing="true"] .slider__dot[aria-current="true"] .slider__dot-fill { animation: none; transform: scaleX(1); }
  .slider__viewport { scroll-behavior: auto; }
  .hero__video { opacity: 1; }
  .presta-modal__panel { transform: none !important; }
}

/* =========================================================================
   Print
   ========================================================================= */
@media print {
  .site-header, .sticky-cta, .form, .mobile-menu { display: none; }
  body { background: var(--c-paper); color: var(--c-ink); }
}
