/* ============================================================
   Terrain & Neige (démo LuxAura) — Aménagement, excavation et déneigement
   Maquette d'avance LuxAura Studio (18 août 2026) — 3 pages, UNE identité.

   MODE COPIE : structure, patrons de performance et CSS repris de
   maquettes/entreprise-sme-deneigement/ (fondation DOUBLE-SERVICE, elle-même
   copie de Roger V2). Ce qui change ici : la PALETTE (vert lime et noir de SA
   publicité au lieu de l'orange machinerie de la fondation), la disparition de
   TOUTE photo (aucune page Facebook propre, aucune image exploitable : les
   emplacements photo deviennent des aplats dégradés avec pictogramme, jamais
   une fausse photo de son entreprise), et le retrait des sections qui vivaient
   de faits propres à la fondation (témoignage, flotte, contenu de contrat).

   ── PALETTE, et d'où vient chaque valeur ──
   Ancres relevées sur SA publicité, vue dans le groupe Facebook « La Conception
   public » (13 août 2026) : vert lime #bad181 (haut du dégradé de ses bandeaux),
   vert foncé #435c20 (bas du dégradé), noir #1a1a1a (encadrés), blanc cassé
   #f2f3f0 (fonds et textes). Contrastes CALCULÉS (WCAG 2.1), pas jugés à l'œil :

     --encre  #f2f3f0  sur le fond  → 15,6:1  (texte courant)
     --note   #c6cbbc  sur le fond  → 10,5:1  (texte secondaire)
     --sable  #bad181  sur le fond  → 11,4:1  (TOUT le texte d'accent)
     --sable-clair #d3e3a9          → 14,0:1  (survol des liens)
     --terre  #435c20  sur le fond  →  2,3:1  ✗ SOUS le seuil de 4,5:1
                                       → DÉCOR SEULEMENT (filets, aplats,
                                         chiffres géants en filigrane),
                                         JAMAIS de texte à lire.
     --rouge  #435c20  : blanc dessus → 7,5:1 ✓ (aplats seulement)
     --rouge-clair #d3e3a9 sur le fond → 14,0:1 ✓ (accent secondaire)

   Le bouton plein prend le VERT LIME en fond avec le noir de sa pub dessus
   (11,4:1) : exactement le rapport de ses propres bandeaux.

   ── Deux ambiances, un seul site ──
   Même typo, même barre, même grille, même grammaire sur les 3 pages.
   La page Déneigement pose `body.hiver`, qui APPROFONDIT les trois fonds au
   lieu de les bleuir : le bleu n'existe nulle part dans sa publicité, on ne
   l'invente pas. Le lime traverse la saison, et c'est ce qui garde l'hiver
   dans la même maison que l'été.
   ============================================================ */

/* ---------- Racine fluide ACCESSIBLE ----------
   1rem = 10 px @1728px, suit le réglage de police du navigateur (WCAG 1.4.4).
   Le vw sec (0.5787vw) casserait ce réglage. */
html { font-size: clamp(0.611rem, 0.3125rem + 0.29vw, 0.72rem); }
@media (max-width: 991px) { html { font-size: clamp(0.611rem, 0.3125rem + 0.42vw, 0.72rem); } }
@media (max-width: 767px) { html { font-size: clamp(0.6rem, 0.47rem + 0.6vw, 0.72rem); } }
/* Les min des clamp garantissent les planchers CLAUDE.md en px RÉELS
   (corps ≥ 16 px mobile / ≥ 17,6 px desktop), quelle que soit la fenêtre. */

:root {
  /* ── Les trois fonds (du plus clair au plus profond) ── */
  --neige: #1a1a1a;    /* [USAGE : fond général de la page · fond des cartes] — le noir de ses encadrés */
  --glace: #212421;    /* [USAGE : fonds de section surélevés · loader] */
  --glace-2: #272b25;  /* [USAGE : cartes posées sur --glace] */
  --glace-3: #2e3329;  /* [USAGE : réserve] */
  --nuit: #101210;     /* [USAGE : fonds les plus profonds — héros · pied de page] */
  --encre: #f2f3f0;    /* [USAGE : tout le texte principal] — 15,6:1 — le blanc cassé de sa pub */
  --note: #c6cbbc;     /* [USAGE : textes secondaires · légendes · kickers] — 10,5:1 */
  --bord: rgba(var(--rgb-encre), 0.14);      /* [USAGE : bordures fines · séparateurs] */
  --bord-fort: rgba(var(--rgb-encre), 0.36); /* [USAGE : bordures boutons · champs] */

  /* ── Composantes RVB des fonds et de l'encre ──
     Elles servent aux voiles et aux ombres plus bas : une seule source de
     vérité, aucune couleur en dur dans les dégradés. */
  --rgb-nuit: 16, 18, 16;     /* = --nuit */
  --rgb-nuit-hiver: 10, 12, 10; /* = --nuit en ambiance hiver */
  --rgb-encre: 242, 243, 240; /* = --encre */
  --rgb-noir: 26, 26, 26;     /* = --neige */
  --rgb-lime: 186, 209, 129;  /* = --sable (le vert lime de sa pub) */
  --rgb-terre: 67, 92, 32;    /* = --terre (le vert foncé de sa pub) */

  /* ── Accents : le dégradé vert lime de ses bandeaux publicitaires ── */
  --sable: #bad181;       /* 11,4:1 — [USAGE : TOUT le texte d'accent] — haut de son dégradé */
  --sable-clair: #d3e3a9; /* 14,0:1 — [USAGE : survol des liens texte] */
  --terre: #435c20;       /* 2,3:1 — [USAGE : DÉCOR seulement : filets, chiffres en filigrane] — bas de son dégradé */
  --rouge: #435c20;       /* blanc dessus 7,5:1 — [USAGE : aplats, jamais de texte dessus le fond] */
  --rouge-clair: #d3e3a9; /* 14,0:1 — [USAGE : accent secondaire lisible] */
  --phare: #d3e3a9;       /* [USAGE : halos et lueurs] */

  /* ── Alias hérités de la référence Roger V2 ──
     Les règles de section copiées plus bas parlent encore en « rose »,
     « vert-f », « jaune ». On les REBRANCHE ici au lieu de renommer 900
     lignes : un alias par rôle, aucune couleur nouvelle. */
  --rose: var(--sable);        /* fond des boutons pleins · bandeau défilant */
  --rose-f: var(--sable-clair);/* survol des boutons pleins */
  --vert-f: var(--sable);      /* TOUT le texte d'accent */
  --vert-n: var(--sable-clair);/* survol des liens texte */
  --vert: var(--rouge-clair);  /* accent secondaire */
  --jaune: var(--sable);       /* anneaux de focus */
  --jaune-2: var(--terre);
  --rouge-f: #2b3a14;   /* vert foncé assombri — [USAGE : aplats pressés/survolés] */
  --brique: var(--rouge);

  /* ── Typo d'INSTRUMENT (auto-hébergée, aucune Google Fonts) ── */
  /* Choix de Yannick dans la tweak bar, 7 sept. 2026 (code or/3/2) : Space
     Grotesk en titres (graisse 700 synthétisée, le woff2 est en 400), Jost
     pour le texte ET pour les rôles mono (les paragraphes vivaient en Geist Mono). */
  --police-titre: 'Space Grotesk', 'Inter', system-ui, sans-serif;
  --police-corps: 'Jost', Futura, 'Century Gothic', system-ui, sans-serif;
  --police-mono: 'Jost', Futura, 'Century Gothic', system-ui, sans-serif;
  --h1-min: 4.88rem;
  --h1-max: 8.88rem;
  --h1-graisse: 700;
  --h1-interlettre: -0.025em;
  --fs-corps: 2.63rem;  /* ≈ 18 px réels @1728 */
  --fs-note: 2.85rem;
  --fs-ui: 2.58rem;
  --fs-badge: 2rem;

  /* ── Layout ── */
  --pad-container: 1.93rem;
  --col-gap: 3.6rem;
  --radius: 1.97rem;
  --bord-1: max(1px, 0.1rem);
}

/* ── ACCENT PAR PAGE (choix de Yannick dans la tweak bar, 7 sept. 2026) ──
   Or sur l'accueil, vert forêt sur Aménagement, bleu glacier sur Déneigement.
   Posé sur html[data-page] (donc sur :root) : les alias --rose/--vert-f/…
   déclarés var(--sable) plus haut suivent sans être redéclarés. */
html[data-page="accueil"] {
  --sable: #e8b84b; --sable-clair: #f0c96f; --terre: #6b5320; --rouge: #6b5320;
  --rouge-clair: #f0c96f; --rouge-f: #4c3b17; --phare: #f6e6bf;
  --rgb-lime: 232, 184, 75; --rgb-terre: 107, 83, 32;
}
html[data-page="amenagement"] {
  --sable: #79c86a; --sable-clair: #a3dd96; --terre: #2f5233; --rouge: #2f5233;
  --rouge-clair: #a3dd96; --rouge-f: #213b25; --phare: #d5edcc;
  --rgb-lime: 121, 200, 106; --rgb-terre: 47, 82, 51;
}
html[data-page="deneigement"] {
  --sable: #5fb8e8; --sable-clair: #93d3f5; --terre: #2f4f66; --rouge: #2f4f66;
  --rouge-clair: #93d3f5; --rouge-f: #22394a; --phare: #cfe8f7;
  --rgb-lime: 95, 184, 232; --rgb-terre: 47, 79, 102;
}

/* ── AMBIANCE HIVER (page Déneigement seulement) ──
   Seuls les trois FONDS bougent, et ils s'APPROFONDISSENT au lieu de bleuir :
   aucun bleu n'existe dans sa publicité, on n'en invente pas un. Le lime
   traverse la saison, sinon on aurait deux sites au lieu de deux ambiances.
   Fonds plus sombres = contrastes tous plus hauts que sur l'accueil. */
body.hiver {
  --neige: #121412;
  --glace: #191c18;
  --glace-2: #1f231d;
  --nuit: #0a0c0a;
  --rgb-nuit: var(--rgb-nuit-hiver);
}

@media (max-width: 767px) {
  :root { --pad-container: 1.93rem; } /* aligné sur le réglage Yannick */
}

/* ---------- Polices auto-hébergées (bibliothèque Awwwards, OFL) ----------
   Aucune Google Fonts externe (règle CLAUDE.md) : 3 woff2 servis en local,
   41 Ko au total, contre 42 Ko pour les deux polices de la V1. */
@font-face {
  font-family: 'Space Grotesk';
  src: url('../fonts/space-grotesk.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Jost';
  src: url('../fonts/jost.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Anton';
  src: url('../fonts/anton.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
/* Repli MÉTRIQUE d'Anton (repris tel quel de la démo Roger V2, calibré au
   navigateur le 25 août 2026 : Anton 1415 px / boîte 151 px sur la chaîne
   témoin ; size-adjust 95 % → 1417 px, ascent 134 % + descent 25 % → 151 px).
   Impact est le seul repli local assez condensé — Arial Narrow est ~47 % plus
   large et ferait sauter la mise en page pendant le `swap`.
   Ce @font-face ne télécharge RIEN : il habille une police déjà installée. */
@font-face {
  font-family: 'Anton Repli';
  src: local('Impact'), local('Arial Narrow'), local('ArialNarrow');
  size-adjust: 95%;
  ascent-override: 134%;
  descent-override: 25%;
  line-gap-override: 0%;
  font-display: swap;
}
@font-face {
  font-family: 'Geist';
  src: url('../fonts/geist.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
}
@font-face {
  font-family: 'Geist Mono';
  src: url('../fonts/geist-mono.woff2') format('woff2');
  font-weight: 400 600;
  font-display: swap;
}

/* ---------- Reset court ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
img, svg, video, canvas { display: block; max-width: 100%; }
button { font: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; }
ul, ol { list-style: none; }

/* Le clip sur body seul laissait la boîte de défilement de html s'élargir :
   sur téléphone la page glissait latéralement (débordement du héros — attrapé
   au test du 4 août). Les deux niveaux doivent clipper. */
html { overflow-x: clip; }
body {
  font-family: var(--police-corps);
  font-size: var(--fs-corps);
  line-height: 1.62;
  color: var(--encre);
  background: var(--neige);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* ---------- Échelle de titres (patron United : uppercase, lh 1.05) ---------- */
.h0, .h1, .h2, .h3, .h4, h1, h2, h3 {
  font-family: var(--police-titre);
  font-weight: var(--h1-graisse);
  text-transform: uppercase;
  /* 1.05 (patron United) clippait les accents FRANÇAIS : le É de RÉSIDENTIEL
     touchait le kicker au-dessus (retour Yannick 3 août). L'anglais n'a pas
     d'accents ; le français exige plus d'air au-dessus des capitales. */
  line-height: 1.14;
  letter-spacing: var(--h1-interlettre);
}
.kicker + h1, .kicker + h2, .kicker + h3, .kicker + .h4 { margin-top: 1.4rem; }
/* Échelle redescendue d'un cran : la titraille condensée porte beaucoup plus large que
   Playfair, et les titres de la séquence horizontale débordaient de leur
   panneau de 100vw. */
.h0 { font-size: 14.43rem; }
h1, .h1 { font-size: clamp(var(--h1-min), 8.88vw, var(--h1-max)); }
h2, .h2 { font-size: 6.22rem; }
h3, .h3 { font-size: 4.33rem; }
.h4 { font-size: 3.44rem; }
@media (max-width: 991px) {
  .h0 { font-size: 8.6rem; }
  h2, .h2 { font-size: 4.66rem; }
  h3, .h3 { font-size: 3.44rem; }
}

/* V2 : tous les kickers passent en mono — étiquette d'instrument, pas titre. */
.kicker {
  font-family: var(--police-mono);
  font-size: var(--fs-badge);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--note);
}
/* Le trait court devant l'étiquette : repère de relevé, emprunté au patron
   United Carriers (leurs libellés de section portent le même). */
.kicker::before {
  content: ''; display: inline-block; width: 2.4rem; height: 1px;
  margin-right: 1.2rem; vertical-align: 0.35em; background: var(--vert-f);
}
.note { font-size: var(--fs-note); color: var(--note); }

/* ---------- Grille 16 colonnes full-bleed (patron United) ---------- */
.grille {
  display: grid;
  grid-template-columns:
    [pleine-deb] minmax(var(--pad-container), 1fr)
    [contenu-deb] repeat(16, minmax(0, 8.4rem))
    [contenu-fin] minmax(var(--pad-container), 1fr)
    [pleine-fin];
  column-gap: var(--col-gap);
}
.grille > * { grid-column: contenu-deb / contenu-fin; }
.pleine { grid-column: pleine-deb / pleine-fin; }

section { position: relative; }
/* Chaque section RÉ-ÉVALUE la couleur de texte localement : sans ça, la
   couleur héritée de body resterait figée et la vue « par section » de la
   tweaks bar ne pourrait pas re-teinter le texte d'UNE seule section. */
header.nav, main > [id], .piste-hiver [id] { color: var(--encre); }
/* (#pourquoi et footer.pied redéclarent déjà la leur plus bas — même effet) */
.section-pad { padding-block: 12rem; }
@media (max-width: 767px) { .section-pad { padding-block: 7rem; } }

/* ---------- Boutons (plat, prononcé) ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  padding: 1.6rem 3rem;
  font-size: var(--fs-ui);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: var(--radius);
  border: var(--bord-1) solid transparent;
  transition: background-color 0.3s, color 0.3s, border-color 0.3s, transform 0.3s;
  min-height: 4.4rem;
}
.btn:active { transform: translateY(1px); }
/* Le bouton plein est le SEUL aplat de sable qui porte du texte. Le sable est
   CLAIR : c'est donc l'encre foncée qui passe dessus (7,35:1). L'inverse —
   blanc sur sable — ne donnait que 2,42:1 : calculé, puis écarté. */
.btn-plein { background: var(--rose); color: var(--neige); }
/* Survol vers le PLUS CLAIR (l'inverse de la référence, dont l'accent était
   sombre) : #d9c0a1 sous l'encre foncée remonte à 10,15:1. */
.btn-plein:hover { background: var(--rose-f); color: var(--neige); }
.btn-contour { border-color: var(--bord-fort); color: var(--encre); }
.btn-contour:hover { border-color: var(--encre); }

/* ---------- Utilitaires ---------- */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.sep-congere { width: 100%; height: auto; color: var(--glace); }

/* ============================================================
   SECTIONS
   ============================================================ */

/* ---------- S0 Loader ---------- */
#chargement {
  position: fixed; inset: 0; z-index: 90;
  background: var(--nuit);
  display: flex; align-items: flex-end; justify-content: space-between;
  padding: var(--pad-container);
}
#chargement .chargement-compteur {
  font-family: var(--police-mono); color: var(--vert-f); line-height: 1;
}
.chargement-secteurs {
  display: flex; flex-direction: column; gap: 0.6rem; overflow: hidden;
  height: 3em; text-align: right; font-family: var(--police-mono); font-size: var(--fs-ui);
  text-transform: uppercase; letter-spacing: 0.18em; color: var(--note);
}
/* Ligne d'horizon qui se remplit pendant le décompte : on voit la route se
   dégager, ce n'est pas juste une attente. */
#chargement::after {
  content: ''; position: absolute; left: var(--pad-container); right: var(--pad-container);
  bottom: calc(var(--pad-container) - 1rem); height: 1px; background: var(--bord);
}

/* ---------- Nav ---------- */
/* V2 : la barre ne pose plus un bandeau opaque sur la photo du héros. Elle est
   transparente en haut de page et se voile dès qu'on défile (classe .nav-fond
   posée par premium.js). */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; gap: 2rem;
  padding: 1.8rem var(--pad-container);
  background: transparent;
  border-bottom: var(--bord-1) solid transparent;
  transition: background-color 0.4s, border-color 0.4s, backdrop-filter 0.4s;
}
/* Voile de tête, tant que la barre n'a pas pris son fond (QA 18 août) :
   mesuré sur la photo d'été de l'accueil, le logo orange tombait à 1,22:1 et
   les liens blancs à 3,06:1 sur le ciel. Le dégradé remonte le logo à ~5,5:1
   et les liens à ~13:1, sans poser de barre pleine sur la photo. */
.nav::before {
  content: ''; position: absolute; inset: 0 0 -4rem 0; z-index: -1;
  pointer-events: none; transition: opacity 0.4s;
  background: linear-gradient(to bottom,
    rgba(var(--rgb-nuit-hiver), 0.85) 0%, rgba(var(--rgb-nuit-hiver), 0.72) 55%, rgba(var(--rgb-nuit-hiver), 0) 100%);
}
.nav.nav-fond::before { opacity: 0; }
.nav.nav-fond {
  background: color-mix(in srgb, var(--nuit) 94%, transparent);
  /* 19 août 2026 : backdrop-filter retiré (recomposition GPU plein écran sur nav fixe — bug Fournel ; nav 94 % opaque, retrait sans effet visuel) */
  border-bottom-color: var(--bord);
}
/* « TERRAIN & NEIGE » (héritage : le nom long de la fondation passait sur deux
   lignes à 1280 px et écraserait les liens. Un cran plus bas + nowrap, et il
   tient. En petite largeur, le mot générique tombe (voir la media query). */
.nav-logo {
  /* max() : 1,7rem d'une racine rescalée ne rendait que 16,6 px, sous le
     plancher desktop de 17,6 px de CLAUDE.md. */
  font-family: var(--police-titre); font-size: var(--fs-ui); letter-spacing: 0.02em; /* même taille que les liens (demande Yannick, 7 sept.) */
  text-decoration: none; text-transform: uppercase; white-space: nowrap;
}
.nav-logo span { color: var(--vert-f); }
.nav nav { display: flex; align-items: center; gap: 2.8rem; }
.nav-liens { display: flex; align-items: center; gap: 2.8rem; }
.nav nav a:not(.btn) {
  font-family: var(--police-mono);
  font-size: var(--fs-ui); font-weight: 500; text-decoration: none;
  letter-spacing: 0.12em; text-transform: uppercase;
}
/* Le bouton du menu n'existe qu'en petite largeur (voir la media query). */
.nav-burger { display: none; }
.nav nav a:not(.btn):hover { color: var(--vert-f); }
.nav-cta { padding: 1rem 2rem; min-height: 0; }
/* ---------- Menu mobile ----------
   Jusqu'au 7 août, les trois liens étaient simplement masqués sous 768 px :
   sur téléphone, on ne pouvait atteindre Prix, Secteurs et Questions qu'en
   faisant défiler toute la page. Le panneau ci-dessous les rend cliquables. */
@media (max-width: 991px) {
  /* 991 et non 767 : entre 768 et 991, la nav complète
     débordait — logo sur « SERVICES », bouton Soumission coupé (vu à 820). */
  /* À 390 px, le nom complet + le bouton + le burger débordent : « PAYSAGISTE »
     tombe, le NOM reste lisible. */
  .nav-logo { font-size: 1.5rem; }
  .nav-logo .nav-long { display: none; }
  .nav-burger {
    display: inline-flex; flex-direction: column; justify-content: center;
    gap: 0.5rem; width: 4.4rem; height: 4.4rem; padding: 1rem;
    border: var(--bord-1) solid var(--bord); border-radius: var(--radius);
  }
  .nav-burger span {
    display: block; height: max(2px, 0.2rem); width: 100%;
    background: var(--encre); border-radius: 1px;
    transition: transform 0.28s, opacity 0.2s;
  }
  /* Trois barres qui deviennent une croix : l'état ouvert doit se voir. */
  .nav-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(0.7rem) rotate(45deg); }
  .nav-burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .nav-burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-0.7rem) rotate(-45deg); }

  .nav nav { gap: 1.2rem; }
  .nav-liens {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: color-mix(in srgb, var(--nuit) 96%, transparent);
    backdrop-filter: blur(14px);
    border-bottom: var(--bord-1) solid var(--bord);
    /* Fermé = replié à zéro, sans display:none : la transition reste possible
       et le contenu sort du parcours de tabulation grâce à visibility. */
    max-height: 0; overflow: hidden; visibility: hidden;
    transition: max-height 0.32s ease, visibility 0.32s;
  }
  .nav.menu-ouvert .nav-liens { max-height: 60vh; visibility: visible; }
  .nav-liens a {
    padding: 2rem var(--pad-container);
    border-top: var(--bord-1) solid var(--bord);
  }
}

/* ---------- S1 Héros + carte ---------- */
.hero {
  min-height: 100svh; align-items: center; padding-top: 12rem; padding-bottom: 6rem;
  overflow: clip; background: var(--nuit);
}
/* Photo plein cadre : elle porte l'ambiance, jamais la lecture. Le voile est
   assez fort pour garder le H1 à 12:1 même sur la partie la plus claire de
   l'image (la neige au soleil). */
/* pleine-deb/pleine-fin : dans une grille, un enfant absolu s'ancre sur SA zone
   de grille — sans ça la photo restait dans les marges de contenu. Hauteur
   bornée au premier écran : c'est là que la machine doit être vue. */
.hero-fond {
  position: absolute; grid-column: pleine-deb / pleine-fin;
  inset: 0 0 auto 0; height: 100svh; z-index: 0; overflow: clip;
}
.hero-fond img {
  /* Verdict Yannick 18 août : la photo héros se montre NUE — aucun filtre.
     Le contraste vit sur le texte (scrim local + ombre portée), voir ::after.
     Chaque page repose object-position à sa photo (voir plus bas). */
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%;
}
/* Le scrim vit SEULEMENT du côté du texte et meurt avant le sujet ; petits
   fondus haut (nav) et bas (transition). Le reste de la photo est nu. */
/* ⚠️ Jamais `transparent` dans ces dégradés : en CSS il vaut rgba(0,0,0,0),
   donc l'interpolation traverse du NOIR et éteint la photo — c'est ce qui a
   fait disparaître la machine deux fois le 7 août. On écrit la couleur du
   voile en alpha 0 (rgba(var(--rgb-nuit),0)) pour que la transition reste propre. */
.hero-fond::after {
  content: ''; position: absolute; inset: 0;
  background:
    /* Le palier de 30 % laissait la fin des lignes de texte sur la crête de
       neige et la lame jaune (3,6-4,2:1 mesurés en QA le 18 août) : le voile
       tient maintenant jusqu'à 34 % et meurt à 62 %. Le SUJET (la machine,
       au-delà de 60 %) reste nu — c'est le verdict « photo nue » de Yannick. */
    linear-gradient(100deg,
      rgba(var(--rgb-nuit), 0.90) 0%, rgba(var(--rgb-nuit), 0.74) 34%,
      rgba(var(--rgb-nuit), 0) 62%),
    linear-gradient(to bottom, rgba(var(--rgb-nuit), 0.65) 0%, rgba(var(--rgb-nuit), 0) 15%),
    linear-gradient(to top, rgba(var(--rgb-nuit), 0.88) 0%, rgba(var(--rgb-nuit), 0) 15%);
}
/* 11 colonnes et non 9 : les titres de héros finissent par un POINT, et
   `.ligne { overflow: hidden }` (nécessaire au masque du SplitText) coupait
   net ce point sur « LA PELLE ARRIVE. » à 1440 px. Le titre est mesuré, pas
   deviné : 16 signes de titraille condensée à 79 px font ~784 px, contre ~780 px
   de colonne utile en span 9. Deux colonnes de plus, et la ponctuation
   rentre à toutes les largeurs. */
.hero-texte { grid-column: contenu-deb / span 11; position: relative; z-index: 3; }
.hero-h1 .ligne { display: block; overflow: hidden; white-space: nowrap; }
.hero-h1 { font-size: clamp(var(--h1-min), 5.77vw, var(--h1-max)); }
/* Le texte du héros passe sur une photo dont la neige est claire : ombre
   portée douce pour tenir la lisibilité partout, quel que soit le cadrage. */
.hero-texte .kicker, .hero-h1, .hero-sous {
  text-shadow: 0 0.1rem 0.5rem rgba(var(--rgb-nuit), 0.92), 0 0.3rem 2rem rgba(var(--rgb-nuit), 0.7);
}
.hero-sous {
  margin-top: 2.4rem; font-family: var(--police-mono); font-size: var(--fs-note);
  color: rgba(var(--rgb-encre), 0.88); letter-spacing: 0.02em;
  /* La ligne courait jusqu'à 62 % de la largeur, donc PAST le voile (qui meurt
     à 58 %) : sur la lame jaune du héros hiver, la fin de phrase tombait à
     4,1:1 (mesuré en QA le 18 août). Bornée, elle reste dans la zone voilée
     et la photo garde son cadrage nu. */
  max-width: 62rem;
}
.hero-cta { display: flex; flex-wrap: wrap; gap: 1.6rem; margin-top: 3.6rem; }

/* Héros déneigement : photo pleine résolution fournie par Yannick le 18 août
   (originaux FB 1536×2048, les DEUX tracteurs dans la neige) — plein cadre
   sans agrandissement, traitement standard. Le panneau divisé essayé plus tôt
   n'est plus nécessaire ; l'alternative reste notée au vault si une photo
   trop petite revient. */
body.hiver .hero-fond img { object-position: 55% 55%; }
@media (max-width: 767px) {
  /* Le ciel blanc de la photo neige passe sous le kicker : léger voile
     continu en haut (0,18-0,28 — la photo reste visible), assise inchangée. */
  body.hiver .hero-fond::after {
    background:
      linear-gradient(to bottom, rgba(var(--rgb-nuit-hiver), 0.72) 0%, rgba(var(--rgb-nuit-hiver), 0.28) 18%,
                      rgba(var(--rgb-nuit-hiver), 0.18) 34%, rgba(var(--rgb-nuit-hiver), 0.65) 48%,
                      rgba(var(--rgb-nuit-hiver), 0.9) 66%, rgba(var(--rgb-nuit-hiver), 0.96) 100%);
  }
}

/* Relevé de la nuit — le métier parle en mesures, la typo mono le dit. */
.hero-releve {
  display: flex; flex-wrap: wrap; gap: 0 5rem; margin-top: 5rem;
  padding-top: 2.4rem; border-top: var(--bord-1) solid var(--bord);
  font-family: var(--police-mono);
}
.hero-releve dt {
  font-size: var(--fs-badge); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--note);
}
.hero-releve dd { margin-top: 0.5rem; font-size: 3.2rem; color: var(--vert-f); }
@media (max-width: 767px) {
  .hero-releve { gap: 0 3rem; margin-top: 3.4rem; }
  .hero-releve dd { font-size: 2.6rem; }
}

@media (max-width: 991px) {
  .hero { padding-top: 12rem; }
  .hero-texte { grid-column: contenu-deb / contenu-fin; }
  /* Empilé, le héros dépasse un écran : la photo couvre les deux tiers hauts
     et se fond dans la nuit, au lieu de s'arrêter net au milieu du texte. */
  .hero-fond { height: 78svh; }
}
@media (max-width: 767px) {
  /* « Chaque entrée » en nowrap à la taille desktop débordait de l'écran :
     la titraille condensée demande sa propre échelle en petite largeur. */
  /* 8,4vw et non 8,8 (18 août) : le point final de « LA PELLE RENTRE. »
     frôlait le bord à 390 px (16 signes, .ligne coupe en overflow:hidden). */
  .hero-h1 { font-size: clamp(3.22rem, 9.32vw, 5.11rem); }
  .hero-fond img { object-position: 62% 62%; }
  /* Mobile : photo dégagée dans le haut de l'écran, assise sombre sous le
     bloc texte seulement. */
  .hero-fond::after {
    background:
      linear-gradient(to bottom, rgba(var(--rgb-nuit), 0.72) 0%, rgba(var(--rgb-nuit), 0.12) 16%,
                      rgba(var(--rgb-nuit), 0) 30%, rgba(var(--rgb-nuit), 0.6) 46%,
                      rgba(var(--rgb-nuit), 0.88) 66%, rgba(var(--rgb-nuit), 0.96) 100%);
  }
}

/* ---------- S2 Intro 2 temps ---------- */
.intro-bloc { grid-column: contenu-deb / span 13; }
.intro-l1 { color: var(--note); }
.intro-l2 { color: var(--encre); }
.intro-p { max-width: 62rem; margin-top: 3.2rem; }

/* ---------- S3 Chiffres ---------- */
.chiffres-grille {
  grid-column: contenu-deb / contenu-fin;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--col-gap);
  border-top: var(--bord-1) solid var(--bord);
}
.chiffre { padding-top: 3rem; border-right: var(--bord-1) solid var(--bord); padding-right: 2rem; }
.chiffre:last-child { border-right: 0; }
.chiffre-val { color: var(--vert-f); }
.chiffre-lib { font-size: var(--fs-note); color: var(--note); max-width: 24rem; }
@media (max-width: 767px) {
  .chiffres-grille { grid-template-columns: 1fr; }
  .chiffre { border-right: 0; border-bottom: var(--bord-1) solid var(--bord); padding-bottom: 2rem; }
  .chiffre:last-child { border-bottom: 0; }
}

/* ---------- S2-S4 : la séquence (blizzard + écrans) ----------
   Depuis le 4 août 2026, la zone intro → services vit dans .piste-hiver
   (séquence HORIZONTALE desktop, bloc dédié plus bas). Les règles ici sont
   le SOCLE commun + le repli vertical (mobile, tier statique, sans JS). */
/* ⚠️ TOUTES les règles #services héritées de Roger V2 sont scopées à
   body.hiver. La page Excavation utilise le MÊME id pour son ancre de nav,
   et sans ce garde-fou elle héritait du `display:flex` de la séquence
   horizontale : ses quatre sections 01-04 se rangeaient côte à côte et la
   page faisait 4 écrans de large (vu au navigateur le 18 août). */
body.hiver #services { background: var(--glace); }
.blizzard {
  position: absolute; inset: 0; z-index: 0; overflow: clip; pointer-events: none;
}
.blizzard canvas { position: sticky; top: 0; width: 100%; height: 100vh; }
.neige-arriere { filter: blur(2.5px); }
.neige-avant { margin-top: -100vh; }
.ecran {
  min-height: 100vh;
  display: flex; align-items: center;
  /* Voile RETIRÉ (verdict Yannick 18 août) : en défilement
     horizontal, le rectangle pâle de l'écran suivant entrait dans le cadre
     comme une bande qui glisse entre l'intro et les services. Le texte vit
     directement sur la nuit + blizzard. (Historique Roger : 88 % → 42 % le
     3 août, → 0 ici.) */
}
/* (Tracteur du défilement + route : retirés le 4 août au soir — stand-by.) */
.ecran-contenu { grid-column: contenu-deb / contenu-fin; padding-block: 10rem; width: 100%; }
.cartes-prix {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--col-gap);
  margin-top: 4rem;
}
.carte-prix {
  background: var(--neige); border: var(--bord-1) solid var(--bord);
  border-radius: var(--radius); padding: 3.2rem;
  transition: border-color 0.3s, transform 0.3s;
}
.carte-prix:hover { border-color: var(--bord-fort); transform: translateY(-0.4rem); }
.carte-desc { margin-top: 1.2rem; font-size: var(--fs-note); color: var(--note); }
.carte-montant { margin-top: 2.4rem; font-size: var(--fs-note); color: var(--note); }
/* Prix en jaune de lame (demande de Yannick, 7 août) : ils rejoignent les
   chiffres géants et les crochets, et deviennent le point de fixation de la
   section — c'est l'information qu'on vient y chercher. */
.carte-montant .prix {
  font-family: var(--police-titre); font-size: 4.2rem; color: var(--vert-f);
  margin-right: 0.6rem; letter-spacing: 0.01em;
}
/* Chez Roger la valeur était un montant court (« 385 $ ») ; ici c'est
   « sur mesure », qui cassait en deux dans une carte de téléphone
   (« sur » / « mesure »). Un cran plus bas sous 640 px et la mention tient
   sur une ligne (QA 18 août). */
@media (max-width: 640px) { .carte-montant .prix { font-size: 3.2rem; } }
.inclus-liste { margin-top: 4rem; max-width: 72rem; }
.inclus-liste li {
  padding: 2.2rem 0 2.2rem 4.4rem; position: relative;
  border-bottom: var(--bord-1) solid var(--bord);
  /* 19 août 2026 (propagation famille, verdict Yannick) : taille en dur → var(--fs-note), aligné sur les cartes de services. */
  font-size: var(--fs-note);
}
.inclus-liste li::before {
  content: ''; position: absolute; left: 0; top: 2.9rem;
  width: 2.4rem; height: 1.2rem;
  border-left: 0.35rem solid var(--vert-f); border-bottom: 0.35rem solid var(--vert-f);
  transform: rotate(-45deg);
}
@media (max-width: 991px) {
  /* minmax(0,1fr) et non 1fr : un 1fr nu prend la taille MIN-CONTENT de la
     carte, qui dépassait le conteneur de 21 px (mot long en titraille condensée). */
  .cartes-prix { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- S5 Pourquoi (nuit) ---------- */
/* V2 : --glace et --neige sont devenus des FONDS sombres — les sections nuit
   prennent maintenant --encre comme couleur de texte. */
#pourquoi { background: var(--nuit); color: var(--encre); overflow: clip; }
#pourquoi .inverse { color: var(--encre); }
#pourquoi .kicker.inverse { color: var(--note); }
.pourquoi-lueur {
  /* Règle maquettes du 19 août : pas de lueur radiale (héritage Roger/SME).
     Éteinte le 27 août — retirer le display:none pour la réactiver. */
  display: none;
  position: absolute; width: 70rem; height: 70rem; left: 60%; top: 30%;
  /* Lueur verte : le lime de ses bandeaux, très dilué. */
  background: radial-gradient(circle, rgba(var(--rgb-lime), 0.13), rgba(var(--rgb-lime), 0) 70%);
  animation: lueur-respire 14s ease-in-out infinite alternate;
  pointer-events: none;
}
@keyframes lueur-respire {
  from { opacity: 0.5; transform: translate(-2rem, 0); }
  to   { opacity: 1; transform: translate(2rem, -3rem); }
}
.pourquoi-tete { grid-column: contenu-deb / span 10; margin-bottom: 5rem; }
.pourquoi-liste { grid-column: contenu-deb / span 12; }
.pourquoi-liste li {
  display: flex; gap: 2.8rem; align-items: baseline;
  /* 19 août 2026 (propagation famille, verdict Yannick) : taille en dur → var(--fs-note), aligné sur les cartes de services. */
  padding: 2.6rem 0; font-size: var(--fs-note); line-height: 1.45;
  border-bottom: var(--bord-1) solid rgba(var(--rgb-encre), 0.14);
}
/* Numéros en jaune de lame (7 août) : le bleu de glace n'existait plus que
   ICI et sur le soulignement des liens de contact — un orphelin qui attirait
   l'œil sur des repères d'ordre. Le bleu reste vivant là où il a un sens :
   la carte des secteurs (flèches, pastilles, halo). */
.pourquoi-num {
  font-family: var(--police-mono); font-size: var(--fs-badge); font-weight: 500;
  letter-spacing: 0.18em; color: var(--vert-f); flex-shrink: 0;
}

/* ---------- S6 Marquee — EN OUTLINE (traitement Roger V3, 27 août 2026) ----------
   Le bandeau était un aplat de lime (--rose) portant du texte --neige. Il
   change de FORME plutôt que de couleurs : texte contour géant sur la nuit.
   Le contraste devient une propriété de la construction — lime --sable #bad181
   sur --nuit : 11,22:1 sur l'accueil et l'aménagement (#101210), 11,71:1 sur
   la page hiver (#0a0c0a). Aucune couleur de la palette ne change.
   Même défilement 30 s, même contenu, même doublon .sr-only. */
.marquee {
  background: var(--nuit); overflow: clip;
  padding: 1.8rem 0; border-block: var(--bord-1) solid var(--bord);
}
.marquee-piste {
  display: flex; white-space: nowrap; width: max-content;
  animation: defile 30s linear infinite;
  font-family: var(--police-titre);
  font-size: clamp(4.2rem, 6.4vw, 9rem);
  line-height: 1.08;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  /* FALLBACK, actif partout : lime PLEIN sur la nuit. Un navigateur sans
     -webkit-text-stroke lit ce bandeau parfaitement, au même ratio. */
  color: var(--vert-f);
}
/* Là où le trait existe (tous les moteurs modernes, préfixe -webkit- compris
   par Firefox), on vide le remplissage et on garde le contour. Le trait porte
   exactement la couleur du fallback : le ratio ne bouge pas d'un point. */
@supports (-webkit-text-stroke: 1px red) {
  .marquee-piste {
    color: transparent;
    -webkit-text-stroke: 0.19rem var(--vert-f);
  }
}
@keyframes defile { to { transform: translateX(-50%); } }

/* ---------- S7 Témoignages + passage du tracteur ---------- */
/* (padding-bottom 26rem retiré avec la traversée du tracteur, 4 août au soir) */
#temoignages { overflow: clip; }
.temoignages-grille {
  grid-column: contenu-deb / contenu-fin;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--col-gap);
  margin-top: 4rem;
}
.temoignage {
  border: var(--bord-1) solid var(--bord); border-radius: var(--radius);
  padding: 3.2rem; background: var(--neige);
}
.temoignage blockquote { margin-top: 1.6rem; font-size: 1.9rem; line-height: 1.55; }
.temoignage figcaption { margin-top: 2rem; font-size: var(--fs-note); color: var(--note); font-weight: 600; }
/* Un SEUL témoignage, parce qu'il n'y en a qu'un de RÉEL (publication
   Facebook du 13 août 2026). Les trois autres de la référence étaient
   fictifs : ils n'ont pas d'équivalent sourcé ici, donc ils n'existent pas. */
.temoignages-grille.une { grid-template-columns: minmax(0, 1fr); max-width: 96rem; }
.une .temoignage blockquote { font-size: 3.2rem; line-height: 1.4; }
@media (max-width: 767px) { .une .temoignage blockquote { font-size: 2.4rem; } }

/* Zone desservie — une seule ville, donc pas de liste ni de carte. */
.zone-p { grid-column: contenu-deb / span 10; margin-top: 3rem; }

.passage {
  position: absolute; bottom: 2rem; left: 0; right: 0; height: 18rem;
  pointer-events: none; overflow: visible;
}
.tracteur-passe {
  position: absolute; bottom: 0; left: 0; width: 26rem; height: auto;
  -webkit-mask-image: radial-gradient(ellipse 62% 70% at 50% 55%, #000 58%, transparent 92%);
          mask-image: radial-gradient(ellipse 62% 70% at 50% 55%, #000 58%, transparent 92%);
  will-change: transform;
}
.congere {
  position: absolute; bottom: 0; left: 0; width: 12rem; height: 5rem;
  background: radial-gradient(ellipse at 30% 100%, var(--neige) 55%, rgba(var(--rgb-noir), 0) 75%);
  transform-origin: left bottom; opacity: 0;
}
.panache { position: absolute; inset: 0; }
@media (max-width: 767px) {
  .temoignages-grille { grid-template-columns: 1fr; }
  .tracteur-passe { width: 17rem; }
}

/* ---------- S8 Équipement ---------- */
#equipement { background: var(--glace); }
.equipement-cartes {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--col-gap);
  padding: 5rem var(--pad-container) 0;
}
.equipement-carte {
  background: var(--neige); border: var(--bord-1) solid var(--bord);
  border-radius: var(--radius); overflow: clip;
}
.equipement-media { overflow: clip; aspect-ratio: 3 / 2; }
.equipement-media img { width: 100%; height: 100%; object-fit: cover; will-change: transform; }
.equipement-info { padding: 3.2rem; }
.equipement-specs { margin-top: 1.8rem; }
.equipement-specs li {
  padding: 1.1rem 0 1.1rem 2.6rem; position: relative;
  font-size: var(--fs-note); border-bottom: var(--bord-1) solid var(--bord);
}
.equipement-specs li:last-child { border-bottom: 0; }
.equipement-specs li::before {
  content: ''; position: absolute; left: 0.2rem; top: 1.9rem;
  width: 1.1rem; height: 0.55rem;
  border-left: 0.25rem solid var(--vert-f); border-bottom: 0.25rem solid var(--vert-f);
  transform: rotate(-45deg);
}
@media (max-width: 991px) { .equipement-cartes { grid-template-columns: minmax(0, 1fr); } }

/* ---------- Galerie 3 photos (variante de .equipement-cartes) ----------
   Sélecteur DOUBLE (.equipement-cartes.galerie-3) : la règle de base et la
   media query ci-dessus sont déjà passées, une classe seule ne les battrait
   pas de façon fiable. */
.equipement-cartes.galerie-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.galerie-3 .equipement-media { aspect-ratio: 4 / 3; }
.galerie-3 figcaption {
  padding: 2rem 2.4rem 2.4rem; font-size: var(--fs-note); color: var(--note);
}
@media (max-width: 991px) {
  .equipement-cartes.galerie-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .equipement-cartes.galerie-3 { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- S1b · L'équipe (section vedette, juste sous le héros) ---------- */
#equipe { background: var(--glace); }
.equipe-flex {
  grid-column: contenu-deb / contenu-fin;
  display: grid; grid-template-columns: 1.1fr 1fr;
  gap: var(--col-gap); align-items: center;
}
.equipe-media {
  overflow: clip; border-radius: var(--radius);
  border: var(--bord-1) solid var(--bord); aspect-ratio: 6 / 5;
}
.equipe-media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; }
.equipe-texte p { margin-top: 2.4rem; }
.equipe-texte .btn { margin-top: 3.4rem; }
@media (max-width: 991px) { .equipe-flex { grid-template-columns: minmax(0, 1fr); } }


/* ---------- S9 Secteurs + carte des 8 secteurs ---------- */
.secteurs-flex {
  grid-column: contenu-deb / contenu-fin;
  display: grid; grid-template-columns: 5fr 7fr; gap: var(--col-gap);
  align-items: center; margin-top: 5rem;
}
.secteurs-liste { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem 2rem; }
.secteurs-liste li {
  font-family: var(--police-titre); font-size: 2.8rem; text-transform: uppercase;
  padding: 1rem 0; border-bottom: var(--bord-1) solid var(--bord);
}
/* (Le radar décoratif a été SUPPRIMÉ en V2 : la vraie carte des 8 secteurs
   prend sa place — un objet qui dit quelque chose au lieu d'un ornement.) */
.secteurs-note { grid-column: contenu-deb / contenu-fin; margin-top: 3rem; font-size: var(--fs-note); }
.secteurs-note a { color: var(--vert-f); font-weight: 600; }
@media (max-width: 767px) {
  .secteurs-flex { grid-template-columns: 1fr; }
  .secteurs-liste li { font-size: 2.2rem; }
}

/* ---------- S10 FAQ ---------- */
.faq-liste { grid-column: contenu-deb / span 12; margin-top: 4rem; }
.faq-item { border-bottom: var(--bord-1) solid var(--bord); }
.faq-item summary {
  cursor: pointer; list-style: none; position: relative;
  padding: 2.4rem 5rem 2.4rem 0; font-size: 2rem; font-weight: 600;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: ''; position: absolute; right: 1rem; top: 50%;
  width: 1.2rem; height: 1.2rem;
  border-right: 0.28rem solid var(--vert-f); border-bottom: 0.28rem solid var(--vert-f);
  transform: translateY(-70%) rotate(45deg); transition: transform 0.3s;
}
.faq-item[open] summary::after { transform: translateY(-30%) rotate(225deg); }
.faq-item p { padding: 0 0 2.6rem; max-width: 68rem; color: var(--note); }

/* ---------- S11 CTA ---------- */
#cta { text-align: center; background: var(--glace); }
.cta-titre { grid-column: contenu-deb / contenu-fin; }
.cta-texte { grid-column: contenu-deb / contenu-fin; margin-top: 2.4rem; font-size: 2rem; }
.cta-btn { justify-self: center; grid-column: contenu-deb / contenu-fin; margin-top: 3.6rem; }

/* ---------- S12 Formulaire-offre ---------- */
.offre { grid-column: contenu-deb / span 11; }
.offre-sous { margin-top: 1.6rem; color: var(--note); }
.offre-form { margin-top: 4rem; position: relative; }
.offre-progression {
  height: 0.4rem; background: var(--glace); border-radius: 0.2rem;
  margin-bottom: 3.2rem; overflow: hidden;
}
.offre-barre {
  display: block; height: 100%; width: 20%;
  background: var(--vert-f); transition: width 0.4s;
}
.offre-etape { border: 0; }
.offre-etape legend { margin-bottom: 2.4rem; }
.offre-pastilles { display: flex; flex-wrap: wrap; gap: 1.2rem; }
.offre-pastilles label { cursor: pointer; position: relative; }
.offre-pastilles input { position: absolute; opacity: 0; }
.offre-pastilles span {
  display: inline-flex; flex-direction: column; align-items: center; gap: 0.6rem;
  padding: 1.4rem 2.2rem; border: var(--bord-1) solid var(--bord-fort);
  border-radius: var(--radius); font-size: var(--fs-ui); font-weight: 600;
  transition: border-color 0.3s, background-color 0.3s, color 0.3s;
}
.offre-pastilles span b { font-family: var(--police-titre); font-size: 2.2rem; font-weight: 400; }
.offre-pastilles input:checked + span { background: var(--rose); border-color: var(--rose); color: var(--neige); }
.offre-pastilles input:focus-visible + span { outline: 0.3rem solid var(--jaune); outline-offset: 0.2rem; }
.offre-types span { min-width: 16rem; }
.offre-champ {
  width: min(38rem, 100%); padding: 1.6rem 2rem; font: inherit;
  border: var(--bord-1) solid var(--bord-fort); border-radius: var(--radius);
}
.offre-champ:focus-visible { outline: 0.3rem solid var(--jaune); outline-offset: 0.2rem; }
.offre-suivant { margin-top: 3.2rem; }
.offre-suivant:disabled { opacity: 0.35; cursor: not-allowed; }
.offre-recap { padding-top: 2rem; }
.offre-recap-detail { font-size: 2rem; margin: 1.2rem 0 0.6rem; }
.offre-recap-prix { color: var(--vert-f); margin-bottom: 2.8rem; }
.offre-recap .note { margin-top: 2rem; }

/* ---------- Formulaire de soumission (page excavation, démonstration) ---------- */
.soumission-form { margin-top: 4rem; }
.soumission-grille { display: grid; grid-template-columns: 1fr 1fr; gap: 2.4rem; }
.soumission-grille label {
  display: grid; gap: 0.9rem;
  font-size: var(--fs-note); color: var(--note);
}
.soumission-grille .offre-champ { width: 100%; }
.soumission-large { grid-column: 1 / -1; }
.soumission-fac { color: var(--note); opacity: 0.7; }
.soumission-form > .btn { margin-top: 3.2rem; }
.soumission-form > .note { margin-top: 2rem; max-width: 52rem; }
@media (max-width: 767px) {
  .soumission-grille { grid-template-columns: 1fr; }
}

/* ---------- S13 Contact ---------- */
.contact-colonnes {
  grid-column: contenu-deb / contenu-fin;
  display: flex; justify-content: space-between; align-items: flex-end; gap: 4rem;
  flex-wrap: wrap;
}
.contact-liste { margin-top: 2.8rem; }
.contact-liste li { padding: 0.9rem 0; font-size: 2rem; }
.contact-liste a { text-decoration-color: var(--vert-f); text-underline-offset: 0.4rem; }
.contact-sociaux { display: flex; gap: 1.6rem; }
.contact-sociaux a {
  display: grid; place-items: center; width: 4.8rem; height: 4.8rem;
  border: var(--bord-1) solid var(--bord-fort); border-radius: 50%;
  transition: border-color 0.3s, color 0.3s;
}
.contact-sociaux a:hover { border-color: var(--vert-f); color: var(--vert-f); }

/* ---------- S14 Pied ---------- */
/* overflow:clip — le rappel géant en filigrane est plus large que l'écran en
   mobile ; c'est voulu (il doit être coupé), mais sans clip il élargissait la
   page de 98 px. Bug hérité de la V1, trouvé à la QA scriptée du 7 août. */
.pied { background: var(--nuit); color: var(--encre); position: relative; overflow: clip; }
.pied .sep-congere { color: var(--nuit); position: absolute; top: 0; transform: translateY(-98%); }
.pied-interieur { padding-block: 10rem 4rem; }
.pied-rappel {
  grid-column: contenu-deb / contenu-fin;
  color: rgba(var(--rgb-encre), 0.1); line-height: 0.95;
}
.pied-nav {
  grid-column: contenu-deb / contenu-fin;
  display: flex; flex-wrap: wrap; gap: 2.8rem; margin-top: 5rem;
  font-size: var(--fs-ui); text-transform: uppercase; letter-spacing: 0.08em;
}
.pied-nav a { text-decoration: none; }
.pied-nav a:hover { color: var(--vert-f); }
.pied-demo {
  grid-column: contenu-deb / contenu-fin;
  margin-top: 4rem; font-size: var(--fs-badge); color: var(--note);
}
.pied-demo a { color: var(--encre); }

/* ---------- S15 Légal (:target) ---------- */
.legal { display: none; background: var(--neige); color: var(--encre); }
.legal:target { display: block; }
.legal-interieur { max-width: 78rem; margin-inline: auto; padding: 8rem var(--pad-container); }
.legal-interieur h2 { margin-top: 3rem; }
.legal-interieur p { margin-top: 1.4rem; font-size: var(--fs-note); }
.legal-interieur a { color: var(--vert-f); }

/* ---------- Curseur FLOCON (pointeur fin seulement — idée Yannick 3 août) ---------- */
/* Base HORS media query (2 sept. 2026) : chargé à la souris puis basculé en
   tactile (DevTools mobile sans recharger), le div perdait ses règles et
   devenait un flocon géant en fin de page. */
.curseur { display: none; }
@media (pointer: fine) {
  .curseur {
    display: block;
    position: fixed; z-index: 99; width: 3rem; height: 3rem;
    pointer-events: none; top: -1.5rem; left: -1.5rem;
    color: var(--vert-f); opacity: 0;
    transition: transform 0.25s, color 0.25s, opacity 0.25s;
  }
  .curseur svg { width: 100%; height: 100%; animation: flocon-tourne 14s linear infinite; }
  .curseur.actif { opacity: 0.85; }
  .curseur.survole { transform: scale(1.55); color: var(--jaune); opacity: 1; }
  @keyframes flocon-tourne { to { transform: rotate(360deg); } }
}

/* ---------- Reduced motion : tout a l'etat final ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}

/* ═══ SÉQUENCE HORIZONTALE (patron United Carriers — 4 août 2026) ═══
   Active seulement : desktop ≥768px ET html SANS .anim-statique (classe posée
   par premium.js quand reduced-motion / tier LuxAnim statique / GSAP absent).
   Partout ailleurs, le socle vertical ci-dessus fait le repli tout seul. */
@media (min-width: 992px) {
  html:not(.anim-statique) .piste-hiver { height: calc(100vh + 400vw); }
  html:not(.anim-statique) .piste-colle {
    position: sticky; top: 0; height: 100vh; overflow: clip;
  }
  html:not(.anim-statique) .piste {
    display: flex; width: max-content; position: relative; z-index: 1;
    height: 100%; will-change: transform;
  }
  html:not(.anim-statique) .piste > .panneau {
    width: 100vw; flex: 0 0 auto; min-height: 100vh; align-content: center;
  }
  html:not(.anim-statique) body.hiver #services { display: flex; background: transparent; }
  html:not(.anim-statique) body.hiver #services .ecran { width: 100vw; flex: 0 0 auto; }
  /* Le blizzard devient l'overlay du viewport sticky (le hack canvas-sticky
     du mode vertical n'a plus de sens ici) */
  html:not(.anim-statique) .blizzard canvas { position: absolute; inset: 0; height: 100%; }
  html:not(.anim-statique) .neige-avant { margin-top: 0; }
  /* (Règles route + tracteur retirées le 4 août au soir — stand-by.) */
}

/* ═══ MOBILE : la grille 16 colonnes se replie en UNE colonne ═══
   (7 août 2026 — bug hérité, trouvé à la QA scriptée en 390 px.)
   Le socle 16 colonnes garde ses 15 gouttières de 3,6 rem quelle que soit la
   largeur : ~520 px de vide sur un écran de 390. Les colonnes, elles, tombent
   à 0 (minmax(0,…)) — donc le contenu était poussé HORS de l'écran et coupé
   par le `overflow-x: clip` posé en urgence le 4 août. Le clip cachait le
   symptôme, pas la cause.
   Ici : une seule colonne de contenu, zéro gouttière, et TOUS les enfants
   ramenés sur cette colonne (sinon un `span 9` créerait des colonnes
   implicites et le débordement reviendrait par la porte d'à côté). */
@media (max-width: 767px) {
  .grille {
    grid-template-columns:
      [pleine-deb] var(--pad-container)
      [contenu-deb] minmax(0, 1fr)
      [contenu-fin] var(--pad-container) [pleine-fin];
    column-gap: 0;
  }
  .grille > * { grid-column: contenu-deb / contenu-fin; }
  .grille > .pleine, .grille > .hero-fond { grid-column: pleine-deb / pleine-fin; }

  /* ── Échelle de texte propre au mobile ──
     Les --fs-* du 3 août sont calibrés pour le desktop : reportés tels quels
     sur 390 px, le corps sortait à 26 px et le kicker prenait trois lignes.
     Valeurs ci-dessous en px RÉELS à 390 px de large (racine ≈ 9,9 px), toutes
     au-dessus des planchers CLAUDE.md : corps 17 px (min 16) · UI 15 px
     (min 12,8) · badges 13 px (min 12). */
  :root {
    --fs-corps: 1.72rem;  /* ≈ 17 px */
    --fs-note: 1.68rem;   /* ≈ 16,6 px */
    --fs-ui: 1.5rem;      /* ≈ 15 px */
    --fs-badge: 1.32rem;  /* ≈ 13 px */
  }
  /* La barre : le logo passait SOUS le bouton et se faisait recouvrir. */
  .nav { padding: 1.2rem var(--pad-container); gap: 1.2rem; }
  .nav-logo { font-size: 1.5rem; line-height: 1.15; }
  /* QA 18 août : à 390 px, « Estimation gratuite » (213 px) poussait le
     burger HORS de l'écran. Le CTA de barre tombe sur téléphone ; le
     formulaire-offre et les tel: du corps restent les chemins d'action. */
  .nav-cta { display: none; }
  .hero { padding-top: 9rem; }
  .hero-cta .btn { flex: 1 1 auto; justify-content: center; }

  /* La titraille condensée en capitales déborde vite sur 390 px : les titres de section
     descendent d'un cran de plus que le palier 991 px. */
  h2, .h2 { font-size: 3.66rem; }
  h3, .h3 { font-size: 2.89rem; }

  /* Le relevé en flex donnait 2 + 1 en quinconce ; en grille, les trois
     colonnes s'alignent, libellé au-dessus de sa valeur. */
  .hero-releve { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem 2.4rem; }

  /* « SAINTE-SCHOLASTIQUE » cassait en deux dans une demi-colonne : la liste
     des secteurs passe sur une seule colonne. */
  .secteurs-liste { grid-template-columns: 1fr; }
  .secteurs-liste li { font-size: 2rem; }

  /* Le rappel géant du pied faisait cinq lignes plein écran avant d'arriver
     aux liens : c'est un filigrane, pas une section. */
  .pied-rappel { font-size: 4.6rem; }
  .pied-interieur { padding-block: 6rem 3rem; }
}

/* ═══ TWEAKS PAR SECTION — VERSION 2 « NUIT » (7 août 2026) ═══
   ⚠️ Le bloc du 3 août (réglages tweaks bar de Yannick) forçait ici
   `--encre:#000000` sur l'entête et le héros, et `--glace:#8bccfd` sur sept
   sections : c'est LUI qui produisait le bleu ciel pâle de la V1, pas le socle.
   Il est conservé intact dans DEMOS/Deneigement-Roger-demo/ (la V1).
   Ci-dessous, les mêmes leviers, réglés pour la nuit — chaque section reçoit
   sa profondeur pour que le défilement respire au lieu d'être un aplat noir. */
#accueil {
  --glace: #191f21;
}
body.hiver #services {  /* les services : le palier le plus clair */
  --glace: #1c2326;
}

#equipement {
  --glace: #171d1f;
}

#cta {               /* l'appel : remonte d'un ton pour appeler le clic */
  --glace: #1f2629;
}
#reserver {
  --glace: #191f21;
}


/* ---------- Bandeau maquette (obligation /demo : aperçu non publié) ---------- */
.bandeau-maquette {
  /* left:50% + translateX(-50%) sur un bloc en largeur auto = shrink-to-fit
     calculé sur la MOITIÉ droite de l'écran : à 390 px, le bandeau tombait à
     ~180 px et empilait 4 lignes par-dessus le héros. left/right + margin auto
     le centre sans amputer sa largeur. */
  /* 18 août : la pilule centrée tombait à 3 lignes en 390 px et recouvrait
     les CTA. Pleine largeur, collée au bas, line-height serré → 2 lignes. */
  position: fixed; left: 0; right: 0; bottom: 0;
  margin: 0; width: auto; max-width: none;
  z-index: 80;
  background: rgba(var(--rgb-nuit), 0.94); color: var(--note);
  border: 0; border-top: var(--bord-1) solid var(--bord); border-radius: 0;
  padding: 5px 10px;
  /* Taille EN DUR, en px, et pas en rem : la racine de cette maquette est
     fluide (1rem ≈ 10 px), donc un « 1,1rem » y vaudrait 11 px. Le bandeau
     est une obligation de /demo, il ne doit dépendre ni de la largeur de la
     fenêtre ni du thème : 17,6 px (= 1,1rem d'une racine normale) au bureau,
     14,4 px (= 0,9rem) sur téléphone. */
  font-size: 17.6px;
  text-align: center; line-height: 1.25; pointer-events: none;
}
@media (max-width: 767px) { .bandeau-maquette { font-size: 14.4px; } }

/* Dégagement bas de page : hauteur réelle du bandeau + marge. En px pour la
   même raison que le bandeau (la racine de cette maquette est rescalée). */
:root { --degagement-bandeau: 52px; }
@media (max-width: 767px) { :root { --degagement-bandeau: 88px; } }
body { padding-bottom: var(--degagement-bandeau); }

/* Écrans BAS de bureau (1366×768 et compagnie) : le héros centré débordait
   son écran et le bouton téléphone finissait sous le bandeau (QA 18 août).
   On resserre le haut et on réserve la hauteur du bandeau en bas. */
@media (min-width: 768px) and (max-height: 820px) {
  .hero { padding-top: 7rem; padding-bottom: calc(1rem + var(--degagement-bandeau)); }
  .hero-cta { margin-top: 2.4rem; }
}

/* ════════════════════════════════════════════════════════════════════
   BLOCS NEUFS — ils n'existent ni chez Roger V2 ni chez A. Chaumont.
   ① le SPLIT été/hiver de l'accueil   ② le squelette de la page Excavation
   ════════════════════════════════════════════════════════════════════ */

/* ---------- ① Accueil : split plein écran été / hiver ----------
   Deux panneaux-photo, un par univers. Le bloc d'identité ne flotte PAS sur
   les photos : il est posé sur son propre aplat de nuit, à cheval sur la
   couture. C'est ce qui garantit le contraste du nom et du slogan sans
   dépendre du cadrage ni de la météo du jour où la photo a été prise. */
.split {
  display: grid; grid-template-columns: 1fr 1fr;
  min-height: 100svh; position: relative;
}
.split-panneau {
  position: relative; overflow: clip; text-decoration: none;
  display: flex; flex-direction: column; justify-content: flex-end;
  /* Le bas est généreux : c'est là que vit le libellé du panneau, et le
     bandeau de maquette est fixé encore plus bas. Sans cette réserve, le
     lien « Voir l'excavation » passait sous le bandeau (vu au navigateur). */
  padding: 16rem var(--pad-container) calc(1rem + var(--degagement-bandeau));
  min-height: 100svh;
}
.split-panneau img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  z-index: 0; transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
/* Verdict Yannick 18 août : photos NUES ici aussi — aucun filtre. */
.split-ete img { object-position: 50% 40%; }
.split-hiver img { object-position: 52% 45%; }
/* Le voile n'existe qu'en BAS (assise du libellé) + un souffle en haut pour
   la nav ; le cœur de la photo reste nu. */
.split-panneau::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(to top,
      rgba(var(--rgb-nuit), 0.92) 0%, rgba(var(--rgb-nuit), 0.66) 40%, rgba(var(--rgb-nuit), 0) 66%),
    linear-gradient(to bottom, rgba(var(--rgb-nuit), 0.5) 0%, rgba(var(--rgb-nuit), 0) 12%);
  transition: background 0.6s;
}
.split-hiver::after {
  background:
    linear-gradient(to top,
      rgba(var(--rgb-nuit-hiver), 0.92) 0%, rgba(var(--rgb-nuit-hiver), 0.66) 40%, rgba(var(--rgb-nuit-hiver), 0) 66%),
    linear-gradient(to bottom, rgba(var(--rgb-nuit-hiver), 0.5) 0%, rgba(var(--rgb-nuit-hiver), 0) 12%);
}
@media (hover: hover) {
  .split-panneau:hover img { transform: scale(1.045); }
  .split-panneau:hover::after {
    background:
      linear-gradient(to top,
        rgba(var(--rgb-nuit), 0.88) 0%, rgba(var(--rgb-nuit), 0.4) 30%, rgba(var(--rgb-nuit), 0) 58%),
      linear-gradient(to bottom, rgba(var(--rgb-nuit), 0.5) 0%, rgba(var(--rgb-nuit), 0) 12%);
  }
}
.split-contenu {
  position: relative; z-index: 2;
  text-shadow: 0 0.1rem 0.5rem rgba(var(--rgb-nuit), 0.92), 0 0.3rem 2rem rgba(var(--rgb-nuit), 0.7);
}
.split-contenu h2 { font-size: 4.88rem; }
.split-saison {
  font-family: var(--police-mono); font-size: var(--fs-badge);
  letter-spacing: 0.24em; text-transform: uppercase; color: var(--sable);
  /* ⚠️ EXCEPTION ASSUMÉE (verdict Yannick, 18 août 2026) : l'orange sur photo
     mesure ~2,2-2,6:1, SOUS le AA de la QA. Verdict : reste orange — « trop de
     blanc dans le site » — l'étiquette est décorative et doublée du H2 blanc
     conforme juste dessous. Ne pas « corriger » à la prochaine passe QA. */
}
.split-p { margin-top: 1.8rem; max-width: 40rem; color: var(--note); font-size: var(--fs-note); }
.split-lien {
  display: inline-flex; align-items: center; gap: 1rem; margin-top: 3rem;
  font-family: var(--police-mono); font-size: var(--fs-ui); font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--encre);
  border-bottom: 0.2rem solid var(--sable); padding-bottom: 0.8rem;
}
.split-panneau:hover .split-lien { color: var(--sable-clair); }
/* Le trait vertical qui sépare les deux saisons. */
.split::before {
  content: ''; position: absolute; z-index: 3; top: 0; bottom: 0; left: 50%;
  width: max(1px, 0.1rem); background: var(--bord-fort);
}

/* Le bloc d'identité, posé à cheval sur la couture.
   Il est ACCROCHÉ EN HAUT (top fixe) et non centré : centré, sur un écran de
   900 px de haut, il descendait sur les deux titres de panneau et les coupait
   en deux (vu au navigateur à 1440×900). Depuis le haut, sa hauteur ne peut
   plus grignoter la zone des libellés, quelle que soit la fenêtre. */
.identite {
  /* QA 18 août : à 1280×768 la carte finissait à ~430 px et recouvrait le
     titre des DEUX panneaux. Remontée sous la nav et resserrée (padding et
     largeur), elle libère ~80 px et les deux titres redeviennent entiers. */
  /* Verdict Yannick 19 août : la carte reste mais PÂLIE (0,9 → 0,62 — l'essai
     sans carte laissait la couture des panneaux derrière le texte) et DESCENDUE
     (top 5,8 → 7,2rem : le haut du texte touchait la barre de navigation).
     Le blur et l'ombre portée compensent l'alpha réduit.
     2e descente (verdict Yannick, même séance) : encore un demi-pouce (~48 px
     ≈ 4,5rem à l'échelle fluide de la page) pour dégager franchement la nav. */
  /* 27 août 2026 (verdict Yannick, défaut de FAMILLE réglé structurellement) :
     fini le rem magique — la carte s'ancre sous la hauteur RÉELLE de la nav
     (--nav-bas, posée par pages.js et suivie au ResizeObserver). À 1280 px la
     nav passait sur 2 lignes (139 px) et la carte montait dedans de 25 px ;
     maintenant elle suit. Repli sans JS : 10.2rem ≈ la nav sur une ligne. */
  position: absolute; z-index: 4; left: 50%;
  top: calc(var(--nav-bas, 10.2rem) + 1.6rem);
  transform: translateX(-50%);
  width: min(92vw, 50rem); text-align: center;
  background: rgba(var(--rgb-nuit), 0.62);
  border: var(--bord-1) solid var(--bord-fort);
  border-radius: var(--radius);
  backdrop-filter: blur(10px);
  /* Chaque rem de hauteur compte : le bas de la carte doit rester AU-DESSUS
     de l'étiquette de saison des deux panneaux (« L'ÉTÉ » / « L'HIVER »).
     Mesuré à 1440×900 : la carte finit à ~423 px, les étiquettes à ~462 px. */
  padding: 1.5rem 2.6rem;
}
.identite h1, .identite-sous, .identite-slogan {
  text-shadow: 0 0.1rem 0.5rem rgba(var(--rgb-nuit), 0.92), 0 0.3rem 2rem rgba(var(--rgb-nuit), 0.7);
}
/* Nom long de la fondation : 22 signes contre 14. En
   titraille condensée (~0,62 em par signe), il demanderait ~680 px à 50 px de corps
   pour 540 px utiles dans la carte : le corps descend à 4rem et le nom tient
   sur deux lignes, ce qui garde la carte au-dessus des étiquettes de saison. */
.identite h1 { font-size: clamp(2.44rem, 3.33vw, 3.55rem); }   /* 4.44rem = 2 lignes a 1280, la carte descendait sur les titres */
.identite-sous {
  margin-top: 1.4rem; font-family: var(--police-mono); font-size: var(--fs-ui);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--sable);
}
/* 2,5rem et non 2,9 : le slogan tient alors sur UNE ligne dans les 540 px
   utiles de la carte, ce qui lui rend son tranchant et économise 40 px. */
.identite-slogan {
  margin-top: 0.8rem; font-size: 2.5rem; line-height: 1.4; color: var(--encre);
  max-width: 52rem; margin-inline: auto;
}
.identite-tel { margin-top: 1.2rem; }
/* Écran COURT (portables 864-900 px et moins) : mesuré le 27 août, le bas de
   la carte couvrait « L'ÉTÉ / L'HIVER » de 42 px à 1536×864. La carte se
   compacte au lieu d'empiéter — elle reste ancrée sous la nav (--nav-bas). */
@media (min-width: 901px) and (max-height: 900px) {
  .identite { padding: 0.8rem 2.2rem; }
  .identite h1 { font-size: clamp(2.11rem, 2.78vw, 2.89rem); }
  .identite-sous { margin-top: 0.7rem; }
  .identite-slogan { font-size: 1.9rem; margin-top: 0.4rem; }
  .identite-tel { margin-top: 0.6rem; }
}
/* Fenêtre ÉCRASÉE (large mais ≤ ~760 px de haut, ex. 1280×720 avec nav sur
   2 lignes) : la superposition ne peut physiquement pas tenir entre la nav et
   les étiquettes (−192 px mesurés). La carte adopte alors la solution du
   mobile : un bandeau en flux AU-DESSUS des deux panneaux, pleine largeur. */
@media (min-width: 901px) and (max-height: 780px),
       (min-width: 901px) and (max-width: 1350px) and (max-height: 840px) {
  /* 2e condition (attrapée par le point 11 de qa-maquette à 1280×800) : quand
     la nav passe sur 2 lignes (≤ ~1350 px), la carte descend et couvrait
     l'étiquette de 61 px dès 800 px de haut — bandeau là aussi. */
  .identite {
    position: static; top: auto; transform: none; order: -1;
    grid-column: 1 / -1; width: auto; max-width: none;
    border: 0; border-radius: 0; backdrop-filter: none;
    background: var(--nuit);
    /* La nav (transparente) survole toujours le haut de page : le bandeau
       se dégage dessous avec la même variable --nav-bas. */
    padding: calc(var(--nav-bas, 10.2rem) + 2rem) var(--pad-container) 2rem;
  }
  .split-panneau { min-height: 52svh; }
}

@media (max-width: 900px) {
  /* Empilé, l'aplat centré tomberait entre les deux photos et en masquerait
     une : il redevient un bloc de flux, posé AVANT le split. */
  .split { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .split::before { display: none; }
  .split-panneau { min-height: 56svh; padding: 10rem var(--pad-container) 5rem; }
  .identite {
    /* order:-1 — dans le HTML l'identité vient APRÈS les deux panneaux (elle
       leur est superposée en grand écran). Sans ça, en pile, le nom de
       l'entreprise arrivait en TROISIÈME position, sous les deux photos. */
    order: -1;
    position: static; top: auto; transform: none; width: auto; border: 0;
    border-radius: 0; backdrop-filter: none; background: var(--nuit);
    padding: 12rem var(--pad-container) 6rem;
  }
  .split-contenu h2 { font-size: 4rem; }
}

/* ---------- Accueil : le bloc « qui on est » ---------- */
#maison { background: var(--glace); }
.maison-flex {
  grid-column: contenu-deb / contenu-fin;
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--col-gap);
}
.maison-flex p { margin-top: 2.4rem; }
.maison-releve {
  margin-top: 4rem; padding-top: 2.6rem;
  border-top: var(--bord-1) solid var(--bord);
  display: grid; grid-template-columns: 1fr 1fr; gap: 3rem;
  font-family: var(--police-mono);
}
.maison-releve dt {
  font-size: var(--fs-badge); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--note);
}
.maison-releve dd { margin-top: 0.6rem; font-size: 2.6rem; color: var(--sable); }
@media (max-width: 900px) { .maison-flex { grid-template-columns: minmax(0, 1fr); } }
/* Sous 560 px, les deux relevés en demi-colonne cassaient « Excavation et
   déneigement » sur trois lignes de mono : on les empile (QA 18 août). */
@media (max-width: 560px) { .maison-releve { grid-template-columns: minmax(0, 1fr); gap: 2.2rem; } }

/* ---------- ② Excavation : les services numérotés 01-04 ----------
   Patron J. Derenzo : un service = un écran, image d'un côté, numéro géant
   et texte de l'autre, l'alternance donne le rythme.
   Le NUMÉRO est en --terre (4,16:1 sur le fond) : sous le seuil 4,5:1 du
   texte courant, mais très au-dessus du seuil de 3:1 qui s'applique au
   texte LARGE (ici ~90 à 150 px). C'est le seul endroit où la terre porte
   des glyphes, et c'est calculé, pas toléré. */
.srv { border-top: var(--bord-1) solid var(--bord); }
.srv:first-of-type { border-top: 0; }
.srv-bloc {
  grid-column: contenu-deb / contenu-fin;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--col-gap); align-items: center;
}
.srv-media {
  overflow: clip; border-radius: var(--radius);
  border: var(--bord-1) solid var(--bord); aspect-ratio: 4 / 5;
}
.srv-media img { width: 100%; height: 100%; object-fit: cover; }
.srv-num {
  font-family: var(--police-titre); font-size: clamp(7rem, 9vw, 13rem);
  line-height: 0.82; color: var(--terre); letter-spacing: -0.03em;
  display: block; margin-bottom: 1.6rem;
}
.srv-texte h2 { font-size: 5.11rem; }
.srv-texte p { margin-top: 2.4rem; max-width: 46rem; }
.srv-points { margin-top: 2.8rem; max-width: 46rem; }
.srv-points li {
  position: relative; padding: 1.4rem 0 1.4rem 3.4rem;
  border-bottom: var(--bord-1) solid var(--bord); font-size: 2rem;
}
.srv-points li:last-child { border-bottom: 0; }
.srv-points li::before {
  content: ''; position: absolute; left: 0.2rem; top: 2.1rem;
  width: 1.8rem; height: 0.9rem;
  border-left: 0.3rem solid var(--sable); border-bottom: 0.3rem solid var(--sable);
  transform: rotate(-45deg);
}
/* L'alternance : sur les blocs pairs, l'image passe à droite. `order` plutôt
   que `direction: rtl`, qui aurait aussi retourné la ponctuation française. */
.srv-bloc.a-droite .srv-media { order: 2; }
@media (max-width: 900px) {
  .srv-bloc { grid-template-columns: minmax(0, 1fr); }
  .srv-bloc.a-droite .srv-media { order: 0; }
  .srv-texte h2 { font-size: 3.66rem; }
}

/* ---------- Excavation : grille équipement à 4 cartes ---------- */
.equipement-cartes.galerie-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.galerie-4 .equipement-media { aspect-ratio: 4 / 3; }
.galerie-4 figcaption {
  padding: 2rem 2.4rem 2.4rem; font-size: var(--fs-note); color: var(--note);
}
@media (max-width: 1100px) { .equipement-cartes.galerie-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .equipement-cartes.galerie-4 { grid-template-columns: minmax(0, 1fr); } }

/* ---------- Excavation : le pont vers l'hiver ----------
   Le seul endroit de la page été où le froid apparaît : un aplat de nuit
   d'hiver au milieu de l'été, pour que le passage d'une saison à l'autre
   se voie avant même de cliquer. */
#pont { background: var(--nuit); color: var(--encre); overflow: clip; }
#pont .kicker { color: var(--note); }
.pont-lueur {
  /* Règle maquettes du 19 août : pas de lueur radiale — éteinte le 27 août. */
  display: none;
  position: absolute; width: 60rem; height: 60rem; left: 62%; top: -10%;
  /* Lueur verte diluée : le pont vers l'hiver garde l'accent de la maison. */
  background: radial-gradient(circle, rgba(var(--rgb-lime), 0.1), rgba(var(--rgb-lime), 0) 70%);
  pointer-events: none;
}
.pont-texte { grid-column: contenu-deb / span 10; position: relative; }
.pont-texte p { margin-top: 2.6rem; max-width: 52rem; color: var(--note); }
.pont-texte .btn { margin-top: 3.6rem; }

/* ---------- Reveals doux (accueil + excavation, aucun canvas) ----------
   L'état de départ n'est posé QUE si le JS a confirmé qu'il va animer
   (classe .js-reveals sur <html>) : sans JS, sans GSAP ou en reduced-motion,
   rien n'est jamais caché. */
html.js-reveals .reveal { opacity: 0; transform: translateY(2.4rem); }

/* ════════════════════════════════════════════════════════════════════
   MAQUETTE SANS PHOTO — les aplats qui remplacent les images
   ════════════════════════════════════════════════════════════════════
   Entreprise fictive : aucune page Facebook, il n'existe
   aucune photo publiée de ses chantiers qu'on puisse montrer. Plutôt que
   d'acheter des photos de banque et de laisser croire que ce sont ses
   terrains, chaque emplacement d'image devient un aplat dégradé dans SES
   couleurs (lime → vert foncé → noir) avec un pictogramme au trait. Rien
   sur cette page ne prétend être une photo de son entreprise.
   Quand il fournira ses vraies photos, ces blocs les reçoivent tels quels. */
.visuel {
  position: absolute; inset: 0; display: grid; place-items: center;
  background:
    radial-gradient(ellipse 90% 70% at 30% 15%, rgba(var(--rgb-lime), 0.20), rgba(var(--rgb-lime), 0) 62%),
    linear-gradient(155deg, var(--terre) 0%, var(--nuit) 58%, var(--neige) 100%);
}
/* Trois variantes de cadrage, pour que deux blocs voisins ne soient pas
   le même dégradé au pixel près. Aucune couleur nouvelle : le même trio. */
.visuel-b {
  background:
    radial-gradient(ellipse 80% 80% at 78% 20%, rgba(var(--rgb-lime), 0.16), rgba(var(--rgb-lime), 0) 60%),
    linear-gradient(200deg, var(--nuit) 0%, var(--terre) 45%, var(--neige) 100%);
}
.visuel-c {
  background:
    radial-gradient(ellipse 100% 60% at 50% 100%, rgba(var(--rgb-terre), 0.85), rgba(var(--rgb-terre), 0) 70%),
    linear-gradient(125deg, var(--neige) 0%, var(--nuit) 62%, var(--terre) 100%);
}
.visuel svg {
  width: min(42%, 26rem); height: auto; color: var(--sable); opacity: 0.55;
  stroke: currentColor; fill: none; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}
/* Les conteneurs d'image de la fondation n'étaient pas positionnés : leurs
   photos étaient en flux. Un aplat absolu a besoin d'un ancrage. */
.srv-media, .equipement-media { position: relative; }
/* Sur le héros, le voile de texte couvre la gauche : le pictogramme va se
   poser dans la zone restée nue, à droite. */
.hero-fond .visuel { place-items: center end; padding-inline-end: 10%; }
.hero-fond .visuel svg { width: min(30%, 30rem); }
@media (max-width: 767px) {
  .hero-fond .visuel { place-items: start center; padding: 18svh 0 0; }
  .hero-fond .visuel svg { width: 42%; }
}
/* Panneaux du split : le pictogramme vit au-dessus du libellé, dans la
   moitié haute que le voile ne touche pas. */
.split-panneau .visuel { place-items: start center; padding-top: 22svh; }
.split-panneau .visuel svg { width: min(34%, 20rem); }

/* Note d'emplacement (19 août) : sous chaque pictogramme, une ligne qui dit
   au client que SA photo prend cette place. Elle vit DANS .visuel, qui est
   aria-hidden — c'est une annotation de maquette, pas du contenu du site,
   et sur le split ça évite de polluer le nom accessible du lien.
   .visuel est une grille : le second enfant se pose simplement sous le SVG. */
.visuel-note {
  font-family: var(--police-mono); font-size: var(--fs-badge);
  letter-spacing: 0.06em; line-height: 1.5; text-align: center;
  color: var(--note); opacity: 0.9;
  max-width: 34rem; margin-top: 1.8rem; padding-inline: 2rem;
}
/* Sur le split, la note NE VIT PAS sous le picto : à cette hauteur elle
   passait derrière la carte .identite (posée à cheval sur la couture, top
   11,7rem, z-index 4). Elle se range donc au bas du panneau, sous le lien,
   dans la zone déjà réservée au texte — et porte aria-hidden pour ne pas
   entrer dans le nom accessible du lien qui l'entoure. */
.split-contenu .visuel-note {
  margin-top: 2.4rem; text-align: left; padding-inline: 0; opacity: 0.8;
}

/* Barre fixe mesuree a 14,26rem sur cette maquette (liens sur deux lignes). */
:root { --degagement-nav: 14.5rem; }

/* ═══ PISTE HORIZONTALE — VIEWPORTS COURTS (20 août 2026) ═══
   Bug rapporté au téléphone par le client 4G, reproduit au navigateur.

   CAUSE : .piste-colle est collée à `height: 100vh` avec `overflow: clip`, et
   .ecran centre son contenu (`align-items: center`). Dès qu'un panneau est plus
   haut que l'écran, le débordement part des DEUX côtés et se fait rogner — le
   kicker et le titre disparaissent en haut, les cartes en bas — sans aucun
   moyen d'y accéder, puisque le conteneur est clippé et non défilant.
   Invisible sur un 1920×1080 (il restait 22 px de marge sur le panneau le plus
   haut), franc sur un portable 1366×768 à l'échelle Windows 125 % (≈ 1093×614 px
   CSS) : 145 à 365 px de texte perdus selon le panneau. À l'échelle 100 % du même
   portable (1366×768) le panneau le plus lourd débordait encore de 211 px — ce
   qui explique « à 80 % ça s'améliore » : baisser l'échelle rallonge le viewport.

   CORRECTIF, en deux temps :
   1. `safe center` — garde-fou permanent. Si un panneau déborde malgré tout
      (contenu plus long sur une future maquette, échelle Windows 150 %), il
      s'aligne en HAUT au lieu de couper le titre.
   2. Un traitement COMPACT sous 1050 px de hauteur : l'air vertical et les deux
      blocs de texte lourds deviennent fluides en vh. Au-dessus de 1050 px —
      donc sur 1920×1080 — AUCUNE de ces règles ne s'applique : la maquette
      validée par Yannick est intacte par construction, pas par calcul.
   Mesuré : les panneaux tiennent dès 550 px de hauteur utile, sous la barre
   fixe et au-dessus du bandeau, texte à 18,6 px (plancher CLAUDE.md : 17,6 px).

   Deux boutons de calibration, à MESURER par maquette (barre et bandeau sont en
   rem, donc les valeurs suivent l'échelle) et à relever au-dessus de ce bloc
   quand la mesure l'exige :
   · --degagement-nav       hauteur de la barre fixe du haut (défaut 10rem =
                            une barre sur une ligne ; 14,5rem si elle en fait deux)
   · --degagement-piste-bas hauteur du bandeau « maquette » du bas (défaut 4rem =
                            une ligne ; 7rem si le texte en prend deux) */
@media (min-width: 992px) {
  html:not(.anim-statique) .piste .ecran { align-items: safe center; }
  html:not(.anim-statique) .piste > .panneau { align-content: safe center; }
}
@media (min-width: 992px) and (max-height: 1050px) {
  html:not(.anim-statique) .piste .ecran-contenu {
    padding-top: var(--degagement-nav, 10rem);
    padding-bottom: max(var(--degagement-piste-bas, 4rem), clamp(2.4rem, 5vh, 10rem));
  }
  html:not(.anim-statique) .piste .cartes-prix,
  html:not(.anim-statique) .piste .inclus-liste { margin-top: clamp(1.4rem, 2.6vh, 4rem); }
  html:not(.anim-statique) .piste .carte-prix { padding: clamp(1.6rem, 2.9vh, 3.2rem); }
  html:not(.anim-statique) .piste .carte-montant { margin-top: clamp(0.9rem, 1.8vh, 2.4rem); }
  html:not(.anim-statique) .piste .carte-montant .prix { font-size: clamp(2.4rem, 4.2vh, 4.2rem); }
  html:not(.anim-statique) .piste .carte-desc { font-size: clamp(1.85rem, 2.9vh, var(--fs-note)); }
  html:not(.anim-statique) .piste .inclus-liste li {
    padding-block: clamp(0.9rem, 1.8vh, 2.2rem);
    font-size: clamp(1.85rem, 3.05vh, var(--fs-note));
    line-height: 1.35;
  }
  /* Le crochet suit la nouvelle marge haute de son item. */
  html:not(.anim-statique) .piste .inclus-liste li::before { top: calc(clamp(0.9rem, 1.8vh, 2.2rem) + 0.7rem); }
}

/* Démo Terrain & Neige (7 sept. 2026) : à 1366×768 (vue desktop-768 du QA, ajoutée
   le 2 sept.) la carte couvrait l'étiquette de saison de 11 px — le seuil du mode
   « bandeau » ci-dessus est monté de 760 à 780 px de haut. */

/* Démo Terrain & Neige (7 sept. 2026) : 4 liens dans la nav des pages de saison
   (Accueil ajouté, demande de Yannick). À 1280 px le bouton passait sur 2 lignes
   et la nav montait à 139 px : gap resserré, bouton sur une ligne → 99 px. */
@media (min-width: 901px) and (max-width: 1400px) {
  /* Jost est plus large que Geist Mono : à 1280 px le bouton sortait de l'écran
     (7 sept., après les choix de Yannick). Interlettrage et marges resserrés. */
  .nav nav { gap: 1.6rem; }
  .nav-liens { gap: 1.4rem; }
  .nav-liens a { letter-spacing: 0.05em; }
  .nav-cta { white-space: nowrap; padding: 1rem 1.6rem; letter-spacing: 0.05em; }
  /* (0,3,2) pour passer devant .nav nav a:not(.btn) ; 2.2rem ≈ 21,5 px à 1280,
     au-dessus du plancher desktop de 17,6 px. */
  .nav nav .nav-liens a:not(.btn), .nav nav .nav-cta, .nav .nav-logo { font-size: 2.2rem; }
}
