/* ============================================================
   CANOPUS — Tristan Lecoindre
   Direction : objet de créateur. Boîtier gris clair et précis,
   aplats de couleur solaire, tout est étiqueté en monospace.
   Référence : Braun / Teenage Engineering, pas le crème éditorial.
   Signature : le sélecteur de bobine dans le hero.
   ============================================================ */

/* ---------- 1. Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
img, video, svg, canvas { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }

/* ---------- 2. Tokens ---------- */
:root {
  /* Le boîtier : gris neutre, pas crème. C'est lui qui évite le cliché. */
  --shell:    #EDECE8;
  --shell-2:  #E4E3DE;
  --shell-3:  #D8D7D1;

  --ink:      #1C1D1A;
  --ink-2:    #5D5F5A;
  --ink-3:    #8D8F89;
  --hairline: #CFCEC7;

  /* Les touches. Aplats francs, jamais de dégradé. */
  --solar:      #F2622E;   /* orange signal — fond de touche */
  --beam:       #F5B838;   /* jaune lumière */
  --sky:        #5BA8F5;   /* bleu franc */
  --grass:      #4FBF7B;   /* vert — disponibilité, validation */

  /* Les touches vives portent une étiquette SOMBRE : c'est le principe
     Braun/OP-1, et c'est aussi la seule façon de tenir le contraste AA
     sans éteindre les couleurs. */
  --on-key:     #1C1D1A;
  /* Version assombrie, seule utilisable pour de l'orange EN TEXTE. */
  --solar-ink:  #A8390B;
  --danger:     #BE2F16;

  --gap: 24px;
  --page-x: clamp(20px, 4.5vw, 72px);
  --maxw: 1480px;

  --font-display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Instrument Sans', 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'DM Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --t-h1:    clamp(2.2rem, 5.2vw, 4.6rem);
  --t-h2:    clamp(1.6rem, 3.2vw, 2.9rem);
  --t-h3:    clamp(1.14rem, 1.7vw, 1.5rem);
  --t-body:  clamp(0.98rem, 1vw, 1.08rem);
  --t-lead:  clamp(1.1rem, 1.45vw, 1.36rem);
  --t-label: 0.72rem;

  /* Rayon franc et assumé : les objets Braun sont adoucis, pas coupés.
     C'est aussi ce qui nous éloigne du gabarit éditorial à angles vifs. */
  --r:    8px;
  --r-lg: 14px;
  --r-pill: 100px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
  --dur: 460ms;
  --dur-fast: 190ms;

  --nav-h: 72px;
}

/* ---------- 3. Base ---------- */
body {
  background: var(--shell);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.6;
  overflow-x: hidden;
}
::selection { background: var(--solar); color: var(--on-key); }
:focus-visible { outline: 2.5px solid var(--sky); outline-offset: 3px; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.032em;
  text-wrap: balance;
}
p { text-wrap: pretty; }

/* Tout est étiqueté, comme sur un panneau de commande. */
.label {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.label--solar { color: var(--solar-ink); }

.lead { font-size: var(--t-lead); line-height: 1.5; letter-spacing: -0.008em; }
.muted { color: var(--ink-2); }

/* ---------- 4. Layout ---------- */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--page-x); }
.grid12 { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gap); }

.section { padding-block: clamp(68px, 9vw, 148px); }
.section--tight { padding-block: clamp(48px, 6vw, 92px); }

.rule { height: 1px; background: var(--hairline); border: 0; }

/* ---------- 5. Navigation ---------- */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 150;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  transition: background var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
.nav__inner {
  width: 100%; max-width: var(--maxw);
  margin-inline: auto; padding-inline: var(--page-x);
  display: flex; align-items: center; justify-content: space-between; gap: var(--gap);
}
.nav--solid {
  background: rgba(237, 236, 232, 0.9);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 1px 0 var(--hairline);
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.02rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  display: flex; align-items: baseline; gap: 11px;
}
/* L'entreprise s'appelle CANOPUS STUDIO : le second mot se pose sous le
   premier, aligné sur son bord gauche, en petites capitales espacées. Il
   ne double pas le wordmark en hauteur — l'interlignage est resserré pour
   que l'ensemble tienne dans la barre de navigation. */
.wordmark { flex-direction: column; align-items: flex-start; gap: 1px; line-height: 1.05; }
.wordmark__sub {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  text-indent: 0.34em;          /* compense l'espacement sur la dernière lettre */
  /* --ink-3 tombe à 3,71:1 sur --shell : sous le seuil AA de 4,5:1, et
     0,58 rem est très loin des 0,85 rem en dessous desquels il ne doit
     plus servir. --ink-2 tient 6,19:1. Voir CLAUDE.md. */
  color: var(--ink-2);
}

.nav__links { display: flex; align-items: center; gap: clamp(14px, 1.9vw, 30px); }
.nav__link {
  font-size: 0.9rem; color: var(--ink-2);
  padding: 7px 2px; position: relative;
  transition: color var(--dur-fast) ease;
}
.nav__link:hover { color: var(--ink); }
.nav__link[aria-current="page"] { color: var(--ink); }
.nav__link[aria-current="page"]::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; background: var(--solar); border-radius: 2px;
}

.burger { display: none; width: 42px; height: 42px; position: relative; border-radius: var(--r); }
.burger span {
  position: absolute; left: 10px; right: 10px; height: 2px;
  background: var(--ink); border-radius: 2px;
  transition: transform var(--dur-fast) var(--ease);
}
.burger span:nth-child(1) { top: 16px; }
.burger span:nth-child(2) { top: 24px; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(4px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { transform: translateY(-4px) rotate(-45deg); }

.menu {
  position: fixed; inset: 0; z-index: 149;
  background: var(--shell);
  padding: calc(var(--nav-h) + 32px) var(--page-x) 36px;
  display: flex; flex-direction: column; justify-content: space-between;
  transform: translateY(-100%); visibility: hidden;
  transition: transform var(--dur) var(--ease);
}
.menu[data-open="true"] { transform: translateY(0); visibility: visible; }
.menu__list { display: flex; flex-direction: column; }
.menu__link {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 8vw, 3rem);
  font-weight: 600; letter-spacing: -0.035em;
  padding-block: 14px;
  border-bottom: 1px solid var(--hairline);
}

/* ---------- 6. Boutons — des touches, pas des rectangles ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 24px;
  font-size: 0.9rem; font-weight: 500;
  border-radius: var(--r-pill);
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease,
              box-shadow var(--dur-fast) ease, transform 120ms var(--ease);
}
/* La touche s'enfonce : le seul geste tactile du site. */
.btn:active { transform: translateY(2px); }
.btn svg { transition: transform 340ms var(--ease); }
.btn:hover svg { transform: translateX(4px); }

.btn--accent {
  background: var(--solar); color: var(--on-key);
  box-shadow: 0 3px 0 #C64A1E;
}
.btn--accent:hover { background: #FF7A45; }
.btn--accent:active { box-shadow: 0 1px 0 #C64A1E; }

.btn--ghost {
  background: transparent; color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--ink-3);
}
.btn--ghost:hover { background: var(--shell-2); box-shadow: inset 0 0 0 1.5px var(--ink-2); }

.btn--lg { padding: 17px 30px; font-size: 0.94rem; }

.tlink {
  display: inline-flex; align-items: center; gap: 9px;
  font-weight: 500; padding-bottom: 3px;
  box-shadow: 0 1px 0 var(--hairline);
  transition: box-shadow var(--dur-fast) ease, color var(--dur-fast) ease;
}
.tlink:hover { color: var(--solar-ink); box-shadow: 0 1.5px 0 var(--solar-ink); }
.tlink svg { transition: transform var(--dur-fast) var(--ease); }
.tlink:hover svg { transform: translateX(4px); }


/* Interlignage serré à dessein : la queue du Q de « qui » vient
   effleurer le D de « de » à la ligne suivante. C'est la signature
   typographique du site — ne pas desserrer, ne pas reformater le titre. */
.hero__title {
  font-size: clamp(2.3rem, 6.6vw, 5.8rem);
  font-weight: 600;
  letter-spacing: -0.042em;
  line-height: 0.855;   /* 0.90 si tu préfères qu'ils se frôlent sans se croiser */
  max-width: 17ch;
}
.hero__title em { font-style: normal; color: var(--solar); }
.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

/* Pastille de disponibilité — un voyant, comme sur un boîtier */


/* ---------- 10. Révélations — un geste par section ---------- */

/* Geste commun de repli */
[data-reveal] {
  opacity: 0; transform: translateY(18px);
  transition: opacity 700ms var(--ease), transform 700ms var(--ease);
  transition-delay: var(--d, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* --- Geste 1 : LE MASQUE. Le texte remonte de derrière une arête,
       comme un carton de générique. Réservé aux titres. --- */
[data-motion="mask"] { overflow: hidden; }
[data-motion="mask"] .ln {
  display: block;
  transform: translateY(106%);
  transition: transform 980ms var(--ease);
  transition-delay: calc(var(--i, 0) * 105ms);
}
[data-motion="mask"].is-in .ln { transform: none; }

/* --- Geste 2 : LA MISE AU POINT. L'élément arrive déflou et se fait
       net, comme un point qu'on tire. --- */
[data-motion="focus"] {
  opacity: 0;
  filter: blur(14px);
  transform: scale(1.035);
  transition: opacity 900ms var(--ease-out),
              filter 1100ms var(--ease-out),
              transform 1100ms var(--ease-out);
  transition-delay: var(--d, 0ms);
}
/* `will-change` force une couche de composition tant qu'il est posé.
   On ne l'active que tant que l'élément n'est pas révélé : dès que
   `is-in` arrive, le sélecteur cesse de correspondre et la couche
   est libérée. */
.js-motion [data-motion="focus"]:not(.is-in) { will-change: filter, transform; }
[data-motion="focus"].is-in { opacity: 1; filter: blur(0); transform: none; }

/* --- Geste 3 : LE DÉVELOPPEMENT. L'image monte du papier, comme
       dans le révélateur. --- */
[data-motion="develop"] { overflow: hidden; }
[data-motion="develop"] > * {
  opacity: 0;
  filter: blur(10px) saturate(0.4);
  transform: scale(1.08);
  transition: opacity 1100ms var(--ease-out),
              filter 1400ms var(--ease-out),
              transform 1600ms var(--ease-out);
  transition-delay: var(--d, 0ms);
}
[data-motion="develop"].is-in > * { opacity: 1; filter: none; transform: none; }

/* --- Geste 4 : LA SÉQUENCE. Il ne sert plus qu'à numéroter les enfants
       (`--i`, posé par motion.js) : la Méthode est pilotée par le
       défilement dans main.js. Ses anciennes règles visaient `.step`, zéro
       occurrence. Les gestes 5 et 6 (compteur, éventail) sont partis pour
       la même raison : aucun élément ne les portait plus. --- */

.shot { position: relative; overflow: hidden; border-radius: var(--r); background: var(--shell-2); }
.shot img, .shot video { width: 100%; height: 100%; object-fit: cover; }

.ar-239 { aspect-ratio: 2.39 / 1; }
.ar-169 { aspect-ratio: 16 / 9; }
.ar-45  { aspect-ratio: 4 / 5; }
.ar-32  { aspect-ratio: 3 / 2; }

/* `.chip` partait avec les cases métier : zéro occurrence sur les six
   pages. Les étiquettes de livrables passent par `.deliv__tag`, qui a
   trois variantes porteuses de sens, et non par une pastille neutre. */

/* ---------- 11. Méthode ---------- */
/* L'ancienne grille `.steps` est partie : la Méthode vit en section 25+
   (`.chrono`, `.etape`). */

/* ---------- 12. Confiance ---------- */
.trust { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap); }
.trust__item { background: var(--shell-2); border-radius: var(--r-lg); padding: 24px; }
.trust__k { font-family: var(--font-display); font-size: clamp(1.6rem, 2.7vw, 2.2rem); font-weight: 600; letter-spacing: -0.03em; }
.trust__v { margin-top: 8px; color: var(--ink-2); font-size: 0.9rem; }

/* ---------- 13. Bloc CTA ---------- */
.cta { background: var(--ink); color: var(--shell); border-radius: var(--r-lg); padding: clamp(32px, 5vw, 76px); }
.cta .label { color: var(--beam); }
.cta .lead { color: rgba(237,236,232,0.76); }
.cta__title { font-size: clamp(1.9rem, 4.6vw, 3.8rem); font-weight: 600; letter-spacing: -0.038em; line-height: 1.02; max-width: 18ch; }

/* ---------- 14. Pied de page ---------- */
.foot { border-top: 1px solid var(--hairline); padding-block: 48px 26px; }
.foot__grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1.4fr; gap: var(--gap); }
/* Les en-têtes de colonne du pied passent en h3 : elles suivaient un h2 de
   section, ce qui sautait un niveau de titre sur cinq pages. */
.foot h3 { font-family: var(--font-mono); font-size: var(--t-label); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2); font-weight: 400; margin-bottom: 14px; }
.foot li + li { margin-top: 8px; }
.foot a { color: var(--ink-2); transition: color var(--dur-fast) ease; }
.foot a:hover { color: var(--solar-ink); }
.foot__bottom {
  margin-top: 40px; padding-top: 18px; border-top: 1px solid var(--hairline);
  display: flex; flex-wrap: wrap; gap: 10px 24px; justify-content: space-between;
  font-family: var(--font-mono); font-size: var(--t-label); color: var(--ink-2);
}

/* ---------- 15. Page intérieure ---------- */
.phero { padding-top: calc(var(--nav-h) + clamp(44px, 6vw, 92px)); padding-bottom: clamp(32px, 4vw, 56px); }
.phero__title { font-size: var(--t-h1); }
.crumb { display: flex; gap: 8px; align-items: center; font-family: var(--font-mono); font-size: var(--t-label); color: var(--ink-2); margin-bottom: 18px; }
.crumb a { transition: color var(--dur-fast) ease; }
.crumb a:hover { color: var(--solar-ink); }

/* ---------- 16. Galerie ---------- */
/* La grille `.gal` part avec les galeries séparées : zéro occurrence sur
   les six pages. `.gal__cap` reste — la légende a survécu au conteneur,
   elle nomme maintenant les plans du récit et du diptyque. */
/* Sur fond clair — les galeries des trois pages métier. La bande sombre de
   l'accueil rehausse cette légende en section 36, où elle tient déjà 5,98:1. */
.gal__cap { margin-top: 10px; font-family: var(--font-mono); font-size: var(--t-label); color: var(--ink-2); }

/* ---------- 17. Formulaire ---------- */
.form { max-width: 760px; }
.progress { display: flex; gap: 6px; margin-bottom: 36px; }
.progress__seg { height: 5px; flex: 1; background: var(--shell-3); border-radius: var(--r-pill); overflow: hidden; position: relative; }
.progress__seg::after {
  content: ''; position: absolute; inset: 0; background: var(--solar);
  transform: scaleX(0); transform-origin: left; transition: transform 480ms var(--ease);
}
.progress__seg.is-done::after { transform: scaleX(1); }

.fstep { display: none; }
.fstep.is-active { display: block; animation: stepIn 460ms var(--ease); }
@keyframes stepIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.fstep__head { margin-bottom: 28px; }
.fstep__head h2 { font-size: var(--t-h2); margin-top: 8px; }

.field { margin-bottom: 22px; }
.field > label, .fieldset > legend { display: block; font-size: 0.88rem; font-weight: 500; margin-bottom: 8px; }
/* Le texte d'aide du formulaire est ce qui explique comment remplir un
   champ : c'est le dernier endroit où lésiner sur la lisibilité. */
.field .hint { font-size: 0.82rem; color: var(--ink-2); margin-top: 6px; }

.input, .select, .textarea {
  width: 100%; padding: 13px 15px;
  background: #F6F5F2;
  border: 1.5px solid var(--hairline);
  border-radius: var(--r);
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
/* Le placeholder porte de vrais exemples — « Lille 59000, Bondues 59910… ».
   --ink-3 donnait 3,61:1 sur le fond #F6F5F2 du champ ; --ink-2 tient 6,01:1. */
.input::placeholder, .textarea::placeholder { color: var(--ink-2); }
/* Pas d'`outline: none` ici : avec sa spécificité (0,2,0) il battait
   l'anneau de focus à deux tons de la section 35, posé en :focus-visible
   (0,1,0). Les champs perdaient le contraste garanti clair/sombre. On ne
   neutralise l'outline qu'au clic souris, jamais au clavier. */
.input:focus:not(:focus-visible),
.select:focus:not(:focus-visible),
.textarea:focus:not(:focus-visible) {
  outline: none;
}
.input:focus, .select:focus, .textarea:focus { border-color: var(--coral); }
.textarea { min-height: 142px; resize: vertical; line-height: 1.6; }

.fieldset { border: 0; margin-bottom: 22px; }
.choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }
.choice { position: relative; }
.choice input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.choice__box {
  display: block; height: 100%; padding: 17px;
  background: #F6F5F2; border: 1.5px solid var(--hairline);
  border-radius: var(--r); cursor: pointer;
  transition: border-color var(--dur-fast) ease, background var(--dur-fast) ease, transform var(--dur-fast) var(--ease);
}
.choice:hover .choice__box { border-color: var(--ink-3); transform: translateY(-2px); }
.choice input:checked + .choice__box { border-color: var(--solar); background: #FDEFE9; }
.choice input:focus-visible + .choice__box { outline: 2.5px solid var(--sky); outline-offset: 3px; }
.choice__t { font-weight: 600; display: block; }
.choice__d { font-size: 0.83rem; color: var(--ink-2); margin-top: 4px; display: block; line-height: 1.45; }

.fnav { display: flex; justify-content: space-between; gap: 12px; margin-top: 34px; padding-top: 24px; border-top: 1px solid var(--hairline); }

.err { color: var(--danger); font-size: 0.83rem; margin-top: 6px; display: none; }
.err.is-on { display: block; }
.input[aria-invalid="true"], .select[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--danger); }

.recap { background: var(--shell-2); border-radius: var(--r); padding: 22px; }
.recap dl { display: grid; grid-template-columns: auto 1fr; gap: 9px 18px; font-size: 0.9rem; }
/* Intitulés du récapitulatif : 3,85:1 à 14,4 px, c'est-à-dire l'écran où on
   demande au visiteur de relire ses réponses. La hiérarchie avec les valeurs
   en --ink tient toujours. */
.recap dt { color: var(--ink-2); }
.recap dd { font-weight: 500; }

.done { text-align: center; padding-block: 54px; }
.done__mark { width: 64px; height: 64px; margin: 0 auto 22px; border-radius: 50%; background: var(--grass); display: grid; place-items: center; color: var(--on-key); }

/* ---------- 18. Emplacements à tourner ---------- */
.ph {
  position: relative; height: 100%; min-height: 148px;
  background: var(--shell-2);
  border: 1.5px dashed var(--shell-3);
  border-radius: var(--r);
  display: grid; place-items: center; text-align: center; padding: 22px;
  color: var(--ink-2);
}
.ph__t { font-family: var(--font-mono); font-size: var(--t-label); letter-spacing: 0.1em; text-transform: uppercase; color: var(--solar-ink); }
.ph__d { font-size: 0.82rem; margin-top: 8px; max-width: 34ch; line-height: 1.5; }

/* ---------- 20. Utilitaires ---------- */
/* On pose UNIQUEMENT la fin de plage : le raccourci `grid-column: span N`
   écrit start ET end, et `grid-column-start` posé ensuite par .start-N
   écrasait le span — l'élément retombait à une seule colonne et le texte
   s'affichait à la verticale. */
.c-3{grid-column-end:span 3}
.c-4{grid-column-end:span 4}.c-5{grid-column-end:span 5}.c-6{grid-column-end:span 6}
.c-7{grid-column-end:span 7}.c-8{grid-column-end:span 8}
.c-12{grid-column-end:span 12}

.start-7{grid-column-start:7}.start-9{grid-column-start:9}

.stack-s > * + * { margin-top: 12px; }
.stack-m > * + * { margin-top: 22px; }
.stack-l > * + * { margin-top: 36px; }

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* Le lien d'évitement doit redevenir visible quand il reçoit le focus,
   sinon le tout premier arrêt de tabulation du site n'existe pas à
   l'écran : l'utilisateur au clavier tape Tab, ne voit rien bouger, et
   doit deviner. Le mécanisme était dans le HTML des six pages et
   neutralisé par le CSS — le pire des deux mondes, parce qu'un contrôle
   automatique qui lit `outline` le compte comme conforme alors que
   l'élément mesure 1×1 px rogné à zéro. WCAG 2.4.7.
   `clip-path` autant que `clip` : le premier est la propriété vivante,
   le second reste nécessaire tant que `.sr-only` le pose. */
.sr-only:focus,
.sr-only:focus-visible {
  position: fixed; top: 12px; left: 12px; z-index: 200;
  width: auto; height: auto; margin: 0; padding: 12px 22px;
  overflow: visible; clip: auto; clip-path: none; white-space: nowrap;
  background: var(--shell); color: var(--ink);
  font-family: var(--font-ui); font-size: 0.95rem; font-weight: 600;
  border-radius: var(--r-pill); box-shadow: var(--nm-out, 0 8px 24px rgba(0,0,0,.22));
}

/* ---------- 21. Responsive ---------- */
@media (max-width: 1080px) {
  .steps { grid-template-columns: repeat(2, 1fr); row-gap: 34px; }
  .foot__grid { grid-template-columns: 1fr 1fr; row-gap: 34px; }
}
@media (max-width: 860px) {
  :root { --nav-h: 62px; --gap: 16px; }
  .nav__links { display: none; }
  .burger { display: block; }
  .trust { grid-template-columns: 1fr; }
  [class*="c-"] { grid-column: 1 / -1 !important; }
  [class*="start-"] { grid-column-start: 1; }
  .gal { grid-template-columns: 1fr; }
  .ar-239 { aspect-ratio: 16/9; }
}
@media (max-width: 560px) {
  .steps { grid-template-columns: 1fr; }
  .foot__grid { grid-template-columns: 1fr; }
}

/* ---------- 22. Mouvement réduit ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  /* Mouvement réduit veut dire moins de mouvement, pas plus aucun retour
     d'interface. On coupe les boucles et les gestes qui déplacent le
     contenu… */
  .scrollcue i,
  .btn[aria-busy="true"] svg {
    animation: none !important;
  }
  [data-reveal], [data-motion="focus"], [data-motion="develop"] > *,
  [data-motion="mask"] .ln {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }

  /* …mais on garde les transitions courtes qui confirment une action :
     un bouton qui ne réagit pas se lit comme un bouton cassé. */
  .btn, .input, .select, .textarea, .choice__box, .faq__q::after,
  .nav__link, .foot a, .tlink {
    transition-duration: 120ms !important;
  }
}

/* ---------- 23. Impression ---------- */
@media print {
  .nav, .cta { display: none !important; }
  body { background: #fff; color: #000; }
}


/* ============================================================
   25. CORAIL ÉLECTRIQUE
   Fond clair en dégradé continu, accent corail → mandarine.
   Le fond défile SOLIDAIREMENT du contenu : plus de couche en
   position fixed, la chaleur est dans le dégradé lui-même.
   Le texte des boutons est sombre : le blanc ne passe pas sur
   corail (3,10:1) ni sur mandarine (2,11:1). Sombre = 5,09:1.
   ============================================================ */

:root {
  /* L'amplitude du papier est réduite de moitié.

     Elle allait du blanc cassé à une pêche franche (#FFCFB4). Sur l'accueil,
     où le papier réapparaît entre chaque bande sombre, le défilement
     enchaînait donc crème clair, sombre, pêche, sombre, pêche plus soutenue :
     le fond changeait de couleur autant que les blocs posés dessus.

     Le papier garde sa chaleur et sa progression — il s'assombrit toujours
     en descendant, c'est l'idée d'éclairage qui tient la page — mais il ne
     change plus assez pour se faire remarquer. Le contraste ne peut que
     s'améliorer : tous les arrêts s'éclaircissent, et l'ancienne butée
     mesurée (--ink-2 à 4,30:1 au cran suivant de #FFCFB4) s'éloigne. */
  --g1: #FFFCF9;
  --g2: #FFF6EF;
  --g3: #FFEDE2;
  --g4: #FFE0CE;

  --shell:   #FFF7F1;
  --shell-2: #FFF3EC;
  --shell-3: #FFE9DC;
  --hairline: rgba(190,140,115,.20);

  --ink:   #362B24;
  --ink-2: #6B5A50;
  --ink-3: #8F7D71;

  --coral: #FF5A3C;
  --mand:  #FF9A3C;
  --coral-ink: #D52100;
  --grad-acc: linear-gradient(120deg, #FF5A3C 0%, #FF9A3C 100%);

  --solar: #FF5A3C;
  --solar-ink: #D52100;
  --sky: #FF7A48;
  --grass: #2FA36B;
  --beam: #FF9A3C;
  --on-key: #2A1A12;
  --danger: #C22B10;

  --font-display: 'Plus Jakarta Sans', sans-serif;
  --font-body: 'DM Sans', sans-serif;
  --r: 14px; --r-lg: 26px; --r-pill: 999px;

  --pane:   linear-gradient(145deg, rgba(255,255,255,.72), rgba(255,255,255,.24));
  --pane-2: linear-gradient(145deg, rgba(255,255,255,.46), rgba(255,255,255,.10));
  --nm-rgb: 214,166,140;

  --nm-out:    10px 10px 24px rgba(var(--nm-rgb), .34),
               -8px -8px 20px rgba(255,255,255,.85),
               inset 1px 1px 0 rgba(255,255,255,.65);
  --nm-out-hi: 14px 14px 32px rgba(var(--nm-rgb), .42),
               -10px -10px 26px rgba(255,255,255,.92),
               inset 1px 1px 0 rgba(255,255,255,.75);
  --nm-out-sm: 6px 6px 14px rgba(var(--nm-rgb), .28),
               -5px -5px 12px rgba(255,255,255,.80),
               inset 1px 1px 0 rgba(255,255,255,.60);
  --nm-in:     inset 7px 7px 16px rgba(var(--nm-rgb), .34),
               inset -6px -6px 14px rgba(255,255,255,.85);
  --nm-in-sm:  inset 3px 3px 7px rgba(var(--nm-rgb), .28),
               inset -3px -3px 7px rgba(255,255,255,.75);
}

/* Le fond : un seul dégradé continu sur toute la hauteur du document.
   Il défile avec le contenu — c'est ce qui règle la différence de
   vitesse que tu voyais (l'ancienne couche était en position:fixed). */
/* Le fond était un seul dégradé linéaire étiré sur toute la hauteur du
   document. Sur une page de huit écrans, chaque écran n'en traversait que
   douze pour cent : la variation existait sur le papier et ne se voyait
   nulle part. D'où l'impression de dégradé accidentel.

   Il est repensé comme un éclairage, pas comme une teinte — la grammaire
   du métier plutôt qu'une décoration. Une lumière principale tombe du haut
   à gauche, dans l'axe de celle du hero. Un contre-jour chaud remonte du
   bas à droite. Et la montée en chaleur est repoussée dans le tiers
   inférieur, là où la page enchaîne ses plus longues plages claires : on
   descend vers la lumière du soir au lieu de traverser un aplat.

   Le fond défile avec le contenu : on avance DANS la lumière.
   Butée mesurée : `--g4` ne peut pas descendre plus bas sans faire passer
   `--ink-2` sous 4,5:1 (4,63 ici, 4,30 au cran suivant). */
body {
  background:
    radial-gradient(68% 30% at 6% 0%,
      rgba(255,255,255,.94) 0%, rgba(255,255,255,0) 62%),
    radial-gradient(54% 24% at 100% 76%,
      rgba(255,176,126,.42) 0%, rgba(255,176,126,0) 70%),
    linear-gradient(174deg,
      var(--g1) 0%,
      var(--g1) 10%,
      var(--g2) 34%,
      var(--g2) 48%,
      var(--g3) 72%,
      var(--g4) 94%,
      var(--g4) 100%);
  background-attachment: scroll;
  background-repeat: no-repeat;
  color: var(--ink);
}

/* ---------- Boutons : minimalistes, aucun glow ---------- */
.btn {
  border-radius: var(--r-pill);
  box-shadow: none;
  transition: transform 160ms var(--ease), background 200ms ease, opacity 200ms ease;
}
.btn--accent {
  background: var(--grad-acc);
  color: var(--on-key);
  font-weight: 600;
  box-shadow: none;
}
.btn--accent:hover { transform: translateY(-2px); filter: saturate(1.08); box-shadow: none; }
.btn--accent:active { transform: translateY(0); }

.btn--ghost {
  background: transparent;
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px rgba(54,43,36,.28);
}
.btn--ghost:hover { box-shadow: inset 0 0 0 1.5px var(--coral); color: var(--coral-ink); background: transparent; }

/* ---------- Surfaces vitrées ---------- */
.trust__item, .cta, .recap {
  background: var(--pane);
  border: 0;
  box-shadow: var(--nm-out);
  border-radius: var(--r-lg);
}
.ph, .shot { background: var(--pane-2); border: 0; box-shadow: var(--nm-in); }
.chip { background: var(--pane-2); box-shadow: var(--nm-in-sm); color: var(--ink-2); border: 0; }
.step__n { background: var(--grad-acc); color: var(--on-key); box-shadow: none; }
.done__mark { background: var(--grad-acc); color: var(--on-key); }

.nav--solid {
  background: rgba(255,252,249,.80);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 6px 20px rgba(var(--nm-rgb), .18);
}
.hero__title em {
  background: var(--grad-acc);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ---------- Séparateurs gravés ---------- */
.rule { height: 2px; background: transparent; border-radius: 2px; box-shadow: var(--nm-in-sm); }
.fnav, .foot, .foot__bottom { border-top: 0; position: relative; }
.fnav::before, .foot::before, .foot__bottom::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  border-radius: 2px; box-shadow: var(--nm-in-sm);
}

/* ---------- Formulaire ---------- */
.choice__box { background: var(--pane); border: 0; box-shadow: var(--nm-out-sm);
  transition: box-shadow 220ms ease, transform 220ms ease; }
.choice:hover .choice__box { box-shadow: var(--nm-out); transform: translateY(-2px); }
.choice input:checked + .choice__box { background: var(--pane-2); box-shadow: var(--nm-in); transform: translateY(1px); }
.choice input:checked + .choice__box .choice__t { color: var(--coral-ink); }
.input, .select, .textarea { background: var(--pane-2); border: 0; box-shadow: var(--nm-in); }
.input:focus, .select:focus, .textarea:focus { box-shadow: var(--nm-in), 0 0 0 2px var(--coral); }
.progress__seg { background: var(--pane-2); box-shadow: var(--nm-in-sm); }
.progress__seg::after { background: var(--grad-acc); border-radius: 999px; }

/* ============================================================
   26. HERO SOMBRE
   ============================================================ */
.hero--dark {
  position: relative; min-height: 100svh;
  display: flex; align-items: flex-end; overflow: hidden;
  background:
    radial-gradient(120% 90% at 78% 16%, #3A2018 0%, transparent 56%),
    radial-gradient(100% 80% at 16% 94%, #45210F 0%, transparent 60%),
    linear-gradient(165deg, #1A100C 0%, #241610 54%, #150D0A 100%);
  color: #F7EDE7;
  padding-top: calc(var(--nav-h) + 40px);
  padding-bottom: clamp(48px, 6vw, 92px);
}
.hero--dark::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .05;
  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='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.hero--dark .hero__inner { position: relative; z-index: 2; width: 100%; }
.hero--dark .hero__title { color: #FBF4EF; }
.hero--dark .label { color: rgba(247,237,231,.62); }
.hero--dark .hero__facts { color: rgba(247,237,231,.86); }
.hero--dark .btn--ghost { color: #FBF4EF; box-shadow: inset 0 0 0 1.5px rgba(247,237,231,.40); }
.hero--dark .btn--ghost:hover { box-shadow: inset 0 0 0 1.5px var(--mand); color: var(--mand); }
.hero--dark .scrollcue {
  position: absolute; right: var(--page-x); bottom: clamp(48px, 6vw, 92px); z-index: 2;
  display: flex; align-items: center; gap: 12px;
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .16em; text-transform: uppercase; color: rgba(247,237,231,.55);
}
.hero--dark .scrollcue i {
  display: block; width: 1px; height: 42px; transform-origin: top;
  background: linear-gradient(180deg, rgba(247,237,231,.7), transparent);
  animation: cue 2.4s cubic-bezier(.65,0,.35,1) infinite;
}
@keyframes cue { 0%{transform:scaleY(0);opacity:0} 35%{opacity:1} 100%{transform:scaleY(1);opacity:0} }
@media (max-width: 860px) { .hero--dark .scrollcue { display: none; } }

.cta--dark {
  background: linear-gradient(150deg, #1F130E 0%, #341C12 55%, #180F0B 100%);
  color: #F7EDE7; box-shadow: none;
}
.cta--dark .lead { color: rgba(247,237,231,.76); }
.cta--dark .label { color: var(--mand); }
.cta--dark .cta__title { color: #FBF4EF; }

/* L'appel final pleine largeur des pages métier et d'À propos est un
   `<section class="cta">` qui contient un `.wrap`. Il héritait du rembourrage
   latéral de la carte `.cta` (72 px) en plus de celui du cadre : son titre
   tombait à x = 137 quand tous les autres titres de la page sont à x = 65.
   Le cadre intérieur porte déjà la marge de page ; le bloc, lui, n'a plus
   d'arrondi, puisqu'il touche les bords de l'écran. L'accueil n'est pas
   concerné : son appel final est une carte `<div class="cta">`. */
section.cta { padding-inline: 0; border-radius: 0; }

/* ============================================================
   27. BOUCLES HORS CHAMP
   ============================================================ */
/* La banderole défilante a quitté l'accueil ; ses règles sont parties avec
   elle (zéro occurrence sur les sept pages). Il reste une boucle, l'indicateur
   de défilement du hero. Une boucle qui tourne hors écran consomme de la
   batterie pour rien : main.js pose `is-out` quand elle quitte le viewport.
   Spécificité assumée : `.hero--dark .scrollcue i` pose le raccourci
   `animation`, qui réinitialise l'état de lecture. Il faut le battre. */
.hero--dark .scrollcue.is-out i { animation-play-state: paused; }

/* ============================================================
   29. ACCENT PAR MÉTIER
   Même gabarit, seul l'accent glisse.
   ============================================================ */
/* Trois territoires, et non trois nuances du même orange.
   L'ancien système mettait immobilier à #FF6B3C et mariage à #FF5A3C :
   **5 degrés de teinte d'écart**, soit la même couleur. C'est ce qui
   produisait l'entre-deux — assez différent pour suggérer trois univers,
   pas assez pour qu'on en sente un seul.

   Le nouveau système sépare par la TEINTE, pas par la luminosité :
   ambre 33°, grenat 347°, acier 209°. Écarts mesurés : 48°, 135°, 177°.
   Chacun garde le contrat de la marque — texte sombre sur l'aplat — et
   chacun est mesuré contre `--on-key` avant d'être posé.

   La marque elle-même (accueil) reste corail → mandarine à 9° : les trois
   métiers en sont les enfants, pas des marques concurrentes. */

/* L'ambre — la lumière sur la brique et le verre. Contraste 6,23:1. */
[data-cat="immobilier"] {
  --coral: #E08A1E; --coral-ink: #9A5B00; --mand: #F5B94A;
  --grad-acc: linear-gradient(120deg, #E08A1E, #F5B94A);
  --ph-grad: linear-gradient(120deg, #2C2A3F, #163040);
  --deep:
    radial-gradient(110% 88% at 80% 14%, #3B2A12 0%, transparent 58%),
    linear-gradient(165deg, #1A140C 0%, #33260F 54%, #14100A 100%);
}
/* Le grenat — la peau et le soir. 5,18:1 : le rose est assez profond pour
   ne pas être un rose de dragée, assez clair pour porter l'encre sombre. */
[data-cat="mariage"] {
  --coral: #EC5F7E; --coral-ink: #A81F45; --mand: #F7A0A8;
  --grad-acc: linear-gradient(120deg, #EC5F7E, #F7A0A8);
  --ph-grad: linear-gradient(120deg, #3B1F2C, #5A2A38);
  --deep:
    radial-gradient(110% 88% at 80% 14%, #3E1C2A 0%, transparent 58%),
    linear-gradient(165deg, #1A0E13 0%, #341823 54%, #140B10 100%);
}
/* Le bleu était trop sombre pour l'encre sombre des boutons d'accent :
   #2F7FD4 ne donnait que 4,07:1 avec --on-key, sous le seuil AA — et le
   blanc n'aurait pas fait mieux (4,11:1). Le 5,09:1 annoncé dans CLAUDE.md
   valait pour le corail, pas pour cette teinte. #3F8FDA remonte à 4,90:1
   sans quitter le bleu. Ne le rassombris pas sans remesurer le bouton. */
[data-cat="entreprise"] {
  /* `--mand` est passé de #4FA8E8 à #6BB6EE. Depuis que la bande phare prend
     le `--deep` de sa catégorie, cette teinte porte du texte sur un fond
     marine : du bleu sur du bleu, soit 4,50:1 au point le plus clair du
     dégradé — la valeur seuil exacte, sans un centième de marge. #6BB6EE
     donne 5,31:1 au même endroit.
     `--grad-acc` garde ses hexadécimaux écrits en clair : le fond de bouton
     ne bouge pas, et le 4,90:1 mesuré avec `--on-key` reste valable. */
  --coral: #3F8FDA; --coral-ink: #1B5FA8; --mand: #6BB6EE;
  --grad-acc: linear-gradient(120deg, #3F8FDA, #4FA8E8);
  --ph-grad: linear-gradient(120deg, #17293D, #1E3A52);
  --deep:
    radial-gradient(110% 88% at 80% 14%, #1B3A5A 0%, transparent 58%),
    linear-gradient(165deg, #0E1620 0%, #17293D 54%, #0B1219 100%);
}
[data-cat="entreprise"] h1,
[data-cat="entreprise"] h2,

/* ------------------------------------------------------------
   29.2  Le papier suit la catégorie
   L'accent glissait déjà (boutons, héros, pastilles) mais le fond
   du document restait pêche sur les trois pages. Sur entreprise,
   dont l'accent est bleu, la page entière tirait vers l'orange :
   les cartes de bas de page avaient l'air posées sur un autre site.

   Ce qui glisse ici : les trois arrêts du dégradé de fond, les deux
   surfaces `--shell-*`, le filet, et surtout `--nm-rgb`, la teinte
   des ombres neumorphiques — sans elle, chaque relief garderait un
   halo orangé sur un fond bleu. `--g1` reste quasi blanc dans les
   trois cas : c'est le haut de page, il doit rester neutre.

   L'amplitude est délibérément faible. La direction reste sobre :
   on doit sentir la teinte sans pouvoir la nommer.
   ------------------------------------------------------------ */
/* La pierre, et non plus le jaune. Le papier tirait vers un jaune de
   surligneur qui ne ressemblait à rien de ce que ce métier photographie.
   L'immobilier et l'architecture ont une matière à eux : le plâtre, le
   calcaire, le béton clair. Un greige chaud, donc, qui reste dans la
   famille du site sans en répéter la pêche.

   Vérification faite au passage, et ce n'était pas qu'une question de
   goût : l'encre ambre #9A5B00 ne tenait que 4,33:1 sur l'ancien jaune,
   sous le seuil AA. Elle passe à #7D4900, soit 5,37:1 sur le fond le plus
   profond de la page et 6,78:1 sur le plus clair. */
[data-cat="immobilier"] {
  --g2: #F7F4EF; --g3: #EDE7DF; --g4: #E2DACF;
  --shell-2: #F7F4EF; --shell-3: #EDE7DF;
  --hairline: rgba(150,133,110,.26);
  --nm-rgb: 186,172,152;
}
[data-cat="immobilier"] { --coral-ink: #7D4900; }
[data-cat="mariage"] {
  /* Le papier suit le grenat. `--nm-rgb` est le point critique : sans lui,
     chaque relief garderait un halo orangé sur un fond rosé. */
  --g2: #FFF1F3; --g3: #FFE1E7; --g4: #FFD1DB;
  --shell-2: #FFF1F3; --shell-3: #FFE1E7;
  --hairline: rgba(186,120,140,.22);
  --nm-rgb: 210,158,172;
}
[data-cat="entreprise"] {
  --g2: #EFF4F9; --g3: #DEE9F3; --g4: #CDDDEE;
  --shell-2: #F2F6FB; --shell-3: #E2ECF6;
  --hairline: rgba(120,150,180,.24);
  --nm-rgb: 150,175,200;
}
/* La barre de navigation opaque était figée en blanc chaud. */
[data-cat="entreprise"] .nav--solid { background: rgba(248,251,254,.82); }

/* ------------------------------------------------------------
   29.3  Le sommaire de page métier
   « J'ai l'impression de chercher les infos au hasard. » Quatre
   ancres posées sous la devanture, dans l'ordre où les questions
   se posent : ce que je reçois, combien, à quoi ça ressemble, et
   le reste. Ce n'est pas décoratif — c'est la table des matières
   qui manquait à une page longue.
   ------------------------------------------------------------ */
/* La navigation est fixe : sans cette marge, une ancre dépose son titre
   sous la barre et le visiteur croit avoir atterri au mauvais endroit. */
[id] { scroll-margin-top: calc(var(--nav-h) + 28px); }

.jump { display: flex; flex-wrap: wrap; gap: 8px; padding-top: clamp(22px, 2.6vw, 34px); }
.jump a {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2);
  padding: 10px 16px; border-radius: var(--r-pill);
  background: var(--pane-2); box-shadow: var(--nm-out-sm);
  transition: color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
.jump a:hover, .jump a:focus-visible { color: var(--coral-ink); box-shadow: var(--nm-in-sm); }

/* ------------------------------------------------------------
   29.4  La signature
   Un visiteur venu de Google atterrit sur une page métier sans
   jamais voir qui parle : tout le texte est à la première personne
   et n'appartient à personne. Ce bloc referme la page sur un nom,
   un visage et un lien.
   ------------------------------------------------------------ */
.sign {
  display: grid; grid-template-columns: auto 1fr;
  gap: clamp(18px, 2.6vw, 32px); align-items: center;
  padding: clamp(20px, 2.6vw, 32px);
  background: var(--pane); box-shadow: var(--nm-out); border-radius: var(--r-lg);
}
.sign__ph {
  width: clamp(78px, 9vw, 112px); aspect-ratio: 4/5;
  border-radius: var(--r); overflow: hidden; box-shadow: var(--nm-in-sm);
}
.sign__ph img { width: 100%; height: 100%; object-fit: cover; }
.sign__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-2);
}
.sign__n { font-family: var(--font-display); font-size: var(--t-h3); font-weight: 600; margin-top: 7px; }
.sign p { color: var(--ink-2); margin-top: 9px; max-width: 58ch; font-size: .95rem; }
.sign .tlink { margin-top: 12px; }
@media (max-width: 560px) { .sign { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------
   29.5  Les deux moitiés du métier
   Le site parlait surtout du drone, alors que la caméra au sol est
   l'autre moitié du fonds de commerce. Deux colonnes séparées d'un
   filet plutôt que deux cartes : c'est une comparaison, pas une
   grille de fonctionnalités.
   ------------------------------------------------------------ */
/* ------------------------------------------------------------
   29.6  Les cadres de galerie s'animent au survol
   Deux secondes et demie en boucle, par-dessus la photo. Rien ne
   part sur le réseau tant que le curseur n'entre pas dans le
   cadre : `preload="none"` et la vidéo n'est même pas créée avant
   le premier survol. Au doigt, l'effet n'existe pas — c'est la
   photo qui reste, et aucun octet n'est téléchargé.
   ------------------------------------------------------------ */
.shot video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 420ms ease;
}
.shot.is-playing video { opacity: 1; }

.duo { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(26px, 4vw, 58px); }
.duo__i + .duo__i {
  border-left: 1px solid var(--hairline); padding-left: clamp(26px, 4vw, 58px);
}
.duo__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .12em; text-transform: uppercase; color: var(--coral-ink);
}
.duo__i h3 { font-size: var(--t-h3); margin-top: 12px; }
.duo__i p { color: var(--ink-2); margin-top: 12px; max-width: 46ch; }
@media (max-width: 760px) {
  .duo { grid-template-columns: 1fr; gap: 0; }
  .duo__i + .duo__i {
    border-left: 0; padding-left: 0;
    border-top: 1px solid var(--hairline);
    margin-top: clamp(26px, 6vw, 38px); padding-top: clamp(26px, 6vw, 38px);
  }
}

/* ------------------------------------------------------------
   Le parcours du regard dans le hero
   Les quatre blocs étaient empilés sur le même bord gauche, à des
   largeurs voisines : rien ne relançait l'œil, qui descendait tout
   droit, et la moitié droite du cadre ne portait rien.

   Les faits passent à droite, calés sur la dernière ligne du titre,
   et un filet part du titre vers eux. Le regard sort de « de la
   hauteur » par la droite, revient à gauche sur les boutons : un Z
   au lieu d'un I. Aucune animation là-dedans — c'est la mise en
   page qui porte le mouvement.
   ------------------------------------------------------------ */
.hero__lede {
  display: grid;
  grid-template-columns: auto minmax(20px, 1fr) auto;
  align-items: end;
  column-gap: clamp(16px, 2.2vw, 30px);
  margin-top: clamp(20px, 2.6vw, 34px);
}
.hero--dark .hero__title { margin-bottom: 0; }

/* Le filet occupe sa propre colonne et prend tout ce qui reste : c'est lui
   qui traverse le vide entre le titre et les faits, au lieu de laisser le
   tiers droit du cadre ne rien porter. Il s'éteint vers la droite pour que
   l'œil arrive sur les faits et non sur une ligne qui bute. */
.hero__tie {
  height: 1px; align-self: end; margin-bottom: 1.15em;
  background: linear-gradient(90deg,
    rgba(247,237,231,.10), rgba(247,237,231,.58) 62%, rgba(247,237,231,.20));
}

.hero__facts {
  position: relative;
  display: grid; gap: clamp(9px, 1vw, 13px);
  padding-bottom: .5em;         /* la première puce s'assied sur la base du titre */
  font-family: var(--font-mono);
  font-size: var(--t-label); letter-spacing: .08em; text-transform: uppercase;
  line-height: 1.35;
}
.hero__facts li { position: relative; padding-left: 19px; }
.hero__facts li::before {
  content: ''; position: absolute; left: 0; top: .48em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--mand);
}
@media (max-width: 900px) {
  .hero__lede { grid-template-columns: 1fr; row-gap: clamp(24px, 3.6vw, 34px); }
  .hero__facts { padding-bottom: 0; }
  .hero__tie { display: none; }   /* plus rien à relier : les blocs s'empilent */
}

.hero--dark .hero__actions { margin-top: clamp(32px, 3.4vw, 46px); }

/* ---------- Navigation lisible sur le hero sombre ---------- */
/* Tant que la nav est transparente au-dessus du hero sombre, le
   wordmark et les liens doivent être clairs. Dès qu'elle devient
   opaque au scroll, ils reprennent l'encre normale. Scopé au
   gabarit à hero sombre : les pages intérieures démarrent clair. */
[data-hero="dark"] .nav:not(.nav--solid) .wordmark,
[data-hero="dark"] .nav:not(.nav--solid) .nav__link { color: #FBF4EF; }
[data-hero="dark"] .nav:not(.nav--solid) .nav__link:hover { color: #FFFFFF; }
[data-hero="dark"] .nav:not(.nav--solid) .wordmark__sub { color: rgba(251, 244, 239, .74); }
[data-hero="dark"] .nav:not(.nav--solid) .burger span { background: #FBF4EF; }
[data-hero="dark"] .nav:not(.nav--solid) .btn--ghost {
  color: #FBF4EF; box-shadow: inset 0 0 0 1.5px rgba(251, 244, 239, .42);
}

/* ============================================================
   30. LE DEMOREEL EN FOND DE HERO
   La vidéo habite le hero en opacité réduite : c'est le dégradé
   sombre qui continue de porter le texte, l'image ne fait que
   respirer derrière. Tant que le fichier n'existe pas, rien ne
   s'affiche et le hero reste exactement tel qu'il est aujourd'hui.
   ============================================================ */
.hero__bg {
  position: absolute; inset: 0; z-index: 0;
  opacity: 0; transition: opacity 1400ms var(--ease-out);
  pointer-events: none; overflow: hidden;
}
.hero__bg.is-on { opacity: 1; }
.hero__bg video, .hero__bg img {
  width: 100%; height: 100%; object-fit: cover;
  /* .38 → .52. Tristan : « on ne voit pas assez les vidéos ».
     Mesuré : le demoreel contient des pixels à 255 de luminance — le pire
     cas est donc une image entièrement blanche, et non le 0,385 qu'affirmait
     la note précédente, qui sous-estimait le risque.

     Recalculé sur ce pire cas, en interpolant le voile ET le foyer radial
     à la position réelle de chaque texte : navigation 5,17:1, label 5,45:1,
     titre 12,3:1, colonne des faits 9,55:1, bouton 16,4:1, indicateur
     5,19:1. Tout tient AA sans toucher au voile — c'est le foyer radial en
     bas à gauche, ignoré par l'ancienne mesure, qui donne cette marge.
     Le maillon faible est la navigation, qui flotte sur le haut du cadre
     où le voile est le plus mince : au-delà de .60 elle passe sous 4,5:1. */
  opacity: .52;
}
/* Le voile : il assied le titre sur le bas du cadre, là où la
   vidéo est la plus chargée. */
.hero__bg::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(0deg,
      rgba(21,13,10,.94) 0%,
      rgba(21,13,10,.62) 42%,
      rgba(21,13,10,.34) 100%),
    radial-gradient(78% 58% at 18% 92%, rgba(21,13,10,.72), transparent 72%);
}

/* ============================================================
   33. QUESTIONS FRÉQUENTES
   Les objections qui font partir un visiteur en silence.
   <details> natif : aucun JS, et ça reste accessible au clavier.
   ============================================================ */
.faq { display: grid; gap: 10px; max-width: 980px; align-items: start; }
.faq__col { display: grid; gap: 10px; align-content: start; }

/* En pleine largeur, la FAQ occupait 980 px dans un cadre de 1 300 et
   laissait 320 px de colonne morte sur toute sa hauteur — à la place
   d'« avant-dernier bloc », donc à l'endroit que la règle du pic-fin
   rend mémorable. Deux colonnes au-delà de 1 100 px : la largeur sert,
   la mesure de lecture reste courte, et le bloc perd la moitié de sa
   hauteur.

   ⚠️ Ce commentaire affirmait qu'avec `align-items: start` un volet ouvert
   « pousse sa seule colonne ». C'était faux : les rangées d'une grille sont
   partagées. Mesuré, ouvrir le premier volet laissait 255 px de vide sous
   son voisin et faisait descendre le quatrième de 245 px. Les questions
   sont donc réparties dans deux `.faq__col`, des colonnes indépendantes qui
   grandissent chacune de leur côté. La première reçoit la première moitié
   des questions : l'ordre du document, donc du clavier et des lecteurs
   d'écran, reste celui de la liste. */
@media (min-width: 1100px) {
  .faq { max-width: none; grid-template-columns: repeat(2, 1fr); gap: 10px 20px; }
}
.faq__i {
  background: var(--pane); box-shadow: var(--nm-out-sm);
  border-radius: var(--r); overflow: hidden;
  transition: box-shadow 300ms ease;
}
.faq__i[open] { box-shadow: var(--nm-out); }
.faq__q {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; padding: clamp(17px, 1.9vw, 23px) clamp(20px, 2.2vw, 30px);
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1rem, 1.35vw, 1.14rem); letter-spacing: -.022em;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after {
  content: ''; flex-shrink: 0; width: 12px; height: 12px;
  border-right: 2px solid var(--coral); border-bottom: 2px solid var(--coral);
  transform: rotate(45deg) translate(-3px, -3px);
  transition: transform 320ms var(--ease);
}
.faq__i[open] .faq__q::after { transform: rotate(-135deg) translate(-3px, -3px); }
/* La réponse apparaissait d'un bloc à l'ouverture, seule l'ombre et le
   chevron disaient que quelque chose avait changé. Elle glisse maintenant
   de 6 px en se révélant. À la fermeture, rien : la sortie doit être plus
   rapide que l'entrée. `<details>` n'animant pas sa hauteur, seule la
   réponse bouge, pas la mise en page. */
.faq__i[open] .faq__a { animation: faqOuvre 280ms cubic-bezier(.16, 1, .3, 1); }
@keyframes faqOuvre { from { opacity: 0; transform: translateY(-6px); } }
@media (prefers-reduced-motion: reduce) { .faq__i[open] .faq__a { animation: none; } }
.faq__a {
  padding: 0 clamp(20px, 2.2vw, 30px) clamp(20px, 2.2vw, 26px);
  color: var(--ink-2); font-size: .95rem; max-width: 72ch;
}
.faq__a a { color: var(--coral-ink); box-shadow: 0 1px 0 currentColor; }

@media (max-width: 860px) {
}

/* ============================================================
   34. HERO DE CATÉGORIE
   Les pages métier ouvraient sur un fil d'Ariane : c'est la
   première surface que voit un visiteur venu de Google, elle ne
   pouvait pas être la plus faible du site. Même gabarit sombre
   que l'accueil, teinté par la catégorie, mais moins haut — on
   doit sentir qu'il y a du contenu dessous.
   ============================================================ */
/* La devanture occupe presque tout l'écran, comme le hero d'accueil.
   Ce n'est pas qu'une affaire de présence : à 1440×900 l'ancienne hauteur
   de 665 px donnait un rapport de 2,15 contre 1,78 à la vidéo, donc 17 %
   de l'image rognée en haut et en bas. À 90svh sur un écran 16/10, la
   boîte tombe pile sur 16/9 et il ne reste plus rien à rogner.

   Le contenu est poussé en bas comme à l'accueil : le fil d'Ariane reste
   en haut, tout le reste descend, et le tiers supérieur se libère pour
   l'image. C'est ce qui permet d'alléger le voile là-haut (voir plus bas)
   sans toucher à la lisibilité du bloc de texte. */
.chero {
  position: relative; overflow: hidden;
  min-height: 90svh;
  display: flex;
  background: var(--deep, linear-gradient(165deg, #1A100C 0%, #241610 54%, #150D0A 100%));
  color: #F7EDE7;
  padding-top: calc(var(--nav-h) + clamp(24px, 3vw, 40px));
  padding-bottom: clamp(48px, 6vw, 92px);
}
.chero > .wrap { flex: 1; display: flex; flex-direction: column; }
/* Le fil d'Ariane garde le haut, le reste est poussé au sol. */
.chero .wrap > .grid12 { margin-top: auto; }
/* Le bouton portait un margin-top en style inline sur les trois pages :
   retiré du HTML et rapatrié ici, où il peut respirer avec le reste. */
.chero .wrap > p:last-child { margin-top: clamp(34px, 4vw, 54px); }

/* Sous 860 px la mise en page s'empile et dépasse déjà la hauteur d'écran :
   forcer 90svh n'ajouterait qu'un vide sous le fil d'Ariane. L'espacement y
   reste serré — la fiche technique passe sur trois lignes, et chaque pixel
   gagné rapproche le bouton de la ligne de flottaison. */
@media (max-width: 860px) {
  .chero { min-height: 0; padding-top: calc(var(--nav-h) + clamp(24px, 5vw, 40px)); }
  .chero .wrap > .grid12 { margin-top: clamp(16px, 3.5vw, 28px); }
  .chero .wrap > p:last-child { margin-top: clamp(24px, 5vw, 34px); }
  .spec { margin-top: clamp(24px, 5vw, 36px); padding-top: clamp(16px, 3vw, 22px); }
}
.chero::after {   /* le même grain que le hero d'accueil */
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .05;
  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='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.chero > * { position: relative; z-index: 2; }

/* ------------------------------------------------------------
   La devanture : fond vidéo du hero de catégorie
   Repris du hero d'accueil, mais le voile est calculé autrement.
   À l'accueil le titre est posé en bas, donc le voile n'a besoin
   d'être opaque qu'en bas. Ici le texte occupe toute la hauteur —
   fil d'Ariane en haut, titre à gauche, accroche à droite, fiche
   technique en bas — et le voile doit donc tenir partout.

   Il est dimensionné pour le pire cas absolu, une image entièrement
   blanche : dans ce cas le fond composite reste à une luminance de
   0,044, et le fil d'Ariane — le plus petit texte du bloc, 11,5 px —
   tient encore 4,64:1. Toute vraie image sera plus sombre que ça.
   Ne baisse ces opacités qu'en remesurant.

   `.chero .chero__bg` et non `.chero__bg` seul : il faut battre
   `.chero > *` ci-dessus, qui pousserait le calque au-dessus du texte.
   ------------------------------------------------------------ */
.chero .chero__bg {
  position: absolute; inset: 0; z-index: 0;
  opacity: 0; transition: opacity 1400ms var(--ease-out);
  pointer-events: none; overflow: hidden;
}
.chero .chero__bg.is-on { opacity: 1; }
/* .40 → .62. Monter l'opacité en gardant un voile uniforme ne donne rien :
   le voile doit compenser exactement ce que la vidéo apporte, et les deux
   s'annulent. Calculé sur une image blanche, aucun texte ne peut passer
   au-dessus de .68 avec un voile plat.

   Ce qui débloque la situation, c'est de cesser de voiler le cadre entier.
   La navigation occupe les 9 premiers pour cent, le fil d'Ariane de 12 à
   21 %, et le bloc de texte descend de 27 à 92 %. Entre les deux, la bande
   n'a que le fil d'Ariane — auquel on donne son propre fond (voir plus bas).
   Le voile peut alors tomber à .34 dans le tiers supérieur, là où l'image
   est la plus lisible, et se refermer sur le texte en dessous.

   Résultat mesuré, sur le pixel le plus clair de chaque vidéo : titre
   6,19:1, accroche 5,91:1, fiche technique 6,27:1. */
.chero .chero__bg video, .chero .chero__bg img {
  /* .62 → .70, sur demande de Tristan. Remesuré au pire cas (image blanche),
     en interpolant le voile à la position réelle de chaque texte, et l'accroche
     ayant quitté la devanture il reste : navigation 4,87:1, titre 11,9:1,
     intitulés de la fiche 6,5:1, valeurs 14,8:1, prix en mandarine 8,4:1,
     fil d'Ariane sur sa pastille 11,9:1.

     Le plafond est la navigation, qui flotte sur les 5 premiers pour cent où
     le voile ne fait que .45 : à .72 elle tombe à 4,69:1, à .76 elle passe
     sous le seuil AA à 4,35:1. Ne monte pas au-delà sans rassombrir le haut
     du voile — et rassombrir le haut, c'est reperdre l'image. */
  width: 100%; height: 100%; object-fit: cover; opacity: .70;
}
.chero .chero__bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(20,12,9,.46) 0%,    /* la navigation flotte ici */
    rgba(20,12,9,.34) 22%,   /* l'image respire */
    rgba(20,12,9,.40) 30%,
    rgba(20,12,9,.74) 46%,   /* le bloc de texte commence */
    rgba(20,12,9,.88) 72%,
    rgba(20,12,9,.92) 100%);
}
/* Le fil d'Ariane est le plus petit texte de la page (11,5 px) et il est
   posé dans la bande où le voile est désormais le plus fin, pour laisser
   voir l'image. Plutôt que de rassombrir toute cette bande pour lui seul,
   il porte son propre fond : le contraste ne dépend alors plus du tout de
   ce qu'il y a derrière. C'est aussi ce qui autorise la vidéo à .62. */
.chero .crumb {
  color: rgba(252,248,245,.94);
  align-self: flex-start;
  background: rgba(18,11,8,.62);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  padding: 7px 14px; border-radius: var(--r-pill);
  margin-bottom: 0;
}
.chero .crumb a:hover { color: var(--mand); }
.chero .label { color: rgba(247,237,231,.62); }
.chero__title { font-size: clamp(2.3rem, 6vw, 5rem); font-weight: 700; letter-spacing: -.042em; line-height: .96; color: #FBF4EF; }
.chero .lead { color: rgba(247,237,231,.80); }
.chero .btn--ghost { color: #FBF4EF; box-shadow: inset 0 0 0 1.5px rgba(247,237,231,.40); }
.chero .btn--ghost:hover { box-shadow: inset 0 0 0 1.5px var(--mand); color: var(--mand); }

/* ------------------------------------------------------------
   La fiche technique
   Ce qu'un client veut savoir avant tout le reste : ce qu'il
   reçoit, quand, et à partir de combien. Posé comme une fiche
   de tournage — étiquettes en monospace, valeurs en display.
   ------------------------------------------------------------ */
.spec {
  margin-top: clamp(32px, 4vw, 54px);
  padding-top: clamp(20px, 2.4vw, 30px);
  border-top: 1px solid rgba(247,237,231,.18);
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 2.6vw, 44px);
  max-width: 940px;
}
/* .55 tenait 4,82:1 sur les thèmes immobilier et mariage mais tombait à
   4,21:1 sur entreprise, dont le --deep est bleu : à luminance égale, le
   bleu creuse moins l'écart. .64 remonte le pire cas des trois thèmes à
   5,10:1 — la fiche technique du héros reste lisible partout. */
.spec__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .14em; text-transform: uppercase; color: rgba(247,237,231,.64);
}
.spec__v {
  margin-top: 11px; font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1rem, 1.5vw, 1.26rem); letter-spacing: -.026em;
  color: #FBF4EF; line-height: 1.28;
}
/* Le tarif prend l'accent : c'est la ligne qu'on cherche des yeux. */
.spec__v em {
  font-style: normal;
  background: var(--grad-acc);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ------------------------------------------------------------
   Les livrables
   Remplace la numérotation 01→04, qui affirmait une séquence
   là où il n'y en a pas. L'étiquette dit ce qui compte vraiment :
   est-ce compris, ou est-ce une option ?
   ------------------------------------------------------------ */
.delivs { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(16px, 2vw, 26px); }
.deliv {
  background: var(--pane); box-shadow: var(--nm-out-sm);
  border-radius: var(--r-lg); padding: clamp(22px, 2.4vw, 32px);
}
.deliv__tag {
  display: inline-flex; align-items: center;
  /* .75rem (12 px) et non .66rem (10,56 px) : ces étiquettes portent un
     statut commercial, « Compris » ou « En option » — une information
     qu'on doit pouvoir lire, pas un ornement. */
  font-family: var(--font-mono); font-size: .75rem;
  letter-spacing: .1em; text-transform: uppercase;
  padding: 6px 12px; border-radius: var(--r-pill);
}
.deliv__tag--inc { background: var(--grad-acc); color: var(--on-key); font-weight: 500; }
.deliv__tag--opt { color: var(--ink-2); box-shadow: inset 0 0 0 1.5px rgba(190,140,115,.42); }

/* --inc et --opt disent un statut commercial : compris, ou en supplément.
   La variante --cat (un classement : recruter, vendre…) est partie avec les
   étiquettes de la grille « L'objectif », dont le mot ouvre maintenant le
   titre (`.deliv__verbe`, section 48). */
.deliv h3 { margin-top: 17px; font-size: var(--t-h3); }
.deliv p { margin-top: 10px; color: var(--ink-2); font-size: .94rem; }

/* ------------------------------------------------------------
   Passer d'une prestation à l'autre
   Une page métier ne doit pas être un cul-de-sac : le visiteur
   qui s'est trompé de porte doit trouver la bonne sans remonter
   à la navigation. Chaque carte porte l'accent de sa destination.
   ------------------------------------------------------------ */
.xnav { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(14px, 1.8vw, 22px); }
.xnav__i {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: clamp(22px, 2.6vw, 34px);
  background: var(--pane); box-shadow: var(--nm-out-sm); border-radius: var(--r-lg);
  transition: box-shadow 260ms ease, transform 260ms var(--ease);
}
.xnav__i:hover { box-shadow: var(--nm-in); transform: translateY(2px); }
.xnav__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-2);
}
.xnav__t {
  display: block; margin-top: 9px; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.28rem, 2.3vw, 1.85rem); letter-spacing: -.032em; color: var(--ink);
}
.xnav__go {
  width: 46px; height: 46px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--grad-acc); color: var(--on-key);
}

@media (max-width: 860px) {
  .spec { grid-template-columns: 1fr; gap: 0; }
  .spec > div + div {
    margin-top: 18px; padding-top: 18px;
    border-top: 1px solid rgba(247,237,231,.14);
  }
  .delivs, .xnav { grid-template-columns: 1fr; }
}

/* ============================================================
   35. PASSE DE FINITION
   Les surfaces que le navigateur dessine à notre place, la
   robustesse des révélations, et le viseur dans les cadres vides.
   ============================================================ */

/* ------------------------------------------------------------
   35.1  Les surfaces du navigateur
   Sélection, curseur de saisie, barre de défilement, anneau de
   focus, soulignement. Tout ça arrive avec des réglages par
   défaut qui n'appartiennent à aucune charte. C'est le signal
   le moins cher qu'une page a été dessinée et pas assemblée.
   ------------------------------------------------------------ */
/* Encre sombre sur la sélection, pour la même raison que sur les
   boutons : le blanc sur corail ne mesure que 3,10:1. */
::selection { background: var(--coral); color: var(--on-key); }
.hero--dark ::selection, .chero ::selection, .cta--dark ::selection {
  background: var(--mand); color: var(--on-key);
}

/* Le curseur de saisie prend l'accent : on le voit clignoter
   dans les champs du devis, c'est un détail qu'on remarque. */
.input, .textarea, .select { caret-color: var(--coral); }

/* La barre de défilement, teintée dans la palette. */
html {
  scrollbar-width: thin;
  scrollbar-color: rgba(190,140,115,.55) transparent;
}
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(190,140,115,.48);
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: rgba(190,140,115,.72); background-clip: content-box; }

/* L'anneau de focus doit se voir sur le hero sombre COMME sur le
   corps clair. Un anneau d'une seule couleur échoue toujours sur
   l'un des deux — celui d'avant était orange sur des boutons
   orange. Noyau sombre + halo clair : il en reste toujours un
   qui contraste. */
:focus-visible {
  outline: 2.5px solid var(--ink);
  outline-offset: 2px;
  box-shadow: 0 0 0 5.5px rgba(255, 247, 241, .92);
  border-radius: 3px;
}
/* Les bandes sombres de l'accueil (`.chapitre`), le plan-manifeste (`.beat`)
   et les bandes phares des pages métier manquaient à cette liste : l'anneau y
   gardait son noyau sombre, invisible sur le brun, et seul le halo clair
   restait. Même inversion que sur les heros. */
.hero--dark :focus-visible, .chero :focus-visible, .cta--dark :focus-visible,
.chapitre :focus-visible, .beat :focus-visible, .phare :focus-visible {
  outline-color: #FFF7F1;
  box-shadow: 0 0 0 5.5px rgba(26, 16, 11, .92);
}

a { text-underline-offset: 0.22em; text-decoration-thickness: 1.5px; }

/* Les chiffres qui se comparent s'alignent en colonne. */
.spec__v, .trust__k, .recap dd, .gal__cap {
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
   35.2  La page reste lisible si le JavaScript tombe
   [data-reveal] posait opacity:0 en dur : un motion.js qui
   n'arrive pas, et le site entier devenait invisible. On ne
   masque plus que si le script a confirmé sa présence.
   ------------------------------------------------------------ */
[data-reveal], [data-motion="focus"], [data-motion="develop"] > * {
  opacity: 1;
}
[data-motion="mask"] .ln { transform: none; }

/* `:not(.is-in)` n'est pas cosmétique : sans lui ces règles ont la même
   spécificité que `[data-reveal].is-in` et, posées plus bas, elles la
   battent — les éléments ne redeviennent jamais visibles. On ne masque
   donc que ce qui n'a pas encore été révélé. */
.js-motion [data-reveal]:not(.is-in) { opacity: 0; }
.js-motion [data-motion="focus"]:not(.is-in) { opacity: 0; }
.js-motion [data-motion="develop"]:not(.is-in) > * { opacity: 0; }
.js-motion [data-motion="mask"]:not(.is-in) .ln { transform: translateY(106%); }

/* --- Geste 7 : L'OBTURATEUR. L'image s'ouvre depuis la couture qu'elle
       partage avec le panneau sombre, comme un obturateur qui s'ouvre sur
       le noir ; le filet d'accent se trace, puis le texte fait sa mise au
       point. ---

   Les bandes de l'accueil et les temps du récit des pages métier ont la
   même composition — image et panneau accolés — et ils entraient comme
   tout le reste du site : le même fondu-montée de 18 px, répété une
   trentaine de fois par page. Un mouvement répété partout ne dit plus
   rien. Celui-ci est réservé à cette composition, et il la raconte :
   l'image naît du panneau, pas du vide.

   Une fois par bloc, 1,1 s au plus. `clip-path` et un flou limité au bloc
   de texte. Conditionné à `.js-motion` comme les six autres gestes : sans
   JavaScript ou en mouvement réduit, tout est visible d'emblée. */
[data-motion="obturateur"] .recit__m,
[data-motion="obturateur"] .bande__m {
  clip-path: inset(0);
  /* 620 ms et non 850 : le geste doit être fini quand l'œil arrive sur le
     bloc, pas se dérouler pendant la lecture (retard signalé par Tristan). */
  transition: clip-path 620ms cubic-bezier(.16, 1, .3, 1);
}
/* Image à gauche : la couture est à son bord droit, l'image s'ouvre de là. */
.js-motion [data-motion="obturateur"]:not(.is-in) .recit__m,
.js-motion [data-motion="obturateur"]:not(.is-in) .bande__m { clip-path: inset(0 0 0 100%); }
/* Image à droite : la couture est à son bord gauche. */
.js-motion .recit__t--inv[data-motion="obturateur"]:not(.is-in) .recit__m,
.js-motion .bande--deux[data-motion="obturateur"]:not(.is-in) .bande__m { clip-path: inset(0 100% 0 0); }
/* Empilé, l'image est au-dessus du panneau : la couture est à son bord bas.
   Les deux composants ne s'empilent pas au même seuil (899 et 900 px). */
@media (max-width: 899px) {
  .js-motion [data-motion="obturateur"]:not(.is-in) .recit__m,
  .js-motion .recit__t--inv[data-motion="obturateur"]:not(.is-in) .recit__m { clip-path: inset(100% 0 0 0); }
}
@media (max-width: 900px) {
  .js-motion [data-motion="obturateur"]:not(.is-in) .bande__m,
  .js-motion .bande--deux[data-motion="obturateur"]:not(.is-in) .bande__m { clip-path: inset(100% 0 0 0); }
}

/* Le filet d'accent se trace de gauche à droite, juste après l'ouverture. */
[data-motion="obturateur"] .recit__c::before,
.bande[data-motion="obturateur"]::before {
  transform-origin: 0 50%;
  transition: transform 560ms cubic-bezier(.16, 1, .3, 1) 60ms;
}
.js-motion [data-motion="obturateur"]:not(.is-in) .recit__c::before,
.js-motion .bande[data-motion="obturateur"]:not(.is-in)::before { transform: scaleX(0); }

/* Le texte fait sa mise au point, élément par élément. `color` et
   `border-color` restent dans la liste, sans délai : sans elles, cette règle
   écraserait la transition de survol de « Voir la prestation ». */
[data-motion="obturateur"] :is(.recit__c, .bande__c) > * {
  transition-property: opacity, filter, color, border-color;
  transition-duration: 480ms, 480ms, 300ms, 300ms;
  transition-timing-function: ease, cubic-bezier(.16, 1, .3, 1), ease, ease;
  transition-delay: calc(120ms + var(--o, 0) * 50ms), calc(120ms + var(--o, 0) * 50ms), 0ms, 0ms;
}
:is(.recit__c, .bande__c) > :nth-child(2) { --o: 1; }
:is(.recit__c, .bande__c) > :nth-child(3) { --o: 2; }
:is(.recit__c, .bande__c) > :nth-child(4) { --o: 3; }
:is(.recit__c, .bande__c) > :nth-child(n+5) { --o: 4; }
.js-motion [data-motion="obturateur"]:not(.is-in) :is(.recit__c, .bande__c) > * { opacity: 0; filter: blur(6px); }

@media (prefers-reduced-motion: reduce) {
  [data-motion="obturateur"] .recit__m, [data-motion="obturateur"] .bande__m,
  [data-motion="obturateur"] .recit__c::before, .bande[data-motion="obturateur"]::before,
  [data-motion="obturateur"] :is(.recit__c, .bande__c) > * { transition: none; }
}

/* ------------------------------------------------------------
   35.3  Le viseur
   Tant qu'il n'y a pas d'image, le cadre vide se lit comme un
   cadre de viseur : repères aux quatre coins et annotation
   technique. Un emplacement en attente devient une intention
   de cadrage — c'est le seul endroit du site où l'absence
   d'images travaille pour nous.
   ------------------------------------------------------------ */
.ph { --mark: rgba(190,140,115,.62); overflow: hidden; }
.ph::before {
  content: ''; position: absolute; inset: clamp(12px, 1.4vw, 20px);
  pointer-events: none;
  background:
    linear-gradient(var(--mark), var(--mark)) 0    0    / 15px 1.5px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 0    0    / 1.5px 15px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 0    / 15px 1.5px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 0    / 1.5px 15px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 0    100% / 15px 1.5px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 0    100% / 1.5px 15px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 100% / 15px 1.5px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 100% / 1.5px 15px no-repeat;
}
.ph__t {
  font-size: .66rem; letter-spacing: .18em;
  color: var(--coral-ink); font-weight: 500;
}
.ph__d { color: var(--ink-2); max-width: 32ch; }

/* ------------------------------------------------------------
   35.4  Le prix se lit avant de décorer
   Le dégradé sur du texte coûte du contraste, et un tarif est
   la ligne qu'on cherche des yeux. Aplat plein, tabulaire.
   Le titre du hero garde son dégradé : c'est la signature.
   ------------------------------------------------------------ */
.spec__v em {
  background: none; -webkit-background-clip: border-box; background-clip: border-box;
  color: var(--mand);
}

/* ------------------------------------------------------------
   35.5  La durée dit la distance parcourue
   L'ouverture du hero est le moment auteur du site : elle a le
   droit d'être longue. Les titres de section sont une arrivée
   de routine et se posaient en presque une seconde — on divise.
   ------------------------------------------------------------ */
.section [data-motion="mask"] .ln,
.section--tight [data-motion="mask"] .ln {
  transition-duration: 620ms;
  transition-delay: calc(var(--i, 0) * 70ms);
}

/* ============================================================
   36. LA BANDE SOMBRE
   Le corps du site était une seule nappe claire du haut en bas :
   la descente n'avait aucun battement. Une bande sombre en plein
   cadre au milieu de la page rétablit la respiration —
   sombre (hero) → clair → SOMBRE → clair → sombre (devis).
   C'est aussi le bon fond pour des images : une galerie se
   regarde sur du noir, pas sur de la crème.
   ============================================================ */
.band {
  position: relative;
  background:
    radial-gradient(100% 80% at 74% 8%, #2E1A12 0%, transparent 62%),
    linear-gradient(168deg, #1B120D 0%, #251710 58%, #170F0B 100%);
  color: #F7EDE7;
  padding-block: clamp(56px, 7vw, 108px);
  margin-block: clamp(40px, 5vw, 78px);
}
/* Le même grain que le hero, pour que les trois surfaces sombres
   du site appartiennent visiblement à la même matière. */
.band::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .05;
  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='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.band > * { position: relative; z-index: 2; }
.band .label { color: rgba(247,237,231,.62); }
.band h2 { color: #FBF4EF; }
.band .gal__cap { color: rgba(247,237,231,.60); }

/* Les cadres s'inversent : creusés dans du sombre, repères clairs.
   C'est là que le viseur prend enfin l'air d'un viseur. */
.band .shot, .band .ph {
  background: rgba(255,247,241,.035);
  box-shadow: inset 3px 3px 12px rgba(0,0,0,.5),
              inset -2px -2px 10px rgba(255,247,241,.05);
}
.band .ph { --mark: rgba(247,237,231,.46); }
.band .ph__t { color: var(--mand); }
.band .ph__d { color: rgba(247,237,231,.66); }

/* ============================================================
   37. ADAPTATION AU TACTILE ET AUX PETITS ÉCRANS
   ============================================================ */

/* ------------------------------------------------------------
   37.1  `hidden` doit vraiment cacher
   `.btn { display: inline-flex }` est une règle d'auteur : elle
   bat le `display: none` que le navigateur applique à [hidden].
   Résultat, « Envoyer ma demande » restait visible dès l'étape 1,
   à côté de « Continuer » — et c'est ce troisième bouton qui
   faisait déborder la page de devis en mobile.
   ------------------------------------------------------------ */
[hidden] { display: none !important; }

/* ------------------------------------------------------------
   37.2  La navigation du formulaire
   Sous 560 px, les boutons passent en colonne et l'action
   principale prend toute la largeur. `column-reverse` la remonte
   au-dessus de « Retour » : c'est elle qu'on cherche du pouce.
   ------------------------------------------------------------ */
@media (max-width: 560px) {
  .fnav { flex-direction: column-reverse; gap: 10px; }
  .fnav .btn { width: 100%; justify-content: center; }
  /* « Retour » est caché par visibility à la première étape :
     en colonne, il laisserait un trou. On le retire du flux. */
  .fnav .btn[style*="hidden"] { display: none; }
}

/* ------------------------------------------------------------
   37.3  Les cibles tactiles
   Conditionné au type de pointeur, pas à la largeur d'écran :
   un portable tactile a un grand écran et des gros doigts.
   Seuil de 44 px, celui des recommandations WCAG 2.5.5.
   ------------------------------------------------------------ */
@media (pointer: coarse) {
  .foot a, .crumb a, .nav__link, .tlink, .gal__cap a, .wordmark, .nav__tel, .jump a {
    align-items: center; min-height: 44px;
  }
  .foot a, .crumb a, .nav__link, .tlink, .gal__cap a, .jump a { display: inline-flex; }
  .foot li + li { margin-top: 2px; }   /* la hauteur de cible remplace l'écart */
  .burger { width: 46px; height: 46px; flex-shrink: 0; }
  .chip { padding: 8px 12px; }
  /* Le survol n'existe pas au doigt : l'aperçu vidéo des cases
     métier ne se déclenchera jamais. On rend l'état au repos
     lisible plutôt que d'attendre un geste impossible. */
}

/* ------------------------------------------------------------
   37.4  Les encoches et les coins arrondis
   Sans ça, le contenu passe sous l'encoche en paysage et sous
   la barre de geste en portrait.
   ------------------------------------------------------------ */
@supports (padding: env(safe-area-inset-left)) {
  .wrap, .nav__inner, .menu {
    padding-left: max(var(--page-x), env(safe-area-inset-left));
    padding-right: max(var(--page-x), env(safe-area-inset-right));
  }
  .foot__bottom { padding-bottom: env(safe-area-inset-bottom); }
}

/* ============================================================
   38. ROBUSTESSE DU FORMULAIRE
   ============================================================ */

/* ------------------------------------------------------------
   38.1  Le plancher de 16 px dans les champs
   Safari iOS zoome de force sur un champ dont le texte fait moins
   de 16 px, et la mise en page saute. Le corps du site est à
   15,68 px : il s'en fallait de peu, mais ça suffisait.
   ------------------------------------------------------------ */
.input, .select, .textarea { font-size: max(1rem, 16px); }

/* ------------------------------------------------------------
   38.2  Le texte long ne casse rien
   Une ville sans espace, une URL collée, un mot allemand : sans
   ça, le champ ou le récapitulatif déborde de sa boîte.
   ------------------------------------------------------------ */
.recap dd, .err, .hint, .choice__d { overflow-wrap: anywhere; }

/* ------------------------------------------------------------
   37.6  La barre d'action mobile
   L'accueil fait 10 072 px à 375 px de large, et entre la fin du
   hero et le bloc de clôture il n'y avait aucun bouton d'accent à
   l'écran : environ 9 000 px pendant lesquels un visiteur convaincu
   n'avait rien à toucher. Le CTA vivait dans `.nav__links`, masqué
   sous 860 px, et le menu le rendait comme un lien ordinaire parmi
   cinq lignes identiques.

   Elle ne s'affiche que quand aucun autre appel n'est visible :
   `main.js` observe le hero et le bloc de clôture et pose
   `is-up` seulement entre les deux. Doubler un CTA déjà à l'écran
   serait du bruit, pas de la conversion.

   Volontairement sobre : le site a déjà sa signature — les cadres
   traités en viseur. Une seconde signature la diluerait. Ici, c'est
   le bouton d'accent qui porte, et rien d'autre.
   ------------------------------------------------------------ */
.actionbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 149;
  display: none; align-items: center; gap: 10px;
  padding: 10px var(--page-x) calc(10px + env(safe-area-inset-bottom));
  background: rgba(26,16,11,.92);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 -1px 0 rgba(247,237,231,.14);
  transform: translateY(100%);
  transition: transform 260ms var(--ease-out);
}
.actionbar.is-up { transform: translateY(0); }
.actionbar .btn { flex: 1; justify-content: center; }
.actionbar__tel {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; flex-shrink: 0;
  border-radius: var(--r-pill); color: #FBF4EF;
  box-shadow: inset 0 0 0 1.5px rgba(247,237,231,.34);
}
@media (max-width: 860px) {
  .actionbar { display: flex; }
  /* La barre est fixe : sans cette réserve elle recouvrait les 45 derniers
     pixels du pied de page — mesuré. On rend au document la hauteur qu'on
     lui prend. */
  .foot { padding-bottom: calc(84px + env(safe-area-inset-bottom)); }
}
@media (prefers-reduced-motion: reduce) {
  .actionbar { transition: none; }
}

/* La sortie de secours du formulaire : deux vraies cibles cliquables sous
   le message d'échec, pas une adresse à recopier. C'est la dernière chose
   que voit un prospect quand l'envoi ne passe pas — elle doit se toucher. */
.err__sortie {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px;
  margin-top: 12px;
}
.err__sortie a {
  font-weight: 600; text-decoration: underline;
  text-underline-offset: .22em; text-decoration-thickness: 1.5px;
}
@media (pointer: coarse) {
  .err__sortie a { display: inline-flex; align-items: center; min-height: 44px; }
}
.recap { max-width: 100%; }
.recap dl { grid-template-columns: minmax(0, auto) minmax(0, 1fr); }

/* ------------------------------------------------------------
   38.3  L'envoi en cours
   Le bouton reste lisible pendant la requête et ne peut pas
   être cliqué deux fois.
   ------------------------------------------------------------ */
.btn[disabled] { opacity: .62; cursor: progress; }
.btn[aria-busy="true"] svg { animation: pulse 1.1s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .btn[aria-busy="true"] svg { animation: none; opacity: .5; }
}

/* Le message d'erreur global reçoit le focus : il ne doit pas
   afficher d'anneau alors qu'il n'est pas interactif, mais il
   doit rester repérable. */
.err[data-err="_form"]:focus-visible { outline-offset: 6px; }

/* ============================================================
   39. LES RÉGLAGES QUE LE NAVIGATEUR DÉCIDE SEUL
   Revue « Web Interface Guidelines » : chacun de ces réglages a
   une valeur par défaut qui n'appartient à aucune charte.
   ============================================================ */

/* Le thème des contrôles natifs. Le site est clair, avec des
   sections sombres qui ne contiennent aucun champ : on le déclare,
   sinon un navigateur en mode sombre inverse les listes et les
   cases à cocher de son propre chef. */
:root { color-scheme: light; }

/* Certains navigateurs mobiles attendent 300 ms après un appui pour
   savoir si un second va suivre. On leur dit qu'aucun double-tap
   n'est attendu : les boutons répondent au premier contact. */
a, button, summary, label, .choice__box, [role="button"] {
  touch-action: manipulation;
}

/* Le halo au doigt était le gris-bleu par défaut d'Android.
   On le met dans la palette, très discret. */
html { -webkit-tap-highlight-color: rgba(255, 90, 60, .14); }

/* Le menu plein écran ne propage plus son défilement à la page
   qui se trouve derrière lui. */
.menu { overscroll-behavior: contain; }

/* ============================================================
   40. CORRECTIFS DE LA CRITIQUE UX
   ============================================================ */

/* ------------------------------------------------------------
   40.1  Un chemin direct pour appeler
   Un agent immobilier décroche son téléphone, il ne remplit pas
   quatre étapes. L'icône reste discrète ; le numéro se déplie au
   survol sur bureau et l'appel part au premier appui sur mobile.
   ------------------------------------------------------------ */
.nav__tel {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 9px 12px; border-radius: var(--r-pill);
  color: var(--ink-2); font-size: .88rem;
  box-shadow: inset 0 0 0 1.5px transparent;
  transition: color 200ms ease, box-shadow 200ms ease;
}
.nav__tel svg { flex-shrink: 0; }
/* Exception assumée : animer max-width provoque un recalcul de mise en page
   à chaque image, ce que le détecteur d'impeccable signale à juste titre.
   Aucun transform ne peut le remplacer ici — le numéro doit réellement
   pousser ses voisins en se dépliant, c'est tout l'effet. Le coût reste
   contenu : un seul élément, au survol, et jamais au doigt puisque
   `pointer: coarse` le laisse déplié en permanence (voir plus bas). */
.nav__tel span {
  max-width: 0; overflow: hidden; white-space: nowrap;
  opacity: 0; font-variant-numeric: tabular-nums;
  /* Exception assumée : un seul élément, au survol, jamais au doigt. Animer
     `transform` obligerait à réserver la largeur du numéro en permanence, et
     c'est précisément ce qu'on veut éviter. Consigné dans CLAUDE.md. */
  /* impeccable-disable-next-line layout-transition */
  transition: max-width 320ms var(--ease), opacity 200ms ease;
}
.nav__tel:hover, .nav__tel:focus-visible { color: var(--coral-ink); }
.nav__tel:hover span, .nav__tel:focus-visible span { max-width: 11ch; opacity: 1; }
[data-hero="dark"] .nav:not(.nav--solid) .nav__tel { color: rgba(251,244,239,.82); }
[data-hero="dark"] .nav:not(.nav--solid) .nav__tel:hover { color: var(--mand); }

/* Au doigt, le survol n'existe pas : le numéro est déplié d'office. */
@media (pointer: coarse) {
  .nav__tel span { max-width: 11ch; opacity: 1; }
  .nav__tel { box-shadow: inset 0 0 0 1.5px rgba(190,140,115,.34); }
}
/* Le lien vit dans .nav__inner, PAS dans .nav__links : ce dernier passe
   en display:none sous 860 px, et un enfant d'un parent masqué ne peut
   jamais s'afficher. C'est ce qui le rend présent à toutes les largeurs. */
@media (max-width: 860px) {
  .nav__tel { margin-left: auto; margin-right: 6px; }
}

/* 40.2 traitait les cases métier au doigt. Elles n'existent plus : les
   trois bandes portent désormais leur propre signal, et `.bande__go` est
   visible à toutes les largeurs sans dépendre du survol. */

/* ------------------------------------------------------------
   40.3  Le récapitulatif se corrige sur place
   Relire ses réponses sans pouvoir les changer est une impasse.
   ------------------------------------------------------------ */
.recap dd { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.recap__edit {
  flex-shrink: 0; font-family: var(--font-mono);
  font-size: .68rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--coral-ink); font-weight: 400;
  box-shadow: 0 1px 0 currentColor;
  transition: opacity 180ms ease;
}
.recap__edit:hover { opacity: .68; }
@media (pointer: coarse) { .recap__edit { padding-block: 12px; } }

/* ============================================================
   41. LES SOUS-PARTIES SE VOIENT
   Tristan : « sépare les sous-parties par des traits ». Un filet nu
   sépare mais n'informe pas. Celui-ci porte le nom de la partie et
   file jusqu'au bord : il divise, il annonce, et il donne à l'œil
   un rail horizontal à chaque étage — c'est ce qui remplace la
   descente uniforme d'une page en colonne unique.

   Le vocabulaire vient d'une feuille de service : une ligne, un
   intitulé en capitales étroites. Pas de numéro — la numérotation
   01→04 reste réservée à la Méthode de l'accueil, qui est une vraie
   séquence, et la répéter ailleurs lui ferait perdre son sens.
   ============================================================ */
.chap {
  display: flex; align-items: center; gap: clamp(14px, 1.8vw, 22px);
  margin-bottom: clamp(26px, 3.2vw, 44px);
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-2);
}
.chap::after {
  content: ''; flex: 1 1 auto; height: 2px;
  border-radius: 2px; box-shadow: var(--nm-in-sm);
}
/* Sur fond sombre le relief creusé disparaît : on repasse au filet. */
.hero--dark .chap, .chero .chap, .cta--dark .chap { color: rgba(247,237,231,.66); }
.hero--dark .chap::after, .chero .chap::after, .cta--dark .chap::after {
  box-shadow: none; background: rgba(247,237,231,.22);
}

/* ============================================================
   42. L'OFFRE RÉCURRENTE
   Elle était traitée comme une section de texte parmi d'autres, avec
   un lien en fin de paragraphe. C'est pourtant la seule proposition
   du site qui s'adresse à un client qui revient — donc la seule qui
   change un chiffre d'affaires. Elle reçoit sa propre surface, un
   liseré d'accent sur le flanc, et un vrai bouton.
   ============================================================ */
.offer {
  position: relative; overflow: hidden;
  background: var(--pane); box-shadow: var(--nm-out);
  border-radius: var(--r-lg);
  padding: clamp(26px, 3.4vw, 48px);
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(24px, 3.4vw, 56px); align-items: center;
}
/* Premier essai : un liseré d'accent de 4 px collé au bord gauche. Le
   détecteur l'a relevé, et il a raison — la bande de couleur sur le flanc
   d'une carte est le tic le plus reconnaissable des interfaces générées.
   Elle est remplacée par la signature du site : les repères de viseur des
   cadres de galerie, repris ici en accent. Le bloc se lit comme un cadrage,
   ce qui appartient à ce site et à aucun autre. */
.offer::before {
  content: ''; position: absolute; inset: clamp(11px, 1.2vw, 17px);
  pointer-events: none; --mark: var(--coral);
  background:
    linear-gradient(var(--mark), var(--mark)) 0    0    / 20px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 0    0    / 2px 20px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 0    / 20px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 0    / 2px 20px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 0    100% / 20px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 0    100% / 2px 20px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 100% / 20px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) 100% 100% / 2px 20px no-repeat;
}
.offer__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .12em; text-transform: uppercase; color: var(--coral-ink);
}
.offer__t {
  font-family: var(--font-display); font-size: var(--t-h3);
  font-weight: 600; letter-spacing: -.02em; margin-top: 10px;
}
.offer p { color: var(--ink-2); margin-top: 12px; max-width: 56ch; }
.offer__pts { display: grid; gap: 12px; }
.offer__pts li {
  position: relative; padding-left: 22px;
  font-size: .95rem; color: var(--ink-1);
}
.offer__pts li::before {
  content: ''; position: absolute; left: 0; top: .5em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--grad-acc);
}
.offer .btn { margin-top: clamp(18px, 2.2vw, 26px); }
@media (max-width: 860px) {
  .offer { grid-template-columns: 1fr; }
}
/* ============================================================
   43. LES VIDES QUI NE SERVENT À RIEN
   Tristan : « ça ne sert à rien de laisser des gros espaces dans
   lesquels rien ne se passe ». Le cas le plus net est la page de
   devis : le bas de la page-titre (56 px) et le haut de la section
   suivante (148 px) s'additionnaient en 204 px de rien entre
   « Demander un devis. » et la première question. Sur une page où
   le visiteur vient remplir un formulaire, cette bande le fait
   défiler avant de commencer.

   La règle vaut partout où une page-titre est suivie d'une section :
   c'est la page-titre qui porte déjà l'air du haut, la section n'a
   pas à le redonner.
   ============================================================ */
.phero + .section,
.phero + .section--tight { padding-top: clamp(26px, 3vw, 52px); }

/* Une section qui prolonge la précédente au lieu d'en ouvrir une nouvelle.
   Mesuré sur les trois pages métier : cinq sections successives portaient le
   même rembourrage de 86 px en haut et en bas, soit 172 px entre chaque bloc,
   qu'ils soient liés ou non. « Qui filme » et « Ce qui est déjà réglé » disent
   tous deux la confiance, et étaient aussi loin l'un de l'autre que la FAQ ;
   les livrables, qui concluent le récit, en étaient séparés par le plus grand
   écart de la page (216 px). Le rythme vient maintenant du contraste : serré
   à l'intérieur d'un groupe, généreux entre deux groupes. */
.section--suite { padding-top: clamp(10px, 1.4vw, 20px); }
/* Les blocs d'une page de texte long se séparent par un filet gravé.
   Utilisé par les mentions légales, où six sections se suivaient sans
   rien entre elles. */
.stack-l--divise > * + * {
  padding-top: clamp(26px, 3vw, 40px);
  position: relative;
}
.stack-l--divise > * + *::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0;
  height: 2px; border-radius: 2px; box-shadow: var(--nm-in-sm);
}
/* ============================================================
   44. LES MOUVEMENTS
   Une page ne doit pas être une colonne de texte ponctuée d'images :
   elle doit alterner. Ces deux blocs remplacent la plus longue zone
   morte de l'accueil — 1,7 écran de texte nu, mesuré, juste après le
   hero. Ils ne suppriment pas l'argument, ils le font tenir en une
   ligne et le posent sur un plan qui le prouve.
   ============================================================ */

/* ------------------------------------------------------------
   44.1  Le plan-manifeste
   Même mécanique que le hero : fond vidéo optionnel, affiche en
   substitut, voile dimensionné pour une image blanche. Le titre
   s'assied en bas à gauche, les annotations tiennent la marge
   droite — le regard traverse au lieu de descendre.
   ------------------------------------------------------------ */
.beat {
  position: relative; overflow: hidden;
  min-height: 88svh; display: flex; align-items: flex-end;
  padding-block: clamp(56px, 8vw, 120px);
  background:
    radial-gradient(120% 90% at 76% 18%, #35241B 0%, transparent 56%),
    linear-gradient(168deg, #17100C 0%, #2C1D14 56%, #130D0A 100%);
  color: #F7EDE7;
}
.beat__bg {
  position: absolute; inset: 0; z-index: 0;
  opacity: 0; transition: opacity 1400ms var(--ease-out);
  pointer-events: none; overflow: hidden;
}
.beat__bg.is-on { opacity: 1; }
/* .80 et non .58. Le raisonnement du hero ne s'applique pas ici : le plan
   du hero est un montage clair, celui-ci est un contre-jour déjà sombre.
   Le voiler comme s'il était clair l'éteignait complètement — on ne voyait
   plus le sujet. Et surtout le texte de cette section tient dans le quart
   bas, là où le voile monte à .82. La navigation, elle, est déjà opaque
   quand on arrive ici : le haut du cadre n'a aucun texte à protéger et
   peut donc rester presque nu. */
.beat__bg video, .beat__bg img {
  width: 100%; height: 100%; object-fit: cover; opacity: .80;
}
/* Le voile ne protège que le bas-gauche, et c'est délibéré : son dégradé
   vertical est mince en haut, son radial est centré sous le titre.
   Mesuré sur la boucle entière : composite sous le titre à 0,024 de
   luminance, soit 13,09:1 pour le titre et 11,40:1 pour l'accroche.

   ⚠️ Ce commentaire annonçait aussi « plus de 9:1 » pour les annotations.
   C'était faux : la mesure avait été prise sous le titre, pas dans leur
   colonne, où le plan monte à 0,799 et où elles tombaient à 3,12:1. Elles
   ne dépendent plus de ce voile — elles portent leur propre fond, voir
   `.notes`. Ne t'appuie pas sur ce dégradé pour du texte à droite. */
.beat__bg::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(180deg,
      rgba(18,11,8,.24) 0%,
      rgba(18,11,8,.14) 28%,
      rgba(18,11,8,.44) 54%,
      rgba(18,11,8,.82) 78%,
      rgba(18,11,8,.92) 100%),
    radial-gradient(76% 56% at 16% 88%, rgba(18,11,8,.56), transparent 74%);
}
.beat__inner {
  position: relative; z-index: 2; width: 100%;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: end; column-gap: clamp(32px, 6vw, 110px);
}
.beat__t {
  font-family: var(--font-display);
  font-size: clamp(2rem, 4.4vw, 3.9rem);
  font-weight: 600; letter-spacing: -.038em; line-height: 1.02;
  color: #FBF4EF; margin-top: clamp(16px, 2vw, 26px);
}
.beat__l {
  margin-top: clamp(16px, 1.8vw, 24px);
  max-width: 46ch; font-size: var(--t-lead); line-height: 1.5;
  color: rgba(247,237,231,.86);
}
.chap--sombre { color: rgba(247,237,231,.66); }
.chap--sombre::after { box-shadow: none; background: rgba(247,237,231,.22); }

/* Les annotations portent leur propre fond.

   Mesuré sur la boucle entière, image par image : dans le rectangle
   qu'occupe cette colonne, le plan monte à 0,799 de luminance — une
   fenêtre en plein jour. Le voile, lui, ne protège que le bas-gauche :
   son dégradé vertical est mince à cette hauteur et son radial est centré
   sur le titre. Résultat, les intitulés tombaient à 3,86:1 et les
   descriptions à 3,12:1, sous le seuil AA.

   Le commentaire du voile, plus haut, certifiait « plus de 9:1 » pour ces
   annotations. Cette valeur avait été relevée sous le titre, pas ici.

   Rassombrir le voile n'était pas la réponse : le plan est déjà un
   contre-jour, et l'éteindre davantage ferait disparaître le sujet qui
   prouve l'argument. C'est le procédé du fil d'Ariane des devantures qui
   s'applique — le texte pose sa propre surface, et son contraste cesse de
   dépendre de ce qui passe derrière. Il tiendra donc aussi si Tristan
   remplace un jour ce plan par un plus clair.

   Pas de `backdrop-filter` : le flou ne change pas la luminance moyenne,
   donc il n'apporterait rien au contraste, et un panneau de verre décoratif
   n'a pas sa place dans cette direction. C'est l'opacité qui travaille. */
/* .74 et non .62 : mesuré, le haut de la colonne atteint une zone où le
   voile ne vaut que 0,358, donc le fond derrière le panneau y monte à
   0,4125 de luminance. À .62 les descriptions plafonnaient à 3,68:1.
   Ne descends pas cette valeur sans remesurer sur la boucle entière —
   c'est l'image la plus claire des seize qui commande, pas la première. */
.notes {
  background: rgba(14, 9, 7, .74);
  border-radius: var(--r);
  padding: clamp(18px, 2vw, 26px);
  box-shadow: inset 0 0 0 1px rgba(247, 237, 231, .10);
}

/* Le carré d'accent remplace la puce ronde — c'est un repère de cadre,
   pas une liste à courses. */
.notes { display: grid; gap: clamp(16px, 2vw, 26px); max-width: 30ch; }
.notes li { position: relative; padding-left: 20px; }
.notes li::before {
  content: ''; position: absolute; left: 0; top: .42em;
  width: 7px; height: 7px; background: var(--mand);
}
.notes b {
  display: block; font-family: var(--font-mono); font-weight: 400;
  font-size: var(--t-label); letter-spacing: .1em; text-transform: uppercase;
  color: #FBF4EF;
}
.notes span {
  display: block; margin-top: 6px;
  /* .80 et non .74 : à .92 rem on est en texte normal, donc au seuil de
     4,5:1 et non de 3:1. Les deux crans — le panneau et cette encre — sont
     nécessaires ensemble. */
  font-size: .92rem; line-height: 1.45; color: rgba(247,237,231,.80);
}

@media (max-width: 900px) {
  .beat { min-height: 0; }
  .beat__inner { grid-template-columns: 1fr; row-gap: clamp(34px, 6vw, 48px); }
  .notes { max-width: none; }
}

/* ------------------------------------------------------------
   44.2  Le diptyque
   Deux panneaux qui se touchent, pas deux cartes espacées : c'est
   une comparaison, et la comparaison a besoin que les deux images
   partagent une arête. Au survol, l'image avance et son voile
   s'allège — transform et opacity seulement.
   ------------------------------------------------------------ */
.halves { display: grid; grid-template-columns: 1fr 1fr; }
.half {
  position: relative; overflow: hidden;
  min-height: clamp(340px, 62svh, 620px);
  display: flex; align-items: flex-end;
  background: var(--deep, #17100C);
}
.half__m { position: absolute; inset: 0; z-index: 0; }
.half__m img, .half__m video {
  width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.02);
  transition: transform 900ms var(--ease-out);
}
.half::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(16,10,7,.30) 0%, rgba(16,10,7,.46) 46%, rgba(16,10,7,.86) 100%);
  transition: opacity 700ms var(--ease-out);
}
.half__c {
  position: relative; z-index: 2; width: 100%;
  padding: clamp(22px, 3vw, 44px);
  color: #FBF4EF;
}
.half__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--mand);
}
.half__t {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 2.5vw, 2.1rem);
  font-weight: 600; letter-spacing: -.03em; margin-top: 10px;
  transition: transform 700ms var(--ease-out);
}
.half__d {
  margin-top: 10px; max-width: 34ch;
  font-size: .95rem; line-height: 1.5; color: rgba(247,237,231,.82);
}
/* Un filet clair sépare les deux panneaux : sans lui, deux images
   sombres côte à côte se lisent comme une seule image coupée. */
.halves > .half + .half { box-shadow: inset 1px 0 0 rgba(247,237,231,.16); }

@media (hover: hover) and (pointer: fine) {
  .half:hover .half__m img, .half:hover .half__m video { transform: scale(1.07); }
  .half:hover::after { opacity: .72; }
  .half:hover .half__t { transform: translateY(-3px); }
}

@media (max-width: 760px) {
  .halves { grid-template-columns: 1fr; }
  .half { min-height: clamp(280px, 46svh, 420px); }
  .halves > .half + .half { box-shadow: inset 0 1px 0 rgba(247,237,231,.16); }
}
/* Au doigt le survol n'existe pas : on montre l'état clair d'emblée
   plutôt que d'attendre un geste impossible. */
@media (pointer: coarse) {
  .half::after { opacity: .8; }
}
/* La boucle du panneau se comporte comme celle d'un cadre : elle se
   fond par-dessus la photo, qui en est l'image zéro. */
.half__m video {
  position: absolute; inset: 0;
  opacity: 0; transition: opacity 420ms ease, transform 900ms var(--ease-out);
}
.half__m.is-playing video { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .half__m img, .half__m video, .half__t { transition: none; }
}
/* ============================================================
   45. LE CHAPITRE SOMBRE
   « Trois façons de travailler ensemble » se noyait : trois papiers
   clairs sur un papier clair. Le contraste ne peut pas venir d'une
   nuance de rose contre une nuance de crème. Il vient du noir.

   Le chapitre rend aussi à la descente le battement clair/sombre que
   la suppression de la galerie lui avait retiré, et sa lisière est
   assez franche pour tirer l'œil vers le bas sans qu'aucune flèche
   ait à le demander.
   ============================================================ */
/* Le chapitre retrouve un fond sombre, mais pas celui des bandes.

   Deux états l'ont précédé, et Tristan a écarté les deux. Soudées dans un
   même aplat, les trois bandes faisaient une dalle de 2,16 écrans qu'on
   traversait sans les compter. Posées sur le papier clair, elles étaient
   séparées par des lignes crème qui coupaient trois fois le sombre :
   « je n'aime pas les lignes blanches ; aérer, oui, mais avec des couleurs
   similaires ».

   La réponse tient entre les deux : un brun plus chaud et un cran plus
   clair que les bandes. Les 46 px qui les séparent restent, mais ils sont
   pris dans la même famille de couleur — l'œil compte trois bandes sans
   qu'un changement de matière vienne le heurter. Et la devanture au-dessus
   étant sombre elle aussi, la ligne claire qui la séparait du titre du
   chapitre disparaît du même geste. Le titre repasse en encre claire. */
.chapitre {
  position: relative; overflow: hidden;
  padding-block: clamp(50px, 6.2vw, 104px);
  color: #F7EDE7;
  background:
    radial-gradient(120% 70% at 18% 0%, #3F2E23 0%, transparent 62%),
    linear-gradient(180deg, #31241C 0%, #2A1F18 55%, #31241C 100%);
}
/* Le grain : la même trame que le hero. Sans elle, un aplat sombre
   aussi large se lit comme du vide, pas comme une matière. */
.chapitre::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .05;
  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='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.chapitre > * { position: relative; z-index: 2; }
.chapitre__tete {
  width: 100%; max-width: var(--maxw); margin-inline: auto;
  padding-inline: var(--page-x);
  margin-bottom: clamp(30px, 3.6vw, 60px);
}
.chapitre__t {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 4.2vw, 3.6rem);
  font-weight: 600; letter-spacing: -.036em; line-height: 1.04;
  color: #FBF4EF; margin-top: clamp(14px, 1.8vw, 22px);
}

/* ------------------------------------------------------------
   45.1  Les trois bandes
   La mosaïque précédente faisait varier les portées et les hauteurs
   pour créer du rythme, mais les six éléments flottaient dans une
   grille commune : rien ne disait où une proposition finissait et
   où la suivante commençait.

   Chaque prestation occupe maintenant une bande entière avec son
   propre fond. La frontière se voit au lieu de se déduire. Le rythme
   est passé à l'intérieur : la part d'image et la hauteur changent
   d'une bande à l'autre, mais le principe de lecture ne change plus.
   ------------------------------------------------------------ */
/* Le fond du chapitre, un brun un cran plus clair que les bandes, passe
   entre elles. C'est tout ce qu'il faut pour qu'on les compte : trois objets
   séparés au lieu d'un bloc continu à traverser, sans ligne claire. */
.bandes { display: grid; gap: clamp(26px, 3.2vw, 54px); }
.bande {
  position: relative;
  display: grid; align-items: stretch;
  color: #F7EDE7;
  isolation: isolate;
  /* Au clavier, l'anneau de focus entoure un rectangle de 1 430 × 560 px
     dont le bord haut passait sous la barre de navigation fixe : on
     voyait une ligne en bas de l'écran et il fallait déduire ce qui
     était sélectionné. La règle `[id]` posait déjà cette marge, mais
     les bandes ne portent pas d'`id`. */
  scroll-margin-top: 96px;
}
/* Le filet d'accent en tête de bande. C'est le signal « une nouvelle
   proposition commence ici », et il porte la couleur de sa catégorie. */
.bande::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px; z-index: 3;
  background: var(--grad-acc);
}

/* Trois fonds, alternés en valeur : c'est la frontière la moins
   ambiguë qui soit, et elle ne coûte rien à la lecture. */
/* Un seul sombre pour les trois bandes.

   Elles en portaient deux — un brun et un presque-noir — et, empilées sur
   le papier clair de la page, le défilement enchaînait crème, brun,
   crème, noir, crème, brun. Six changements de matière pour trois
   propositions : c'est ce qui donnait la sensation de page bariolée.

   La différenciation ne passe plus par le fond mais par l'accent, qui est
   déjà le système : le filet de tête, la promesse et « Voir la prestation »
   prennent l'ambre, le grenat ou le bleu de leur `data-cat`. Un matériau
   commun, trois lumières. C'est aussi la règle de la marque — les bandes
   sont le même studio, pas trois entreprises.

   Le fond des pages métier, lui, reste propre à chaque métier : sur une
   page il n'y a qu'une couleur, elle ne peut entrer en collision avec
   rien, et c'est là qu'elle doit s'affirmer. Voir `.phare`. */
/* Le panneau sombre de la marque, défini une seule fois. Il habille les
   trois bandes de l'accueil ET les panneaux de texte du récit des pages
   métier. Tristan : « une cohérence dans les couleurs et pas une
   mosaïque ». Une variable commune empêche les deux de dériver l'un de
   l'autre ; ne la redéclare pas par `[data-cat]`, c'est l'accent seul qui
   porte le métier. */
:root { --panneau: linear-gradient(104deg, #1F1610 0%, #171009 100%); }
.bande {
  background: var(--panneau);
}

/* Le rythme vit ici : trois partages différents, trois hauteurs
   différentes. Le mariage garde la plus grande image parce que c'est
   la prestation la plus émotionnelle ; l'entreprise la plus compacte
   parce que son argument est factuel. */
.bande--une   { grid-template-columns: 1.12fr .88fr; min-height: clamp(380px, 62svh, 600px); }
.bande--deux  { grid-template-columns: .84fr 1.16fr; min-height: clamp(420px, 70svh, 680px); }
.bande--trois { grid-template-columns: 1.04fr .96fr; min-height: clamp(360px, 57svh, 550px); }
.bande--deux .bande__m { order: 2; }

.bande__m { position: relative; overflow: hidden; background: #16100B; }
.bande__m img, .bande__m video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform 1000ms var(--ease-out);
}
.bande__m video { opacity: 0; transition: opacity 420ms ease, transform 1000ms var(--ease-out); }
.bande__m.is-playing video { opacity: 1; }

/* Marge intérieure élargie : une bande qui respire à l'intérieur n'a pas
   besoin d'être plus haute pour paraître ample. */
.bande__c {
  display: flex; flex-direction: column; justify-content: center;
  padding: clamp(30px, 4.4vw, 84px);
}
/* Le nom du métier passe devant la promesse : la première question du
   visiteur est « de quoi s'agit-il ». */
.bande__t {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 3.2vw, 2.9rem);
  font-weight: 600; letter-spacing: -.034em; line-height: 1.02;
  color: #FBF4EF;
}
.bande__l {
  margin-top: clamp(14px, 1.6vw, 20px);
  max-width: 26ch;
  font-size: clamp(1.02rem, 1.35vw, 1.24rem); line-height: 1.4;
  letter-spacing: -.012em;
  color: var(--mand);
}
.bande__d {
  margin-top: clamp(12px, 1.2vw, 16px); max-width: 36ch;
  color: rgba(247,237,231,.76); font-size: .98rem; line-height: 1.55;
}
.bande__p {
  margin-top: clamp(18px, 2.2vw, 28px);
  font-family: var(--font-mono); font-size: .72rem;
  letter-spacing: .1em; text-transform: uppercase; color: rgba(247,237,231,.58);
}
.bande__p b {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.2rem, 1.7vw, 1.5rem); letter-spacing: -.025em;
  text-transform: none; color: #FBF4EF; margin-left: 9px;
}
/* Le second cran du registre « feuille de service ».
   Dix rôles du site sont rendus à l'identique — mono, capitales,
   var(--t-label) — si bien que « Voir la prestation », qui est l'action
   la plus importante de la page, avait exactement la même forme que
   « À partir de » deux lignes plus haut. L'accent n'arrivait qu'au
   survol, donc jamais au doigt, où c'est pourtant le seul signal que la
   bande est cliquable.
   Il ne devient pas un bouton : l'accent visuel de la bande appartient à
   l'image. Il gagne l'encre d'accent au repos, un cran de corps, et un
   filet qui se prolonge au survol — trois marqueurs qui le sortent de la
   famille des étiquettes sans quitter sa grammaire. */
.bande__go {
  margin-top: clamp(16px, 2vw, 24px);
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-mono); font-size: 0.82rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--mand);
  padding-bottom: 4px;
  border-bottom: 1px solid color-mix(in srgb, var(--mand) 42%, transparent);
  transition: color 300ms ease, border-color 300ms ease;
}
.bande__go svg { transition: transform 340ms var(--ease-out); }

@media (hover: hover) and (pointer: fine) {
  .bande:hover .bande__m img, .bande:hover .bande__m video { transform: scale(1.04); }
  .bande:hover .bande__go { color: #FBF4EF; border-bottom-color: #FBF4EF; }
  .bande:hover .bande__go svg { transform: translateX(7px); }
}
/* Au doigt, le survol n'existe pas : une bande appuyée ne répondait rien
   avant la navigation. L'image avance d'un cran et l'appel s'éclaire le
   temps de l'appui — 140 ms, le délai d'un retour, pas d'une animation. */
@media (hover: none) {
  .bande:active .bande__m img, .bande:active .bande__m video {
    transform: scale(1.025); transition-duration: 140ms;
  }
  .bande:active .bande__go { color: #FBF4EF; border-bottom-color: #FBF4EF; }
}

/* Sous 900 px les bandes s'empilent. L'image passe devant le texte :
   au doigt, on regarde avant de lire. La frontière entre prestations
   reste lisible parce que c'est le fond qui la porte, pas la grille. */
@media (max-width: 900px) {
  .bande, .bande--une, .bande--deux, .bande--trois {
    grid-template-columns: 1fr; min-height: 0;
  }
  .bande__m { order: 0 !important; aspect-ratio: 16 / 10; }
  .bande__c { padding-block: clamp(26px, 6vw, 40px); }
}
@media (prefers-reduced-motion: reduce) {
  .bande__m img, .bande__m video, .bande__go, .bande__go svg { transition: none; }
}

/* ============================================================
   46. LA CHRONOLOGIE
   La méthode était quatre colonnes étroites de texte minuscule.
   Deux défauts, pas un : le texte était réduit pour tenir dans un
   quart de largeur, et quatre colonnes côte à côte se lisent comme
   quatre choses parallèles, jamais comme quatre étapes.

   Verticale, donc : c'est le sens de lecture d'une suite. Le filet
   qui traverse les quatre repères se trace en descendant quand la
   section entre dans le cadre — le seul mouvement de la page qui
   dessine littéralement ce qu'il raconte, le temps qui passe.
   ============================================================ */
.methode {
  display: grid;
  grid-template-columns: minmax(0, 33%) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 96px);
  align-items: start;
  margin-top: clamp(10px, 1.4vw, 18px);
}
/* Le titre reste collé pendant qu'on traverse les étapes : elles
   appartiennent toutes à la même question, et il le rappelle sans
   qu'une phrase ait à le dire. */
.methode__tete {
  position: sticky;
  top: calc(var(--nav-h) + clamp(22px, 6vh, 62px));
}
.methode__t {
  font-size: var(--t-h2);
  line-height: 1.04; letter-spacing: -.034em;
}

.chrono { position: relative; padding-left: clamp(56px, 5vw, 74px); }
/* Le filet. `scaleY` depuis le haut : il descend, il ne s'étire pas
   depuis le centre. Origine et direction comptent autant que la durée. */
.chrono::before {
  content: ''; position: absolute;
  left: clamp(17px, 1.7vw, 22px); top: 10px; bottom: 10px; width: 2px;
  background: linear-gradient(180deg, var(--coral), var(--mand));
  transform: scaleY(0); transform-origin: 50% 0;
  transition: transform 1400ms var(--ease-out);
}
.chrono.is-in::before { transform: scaleY(1); }

/* L'étape traversée par le regard s'allume, les autres restent lisibles
   mais en retrait. On change la couleur et non l'opacité : l'opacité est
   déjà pilotée par les révélations, et deux mécanismes sur la même
   propriété finissent toujours par se contredire. */
.etape {
  position: relative;
  transition: transform 620ms var(--ease-out);
}
.etape + .etape { margin-top: clamp(24px, 3vw, 40px); }
.etape__n {
  position: absolute; left: calc(-1 * clamp(56px, 5vw, 74px)); top: 1px;
  width: clamp(36px, 3.6vw, 44px); height: clamp(36px, 3.6vw, 44px);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--g1); color: var(--ink-2);
  box-shadow: inset 0 0 0 2px var(--hairline);
  font-family: var(--font-mono); font-size: .74rem; letter-spacing: .04em;
  transition: background 480ms ease, color 480ms ease, box-shadow 480ms ease;
}
.etape__h {
  font-family: var(--font-display); font-size: clamp(1.2rem, 1.75vw, 1.48rem);
  font-weight: 600; letter-spacing: -.026em;
  color: var(--ink-2);
  transition: color 480ms ease;
}
/* `--ink-3` (#8F7D71) à 1 rem ne donne que 3,4:1 contre le fond de la page
   à cette hauteur, et 3,93:1 contre du blanc pur : sous le seuil AA de
   4,5:1. Comme seule l'étape active remontait à `--ink-2`, trois étapes
   sur quatre étaient illisibles en permanence — et le repli sans
   JavaScript (`:not(:has(.is-actif))`, plus bas) était donc PLUS lisible
   que le comportement normal. La hiérarchie momentanée est conservée,
   elle joue maintenant entre `--ink-2` (6,19:1) et `--ink`.
   La règle de CLAUDE.md « --ink-3 ne va pas sous 0,85 rem » était trop
   faible : --ink-3 ne porte pas de texte courant, quelle que soit la
   taille. Il ne reste en place que pour des bordures et des ombres. */
.etape__d {
  margin-top: 9px; max-width: 52ch;
  color: var(--ink-2); font-size: 1rem; line-height: 1.58;
  transition: color 480ms ease;
}

.etape.is-actif { transform: translateX(6px); }
.etape.is-actif .etape__n {
  background: var(--grad-acc); color: var(--on-key); box-shadow: none;
}
.etape.is-actif .etape__h { color: var(--ink); }
.etape.is-actif .etape__d { color: var(--ink); }

/* Sans JavaScript, ou en mouvement réduit, aucune étape n'est marquée
   active : toutes doivent alors être à pleine lisibilité. */
.chrono:not(:has(.is-actif)) .etape__h { color: var(--ink); }
/* Le descriptif n'a plus besoin d'être relevé ici : son état au repos est
   déjà `--ink-2`, au-dessus du seuil AA. Seul le titre gagnait à passer
   à pleine encre quand aucune étape n'est marquée. */

@media (max-width: 860px) {
  .methode { grid-template-columns: 1fr; gap: clamp(22px, 5vw, 32px); }
  .methode__tete { position: static; }
}
@media (prefers-reduced-motion: reduce) {
  .chrono::before { transition: none; transform: scaleY(1); }
}

/* ------------------------------------------------------------
   46.0  La méthode se découvre étape par étape
   Tristan : étendre « Comment ça se passe » avec une animation qui
   fasse réellement découvrir le processus étape par étape, en
   gardant le remplissage orange.

   Jusqu'ici un repère changeait de couleur, mais les quatre étapes
   étaient lisibles d'un bloc dès l'arrivée : on voyait une liste, pas
   une progression. Trois gestes, qui disent tous la même chose — où
   l'on en est :
   · le filet orange ne se trace plus d'un coup, il suit la ligne de
     lecture et atteint chaque repère au moment où son étape s'allume ;
   · le descriptif d'une étape à venir attend, flou et un cran plus bas,
     puis fait sa mise au point quand on l'atteint — le geste du métier,
     déjà celui des titres du site — et reste lisible une fois passé ;
   · un compteur collé sous le titre tourne de 01 à 04.
   Les étapes s'écartent pour qu'on les traverse une à une.
   Une version courte, sans compteur et à découverte anticipée, a été
   essayée le 13/09/2026 ; Tristan a préféré revenir à celle-ci, plus
   longue et plus lisible comme progression. Ne la raccourcis pas.

   Aucune hauteur ne change pendant le défilement : seuls l'opacité, le
   flou et les transformations bougent. Replier les étapes passées aurait
   fait remonter la page sous le doigt, et l'étape active se serait
   déplacée sous la ligne même qui la détecte.

   Tout dépend de `.is-pilote`, posé par main.js : sans JavaScript ou en
   mouvement réduit, la chronologie reste entièrement lisible, filet
   tracé, comme avant.
   ------------------------------------------------------------ */
.methode.is-pilote .chrono::before {
  transform: scaleY(var(--avance, 0));
  transition: transform 160ms linear;
}
.methode.is-pilote .etape + .etape { margin-top: clamp(64px, 19vh, 190px); }

.methode.is-pilote .etape__d {
  transition: opacity 620ms var(--ease-out), filter 620ms var(--ease-out),
              transform 620ms var(--ease-out), color 480ms ease;
}
.methode.is-pilote .etape:not(.is-actif):not(.is-fait) .etape__d {
  opacity: 0; filter: blur(6px); transform: translateY(10px);
}
/* Une étape passée garde son accent en anneau : le chemin parcouru se lit.
   --coral-ink sur --g1 tient 5,1:1 pour le numéro. */
.etape.is-fait .etape__n {
  background: var(--g1); color: var(--coral-ink);
  box-shadow: inset 0 0 0 2px var(--coral);
}

.compteur { display: none; }
.compteur__fen {
  display: inline-block; height: 1em; overflow: hidden; line-height: 1;
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(3rem, 5.4vw, 5rem); letter-spacing: -.04em;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.compteur__rouleau {
  display: flex; flex-direction: column;
  transform: translateY(calc(var(--etape, 0) * -1em));
  transition: transform 700ms var(--ease-out);
}
.compteur__rouleau > span { display: block; height: 1em; line-height: 1; }
.compteur__sur {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .1em; color: var(--ink-2);
}
@media (min-width: 861px) {
  .methode.is-pilote .compteur {
    display: flex; align-items: flex-end; gap: 12px;
    margin-top: clamp(24px, 3.2vw, 44px);
  }
}
@media (max-width: 860px) {
  .methode.is-pilote .etape + .etape { margin-top: clamp(36px, 9vh, 84px); }
}
@media (prefers-reduced-motion: reduce) {
  .compteur__rouleau, .methode.is-pilote .etape__d { transition: none; }
}
/* ------------------------------------------------------------
   46.1  Les cases de réassurance répondent au survol
   Trois affirmations posées à plat : rien ne disait qu'on pouvait
   les regarder une par une. Le relief se creuse légèrement, la case
   monte de trois pixels et son étiquette prend l'accent. L'effet est
   volontairement petit : il sert à créer une hiérarchie momentanée,
   pas à faire un numéro.
   ------------------------------------------------------------ */
.trust__item {
  transition: transform 420ms var(--ease-out),
              box-shadow 420ms ease;
}
.trust__item .label,
.trust__item .trust__k { transition: color 420ms ease; }

@media (hover: hover) and (pointer: fine) {
  .trust__item:hover {
    transform: translateY(-3px) scale(1.012);
    box-shadow: var(--nm-out-hi);
  }
  .trust__item:hover .trust__k { color: var(--coral-ink); }
}
/* Au clavier, la case n'est pas focalisable : on relève donc l'état
   au survol du lien qu'elle contient, s'il y en a un. */
.trust__item:focus-within { box-shadow: var(--nm-out-hi); }

@media (prefers-reduced-motion: reduce) {
  .trust__item { transition: none; }
  .trust__item:hover { transform: none; }
}

/* ============================================================
   47. LE RÉCIT DE LA PRESTATION
   Les pages métier disaient trois fois la même chose : un bloc de
   texte expliquait la prestation, une grille de cartes la listait,
   puis une galerie « Quelques images » la montrait — quatre plans
   posés ensemble, hors du propos, à l'endroit où le visiteur avait
   déjà arrêté sa décision. Trois registres, aucune liaison : c'est
   ce qui donnait la sensation de brochure.

   Les mêmes plans deviennent le fil. Chaque temps porte une image
   et le paragraphe qui lui correspond, dans l'ordre d'une visite.
   Le texte ne change pas — il est réparti au lieu d'être empilé.

   Les cadres restent des `.shot` : la boucle au survol, l'affiche
   en image zéro et le filet anti-image-cassée continuent de
   fonctionner sans une ligne de JavaScript en plus.
   ============================================================ */
.recit { display: grid; gap: clamp(44px, 5vw, 78px); }

/* `stretch` et non `center`. Centré, un texte de trois lignes posé à côté
   d'une image de 700 px flottait au milieu d'un vide qui n'appartenait ni
   au haut ni au bas : c'est ce qui donnait la sensation de page à moitié
   remplie. La colonne occupe maintenant toute la hauteur du cadre, et son
   contenu se cale en haut, sur le bord supérieur de l'image. */
/* Chaque temps reprend la composition d'une bande de l'accueil : l'image et
   le panneau sombre accolés, sans gouttière, dans un même cadre arrondi.
   Le champ au-dessus du texte n'est plus un blanc à meubler — c'est la
   matière du panneau, la même que celle des prestations. */
.recit__t {
  display: grid; gap: 0; align-items: stretch;
  border-radius: var(--r); overflow: hidden;
  /* La matière du panneau sous l'image : pendant que l'obturateur s'ouvre,
     la partie encore fermée montre le noir, pas le papier de la page. */
  background: var(--panneau);
}
/* L'arrondi appartient maintenant au cadre commun, plus à l'image seule.
   Le creux neumorphique de `.shot` (ombre intérieure claire) n'a rien à
   faire sur le panneau sombre : tant que l'image n'était pas peinte, il
   dessinait un carré gris pâle que l'obturateur ouvrait à la place du plan. */
.recit__m .shot { border-radius: 0; box-shadow: none; background: transparent; }

/* Le vide restant n'est pas comblé, il est mesuré. Un filet en haut, aligné
   sur le bord de l'image, et un repère de cadre en bas : entre les deux,
   l'espace devient une marge tenue par ses deux extrémités au lieu d'un
   trou. C'est la grammaire du viseur que le site emploie déjà, et elle
   n'ajoute pas un mot d'information. */
.recit__c {
  align-self: stretch;
  display: flex; flex-direction: column;
  padding: clamp(26px, 3.4vw, 56px);
  background: var(--panneau);
  color: #F7EDE7;
}
/* Le filet de tête prend l'accent du métier, comme celui des bandes. */
.recit__c::before {
  content: ''; height: 2px; flex: none;
  background: var(--grad-acc);
}
/* Le texte descend au pied du cadre. Aligner un paragraphe de trois lignes
   sur le haut d'une image de 680 px laissait 560 px de vide dessous, et
   centré c'était pire : il flottait sans appartenir à rien. Posé en bas, le
   bloc s'aligne sur le pied de l'image, et l'espace au-dessus devient un
   champ tenu par le filet du haut — une marge, pas un trou. C'est la
   disposition d'une feuille de service : le repère en tête, la note en pied. */
/* `p.recit__k` et non `.recit__k` : la règle `.recit__c > p` plus bas compte
   deux classes et un type. Sans le sélecteur de type ici, elle réimpose son
   `margin-top: 14px` et le bloc remonte en tête de colonne — le vide se
   reforme au pied, exactement ce qu'on corrige. */
.recit__c > p.recit__k { margin-top: auto; }
.recit__c::after {
  content: ''; height: 7px; flex: none;
  margin-top: clamp(18px, 2vw, 26px);
  background:
    linear-gradient(var(--mand), var(--mand)) 0 0 / 7px 7px no-repeat,
    linear-gradient(rgba(247,237,231,.18), rgba(247,237,231,.18)) 17px 3px / calc(100% - 17px) 1px no-repeat;
}

/* L'image remplit toute sa colonne, bord à bord. Elle était plafonnée en
   hauteur tout en gardant son format : un portrait 4:5 plafonné à 558 px ne
   faisait plus que 446 px de large dans une colonne de 559, et le panneau
   sombre apparaissait en bande à côté de l'image — l'obturateur ouvrait ce
   pan vide avec elle. La colonne porte maintenant la hauteur, l'image s'y
   pose en absolu et `cover` recadre. Temps ample : la hauteur d'un 16:9 à
   cette largeur (34vw), plafonnée ; temps resserré : la hauteur pleine. */
@media (min-width: 900px) {
  .recit__m { position: relative; min-height: min(34vw, 62svh, 600px); }
  .recit__m:has(.ar-32) { min-height: min(38vw, 62svh, 600px); }
  .recit__t--inv .recit__m { min-height: min(62svh, 600px); }
  .recit__m .shot { position: absolute; inset: 0; aspect-ratio: auto; }
}

/* La légende reprend le rôle qu'avait `.gal__cap` : elle nomme le
   moment de la visite. C'est une information, pas un ornement —
   elle dit où l'on en est dans le déroulé. */
.recit__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .12em; text-transform: uppercase; color: var(--mand);
}
/* Encre claire sur le panneau, aux mêmes valeurs que dans les bandes. */
.recit__c > p:not(.recit__k) { margin-top: 14px; color: rgba(247,237,231,.80); max-width: 46ch; }
.recit__c > p.lead { color: #FBF4EF; max-width: 42ch; }

/* Empilé, le cadre n'a plus de hauteur à accompagner : le repère de pied
   se retrouverait collé sous le texte sans rien tenir. */
@media (max-width: 899px) {
  .recit__c { display: block; }
  .recit__c::before, .recit__c::after { display: none; }
}

/* Le rythme vient du partage, pas d'une taille unique appliquée
   partout. Le plan d'ensemble prend la plus grande part, l'intérieur
   la plus petite, et le diptyque occupe toute la largeur. */
@media (min-width: 900px) {
  /* Temps ample : l'image vient d'abord et prend la plus grande part.
     C'est le plan qui situe — il a besoin de la largeur. */
  .recit__t { grid-template-columns: minmax(0, 1.34fr) minmax(0, .66fr); }

  /* Temps resserré : le texte d'abord, l'image ensuite et plus étroite.
     L'alternance empêche la page de se lire comme une colonne unique,
     et le format vertical du plan d'intérieur resserre encore la part
     réelle de l'image sans qu'on ait à la contraindre. */
  .recit__t--inv { grid-template-columns: minmax(0, 1.14fr) minmax(0, .86fr); }
  .recit__t--inv .recit__m { order: 2; }
}

/* Le diptyque ferme le récit : deux plans, aucune phrase. Le visiteur
   vient de lire, il regarde. C'est le geste que la page d'accueil
   emploie déjà pour `.halves`. */
.recit__duo { display: grid; gap: clamp(14px, 1.8vw, 24px); }
@media (min-width: 760px) {
  .recit__duo { grid-template-columns: 1fr 1fr; align-items: start; }
}

/* Le temps solo : un plan tenu, sans phrase à côté. Il sert quand une
   image est l'argument à elle seule — sur le mariage, le plan que
   personne n'a demandé prouve la discrétion mieux que la phrase qui la
   revendique. Resserré et centré : à pleine largeur il deviendrait une
   bannière, alors qu'on veut un cadre qu'on regarde. */
/* `width` et non `max-width` : les marges automatiques désactivent
   l'étirement d'un élément de grille, qui retombe alors sur sa largeur
   de contenu. Le cadre étant une boîte à `aspect-ratio` dont l'image est
   en position absolue, cette largeur vaut zéro — le bloc se retrouvait
   dimensionné par sa légende, à 152 px. Une largeur définie règle le cas
   sans toucher à l'alignement. */
.recit__seul { width: 78%; margin-inline: auto; }
@media (max-width: 760px) { .recit__seul { width: 100%; } }

/* La même figure, à l'échelle opposée. Le mariage se referme sur un cadre
   tenu, resserré, qu'on regarde ; l'entreprise se referme sur toute la
   largeur, parce que ce qu'elle doit dire à cet endroit est une échelle.
   Un composant, deux tempéraments. */
/* `100%` et non `auto` : les marges automatiques restent en place, donc
   `auto` ferait retomber le bloc sur sa largeur de contenu — le même
   piège que ci-dessus, à l'autre bout de l'échelle. */
.recit__seul--pleine { width: 100%; }

/* ============================================================
   48. LA BANDE PHARE
   L'offre récurrente est le seul endroit du site où la répétition
   se vend : une agence qui rentre des mandats toutes les semaines
   n'achète pas au même titre qu'un particulier. Elle occupait un
   panneau clair parmi d'autres panneaux clairs.

   Elle prend maintenant toute la largeur et change de fond. Le
   changement de terrain est le signal — c'est le même procédé que
   le chapitre sombre de l'accueil, et il n'a pas besoin d'une
   phrase pour dire « ceci est différent ».
   ============================================================ */
/* La bande prend le sombre de sa catégorie, pas un brun générique.

   `--deep` existe déjà et il est accordé métier par métier : brun ambré
   pour l'immobilier, grenat pour le mariage, marine pour l'entreprise.
   Il était ignoré ici au profit d'un brun écrit en dur, si bien que les
   trois pages avaient la même bande — l'endroit le plus visible de chacune
   était précisément celui qui ne disait rien de son métier.

   C'est l'inverse de la règle appliquée aux bandes de l'accueil, et pour
   la bonne raison : sur une page métier, une seule couleur règne et ne
   peut entrer en collision avec rien. C'est là qu'elle doit s'affirmer.

   Repli en brun si `--deep` manque — la bande ne doit jamais devenir
   transparente et laisser l'encre claire sur du papier clair. */
.phare {
  position: relative; overflow: hidden;
  padding-block: clamp(46px, 5.8vw, 96px);
  color: #F7EDE7;
  background: var(--deep, linear-gradient(104deg, #241810 0%, #17100B 100%));
}
/* Le filet d'accent en tête, comme sur les bandes de l'accueil. */
.phare::before {
  content: ''; position: absolute; inset: 0 0 auto 0;
  height: 2px; z-index: 3; background: var(--grad-acc);
}
/* Le grain, identique à celui du chapitre : sans lui, un aplat sombre
   de cette taille se bande sur les écrans 8 bits. */
.phare::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .05;
  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='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.phare > * { position: relative; z-index: 2; }

/* Sur ce fond, le panneau n'a plus de raison d'être : le fond EST le
   panneau. On retire le relief et on reprend l'encre claire. */
.phare .offer {
  background: none; box-shadow: none; border-radius: 0; padding: 0;
}
.phare .offer::before { display: none; }
/* La règle de paragraphe ci-dessous compte deux classes et un type ;
   l'étiquette et le titre n'en comptaient que deux, et se faisaient donc
   battre et reverser dans l'encre du corps de texte — soit précisément la
   hiérarchie que cette bande existe pour créer. Trois classes suffisent à
   rétablir l'ordre, sans `!important`, et sans supposer que le titre est
   un `<p>` : sur le mariage c'est un vrai `<h2>`, parce qu'il ouvre une
   section que le sommaire cible. */
.phare .offer .offer__k { color: var(--mand); }
.phare .offer .offer__t {
  color: #FBF4EF; font-size: clamp(1.6rem, 3.2vw, 2.6rem); letter-spacing: -.032em;
}
.phare .offer p { color: rgba(247,237,231,.82); }
.phare .offer__pts li { color: #F7EDE7; }
.phare .offer__pts li::before { background: var(--mand); }

/* La bande accueille aussi une grille de cartes : sur l'entreprise, le
   point focal n'est pas une offre à deux colonnes mais quatre objectifs
   qui ne se ressemblent pas. Les cartes perdent leur relief creusé, qui
   n'existe pas sur fond sombre, et reprennent un simple filet. */
.phare__tete { margin-bottom: clamp(28px, 3.4vw, 52px); }
.phare__k {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .12em; text-transform: uppercase; color: var(--mand);
}
.phare__t {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 3.2vw, 2.6rem);
  font-weight: 600; letter-spacing: -.032em; color: #FBF4EF;
  margin-top: clamp(12px, 1.4vw, 18px);
}
.phare .deliv {
  background: rgba(247,237,231,.045);
  box-shadow: inset 0 0 0 1px rgba(247,237,231,.14);
}
.phare .deliv h3 { color: #FBF4EF; }
.phare .deliv p { color: rgba(247,237,231,.78); }
/* L'objectif devient le début du titre. Il était posé en petite étiquette
   au-dessus (`.deliv__tag--cat`) : quatre des douze étiquettes de la page
   entreprise, alors que « Recruter », « Vendre », « Rassurer »,
   « Documenter » sont précisément ce que le visiteur cherche dans cette
   grille. Le mot passe dans la hiérarchie des titres, à l'accent du métier
   (#6BB6EE sur le marine : 5,3:1), et le séparateur n'existe que pour les
   lecteurs d'écran. */
.deliv__verbe {
  display: block; margin-bottom: 4px;
  font-size: clamp(1.35rem, 1.9vw, 1.65rem); letter-spacing: -.03em;
  color: var(--mand);
}
.phare__note { margin-top: clamp(26px, 3vw, 40px); color: rgba(247,237,231,.78); max-width: 62ch; }

/* La liste « Ce qui est inclus » du devis. Ses puces étaient des « · »
   tapés dans le texte, que certains lecteurs d'écran lisent à voix haute.
   Le carré d'accent est celui des annotations de l'accueil : un repère de
   cadre, dans la grammaire du site. */
.inclus li { position: relative; padding-left: 18px; }
.inclus li::before {
  content: ''; position: absolute; left: 0; top: .62em;
  width: 6px; height: 6px; background: var(--coral);
}

@media (prefers-reduced-motion: reduce) {
  .recit__t, .recit__duo { transition: none; }
}

/* ============================================================
   49. À PROPOS — LA FICHE, L'ÉCRAN, LE CAP
   La page disait « chef opérateur de formation » et s'arrêtait là. Elle
   devient une fiche qu'on lit en un regard, puis une lecture pour ceux qui
   veulent savoir d'où vient ce regard.
   ============================================================ */

/* 49.1  Les repères de viseur. Quatre coins, la grammaire de cadre du site
   (repère de pied du récit, carré des annotations). */
.vis { position: absolute; inset: clamp(14px, 2vw, 24px); pointer-events: none; z-index: 2; }
.vis i {
  position: absolute; width: 22px; height: 22px;
  border: 0 solid var(--mand);
  transition: transform 900ms cubic-bezier(.34, 1.56, .64, 1) 250ms, opacity 400ms ease 250ms;
}
.vis i:nth-child(1) { top: 0;    left: 0;  border-top-width: 2px;    border-left-width: 2px;  --dx: -1; --dy: -1; }
.vis i:nth-child(2) { top: 0;    right: 0; border-top-width: 2px;    border-right-width: 2px; --dx: 1;  --dy: -1; }
.vis i:nth-child(3) { bottom: 0; left: 0;  border-bottom-width: 2px; border-left-width: 2px;  --dx: -1; --dy: 1; }
.vis i:nth-child(4) { bottom: 0; right: 0; border-bottom-width: 2px; border-right-width: 2px; --dx: 1;  --dy: 1; }

/* 49.2  La fiche : portrait et données dans un seul objet sombre. */
.fiche {
  display: grid; overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--panneau); color: #F7EDE7;
}
@media (min-width: 900px) {
  .fiche { grid-template-columns: minmax(0, .86fr) minmax(0, 1.14fr); }
}
/* Le fil d'Ariane seul en tête : le nom est dans la fiche. */
.phero--fil { padding-top: calc(var(--nav-h) + clamp(20px, 2.6vw, 40px)); padding-bottom: 0; }
.phero--fil .crumb { margin-bottom: 0; }

/* Empilée (< 900 px), la fiche ouvrait sur un portrait 4:5 qui remplissait
   l'écran à lui seul — 689 × 861 px en 768 : le nom et la fiche passaient
   dessous. Un 5:4 cadré sur le visage laisse le nom monter dans le premier
   écran. */
.fiche__ph { position: relative; overflow: hidden; aspect-ratio: 5 / 4; background: #16100B; }
@media (min-width: 900px) {
  .fiche__ph { aspect-ratio: auto; min-height: min(72svh, 660px); }
}
.fiche__ph img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 22%;
  transition: filter 1200ms var(--ease-out), transform 1600ms var(--ease-out);
}
/* Le pied du portrait rejoint le panneau : l'image se pose, elle ne découpe pas. */
.fiche__ph::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(0deg, rgba(20, 13, 9, .5) 0%, transparent 38%);
}
.fiche__c { display: flex; flex-direction: column; padding: clamp(28px, 3.6vw, 60px); }
/* Le nom est le titre de la page, et le plus grand : la hiérarchie mesurée
   plaçait le grand mot de l'écran (72 px) au niveau du h1 et le titre du cap
   au-dessus des autres h2. */
.fiche__nom {
  font-size: clamp(2.5rem, 4.8vw, 4.4rem); font-weight: 700;
  letter-spacing: -.04em; line-height: .96; color: #FBF4EF;
}
.fiche__t {
  margin-top: clamp(12px, 1.2vw, 18px);
  font-family: var(--font-display); font-size: clamp(1.3rem, 2vw, 1.85rem); font-weight: 600;
  letter-spacing: -.02em; line-height: 1.15; color: rgba(247, 237, 231, .9);
}
.fiche__t em { font-style: normal; color: var(--mand); }
.fiche__intro {
  margin-top: clamp(16px, 1.6vw, 22px); max-width: 48ch;
  font-size: 1.06rem; line-height: 1.6; color: rgba(247, 237, 231, .80);
}
.fiche__dl { margin: clamp(28px, 3.2vw, 48px) 0 0; }
@media (min-width: 900px) {
  /* Les données tombent au pied du panneau, alignées sur le bas du portrait. */
  .fiche__dl { margin-top: auto; padding-top: clamp(28px, 3.2vw, 48px); }
}
.fiche__dl > div {
  display: grid; grid-template-columns: minmax(8.5em, .36fr) 1fr;
  gap: 16px; align-items: baseline;
  padding-block: 11px; border-top: 1px solid rgba(247, 237, 231, .12);
}
/* Entre 900 et 1 100 px, la colonne des valeurs tombait à 240 px et quatre
   lignes sur six passaient à la ligne (77 px au lieu de 52). L'étiquette
   passe au-dessus de sa valeur, comme sous 420 px. */
@media (min-width: 900px) and (max-width: 1099px) {
  .fiche__dl > div { grid-template-columns: 1fr; gap: 2px; padding-block: 9px; }
}
.fiche__dl dt {
  font-family: var(--font-mono); font-size: var(--t-label);
  letter-spacing: .12em; text-transform: uppercase; color: rgba(247, 237, 231, .64);
}
.fiche__dl dd { margin: 0; color: #FBF4EF; }
@media (max-width: 420px) {
  .fiche__dl > div { grid-template-columns: 1fr; gap: 4px; }
}

/* L'arrivée : le portrait se développe, les coins du viseur resserrent le
   cadre en dépassant d'un cran avant de se poser — la mise au point qui
   cherche —, puis les lignes de la fiche s'impriment une à une. */
.fiche__c > :not(.fiche__dl), .fiche__dl > div {
  transition: opacity 650ms ease, filter 650ms var(--ease-out);
  transition-delay: calc(380ms + var(--o, 0) * 80ms);
}
.fiche__c > :nth-child(2) { --o: 1; }
.fiche__c > :nth-child(3) { --o: 2; }
.fiche__dl > div:nth-child(1) { --o: 3; }
.fiche__dl > div:nth-child(2) { --o: 4; }
.fiche__dl > div:nth-child(3) { --o: 5; }
.fiche__dl > div:nth-child(4) { --o: 6; }
.js-motion [data-motion="fiche"]:not(.is-in) .fiche__ph img { filter: blur(12px) saturate(.5); transform: scale(1.06); }
.js-motion [data-motion="fiche"]:not(.is-in) .vis i {
  opacity: 0; transform: translate(calc(var(--dx) * 18px), calc(var(--dy) * 18px));
}
.js-motion [data-motion="fiche"]:not(.is-in) :is(.fiche__c > :not(.fiche__dl), .fiche__dl > div) {
  opacity: 0; filter: blur(6px);
}

/* 49.3  L'histoire : l'écran collé et les quatre moments. */
.regard__h { font-size: var(--t-h2); max-width: 20ch; margin-bottom: clamp(28px, 4vw, 60px); }
.regard__g { display: grid; gap: clamp(28px, 4vw, 72px); }
.regard__ecran { display: none; }
@media (min-width: 900px) {
  .regard__g { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); align-items: start; }
  .regard__ecran { display: block; position: sticky; top: calc(var(--nav-h) + 7vh); }
}
.regard__cadre {
  position: relative; isolation: isolate; overflow: hidden;
  height: min(64vh, 580px);
  border-radius: var(--r-lg);
  background: var(--panneau); color: #F7EDE7;
}
/* Le faisceau : une lueur chaude dans l'écran, comme la lumière d'une
   projection sur la poussière. Fixe depuis que les quatre plans portent les
   images de Tristan : elle ne se voit plus que si un média manque, et sa
   dérive de 14 s tournait en permanence derrière elles, en plus de la roue,
   de la timeline et de la vidéo du moment « 14 ans ». */
.regard__cadre::before {
  content: ''; position: absolute; inset: -25%; z-index: -1;
  background: radial-gradient(38% 32% at 30% 28%, rgba(255, 154, 60, .17), transparent 70%);
}

/* Chaque plan est posé dans l'écran ; un seul est net. Le passage de l'un à
   l'autre est une mise au point, le geste qu'a déjà le site. */
.regard__pl {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 14px;
  padding: clamp(34px, 3.4vw, 56px);
  opacity: 0; filter: blur(10px); transform: scale(1.03);
  transition: opacity 600ms var(--ease-out), filter 700ms var(--ease-out), transform 900ms var(--ease-out);
}
.regard__pl.is-actif { opacity: 1; filter: none; transform: none; }
.regard__f {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(2.4rem, 4vw, 3.6rem); letter-spacing: -.035em; line-height: .98;
  color: #FBF4EF;
}
.regard__f--s  { font-size: clamp(2rem, 3.4vw, 3.1rem); }

/* Premier temps : « Regarder » devient « Filmer ». Le mot fait la mise au
   point sur son contraire — c'est tout le propos du moment. */
.regard__alt { display: grid; }
.regard__alt > span { grid-area: 1 / 1; }
.regard__alt > span:first-child { animation: altVoir 5s var(--ease-out) infinite; }
.regard__alt > span:last-child { color: var(--mand); opacity: 0; animation: altFaire 5s var(--ease-out) infinite; }
@keyframes altVoir  { 0%, 40% { opacity: 1; filter: none; } 50%, 90% { opacity: 0; filter: blur(8px); } 100% { opacity: 1; filter: none; } }
@keyframes altFaire { 0%, 40% { opacity: 0; filter: blur(8px); } 50%, 90% { opacity: 1; filter: none; } 100% { opacity: 0; filter: blur(8px); } }

/* Troisième temps : la roue des formats de la chaîne. La dernière ligne
   répète la première, la boucle ne saute pas. */
.regard__roue {
  display: block; height: 1.15em; overflow: hidden;
  font-family: var(--font-display); font-weight: 600; line-height: 1.15;
  font-size: clamp(1.4rem, 2.4vw, 2.1rem); letter-spacing: -.02em; color: var(--mand);
}
.regard__roue-in { display: flex; flex-direction: column; animation: roue 7.5s cubic-bezier(.65, 0, .35, 1) infinite; }
.regard__roue-in > span { display: block; height: 1.15em; }
@keyframes roue {
  0%, 14%  { transform: translateY(0); }
  20%, 34% { transform: translateY(-1.15em); }
  40%, 54% { transform: translateY(-2.3em); }
  60%, 74% { transform: translateY(-3.45em); }
  80%, 94% { transform: translateY(-4.6em); }
  100%     { transform: translateY(-5.75em); }
}

/* Les images de l'histoire : les vraies, celles de Tristan — l'enfant en
   noir et blanc, la boîte du premier drone, l'intro YouTube et le montage, la
   carte jusqu'à Lille. Quatre sources de nature et de couleur différentes :
   elles passent toutes au noir et blanc sous le voile brun du panneau, pour
   que l'écran reste un seul objet et pas une mosaïque. Le voile est dense en
   bas, là où sont les grands mots (≥ 0,92 sous le texte), léger en haut, là
   où l'image doit se voir. Le trajet dessiné du dernier temps est parti : la
   vidéo de la carte le raconte déjà. */
.regard__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.regard__media img, .regard__media video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 30%;
  filter: grayscale(1) contrast(1.06) brightness(.8);
}
/* La vidéo se crée à l'arrivée de son moment (main.js) et apparaît sur son
   affiche quand elle joue vraiment. Absente ou en échec, l'affiche reste. */
.regard__media video { opacity: 0; transition: opacity 500ms ease; }
.regard__media.is-playing video { opacity: 1; }
.regard__media::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(0deg, rgba(20, 13, 9, .94) 0%, rgba(20, 13, 9, .78) 34%, rgba(20, 13, 9, .32) 70%, rgba(20, 13, 9, .42) 100%),
    linear-gradient(rgba(255, 140, 60, .08), rgba(255, 140, 60, .08));
}
.regard__pl > :not(.regard__media) { position: relative; z-index: 1; }
.regard__pl:not(.is-actif) :is(.regard__alt > span, .regard__roue-in, .regard__drone, .regard__drone .helice) {
  animation-play-state: paused;
}
.regard__an {
  font-family: var(--font-mono); font-size: .78rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--mand);
}

/* La timeline du plan « 14 ans » : deux pistes de plans qui défilent sous une
   tête de lecture. Elle ne tourne que lorsque son plan est à l'écran. */
.regard__tl { position: relative; display: grid; gap: 6px; overflow: hidden; border-radius: 3px; }
.regard__tl b {
  display: block; height: 14px; width: calc(100% + 320px);
  background:
    linear-gradient(90deg,
      transparent 0 4px, rgba(247,237,231,.55) 4px 86px, transparent 86px 92px,
      rgba(255,154,60,.85) 92px 138px, transparent 138px 144px,
      rgba(247,237,231,.30) 144px 262px, transparent 262px 268px,
      rgba(247,237,231,.55) 268px 320px) 0 0 / 320px 100% repeat-x;
  animation: bobine 8s linear infinite;
}
.regard__tl b + b {
  background:
    linear-gradient(90deg,
      rgba(247,237,231,.30) 0 58px, transparent 58px 64px,
      rgba(247,237,231,.55) 64px 196px, transparent 196px 202px,
      rgba(255,90,60,.75) 202px 250px, transparent 250px 256px,
      rgba(247,237,231,.30) 256px 320px) 0 0 / 320px 100% repeat-x;
  animation-duration: 11s;
}
.regard__tl::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 38%; width: 2px;
  background: #FBF4EF; box-shadow: 0 0 10px rgba(255, 154, 60, .8);
}
@keyframes bobine { to { transform: translateX(-320px); } }
.regard__pl:not(.is-actif) .regard__tl b { animation-play-state: paused; }
/* Réunie avec la chaîne, la timeline s'ajoute sous la roue : un peu d'air
   entre les deux pistes de lecture. */
.regard__roue + .regard__tl { margin-top: 4px; }

/* Le premier drone, à 12 ans : dessiné au trait, en vol stationnaire dans le
   haut de l'écran — le ciel au-dessus du titre. Il flotte, s'incline à peine,
   et ses hélices battent. */
.regard__drone {
  align-self: flex-end; margin-bottom: auto;
  width: clamp(130px, 14vw, 200px); height: auto; overflow: visible;
  animation: vol 3.4s ease-in-out infinite alternate;
}
.regard__drone rect { fill: rgba(247, 237, 231, .88); }
.regard__drone .bras { fill: none; stroke: rgba(247, 237, 231, .88); stroke-width: 3; stroke-linecap: round; }
.regard__drone .nacelle { fill: #1A120C; stroke: var(--mand); stroke-width: 2.5; }
.regard__drone .helice {
  fill: var(--mand); opacity: .75;
  transform-box: fill-box; transform-origin: center;
  animation: helice 160ms linear infinite alternate;
}
@keyframes vol { from { transform: translateY(0) rotate(-1.5deg); } to { transform: translateY(-12px) rotate(1.5deg); } }
@keyframes helice { to { transform: scaleX(.5); opacity: .45; } }

/* Les repères sous l'écran : où l'on en est dans les quatre moments. */
.regard__rep { display: flex; gap: 6px; margin-top: 14px; }
.regard__rep i {
  flex: 1; height: 2px; border-radius: 2px;
  background: var(--hairline); transition: background 450ms ease;
}
.regard__rep i.is-vu, .regard__rep i.is-actif { background: var(--coral); }

/* Le fil de l'histoire : le même geste que la méthode de l'accueil. Une
   piste discrète dit qu'il reste du chemin ; le remplissage orange la suit
   jusqu'à la ligne de lecture (`--avance`, main.js), et chaque moment porte
   son repère sur la première ligne de son titre. Sans JavaScript, le fil
   est plein et tous les textes sont lisibles. */
.regard__etapes {
  --rail: clamp(40px, 3.6vw, 56px);
  position: relative; list-style: none; margin: 0; padding: 0 0 0 var(--rail);
}
.regard__etapes::before, .regard__etapes::after {
  content: ''; position: absolute; left: 7px; top: 0; bottom: var(--fin, 0px); width: 2px; border-radius: 2px;
}
/* Sur grand écran, la liste se prolonge d'une demi-hauteur d'écran sous le
   dernier moment (`--fin`). Sans elle, quand l'écran cesse d'être collé,
   le titre du dernier moment est encore sous son centre — et les deux
   défilent ensuite ensemble : « L'autre bout du monde » ne s'allumait
   jamais. Le fil s'arrête avant cette marge, et main.js la retire du
   calcul du remplissage. */
@media (min-width: 900px) {
  .regard__etapes { --fin: max(0px, calc(min(64vh, 580px) * .6 - 120px)); padding-bottom: var(--fin); }
}
.regard__etapes::before { background: var(--hairline); }
.regard__etapes::after {
  background: linear-gradient(180deg, var(--coral), var(--mand));
  transform: scaleY(var(--avance, 1)); transform-origin: 50% 0;
}
.regard.is-pilote .regard__etapes::after { transition: transform 160ms linear; }

.regard__e { position: relative; }
.regard__e + .regard__e { margin-top: clamp(36px, 6vh, 60px); }
.regard__e h3 {
  position: relative;
  font-size: clamp(1.45rem, 2.4vw, 2.2rem); letter-spacing: -.03em; line-height: 1.08;
  transition: color 450ms ease;
}
.regard__e h3::before {
  content: ''; position: absolute; left: calc(-1 * var(--rail)); top: .54em;
  width: 16px; height: 16px; margin-top: -8px; border-radius: 50%;
  background: var(--g1); box-shadow: inset 0 0 0 2px var(--hairline);
  transition: background 480ms ease, box-shadow 480ms ease, transform 480ms var(--ease-out);
}
.regard.is-pilote .regard__e.is-actif h3::before {
  background: var(--grad-acc); transform: scale(1.2);
  box-shadow: 0 0 0 6px rgba(255, 90, 60, .14);
}
/* Un moment passé garde son repère cerclé : le chemin parcouru se lit. */
.regard.is-pilote .regard__e.is-fait h3::before { box-shadow: inset 0 0 0 2px var(--coral); }

/* La découverte (mouvement normal seulement) : le moment à venir montre son
   titre, son texte attend flou un cran plus bas ; le moment atteint fait sa
   mise au point ; les moments passés s'effacent à mesure qu'on avance —
   seul le repère cerclé reste net. On remonte, ils reviennent. Aucune
   hauteur ne change : seuls couleur, opacité, flou et transformation. */
.regard.is-decouverte .regard__e > p {
  transition: opacity 620ms var(--ease-out), filter 620ms var(--ease-out), transform 620ms var(--ease-out);
}
.regard.is-decouverte .regard__e:not(.is-actif):not(.is-fait) h3 { color: var(--ink-2); }
.regard.is-decouverte .regard__e:not(.is-actif):not(.is-fait) > p {
  opacity: 0; filter: blur(6px); transform: translateY(10px);
}
/* Les moments passés s'effacent, sans devenir illisibles. À 30 % ils
   tombaient à 1,8:1 (titre) et 1,5:1 (texte) : une recherche Ctrl+F
   atterrissait sur du texte presque invisible, sur la page dont le travail
   est la confiance. Tristan a choisi « effacer moins » (critique du
   13/09/2026). Calculé sur le fond le plus sombre de la page (--g4,
   #FFE0CE) : titre à 60 % = 3,6:1, seuil des grands caractères ; texte à
   94 % = 4,7:1, seuil AA du texte courant. L'effacement est donc porté par
   le titre et son repère, et réservé au grand écran, où l'écran collé le
   justifie : sur mobile, tout reste à pleine encre. */
@media (min-width: 900px) {
  .regard.is-decouverte .regard__e.is-fait h3 { color: rgba(54, 43, 36, .6); }
  .regard.is-decouverte .regard__e.is-fait > p { opacity: .94; }
}
/* Contraste renforcé demandé par le système : ni flou, ni effacement. Mêmes
   sélecteurs que les règles qu'on annule, posés après : ils gagnent. */
@media (prefers-contrast: more) {
  .regard.is-decouverte .regard__e:not(.is-actif):not(.is-fait) h3,
  .regard.is-decouverte .regard__e.is-fait h3 { color: var(--ink); }
  .regard.is-decouverte .regard__e:not(.is-actif):not(.is-fait) > p,
  .regard.is-decouverte .regard__e.is-fait > p { opacity: 1; filter: none; transform: none; }
}
/* Sous 900 px, l'écran collé n'existe pas : l'histoire perdait toutes les
   images de Tristan et devenait 790 px de texte le long d'un fil (critique
   du 13/09/2026). Chaque moment porte donc sa vignette sous son titre, dans
   le même noir et blanc chaud que l'écran. Sans vidéo : c'est l'affiche.
   Le `<picture>` sert une image vide d'un pixel à partir de 900 px, pour
   qu'aucun navigateur ne télécharge la vignette là où elle est masquée.
   4:3 plutôt que 16:9, qui ne gardait qu'un tiers des portraits verticaux ;
   largeur plafonnée à 74vh pour le téléphone tenu à l'horizontale. */
.regard__vignette {
  display: block; position: relative; overflow: hidden;
  width: min(100%, 420px, 74vh); aspect-ratio: 4 / 3;
  margin-top: 14px; border-radius: var(--r);
  background: var(--panneau);
}
.regard__vignette img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 32%;
  filter: grayscale(1) contrast(1.06) brightness(.9);
}
.regard__vignette::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(rgba(255, 140, 60, .08), rgba(255, 140, 60, .08));
}
.regard__e:nth-child(1) .regard__vignette img { object-position: 50% 38%; }
.regard__e:nth-child(4) .regard__vignette img { object-position: 50% 50%; }
@media (min-width: 900px) {
  .regard__vignette { display: none; }
}

.regard__e > p:last-child {
  margin-top: 14px; max-width: 46ch;
  font-size: 1.05rem; line-height: 1.62; color: var(--ink-2);
}
@media (min-width: 900px) {
  /* Chaque moment occupe 40vh : assez pour que l'écran change de plan, pas
     plus. À 56vh, quatre textes de 110 px s'étalaient sur 2,4 écrans, avec
     des vides de 400 à 490 px entre eux — plus grands que les écarts entre
     sections : l'espace annonçait un nouveau chapitre au milieu d'une même
     histoire. */
  .regard__e { min-height: 36vh; display: flex; flex-direction: column; justify-content: center; }
  .regard__e + .regard__e { margin-top: 0; }
  .regard__e:first-child { justify-content: flex-start; padding-top: 4vh; }
  /* Le dernier moment n'a plus d'écran à attendre après lui : sa hauteur
     imposée ne faisait qu'ajouter un vide avant la section suivante. */
  .regard__e:last-child { min-height: 0; padding-top: 10vh; }
}

/* 49.4  Les cases. Un seul composant pour les deux mosaïques du bas :
   le papier en relief du site (comme les livrables) ou le panneau sombre
   des bandes. Pas de troisième matière, pas de couleur par case. Les cases
   claires gagnent un peu de présence au survol, sans zoom. */
.tuile {
  position: relative; overflow: hidden;
  padding: clamp(22px, 2.4vw, 36px);
  border-radius: var(--r-lg);
  background: var(--pane); box-shadow: var(--nm-out-sm);
}
.tuile h3 { font-size: clamp(1.2rem, 1.7vw, 1.5rem); letter-spacing: -.02em; line-height: 1.15; }
.tuile p { margin-top: 8px; color: var(--ink-2); line-height: 1.6; max-width: 52ch; }
.tuile--sombre { background: var(--panneau); box-shadow: none; color: #F7EDE7; }
.tuile--sombre h3 { color: #FBF4EF; }
.tuile--sombre p { color: rgba(247, 237, 231, .8); }
/* Le survol passe par `translate` et `scale`, pas par `transform` : ce
   dernier appartient à l'apparition (`data-reveal`), et redéclarer la
   transition sur lui effaçait le fondu et son délai en cascade. Chaque
   propriété garde sa durée ; seul l'apparition garde son délai. */
.tuile:not(.tuile--sombre) {
  transition-property: opacity, transform, translate, scale, box-shadow;
  transition-duration: 700ms, 700ms, 420ms, 420ms, 420ms;
  transition-timing-function: var(--ease), var(--ease), var(--ease-out), var(--ease-out), var(--ease-out);
  transition-delay: var(--d, 0ms), var(--d, 0ms), 0ms, 0ms, 0ms;
}
@media (hover: hover) and (pointer: fine) {
  .tuile:not(.tuile--sombre):hover { translate: 0 -3px; scale: 1.012; }
}

/* D'où vient le nom : le ciel à gauche sur toute la hauteur, trois cases
   claires empilées à côté. Il y en avait cinq, avec une seconde case sombre
   « Basé à Lille » qui redisait la fiche et venait coller au bloc sombre du
   cap juste en dessous. */
.nom__t { font-size: var(--t-h2); }
.nom__b { display: grid; gap: clamp(12px, 1.2vw, 18px); margin-top: clamp(24px, 3vw, 44px); }
@media (min-width: 900px) {
  .nom__b { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .nom__b > :nth-child(1) { grid-column: 1 / span 7; grid-row: 1 / span 3; }
  .nom__b > :nth-child(2) { grid-column: 8 / span 5; grid-row: 1; }
  .nom__b > :nth-child(3) { grid-column: 8 / span 5; grid-row: 2; }
  .nom__b > :nth-child(4) { grid-column: 8 / span 5; grid-row: 3; }
}
.nom__b > .tuile:not(.ciel) { display: flex; flex-direction: column; justify-content: flex-end; }

/* Le ciel. Un champ d'étoiles fixe, Canopus qui scintille, et une mire qui
   fait la mise au point sur elle à l'arrivée de la case. */
.ciel {
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(300px, 30vw, 440px);
  background:
    radial-gradient(90% 70% at 70% 20%, rgba(255, 154, 60, .10), transparent 60%),
    var(--panneau);
}
.ciel::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    radial-gradient(1.2px 1.2px at 8% 14%, rgba(247,237,231,.75), transparent 70%),
    radial-gradient(1px 1px at 18% 38%, rgba(247,237,231,.5), transparent 70%),
    radial-gradient(1.4px 1.4px at 27% 9%, rgba(247,237,231,.8), transparent 70%),
    radial-gradient(1px 1px at 36% 26%, rgba(247,237,231,.45), transparent 70%),
    radial-gradient(1.2px 1.2px at 44% 52%, rgba(247,237,231,.55), transparent 70%),
    radial-gradient(1px 1px at 52% 12%, rgba(247,237,231,.6), transparent 70%),
    radial-gradient(1.3px 1.3px at 81% 16%, rgba(247,237,231,.7), transparent 70%),
    radial-gradient(1px 1px at 88% 42%, rgba(247,237,231,.5), transparent 70%),
    radial-gradient(1.2px 1.2px at 93% 8%, rgba(247,237,231,.65), transparent 70%),
    radial-gradient(1px 1px at 74% 58%, rgba(247,237,231,.4), transparent 70%),
    radial-gradient(1px 1px at 12% 62%, rgba(247,237,231,.35), transparent 70%),
    radial-gradient(1.2px 1.2px at 58% 34%, rgba(247,237,231,.5), transparent 70%);
}
.ciel__astre {
  position: absolute; left: 66%; top: 30%;
  width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%;
  background: #FFF7EC;
  box-shadow: 0 0 10px 3px rgba(255, 240, 220, .9), 0 0 40px 12px rgba(255, 154, 60, .32);
  animation: scintille 4.6s ease-in-out infinite;
}
.ciel__astre::before, .ciel__astre::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  background: linear-gradient(90deg, transparent, rgba(255, 240, 220, .8), transparent);
  width: 64px; height: 1px; transform: translate(-50%, -50%);
}
.ciel__astre::after { transform: translate(-50%, -50%) rotate(90deg); }
@keyframes scintille { 50% { transform: scale(.82); opacity: .82; } }
.ciel__mire {
  position: absolute; left: 66%; top: 30%;
  width: clamp(96px, 9vw, 130px); height: auto;
  transform: translate(-50%, -50%);
  fill: none; stroke: rgba(247, 237, 231, .4); stroke-width: 1.2;
  transition: transform 1300ms cubic-bezier(.34, 1.4, .64, 1) 300ms, opacity 700ms ease 300ms;
}
.js-motion .ciel:not(.is-in) .ciel__mire { transform: translate(-50%, -50%) scale(1.7); opacity: 0; }
/* La légende sous la mire, centrée sur l'étoile. À droite de l'étoile, elle
   sortait de la case dès 1 024 px (case de 533 px de large). */
.ciel__legende {
  position: absolute; left: 66%; top: calc(30% + clamp(56px, 5.4vw, 76px));
  transform: translateX(-50%);
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; color: rgba(247, 237, 231, .72); white-space: nowrap;
}
/* La légende est en capitales : le α grec y devenait un Α, lu « A CARINAE ».
   Seule la lettre grecque échappe à la mise en capitales. */
.ciel__grec { text-transform: none; }
/* Sous le titre de section (--t-h2, 46 px en 1440) : à 52 px, le h3
   « Canopus » dépassait son propre h2. */
.ciel h3 { font-size: clamp(1.45rem, 2.9vw, 2.6rem); font-weight: 600; letter-spacing: -.04em; line-height: .96; }
@media (max-width: 520px) {
  .ciel__astre, .ciel__mire, .ciel__legende { left: 58%; }
}

/* 49.5  Le cap : la phrase dans sa case sombre, la mire graduée à droite qui tourne
   en une minute — à peine vue, comme une bague de mise au point. Au rang des
   autres h2 (46 px), un cran au-dessus parce que c'est une phrase-manifeste,
   mais sous le nom (70 px). */
.cap__q {
  display: flex; align-items: center;
  min-height: clamp(220px, 21vw, 320px);
  padding: clamp(30px, 4.4vw, 72px);
}
.cap__mire {
  position: absolute; right: clamp(-60px, -3vw, -20px); top: 50%;
  width: clamp(200px, 25vw, 360px); height: auto; transform: translateY(-50%);
  fill: none; stroke: rgba(247, 237, 231, .2); stroke-width: 1.2; pointer-events: none;
}
.cap__mire .graduation {
  stroke: rgba(255, 154, 60, .45); stroke-width: 6; stroke-dasharray: 1.2 8.4;
  transform-box: fill-box; transform-origin: center;
  animation: bague 60s linear infinite;
}
@keyframes bague { to { transform: rotate(360deg); } }
/* Serré à -.04em, les mots se touchaient (« Jenecherchepasuntitre ») : la
   phrase se lisait comme un bloc. Approche et espace entre les mots rouverts. */
.cap__t {
  position: relative;
  font-size: clamp(1.8rem, 3.5vw, 3.2rem); font-weight: 600; color: #FBF4EF;
  letter-spacing: -.022em; word-spacing: .06em; line-height: 1.08; max-width: 20ch;
}
.cap__t em { font-style: normal; color: var(--mand); }
/* Les trois cases de valeurs sous la phrase (« Le cadre d'abord »,
   « M'entourer », « Me remettre en question ») ont été retirées après la
   critique du 13/09/2026 : c'était le seul bloc interchangeable de la page,
   placé juste avant le devis. Tristan a choisi de garder la phrase seule. */

/* 49.6  Ce que je filme : le pont entre l'histoire et le devis. Les cartes
   des pages métier, à trois. Une seule colonne sous 900 px : à deux, la
   troisième carte restait orpheline sur tablette. */
/* Un vrai titre de section, à la taille des autres (--t-h2). En étiquette
   mono de 11,5 px, juste après la phrase du cap à 50 px, il se lisait comme
   une légende et la nouvelle section passait inaperçue (critique du 13/09). */
.pont__t { font-size: var(--t-h2); margin-bottom: clamp(24px, 3vw, 44px); }
.xnav--trois { grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .xnav--trois { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.xnav__d { display: block; margin-top: 6px; max-width: 32ch; color: var(--ink-2); font-size: .95rem; line-height: 1.5; }

@media (prefers-reduced-motion: reduce) {
  .vis i, .fiche__ph img, .fiche__c > *, .fiche__dl > div,
  .regard__pl, .regard__rep i, .regard__e h3, .regard__e h3::before,
  .regard.is-pilote .regard__etapes::after { transition: none; }
  .regard__tl b, .regard__alt > span, .regard__roue-in,
  .regard__drone, .regard__drone .helice, .ciel__astre, .cap__mire .graduation { animation: none; }
  .regard__media video, .tuile, .ciel__mire { transition: none; }
}
