/* ============================================================
   CERVIS — Les pièces de caractère.

   Vocabulaire demandé : dégradés, verre dépoli, motifs de fond,
   objets animés. Il est employé, mais tenu par la charte : les
   dégradés ne quittent jamais le bleu et le rouge de la marque,
   le verre reste assez opaque pour que le texte tienne, et les
   motifs viennent du métier (papier millimétré, cotes, trames de
   coffrage) plutôt que d'un catalogue d'effets.
   ============================================================ */

:root {
  /* ---- Dégradés de marque. Aucune teinte étrangère n'entre ici. ---- */
  --deg-marque:  linear-gradient(135deg, #2947a8 0%, #1e3a8a 42%, #0b1b3f 100%);
  --deg-nuit:    linear-gradient(160deg, #12245a 0%, #0b1b3f 55%, #060f26 100%);
  /* Le dégradé d'origine descendait à 3,26:1 avec du blanc et annulait en
     silence le travail fait sur --rouge-fonce, sur le bouton le plus
     important du site. Assombri, il tient 5,5:1 au pire point. */
  --deg-accent:  linear-gradient(90deg, #b30d14 0%, #d1121a 100%);
  --deg-accent-deco: linear-gradient(90deg, #ed1b24 0%, #ff4d55 100%);
  --deg-voile:   linear-gradient(to top, rgb(6 15 38 / .96) 0%, rgb(11 27 63 / .78) 34%,
                                          rgb(11 27 63 / .34) 66%, rgb(11 27 63 / .12) 100%);

  /* ---- Verre dépoli. Trois densités, jamais improvisées.
     Le verre se règle par l'opacité du fond, jamais en fonçant le texte. ---- */
  --verre-sol:    rgb(255 255 255 / .10);   /* sur photo sombre, décoratif */
  --verre-carte:  rgb(255 255 255 / .14);
  --verre-bande:  rgb(255 255 255 / .94);   /* porte du texte : plancher haut */
  --verre-bord:   rgb(255 255 255 / .22);
  --verre-flou:   blur(18px) saturate(1.5);

  --lueur-bleue: radial-gradient(circle at 50% 50%, rgb(41 71 168 / .55) 0%, rgb(30 58 138 / 0) 68%);
  --lueur-rouge: radial-gradient(circle at 50% 50%, rgb(237 27 36 / .30) 0%, rgb(237 27 36 / 0) 70%);
}

/* ─────────────────────────────────────────── Verre : la classe unique */
.verre {
  background: var(--verre-carte);
  border: 1px solid var(--verre-bord);
  border-radius: var(--r-3);
  backdrop-filter: var(--verre-flou);
  -webkit-backdrop-filter: var(--verre-flou);
  /* Le liseré clair en haut : c'est ce qui donne l'épaisseur au verre */
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .28),
              0 18px 48px -22px rgb(0 0 0 / .55);
}
/* Sans backdrop-filter, le verre deviendrait un rectangle translucide
   illisible : on retombe sur un aplat franc. */
@supports not (backdrop-filter: blur(4px)) {
  .verre { background: rgb(11 27 63 / .82); }
}

/* ───────────────────────────────────── Grain : le liant de toute la page.
   Une trame fine posée sur les fonds sombres. Elle empêche les grands
   aplats bleus de paraître plats et numériques. */
.grain::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none; z-index: 1;
  opacity: .32; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='b'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23b)' opacity='.45'/%3E%3C/svg%3E");
}

/* ─────────────────────────────── Halos : deux, pas dix, et très lents */
/* Classe doublée à dessein : 0,2,0 de spécificité. Une règle en `> *`
   (0,1,0) déclarée plus bas ne peut donc plus remettre un halo dans le
   flux. Ce piège a coûté deux fois : 1 088 px de vide dans la section
   Vision et Mission, puis 500 px dans le panneau de chiffrage. */
.halo, .halo.halo {
  position: absolute; border-radius: 50%;
  pointer-events: none; z-index: 0;
  filter: blur(30px);
}
.halo--bleu  { background: var(--lueur-bleue); }
.halo--rouge { background: var(--lueur-rouge); }
@media (prefers-reduced-motion: no-preference) {
  .halo--bleu  { animation: derive 26s var(--ease-doux) infinite alternate; }
  .halo--rouge { animation: derive 34s var(--ease-doux) infinite alternate-reverse; }
}
@keyframes derive {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(6%, -8%, 0) scale(1.14); }
}


/* ═══════════════════════════════════════════ 1. L'ouverture au niveau
   La page s'ouvre comme un niveau qu'on pose : un trait rouge à
   mi-hauteur, puis la vue s'écarte de part et d'autre. Le geste vient
   du métier, pas d'un catalogue d'effets. */

.heros {
  background: var(--deg-nuit);
  /* 94 svh ne laissait rien voir de la section suivante : la page
     semblait s'arrêter là. 80 svh laisse dépasser le haut du bandeau,
     ce qui suffit à donner envie de défiler. */
  min-height: min(80svh, 760px);
}
.heros__media { clip-path: inset(0 0 0 0); }
.js-motion .heros__media { clip-path: inset(49.6% 0 49.6% 0); }

.heros__voile { background: var(--deg-voile); }
/* Une seconde couche, teintée marque, posée en biais */
.heros__voile::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(104deg, rgb(30 58 138 / .58) 0%, rgb(30 58 138 / .12) 46%,
                                       rgb(237 27 36 / .10) 100%);
  mix-blend-mode: multiply;
}

.heros__niveau {
  position: absolute; left: 0; right: 0; top: 50%;
  height: 2px; background: var(--deg-accent-deco);
  box-shadow: 0 0 24px rgb(237 27 36 / .75);
  transform: scaleX(0); transform-origin: center;
  z-index: 2; pointer-events: none; opacity: 0;
}

/* Titre révélé ligne à ligne par un volet, pas par un fondu */
/* Le titre gagne son autorité par le contraste de graisse, pas par la
   seule taille : « L'exigence » en fin, « du détail » en plein. L'accent
   tombe donc sur le mot qui porte la promesse de l'entreprise. */
.heros h1 {
  /* 8,5 rem donnait 233 px de titre à lui seul, soit le tiers de la
     hauteur utile d'un portable. 6,25 rem garde l'autorité sans manger
     la bannière. */
  font-size: clamp(2.5rem, .9rem + 6.4vw, 6.25rem);
  /* .95 collait les deux lignes : à cette taille, la panse du « g » de
     « L'exigence » venait toucher le haut du « d » de « détail ». */
  line-height: 1.02;
  letter-spacing: -0.044em;
  font-weight: 300;
  max-width: 11ch;
}
.heros h1 .plein { font-weight: 700; }
.heros--page h1 { font-weight: 700; font-size: var(--t-h1); max-width: 20ch; }
/* Le masque coupe à ras : le retrait bas laisse passer les jambages, et
   l'écart entre deux lignes se règle ici, pas par l'interligne seul. */
.ligne-masque { display: block; overflow: hidden; padding-bottom: .1em; }
.ligne-masque + .ligne-masque { margin-top: .04em; }
.ligne-masque > span { display: block; will-change: transform; }

/* Les repères du héros passent sur verre : ils flottent au-dessus de la
   photo au lieu d'être posés dessus. */
.heros__reperes {
  border-top: 0;
  padding: var(--e-2);
  gap: 1px;
  background: var(--verre-sol);
  border: 1px solid var(--verre-bord);
  border-radius: var(--r-4);
  backdrop-filter: var(--verre-flou);
  -webkit-backdrop-filter: var(--verre-flou);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .24), 0 24px 60px -30px rgb(0 0 0 / .7);
  overflow: hidden;
}
.heros__repere {
  padding: var(--e-5) var(--e-5);
  border-right: 1px solid rgb(255 255 255 / .14);
  transition: background var(--d-moyen) var(--ease-doux);
}
.heros__repere:hover { background: rgb(255 255 255 / .07); }

/* Fil d'aplomb : un trait rouge descend du héros et traverse la page */
.fil-aplomb {
  position: absolute; left: var(--gouttiere); bottom: 0;
  width: 2px; height: clamp(40px, 8vw, 96px);
  background: linear-gradient(to bottom, var(--rouge), rgb(237 27 36 / 0));
  transform-origin: top; z-index: 3;
}
@media (max-width: 860px) { .fil-aplomb { display: none; } }


/* ═══════════════════════════════════════ 2. Du plan à l'ouvrage
   Une élévation d'architecte se trace au fil du défilement, puis la
   photographie de l'ouvrage bâti prend sa place. C'est le métier de
   l'entreprise en un seul geste, et c'est l'objet animé du site. */

/* Trois temps à parcourir, contre deux auparavant : la course s'allonge
   pour que chacun ait le temps de se lire. */
.plan { position: relative; background: var(--deg-nuit); height: 340vh; }
.plan__scene {
  position: sticky; top: 0; height: 100svh; min-height: 0;
  display: flex; flex-direction: column; justify-content: center;
  gap: clamp(1rem, 2.4vh, 2rem);
  /* Le retrait haut doit toujours dépasser l'en-tête collant (78 px),
     sinon le titre passe dessous sur un portable en 720 px de haut. */
  /* Aucun retrait latéral : la largeur vient de .enveloppe, posée sur
     chaque enfant. Un retrait en plus s'ajoutait au centrage et décalait
     toute la section vers la droite, d'une gouttière entière. */
  padding: max(6.5rem, 12vh) 0 clamp(1.5rem, 4vh, 3rem);
  overflow: hidden;
}

/* Papier millimétré : le fond d'un plan, pas une texture décorative */
.plan__quadrillage {
  position: absolute; inset: 0; z-index: 0;
  background-image:
    linear-gradient(rgb(255 255 255 / .05) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / .05) 1px, transparent 1px),
    linear-gradient(rgb(127 155 221 / .16) 1px, transparent 1px),
    linear-gradient(90deg, rgb(127 155 221 / .16) 1px, transparent 1px);
  background-size: 16px 16px, 16px 16px, 96px 96px, 96px 96px;
  mask-image: radial-gradient(ellipse 92% 78% at 50% 46%, #000 26%, transparent 100%);
}

.plan__cadre {
  /* La perspective est portée par le cadre : c'est elle qui donne son
     épaisseur au basculement de l'élévation vers la maquette. */
  perspective: 1600px;
  position: relative; z-index: 2;
  width: min(100% - (var(--gouttiere) * 2), var(--largeur));
  margin-inline: auto;
  /* base 0 et non auto : avec « auto », le cadre réclame sa hauteur
     naturelle, la colonne dépasse les 100 svh de la scène et le titre
     part se cacher sous l'en-tête collant. */
  flex: 1 1 0; min-height: 0;
  /* La hauteur est celle qui reste dans la scène. Le titre et la légende
     sont ses frères dans la colonne, jamais ses enfants : une photo posée
     en absolu recouvrirait sinon les deux. */
}

.plan__photo { position: absolute; inset: 0; overflow: hidden; border-radius: var(--r-4); }
.plan__photo img { width: 100%; height: 100%; object-fit: cover; }
/* Sans mouvement, la photo est simplement là, à sa vraie place. */
.js-motion .plan__photo img { opacity: 0; filter: grayscale(1) contrast(1.08); }

.plan__dessin { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; }
.plan__dessin [data-trace] {
  fill: none; stroke: #8fa9e6; stroke-width: 1.6;
  stroke-linecap: square; vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 6px rgb(143 169 230 / .45));
}
.plan__dessin [data-trace="cote"] { stroke: var(--rouge); stroke-width: 1.2;
  filter: drop-shadow(0 0 8px rgb(237 27 36 / .6)); }
.plan__dessin [data-trace="sol"]  { stroke: #b9cbf5; stroke-width: 2.6; }

.plan__titre {
  position: relative; z-index: 3; flex: 0 0 auto;
  width: min(100% - (var(--gouttiere) * 2), var(--largeur));
  margin-inline: auto;
}
.plan__titre p {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--rouge-clair); margin-bottom: .6rem;
}
.plan__titre h2 {
  color: #fff; font-size: clamp(1.5rem, .9rem + 2.4vw, 2.75rem);
  letter-spacing: -0.03em; line-height: 1.04;
  display: flex; flex-wrap: wrap; gap: 0 .35em;
}
.plan__titre .bascule { color: #8fa9e6; }

.plan__legende {
  position: relative; z-index: 3; flex: 0 0 auto;
  width: min(100% - (var(--gouttiere) * 2), var(--largeur));
  margin-inline: auto;
  display: flex; flex-wrap: wrap; gap: .4rem 2rem; align-items: baseline;
  font-size: var(--t-sm); color: rgb(255 255 255 / .6);
}
.plan__legende b { color: #fff; font-weight: 600; }



/* ═══════════════════════════════════════════════ 3. Avant / après
   Le visiteur tire lui-même le curseur. Sur un métier de rénovation,
   c'est la démonstration la plus directe qui existe. */

.avant-apres {
  position: relative; aspect-ratio: 3 / 2; overflow: hidden;
  border-radius: var(--r-4); background: var(--n-100);
  touch-action: pan-y; user-select: none;
  box-shadow: 0 30px 70px -34px rgb(11 27 63 / .55);
}
.avant-apres img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.avant-apres__apres { clip-path: inset(0 0 0 var(--curseur, 50%)); }

.avant-apres__poignee {
  position: absolute; top: 0; bottom: 0; left: var(--curseur, 50%);
  width: 3px; background: var(--deg-accent-deco);
  box-shadow: 0 0 22px rgb(237 27 36 / .7);
  transform: translateX(-1.5px); z-index: 2; pointer-events: none;
}
.avant-apres__poignee::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 56px; height: 56px; transform: translate(-50%, -50%);
  border-radius: var(--r-plein); background: var(--deg-accent);
  border: 2px solid rgb(255 255 255 / .35);
  box-shadow: 0 6px 22px rgb(11 27 63 / .45);
}
.avant-apres__poignee i {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  z-index: 3; display: block; color: #fff;
}
.avant-apres__etiquette {
  position: absolute; top: var(--e-4); z-index: 3;
  padding: .4rem .85rem;
  font-size: var(--t-xs); font-weight: 600; letter-spacing: var(--ls-label);
  text-transform: uppercase; color: #fff;
  background: rgb(11 27 63 / .62);
  border: 1px solid rgb(255 255 255 / .22);
  border-radius: var(--r-plein);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.avant-apres__etiquette--avant { left: var(--e-4); }
.avant-apres__etiquette--apres { right: var(--e-4); background: rgb(30 58 138 / .78); }

/* Le curseur natif porte la manœuvre : clavier, lecteur d'écran, tactile.
   Il est transparent et couvre l'image ; la poignée rouge n'est que sa peau. */
.avant-apres input[type="range"] {
  position: absolute; inset: 0; z-index: 4;
  width: 100%; height: 100%; margin: 0;
  appearance: none; -webkit-appearance: none;
  background: transparent; cursor: ew-resize;
}
.avant-apres input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 56px; height: 56px;
  border-radius: 50%; background: transparent; cursor: ew-resize;
}
.avant-apres input[type="range"]::-moz-range-thumb {
  width: 56px; height: 56px; border: 0; border-radius: 50%;
  background: transparent; cursor: ew-resize;
}
.avant-apres input[type="range"]:focus-visible { outline: 3px solid var(--rouge); outline-offset: 4px; }


/* ═══════════════════════════════════ Motifs de fond, sections claires */
.section--calque {
  position: relative;
  background-color: var(--fond-alt);
  background-image:
    linear-gradient(rgb(30 58 138 / .045) 1px, transparent 1px),
    linear-gradient(90deg, rgb(30 58 138 / .045) 1px, transparent 1px);
  background-size: 88px 88px, 88px 88px;
  overflow: hidden;
}

/* Trame de cotes : de petits traits verticaux, comme sur un mètre de
   chantier. Employée une seule fois, en tête de la section méthode. */
.trame-cotes {
  height: 26px;
  background-image: linear-gradient(90deg, var(--filet-fort) 1px, transparent 1px);
  background-size: 12px 100%;
  mask-image: linear-gradient(90deg, #000 0%, #000 22%, transparent 78%);
}


/* ═══════════════════════════ Objet animé : le volume en fil de fer.
   Un parallélépipède en rotation lente, dessiné à l'arête. C'est le
   volume brut avant l'ouvrage, la forme la plus élémentaire du métier. */
.volume { position: relative; width: 200px; height: 200px; perspective: 900px; }
.volume__cube {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(-22deg) rotateY(28deg);
}
@media (prefers-reduced-motion: no-preference) {
  .volume__cube { animation: tourne 26s linear infinite; }
}
@keyframes tourne {
  from { transform: rotateX(-22deg) rotateY(0deg); }
  to   { transform: rotateX(-22deg) rotateY(360deg); }
}
.volume__face {
  position: absolute; inset: 0;
  border: 1px solid rgb(143 169 230 / .5);
  background: rgb(41 71 168 / .07);
}
.volume__face:nth-child(1) { transform: translateZ(100px); }
.volume__face:nth-child(2) { transform: rotateY(180deg) translateZ(100px); }
.volume__face:nth-child(3) { transform: rotateY(90deg)  translateZ(100px); }
.volume__face:nth-child(4) { transform: rotateY(-90deg) translateZ(100px); }
.volume__face:nth-child(5) { transform: rotateX(90deg)  translateZ(100px); border-color: rgb(237 27 36 / .55); }
.volume__face:nth-child(6) { transform: rotateX(-90deg) translateZ(100px); }
/* Le volume tourne aussi sur mobile, en plus petit et sous les énoncés :
   c'est le seul objet animé de cette section, le masquer laissait un pavé
   de texte sans vie. */
@media (max-width: 900px) {
  .volume { width: 132px; height: 132px; margin: var(--e-7) auto 0; }
  .volume__face:nth-child(1) { transform: translateZ(66px); }
  .volume__face:nth-child(2) { transform: rotateY(180deg) translateZ(66px); }
  .volume__face:nth-child(3) { transform: rotateY(90deg)  translateZ(66px); }
  .volume__face:nth-child(4) { transform: rotateY(-90deg) translateZ(66px); }
  .volume__face:nth-child(5) { transform: rotateX(90deg)  translateZ(66px); }
  .volume__face:nth-child(6) { transform: rotateX(-90deg) translateZ(66px); }
}


/* ═══════════════ Rehauts de verre et de dégradé sur l'existant ═══════════ */

/* En-tête : verre franc, plancher d'opacité haut car il porte du texte */
.entete {
  background: var(--verre-bande);
  border-bottom: 1px solid rgb(30 58 138 / .10);
}
@supports (backdrop-filter: blur(12px)) {
  .entete {
    background: rgb(255 255 255 / .72);
    backdrop-filter: blur(20px) saturate(1.8);
    -webkit-backdrop-filter: blur(20px) saturate(1.8);
  }
}
.entete.est-pose { box-shadow: 0 1px 0 rgb(30 58 138 / .06), 0 10px 30px -14px rgb(11 27 63 / .22); }

/* Bouton principal : le dégradé de marque, et un reflet qui balaie au survol */
.bouton { background: var(--deg-marque); border-color: transparent; }
.bouton:hover { background: var(--deg-marque); filter: brightness(1.12); }
.bouton--rouge { background: var(--deg-accent); }
.bouton--rouge:hover { background: var(--deg-accent); filter: brightness(1.08); }
.bouton--fantome, .bouton--clair { background: transparent; }
.bouton--fantome:hover { background: var(--bleu-voile); filter: none; }
.bouton--clair {
  background: rgb(255 255 255 / .12);
  border-color: rgb(255 255 255 / .42);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.bouton--clair:hover { background: #fff; color: var(--bleu); border-color: #fff; filter: none; }

.bouton__reflet {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, rgb(255 255 255 / .30) 50%, transparent 62%);
  transform: translateX(-120%);
}
@media (prefers-reduced-motion: no-preference) {
  .bouton:hover .bouton__reflet { animation: balaie .85s var(--ease-doux); }
}
@keyframes balaie { to { transform: translateX(120%); } }

/* Fiches d'expertise : le verre n'a de sens que sur une image. Ici la
   carte reste opaque, mais son entête de média reçoit le dégradé. */
.domaine__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgb(11 27 63 / .55) 0%, transparent 52%);
  opacity: 0; transition: opacity var(--d-moyen) var(--ease-doux);
}
.domaine:hover .domaine__media::after { opacity: 1; }
.domaine__numero {
  background: var(--deg-marque);
  box-shadow: 0 8px 22px -10px rgb(11 27 63 / .7);
}

/* Sections sombres : dégradé, grain et halos plutôt qu'un aplat */
.section--sombre { background: var(--deg-nuit); position: relative; overflow: hidden; }
/* On vise l'enveloppe, PAS `> *`. Avec le sélecteur universel, la règle
   avait la même spécificité que .halo et, déclarée après lui, elle lui
   imposait position: relative. Les deux halos décoratifs entraient alors
   dans le flux et ajoutaient 1 088 px de bleu vide sous le texte. */
.section--sombre > .enveloppe { position: relative; z-index: 2; }

/* Appel final : le dégradé remplace le voile plat */
/* Voile latéral : il couvre la moitié qui porte le texte et laisse
   l'autre moitié de la photographie parfaitement lisible. */
.appel__voile {
  background:
    linear-gradient(100deg, rgb(6 15 38 / .94) 0%, rgb(6 15 38 / .88) 38%,
                            rgb(11 27 63 / .42) 66%, rgb(11 27 63 / .18) 100%),
    linear-gradient(to top, rgb(6 15 38 / .72) 0%, rgb(6 15 38 / 0) 42%);
}
@media (max-width: 760px) {
  .appel__voile { background: linear-gradient(to top, rgb(6 15 38 / .95) 0%,
                                                      rgb(6 15 38 / .82) 55%,
                                                      rgb(11 27 63 / .62) 100%); }
}

/* Pied de page : dégradé et liseré rouge en tête */
.pied { background: var(--deg-nuit); position: relative; overflow: hidden; }
.pied::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  background: linear-gradient(90deg, var(--rouge) 0 22%, rgb(237 27 36 / 0) 55%);
}
.pied > .enveloppe { position: relative; z-index: 2; }

/* Barre mobile : verre, plancher haut car elle porte deux libellés */
.barre-mobile { background: rgb(255 255 255 / .94); }
@supports (backdrop-filter: blur(12px)) {
  .barre-mobile { background: rgb(255 255 255 / .82); backdrop-filter: blur(18px) saturate(1.6);
                  -webkit-backdrop-filter: blur(18px) saturate(1.6); }
}
.barre-mobile a:last-child { background: var(--deg-marque); }

/* Bande défilante : dégradé de marque plutôt qu'un bleu plat */
.bande-confiance { background: var(--deg-marque); position: relative; }

/* Mouvement réduit : tout ce qui bouge s'arrête, rien ne disparaît. */
@media (prefers-reduced-motion: reduce) {
  .js-motion .heros__media { clip-path: inset(0 0 0 0); }
  .js-motion .plan__photo img { opacity: 1; filter: none; }
  .halo, .volume__cube, .bouton__reflet { animation: none !important; }
}


/* ═══════════════════════════════════════════════ 4. Les outils
   Deux widgets, parce qu'ils répondent chacun à une question que le
   visiteur se pose vraiment : « combien ça coûte » et « saurai-je où
   en est mon chantier ». Un troisième n'aurait servi qu'à décorer. */

.outil {
  position: relative; z-index: 2;
  background: var(--surface);
  border: 1px solid var(--filet);
  border-radius: var(--r-4);
  overflow: hidden;
  box-shadow: 0 26px 60px -34px rgb(11 27 63 / .34);
}
.outil__haut {
  display: flex; flex-wrap: wrap; gap: var(--e-3) var(--e-5);
  align-items: baseline; justify-content: space-between;
  padding: var(--e-5) var(--e-6);
  background: var(--deg-marque); color: #fff;
}
.outil__haut h3 { color: #fff; font-size: var(--t-h4); }
.outil__haut p { font-size: var(--t-sm); color: rgb(255 255 255 / .72); }
.outil__corps { padding: var(--e-6); display: grid; gap: var(--e-6); }

/* ---- Estimateur ---- */
@media (min-width: 940px) {
  .estimateur { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); align-items: start; }
}
.estimateur__reglages { display: grid; gap: var(--e-5); }

/* Les cinq natures tiennent sur une ligne dès qu'il y a la place, et se
   replient en deux colonnes sur un téléphone. Empilées pleine largeur,
   elles imposaient huit boutons avant d'arriver au curseur. */
.segments { display: grid; gap: .4rem; grid-template-columns: repeat(auto-fit, minmax(min(126px, 100%), 1fr)); }
.segments--trois { grid-template-columns: repeat(3, minmax(0, 1fr)); }

@media (max-width: 700px) {
  .segments { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Un cinquième choix seul sur sa ligne : il la prend toute. La règle ne
     vaut QUE pour la grille à deux colonnes : sur le groupe de trois, le
     dernier est aussi en rang impair et « Exception » se retrouvait seul
     sur toute la largeur. */
  .segments:not(.segments--trois) label:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .segments--trois { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .segments span { padding: .7rem .5rem; font-size: .8125rem; line-height: 1.3; }
}
@media (max-width: 560px) {
  /* Les précisions sous les niveaux de finition doublent la hauteur des
     cases pour un gain d'information faible : elles tombent. */
  .segments--trois span small { display: none; }
}
.segments input { position: absolute; opacity: 0; width: 0; height: 0; }
.segments label { display: block; }
.segments span {
  display: block; padding: .7rem .9rem; text-align: center; cursor: pointer;
  border: 1px solid var(--filet-fort); border-radius: var(--r-2);
  font-size: 0.875rem; font-weight: 500; line-height: 1.35;
  transition: all var(--d-court) var(--ease-doux);
}
.segments label:hover span { border-color: var(--bleu); }
.segments input:checked + span {
  background: var(--deg-marque); border-color: transparent; color: #fff;
  box-shadow: 0 8px 20px -10px rgb(11 27 63 / .6);
}
.segments input:focus-visible + span { outline: 3px solid var(--rouge); outline-offset: 3px; }

.curseur-champ { display: grid; gap: .6rem; }
.curseur-champ__tete { display: flex; align-items: baseline; justify-content: space-between; gap: var(--e-4); }
.curseur-champ__tete b {
  font-family: var(--f-titre); font-size: 1.375rem; color: var(--bleu);
  font-variant-numeric: tabular-nums;
}
.curseur-champ input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 6px; margin: .6rem 0;
  border-radius: var(--r-plein); background: var(--filet-fort);
  background-image: var(--deg-accent);
  background-size: var(--rempli, 50%) 100%; background-repeat: no-repeat;
  cursor: pointer;
}
.curseur-champ input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 26px; height: 26px; border-radius: 50%;
  background: #fff; border: 3px solid var(--bleu); cursor: grab;
  box-shadow: 0 3px 10px rgb(11 27 63 / .3);
}
.curseur-champ input[type="range"]::-moz-range-thumb {
  width: 26px; height: 26px; border-radius: 50%;
  background: #fff; border: 3px solid var(--bleu); cursor: grab;
}
.curseur-champ input[type="range"]:focus-visible { outline: 3px solid var(--rouge); outline-offset: 4px; }
.curseur-champ__bornes { display: flex; justify-content: space-between; font-size: var(--t-sm); color: var(--texte-doux); }

/* Le résultat : la seule zone de la page où un chiffre est énorme */
.estimateur__resultat {
  container-type: inline-size;
  position: relative; overflow: hidden;
  padding: var(--e-6);
  border-radius: var(--r-4);
  background: var(--deg-nuit); color: #fff;
}
.estimateur__resultat > :not(.halo) { position: relative; z-index: 2; }
.estimateur__resultat dt {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--rouge-clair);
}
/* La fourchette se lit comme une ligne de devis : le mot à gauche, le
   nombre aligné à droite. Les deux montants étant en chasse fixe et calés
   sur la même colonne, leurs chiffres se superposent exactement d'une
   ligne à l'autre. Aucun retour à la ligne n'est laissé au hasard. */
.estimateur__montant {
  margin: var(--e-4) 0 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  column-gap: .7rem; row-gap: .1rem;
  font-family: var(--f-titre);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.028em;
}
.estimateur__montant i {
  font-style: normal; font-weight: 500;
  font-size: .8125rem; text-transform: uppercase; letter-spacing: .1em;
  color: rgb(255 255 255 / .5);
  font-family: var(--f-corps);
}
.estimateur__montant b {
  font-weight: 700; text-align: right;
  font-size: clamp(1.5rem, 1rem + 1.7vw, 2.375rem);
  line-height: 1.1;
  white-space: nowrap;
}
.estimateur__montant .devise {
  grid-column: 1 / -1; justify-self: end;
  margin-top: .35rem;
  font-family: var(--f-corps); font-weight: 500;
  font-size: var(--t-sm); letter-spacing: .1em; text-transform: uppercase;
  color: rgb(255 255 255 / .62);
}
.estimateur__unite { font-size: var(--t-sm); color: rgb(255 255 255 / .6); margin-top: .5rem; }
.estimateur__detail {
  margin-top: var(--e-5); padding-top: var(--e-5);
  border-top: 1px solid rgb(255 255 255 / .16);
  display: grid; gap: .55rem; font-size: var(--t-sm); color: rgb(255 255 255 / .78);
}
/* En dessous de 420 px de panneau, « Coût au mètre carré » et sa valeur
   ne tiennent pas côte à côte : la valeur se cassait sur trois lignes.
   On les empile alors, le libellé au-dessus. */
.estimateur__detail div {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: .15rem var(--e-4);
}
.estimateur__detail b { white-space: nowrap; }
@container (max-width: 420px) { .estimateur__detail div { display: grid; } }
.estimateur__detail b { color: #fff; font-weight: 600; font-variant-numeric: tabular-nums; }
.estimateur__avis {
  margin-top: var(--e-5); font-size: var(--t-sm); line-height: 1.5;
  color: rgb(255 255 255 / .55);
}

/* ---- Suivi de chantier ---- */
.suivi { display: grid; gap: var(--e-6); }
@media (min-width: 900px) { .suivi { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); } }

.suivi__jauge { display: grid; gap: var(--e-4); align-content: start; }
.suivi__anneau { position: relative; width: 172px; height: 172px; }
.suivi__anneau svg { transform: rotate(-90deg); }
.suivi__anneau circle { fill: none; stroke-width: 10; stroke-linecap: round; }
.suivi__anneau .piste { stroke: var(--filet); }
.suivi__anneau .part  { stroke: var(--rouge); transition: stroke-dashoffset var(--d-long) var(--ease-sortie); }
.suivi__anneau b {
  position: absolute; inset: 0; display: grid; place-content: center;
  font-family: var(--f-titre); font-size: 2.25rem; color: var(--bleu);
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}

.phases { display: grid; gap: 0; border-top: 1px solid var(--filet); }
.phase {
  display: grid; grid-template-columns: 30px minmax(0, 1fr) auto;
  gap: var(--e-4); align-items: center;
  padding: var(--e-4) 0; border-bottom: 1px solid var(--filet);
  cursor: pointer; background: none; border-left: 0; border-right: 0; text-align: left;
  transition: background var(--d-court) var(--ease-doux);
}
.phase:hover { background: var(--fond-alt); }
.phase__puce {
  width: 26px; height: 26px; border-radius: var(--r-plein);
  display: grid; place-items: center;
  border: 2px solid var(--filet-fort); color: var(--n-500);
  font-size: 11px; font-weight: 700; font-family: var(--f-titre);
}
.phase[data-etat="fait"] .phase__puce { background: var(--deg-marque); border-color: transparent; color: #fff; }
.phase[data-etat="encours"] .phase__puce { background: var(--deg-accent); border-color: transparent; color: #fff; }
.phase__nom { font-weight: 500; font-size: 0.9375rem; color: var(--n-700); }
.phase[data-etat="attente"] .phase__nom { color: var(--n-500); }
.phase__etat {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  padding: .25rem .6rem; border-radius: var(--r-plein);
}
.phase[data-etat="fait"] .phase__etat    { color: var(--bleu); background: var(--bleu-voile); }
.phase[data-etat="encours"] .phase__etat { color: var(--rouge-fonce); background: var(--rouge-voile); }
.phase[data-etat="attente"] .phase__etat { color: var(--n-500); background: var(--n-050); }
.phase__note {
  grid-column: 2 / -1; font-size: var(--t-sm); color: var(--texte-doux);
  overflow: hidden; height: 0; transition: height var(--d-moyen) var(--ease-sortie);
}
.phase[aria-expanded="true"] .phase__note { height: auto; padding-top: .5rem; }


/* ═══════════════════════ Retouches issues de la revue adversariale */

/* Le numéro de téléphone de l'en-tête faisait 19 px de haut : impossible
   à viser au doigt, alors que c'est le premier geste attendu. */
.dispo__tel {
  display: inline-block; padding-block: .5rem;
  color: inherit; text-decoration: none;
}
.dispo__tel:hover { color: var(--bleu); text-decoration: underline; }
.dispo--nu { border: 0; padding: 0; margin: 0; }

/* L'indicateur de défilement annonçait « Faire défiler » sans rien faire.
   C'est désormais un lien vers la première section. */
a.heros__defiler { text-decoration: none; transition: color var(--d-court) var(--ease-doux); }
a.heros__defiler:hover { color: #fff; }
a.heros__defiler:focus-visible { outline-offset: 6px; }

/* Chasse fixe partout où des chiffres se comparent ou s'animent */
.chiffre__valeur, .estimateur__montant, .curseur-champ__tete b,
.suivi__anneau b, .realisation__meta { font-variant-numeric: tabular-nums; }

/* Utilitaires, pour sortir les styles en dur du balisage */
.txt-lead   { font-size: var(--t-lead); }
.txt-petit  { font-size: var(--t-sm); color: var(--n-600); }
.marge-haut { margin-top: var(--e-6); }
.pile-fin   { display: flex; justify-content: flex-end; }
.legende-fig{ margin-top: var(--e-4); font-size: var(--t-sm); color: var(--n-600); }

/* Titres de colonnes du pied : ils suivent un h2 de page, donc h3.
   Ils gardent l'aspect qu'ils avaient en h4. */
.pied .pied__titre {
  color: #fff; font-size: var(--t-sm); font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--ls-label);
  margin-bottom: var(--e-4); padding-bottom: var(--e-3);
  border-bottom: 1px solid var(--filet-sombre); position: relative;
}
.pied .pied__titre::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 32px; height: 2px; background: var(--rouge);
}

/* Le compteur de filtres n'existait que pour les lecteurs d'écran :
   un visiteur voyant qui filtre n'avait aucun retour chiffré. */
.compte-filtre {
  margin: calc(var(--e-6) * -1) 0 var(--e-6);
  font-size: var(--t-sm); color: var(--n-600);
  font-variant-numeric: tabular-nums;
}
.aucun-resultat {
  padding: var(--e-8) var(--e-6); text-align: center;
  border: 1px dashed var(--filet-fort); border-radius: var(--r-2);
  color: var(--n-600); display: grid; gap: var(--e-4); justify-items: center;
}

/* Sous-titres des mentions légales : ils suivent directement le h1 de la
   page, donc h2. La taille reste celle d'un h3, la hiérarchie visuelle ne
   change pas, seule la hiérarchie sémantique est corrigée. */
.mentions__titre { font-size: var(--t-h3); margin-bottom: var(--e-4); }
.mentions__titre--espace { margin-top: var(--e-8); }


/* ═══════════════════ Bannière : tenue en hauteur sur petit écran
   Quatre repères empilés portaient le héros à 133 % de la fenêtre : il
   fallait défiler pour voir le bas de la bannière, ce qui est exactement
   le contraire de ce qu'une bannière doit faire. */
@media (max-width: 720px) {
  .heros { min-height: auto; }
  .heros__contenu { padding-block: clamp(2.25rem, 1.5rem + 5vw, 3.5rem) var(--e-6); }
  .heros__reperes {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin-top: var(--e-6);
  }
  .heros__repere {
    padding: var(--e-4);
    border-right: 1px solid rgb(255 255 255 / .14);
    border-bottom: 1px solid rgb(255 255 255 / .14);
  }
  .heros__repere:nth-child(2n)  { border-right: 0; }
  .heros__repere:nth-child(n+3) { border-bottom: 0; }
  .heros__repere dd { font-size: .8125rem; line-height: 1.35; }
  .heros__texte { font-size: 1rem; }
  .heros__actions { margin-top: var(--e-6); }
}
@media (max-width: 430px) {
  /* Sous 430 px, deux colonnes de repères deviennent illisibles :
     on n'en garde que les deux premiers, les autres sont dits ailleurs. */
  .heros__reperes { grid-template-columns: minmax(0, 1fr); }
  .heros__repere { border-right: 0; }
  .heros__repere:nth-child(n+3) { display: none; }
  .heros__repere:nth-child(2) { border-bottom: 0; }
}

/* ═══════════════════ Bannière : écrans COURTS
   Le problème n'est pas la largeur mais la hauteur utile. Un portable de
   1280 × 720 est large et bas : la bannière y débordait de 16 % alors
   qu'elle tenait sur un écran de bureau. On règle donc la respiration sur
   la hauteur de fenêtre, pas sur la largeur. */
@media (max-height: 820px) {
  .heros__contenu {
    padding-block: clamp(1.75rem, 5.5vh, 3.25rem) clamp(1.25rem, 3.5vh, 2.25rem);
  }
  .heros h1 { font-size: clamp(2.25rem, 9vh, 5rem); }
  .heros__texte { margin-top: var(--e-4); font-size: 1.0625rem; max-width: 48ch; }
  .heros__actions { margin-top: var(--e-5); }
  .heros__reperes { margin-top: clamp(1rem, 2.6vh, 1.75rem); }
  .heros__repere { padding-block: var(--e-4); }
  .heros__ligne { margin-bottom: var(--e-4); }
}
@media (max-height: 680px) {
  /* Très bas : les repères passent en une seule ligne compacte. */
  .heros__repere dd { font-size: .8125rem; line-height: 1.3; }
  .heros__repere { padding-block: .7rem; }
}

/* ═══════════════════ Bannière : petits téléphones
   Les quatre repères pesaient 207 px pour deux entrées visibles, soit le
   quart de l'écran d'un téléphone de 360 px. Sur cette taille on ne garde
   que la disponibilité : les trois métiers sont énoncés dans le bandeau
   juste en dessous et dans les fiches d'expertise. */
@media (max-width: 560px) {
  .heros__reperes { grid-template-columns: minmax(0, 1fr); margin-top: var(--e-5); }
  .heros__repere { display: none; padding: .75rem var(--e-4); border: 0; }
  .heros__repere:nth-child(4) { display: block; }
  .heros__repere:nth-child(4) dt { margin-bottom: .25rem; }
  .heros__repere:nth-child(4) dd { font-size: .875rem; line-height: 1.4; }
  .heros__texte { font-size: .9375rem; line-height: 1.55; }
  .heros h1 { font-size: clamp(2.125rem, 1.1rem + 5.2vw, 3rem); }
}

/* ═══════════════════ Devis : le vide de droite
   Le formulaire, plafonné à 880 px et aligné à gauche, laissait 600 px de
   blanc sur un écran de bureau. La place sert maintenant à répondre aux
   deux questions qu'on se pose en remplissant : « et après ? » et
   « puis-je faire plus vite ? ». */
.devis-cadre { display: grid; gap: var(--e-7); align-items: start; }
@media (min-width: 1000px) {
  .devis-cadre { grid-template-columns: minmax(0, 7fr) minmax(0, 4fr); gap: var(--e-9); }
  .devis-aside { position: sticky; top: 7rem; }
}
.devis-cadre__colonne { min-width: 0; }
.devis-aside { display: grid; gap: var(--e-5); }
.devis-aside__bloc {
  padding: var(--e-6);
  border: 1px solid var(--filet);
  border-radius: var(--r-4);
  background: var(--surface);
}
.devis-aside__bloc--fort {
  background: var(--deg-nuit); border-color: transparent; color: rgb(255 255 255 / .78);
  position: relative; overflow: hidden;
}
.devis-aside__bloc--fort .etiquette { color: var(--rouge-clair); }
.devis-aside__texte { margin: var(--e-4) 0 var(--e-5); font-size: 0.9375rem; color: rgb(255 255 255 / .82); }
.devis-aside__note { margin-top: var(--e-4); font-size: var(--t-sm); color: rgb(255 255 255 / .55); }

.devis-suite { counter-reset: etape; display: grid; gap: var(--e-4); margin-top: var(--e-5); }
/* La pastille occupe la première colonne, le libellé et sa suite la
   seconde. Sans enveloppe explicite, le texte qui suit un <b> devient un
   élément de grille à part, renvoyé dans la colonne de 26 px : un mot
   par ligne. */
.devis-suite li {
  counter-increment: etape;
  display: grid; grid-template-columns: 26px minmax(0, 1fr);
  gap: .25rem var(--e-3);
  font-size: 0.9375rem; line-height: 1.5;
}
.devis-suite li > span { grid-column: 2; color: var(--texte); }
.devis-suite li > b { grid-column: 2; }
.devis-suite li::before {
  content: counter(etape);
  width: 26px; height: 26px; display: grid; place-items: center;
  border-radius: var(--r-plein); background: var(--bleu-voile); color: var(--bleu);
  font-family: var(--f-titre); font-weight: 700; font-size: 12px;
}
.devis-suite b { color: var(--n-800); font-weight: 600; }


/* ═══════════════════ La maquette filaire, deuxième temps
   L'élévation est un dessin de face, à plat. La volumétrie est le même
   ouvrage vu dans l'espace, en projection isométrique à 30°. Sa géométrie
   est calculée, pas dessinée à la main : les arêtes se rejoignent. */
.plan__axo {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1;
  opacity: 0;
}
.plan__axo [data-trace3d] {
  fill: none; stroke: #8fa9e6; stroke-width: 1.5;
  stroke-linecap: round; vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 6px rgb(143 169 230 / .4));
}
.plan__axo [data-trace3d="trame"] { stroke: #3f5da4; stroke-width: 1; filter: none; }
.plan__axo [data-trace3d="fin"]   { stroke: #cddaf7; stroke-width: 1.1; }
.plan__axo [data-trace3d="creux"] { stroke: #6f8bd0; stroke-width: 1.2; }
.plan__axo [data-trace3d="cote"]  { stroke: var(--rouge); stroke-width: 1.2;
                                    filter: drop-shadow(0 0 8px rgb(237 27 36 / .55)); }

/* Frise des trois temps : elle dit où l'on en est dans la démonstration. */
.plan__etapes {
  position: relative; z-index: 3; flex: 0 0 auto;
  width: min(100% - (var(--gouttiere) * 2), var(--largeur));
  margin-inline: auto;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--e-4);
}
.plan__etapes li {
  display: flex; align-items: baseline; gap: .6rem;
  padding-top: .7rem;
  border-top: 2px solid rgb(255 255 255 / .16);
  color: rgb(255 255 255 / .42);
  font-size: 0.9375rem;
  transition: color var(--d-moyen) var(--ease-doux),
              border-color var(--d-moyen) var(--ease-doux);
}
.plan__etapes li b {
  font-family: var(--f-titre); font-size: var(--t-xs); font-weight: 700;
  letter-spacing: .1em;
}
.plan__etapes li.est-active { color: #fff; border-top-color: var(--rouge); }
.plan__etapes li.est-active b { color: var(--rouge-clair); }
.plan__etapes li.est-faite { color: rgb(255 255 255 / .66); border-top-color: rgb(143 169 230 / .55); }

@media (max-width: 900px) {
  /* La séquence est jouée sur mobile aussi : c'est la pièce maîtresse du
     site, la couper revenait à priver de tout le travail le visiteur qui
     vient du téléphone, c'est-à-dire la majorité.
     Ce qui change : la course est plus courte, les traits sont plus épais
     pour rester lisibles à 350 px, et les trames les plus denses tombent. */
  /* 300vh : la course de l'animation en occupe 1,15, le reste devient
     un temps d'arrêt d'environ 0,85 écran sur l'ouvrage fini. */
  .plan { height: 300vh; }
  .plan__scene { padding-top: max(5.5rem, 11vh); gap: .75rem; }
  .plan__cadre { aspect-ratio: 5 / 4; }
  .plan__dessin [data-trace] { stroke-width: 2.1; }
  .plan__axo   [data-trace3d] { stroke-width: 2; }
  /* Hachures de terrain et trame de sol : illisibles à cette taille,
     elles ne font que salir le dessin. */
  .plan__dessin [data-trace]:nth-of-type(2),
  .plan__axo [data-trace3d="trame"] { display: none; }
  .plan__quadrillage { background-size: 24px 24px, 24px 24px, 120px 120px, 120px 120px; }

  .plan__etapes { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem; }
  .plan__etapes li { font-size: .75rem; gap: .35rem; padding-top: .5rem; flex-wrap: wrap; }
  .plan__etapes li b { font-size: 10px; }
  .plan__legende { font-size: .75rem; gap: .3rem 1rem; }
  .plan__titre h2 { font-size: clamp(1.5rem, 1.1rem + 2.4vw, 2rem); }
}
@media (max-width: 430px) {
  /* Sous 430 px, le troisième repère de la légende passe à la ligne et
     mange la scène : on n'en garde que deux. */
  .plan__legende span:nth-child(3) { display: none; }
  .plan__etapes li span { display: none; }
  .plan__etapes li::after { content: attr(data-court); }
}


/* La section Vision et Mission empile ses deux colonnes sous 900 px, et le
   volume en fil de fer se place dessous, centré. */
@media (max-width: 900px) {
  #vision .enveloppe > div { flex-direction: column; gap: var(--e-6) !important; }
}

/* ═══════════════════════ WhatsApp
   Le vert de WhatsApp n'entre pas dans la charte CERVIS : il ne sert que
   sur le pictogramme et sur le bouton d'action dédié, jamais ailleurs. */
:root { --wa: #25d366; --wa-fonce: #128c4a; }

.lien-wa { display: inline-flex; align-items: center; gap: .5rem; }
.lien-wa .pic-wa { flex: 0 0 auto; color: var(--wa); }
.pied .lien-wa { color: rgb(255 255 255 / .72); }
.pied .lien-wa:hover { color: #fff; }
.contact-direct .lien-wa { padding-block: .45rem; }

/* Bouton dédié dans le panneau mobile */
.bouton--wa {
  --bt-fond: var(--wa-fonce); --bt-bord: transparent; --bt-texte: #fff;
  background: var(--wa-fonce);
}
.bouton--wa:hover { background: #0f7a41; filter: none; }
.bouton--wa::after { background: #fff; }
.bouton--wa .pic-wa { color: #fff; }

/* Barre d'action mobile : trois gestes au lieu de deux */
.barre-mobile { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.barre-mobile a { gap: .4rem; font-size: .875rem; }
.barre-mobile a:first-child { color: var(--bleu); border-right: 1px solid var(--filet); }
.barre-mobile__wa {
  color: var(--wa-fonce); border-right: 1px solid var(--filet);
}
.barre-mobile__wa .pic-wa { color: var(--wa); }
.barre-mobile a:last-child { background: var(--deg-marque); color: #fff; }
@media (max-width: 380px) {
  /* Sous 380 px, trois libellés ne tiennent plus : le pictogramme parle. */
  .barre-mobile__wa span { position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .barre-mobile a { font-size: .8125rem; padding-inline: .4rem; }
}

/* ═══════════════════ L'invite à défiler
   En arrivant sur la section, rien n'indique que le dessin ne se fera que
   si l'on continue à défiler : on peut croire à une image fixe et passer
   à côté de toute la démonstration. Cette invite le dit, une fois, puis
   s'efface dès que le tracé commence. */
.plan__invite {
  position: relative; z-index: 3; flex: 0 0 auto;
  width: min(100% - (var(--gouttiere) * 2), var(--largeur));
  margin-inline: auto;
  display: flex; align-items: center; gap: .7rem;
  font-size: var(--t-sm); font-weight: 500;
  letter-spacing: .04em;
  color: rgb(255 255 255 / .62);
  transition: opacity var(--d-long) var(--ease-doux),
              transform var(--d-long) var(--ease-sortie);
}
.plan__invite.est-partie { opacity: 0; transform: translateY(-6px); pointer-events: none; }

/* Un filet qui descend, repris de l'indicateur de la bannière */
.plan__invite i {
  flex: 0 0 auto; display: block;
  width: 1px; height: 22px;
  background: rgb(255 255 255 / .28);
  position: relative; overflow: hidden;
}
.plan__invite i::after {
  content: ""; position: absolute; inset: 0;
  background: var(--rouge); transform: translateY(-100%);
}
@media (prefers-reduced-motion: no-preference) {
  .plan__invite i::after { animation: filet-descend 2s var(--ease-doux) infinite; }
}
@media (max-width: 560px) {
  .plan__invite { font-size: .75rem; gap: .55rem; }
  .plan__invite i { height: 18px; }
}

/* ═══════════════════ WhatsApp dans l'en-tête
   Le canal le plus utilisé en Côte d'Ivoire mérite d'être atteignable sans
   défiler. Le bouton se resserre sur pictogramme seul dès que la place
   manque, plutôt que de pousser la barre à se replier. */
/* Le numéro WhatsApp est écrit à côté du glyphe : demandé par le client,
   un numéro qu'on voit se recopie et s'appelle. Il occupe la place que
   libère le bloc disponibilité, qui ne porte plus de numéro — la largeur
   totale de l'en-tête est donc inchangée. Sous 1320 px, là où ce bloc
   disparaît, le numéro se replie et le glyphe reste seul ; le nom et le
   numéro restent portés par aria-label. */
.entete__wa { padding-inline: .8rem; white-space: nowrap; }
.entete__wa .pic-wa { color: #fff; }
.entete__wa .wa-num { font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 1359px) {
  .entete__wa .wa-num { position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .entete__wa { padding-inline: .7rem; }
}

/* Libellé du bouton de devis : long tant qu'il y a la place, court ensuite */
.entete__devis .mot-court { display: none; }
@media (max-width: 1200px) {
  .entete__devis .mot-long { display: none; }
  .entete__devis .mot-court { display: inline; }
  .entete__devis { padding-inline: 1.1rem; }
}

/* Disponibilité compacte : le numéro WhatsApp est désormais écrit dans le
   bouton voisin, la phrase longue ferait doublon ET déborder la barre —
   mesuré à 1321 px de contenu pour une enveloppe de 1280. Le libellé
   complet reste dans le pied de page et le panneau de menu. */
.dispo__court { display: inline-flex; align-items: baseline; gap: .3rem;
  font-size: 0.8125rem; color: var(--n-700); white-space: nowrap; }
.dispo__court strong { display: inline; color: var(--bleu); font-weight: 600; }

/* Au-delà de 1359 px le numéro est écrit en toutes lettres dans le bouton :
   il faut lui faire 47 px de place, mesurés. On les prend sur les écarts
   entre blocs et sur les marges intérieures, jamais sur la navigation,
   qui se mettrait à passer à la ligne. Contenu ramené de 1327 à 1280. */
@media (min-width: 1360px) {
  .entete__interieur { gap: 1rem; }
  .dispo { margin-left: 2px; }
  .entete__wa .wa-num { font-size: 0.875rem; letter-spacing: -.01em; }
  .entete__devis { padding-inline: 1.15rem; }
}

/* La disponibilité est le premier bloc à céder : elle est répétée dans le
   pied de page et dans le panneau de menu. */
@media (max-width: 1320px) { .dispo { display: none; } }

@media (max-width: 620px) {
  /* La barre d'action en pied d'écran porte déjà WhatsApp : le garder ici
     doublerait l'appel à l'action. */
  .entete__wa { display: none; }
}

/* ═══════════════════ Aucun retour à la ligne sur les coordonnées
   Un numéro ou un nom de canal coupé en deux se lit mal et se recopie mal. */
.lien-wa, .lien-wa span,
.contact-direct a, .contact-direct span,
.dispo__tel, .pied .lien-wa span,
.entete__wa .wa-num { white-space: nowrap; }
.contact-direct dd { min-width: 0; }
.barre-mobile a { white-space: nowrap; }

/* Le libellé d'un bouton d'action ne se coupe pas : « Écrire sur
   WhatsApp » sur deux lignes dans une fiche étroite se lisait mal. */
.bouton--wa { white-space: nowrap; }

/* L'invite est une phrase : elle a le droit de se replier, mais sur un très
   petit écran elle se resserre pour ne pas manger la scène. */
@media (max-width: 380px) {
  .plan__invite { font-size: .7rem; line-height: 1.35; gap: .45rem; }
}

/* ═══════════════════ Coordonnées : un pictogramme, jamais de coupure
   `svg { display: block }` est posé globalement pour les images. Sur un
   pictogramme en ligne, il fait passer le libellé à la ligne suivante dès
   que le parent n'est pas une boîte flexible — c'est ce qui coupait le
   lien WhatsApp du pied de page en deux. La spécificité est donc relevée
   ici pour que le conteneur redevienne flexible. */
a.lien-contact, span.lien-contact, .lien-contact {
  display: inline-flex; align-items: center; gap: .6rem;
  white-space: nowrap;
}
.lien-contact > span { white-space: nowrap; }
.lien-contact .pic, .lien-contact .pic-wa {
  flex: 0 0 auto; display: block;
  color: rgb(255 255 255 / .42);
  transition: color var(--d-court) var(--ease-doux);
}
.lien-contact:hover .pic { color: var(--rouge-clair); }
.lien-contact .pic-wa { color: var(--wa); }
.lien-contact--muet { cursor: default; }

/* Intitulés des blocs de contact : le pictogramme précède le mot */
.contact-direct dt {
  display: inline-flex; align-items: center; gap: .45rem; white-space: nowrap;
}
.contact-direct dt .pic, .contact-direct dt .pic-wa { flex: 0 0 auto; display: block; }
.contact-direct dt .pic-wa { color: var(--wa); }

/* Même précaution sur les boutons et la barre d'action : le pictogramme y
   est un élément de rangée, jamais un bloc qui pousse le libellé dessous. */
.bouton .pic-wa, .bouton .pic, .barre-mobile a .pic-wa { display: block; flex: 0 0 auto; }

/* `.pied li > span` (0,1,2) reprenait le dessus sur `span.lien-contact`
   (0,1,1) et remettait le repère de lieu en bloc. Deux classes suffisent
   à trancher, sans recourir à !important. */
.pied .lien-contact { display: inline-flex; align-items: center; }

/* ═══════════════════ Les deux boutons flottants
   Une seule colonne, un seul écart : deux éléments posés séparément
   finissent toujours par se toucher sur une taille d'écran qu'on n'a pas
   testée. Ici la géométrie interdit le chevauchement.
   La colonne se pose au-dessus de la barre d'action mobile quand elle
   existe, et respecte les zones sûres des téléphones à encoche. */
.flottants {
  position: fixed; z-index: var(--z-flottant);
  right: clamp(1rem, 2.4vw, 1.75rem);
  bottom: calc(clamp(1rem, 2.4vw, 1.75rem) + env(safe-area-inset-bottom));
  display: grid; gap: .7rem; justify-items: center;
  pointer-events: none;              /* seuls les boutons captent le doigt */
}
.flottant {
  pointer-events: auto;
  width: 54px; height: 54px;
  display: grid; place-items: center;
  border-radius: var(--r-plein);
  border: 0; cursor: pointer;
  box-shadow: 0 6px 20px -6px rgb(11 27 63 / .45), 0 2px 6px rgb(11 27 63 / .18);
  transition: transform var(--d-court) var(--ease-sortie),
              background var(--d-court) var(--ease-doux),
              opacity var(--d-moyen) var(--ease-doux);
}
.flottant:hover { transform: translateY(-2px); }
.flottant:active { transform: translateY(0); }
.flottant:focus-visible { outline: 3px solid var(--rouge); outline-offset: 3px; }

.flottant--wa { background: var(--wa); color: #fff; }
.flottant--wa:hover { background: #1fbb59; color: #fff; }
.flottant--wa .pic-wa { display: block; }

.flottant--haut {
  background: rgb(255 255 255 / .94); color: var(--bleu);
  border: 1px solid var(--filet-fort);
}
@supports (backdrop-filter: blur(10px)) {
  .flottant--haut { background: rgb(255 255 255 / .82);
    backdrop-filter: blur(14px) saturate(1.5); -webkit-backdrop-filter: blur(14px) saturate(1.5); }
}
.flottant--haut:hover { background: #fff; }
.flottant--haut svg { display: block; }

/* Au-dessus de la barre d'action, jamais dessus. La barre fait 60 px plus
   la zone sûre : la colonne s'y ajoute au lieu de la recouvrir. */
@media (max-width: 720px) {
  .flottants { bottom: calc(60px + env(safe-area-inset-bottom) + .85rem); }
  .flottant { width: 50px; height: 50px; }
  .flottants { gap: .6rem; }
}
/* Écran très bas : deux boutons de 54 px plus la barre mangeraient l'écran. */
@media (max-height: 480px) {
  .flottant { width: 44px; height: 44px; }
  .flottant--wa .pic-wa { width: 21px; height: 21px; }
}

/* La barre d'action retrouve ses deux gestes */
.barre-mobile { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.barre-mobile a:first-child { border-right: 1px solid var(--filet); }

@media (prefers-reduced-motion: reduce) {
  .flottant { transition: none; }
}
