/* ==========================================================================
   Construland - feuille de style unique
   Ordre : polices, jetons, socle, mise en page, composants, pages, landings.
   Un seul fichier, volontairement. Pas de build, pas de préprocesseur.
   ========================================================================== */

/* -------------------------------------------------------------- Polices --
   Sous-ensembles latin et latin-ext auto-hébergés. Le preload des deux faces
   critiques (Inter 400, Archivo 700) est dans inc/tete.php, sur TOUTES les
   pages : une seule page sans preload et la typo saute au premier affichage. */

@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('../assets/fonts/inter-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('../assets/fonts/inter-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('../assets/fonts/inter-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('../assets/fonts/inter-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('../assets/fonts/inter-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('../assets/fonts/inter-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('../assets/fonts/archivo-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('../assets/fonts/archivo-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('../assets/fonts/archivo-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('../assets/fonts/archivo-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------- Jetons -- */

:root {
  /* Couleurs. Contrastes calculés sur fond papier et sur fond sable,
     pas estimés à l'oeil.
       ardoise / papier  7,18:1      ardoise / sable  6,55:1
       brique  / papier  6,03:1      papier  / brique 6,03:1
       brume   / nuit   11,3:1       cuivre  / nuit    6,8:1                */
  --papier:        #ffffff;
  --sable:         #f7f4ef;   /* fond de section alterné, chaud */
  --sable-fonce:   #efeae1;   /* aplats internes, séparateurs pleins */
  --encre:         #17191d;   /* titres et texte fort */
  --ardoise:       #52585f;   /* texte courant secondaire */
  --trait:         #e4dfd6;   /* filets, contours de carte */
  --brique:        #a2481b;   /* accent unique du site */
  --brique-fonce:  #7e370f;   /* survol, texte accentué sur sable */
  --brique-voile:  #f6ece5;   /* aplat très clair pour badges */
  --nuit:          #16181c;   /* sections sombres, pied de page */
  --brume:         #c9cdd3;   /* texte courant sur nuit */
  --cuivre:        #e08a55;   /* accent sur nuit, éclairci pour le contraste */
  --etoile:        #f59a23;   /* étoiles de la note des avis, orange franc */

  /* Typographie. Deux sans-serif, jamais d'empattements : le client les a
     écartées le 2026-08-31. Le contraste entre titres et texte vient donc de
     la graisse et de la largeur, pas de la présence de serifs. Archivo est un
     grotesque un peu resserré, d'origine signalétique, qui pose bien sur un
     métier du bâtiment. Inter porte le texte courant.
     La pile de secours embarque les polices Apple avant Arial : sans elles
     Safari retombe sur Helvetica, sensiblement plus large, et la mise en page
     diverge entre PC et Mac. */
  --titre:  'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  --texte:  'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;

  --fs-hero:   clamp(2.5rem,  1.55rem + 3.9vw, 4.4rem);
  --fs-h1:     clamp(2.125rem, 1.5rem  + 2.6vw, 3.4rem);
  --fs-h2:     clamp(1.75rem, 1.36rem + 1.65vw, 2.55rem);
  --fs-h3:     clamp(1.1875rem, 1.11rem + .32vw, 1.4rem);
  --fs-lead:   clamp(1.125rem, 1.04rem + .36vw, 1.3125rem);
  --fs-corps:  clamp(1rem, .975rem + .1vw, 1.0625rem);
  --fs-petit:  .9375rem;
  --fs-micro:  .8125rem;

  /* Espacement. Une seule échelle, utilisée partout. */
  --e-1: .375rem;  --e-2: .75rem;   --e-3: 1.125rem;
  --e-4: 1.75rem;  --e-5: 2.5rem;   --e-6: 3.5rem;
  --gouttiere: clamp(1.25rem, .85rem + 1.5vw, 2.125rem);
  --marge-page: clamp(1.25rem, .5rem + 2.6vw, 3rem);
  --section-y: clamp(3.75rem, 2.2rem + 5.2vw, 6.75rem);
  --contenu: 1220px;
  --lisible: 62ch;   /* longueur de ligne confortable pour un paragraphe */

  /* Rayons volontairement discrets. Des angles très arrondis lisent
     « application web » et non « entreprise de construction ». */
  --r:   3px;
  --r-l: 6px;

  --transition: 160ms cubic-bezier(.2, .6, .3, 1);
}

/* ---------------------------------------------------------------- Socle -- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;   /* sinon iOS gonfle le texte */
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--papier);
  color: var(--encre);
  font-family: var(--texte);
  font-size: var(--fs-corps);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: 'kern' 1, 'liga' 1;
}

h1, h2, h3, h4 {
  font-family: var(--titre);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -.02em;
  margin: 0;
  color: var(--encre);
  text-wrap: balance;
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); line-height: 1.24; letter-spacing: -.005em; }

p { margin: 0; text-wrap: pretty; }
p + p { margin-top: var(--e-3); }

a { color: var(--brique-fonce); text-decoration-thickness: 1px; text-underline-offset: .18em; }
a:hover { color: var(--encre); }

img, svg, video { max-width: 100%; height: auto; display: block; }

ul, ol { margin: 0; padding: 0; }
li { list-style: none; }

/* Le navigateur applique margin: 1em 40px aux figure. Sans cette remise a
   zero, le visuel du hero sortait a 451 px de large dans une colonne de 532,
   et son bord droit ne tombait pas sur celui du reste de la page. */
figure { margin: 0; }

button, input, select, textarea { font: inherit; color: inherit; }

hr { border: 0; border-top: 1px solid var(--trait); margin: var(--e-5) 0; }

:focus-visible {
  outline: 2px solid var(--brique);
  outline-offset: 3px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ------------------------------------------------------------ Utilitaires */

.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;
}

.saut-contenu {
  position: absolute; left: var(--e-2); top: -4rem; z-index: 200;
  background: var(--encre); color: var(--papier); padding: var(--e-2) var(--e-3);
  border-radius: var(--r); transition: top var(--transition);
}
.saut-contenu:focus { top: var(--e-2); color: var(--papier); }

/* ----------------------------------------------------------- Mise en page */

.contenu {
  width: 100%;
  max-width: var(--contenu);
  margin-inline: auto;
  padding-inline: var(--marge-page);
}
.contenu--etroit { max-width: 780px; }

.section { padding-block: var(--section-y); }
.section--sable { background: var(--sable); }
.section--nuit  { background: var(--nuit); color: var(--brume); }
.section--nuit h2, .section--nuit h3 { color: var(--papier); }
.section--nuit a { color: var(--cuivre); }
.section--nuit a:hover { color: var(--papier); }
.section--serree { padding-block: calc(var(--section-y) * .62); }

/* Deux sections consécutives de même fond fusionneraient visuellement.
   Un filet les sépare sans ajouter de bordure supplémentaire. */
.section--sable + .section--sable { border-top: 1px solid var(--sable-fonce); }

/* En-tête de section. UN titre, rien au-dessus. Voir plus bas pourquoi la
   classe .surtitre n'existe plus.

   Centré depuis le 2026-09-01, à la demande du client. Le centrage ne
   s'applique qu'aux en-têtes qui occupent toute la largeur d'une section : un
   titre qui vit dans une colonne de grille, face à une liste ou à un
   formulaire, reste aligné à gauche, sinon il se décroche de ce qu'il
   annonce. */
.tete-section {
  max-width: var(--lisible);
  margin: 0 auto var(--e-5);
  text-align: center;
}
.tete-section--large { max-width: 46rem; }
.tete-section > p {
  margin: var(--e-3) auto 0;
  /* Mesure plus courte que le bloc : un paragraphe centré se lit mal au-delà,
     l'oeil perd le début de la ligne suivante. */
  max-width: 58ch;
  font-size: var(--fs-lead); color: var(--ardoise);
}
.section--nuit .tete-section > p { color: var(--brume); }

/* Il n'y a plus de classe .surtitre, et c'est volontaire.
   Elle servait à poser un petit intitulé au-dessus d'un h2, du genre
   « Nos interventions » juste avant « Ce que Construland prend en charge ».
   Le client l'a fait retirer le 2026-09-01 : le procédé se voit, il annonce
   deux fois la même chose, et c'est un marqueur de page générée.
   Une section porte UN titre. Si l'intitulé apportait vraiment quelque chose,
   c'est qu'il aurait dû être le titre. */


/* --------------------------------------------------------------- Le trait --
   Un filet terracotta sous le mot qui porte le sens d'un titre.

   Première version : un tracé SVG irrégulier, façon feutre. Écarté le
   2026-09-10, jugé peu élégant, et à raison. Un trait tremblé lit « fait à la
   main » ; sur un métier où tout se joue au millimètre, c'est le contraire de
   ce qu'on veut raconter. Un filet tiré au trait lit « dessiné », ce qui est
   la bonne référence pour du bâtiment.

   Deux détails qui font la différence avec une bordure par défaut :

   - l'épaisseur est en em, donc proportionnelle au titre. Le filet fait 2 px
     sous un titre de section et près de 5 px sous la devise du hero, sans
     qu'on ait à le régler deux fois ;
   - il déborde légèrement du mot des deux côtés, comme un trait de repère sur
     un plan, au lieu de s'arrêter pile sur la dernière lettre.

   background-image plutôt qu'un ::after : un mot coupé en fin de ligne reçoit
   son filet sur les deux morceaux, ce qu'un pseudo-élément absolu ne sait pas
   faire. */

.trait {
  --filet: var(--brique);

  /* Trois réglages, et c'est tout ce qui pilote le filet.

     --filet-ep    épaisseur. En em, donc proportionnelle au titre : 2 px sous
                   un titre de section, près de 5 px sous la devise du hero,
                   sans avoir à la régler deux fois. Le max() garde un filet
                   visible sur les petits titres, où .055em tomberait sous le
                   pixel et disparaîtrait à certains niveaux de zoom.

     --filet-air   air laissé entre la ligne de descente et le haut du filet.
                   C'est le seul chiffre à toucher si le filet paraît trop
                   haut ou trop bas.

     --filet-reserve  padding qui empêche le filet d'être rogné. Il ne se voit
                   pas : la position le compense exactement. */
  --filet-ep:      max(2px, .055em);
  --filet-air:     .04em;
  --filet-reserve: .2em;

  background-image: linear-gradient(var(--filet), var(--filet));
  background-repeat: no-repeat;

  /* Position calculée depuis le bas de la boîte, réserve et épaisseur
     déduites. Sans ce calcul, le filet se posait sous la ligne de descente
     PUIS sous le padding : 0,33 em sous la ligne de base, soit 29 px sur la
     devise du hero. Sur un mot à fond plat comme « Réalisons », il se
     détachait du mot au lieu de le souligner. Il est maintenant à 0,24 em.

     L'épaisseur entre dans le calcul et ce n'est pas une coquetterie : elle a
     un plancher de 2 px, donc sous 36 px de titre elle cesse d'être
     proportionnelle. Sans la déduire, le filet remonterait sur les petits
     titres jusqu'à couper les jambages, alors qu'il est bien placé sur les
     grands. Ainsi calculé, l'écart vaut 0,24 em à toutes les tailles.

     Ne pas descendre sous 0,20 em au total : le jambage des p, g, j, q et y
     descend à 0,193 em dans Archivo, mesuré et non estimé. Un vrai
     text-decoration ferait mieux, il sait éviter les jambages tout seul ;
     il ne sait ni déborder du mot ni se tirer de gauche à droite, et ces
     deux-là sont le dessin. */
  background-position: 50%
    calc(100% - var(--filet-reserve) + var(--filet-air) + var(--filet-ep));
  background-size: calc(100% + .28em) var(--filet-ep);
  padding-bottom: var(--filet-reserve);
  -webkit-box-decoration-break: clone;
          box-decoration-break: clone;
}

/* Sur fond sombre, le terracotta s'éteint. Le cuivre du pied de page prend le
   relais, c'est la même couleur éclaircie pour le contraste. */
.section--nuit .trait, .bandeau .trait, .cine .trait { --filet: var(--cuivre); }

/* Le filet se tire de gauche à droite quand le titre entre dans l'écran.
   Une seule fois, et jamais deux fois sur le même titre : c'est une
   ponctuation, pas une animation. La classe est posée par js/script.js. */
.trait { transition: background-size 700ms cubic-bezier(.22, .7, .28, 1); }
[data-anime] .trait { background-size: 0 var(--filet-ep); }
[data-anime='vu'] .trait { background-size: calc(100% + .28em) var(--filet-ep); }

@media (prefers-reduced-motion: reduce) {
  .trait { transition: none; }
  [data-anime] .trait { background-size: calc(100% + .28em) var(--filet-ep); }
}

/* --------------------------------------------------------------- Boutons -- */

.bouton {
  display: inline-flex; align-items: center; justify-content: center;
  gap: .55em;
  padding: .82em 1.5em;
  border: 1px solid transparent;
  border-radius: var(--r);
  font-size: var(--fs-petit);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  /* Jamais sur deux lignes. Mesure : dans l'en-tete fixe de l'accueil, le CTA
     passait a deux lignes et depassait la barre par le haut. */
  white-space: nowrap;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition), transform var(--transition);
}
.bouton:active { transform: translateY(1px); }

/* Taille du pictogramme dans un bouton.
   Sans cette règle, un SVG en ligne sans attribut width hérite du
   height: auto du socle et sort à 0 par 0 : l'icône est bien dans le HTML,
   elle n'occupe aucune place, et personne ne la voit. C'était le cas du
   bouton d'appel du hero, de celui de la page merci et des deux des
   landings. Mesuré à 0 x 0 avant correction. */
.bouton svg { width: 1.05em; height: 1.05em; flex: none; }

.bouton--plein { background: var(--brique); color: var(--papier); }
.bouton--plein:hover { background: var(--brique-fonce); color: var(--papier); }

.bouton--ligne { background: transparent; color: var(--encre); border-color: var(--trait); }
.bouton--ligne:hover { border-color: var(--encre); color: var(--encre); background: transparent; }

.bouton--encre { background: var(--encre); color: var(--papier); }
.bouton--encre:hover { background: #000; color: var(--papier); }

.bouton--clair { background: var(--papier); color: var(--encre); }
.bouton--clair:hover { background: var(--sable); color: var(--encre); }

.bouton--large { width: 100%; }

/* Rangée d'actions. Les deux boutons doivent tomber exactement à la même
   hauteur : rien de plus haut que l'autre ne doit vivre dans le flux. */
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-3); }

.lien-fleche {
  display: inline-flex; align-items: center; gap: .5em;
  font-weight: 600; font-size: var(--fs-petit);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
}
.lien-fleche svg { width: .85em; height: .85em; transition: transform var(--transition); }
.lien-fleche:hover svg { transform: translateX(3px); }

/* -------------------------------------------------------------- En-tête -- */

.entete {
  position: sticky; top: 0; z-index: 100;
  background: rgba(255, 255, 255, .94);
  backdrop-filter: saturate(180%) blur(10px);
  border-bottom: 1px solid var(--trait);
}
.entete__barre {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3);
  min-height: 76px;
}

.marque { display: inline-flex; align-items: baseline; gap: .45rem; text-decoration: none; }
.marque__nom {
  font-family: var(--titre); font-weight: 700; font-size: 1.3125rem;
  letter-spacing: -.03em; color: var(--encre);
}
/* « .Be » collé au nom, dans la couleur qu'avait « Belgique » : brique sur
   fond clair, cuivre sur fond sombre (règles cine et pied plus bas). */
.marque__be { color: var(--brique); }

/* margin-left auto plutot que de compter sur space-between. Avec cinq entrees
   au lieu de six, l'espace libre de la barre se logeait entre la navigation et
   le bloc actions, et un trou s'ouvrait entre le bouton de devis et le
   telephone. Une marge automatique absorbe tout l'espace AVANT la navigation :
   navigation, bouton et telephone restent collés à droite.
   Sans effet en mobile, ou .nav est en position absolute donc hors du flux. */
.nav { display: flex; align-items: center; gap: var(--e-3); margin-left: auto; }
.nav__liste {
  display: flex; align-items: center;
  /* Gouttiere fixe et non clamp au viewport : en clamp, elle grandissait avec
     la largeur d'ecran alors que la barre est bornee a 1220 px, et la barre
     redebordait a 1920. */
  gap: 1.15rem;
}
.nav__lien {
  position: relative;
  /* Sans nowrap, « Qui sommes-nous » et « Zones d'intervention » se coupaient
     en deux et les six entrees retombaient sur trois lignes de hauteurs
     differentes. Mesure avant correction : tops a 26, 12, 12, -2, 12, 26. */
  white-space: nowrap;
  font-size: var(--fs-petit); font-weight: 500;
  color: var(--ardoise); text-decoration: none;
  padding-block: .35rem;
  transition: color var(--transition);
}
.nav__lien:hover { color: var(--encre); }
.nav__lien[aria-current='page'] { color: var(--encre); font-weight: 600; }
.nav__lien[aria-current='page']::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 2px; background: var(--brique);
}

.entete__actions { display: flex; align-items: center; gap: var(--e-3); }
/* Le téléphone est un bouton encadré, pas une ligne de texte posée là. Un
   numéro sans cadre ne se lit pas comme une action, et il se perd à côté du
   bouton de devis qui, lui, en a un. Le pictogramme de combiné est à gauche
   du numéro, aligné sur sa hauteur d'x. */
.entete__tel {
  gap: .5em;
  /* Hauteur imposée plutôt que déduite du padding : le bouton sortait à 45 px
     quand les pastilles voisines en font 44, et l'écart d'un pixel se voit
     entre deux bordures côte à côte. */
  height: 44px; padding-block: 0;
}
.entete__tel svg { width: 1em; height: 1em; flex: none; color: var(--brique); }
/* Sur un bouton plein, le picto brique se confondait avec le fond brique :
   l'icône était dans le HTML mais invisible, dans l'en-tête des landings. */
.entete__tel.bouton--plein svg { color: currentColor; }
.entete[data-mode='cine'] .entete__tel svg { color: var(--cuivre); }

/* Pastille carrée, exactement la boîte du burger : 44 px, même bordure, même
   rayon. Les deux se posent côte à côte sans qu'aucun réglage fin ne soit
   nécessaire, et la cible reste au-dessus du minimum tactile. */
.entete__pastille {
  display: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  border: 1px solid var(--trait); border-radius: var(--r);
  color: var(--encre);
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.entete__pastille svg { width: 20px; height: 20px; }

/* Pastilles pleines, pas des contours. Un pictogramme accent dans un carré
   vide se lit comme un ornement ; le même en blanc sur un aplat de couleur se
   lit comme un bouton. C'est le seul endroit du site où deux couleurs pleines
   se côtoient, et c'est assumé : ce sont deux actions, pas deux décors. */
.entete__pastille--tel {
  background: var(--brique); border-color: var(--brique); color: var(--papier);
}
.entete__pastille--tel:hover {
  background: var(--brique-fonce); border-color: var(--brique-fonce); color: var(--papier);
}

/* Vert de la marque WhatsApp. Le glyphe reste sombre et non blanc : blanc sur
   #25D366 ne donne que 2,0 pour 1, sous le minimum de 3 pour 1 exigé d'un
   élément graphique porteur de sens. En vert foncé, 7,5 pour 1. */
.entete__pastille--wa {
  background: #25D366; border-color: #25D366; color: #0b2e18;
}
.entete__pastille--wa:hover { background: #1eb356; border-color: #1eb356; color: #0b2e18; }

/* Sur le hero sombre, les pastilles gardent leur aplat : ce sont des CTA, pas
   des éléments de chrome qui doivent s'effacer. */
.entete[data-mode='cine'] .entete__pastille--tel { border-color: var(--brique); }
.entete[data-mode='cine'] .entete__pastille--wa  { border-color: #25D366; }

/* WhatsApp est visible à toutes les largeurs : c'est une action, pas un
   ornement, et elle ne coûte que 44 px. */
.entete__pastille--wa { display: inline-flex; }

/* En dessous de 1100 px le bouton complet disparaît, la pastille prend le
   relais. Les deux ne sont jamais visibles ensemble. */
/* 1200 px et non 1100 : l'ajout de la pastille WhatsApp coûte 44 px plus sa
   gouttière, et la barre débordait de 47 px à 1101 px. Mesuré, pas estimé. */
@media (max-width: 1200px) {
  .entete__pastille--tel { display: inline-flex; }
}

/* Sous 700 px, WhatsApp sort de l'en-tête : la barre d'appel fixe en bas
   d'écran le propose déjà, en bien plus grand. Le garder ici ferait déborder
   la barre de 19 px à 390 px, pour une action affichée deux fois. */
@media (max-width: 700px) {
  .entete__pastille--wa { display: none; }
}

.burger {
  display: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--trait); border-radius: var(--r);
  cursor: pointer;
}
.burger__traits, .burger__traits::before, .burger__traits::after {
  content: ''; display: block; width: 18px; height: 1.5px;
  background: var(--encre); transition: transform var(--transition), opacity var(--transition);
}
.burger__traits::before { transform: translateY(-6px); }
.burger__traits::after  { transform: translateY(4.5px); }
.burger[aria-expanded='true'] .burger__traits { background: transparent; }
.burger[aria-expanded='true'] .burger__traits::before { transform: rotate(45deg); }
.burger[aria-expanded='true'] .burger__traits::after  { transform: rotate(-45deg) translateY(0); }

/* Le bouton téléphone complet saute avant la navigation : c'est le seul des
   trois blocs qui soit répété ailleurs sur la page, et la pastille le
   remplace au même endroit.
   Mesure à cinq entrées : marque 194 + navigation 621 + téléphone 101, plus
   les gouttières et la marge de page, soit 1043 px pour la barre complète. */
@media (max-width: 1200px) { .entete__tel { display: none; } }

@media (max-width: 980px) {
  .burger { display: inline-flex; }
  .entete__tel { display: none; }
  .nav {
    /* top: 100% plutot qu'une hauteur en dur : la barre mesure 83 px et non
       les 76 px de son min-height, et l'ecart laissait une bande claire
       entre l'en-tete et le panneau. */
    position: absolute; top: 100%; left: 0; right: 0;
    display: block;
    background: var(--papier);
    border-bottom: 1px solid var(--trait);
    padding: var(--e-3) var(--marge-page) var(--e-5);
    max-height: calc(100dvh - 100%);
    overflow-y: auto;
    transform: translateY(-8px);
    opacity: 0; visibility: hidden;
    transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
  }
  .nav[data-ouvert='true'] { opacity: 1; visibility: visible; transform: none; }
  .nav__liste { display: block; }
  .nav__liste li + li { border-top: 1px solid var(--trait); }
  .nav__lien { display: block; padding: var(--e-3) 0; font-size: 1.0625rem; }
  .nav__lien[aria-current='page']::after { display: none; }
  .nav .bouton { margin-top: var(--e-3); width: 100%; }
}

/* ------------------------------------------------------- Hero cinématique --
   La vidéo plein cadre se referme au scroll dans le « C » de Construland.

   Une seule variable pilote tout : --fermeture, de 0 à 1, écrite par
   js/script.js sur requestAnimationFrame. Le CSS fait le reste en calc, ce
   qui garde le JS à une trentaine de lignes et sans aucune dépendance.

   La vidéo n'est jamais masquée. C'est un cache plus grand que l'écran qui
   se pose par-dessus et n'y laisse ouverte que la silhouette. Travailler par
   soustraction plutôt qu'en découpant la vidéo évite d'avoir à faire tenir la
   forme finale dans un masque agrandi, ce qui imposerait une forme pleine et
   ferait apparaître un contour parasite autour du logo. */

.cine {
  --fermeture: 0;
  /* Course du scroll épinglé. Mesurée : à 306 px, la fermeture atteignait
     0,69 en 120 px de molette et le texte tombait à 20 % d'opacité avant que
     l'oeil ait eu le temps de le lire. */
  --course: clamp(380px, 58vh, 700px);

  /* Ouverture du masque. Le maximum est calé sur la plus grande dimension du
     viewport : au-delà, l'ouverture déborde de tous les côtés et on ne voit
     qu'une vidéo plein cadre, ce qui est exactement l'état de départ. */
  --ouv-max: 150vmax;
  /* Taille finale de la silhouette.
     Le plancher en vmax n'est pas cosmétique : le cache doit rester plus
     grand que la diagonale du viewport, sinon les angles de l'écran laissent
     réapparaître la vidéo. Le cache vaut cinq fois --ouverture, et la
     diagonale ne dépasse jamais 1,42 vmax, d'où 29vmax au minimum.
     Mesuré : en 2560 sur 1440, un plafond à 580 px donnait un cache de
     2900 px pour une diagonale de 2937. */
  --ouv-min: max(clamp(320px, 54vmin, 760px), 29vmax);
  --ouverture: calc(var(--ouv-max) + (var(--ouv-min) - var(--ouv-max)) * var(--fermeture));

  position: relative;
  background: var(--sable);
}

.cine__piste { height: calc(100vh + var(--course)); height: calc(100svh + var(--course)); }

.cine__ecran {
  position: sticky; top: 0;
  height: 100vh; height: 100svh;
  overflow: hidden;
  display: grid; place-items: center;
  /* Le fond est celui de la section suivante : quand la vue s'est refermée,
     la transition vers « Nos interventions » est continue. */
  background: var(--sable);
}

.cine__media {
  /* Aucun masque. La vidéo reste plein cadre du début à la fin ; c'est le
     cache posé par-dessus qui referme la vue sur la silhouette. */
  position: absolute; inset: 0;
}

.cine__fond, .cine__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.cine__video { opacity: 0; transition: opacity 600ms ease; }
.cine__video[data-prete='oui'] { opacity: 1; }

/* Voile de lisibilité. Deux dégradés plutôt qu'un aplat : le texte est au
   centre, et un aplat assez fort pour lui suffire éteindrait la photo. */
.cine__voile {
  position: absolute; inset: 0;
  background:
    radial-gradient(58% 46% at 50% 48%, rgba(0, 0, 0, .6), rgba(0, 0, 0, .14) 78%),
    linear-gradient(to bottom, rgba(0, 0, 0, .44), rgba(0, 0, 0, .2) 34%, rgba(0, 0, 0, .5));
  opacity: calc((1 - var(--fermeture)) * 1.7);
}

/* Le cache. Il couvre tout l'écran et n'ouvre que la silhouette.
   Le facteur 5 vient du cadre du SVG : la silhouette occupe le cinquième
   central, donc à --ouverture donnée le remplissage déborde de deux fois
   cette valeur de chaque côté et couvre le viewport quelle que soit sa
   taille. Détail dans inc/hero.php.
   max-width est neutralisé : la règle du socle bornait le SVG à la largeur de
   son parent et ramenait le cache à la taille du seul logo. */
.cine__decoupe {
  position: absolute;
  width: calc(var(--ouverture) * 5); height: calc(var(--ouverture) * 5);
  max-width: none;
  left: 50%; top: 50%;
  translate: -50% -50%;
  opacity: calc((var(--fermeture) - .52) / .30);
  pointer-events: none;
}
/* Enfant direct uniquement. Poser fill sur le <svg> ferait gagner la règle CSS
   sur les attributs fill des blocs du <mask>, qui deviendraient tous sable :
   le masque serait uniforme et la silhouette disparaîtrait. */
.cine__decoupe > rect { fill: var(--sable); }

.cine__texte {
  position: relative;
  z-index: 2;
  width: min(100%, 46rem);
  padding-inline: var(--marge-page);
  text-align: center;
  color: var(--papier);
  /* Plein jusqu'à 30 % de la course, éteint à 60 %, soit juste avant que le
     cache sable ne commence à couvrir l'écran : du texte blanc à 20 %
     d'opacité sur fond crème est illisible et sale. */
  opacity: calc((.60 - var(--fermeture)) / .30);
  transform: translate3d(0, calc(var(--fermeture) * -56px), 0);
}
.cine[data-referme='oui'] .cine__texte { pointer-events: none; }

.cine__devise {
  font-family: var(--titre);
  font-weight: 700;
  font-size: clamp(2.75rem, 1.5rem + 5.2vw, 5.5rem);
  line-height: 1;
  letter-spacing: -.035em;
  color: var(--papier);
  text-wrap: balance;
  text-shadow: 0 2px 30px rgba(0, 0, 0, .35);
}

.cine h1 {
  margin: var(--e-4) auto 0;
  font-family: var(--texte);
  font-size: var(--fs-lead);
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.45;
  color: var(--papier);
  max-width: 34rem;
  text-shadow: 0 1px 16px rgba(0, 0, 0, .45);
}

.cine__accroche {
  margin: var(--e-2) auto 0;
  font-size: var(--fs-petit);
  color: rgba(255, 255, 255, .84);
  max-width: 34rem;
  text-shadow: 0 1px 14px rgba(0, 0, 0, .4);
}

/* Les deux boutons du hero font la même largeur.
   En flex, chacun prend la largeur de son texte : « Demander un devis
   gratuit » sortait nettement plus large que le numéro, et deux boutons de
   tailles différentes côte à côte se lisent comme un principal et un
   accessoire. Ce sont deux actions de même rang. Une grille à deux colonnes
   égales règle ça sans toucher au contenu. */
.actions--centrees {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  justify-content: center;
  gap: var(--e-3);
  max-width: 34rem;
  margin: var(--e-4) auto 0;
}
@media (max-width: 560px) { .actions--centrees { grid-template-columns: 1fr; } }

/* Bouton posé sur une image : un contour clair, pas un contour ardoise qui
   disparaîtrait sur une zone sombre de la photo. */
/* Un simple contour blanc translucide se noyait dans une photo chargée : le
   bouton d'appel du hero paraissait éteint à côté du bouton de devis. Il lui
   faut un fond sombre qui détache le texte, un contour net, et le pictogramme
   à l'accent pour signaler que c'est une action. */
.bouton--voile {
  background: rgba(16, 18, 21, .58);
  color: var(--papier);
  border-color: rgba(255, 255, 255, .64);
  backdrop-filter: blur(10px) saturate(140%);
}
.bouton--voile svg { color: var(--cuivre); }
.bouton--voile:hover { background: var(--papier); color: var(--encre); border-color: var(--papier); }
.bouton--voile:hover svg { color: var(--brique); }

/* Sans masque CSS, la vidéo reste en plein cadre et le texte est lisible :
   l'effet manque, la page fonctionne. */
@supports not ((-webkit-mask-image: url("")) or (mask-image: url(""))) {
  .cine__decoupe { display: none; }
  .cine__piste { height: 100svh; }
}

/* Sur petit écran, la course se fait au pouce : 58vh de molette virtuelle
   deviennent pénibles. On raccourcit, l'effet reste lisible. */
@media (max-width: 700px) {
  .cine { --course: clamp(300px, 42vh, 430px); }
}

/* Mouvement réduit : aucune animation, aucun scroll épinglé, aucune lecture
   automatique. L'image fixe et le texte, point. */
@media (prefers-reduced-motion: reduce) {
  .cine__piste { height: auto; }
  .cine__ecran { position: static; height: auto; min-height: 78svh; padding-block: var(--e-6); }
  .cine__media { -webkit-mask-image: none; mask-image: none; }
  .cine__decoupe { display: none; }
  .cine__texte { opacity: 1; transform: none; }
  .cine__voile { opacity: 1; }
}

/* ------------------------------------------------- En-tête sur hero sombre --
   Sur l'accueil, l'en-tête est transparent au-dessus de la vidéo puis se
   remplit progressivement. --voile est écrit par le même passage de scroll
   que --fermeture : une seule lecture de position par image. */

.entete[data-mode='cine'] {
  --voile: 0;
  /* fixed et non sticky : le hero doit commencer au pixel zéro et passer
     DERRIÈRE l'en-tête. En sticky, l'en-tête reste dans le flux et pousse la
     vidéo de 83 px vers le bas, ce qui laisse une bande claire en haut. */
  position: fixed; inset: 0 0 auto 0;
  background: rgb(22 24 28 / calc(var(--voile) * .93));
  border-bottom-color: rgb(255 255 255 / calc(var(--voile) * .1));
  backdrop-filter: blur(calc(var(--voile) * 9px)) saturate(140%);
}
.entete[data-mode='cine'] .marque__nom,
.entete[data-mode='cine'] .nav__lien,
.entete[data-mode='cine'] .entete__tel { color: var(--papier); }
.entete[data-mode='cine'] .marque__be { color: var(--cuivre); }
.entete[data-mode='cine'] .nav__lien:hover,
.entete[data-mode='cine'] .entete__tel:hover { color: var(--cuivre); }
.entete[data-mode='cine'] .nav__lien[aria-current='page']::after { background: var(--cuivre); }
.entete[data-mode='cine'] .burger { border-color: rgba(255, 255, 255, .35); }
.entete[data-mode='cine'] .burger__traits,
.entete[data-mode='cine'] .burger__traits::before,
.entete[data-mode='cine'] .burger__traits::after { background: var(--papier); }

/* Le panneau mobile déroulé est opaque : les libellés clairs de l'en-tête n'y
   ont pas cours, ils redeviennent sombres sur fond papier. */
@media (max-width: 980px) {
  .entete[data-mode='cine'] .nav { background: var(--papier); }
  .entete[data-mode='cine'] .nav__lien { color: var(--ardoise); }
  .entete[data-mode='cine'] .nav__lien:hover { color: var(--encre); }
  .entete[data-mode='cine'] .nav .bouton--plein { color: var(--papier); }
}

/* ----------------------------------------------------------------- Hero -- */

.hero { padding-block: clamp(3rem, 1.5rem + 5vw, 5.5rem) var(--section-y); }
.hero__grille {
  display: grid;
  /* 1fr 1fr : quand deux colonnes se font face, 1,05fr / 0,95fr se voit. */
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 1rem + 3.5vw, 4.5rem);
  align-items: center;
}
.hero__texte > * + * { margin-top: var(--e-4); }
.hero h1 { font-size: var(--fs-hero); }
.hero__accroche {
  font-size: var(--fs-lead); color: var(--ardoise); max-width: 34rem;
}
.hero__media {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-l);
  overflow: hidden;
  background: var(--sable-fonce);
}
.hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* La légende sort du flux : empilée sous le bloc, elle décalait la colonne
   voisine et cassait l'alignement vertical des deux colonnes. */
.hero__legende {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: var(--e-4) var(--e-3) var(--e-2);
  font-size: var(--fs-micro); color: var(--papier);
  background: linear-gradient(to top, rgba(0, 0, 0, .62), transparent);
}

.hero__points {
  display: flex; flex-wrap: wrap; gap: var(--e-2) var(--e-4);
  padding-top: var(--e-3); border-top: 1px solid var(--trait);
}
.hero__points li {
  display: flex; align-items: center; gap: .5em;
  font-size: var(--fs-petit); color: var(--ardoise);
}
.hero__points svg { width: 1em; height: 1em; color: var(--brique); flex: none; }

@media (max-width: 860px) {
  .hero__grille { grid-template-columns: 1fr; }
  .hero__media { aspect-ratio: 3 / 2; order: -1; }
}

/* --------------------------------------------------------------- Grilles --
   Paliers explicites plutôt que repeat(auto-fit, minmax(...)). L'auto-fit est
   pratique et produit des rangées orphelines : cinq items retombent en 3 + 2,
   puis un seul item pend à gauche sur la dernière rangée. On compte les items
   avant de choisir le mode de grille. */

.grille { display: grid; gap: var(--gouttiere); }
.grille--2 { grid-template-columns: repeat(2, 1fr); }
.grille--3 { grid-template-columns: repeat(3, 1fr); }
.grille--4 { grid-template-columns: repeat(4, 1fr); }
.grille--5 { grid-template-columns: repeat(5, 1fr); }

@media (max-width: 1080px) {
  .grille--5 { grid-template-columns: repeat(3, 1fr); }
  .grille--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  .grille--3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grille--5, .grille--4, .grille--3, .grille--2 { grid-template-columns: 1fr; }
}

/* Cartes alignées par subgrid : des titres de longueurs différentes décalent
   sinon tout le texte en dessous d'une carte à l'autre. Les rangées sont
   partagées, badges, titres et paragraphes tombent au même niveau.

   Deux variantes, selon le nombre d'éléments réels de la carte. Compter avant
   de choisir : une carte à trois enfants dans une grille à quatre rangées
   oblige à glisser un <span> vide pour combler, ce que faisaient les cartes
   du blog avant qu'on retire leur surtitre. */
.grille--alignee   { grid-template-rows: auto auto 1fr auto; }   /* pastille, titre, texte, pied */
.grille--alignee-3 { grid-template-rows: auto 1fr auto; }        /* titre, texte, pied */
.grille--alignee-2 { grid-template-rows: auto 1fr; }             /* titre, texte */
.grille--alignee   > .carte { grid-row: span 4; grid-template-rows: subgrid; }
.grille--alignee-3 > .carte { grid-row: span 3; grid-template-rows: subgrid; }
.grille--alignee-2 > .carte { grid-row: span 2; grid-template-rows: subgrid; }

/* --------------------------------------------------------------- Bande --
   Quatre photos en portrait, bord à bord, sur toute la largeur de l'écran.

   Elle sort volontairement du conteneur de 1220 px : c'est la seule
   respiration pleine largeur du site, et c'est ce qui la rend remarquable.
   Le format portrait est un choix, pas un hasard : quatre paysages côte à
   côte auraient donné une frise basse et anonyme.

   Ne demande que des photos d'après travaux, aucune photo d'état initial. */

.bande { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px; }
.bande figure { position: relative; margin: 0; aspect-ratio: 3 / 4; overflow: hidden; background: var(--sable-fonce); }
.bande img { width: 100%; height: 100%; object-fit: cover; }
.bande figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: var(--e-5) var(--e-3) var(--e-3);
  color: var(--papier); font-size: var(--fs-petit); font-weight: 600;
  background: linear-gradient(to top, rgba(0, 0, 0, .74), transparent);
}
.bande figcaption span { display: block; font-weight: 400; font-size: var(--fs-micro); opacity: .84; }

/* Quatre portraits deviennent illisibles en dessous de 900 px : deux par
   rangée, ce qui tombe juste puisqu'il y en a quatre. */
@media (max-width: 900px) { .bande { grid-template-columns: repeat(2, 1fr); } }

/* ------------------------------------------------------------- Mosaïque --
   Cinq tuiles, une grande et quatre petites. L'asymétrie est délibérée et
   calculée : la grande occupe deux colonnes sur deux rangées, les quatre
   autres remplissent exactement le reste. Aucun trou, aucune tuile orpheline.

       +-----------+--+--+
       |           | 2| 3|
       |     1     +--+--+
       |           | 4| 5|
       +-----------+--+--+

   La grande tuile prend deux colonnes sur deux rangées, les quatre autres
   occupent une cellule chacune. Quatre colonnes sur deux rangées font huit
   cellules : 2 x 2 pour la grande, plus quatre, le compte tombe juste.

   Un premier jet donnait aussi deux colonnes à la cinquième tuile. Il ne
   restait plus qu'une cellule libre, elle n'y tenait pas, et elle basculait
   sur une troisième rangée en laissant un trou derrière elle. */

.mosaique {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(0, 1fr);
  gap: var(--gouttiere);
  aspect-ratio: 16 / 9;
}
.mosaique > * { position: relative; overflow: hidden; border-radius: var(--r-l); background: var(--sable-fonce); }
.mosaique > *:nth-child(1) { grid-column: span 2; grid-row: span 2; }
.mosaique img { width: 100%; height: 100%; object-fit: cover; transition: transform 500ms cubic-bezier(.2, .6, .3, 1); }
.mosaique a:hover img { transform: scale(1.04); }

.mosaique__legende {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: var(--e-4) var(--e-3) var(--e-2);
  color: var(--papier); font-size: var(--fs-petit); font-weight: 600;
  background: linear-gradient(to top, rgba(0, 0, 0, .72), transparent);
}
.mosaique__legende span { display: block; font-weight: 400; font-size: var(--fs-micro); opacity: .84; }

/* Deux colonnes : la grande garde ses deux colonnes sur une seule rangée, les
   quatre autres se rangent deux par deux. Toujours pas de trou. */
/* Deux colonnes : la grande garde ses deux colonnes sur une seule rangée,
   les quatre autres se rangent deux par deux. Toujours pas de trou. */
@media (max-width: 900px) {
  .mosaique { grid-template-columns: repeat(2, 1fr); aspect-ratio: auto; grid-auto-rows: 44vw; }
  .mosaique > *:nth-child(1) { grid-column: span 2; grid-row: span 1; }
}
@media (max-width: 560px) {
  .mosaique { grid-template-columns: 1fr; grid-auto-rows: 62vw; }
  .mosaique > *:nth-child(1) { grid-column: span 1; }
}

/* ----------------------------------------------------------- Carte zone --
   Un point par commune desservie, aux coordonnées réelles, taille selon la
   population. Générée par inc/carte.php depuis data/communes-be.json.
   Le nom est carte-zone et non carte : .carte désigne déjà les blocs en
   carte du site, avec fond, padding et coins arrondis. */

.carte-zone { width: 100%; height: auto; overflow: visible; }
.carte-zone__points circle { fill: var(--brique); }
.carte-zone__villes text {
  fill: var(--encre);
  font-family: var(--texte); font-size: 11px; font-weight: 600;
  /* Le contour de la couleur du fond détache l'étiquette de la nuée de
     points, sans quoi les noms deviennent illisibles autour des grandes
     villes, là où les points sont les plus denses. */
  paint-order: stroke;
  stroke: var(--sable); stroke-width: 3.5px; stroke-linejoin: round;
}

/* ---------------------------------------------------------------- Cartes -- */

.carte {
  display: grid;
  gap: var(--e-2);
  align-content: start;
  padding: var(--e-4);
  background: var(--sable);
  border-radius: var(--r-l);
  transition: background var(--transition), transform var(--transition);
}
/* Sur fond sable, la carte s'inverse : le contraste vient du fond, pas d'une
   bordure ajoutée. Des bordures partout donnent une allure de tableur. */
.section--sable .carte { background: var(--papier); border: 1px solid var(--trait); }
.section--nuit  .carte { background: #1e2126; color: var(--brume); }

.carte p { color: var(--ardoise); font-size: var(--fs-petit); }
.section--nuit .carte p { color: var(--brume); }

.carte--lien { text-decoration: none; color: inherit; }
.carte--lien:hover { transform: translateY(-2px); color: inherit; }
.section--sable .carte--lien:hover { border-color: var(--encre); }

.carte__pastille {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: var(--r);
  background: var(--brique-voile); color: var(--brique-fonce);
  margin-bottom: var(--e-1);
}
.carte__pastille svg { width: 20px; height: 20px; }
.section--nuit .carte__pastille { background: rgba(224, 138, 85, .15); color: var(--cuivre); }

.carte__pied {
  margin-top: var(--e-2); padding-top: var(--e-2);
  border-top: 1px solid var(--trait);
  font-size: var(--fs-micro); font-weight: 600; color: var(--brique-fonce);
}
.section--nuit .carte__pied { border-color: #2c3037; color: var(--cuivre); }

/* ------------------------------------------------------------- Étapes  --- */

.etape { display: grid; gap: var(--e-2); align-content: start; }
.etape__num {
  font-family: var(--titre); font-weight: 700; font-size: 2rem; line-height: 1;
  color: var(--brique); font-variant-numeric: lining-nums;
}
.etape h3 { font-size: 1.0625rem; font-family: var(--texte); font-weight: 600; letter-spacing: 0; }
.etape p { font-size: var(--fs-petit); color: var(--ardoise); }
.grille--etapes { grid-template-rows: auto auto 1fr; }
.grille--etapes > .etape { grid-row: span 3; grid-template-rows: subgrid; }

/* ------------------------------------------------------------- Galerie  -- */
/* Grid et non flex centré : le flex rattrape une dernière rangée incomplète
   mais casse l'alignement vertical des colonnes, et une galerie de photos se
   juge d'abord sur l'alignement de ses bords. */

/* -------------------------------------------------- Titres de section --
   Tous les h1 et h2 du site sont centrés, demandé le 2026-09-11 : certains
   l'étaient par .tete-section, d'autres non, et la page se lisait comme deux
   gabarits cousus ensemble.

   Trois exceptions, et ce sont les seules. Un titre centré au-dessus d'un
   texte au fer à gauche cesse de se rattacher à ce qu'il annonce :

   - le corps d'un article, qui est de la lecture suivie ;
   - le titre d'une carte, qui coiffe un paragraphe court au fer à gauche ;
   - le titre d'un formulaire, qui est l'étiquette des champs sous lui. */

h1, h2 { text-align: center; }

/* Le bandeau d'appel à l'action est une colonne étroite à côté d'un bouton :
   son titre centré au-dessus d'un paragraphe au fer à gauche se voyait comme
   une erreur. Les deux sont centrés ensemble, le bouton garde sa colonne. */
.bandeau > div:first-child { text-align: center; }

.prose--article h1,
.prose--article h2,
.prose--article h3,
.carte h2,
.formulaire h2 { text-align: left; }

/* ------------------------------------------------------ Bloc de service --
   Un service = une rangée. La photo occupe la moitié et change de côté d'une
   rangée à l'autre : sans cette alternance, neuf rangées identiques se lisent
   comme un tableau et le regard décroche à la troisième.

   Quatre des neuf services n'ont pas de photo qui les montre dans les
   dossiers fournis, et illustrer une toiture avec une photo d'escalier se
   voit. Ces rangées passent sur une colonne centrée, prestations sur deux
   colonnes. C'est une variante de mise en page assumée, pas un trou : elle a
   son propre équilibre et ne demande rien pour paraître finie. */

.service__grille {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 1rem + 3.5vw, 4.5rem);
  align-items: center;
}
/* order sur la figure seule : le texte garde sa place dans le flux du DOM,
   donc l'ordre de lecture au clavier et au lecteur d'écran reste celui du
   document quelle que soit la rangée. */
.service__grille--droite .service__vue { order: 2; }

.service__vue {
  margin: 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--r-l);
  background: var(--sable-fonce);
}
.service__vue img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* L'en-tête de la rangée est centré comme partout ailleurs sur le site :
   pictogramme, titre, phrase d'introduction. La liste des prestations reste
   au fer à gauche, c'est une liste et elle se lit en colonne. */
.service__texte > * + * { margin-top: var(--e-3); }
/* display:flex et non inline-flex : la pastille est inline-flex par défaut,
   et margin-inline:auto ne centre pas un élément en ligne. */
.service__texte > .carte__pastille { display: flex; margin-inline: auto; }
.service__texte > h2,
.service__texte > .service__intro { text-align: center; }
.service__texte .liste-checks { margin-top: var(--e-4); text-align: left; }
.service__texte > p:last-child { text-align: center; }
.service__intro { color: var(--ardoise); font-size: var(--fs-lead); }

/* Variante sans photo. La liste passe sur deux colonnes : sur une seule, une
   colonne de sept lignes sous un titre centré laisse la rangée déséquilibrée
   à droite. */
.service__seul { max-width: 860px; margin-inline: auto; }
.service__seul .liste-checks--2col { margin-top: var(--e-5); }
.service__lien { margin-top: var(--e-4); text-align: center; }

@media (max-width: 900px) {
  .service__grille { grid-template-columns: 1fr; }
  /* La photo repasse au-dessus du texte sur toutes les rangées : en une
     colonne, l'alternance ne se voit plus et ne fait que déplacer l'image. */
  .service__grille--droite .service__vue { order: 0; }
  .service__vue { aspect-ratio: 4 / 3; }
}

/* ------------------------------------------------- Lots de réalisations --
   La page réalisations publie toutes les photos fournies, aujourd'hui 34.
   D'affilée, ça fait un mur de vignettes que personne ne parcourt jusqu'au
   bout. Groupées par corps de métier, ça fait cinq ensembles courts, chacun
   sous son titre, et le visiteur sait à tout moment ce qu'il regarde.

   L'écart entre deux lots est volontairement plus grand que la gouttière de
   la grille : c'est lui, et non un filet, qui sépare les groupes. */

.lot + .lot { margin-top: clamp(3.5rem, 2rem + 4vw, 6rem); }
.lot__tete { text-align: center; margin-bottom: var(--e-4); }
.lot__compte {
  margin-top: var(--e-1);
  font-size: var(--fs-micro);
  color: var(--ardoise);
}

.galerie { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gouttiere); }
@media (max-width: 900px) { .galerie { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .galerie { grid-template-columns: 1fr; } }

.projet { display: grid; gap: var(--e-2); text-decoration: none; color: inherit; }
/* 4/5 portrait et non 4/3 paysage : les photos de chantier fournies sont
   prises au téléphone, donc verticales. Un cadre paysage les recadrait de
   moitié et coupait systématiquement le haut de ce qui était montré. */
.projet__vue {
  aspect-ratio: 4 / 5; overflow: hidden; border-radius: var(--r-l);
  background: var(--sable-fonce);
}
.projet__vue img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 400ms cubic-bezier(.2, .6, .3, 1);
}
.projet:hover .projet__vue img { transform: scale(1.03); }
.projet__meta {
  display: flex; flex-wrap: wrap; gap: .4em .8em;
  font-size: var(--fs-micro); color: var(--ardoise);
}
.projet h3 { font-size: 1.125rem; font-family: var(--texte); font-weight: 600; letter-spacing: 0; }

/* Lieu du chantier sous la photo : épingle, commune, puis province en
   retrait. Une commune seule en gris clair se lisait comme un reste. */
.projet__lieu {
  display: flex; flex-wrap: wrap; align-items: center; gap: .2em .45em;
  font-size: var(--fs-petit); line-height: 1.3;
}
.projet__lieu svg { width: 1em; height: 1em; color: var(--brique); flex: none; }
.projet__ville { font-weight: 600; }
.projet__province { color: var(--ardoise); }
.projet__province::before { content: "·"; margin-right: .45em; color: var(--ardoise); }

/* Renvoi en astérisque dans une introduction de page, et sa note. */
.renvoi { color: var(--brique); margin-left: .1em; }
.entete-page .note-renvoi {
  margin-top: var(--e-2);
  font-size: var(--fs-micro);
  color: var(--ardoise);
}

/* --------------------------------------------------------------- Listes -- */

.liste-checks { display: grid; gap: var(--e-2); }
.liste-checks li { display: flex; gap: .7em; align-items: flex-start; }
.liste-checks svg { width: 1.05em; height: 1.05em; margin-top: .32em; color: var(--brique); flex: none; }
.section--nuit .liste-checks svg { color: var(--cuivre); }

/* Deux colonnes pour les listes longues, une seule en dessous de 640px. */
.liste-checks--2col { grid-template-columns: repeat(2, 1fr); gap: var(--e-2) var(--gouttiere); }
@media (max-width: 640px) { .liste-checks--2col { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------- Article --
   Le corps d'un article est plus long que n'importe quelle autre page : la
   mesure de ligne et le rythme vertical y comptent davantage. */

.prose--article { max-width: 68ch; font-size: 1.0625rem; line-height: 1.72; }
.prose--article > * + * { margin-top: var(--e-3); }
.prose--article h2 {
  margin-top: var(--e-6);
  padding-top: var(--e-3);
  border-top: 1px solid var(--trait);
}
.prose--article h3 { margin-top: var(--e-5); }
.prose--article p, .prose--article li { color: var(--ardoise); }
.prose--article strong { color: var(--encre); font-weight: 600; }

.prose__liste { display: grid; gap: var(--e-2); margin-top: var(--e-3); }
.prose__liste li { display: flex; gap: .7em; }
.prose__liste li::before {
  content: ''; flex: none;
  width: 5px; height: 5px; margin-top: .72em;
  border-radius: 50%; background: var(--brique);
}

.prose--article blockquote {
  margin: var(--e-4) 0;
  padding: var(--e-3) 0 var(--e-3) var(--e-4);
  border-left: 2px solid var(--brique);
  font-size: 1.125rem;
  line-height: 1.55;
  color: var(--encre);
}

/* Un tableau large deborde sur mobile : il defile dans son propre cadre
   plutot que de faire defiler la page entiere. */
.prose__tableau { overflow-x: auto; margin-top: var(--e-4); }
.prose__tableau table { border-collapse: collapse; width: 100%; font-size: var(--fs-petit); }
.prose__tableau th, .prose__tableau td {
  text-align: left; padding: .7rem .9rem;
  border-bottom: 1px solid var(--trait);
}
.prose__tableau th { color: var(--encre); font-weight: 600; white-space: nowrap; }
.prose__tableau td { color: var(--ardoise); }

.prose--article code {
  font-size: .9em; padding: .1em .35em;
  background: var(--sable); border-radius: 3px;
}

.sommaire {
  padding: var(--e-3) var(--e-4);
  background: var(--sable);
  border-radius: var(--r-l);
  margin-bottom: var(--e-5);
}
.sommaire ol { display: grid; gap: .45rem; counter-reset: som; }
.sommaire li { counter-increment: som; font-size: var(--fs-petit); }
.sommaire li::before { content: counter(som, decimal-leading-zero) '  '; color: var(--brique); font-weight: 600; }
.sommaire a { color: var(--ardoise); text-decoration: none; }
.sommaire a:hover { color: var(--encre); text-decoration: underline; }

.liste-communes {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--e-1) var(--gouttiere);
  font-size: var(--fs-petit); color: var(--ardoise);
}
@media (max-width: 900px) { .liste-communes { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px) { .liste-communes { grid-template-columns: repeat(2, 1fr); } }

.prose { max-width: var(--lisible); }
.prose > * + * { margin-top: var(--e-3); }
.prose h2 { margin-top: var(--e-5); }
.prose h3 { margin-top: var(--e-4); }
.prose ul { display: grid; gap: var(--e-1); padding-left: 1.1em; }
.prose ul li { list-style: disc; }
.prose p, .prose li { color: var(--ardoise); }

/* --------------------------------------------------------- Bandeau appel -- */

.bandeau {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--gouttiere);
  align-items: center;
  padding: clamp(1.75rem, 1rem + 2.4vw, 3rem);
  border-radius: var(--r-l);
  background: var(--nuit);
  color: var(--brume);
}
.bandeau h2 { color: var(--papier); font-size: var(--fs-h2); }
/* margin-inline:auto n'est pas décoratif ici. Le paragraphe est borné à 46ch
   pour la mesure de lecture, le titre ne l'est pas : sans marges automatiques,
   la boîte du paragraphe reste collée à gauche de la colonne et son texte se
   centre dans cette boîte, pas dans la colonne. Titre et paragraphe se
   retrouvent alors centrés sur deux axes distincts, décalés de 159 px en
   1440. Mesuré. Toute boîte bornée en largeur sous un titre centré a besoin
   de ces marges. */
.bandeau p { margin: var(--e-2) auto 0; max-width: 46ch; }
@media (max-width: 820px) { .bandeau { grid-template-columns: 1fr; } }

/* ----------------------------------------------------------- Formulaire -- */

.formulaire { display: grid; gap: var(--e-3); }
.formulaire__duo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-3); }
@media (max-width: 560px) { .formulaire__duo { grid-template-columns: 1fr; } }

.champ { display: grid; gap: .4rem; }
.champ > label { font-size: var(--fs-petit); font-weight: 500; }
.champ .obligatoire { color: var(--brique); }

.champ input, .champ select, .champ textarea {
  width: 100%;
  padding: .78rem .9rem;
  background: var(--papier);
  border: 1px solid var(--trait);
  border-radius: var(--r);
  font-size: var(--fs-petit);
  transition: border-color var(--transition), box-shadow var(--transition);
}
/* Sous 16 px, Safari iOS zoome sur le champ touché et le visiteur se retrouve
   décalé au milieu du formulaire. */
@media (max-width: 700px) { .champ input, .champ select, .champ textarea { font-size: 1rem; } }
.champ textarea { min-height: 8rem; resize: vertical; }
.champ input:focus, .champ select:focus, .champ textarea:focus {
  outline: none;
  border-color: var(--brique);
  box-shadow: 0 0 0 3px rgba(162, 72, 27, .14);
}
.champ input[aria-invalid='true'], .champ textarea[aria-invalid='true'] { border-color: #b3261e; }
.champ__erreur { font-size: var(--fs-micro); color: #b3261e; }

/* Le bouton d'envoi tombe exactement sur les bords des champs : même largeur,
   même boîte, aucune marge latérale ajoutée. */
.formulaire .bouton--large { padding-block: .95rem; }

.formulaire__note { font-size: var(--fs-micro); color: var(--ardoise); }

.formulaire__legende { font-size: var(--fs-micro); color: var(--ardoise); margin-top: calc(var(--e-2) * -1); }
.formulaire__legende .obligatoire { color: var(--brique); }

.formulaire__rappel {
  display: flex;
  gap: .6em;
  align-items: flex-start;
  padding: .7rem .9rem;
  background: rgba(162, 72, 27, .07);
  border-radius: var(--r);
  font-size: var(--fs-petit);
}
.formulaire__rappel svg { width: 1.1em; height: 1.1em; margin-top: .22em; color: var(--brique); flex: none; }

/* Formulaire en deux temps (landings). Chaque étape reprend la grille et
   l'espacement du formulaire : sans JS, les deux s'empilent et rien ne
   distingue la page d'un formulaire d'un seul tenant. La règle [hidden] est
   nécessaire : display: grid l'emporterait sinon sur l'attribut. */
.formulaire__etape { display: grid; gap: inherit; }
.formulaire__etape[hidden] { display: none; }
.formulaire__repere {
  font-size: var(--fs-micro); font-weight: 600; color: var(--brique-fonce);
  letter-spacing: .01em;
}
.formulaire__repere[hidden] { display: none; }
.formulaire__raison { font-size: var(--fs-petit); color: var(--ardoise); }
.formulaire__retour {
  justify-self: center;
  padding: .35rem .5rem;
  background: none; border: 0;
  font-size: var(--fs-micro); color: var(--ardoise);
  text-decoration: underline; text-underline-offset: .2em;
  cursor: pointer;
}
.formulaire__retour:hover { color: var(--encre); }
.formulaire__retour[hidden],
.formulaire [data-etape-suivante][hidden] { display: none; }

/* Message d'échec. Il ne dit jamais « merci » et il donne toujours un repli
   joignable : un prospect perdu en silence est pire qu'un refus bruyant. */
.alerte {
  padding: var(--e-3);
  border-radius: var(--r);
  border-left: 3px solid #b3261e;
  background: #fdf3f2;
  font-size: var(--fs-petit);
}
.alerte--ok { border-left-color: #1f6b3b; background: #f1f8f3; }
.alerte[hidden] { display: none; }

.encart-form {
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  background: var(--papier);
  border: 1px solid var(--trait);
  border-radius: var(--r-l);
}
.section--sable .encart-form { box-shadow: 0 1px 2px rgba(23, 25, 29, .04); }

/* ------------------------------------------------------- Appel mobile --
   Barre fixe en bas d'écran, sous 700 px. Deux cibles larges, appeler et
   WhatsApp.

   Le corps de page reçoit une marge basse de la même hauteur : sans elle, le
   dernier paragraphe du pied de page passe sous la barre et devient
   inatteignable. env(safe-area-inset-bottom) tient compte de la barre
   d'accueil des iPhone récents, qui mangerait sinon le bas des boutons. */

/* Deux blocs arrondis séparés, et non une barre pleine largeur d'un seul
   tenant. Le partage 80/20 n'est pas décoratif : le téléphone est le CTA, il
   porte son pictogramme ET le numéro écrit, parce qu'un numéro visible se
   mémorise et se rappelle plus tard. WhatsApp est un second chemin, son
   glyphe suffit.

   Le conteneur n'a pas de fond plein, seulement un dégradé qui éteint le
   contenu derrière les boutons. Il est en pointer-events: none pour que ce
   dégradé n'avale pas les clics sur la page ; les deux boutons les
   reprennent. */

.appel-mobile {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  grid-template-columns: 4fr 1fr;
  gap: .6rem;
  padding: .7rem var(--marge-page) calc(.7rem + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, var(--sable) 44%, rgba(247, 244, 239, 0));
  pointer-events: none;
}
/* Ce qui donne envie d'appuyer, sans clinquant.
   Un aplat mat et une ombre grise donnent un bouton correct et inerte. Trois
   choses suffisent à le rendre vivant sans le rendre criard :

     1. un dégradé vertical très court, plus clair en haut. L'oeil y lit un
        relief, donc un objet sur lequel on appuie ;
     2. un filet clair d'un pixel à l'intérieur du bord haut, qui accroche la
        lumière comme le ferait une touche ;
     3. une ombre portée DE LA COULEUR DU BOUTON et non grise. C'est ce qui
        fait la différence entre un bouton posé sur la page et un bouton qui
        éclaire ce qu'il y a dessous.

   Pas d'animation d'attente, pas de pulsation, pas de dégradé arc-en-ciel :
   on prend le visiteur par la main, on ne lui agite pas la main devant les
   yeux. La seule animation est l'enfoncement au doigt, qui est un retour et
   non une sollicitation. */

.appel-mobile__action {
  pointer-events: auto;
  display: flex; align-items: center; justify-content: center; gap: .5em;
  height: 58px;
  border-radius: 14px;
  font-size: 1.125rem; font-weight: 700;
  letter-spacing: -.015em;
  text-decoration: none;
  transition: transform 120ms cubic-bezier(.2, .6, .3, 1), box-shadow 120ms ease;
}
.appel-mobile__action svg { width: 1.2em; height: 1.2em; flex: none; }

.appel-mobile__action--tel {
  background: linear-gradient(180deg, #b95523 0%, var(--brique) 58%, #964116 100%);
  color: var(--papier);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22),
              0 6px 18px rgba(162, 72, 27, .42);
}
.appel-mobile__action--wa {
  background: linear-gradient(180deg, #2ee275 0%, #25D366 58%, #1fb457 100%);
  color: #0b2e18;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3),
              0 6px 18px rgba(37, 211, 102, .4);
}
.appel-mobile__action--wa svg { width: 1.7em; height: 1.7em; }

/* Enfoncement au doigt : le bouton descend et son ombre se resserre, comme
   une vraie touche. C'est un retour, pas une sollicitation. */
.appel-mobile__action:active {
  transform: translateY(2px);
}
.appel-mobile__action--tel:active {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18), 0 2px 8px rgba(162, 72, 27, .5);
}
.appel-mobile__action--wa:active {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .24), 0 2px 8px rgba(37, 211, 102, .5);
}

@media (prefers-reduced-motion: reduce) {
  .appel-mobile__action { transition: none; }
  .appel-mobile__action:active { transform: none; }
}

@media (max-width: 700px) {
  .appel-mobile { display: grid; }
  /* 56 px de bouton plus 0,7rem de marge en haut et en bas. La hauteur a déjà
     été sous-estimée une fois en la déduisant du padding à la main : elle est
     ici mesurée dans le navigateur. */
  body { padding-bottom: calc(78px + env(safe-area-inset-bottom, 0px)); }
}

/* WhatsApp absent : le téléphone prend toute la largeur. */
.appel-mobile:has(> :only-child) { grid-template-columns: 1fr; }

/* Sous 360 px, le numéro complet ne tient plus à côté du pictogramme sans
   déborder du bouton. Le libellé court prend le relais, le lien ne change
   pas. */
.appel-mobile__court { display: none; }
@media (max-width: 359px) {
  .appel-mobile__numero { display: none; }
  .appel-mobile__court  { display: inline; }
}

/* ---------------------------------------------------------- Pied de page -- */

.pied { background: var(--nuit); color: var(--brume); padding-block: var(--e-6) var(--e-4); }
.pied a { color: var(--brume); text-decoration: none; }
.pied a:hover { color: var(--papier); text-decoration: underline; }

.pied__haut {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1.3fr;
  gap: var(--gouttiere);
  padding-bottom: var(--e-5);
}
@media (max-width: 900px) { .pied__haut { grid-template-columns: 1fr 1fr; gap: var(--e-5) var(--gouttiere); } }
@media (max-width: 520px) { .pied__haut { grid-template-columns: 1fr; } }

.pied .marque__nom { color: var(--papier); }
.pied .marque__be { color: var(--cuivre); }
.pied__intro { margin-top: var(--e-2); font-size: var(--fs-petit); max-width: 34ch; }

.pied__titre {
  font-family: var(--texte); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: .08em; color: var(--papier); margin-bottom: var(--e-2);
}
.pied__liste { display: grid; gap: .5rem; font-size: var(--fs-petit); }

.pied__bas {
  display: flex; flex-wrap: wrap; gap: var(--e-2) var(--e-4);
  align-items: center; justify-content: space-between;
  padding-top: var(--e-3);
  border-top: 1px solid #2c3037;
  font-size: var(--fs-micro);
}
.pied__legaux { display: flex; flex-wrap: wrap; gap: var(--e-2) var(--e-3); }

/* Le bouton « Cookies » du pied doit passer pour un lien comme les autres :
   un <button> y arrive avec son fond, son cadre et sa police de formulaire. */
.pied__cookies {
  appearance: none; background: none; border: 0; padding: 0;
  font: inherit; cursor: pointer;
  color: var(--brume); text-decoration: none;   /* calqué sur .pied a */
}
.pied__cookies:hover { color: var(--papier); text-decoration: underline; }

/* ------------------------------------------------------------- Fil d'A. -- */

.fil { font-size: var(--fs-micro); color: var(--ardoise); padding-top: var(--e-4); }
.fil ol { display: flex; flex-wrap: wrap; gap: .4em; }
.fil li::after { content: '/'; margin-left: .4em; color: var(--trait); }
.fil li:last-child::after { content: none; }
.fil a { color: var(--ardoise); text-decoration: none; }
.fil a:hover { color: var(--encre); text-decoration: underline; }

/* --------------------------------------------------------------- Bandeaux */

.entete-page {
  padding-block: var(--e-5) var(--section-y);
  background: var(--sable);
  text-align: center;
}
.entete-page h1 { margin: var(--e-3) auto 0; max-width: 20ch; }
.entete-page p {
  margin: var(--e-3) auto 0;
  font-size: var(--fs-lead); color: var(--ardoise);
  max-width: 58ch;
}
/* Le fil d'Ariane suit l'en-tête qu'il coiffe : le laisser à gauche au-dessus
   d'un titre centré donnerait un bloc de travers. */
.entete-page .fil ol { justify-content: center; }

/* ------------------------------------------------------------- Landings --
   Gabarit des pages Ads. Le hero pleine page de l'accueil appliqué tel quel à
   une landing bien plus dense donnait un hero plus haut que l'écran et un H1
   disproportionné : la landing a sa propre variante compacte. */

.lp-hero { padding-block: clamp(2.25rem, 1.4rem + 3vw, 3.75rem) clamp(2.5rem, 1.5rem + 3.5vw, 4rem); }
.lp-hero__grille {
  display: grid;
  grid-template-columns: 1.15fr .85fr;   /* la colonne formulaire est plus étroite, à dessein */
  gap: clamp(2rem, 1rem + 3vw, 3.5rem);
  align-items: start;
}
.lp-hero h1 { font-size: var(--fs-h1); }
.lp-hero__texte > * + * { margin-top: var(--e-3); }
@media (max-width: 940px) { .lp-hero__grille { grid-template-columns: 1fr; } }

.lp-preuves {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--e-3);
  padding-block: var(--e-4);
  border-block: 1px solid var(--trait);
}
@media (max-width: 860px) { .lp-preuves { grid-template-columns: repeat(2, 1fr); } }
  .lp-preuve strong { display: block; font-family: var(--titre); font-weight: 700; font-size: 1.1875rem; letter-spacing: -.02em; }
.lp-preuve span { font-size: var(--fs-micro); color: var(--ardoise); }

/* --------------------------------------------- Landings de conversion --
   Gabarit de inc/lp-conversion.php. Hero sombre, sur photo quand elle existe,
   H1 à gauche et formulaire à droite ; carrousels de réalisations et d'avis. */

.lpc-hero {
  position: relative; isolation: isolate; overflow: hidden;
  padding-block: clamp(1.75rem, 1rem + 2.5vw, 3rem);
  background:
    radial-gradient(110% 80% at 90% 0%, rgba(224, 138, 85, .16), transparent 60%),
    var(--nuit);
  color: var(--brume);
}
.lpc-hero__fond {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
}
/* Voile plus dense du côté du texte : le formulaire est une carte blanche,
   il n'a pas besoin du voile pour se lire. */
.lpc-hero--photo::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg, rgba(16, 18, 21, .92) 0%, rgba(16, 18, 21, .8) 48%, rgba(16, 18, 21, .5) 100%);
}
@media (max-width: 940px) { .lpc-hero--photo::before { background: rgba(16, 18, 21, .82); } }

.lpc-hero__grille {
  display: grid; grid-template-columns: 1.1fr .9fr;
  gap: clamp(2rem, 1rem + 3vw, 4rem); align-items: center;
}
@media (max-width: 940px) { .lpc-hero__grille { grid-template-columns: 1fr; } }

/* Aligné à gauche malgré le centrage général des titres : il vit dans une
   colonne, au-dessus d'un texte aligné à gauche. Centré, il se décrochait de
   son propre paragraphe. */
.lpc-hero h1 { color: var(--papier); font-size: var(--fs-h1); text-wrap: balance; text-align: left; }
.lpc-hero__texte > * + * { margin-top: var(--e-3); }
/* Le nom de la commune dans le H1, à l'orange de la marque version fond
   sombre, celui du « .Be » du logo sur l'en-tête de l'accueil. */
.lpc-lieu { color: var(--cuivre); }
.lpc-hero__accroche { font-size: var(--fs-lead); color: var(--brume); max-width: 38rem; }

.lpc-preuves { display: flex; flex-wrap: wrap; gap: var(--e-2); }
.lpc-preuves li {
  display: flex; align-items: center; gap: .55em;
  padding: .55rem .85rem;
  border: 1px solid rgba(255, 255, 255, .18); border-radius: var(--r-l);
  background: rgba(255, 255, 255, .06);
  font-size: var(--fs-petit); color: var(--brume);
}
.lpc-preuves svg { width: 1.15em; height: 1.15em; color: var(--cuivre); flex: none; }
.lpc-preuves strong { color: var(--papier); font-weight: 700; }
.lpc-preuves .lpc-preuves__note svg { color: var(--etoile); width: 1.25em; height: 1.25em; }

.lpc-hero .lpc-hero__actions { margin-top: var(--e-4); }
.lpc-hero__rappel, .lpc-hero__zones { display: flex; align-items: flex-start; gap: .5em; }
.lpc-hero__rappel { font-size: var(--fs-petit); color: var(--papier); }
.lpc-hero__zones { font-size: var(--fs-micro); color: var(--brume); max-width: 40rem; }
.lpc-hero__rappel svg, .lpc-hero__zones svg { width: 1.1em; height: 1.1em; margin-top: .15em; color: var(--cuivre); flex: none; }

.lpc-hero .encart-form { color: var(--encre); box-shadow: 0 24px 60px -24px rgba(0, 0, 0, .6); }

/* Formulaire compact dans le hero. À sa taille normale il mesurait 947 px :
   en 1440 x 900, le bouton d'envoi tombait sous la ligne de flottaison, sur
   une page dont c'est la seule raison d'être. Mesuré. */
.lpc-hero .encart-form { padding: clamp(1.25rem, .85rem + 1.2vw, 1.875rem); }
.lpc-hero .formulaire { gap: var(--e-2); }
.lpc-hero .formulaire h2 { font-size: var(--fs-h3); }
.lpc-hero .formulaire__legende { margin-top: 0; }
.lpc-hero .champ { gap: .3rem; }
.lpc-hero .champ input, .lpc-hero .champ select, .lpc-hero .champ textarea { padding-block: .6rem; }
.lpc-hero .champ textarea { min-height: 4.25rem; }
.lpc-hero .formulaire__rappel { padding-block: .55rem; }
/* Le lien « Demander mon devis » du hero ne sert qu'en une colonne, quand le
   formulaire est sous le texte : à côté du formulaire, il ferait doublon. */
@media (min-width: 941px) { .lpc-hero__vers-form { display: none; } }
/* L'en-tête collant mesure 77 px en mobile : avec la seule marge de 28 px, le
   titre du formulaire et « Visite et devis gratuits » passaient dessous. */
#devis { scroll-margin-top: calc(5rem + var(--e-3)); }
/* Quatre badges empilés prenaient 212 px et repoussaient le formulaire au
   deuxième écran. Deux par deux, ils en rendent la moitié. */
@media (max-width: 560px) {
  .lpc-preuves { display: grid; grid-template-columns: 1fr 1fr; }
  .lpc-preuves li { align-items: flex-start; padding: .5rem .65rem; line-height: 1.3; }
}

/* Carrousel horizontal, en CSS seul. La piste contient deux fois la même
   série ; elle glisse d'une demi-longueur, et la seconde série prend la place
   exacte de la première, d'où une boucle sans à-coup. Pas de pause au
   survol, à la demande du client : la bande tourne sans interruption. La copie est masquée
   aux lecteurs d'écran. En mouvement réduit : pas d'animation, défilement à
   la main. */
.defile {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.defile__piste { display: flex; width: max-content; animation: defile var(--duree, 80s) linear infinite; }
.defile__lot { display: flex; align-items: stretch; gap: var(--gouttiere); padding-right: var(--gouttiere); }
@keyframes defile { from { transform: translateX(-50%); } to { transform: translateX(0); } }
/* Sens inverse, de droite à gauche : bande des avis. */
.defile--gauche .defile__piste { animation-direction: reverse; }
@media (prefers-reduced-motion: reduce) {
  .defile { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .defile__piste { animation: none; }
  .defile__lot[aria-hidden="true"] { display: none; }
}

.lpc-real { width: clamp(200px, 20vw, 280px); display: grid; gap: var(--e-1); }
.lpc-real__vue { aspect-ratio: 4 / 5; overflow: hidden; border-radius: var(--r-l); background: var(--sable-fonce); }
.lpc-real__vue img { width: 100%; height: 100%; object-fit: cover; }
.lpc-real p { font-size: var(--fs-micro); color: var(--ardoise); }

.lpc-avis {
  position: relative;
  width: clamp(270px, 28vw, 360px);
  display: flex; flex-direction: column; gap: var(--e-2);
  padding: var(--e-4);
  background: var(--papier); border: 1px solid var(--trait); border-radius: var(--r-l);
  box-shadow: 0 1px 2px rgba(23, 25, 29, .04), 0 8px 24px -12px rgba(23, 25, 29, .12);
}
/* Guillemet d'ouverture en filigrane, coin haut droit. */
.lpc-avis::before {
  content: "\201C";
  position: absolute; top: var(--e-2); right: var(--e-3);
  font: 700 4.5rem/1 Georgia, serif; color: var(--sable-fonce);
  pointer-events: none;
}
.lpc-avis__pied {
  display: flex; align-items: center; gap: var(--e-2);
  padding-top: var(--e-3); border-top: 1px solid var(--trait);
}
.lpc-avis__initiale {
  flex: none; display: grid; place-items: center;
  width: 2.5rem; height: 2.5rem; border-radius: 50%;
  background: var(--sable-fonce); color: var(--encre); font-weight: 700;
}
.lpc-avis__photo { aspect-ratio: 16 / 10; overflow: hidden; border-radius: var(--r); }
.lpc-avis__photo img { width: 100%; height: 100%; object-fit: cover; }
.lpc-avis__note { color: var(--etoile); letter-spacing: .12em; }
.lpc-avis__note-vide { color: var(--sable-fonce); }
.lpc-avis__moyenne { display: inline-flex; align-items: center; gap: .45em; }
.lpc-avis__moyenne svg { width: 1.3em; height: 1.3em; color: var(--etoile); flex: none; }
.lpc-avis__moyenne strong { color: var(--encre); }
.lpc-avis__texte { flex: 1; font-size: var(--fs-petit); color: var(--encre); }
.lpc-avis__auteur { font-size: var(--fs-micro); color: var(--ardoise); }

.lpc-etapes__action { justify-content: center; margin-top: var(--e-5); }

/* Visite : l'offre sur aplat nuit à gauche, les apports en liste à droite.
   Deux colonnes égales, alignées en haut. Les titres de l'aplat et de la
   liste coiffent un paragraphe court : exception « titre de carte », au fer
   à gauche. */
.lpc-visite {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 1rem + 3vw, 4rem);
  align-items: start;
  margin-top: var(--e-5);
}
.lpc-offre {
  background: var(--nuit);
  color: var(--brume);
  border-radius: var(--r-l);
  padding: clamp(1.75rem, 1rem + 2.4vw, 3rem);
}
.lpc-offre > * + * { margin-top: var(--e-3); }
.lpc-offre h3 { color: var(--papier); font-size: clamp(1.5rem, 1.25rem + 1vw, 2rem); text-align: left; }
.lpc-offre__liste { display: grid; gap: var(--e-2); padding-block: var(--e-2); border-block: 1px solid #2c3037; }
.lpc-offre__liste li { display: flex; align-items: flex-start; gap: .65em; color: var(--papier); }
.lpc-offre__liste svg { width: 1.15em; height: 1.15em; margin-top: .2em; color: var(--cuivre); flex: none; }
/* Deux actions de même rang, donc deux colonnes égales (même règle que le
   hero de l'accueil), empilées en pleine largeur sur mobile. */
.lpc-offre__actions { margin-top: var(--e-4); display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-2); }
@media (max-width: 560px) { .lpc-offre__actions { grid-template-columns: 1fr; } }

.lpc-apports { display: grid; }
.lpc-apports li {
  display: grid;
  grid-template-columns: 2.75rem 1fr;
  gap: var(--e-3);
  padding-block: var(--e-4);
  border-top: 1px solid var(--sable-fonce);
}
.lpc-apports li:first-child { padding-top: 0; border-top: 0; }
.lpc-apports__icone {
  display: grid; place-items: center;
  width: 2.75rem; height: 2.75rem;
  border: 1px solid var(--brique); border-radius: 50%;
  color: var(--brique);
}
.lpc-apports__icone svg { width: 1.3rem; height: 1.3rem; }
.lpc-apports h3 { font-size: var(--fs-h3); text-align: left; }
.lpc-apports p { margin-top: var(--e-1); color: var(--ardoise); }

@media (max-width: 900px) {
  .lpc-visite { grid-template-columns: minmax(0, 1fr); }
}

/* Étapes : une frise, trois points reliés par un filet. Le filet part du
   bord droit d'un cercle et s'arrête avant le suivant ; il n'existe pas
   après le dernier. Sous 760 px, la frise passe à la verticale et le filet
   descend le long des cercles. */
.lpc-frise {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--e-5);
  margin-top: var(--e-5);
  padding: clamp(1.75rem, 1rem + 2.4vw, 3rem);
  background: var(--papier);
  border: 1px solid var(--trait);
  border-radius: var(--r-l);
}
.lpc-frise li { position: relative; padding-top: 4rem; }
.lpc-frise li:not(:last-child)::after {
  content: '';
  position: absolute;
  top: 1.375rem;
  left: 3.5rem;
  right: calc(-1 * var(--e-5) + .75rem);
  height: 1px;
  background: var(--brique);
  opacity: .45;
}
.lpc-frise__num {
  position: absolute; top: 0; left: 0;
  display: grid; place-items: center;
  width: 2.75rem; height: 2.75rem;
  border-radius: 50%;
  background: var(--brique); color: var(--papier);
  font-family: var(--titre); font-weight: 700; font-size: 1.125rem;
}
/* Le dessin de l'étape, entre la frise et le titre : sur un aplat sable,
   pour qu'un trait blanc et encre se détache du fond papier de la frise. */
.lpc-frise__vue {
  margin: 0 0 var(--e-3);
  aspect-ratio: 4 / 3;
  background: var(--sable);
  border-radius: var(--r-l);
  overflow: hidden;
}
.lpc-frise__vue img { display: block; width: 100%; height: 100%; }
.lpc-frise h3 { font-size: var(--fs-h3); text-align: left; }
.lpc-frise p { margin-top: var(--e-2); color: var(--ardoise); }

@media (max-width: 760px) {
  .lpc-frise { grid-template-columns: 1fr; }
  .lpc-frise li { padding-top: 0; padding-left: 4rem; min-height: 2.75rem; }
  .lpc-frise li:not(:last-child)::after {
    top: 3.25rem; bottom: calc(-1 * var(--e-5) + .5rem);
    left: 1.375rem; right: auto;
    width: 1px; height: auto;
  }
}

.lpc-faq { margin-top: var(--e-4); display: grid; gap: var(--e-3); }
.lpc-faq details { border-bottom: 1px solid var(--trait); padding-bottom: var(--e-3); }
.lpc-faq summary { cursor: pointer; font-weight: 600; font-family: var(--texte); }
.lpc-faq p { margin-top: var(--e-2); color: var(--ardoise); font-size: var(--fs-petit); }

/* Récit des landings : une rangée photo et texte, la photo change de côté
   d'une rangée à l'autre, comme sur la page services. Le texte reste au fer
   à gauche, titre compris : c'est de la lecture suivie, la même exception
   que le corps d'un article. Photo en 4/3 et non en 4/5 : à côté de trois
   paragraphes, un portrait allonge la rangée bien au-delà du texte. */
.lpc-recit { display: grid; gap: clamp(3rem, 2rem + 3vw, 5rem); margin-top: var(--e-5); }
.lpc-recit__rangee {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 1rem + 3.5vw, 4.5rem);
  align-items: center;
}
/* order sur la figure seule, pour garder l'ordre de lecture du document. */
.lpc-recit__rangee--droite .lpc-recit__vue { order: 2; }
.lpc-recit__vue {
  margin: 0;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--r-l);
  background: var(--sable-fonce);
}
.lpc-recit__vue img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lpc-recit__texte > * + * { margin-top: var(--e-3); }
.lpc-recit__texte h3 { font-size: var(--fs-h3); text-align: left; }
.lpc-recit__texte p { color: var(--ardoise); }
.lpc-recit__action { justify-content: center; margin-top: var(--e-6); }
@media (max-width: 900px) {
  .lpc-recit__rangee { grid-template-columns: 1fr; gap: var(--e-4); }
  .lpc-recit__rangee--droite .lpc-recit__vue { order: 0; }
}

.lpc-zones > p { margin-top: var(--e-3); color: var(--ardoise); }
.lpc-zones > h2 + p { margin-top: var(--e-4); }

/* Cartes d'avis : hauteur d'auteur réservée sur deux lignes. Un « Prénom N. »
   suivi d'une commune qui passe à la ligne décale sinon toute la carte. */
.grille--avis { grid-template-rows: auto 1fr auto; }
.grille--avis > .avis { grid-row: span 3; grid-template-rows: subgrid; }
.avis__auteur { min-height: 2.9em; font-size: var(--fs-micro); color: var(--ardoise); }

/* =========================================================== Cookies
   Bandeau posé en bas de l'écran, jamais en plein écran modal : une landing
   Ads doit rester lisible pendant le choix, sinon le visiteur repart. Le
   balisage est dans inc/cookies.php, le pilote dans js/consent.js. */
.cookies {
  position: fixed; inset: auto 0 0 0; z-index: 95;   /* au-dessus de .appel-mobile, z-index 90 */
  padding: var(--marge-page);
  display: flex; justify-content: center;
  animation: cookies-monte 220ms cubic-bezier(.2, .6, .3, 1) both;
}
/* Sans cette règle, le display: flex ci-dessus l'emporte sur l'attribut
   hidden et le bandeau ne se ferme jamais, quel que soit le bouton. */
.cookies[hidden] { display: none; }
@keyframes cookies-monte { from { transform: translateY(12px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .cookies { animation: none; } }

.cookies__boite {
  width: min(680px, 100%);
  background: var(--papier);
  border: 1px solid var(--trait); border-radius: var(--r-l);
  box-shadow: 0 10px 40px rgba(23, 25, 29, .18);
  padding: var(--e-4);
}
.cookies__titre { font-size: var(--fs-h3); margin: 0 0 var(--e-2); }
.cookies__texte { font-size: var(--fs-petit); color: var(--ardoise); margin: 0 0 var(--e-3); }
.cookies__texte a { color: var(--brique-fonce); }

.cookies__actions { display: flex; flex-wrap: wrap; gap: var(--e-2); }
.cookies__actions .bouton { flex: 1 1 auto; justify-content: center; }

/* « Nécessaires uniquement » : gris, mais un gris qui se lit. Un bouton de
   refus trop pâle pour être vu est exactement ce que l'APD sanctionne, et il
   doit garder la taille du bouton d'acceptation. */
.cookies__bouton--gris {
  background: var(--sable-fonce); color: var(--encre); border-color: var(--sable-fonce);
}
.cookies__bouton--gris:hover { background: #e2dbd0; color: var(--encre); border-color: #d6cec1; }
.cookies__bouton--gris svg { color: var(--ardoise); }
.cookies__bouton--discret { flex: 0 1 auto; }

/* Réglage par catégorie */
.cookies__categories { list-style: none; margin: 0 0 var(--e-4); padding: 0; display: grid; gap: var(--e-3); }
.cookies__categorie {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--e-3);
  padding-bottom: var(--e-3); border-bottom: 1px solid var(--trait);
}
.cookies__categorie:last-child { border-bottom: 0; padding-bottom: 0; }
.cookies__cat-nom { display: block; font-weight: 600; font-size: var(--fs-petit); margin: 0 0 var(--e-1); }
.cookies__cat-texte { margin: 0; font-size: var(--fs-micro); color: var(--ardoise); max-width: 46ch; }
.cookies__toujours {
  display: inline-flex; align-items: center; gap: .4em; flex: none;
  font-size: var(--fs-micro); color: var(--ardoise);
}
.cookies__toujours svg { width: 1.05em; height: 1.05em; }

/* Interrupteur : une case à cocher habillée. L'input reste un input, donc il
   garde le clavier, le focus et les lecteurs d'écran. */
.bascule { flex: none; position: relative; display: inline-flex; cursor: pointer; }
.bascule input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.bascule__piste {
  width: 42px; height: 24px; border-radius: 999px;
  background: var(--sable-fonce); border: 1px solid var(--trait);
  transition: background var(--transition), border-color var(--transition);
}
.bascule__piste::after {
  content: ''; position: absolute; top: 4px; left: 4px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--papier); box-shadow: 0 1px 3px rgba(23, 25, 29, .3);
  transition: transform var(--transition);
}
.bascule input:checked + .bascule__piste { background: var(--brique); border-color: var(--brique); }
.bascule input:checked + .bascule__piste::after { transform: translateX(18px); }
.bascule input:focus-visible + .bascule__piste { outline: 2px solid var(--encre); outline-offset: 2px; }

/* Le bandeau couvre la barre d'appel mobile, elle-même en position fixe en bas
   de l'écran. Elle s'efface tant que le choix n'est pas fait, puis revient.
   visibility et non display : la barre est affichée par une requête de média,
   qu'un display ici écraserait. */
body.a-cookies .appel-mobile { visibility: hidden; }

@media (max-width: 560px) {
  .cookies { padding: var(--e-2); }
  .cookies__boite { padding: var(--e-3); max-height: 82vh; overflow-y: auto; }
  .cookies__actions .bouton { flex: 1 1 100%; }
}

/* ------------------------------------------------ Landings : mouvement --
   Demandé le 2026-10-14 : « ajoute de la vie sans dénaturer ». Tout part du
   vocabulaire déjà là, le trait qui se tire une fois : des photos qui se
   dévoilent comme un volet, une frise dont le trait se trace d'un point à
   l'autre. Une seule fois chacun, aucune boucle, aucune pulsation, rien sous
   prefers-reduced-motion (html.anime-ok n'est alors jamais posée). */

/* Photo du hero : elle se pose en reculant à peine, à l'ouverture. Une fois,
   puis plus rien : ce n'est pas un Ken Burns qui tourne en fond. */
@media (prefers-reduced-motion: no-preference) {
  .lpc-hero__fond { animation: lpc-pose 2.4s cubic-bezier(.22, .7, .28, 1) both; }
}
@keyframes lpc-pose { from { transform: scale(1.07); } to { transform: none; } }

/* Récit : le volet s'ouvre depuis le côté où la photo est posée, pendant que
   l'image recule de 1,22 à 1,08. L'échelle de 1,08 reste ensuite pour laisser
   à la dérive (js/script.js) la marge de glisser sans découvrir le fond. */
@property --zoom { syntax: '<number>'; inherits: false; initial-value: 1.08; }
.lpc-recit__vue img {
  transform: translateY(var(--derive, 0px)) scale(var(--zoom));
  transition: --zoom 1.5s cubic-bezier(.22, .7, .28, 1);
}
/* Le volet est décrit sur la photo, mais c'est la rangée qui est observée :
   une photo fermée par clip-path n'est jamais vue « dans l'écran » par
   IntersectionObserver, et ne s'ouvrirait donc jamais. */
.anime-ok .lpc-recit__rangee[data-revele] .lpc-recit__vue {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 1.1s cubic-bezier(.77, 0, .18, 1);
}
.anime-ok .lpc-recit__rangee--droite[data-revele] .lpc-recit__vue { clip-path: inset(0 0 0 100%); }
.anime-ok .lpc-recit__rangee[data-revele] .lpc-recit__vue img { --zoom: 1.22; }
.anime-ok .lpc-recit__rangee[data-revele='vu'] .lpc-recit__vue { clip-path: inset(0 0 0 0); }
.anime-ok .lpc-recit__rangee[data-revele='vu'] .lpc-recit__vue img { --zoom: 1.08; }

/* Frise : chaque numéro apparaît, puis le trait part vers le suivant. */
.anime-ok .lpc-frise[data-revele] .lpc-frise__num {
  opacity: 0; transform: scale(.4);
  transition: opacity .3s ease, transform .5s cubic-bezier(.34, 1.56, .64, 1);
}
.anime-ok .lpc-frise[data-revele] li:not(:last-child)::after {
  transform: scaleX(0); transform-origin: left center;
  transition: transform .6s cubic-bezier(.22, .7, .28, 1);
}
.anime-ok .lpc-frise[data-revele='vu'] .lpc-frise__num { opacity: 1; transform: none; }
.anime-ok .lpc-frise[data-revele='vu'] li:not(:last-child)::after { transform: none; }
.anime-ok .lpc-frise li:nth-child(1)::after { transition-delay: .3s; }
.anime-ok .lpc-frise li:nth-child(2) .lpc-frise__num { transition-delay: .8s; }
.anime-ok .lpc-frise li:nth-child(2)::after { transition-delay: 1.1s; }
.anime-ok .lpc-frise li:nth-child(3) .lpc-frise__num { transition-delay: 1.6s; }
@media (max-width: 760px) {
  .anime-ok .lpc-frise[data-revele] li:not(:last-child)::after { transform: scaleY(0); transform-origin: center top; }
}

/* Visite : les pictogrammes se posent l'un après l'autre. */
.anime-ok .lpc-apports[data-revele] .lpc-apports__icone {
  opacity: 0; transform: scale(.4) rotate(-20deg);
  transition: opacity .3s ease, transform .55s cubic-bezier(.34, 1.56, .64, 1);
}
.anime-ok .lpc-apports[data-revele='vu'] .lpc-apports__icone { opacity: 1; transform: none; }
.anime-ok .lpc-apports li:nth-child(2) .lpc-apports__icone { transition-delay: .18s; }
.anime-ok .lpc-apports li:nth-child(3) .lpc-apports__icone { transition-delay: .36s; }

/* ------------------------------------------------ Landings : comparatif --
   Une grille de cinq colonnes : la prestation, puis Construland et trois
   types de prestataires. La colonne Construland est un aplat sable continu,
   ouvert en haut par un filet terracotta, comme une colonne tirée du
   tableau. Sous 760 px, chaque ligne devient une carte : le titre, puis
   quatre pastilles étiquetées. Pas de capitales forcées (PRODUCT.md). */
.cmp-legende {
  list-style: none; margin: var(--e-4) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--e-2) var(--e-4);
  font-size: var(--fs-petit); color: var(--ardoise);
}
.cmp-legende li { display: inline-flex; align-items: center; gap: .5em; }
.cmp-legende .cmp-pastille { width: 1.5rem; height: 1.5rem; }

.cmp-pastille {
  display: inline-grid; place-items: center; flex: none;
  width: 1.875rem; height: 1.875rem; border-radius: 50%;
  border: 1.5px solid #cfc8bc; color: var(--ardoise); background: var(--papier);
}
.cmp-pastille svg { width: 62%; height: 62%; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.cmp-pastille--oui { background: var(--encre); border-color: var(--encre); color: var(--papier); }
.cmp-pastille--nous { background: var(--brique); border-color: var(--brique); color: var(--papier); }

.cmp { margin-top: var(--e-5); }
.cmp__ligne {
  display: grid;
  grid-template-columns: minmax(0, 2.4fr) repeat(4, minmax(0, 1fr));
  align-items: stretch;
  border-bottom: 1px solid var(--trait);
}
.cmp__ligne:last-child { border-bottom: 0; }
.cmp__prestation { padding: var(--e-3) var(--e-4) var(--e-3) 0; }
.cmp__prestation h3 { font-size: 1.0625rem; text-align: left; }
.cmp__prestation p { margin-top: var(--e-1); font-size: var(--fs-petit); color: var(--ardoise); }
.cmp__case { display: grid; place-items: center; padding: var(--e-3) var(--e-2); text-align: center; }
.cmp__case--nous { background: var(--sable); }
.cmp__ligne:last-child .cmp__case--nous { border-radius: 0 0 var(--r-l) var(--r-l); }

.cmp__ligne--tete { border-bottom-color: var(--trait); }
.cmp__ligne--tete .cmp__prestation,
.cmp__ligne--tete .cmp__case {
  align-self: end; padding-block: var(--e-3);
  font-size: var(--fs-petit); font-weight: 600; color: var(--encre);
}
.cmp__ligne--tete .cmp__prestation { color: var(--ardoise); }
.cmp__ligne--tete .cmp__case--nous {
  align-self: stretch; padding-top: var(--e-4);
  border-top: 3px solid var(--brique); border-radius: var(--r-l) var(--r-l) 0 0;
  font-family: var(--titre); font-size: 1.25rem; font-weight: 700; color: var(--brique);
}
.cmp__note { margin-top: var(--e-3); text-align: center; font-size: var(--fs-micro); color: var(--ardoise); }

@media (max-width: 760px) {
  .cmp__ligne--tete { display: none; }
  .cmp { display: grid; gap: var(--e-3); }
  /* La colonne Construland est un peu plus large : son étiquette est la
     plus longue et ne se coupe pas (75 px mesurés, pour 56 disponibles à
     320 px en colonnes égales). */
  .cmp__ligne {
    grid-template-columns: minmax(0, 1.45fr) repeat(3, minmax(0, 1fr));
    gap: var(--e-1);
    padding: var(--e-3);
    border: 1px solid var(--trait); border-radius: var(--r-l);
  }
  .cmp__ligne:last-child { border-bottom: 1px solid var(--trait); }
  .cmp__prestation { grid-column: 1 / -1; padding: 0 0 var(--e-2); }
  .cmp__case { gap: .35rem; padding: var(--e-2) .25rem; border-radius: var(--r-l); align-content: start; }
  .cmp__case::before {
    content: attr(data-col);
    font-size: .75rem; line-height: 1.2; color: var(--ardoise);
  }
  .cmp__case--nous::before { color: var(--brique-fonce); font-weight: 600; }
  .cmp__ligne:last-child .cmp__case--nous { border-radius: var(--r-l); }
}
@media (max-width: 380px) {
  .cmp__case::before { font-size: .6875rem; }
  .cmp__ligne { padding-inline: var(--e-2); gap: .25rem; }
  .cmp__case { padding-inline: 0; }
}
/* Plus étroit encore, quatre étiquettes ne tiennent plus sur une rangée :
   deux par deux. */
@media (max-width: 340px) {
  .cmp__ligne { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ------------------------------------------ Landings : mots mis en valeur --
   Les passages entre **…** de la copy (lp_fort() dans inc/lp.php) :
   graisse et terracotta foncé sur fond clair, cuivre sur fond sombre. Ni
   soulignement ni surlignage, le seul ornement du site reste le trait des
   titres. Demandé le 2026-10-14. */
.fort { font-weight: 600; color: var(--brique-fonce); }
.lpc-hero .fort, .section--nuit .fort, .bandeau .fort, .lpc-offre .fort { color: var(--cuivre); }
/* Le formulaire est une carte blanche posée dans le hero sombre. */
.lpc-hero .encart-form .fort { color: var(--brique-fonce); }

/* ------------------------------------------ Landings : boutons mobiles --
   Sous 700 px, chaque bouton des landings prend toute la largeur, 56 px de
   haut (la cible de la barre d'appel mobile) et un corps plus lisible ; deux
   boutons d'une même rangée s'empilent au lieu de se serrer côte à côte à
   des largeurs différentes. Demandé le 2026-10-14. */
@media (max-width: 700px) {
  .landing main .actions {
    display: grid; grid-template-columns: minmax(0, 1fr);
    justify-items: stretch; gap: var(--e-2);
    width: 100%;
  }
  /* Ici, et ici seulement, un bouton peut passer sur deux lignes : il occupe
     toute la largeur, rien ne le borne en hauteur. Avec le nowrap général,
     « Planifier ma visite gratuite » élargissait la carte de la visite et le
     bandeau final au-delà de l'écran sous 343 px de large : la page glissait
     de gauche à droite et la barre d'appel se décalait (2026-10-14). */
  .landing main .actions .bouton,
  .landing main .formulaire .bouton {
    width: 100%; min-height: 56px; min-width: 0;
    font-size: 1.0625rem;
    justify-content: center; text-align: center;
    white-space: normal;
  }
}

/* ------------------------------------------------ Landings : menu --------
   Ancres vers les sections de la page, jamais vers le site (inc/lp-entete.php).
   Reprend .nav et .burger du site vitrine ; seules la place du burger et la
   marge des ancres changent. */

/* Une section atteinte par le menu s'arrête sous l'en-tête collant, comme
   #devis, au lieu de glisser dessous. */
.landing main section[id] { scroll-margin-top: calc(5rem + var(--e-2)); }

/* Ordinateur : trois colonnes, les deux latérales égales (1fr auto 1fr).
   La navigation est donc au centre exact de la barre, marque à gauche,
   actions à droite. Elle était poussée à droite par margin-left: auto et
   collée aux boutons, avec tout le vide entre la marque et le premier lien
   (retour client du 2026-10-14 : « asymétrie dans le menu »).
   Pas de bouton de devis dans la barre sur ordinateur : à côté du
   téléphone, il élargissait la colonne de droite au-delà de celle de
   gauche et mordait sur la navigation (mesuré de 1301 à 1920 px). Le
   formulaire est dans le hero, et le panneau mobile garde son bouton. */
@media (min-width: 981px) {
  /* minmax(0, 1fr) et justify-content: normal : la barre hérite du
     space-between du site vitrine, et avec des 1fr nus les deux colonnes
     latérales prenaient la largeur de leur contenu (284 et 330 px mesurés),
     ce qui décalait la navigation de 23 px. */
  .entete--lp .entete__barre {
    display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    justify-content: normal;
  }
  .entete--lp .marque { justify-self: start; }
  .entete--lp .nav { margin-left: 0; justify-self: center; }
  .entete--lp .nav__devis { display: none; }
  .entete--lp .entete__actions { justify-self: end; }
}

/* Burger des landings : sans cadre, trois traits de 2 px aux bouts arrondis.
   Le carré à contour gris de 1 px se lisait comme une case vide à côté de la
   pastille téléphone pleine. La boîte reste de 44 px pour la cible tactile ;
   la marge négative aligne les traits sur le bord du contenu, comme la
   marque l'est au-dessus de 980 px. */
.entete--lp .burger { border: 0; margin-left: -11px; }
.entete--lp .burger__traits,
.entete--lp .burger__traits::before,
.entete--lp .burger__traits::after { width: 22px; height: 2px; border-radius: 2px; }
.entete--lp .burger__traits::before { transform: translateY(-7px); }
.entete--lp .burger__traits::after  { transform: translateY(5px); }
.entete--lp .burger[aria-expanded='true'] .burger__traits::before { transform: rotate(45deg); }
.entete--lp .burger[aria-expanded='true'] .burger__traits::after  { transform: translateY(-2px) rotate(-45deg); }
.entete--lp .burger:focus-visible { outline: 2px solid var(--brique); outline-offset: 2px; }

/* Sous 980 px : burger à gauche de la marque (hemea.be), téléphone à droite. */
@media (max-width: 980px) {
  .entete--lp .entete__barre { justify-content: flex-start; }
  .entete--lp .marque { margin-right: auto; }
  .entete--lp .nav__devis { min-height: 56px; font-size: 1.0625rem; }
}
