/* ============================================================
   Reeloq — site public
   ============================================================ */

/* --------------------------------------------------- en-tête */
.entete{
  position:sticky; top:0; z-index:100;
  background:color-mix(in srgb, var(--fond) 92%, transparent);
  backdrop-filter:blur(12px);
  border-bottom:1px solid transparent;
  transition:border-color var(--transition), background var(--transition);
}
.entete.collee{ border-bottom-color:var(--bordure) }
.entete__inner{
  display:flex; align-items:center; justify-content:space-between;
  gap:var(--e-5); height:76px;
}
.marque{ display:flex; align-items:center; gap:var(--e-3); flex-shrink:0 }
.marque img{ width:40px; height:40px }
.marque__nom{
  font-family:var(--f-titre); font-size:1.35rem;
  font-weight:600; letter-spacing:-.02em;
}
.nav{ display:flex; align-items:center; gap:var(--e-6) }
.nav a{
  font-size:var(--t-sm); font-weight:500; color:var(--texte-doux);
  position:relative; padding-block:var(--e-2); transition:color var(--transition);
}
.nav a::after{
  content:""; position:absolute; left:0; bottom:0;
  width:0; height:1.5px; background:var(--accent); transition:width var(--transition);
}
.nav a:hover{ color:var(--texte) }
.nav a:hover::after, .nav a[aria-current="page"]::after{ width:100% }
.nav a[aria-current="page"]{ color:var(--texte) }

.entete__actions{ display:flex; align-items:center; gap:var(--e-3) }
.burger{
  display:none; width:44px; height:44px;
  flex-direction:column; align-items:center; justify-content:center; gap:5px;
}
.burger span{
  display:block; width:22px; height:2px; border-radius:2px;
  background:var(--texte); transition:transform var(--transition), opacity var(--transition);
}
.burger[aria-expanded="true"] span:nth-child(1){ transform:translateY(7px) rotate(45deg) }
.burger[aria-expanded="true"] span:nth-child(2){ opacity:0 }
.burger[aria-expanded="true"] span:nth-child(3){ transform:translateY(-7px) rotate(-45deg) }

.nav-mobile{
  position:fixed; inset:76px 0 0 0; z-index:99;
  background:var(--fond); padding:var(--e-6) var(--gouttiere);
  display:flex; flex-direction:column; gap:var(--e-2);
  transform:translateX(100%); visibility:hidden;
  transition:transform .35s cubic-bezier(.6,0,.2,1), visibility .35s;
}
.nav-mobile[data-ouvert="true"]{ transform:none; visibility:visible }
.nav-mobile a{
  font-family:var(--f-titre); font-size:1.75rem; padding-block:var(--e-3);
  border-bottom:1px solid var(--bordure);
}
.nav-mobile .bouton{ margin-top:var(--e-5) }

/* --------------------------------------------------- hero
   Le héros est sombre : sur fond crème partout, la page se lisait comme une
   feuille blanche et le logo brun n'avait nulle part où résonner. Le brun
   profond donne le point d'appui, et la crème du texte reprend exactement
   la couleur du R du logo. */
.hero{
  padding-block:clamp(4rem,10vw,8rem) clamp(3rem,7vw,6rem);
  background:var(--brun-profond);
  position:relative; overflow:hidden;
}
/* Halo terre très diffus derrière le titre : évite l'aplat mort. */
.hero::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:
    radial-gradient(70% 90% at 12% 30%, rgba(169,100,59,.20), transparent 62%),
    radial-gradient(50% 70% at 92% 88%, rgba(169,100,59,.12), transparent 60%);
}
.hero .contenant{ position:relative; z-index:1 }

/* --------------------------------------------------- en-tête de page interne
   Même logique que le héros, en plus court : chaque page s'ouvre sur un bloc
   sombre. C'est ce qui donne au site son rythme clair/sombre au lieu d'une
   longue page crème. */
.entete-page{
  padding-block:clamp(3rem,7vw,5.5rem);
  background:var(--brun-profond);
  position:relative; overflow:hidden;
}
.entete-page::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(65% 100% at 18% 40%, rgba(169,100,59,.18), transparent 62%);
}
.entete-page .contenant{ position:relative; z-index:1 }

/* --------------------------------------------------- bandeau illustré
   Image de matière en fond, assombrie deux fois : une première fois au
   traitement du fichier, une seconde par ce voile. Le texte crème garde
   ainsi un contraste confortable même si l'image est un jour remplacée
   par une plus claire. */
.bandeau{
  padding-block:clamp(4rem,9vw,7rem);
  position:relative; isolation:isolate;
  background:var(--brun-profond);
}
/* Le surtitre est petit et en capitales : c'est le texte le plus fragile de la
   page. Sur l'endroit le plus clair de la photo, le terracotta habituel tombe
   à 2,97:1. Cette teinte remonte à 4,6:1, au-dessus du seuil AA même dans le
   pire cas. On ne touche pas à --accent : le bouton s'en sert comme fond et
   l'éclaircir le rendrait fade. */
.bandeau .surtitre{ color:#E0AE88 }
.bandeau::before{
  content:""; position:absolute; inset:0; z-index:-1;
  background-image:
    linear-gradient(rgba(42,30,21,.70), rgba(42,30,21,.82)),
    url("/assets/img/ia-matiere.webp");
  background-size:cover; background-position:center;
}
/* Le bandeau et le pied de page sont tous deux sombres : sans ce filet, ils
   se lisent comme un seul bloc et la fin de page s'écrase. */
.bandeau + .pied, .bandeau{ border-top:1px solid rgba(228,216,201,.12) }
@media (max-width:700px){
  .bandeau::before{
    background-image:
      linear-gradient(rgba(42,30,21,.82), rgba(42,30,21,.90)),
      url("/assets/img/ia-matiere-800.webp");
  }
}
.hero__grille{
  display:grid; grid-template-columns:1.15fr .85fr;
  gap:clamp(2rem,6vw,5rem); align-items:center;
}
.hero h1{ margin-block:var(--e-4) var(--e-5) }
/* Sur fond sombre, le terracotta d'origine tombe sous le seuil de lisibilité :
   on passe à la version claire de la même couleur. */
.hero h1 em{ font-style:italic; color:var(--terre-clair) }
.hero__actions{ display:flex; flex-wrap:wrap; gap:var(--e-3); margin-top:var(--e-6) }
.hero__note{
  margin-top:var(--e-5); font-size:var(--t-sm); color:var(--texte-faible);
  display:flex; align-items:center; gap:var(--e-2);
}
.hero__note::before{
  content:""; width:7px; height:7px; border-radius:50%;
  background:var(--succes); flex-shrink:0;
}

/* --------------------------------------------------- visuels
   Un cadre décalé couleur terre passe derrière l'image : il rattache la
   photo à la charte sans poser de logo par-dessus. `isolation` crée un
   contexte d'empilement local, pour que le liseré reste sous l'image
   sans jamais passer sous le fond de la section. */
.visuel{ position:relative; isolation:isolate; margin:0; align-self:start }
.visuel img{
  position:relative; z-index:1;
  display:block; width:100%; height:auto;
  aspect-ratio:3/2; object-fit:cover;
  border-radius:var(--rayon-lg);
  box-shadow:0 26px 60px -34px rgba(42,30,21,.6);
}
/* Le liseré n'est posé que sur le visuel du héros : ailleurs, il déborde
   sur l'élément suivant de la colonne et brouille la lecture. */
.visuel--portrait::before{
  content:""; position:absolute; z-index:0;
  inset:18px -18px -18px 18px;
  border:1px solid var(--terre);
  border-radius:var(--rayon-lg);
  opacity:.55;
}
/* Hauteur plafonnée : sans cela une image 4/5 sur une colonne large fait
   grimper la section au-delà d'un écran et le titre décroche. */
.visuel--portrait img{ aspect-ratio:4/5; max-height:min(64vh,580px) }

@media (max-width:860px){
  .visuel--portrait::before{ inset:12px -12px -12px 12px }
  .visuel--portrait img{ aspect-ratio:3/2; max-height:none }
}

/* --------------------------------------------------- bandeau de chiffres */
.chiffres{ background:var(--brun); color:var(--creme) }
.chiffres__grille{
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:1px; background:rgba(228,216,201,.15);
}
.chiffre{ background:var(--brun); padding:var(--e-5) var(--e-4); text-align:center }
.chiffre b{
  display:block; font-family:var(--f-titre);
  font-size:clamp(1.75rem,3.5vw,2.5rem); line-height:1;
}
.chiffre span{
  display:block; margin-top:var(--e-2);
  font-size:var(--t-xs); letter-spacing:.14em; text-transform:uppercase;
  color:rgba(228,216,201,.65);
}

/* --------------------------------------------------- cartes */
.cartes{ display:grid; gap:var(--e-4); margin-top:var(--e-7) }
.cartes--3{ grid-template-columns:repeat(3,1fr) }
.cartes--2{ grid-template-columns:repeat(2,1fr) }
.carte{
  background:var(--surface); border:1px solid var(--bordure);
  border-radius:var(--rayon-lg); padding:clamp(1.5rem,3vw,2.25rem);
  transition:border-color var(--transition), transform var(--transition),
             box-shadow var(--transition);
}
.carte:hover{
  border-color:var(--accent); transform:translateY(-3px); box-shadow:var(--ombre-2);
}
.carte__num{
  font-family:var(--f-titre); font-size:var(--t-sm); font-weight:600;
  color:var(--accent); letter-spacing:.1em; display:block; margin-bottom:var(--e-4);
}
.carte h3{ margin-bottom:var(--e-3) }
.carte p{ font-size:var(--t-sm); color:var(--texte-doux); line-height:1.75 }

/* --------------------------------------------------- tarifs */
.offres{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--e-4); margin-top:var(--e-7) }
.offre{
  background:var(--surface); border:1.5px solid var(--bordure);
  border-radius:var(--rayon-lg); padding:clamp(1.75rem,3vw,2.5rem);
  display:flex; flex-direction:column;
}
.offre--vedette{ border-color:var(--accent); position:relative }
.offre--vedette::before{
  content:"Le plus choisi"; position:absolute; top:-.75rem; left:50%;
  transform:translateX(-50%); background:var(--accent); color:#fff;
  font-size:var(--t-xs); font-weight:600; letter-spacing:.08em;
  padding:.3rem .9rem; border-radius:100px; white-space:nowrap;
}
.offre__nom{ font-family:var(--f-titre); font-size:var(--t-lg); margin-bottom:var(--e-2) }
.offre__prix{
  font-family:var(--f-titre); font-size:2.75rem; line-height:1;
  margin-block:var(--e-4) var(--e-1);
}
.offre__prix small{ font-family:var(--f-texte); font-size:var(--t-sm); color:var(--texte-faible) }
.offre__desc{ font-size:var(--t-sm); color:var(--texte-doux); margin-bottom:var(--e-5) }
.offre ul{ list-style:none; display:grid; gap:var(--e-3); margin-bottom:var(--e-6); flex:1 }
.offre li{ font-size:var(--t-sm); display:flex; gap:var(--e-3); align-items:flex-start }
.offre li::before{
  content:""; flex-shrink:0; width:16px; height:16px; margin-top:3px;
  background:var(--accent); opacity:.9;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20 6 9 17l-5-5' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20 6 9 17l-5-5' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
}

/* --------------------------------------------------- pied de page */
.pied{ background:var(--brun-profond); color:var(--creme); padding-block:var(--e-8) 0 }
.pied__grille{
  display:grid; grid-template-columns:1.6fr 1fr 1fr 1fr; gap:var(--e-6);
}
.pied h4{
  font-family:var(--f-texte); font-size:var(--t-xs); font-weight:600;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--terre-clair); margin-bottom:var(--e-4);
}
.pied ul{ list-style:none; display:grid; gap:var(--e-2) }
.pied a, .pied li{ font-size:var(--t-sm); color:rgba(228,216,201,.72); transition:color var(--transition) }
.pied a:hover{ color:var(--creme) }
.pied__marque img{ width:44px; height:44px; margin-bottom:var(--e-4) }
.pied__marque p{ font-size:var(--t-sm); color:rgba(228,216,201,.72); max-width:34ch; line-height:1.8 }
.pied__bas{
  margin-top:var(--e-7); border-top:1px solid rgba(228,216,201,.14);
  padding-block:var(--e-4); display:flex; flex-wrap:wrap; gap:var(--e-3);
  justify-content:space-between; font-size:var(--t-xs); color:rgba(228,216,201,.45);
}

/* --------------------------------------------------- adaptatif */
@media (max-width:960px){
  .nav{ display:none }
  .burger{ display:flex }
  .entete__actions .bouton{ display:none }
  .hero__grille{ grid-template-columns:1fr }
  .medaillon{ order:-1; max-width:220px; margin-inline:auto }
  .cartes--3, .cartes--2, .offres{ grid-template-columns:1fr }
  .pied__grille{ grid-template-columns:1fr 1fr }
}
@media (max-width:560px){
  .chiffres__grille{ grid-template-columns:1fr }
  .pied__grille{ grid-template-columns:1fr }
  .hero__actions .bouton{ width:100% }
}

/* ==========================================================================
   Sections en terre cuite
   --------------------------------------------------------------------------
   La charte déclare la terre cuite « accent principal », mais le site ne
   l'employait qu'en filets et en boutons. Elle devient ici une couleur de
   section à part entière : le site passe de deux niveaux (brun / crème) à
   quatre, et la couleur cesse d'être un détail.

   La terre cuite vive #A9643B ne supporte pas la crème : elle n'y atteint
   que 3,27:1, sous le seuil AA de 4,5. Elle supporte en revanche le blanc
   pur, à 4,59:1. C'est ce couple qu'on retient — la couleur reste vive, et
   le texte reste lisible.

   Conséquence sur les dégradés : ils ne peuvent qu'assombrir. Un halo plus
   clair ferait remonter le fond vers le blanc du texte et casserait le
   rapport. Tous les mélanges vont donc vers le brun, jamais vers la lumière.
   ========================================================================== */

.section--terre{
  position:relative; isolation:isolate; overflow:hidden;
  background:var(--terre);
  color:#FFFFFF;

  /* Jetons réécrits pour la section : cartes, bordures et boutons suivent
     sans qu'on ait à styler chaque élément un par un. */
  --texte:         #FFFFFF;
  --texte-doux:    #FFFFFF;
  --texte-faible:  rgba(255,255,255,.86);
  --surface:       var(--brun-profond);
  --fond-alt:      var(--terre);
  --bordure:       rgba(255,255,255,.24);
  --bordure-forte: rgba(255,255,255,.40);
  --accent:        #FFFFFF;
  --accent-texte:  var(--brun-profond);
}

/* Le mélange : le brun profond monte des deux angles opposés et laisse la
   terre vive au centre, là où se trouve le texte. La surface n'est jamais
   d'une seule couleur, et le contraste ne peut que s'améliorer en bordure. */
.section--terre::before{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(75% 120% at 4% 0%, rgba(42,30,21,.55), transparent 58%),
    radial-gradient(70% 115% at 100% 100%, rgba(138,78,44,.75), transparent 60%);
}

/* Cartes brunes sur fond terre : c'est le contraste de matière le plus fort
   du site, et il n'existe que dans ces sections. */
.section--terre .carte{ border-color:rgba(255,255,255,.16) }

/* La bordure des sections terre contre le bloc voisin : un filet clair
   marque la couture, sinon terre et brun se touchent en fondu sale. */
.section--terre{ border-block:1px solid rgba(255,255,255,.16) }

/* --------------------------------------------------------- bandeau chiffré */
/* Le même principe appliqué à la bande de chiffres, qui était un aplat brun
   plat entre deux blocs. */
.chiffres{ position:relative; isolation:isolate; overflow:hidden }
.chiffres::before{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:
    linear-gradient(100deg, rgba(169,100,59,.42) 0%, transparent 46%),
    radial-gradient(60% 140% at 88% 50%, rgba(169,100,59,.26), transparent 64%);
}

/* ------------------------------------------------------------------ héros */
/* Un titre d'accueil doit se voir de loin : on monte d'un cran par rapport
   aux titres de section, sans aller jusqu'au palier maximal qui ferait
   passer la phrase sur quatre lignes. */
.hero h1{
  font-size:clamp(2.75rem, 6.2vw, 5rem);
  line-height:1.04;
  letter-spacing:-.02em;
}

/* ==========================================================================
   Filet de sécurité : toute section « sombre » est peinte
   --------------------------------------------------------------------------
   `.theme-sombre` ne fait que redéfinir des variables de couleur. Une section
   qui porte la classe sans règle de fond reste donc crème, avec un texte
   passé en crème par les jetons : crème sur crème, invisible.

   Le cas s'est produit en production sur le dernier bloc de « Ce qu'on fait ».
   Le fond n'y tenait qu'à un `style="background:var(--brun)"` écrit dans le
   HTML — un attribut oublié à la copie, et le texte disparaît sans que rien
   ne signale l'erreur.

   Cette règle rend la classe autoportante. La spécificité (0,1,1) l'emporte
   sur `.hero`, `.entete-page` et `.bandeau`, mais elle applique la même
   valeur qu'eux : aucun changement visuel, seulement une garantie.

   Elle ne vise QUE les `section`. L'en-tête porte aussi `.theme-sombre`, mais
   son fond est volontairement translucide (`color-mix` + `backdrop-filter`)
   pour laisser deviner le contenu qui défile dessous : le peindre en aplat
   supprimerait l'effet.
   ========================================================================== */

section.theme-sombre{
  background:var(--fond);
  color:var(--texte);
}

/* ==========================================================================
   Bandeau illustré en tête de carte
   --------------------------------------------------------------------------
   L'image sort du rembourrage de la carte pour toucher ses trois bords hauts.
   Une image qui garde la marge intérieure flotte au milieu du cadre et
   fabrique une deuxième bordure, plus faible que la vraie.

   Les marges négatives reprennent exactement le `padding` de `.carte`
   (`clamp(1.5rem,3vw,2.25rem)`) : si ce rembourrage change, celui-ci suit,
   sans avoir à retoucher deux endroits.
   ========================================================================== */

.carte__image{
  margin:calc(clamp(1.5rem,3vw,2.25rem) * -1);
  margin-bottom:var(--e-5);
  border-radius:calc(var(--rayon-lg) - 1px) calc(var(--rayon-lg) - 1px) 0 0;
  overflow:hidden;
  background:var(--brun-profond);   /* évite le flash blanc avant chargement */
}
.carte__image img{
  display:block; width:100%; height:auto;
  aspect-ratio:16/9; object-fit:cover;
  transition:transform var(--transition);
}
/* Léger rapprochement au survol, dans le prolongement du soulèvement de la
   carte. L'image est recadrée en `cover` : le zoom ne déforme rien. */
.carte:hover .carte__image img{ transform:scale(1.03) }

@media (prefers-reduced-motion: reduce){
  .carte__image img{ transition:none }
  .carte:hover .carte__image img{ transform:none }
}

/* ==========================================================================
   Page Contact
   --------------------------------------------------------------------------
   Elle réutilisait `.hero__grille`, qui centre ses colonnes verticalement.
   Contre un formulaire deux fois plus haut que le texte, ce centrage créait
   un vide au-dessus du titre et un autre sous la dernière ligne. Ici les
   deux colonnes démarrent en haut, alignées sur la même ligne d'horizon.
   ========================================================================== */

.contact__grille{
  display:grid;
  grid-template-columns:1fr 1.05fr;
  gap:clamp(2rem,6vw,5rem);
  align-items:start;
}
.contact__infos{ display:grid; gap:var(--e-6); align-content:start }

/* `.surtitre` est en `inline-flex` — sans passage en bloc, la valeur qui
   suit se colle sur la même ligne que l'intitulé. C'est ce qui donnait
   « PAR EMAIL contact@reeloq.fr » au lieu de deux lignes. */
.bloc-info .surtitre{ display:flex }
.bloc-info__valeur{
  display:block; margin-top:var(--e-2);
  font-size:var(--t-md); color:var(--texte-doux); line-height:1.7;
}
a.bloc-info__valeur{
  color:var(--texte); text-decoration:underline;
  text-underline-offset:3px; text-decoration-thickness:1px;
}
a.bloc-info__valeur:hover{ color:var(--accent) }

@media (max-width:860px){
  .contact__grille{ grid-template-columns:1fr }
  /* Sur téléphone, le formulaire passe devant : c'est l'objet de la page,
     il ne doit pas être repoussé sous trois blocs d'information. */
  .contact__infos{ order:2 }
}

/* ==========================================================================
   Calibrage : un rythme vertical unique
   --------------------------------------------------------------------------
   Avant ce bloc, chaque page portait ses marges en clair dans le HTML :
   « style="margin-block:var(--e-4)" » repete vingt-quatre fois, avec des
   valeurs qui ne concordaient pas. Un titre respirait 24 px sous lui sur
   l'accueil, 16 px sur les tarifs, 12 px sur le contact, et rien du tout
   dans trois sections ou l'attribut avait ete oublie.

   Quatre intervalles suffisent a tenir tout le site. Ils sont nommes par
   leur ROLE, pas par leur taille : le jour ou l'un d'eux change, il change
   partout, et personne n'a a rouvrir cinq gabarits.
   ========================================================================== */

:root{
  --r-surtitre: 0.875rem;   /* 14 px — surtitre collé à son titre */
  --r-titre:    1.375rem;   /* 22 px — titre vers son chapeau */
  --r-bloc:     3.5rem;     /* 56 px — bloc d'introduction vers le contenu */
  --r-action:   2.5rem;     /* 40 px — contenu vers les boutons */
}

/* --- surtitre ------------------------------------------------------------ */
/* `.section--serree` ne porte PAS la classe `.section` : oubliee dans la
   premiere version de ce bloc, elle laissait trois sections de « Ce qu'on
   fait » sans aucun rythme. Toute section du site doit figurer ici. */
.hero .surtitre,
.entete-page .surtitre,
.section .surtitre,
.section--serree .surtitre,
.bandeau .surtitre{ margin-bottom:var(--r-surtitre) }

/* --- titres -------------------------------------------------------------- */
/* margin-block a deux valeurs : zero au-dessus, l'intervalle en dessous.
   Le blanc au-dessus d'un titre est deja donne par le bloc precedent ;
   l'empiler deux fois cree ces vides qu'on ne sait pas expliquer. */
.hero h1, .entete-page h1, .section h1, .section--serree h1,
.hero h2, .entete-page h2, .section h2, .section--serree h2, .bandeau h2{
  margin-block:0 var(--r-titre);
}

/* --- chapeau ------------------------------------------------------------- */
/* 62 caracteres par ligne : au-dela, l'oeil perd le debut de la ligne
   suivante. C'est la seule regle de lisibilite qui se mesure vraiment. */
.hero .chapeau, .entete-page .chapeau, .section .chapeau,
.section--serree .chapeau, .bandeau .chapeau{
  margin-block:0;
  max-width:62ch;
}
.bandeau .chapeau{ margin-inline:auto }
.hero .chapeau + .chapeau,
.section .chapeau + .chapeau{ margin-top:var(--r-titre) }

/* --- contenu et actions -------------------------------------------------- */
.section .cartes,
.section .offres,
.section--serree .cartes,
.section--serree .offres,
.bandeau .cartes{ margin-top:var(--r-bloc) }

/* Dans une grille a deux colonnes, la colonne de droite ne doit PAS heriter
   de cet intervalle : elle demarre a la meme hauteur que le texte de gauche.
   C'est ce que les gabarits obtenaient avec « margin-top:0 » en clair. */
.hero__grille .cartes,
.contact__grille .cartes{ margin-top:0 }

.hero__actions{ margin-top:var(--r-action) }

/* Un bouton seul, hors groupe d'actions, garde le meme intervalle.
   La regle porte sur le VOISIN precedent et non sur la profondeur
   d'imbrication : la version d'avant exigeait que le bouton soit enfant
   direct du conteneur, et le ratait des qu'une grille s'intercalait — il se
   retrouvait alors colle au paragraphe. */
p + .bouton,
h2 + .bouton,
h3 + .bouton,
ul + .bouton,
.chapeau + .bouton,
.cartes + .bouton,
.offres + .bouton{ margin-top:var(--r-action) }

/* --- boutons ------------------------------------------------------------- */
/* 48 px de haut : c'est la taille sous laquelle une cible devient penible
   au pouce sur telephone. Les recommandations parlent de 44 px minimum ;
   on prend une marge. */
.bouton{
  min-height:48px;
  display:inline-flex; align-items:center; justify-content:center;
}
.hero__actions{ gap:var(--e-4) }

/* --- notes et mentions --------------------------------------------------- */
.hero__note{ margin-top:var(--r-action) }

/* --- respiration des sections -------------------------------------------- */
/* Une section doit avoir plus d'air en haut et en bas que ses elements n'en
   ont entre eux, sinon les blocs se touchent visuellement d'une section a
   l'autre et le decoupage disparait. */
.section{ padding-block:clamp(4rem, 7vw, 6.5rem) }
.section--serree{ padding-block:clamp(2.5rem, 4vw, 3.5rem) }

@media (max-width:700px){
  :root{
    --r-bloc:   2.5rem;
    --r-action: 2rem;
  }
}

/* ==========================================================================
   Accent typographique dans les sections en terre cuite
   --------------------------------------------------------------------------
   Tout en blanc, ces sections tombaient a plat. Mais on ne peut pas colorer
   n'importe quoi : la creme sur terre cuite ne donne que 3,27:1.

   Or le seuil AA depend de la TAILLE. Pour un texte dit « grand » — 24 px,
   ou 18,7 px en gras — il tombe a 3:1. Un titre de section fait 40 px : la
   creme y est donc conforme, alors qu'elle ne le serait pas sur un
   paragraphe. On colore le titre, jamais le texte courant.

   Meme geste que le heros, ou « fiche Google » passe en terre claire : un
   segment en italique dans une autre teinte, pour que la phrase ait un
   relief au lieu d'un aplat.
   ========================================================================== */

.section--terre h2 em{
  font-style:italic;
  color:var(--creme);
}

/* Le filet du surtitre reprend la meme creme : il relie l'accent du titre
   au bloc qui le surmonte. Le texte du surtitre, lui, reste blanc — il est
   petit, et la creme y descendrait sous le seuil. */
.section--terre .surtitre::before{ background:var(--creme) }

/* Lettrine de chiffre des cartes, sur fond brun : la terre claire ressort
   nettement mieux que le blanc, et rappelle l'accent du titre. */
.section--terre .carte__num{ color:var(--terre-clair) }

/* ==========================================================================
   Animations
   --------------------------------------------------------------------------
   Trois regles tenues d'un bout a l'autre :

   1. On n'anime que `opacity` et `transform`. Ce sont les deux seules
      proprietes que le navigateur traite sans recalculer la mise en page ;
      animer une hauteur ou une marge fait tomber le defilement sous les
      60 images par seconde sur un telephone d'entree de gamme.

   2. Rien ne depend du JavaScript pour rester lisible. L'entree du heros est
      une animation CSS pure : si le script echoue, elle se joue quand meme.
      Les revelations au defilement, elles, ont un filet — voir plus bas.

   3. Tout s'efface sous `prefers-reduced-motion`. Ce n'est pas une option de
      confort : le mouvement declenche des nausees et des migraines chez une
      partie des visiteurs, et le reglage existe pour ca.
   ========================================================================== */

@keyframes rq-monte{
  from{ opacity:0; transform:translateY(22px) }
  to  { opacity:1; transform:none }
}
@keyframes rq-fondu{
  from{ opacity:0 }
  to  { opacity:1 }
}
@keyframes rq-image{
  from{ opacity:0; transform:scale(1.04) }
  to  { opacity:1; transform:none }
}

/* --- entree du heros et des en-tetes de page ----------------------------- */
/* Cascade de 90 ms : le regard suit l'ordre de lecture au lieu de recevoir
   le bloc entier d'un coup. `both` garde l'etat initial avant le depart,
   sinon le texte clignote pendant le delai. */
.hero .surtitre,
.entete-page .surtitre{ animation:rq-monte .7s cubic-bezier(.2,.7,.3,1) both .05s }
.hero h1,
.entete-page h1{        animation:rq-monte .7s cubic-bezier(.2,.7,.3,1) both .14s }
.hero .chapeau,
.entete-page .chapeau{  animation:rq-monte .7s cubic-bezier(.2,.7,.3,1) both .23s }
.hero__actions{         animation:rq-monte .7s cubic-bezier(.2,.7,.3,1) both .32s }
.hero__note{            animation:rq-fondu .9s ease both .45s }
.hero .visuel{          animation:rq-image 1.1s cubic-bezier(.2,.7,.3,1) both .1s }
.chiffres .chiffre{     animation:rq-monte .6s cubic-bezier(.2,.7,.3,1) both }
.chiffres .chiffre:nth-child(2){ animation-delay:.08s }
.chiffres .chiffre:nth-child(3){ animation-delay:.16s }

/* --- revelation au defilement, en cascade -------------------------------- */
/* Le decalage est porte par le CSS et non par le JavaScript : une carte de
   plus dans une grille se decale toute seule, sans rien a recalculer. */
.cartes > .apparait:nth-child(2),
.offres > .apparait:nth-child(2){ transition-delay:.09s }
.cartes > .apparait:nth-child(3),
.offres > .apparait:nth-child(3){ transition-delay:.18s }
.cartes > .apparait:nth-child(4){ transition-delay:.27s }

/* Variantes de direction, choisies selon la place de l'element dans la page. */
.apparait--gauche{ transform:translateX(-26px) }
.apparait--droite{ transform:translateX(26px) }
.apparait--zoom{   transform:scale(.965) }
.apparait--gauche.vu, .apparait--droite.vu, .apparait--zoom.vu{ transform:none }

/* --- parallaxe ----------------------------------------------------------- */
/* Le decalage est ecrit par le script dans une variable CSS, et applique ici.
   Passer par une variable evite de toucher au `transform` depuis le script :
   la regle reste lisible dans la feuille, et le pseudo-element ::before est
   atteignable, ce qu'un style en ligne ne permet pas. */
.bandeau::before{
  transform:translate3d(0, var(--parallaxe, 0), 0) scale(1.12);
  will-change:transform;
}

/* --- liens ---------------------------------------------------------------- */
/* Le soulignement pousse depuis la gauche au lieu d'apparaitre d'un bloc. */
.nav a, .pied a{ position:relative }
.nav a::after, .pied a::after{
  content:""; position:absolute; left:0; right:0; bottom:-3px; height:1px;
  background:currentColor; transform:scaleX(0); transform-origin:left;
  transition:transform var(--transition);
}
.nav a:hover::after, .pied a:hover::after{ transform:scaleX(1) }
.nav a[aria-current="page"]::after{ transform:scaleX(1) }

/* --- boutons -------------------------------------------------------------- */
/* Enfoncement au clic : un retour tactile immediat vaut mieux qu'une
   animation longue, surtout sur un formulaire. */
.bouton{ transition:background var(--transition), transform .12s ease, box-shadow var(--transition) }
.bouton:hover{ transform:translateY(-1px) }
.bouton:active{ transform:translateY(1px) }

@media (prefers-reduced-motion: reduce){
  .hero .surtitre, .entete-page .surtitre, .hero h1, .entete-page h1,
  .hero .chapeau, .entete-page .chapeau, .hero__actions, .hero__note,
  .hero .visuel, .chiffres .chiffre{ animation:none }
  .cartes > .apparait, .offres > .apparait{ transition-delay:0s }
  .bandeau::before{ transform:none; will-change:auto }
  .bouton:hover, .bouton:active{ transform:none }
  html{ scroll-behavior:auto }
}

/* ==========================================================================
   Bande de chiffres — refonte
   --------------------------------------------------------------------------
   Elle se lisait comme un morceau rapporte. Trois causes :

   1. Son brun n'etait celui d'aucun de ses voisins : ni le brun profond du
      heros au-dessus, ni la terre cuite en dessous. Une troisieme teinte
      entre les deux fabrique une bande flottante.
   2. Les separateurs venaient d'une grille a `gap:1px` posee sur un fond
      clair. Les filets s'arretaient net a 1200 px alors que la bande, elle,
      allait d'un bord a l'autre de l'ecran : le trait paraissait coupe.
   3. Le rembourrage etait trop faible pour la taille des chiffres.

   Elle devient le prolongement du heros : meme fond, une simple couture en
   haut et en bas, des filets qui ne touchent ni le haut ni le bas.
   ========================================================================== */

.chiffres{
  background:var(--brun-profond);
  border-block:1px solid rgba(228,216,201,.13);
  padding-block:var(--e-6);
}
.chiffres__grille{
  gap:0;
  background:none;               /* plus de fond clair vu au travers du gap */
}
.chiffre{
  background:none;
  padding:var(--e-3) var(--e-5);
  position:relative;
}
/* Filet vertical entre les cellules, en retrait haut et bas : il separe sans
   decouper la bande en trois boites. */
.chiffre + .chiffre::before{
  content:""; position:absolute; left:0; top:12%; bottom:12%;
  width:1px; background:rgba(228,216,201,.16);
}
.chiffre b{ font-size:clamp(1.5rem, 2.6vw, 2rem) }
.chiffre span{ color:rgba(228,216,201,.6) }

@media (max-width:560px){
  /* En colonne, le filet vertical n'a plus de sens : il passe a l'horizontale. */
  .chiffre + .chiffre::before{
    left:12%; right:12%; top:0; bottom:auto; width:auto; height:1px;
  }
  .chiffre{ padding-block:var(--e-4) }
}

/* ==========================================================================
   Interactions au defilement
   --------------------------------------------------------------------------
   Pourquoi pas GSAP : l'en-tete Content-Security-Policy du site n'autorise
   que `script-src 'self'`. Une bibliotheque servie depuis un CDN serait
   bloquee par le navigateur avant meme d'etre lue. Il faudrait soit ouvrir
   la politique — on perdrait la protection contre l'injection de scripts —
   soit heberger GSAP nous-memes, ce qui ajoute environ 70 Ko compresses
   pour, ici, des effets qu'on obtient en 3 Ko.

   Ce qui suit est donc natif. Deux mecanismes :

   - REVELATION : declenchee une fois, quand l'element entre dans le champ.
     Le rideau se leve par `clip-path`, ce qui donne un balayage franc
     plutot qu'un simple fondu.
   - SUIVI : recalcule a chaque image tant que l'element est visible. C'est
     ce qui fait bouger les photos dans leur cadre pendant qu'on defile.
   ========================================================================== */

/* --- rideau de revelation ------------------------------------------------ */
.revele{
  opacity:0;
  transform:translateY(38px);
  clip-path:inset(0 0 100% 0);
  transition:opacity .85s cubic-bezier(.16,.8,.3,1),
             transform .85s cubic-bezier(.16,.8,.3,1),
             clip-path 1s cubic-bezier(.16,.8,.3,1);
}
.revele.vu{ opacity:1; transform:none; clip-path:inset(0 0 0 0) }

/* Balayage lateral, pour les blocs qui arrivent depuis un cote. */
.revele--cote{ transform:translateX(-44px); clip-path:inset(0 100% 0 0) }
.revele--cote.vu{ transform:none; clip-path:inset(0 0 0 0) }

/* --- photos qui glissent dans leur cadre --------------------------------- */
/* L'image est plus haute que son cadre : la difference est la course
   disponible. Sans ce surdimensionnement, la translation ferait apparaitre
   un bord vide en haut ou en bas. */
/* PREMIERE VERSION, ABANDONNEE : l'image faisait 118 % de la hauteur de son
   cadre et glissait a l'interieur. Le principe est fragile — il suffit d'un
   arrondi, d'un rapport d'image different ou d'une course mal bornee pour
   qu'un bord du cadre apparaisse. C'est arrive en production.

   VERSION RETENUE : c'est la CARTE ENTIERE qui se decale, pas l'image dans
   son cadre. Le mouvement se produit dans le blanc qui entoure deja la
   carte, donc il ne peut rien decouvrir ni rien rogner. */
.cadre-suivi{ overflow:hidden; aspect-ratio:16/9 }
.cadre-suivi img{ width:100%; height:100%; object-fit:cover }

/* L'image respire pendant le defilement — mais par AGRANDISSEMENT, jamais
   par translation. Un facteur toujours superieur ou egal a 1 ne fait que
   recadrer davantage : il ne peut mathematiquement pas decouvrir un bord,
   contrairement au glissement qu'on vient d'abandonner.
   Le survol se multiplie au zoom de defilement au lieu de l'ecraser. */
.carte__image img{
  transform:scale(calc(var(--zoom, 1) * var(--zoom-survol, 1)));
  transform-origin:center;
}
.carte:hover .carte__image img{ --zoom-survol:1.04 }

@media (prefers-reduced-motion: reduce){
  .carte__image img{ transform:none }
}

/* Decalage vertical de la carte, ecrit par le script. Les colonnes n'ont pas
   le meme coefficient : elles se decalent legerement les unes par rapport aux
   autres, ce qui donne la profondeur. */
.suit-defilement{
  transform:translate3d(0, var(--decale, 0px), 0);
  will-change:transform;
}

/* --- barre de progression ------------------------------------------------ */
.progression{
  position:fixed; top:0; left:0; height:2px; width:100%;
  transform:scaleX(var(--avancement, 0)); transform-origin:left;
  background:var(--terre-clair);
  z-index:200; pointer-events:none;
}

/* --- inclinaison des cartes sous le curseur ------------------------------ */
@media (hover:hover) and (pointer:fine){
  .carte{ transform-style:preserve-3d }
  .carte--incline{
    transform:perspective(900px)
              rotateX(var(--incline-x, 0deg))
              rotateY(var(--incline-y, 0deg))
              translateY(-3px);
    transition:transform .18s ease-out;
  }
}

@media (prefers-reduced-motion: reduce){
  .revele, .revele--cote{ opacity:1; transform:none; clip-path:none; transition:none }
  .suit-defilement{ transform:none; will-change:auto }
  .progression{ display:none }
  .carte--incline{ transform:none }
}

/* ==========================================================================
   Classes utilitaires
   --------------------------------------------------------------------------
   Elles remplacent les attributs `style=` ecrits dans les gabarits.

   Ce n'est pas une preference d'ecriture, c'est une obligation : l'en-tete
   Content-Security-Policy du site declare `style-src 'self' 'nonce-...'`
   SANS `'unsafe-inline'`. Le navigateur ignore donc purement et simplement
   tout attribut `style=`. Trente-cinq d'entre eux etaient inertes en
   production alors qu'ils fonctionnaient en developpement, ou aucun en-tete
   de securite n'est envoye — d'ou des blocs non centres en ligne et centres
   sur le poste.

   Les styles poses par le SCRIPT (`element.style.setProperty`) ne sont pas
   concernes : la politique ne filtre que le balisage, pas le CSSOM. La
   parallaxe et les inclinaisons continuent donc de fonctionner.
   ========================================================================== */

.centre        { text-align:center }
/* Un chapeau est plafonne a 62 caracteres : dans un bloc centre, il faut
   aussi centrer la BOITE, sinon le texte est centre mais colle a gauche. */
.centre .chapeau,
.centre .mention{ margin-inline:auto }
.centre-bloc   { margin-inline:auto }
.relatif       { position:relative; z-index:1 }
.sans-gouttiere{ padding-inline:0 }
.pleine-largeur{ width:100% }
.actions-centrees{ justify-content:center }

.etroit-46  { max-width:46rem }
.etroit-52  { max-width:52ch }
.etroit-56  { max-width:56ch }
.etroit-58  { max-width:58ch }
.etroit-520 { max-width:520px }
.etroit-760 { max-width:760px }
.etroit-820 { max-width:820px }

.mention{ font-size:var(--t-xs); color:var(--texte-faible) }
.lien-souligne{ text-decoration:underline }
.texte-creme{ color:var(--creme) }
.texte-creme-doux{ color:rgba(228,216,201,.78) }

/* Panneau de formulaire — reprend l'aspect d'une carte. */
.panneau{
  background:var(--surface);
  border:1px solid var(--bordure);
  border-radius:var(--rayon-lg);
  padding:clamp(1.5rem,3vw,2.25rem);
}

/* Bloc d'appel sombre en fin de page interne. */
.bloc-sombre{ background:var(--brun); color:var(--creme) }

/* Page d'erreur. */
.page-erreur{ min-height:60svh; display:grid; place-items:center }
.code-erreur{
  font-family:var(--f-titre);
  font-size:clamp(4rem,14vw,8rem);
  line-height:1; color:var(--terre); opacity:.28;
}

/* Terme surligne dans les pages legales. */
.surligne{
  background:var(--attente); color:var(--brun-profond);
  padding:0 .3em; border-radius:2px;
}

/* ==========================================================================
   Acces a l'espace client
   ========================================================================== */

/* Lien discret dans l'en-tete, avant le bouton d'appel a l'action. Il
   s'adresse aux clients existants, pas aux visiteurs a convaincre : il ne
   doit donc pas rivaliser avec « Parler du projet ». */
.entete__acces{
  font-size:var(--t-sm);
  color:var(--texte-doux);
  white-space:nowrap;
  transition:color var(--transition);
}
.entete__acces:hover{ color:var(--texte) }

@media (max-width:960px){
  /* Sous cette largeur, la place manque : le lien passe dans le menu. */
  .entete__acces{ display:none }
}

/* ==========================================================================
   Etats vides
   --------------------------------------------------------------------------
   Une section sans contenu ne doit pas ressembler a une section cassee. Le
   filet a gauche et le retrait disent « c'est normal, il n'y a rien encore »
   au lieu de laisser un blanc qu'on prend pour un bug d'affichage.
   ========================================================================== */

.vide{
  margin-top:var(--r-bloc);
  padding-left:var(--e-5);
  border-left:2px solid var(--bordure-forte);
}
.vide .chapeau{ margin-bottom:var(--e-5) }
.section--terre .vide{ border-left-color:rgba(255,255,255,.32) }

/* Formulaire compact de renvoi du lien d'activation, dans la colonne laterale. */
.renvoi{ display:grid; gap:var(--e-3); margin-top:var(--e-3) }
.renvoi input{
  width:100%; padding:.7rem .8rem;
  background:var(--surface); color:var(--texte);
  border:1px solid var(--bordure); border-radius:var(--rayon);
  font:inherit; font-size:var(--t-sm);
}
.renvoi input:focus-visible{ outline:2px solid var(--accent); outline-offset:2px }
.renvoi .bouton{ justify-self:start }

/* Etiquette reservee aux lecteurs d'ecran : le champ a un espace reserve
   visuellement par son texte indicatif, mais un texte indicatif n'est pas
   une etiquette — il disparait des qu'on tape. */
.visuellement-cache{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
}
