/* ==========================================================================
   OBT Agency — style.css
   Toutes les valeurs viennent de tokens.css. Aucune couleur ni taille de
   police écrite en dur dans ce fichier.
   Mobile d'abord — points de rupture : 480 / 768 / 1024 / 1440 px.
   ========================================================================== */

/* ---- Reset ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
/* Double appui : deux appuis rapproches sur une commande sont un double clic,
   pas une demande de zoom. Sur telephone, ils zoomaient la page et il fallait
   dezoomer a la main pour continuer la visite.

   `manipulation` ne retire QUE le zoom par double appui : le defilement et le
   pincement pour zoomer restent entiers. La balise viewport n'est pas touchee
   pour cette raison : `user-scalable=no` aurait supprime tout zoom et rendu le
   site inutilisable pour qui a besoin d'agrandir.

   Pose sur la racine, donc partout ; repete sur les commandes parce que Safari
   sur iOS a longtemps ignore la regle posee sur un ancetre pour cette
   gesture-la, et c'est la que le defaut se voit. */
html { touch-action: manipulation; }
button, a, label, summary, input, select, textarea, [role="button"],
[data-carousel-next], [data-carousel-prev], [data-avis-dot] {
  touch-action: manipulation;
}
/* `height: auto` sur les images, et pas seulement `max-width` : sans lui,
   l'attribut `height` du balisage fait loi et une image en largeur fluide garde
   sa hauteur intrinsèque. C'est ce qui faisait passer les vignettes de
   réalisations de 475 à 770 px de haut. Les logos, eux, fixent leur hauteur en
   CSS : ils ne sont pas concernés. */
/* `[hidden]` doit gagner contre TOUTE règle d'affichage d'auteur. La feuille
   du navigateur le pose sans `!important` : n'importe quel `display: grid` de
   composant l'écrase, et l'élément reste à l'écran alors que le script le croit
   masqué. C'est ce qui laissait le « Merci » du tunnel Tarifs visible en
   permanence sous le formulaire, et ce qui affichait les sept groupes de
   formules à la fois. Une seule ligne règle la famille entière. */
[hidden] { display: none !important; }

img { height: auto; }
img, svg, video { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
h1, h2, h3, h4, h5, h6 { font-weight: inherit; font-size: inherit; }
table { border-collapse: collapse; }
fieldset { border: 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ---- Base ----------------------------------------------------------------- */
html, body { background: var(--c-bg); }

body {
  font-family: var(--font-base);
  font-size: var(--body-size);
  font-weight: var(--body-weight);
  line-height: var(--body-lh);
  letter-spacing: var(--body-ls);
  color: var(--c-text);
  -webkit-font-smoothing: antialiased;
  /* `clip` plutôt que `hidden` : `hidden` ferait du body un conteneur de
     défilement, ce qui casse `position: sticky` (cartes empilées de la page
     Services). `hidden` reste en repli pour les navigateurs sans `clip`. */
  overflow-x: hidden;
  overflow-x: clip;
}
body.is-locked { overflow: hidden; }

h1, h2, h3 { font-weight: var(--fw-bold); }
h1 { font-size: var(--h1-size); line-height: var(--h1-lh); letter-spacing: var(--h1-ls); }
h2 { font-size: var(--h2-size); line-height: var(--h2-lh); letter-spacing: var(--h2-ls); font-weight: var(--h2-weight); }
h3 { font-size: var(--h3-size); line-height: var(--h3-lh); letter-spacing: var(--h3-ls); font-weight: var(--h3-weight); }
p  { color: var(--c-text-muted); }

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.section { padding-block: var(--section-pad-mobile); }
/* Une ancre (`#tarifs-s2`, `#realisations-s2`…) amène le haut de la section au
   haut de la fenêtre, c'est-à-dire SOUS le bandeau menu : le surtitre et une
   partie du titre passaient derrière. Le décalage vaut aussi pour les
   `scrollIntoView` du tunnel. */
section[id] { scroll-margin-top: var(--header-height); }
@media (min-width: 768px) { .section { padding-block: var(--section-pad); } }

.section-head { max-width: 640px; margin-bottom: var(--sp-12); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head .lead { margin-top: var(--sp-4); font-size: var(--lead-size); }
.section-head--center .lead { max-width: 640px; margin-inline: auto; }
.section-title--wide { max-width: 820px; margin-inline: auto; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  font-size: var(--eyebrow-size);
  font-weight: var(--eyebrow-weight);
  letter-spacing: var(--eyebrow-ls);
  text-transform: var(--eyebrow-case);
  color: var(--eyebrow-color);
}
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}

:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
  border-radius: 6px;
}

.skip-link {
  position: fixed; left: var(--sp-4); top: -80px; z-index: 999;
  background: var(--c-accent); color: var(--c-text-on-accent);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-sm);
  transition: top var(--dur-fast) var(--ease-out-soft);
}
.skip-link:focus { top: var(--sp-4); }

/* ---- Icônes --------------------------------------------------------------- */
.icon {
  width: var(--icon-size); height: var(--icon-size);
  stroke: currentColor; fill: none;
  stroke-width: var(--icon-stroke);
  stroke-linecap: round; stroke-linejoin: round;
  flex-shrink: 0;
}
.icon--sm { width: 16px; height: 16px; }
.icon--accent { color: var(--c-accent); }
.icon--star { width: 14px; height: 14px; fill: currentColor; stroke: none; color: var(--c-accent); }

.icon-box {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--icon-box-size); height: var(--icon-box-size);
  border-radius: var(--icon-box-radius);
  background: var(--icon-box-bg);
  border: 1px solid var(--icon-box-border);
  color: var(--c-accent);
  flex-shrink: 0;
}

/* ---- Placeholders (§5 du brief) -------------------------------------------- */


/* Photo verticale de la colonne centrale, section « Nos services » de
   l'accueil. Pas d'`aspect-ratio` imposé : elle garde ses proportions propres
   (0,56) plutôt que d'être rognée en haut et en bas pour tenir dans le 3/4 du
   bloc gris qu'elle remplace. */
.flank-shot {
  width: 100%; height: auto;
  border-radius: var(--radius-md);
  background: var(--c-bg-elevated);
}

/* Capture réelle d'une réalisation. Même cadre que le bloc gris qu'elle
   remplace : `object-fit: cover` recadre la capture (19/10) dans le 16/10 de
   la vignette plutôt que de la déformer. */
/* Pas d'`aspect-ratio` imposé ni de recadrage : la vignette prend les
   proportions propres de la capture, et c'est la carte qui s'ajuste. */
/* Plus d'arrondi ici : la vignette et la légende forment désormais un seul
   bloc, et c'est le bouton qui les enveloppe qui porte le rayon. Le joint
   entre les deux reste droit, ce qui les fait lire comme une même carte. */
.work-shot {
  display: block;
  width: 100%; height: auto;
  border-radius: 0;
  background: var(--c-bg-elevated);
}

/* Chaque carte prend la hauteur de son image plutôt que celle de la plus haute
   de la rangée : sans cela, `align-items: stretch` de la piste laisserait un
   vide sous les captures les moins hautes. */
.carousel-track .work-card { align-self: start; }

/* ==========================================================================
   BANDE MENU
   ========================================================================== */
.site-header {
  position: fixed; inset-inline: 0; top: 0; z-index: 100;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--header-pad-y) var(--container-pad);
  /* Aucun bandeau de fond : seuls le logo, la pilule de navigation et le CTA
     portent leur propre surface, comme sur la capture. */
  background: transparent;
  pointer-events: none;
  transition: top var(--dur-med) var(--ease-out-soft);
}
.site-header.is-hidden { top: calc(-1 * var(--header-height) - 20px); }

/* Le bandeau ne capte plus le clic (il est transparent) ; ses enfants si. */
.site-header > *, .site-header .nav { pointer-events: auto; }

.logo { display: flex; align-items: center; z-index: 101; }

/* Logo de marque. Le fichier est détouré (fond transparent) : indispensable,
   la bande menu n'a pas de fond et flotte au-dessus des taches du hero. */
.brand-logo {
  display: block;
  height: var(--logo-height);
  width: auto;
}
.brand-logo--footer { height: var(--logo-height-footer); }

/* Piste de navigation en pilule, reprise de la capture : les liens vivent dans
   un bandeau propre, le lien actif porte sa propre pilule plus claire. */
.nav-list {
  display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1);
  border-radius: var(--radius-pill);
  background: var(--nav-track-bg);
  border: 1px solid var(--nav-track-border);
}
.nav-list a {
  display: block;
  padding: var(--sp-2) var(--sp-6);
  border-radius: var(--radius-pill);
  font-size: var(--nav-size);
  font-weight: var(--nav-weight);
  line-height: var(--nav-lh);
  letter-spacing: var(--nav-ls);
  color: var(--c-text);
  transition: background var(--dur-fast), color var(--dur-fast);
}
/* Au survol, une pilule discrète apparaît derrière le lien — moins marquée
   que celle de la page active, qui reste blanche avec son ombre. Le texte, lui,
   ne change plus de couleur. */
.nav-list a:hover { background: var(--nav-hover-bg); }
.nav-list a[aria-current="page"] {
  background: var(--nav-active-bg);
  box-shadow: var(--nav-active-shadow);
}

.header-actions { display: flex; align-items: center; gap: var(--sp-4); }

.nav-toggle {
  display: none; z-index: 101;
  width: 40px; height: 40px; border-radius: 50%;
  align-items: center; justify-content: center;
  background: var(--c-surface); border: 1px solid var(--c-border);
  color: var(--c-text);
}
.nav-toggle .icon { width: 20px; height: 20px; }

@media (max-width: 1024px) {
  .nav-list a { padding-inline: var(--sp-4); }
}

@media (max-width: 768px) {
  .nav {
    position: fixed; inset: 0; z-index: 100;
    background: var(--c-bg);
    display: flex; align-items: center; justify-content: center;
    transform: translateY(-100%);
    transition: transform .4s var(--ease-inout-soft);
  }
  .nav.is-open { transform: translateY(0); }
  .nav-list { flex-direction: column; gap: var(--sp-4); padding: 0; background: none; border: 0; }
  .nav-list a { font-size: var(--fs-xl); }
  /* Le bouton du menu est le SEUL accès aux autres pages en mobile : il doit
     se voir PARTOUT. Les deux surfaces essayées avant échouaient chacune sur
     une partie du site : la pastille translucide disparaissait sur le dégradé
     bleu du hero, la pastille blanche sur les sections blanches — et elles
     sont la majorité — où il ne restait que les trois barres de l'icône
     posées sur le texte de la page.
     On lui donne donc la surface pleine du bouton d'appel à l'action : bleu
     sur blanc, sur gris clair, sur les taches du hero comme sur le pied de
     page sombre, le contraste tient dans tous les cas. */
  .nav-toggle {
    display: inline-flex;
    background: var(--btn-solid-bg);
    border-color: var(--btn-solid-border);
    color: var(--btn-solid-text);
    box-shadow: var(--btn-solid-shadow);
  }

  /* Le bandeau s'escamote de nouveau en descendant et revient en remontant,
     comme sur grand écran. Le garde-fou qui le clouait à l'écran n'a plus lieu
     d'être : le bouton du menu est désormais bleu plein, on le retrouve d'un
     coup d'œil dès qu'il réapparaît. */
  /* Sélecteur volontairement plus spécifique que `.btn { display: inline-flex }`,
     défini plus bas dans la feuille. */
  .site-header .header-cta { display: none; }
}

/* ==========================================================================
   BOUTONS
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--btn-gap);
  font-size: var(--btn-size);
  font-weight: var(--btn-weight);
  line-height: var(--btn-lh);
  letter-spacing: var(--btn-ls);
  text-transform: var(--btn-case);
  white-space: nowrap;
  border-radius: var(--btn-radius);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border: 1px solid transparent;
  transition: transform var(--dur-fast) var(--ease-out-soft),
              background var(--dur-fast), color var(--dur-fast),
              border-color var(--dur-fast), box-shadow var(--dur-fast);
}

.btn--solid {
  background: var(--btn-solid-bg);
  color: var(--btn-solid-text);
  border-color: var(--btn-solid-border);
  box-shadow: var(--btn-solid-shadow);
}
.btn--solid:hover {
  background: var(--btn-solid-bg-hover);
  color: var(--btn-solid-text-hover);
}

.btn--outline {
  background: var(--btn-outline-bg);
  color: var(--btn-outline-text);
  border-color: var(--btn-outline-border);
  padding: var(--btn-outline-pad-y) var(--btn-outline-pad-x);
}
.btn--outline:hover {
  border-color: var(--btn-outline-border-hover);
  color: var(--btn-outline-text-hover);
}

/* Le CTA du menu reprend exactement le bouton plein du hero, sans la pastille. */
.btn--nav {
  background: var(--btn-solid-bg);
  color: var(--btn-solid-text);
  border-color: var(--btn-solid-border);
  box-shadow: var(--btn-solid-shadow);
  padding: var(--btn-nav-pad-y) var(--sp-6);
}
.btn--nav:hover {
  background: var(--btn-solid-bg-hover);
  color: var(--btn-solid-text-hover);
}

/* Bouton à pastille ronde (hero) */
.btn--with-circle { padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-6); }
.btn-circle {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--btn-circle-size); height: var(--btn-circle-size);
  border-radius: 50%;
  background: var(--btn-circle-bg);
  color: var(--btn-circle-text);
  flex-shrink: 0;
}
.btn-circle .icon { width: 16px; height: 16px; }
/* Pastille sur fond blanc, flèche sombre. */
.btn-circle--white {
  background: var(--c-bg);
  color: var(--c-text);
}

/* ==========================================================================
   ACCUEIL — S1 : HERO
   L'image de fond de la capture est remplacée par un fond blanc uni : le texte,
   blanc sur la photo d'origine, passe donc en couleur de texte standard.
   ========================================================================== */
.hero {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; justify-content: flex-end;
  /* `100vh` d'abord, `100svh` ensuite — comme `.svc-hero` : là où `svh`
     manque, la première déclaration tient encore. Seule, `100svh` était
     rejetée en bloc et le hero perdait toute hauteur minimale. */
  min-height: 100vh;
  min-height: 100svh;
  padding-top: calc(var(--header-height) + var(--sp-8));
  background: var(--c-bg);
  overflow: hidden;
}
.hero-inner {
  width: 100%; max-width: var(--container-max);
  margin-inline: auto;
  /* La colonne de texte est ramenée vers la gauche : seule la marge GAUCHE
     est réduite, les écarts entre titre, sous-titre, bouton et cases ne
     bougent pas. La marge droite reste celle du conteneur, donc la démo
     d'audit garde sa position. */
  padding: 0 var(--container-pad) var(--sp-24) var(--hero-pad-left);
  display: grid; gap: var(--sp-12);
  align-items: center;
}
.hero-main { display: grid; gap: var(--sp-12); min-width: 0; }
@media (min-width: 1024px) {
  .hero-inner { grid-template-columns: minmax(0, 1fr) minmax(0, 560px); gap: var(--sp-16); }
}
/* Un peu d'air au-dessus de l'eyebrow : il descend, et le bloc avec lui. */
.hero-lead .eyebrow { margin-top: var(--sp-8); }
.hero-title {
  max-width: 780px;
  font-size: var(--hero-size);
  line-height: var(--h1-lh);
  letter-spacing: var(--hero-ls);
  color: var(--c-text);
}
.hero-subtitle {
  max-width: 46ch; margin-top: var(--sp-4);
  font-size: var(--lead-size);
  color: var(--c-text-muted);
}
/* La note d'avis est passée DANS cette ligne, à droite du bouton :
   `align-items: center` les met sur la même ligne de base optique. */
.hero-cta-row { margin-top: var(--sp-8); display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-6); }
/* La note n'était mise en forme qu'en mobile ; elle est désormais visible
   partout, il lui faut donc sa règle de base. */
.hero-rating {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-2xs); color: var(--c-text-muted);
}
.hero-rating .stars { display: inline-flex; color: var(--c-accent); }
.hero-rating strong { color: var(--c-text); font-weight: var(--fw-semibold); }

.hero-bottom {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-6); flex-wrap: wrap;
}
.hero-bottom > * { min-width: 0; }


/* Les trois cases tiennent sur une seule ligne. */
.hero-services {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-3);
}
.hero-services .hero-chip { flex: 0 0 auto; }
.hero-chip {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface);
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  color: var(--c-text);
  transition: transform var(--dur-fast) var(--ease-out-soft), border-color var(--dur-fast);
}
.hero-chip:hover { transform: translateY(-4px); border-color: var(--c-hover-border); }

.hero-readmore {
  position: absolute; left: 50%; bottom: var(--sp-8);
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  color: var(--c-text-faint);
}
.scroll-line { width: 1px; height: 28px; background: var(--c-border); overflow: hidden; }

/* --- Écrans larges mais COURTS (portables 13-14 pouces) -------------------
   Un 1366 × 768 laisse environ 625 px utiles une fois le navigateur et la
   barre des tâches déduits ; à l'échelle Windows 125 %, il n'en reste que
   590. Avec les espacements du grand écran, le hero mesurait 869 px : les
   deux boutons finissaient à 707 px et les trois jauges du simulateur entre
   624 et 701 px — donc hors de l'écran. Le visiteur arrivait sur une page
   sans action visible ni démonstration.

   Seuls les ESPACEMENTS et la fenêtre du simulateur sont resserrés. Aucune
   taille de police n'est touchée : le titre occupe 333 px à lui seul et reste
   tel quel, si bien que le hero dépasse encore un peu la ligne de flottaison
   — mais tout ce qui est actionnable, lui, tient dans l'écran.

   `min-width: 768px` protège le mobile, qui remplit lui aussi `max-height`. */
@media (min-width: 768px) and (max-height: 760px) {
  .hero { padding-top: calc(var(--header-height) + var(--sp-2)); }
  .hero-inner { padding-bottom: var(--sp-8); }
  .hero-main { gap: var(--sp-6); }
  .hero-lead .eyebrow { margin-top: 0; }
  .hero-subtitle { margin-top: var(--sp-2); }
  .hero-cta-row { margin-top: var(--sp-4); }
}

/* La colonne de droite est ramenée de 560 à 440 px, et l'écart entre colonnes
   de 64 à 32. Ce n'est pas un détail d'esthétique : à 1093 px de large — un
   1366 à l'échelle Windows 125 % — la colonne de texte tombait à 400 px et le
   titre s'étalait alors sur 409 px de haut au lieu de 333, ce qui repoussait
   les boutons à 784 px. Rendre 152 px à la colonne de texte lui fait gagner
   des lignes sans toucher au corps du titre. */
@media (min-width: 1024px) and (max-height: 760px) {
  .hero-inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 440px);
    gap: var(--sp-8);
  }
}

/* Second palier, pour les écrans vraiment courts : un 1366 × 768 à l'échelle
   Windows 125 % ne laisse que 590 px, un netbook 600. Le premier palier y
   ramenait déjà les boutons dans l'écran, mais les jauges restaient 35 px trop
   bas. On resserre encore le retrait haut et la fenêtre de démonstration. */
@media (min-width: 768px) and (max-height: 620px) {
  .hero { padding-top: var(--header-height); }
  .hero-inner { padding-bottom: var(--sp-6); }
}

.scroll-line span {
  display: block; width: 100%; height: 50%;
  background: var(--c-accent);
  animation: scrollLine 1.8s var(--ease-inout-soft) infinite;
}
@keyframes scrollLine { from { transform: translateY(-100%); } to { transform: translateY(200%); } }

@media (max-width: 768px) {
  .hero-inner { padding-bottom: var(--sp-24); gap: var(--sp-8); }
  .hero-title { font-size: var(--fs-2xl); line-height: var(--h2-lh); }
  .hero-subtitle { font-size: var(--fs-sm); }
  .hero-cta-row .btn { width: 100%; justify-content: space-between; }
  .hero-bottom { flex-direction: column; align-items: flex-start; }
  .hero-services { width: 100%; }
}
@media (max-width: 480px) {
  .hero-services .hero-chip { flex: 1 1 100%; text-align: center; }
  .hero-readmore { bottom: var(--sp-4); }
}
@media (prefers-reduced-motion: reduce) {
  .scroll-line span { animation: none; }
}

/* ==========================================================================
   ACCUEIL — S2 : BANDE DÉFILANTE
   Boucle infinie, jamais interrompue (y compris au survol).
   ========================================================================== */
.marquee-section {
  padding-block: var(--sp-6);
  border-block: 1px solid var(--c-border);
  background: var(--c-bg-panel);
}
/* Fondu blanc à gauche et à droite, identique au bandeau de certifications. */
.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--mask-opaque) 8%, var(--mask-opaque) 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, var(--mask-opaque) 8%, var(--mask-opaque) 92%, transparent);
}
.marquee-track {
  display: flex; width: max-content;
  animation: marquee var(--marquee-duration) linear infinite;
  will-change: transform;
}
/* La piste contient N groupes identiques ; translater de -100 %/N revient à
   décaler d'exactement une largeur de groupe, donc le raccord est invisible.
   N est calculé par main.js : avec seulement deux groupes, si un groupe est
   plus étroit que l'écran, la fin de la piste entre dans le cadre et la bande
   défile à vide. La distance parcourue reste une largeur de groupe quel que
   soit N, la vitesse ne change donc pas. */
@keyframes marquee { to { transform: translateX(calc(-100% / var(--marquee-groups, 2))); } }

.marquee-group { display: flex; align-items: center; gap: var(--sp-8); padding-right: var(--sp-8); }
.marquee-item {
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  color: var(--c-text); white-space: nowrap;
}
.marquee-sep { width: 14px; height: 14px; color: var(--c-accent); fill: currentColor; stroke: none; }

/* Le mouvement ne s'arrête jamais (consigne §7). Sous prefers-reduced-motion il
   est fortement ralenti plutôt que stoppé. */
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation-duration: calc(var(--marquee-duration) * 4); }
}

/* Bandeau de certifications (S8) — même mécanique, dégradé sur les bords */
.certs { margin-top: var(--sp-16); }
.certs .marquee-group { gap: var(--sp-16); padding-right: var(--sp-16); }
.marquee-track--slow { animation-duration: calc(var(--marquee-duration) * .7); }
.cert-item {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-md); font-weight: var(--fw-bold);
  color: var(--c-text-faint); white-space: nowrap;
}
.cert-item .icon { width: 20px; height: 20px; }

/* ==========================================================================
   ACCUEIL — S3 : BANDEAU DE RÉASSURANCE
   ========================================================================== */


.stars { display: inline-flex; gap: 2px; }
/* --- Notes cliquables vers la fiche Google -------------------------------
   Les rangees d'etoiles et les notes « sur 5 » menent aux avis Google. Au
   repos le lien ne se voit pas : ces blocs sont avant tout des chiffres, un
   soulignement les alourdirait. Il reagit au survol, et le contour de focus
   general s'applique au clavier.
   `.stars` etant deja en `inline-flex`, une rangee d'etoiles devenue <a>
   garde exactement la meme mise en page. */
.avis-lien {
  color: inherit;
  text-decoration: none;
  transition: opacity var(--dur-fast);
}
.avis-lien:hover { opacity: .72; }
/* Le hero aligne etoiles et note par un flex a deux enfants : le lien qui les
   enveloppe reprend cet alignement, sinon l'ecart entre eux disparait. */
.hero-rating .avis-lien { display: inline-flex; align-items: center; gap: var(--sp-2); }
/* Le bloc de score est une boite : le lien doit rester en bloc pour garder sa
   place d'element flex dans `.reviews-summary`. */
.reviews-score.avis-lien { display: block; }


/* ==========================================================================
   ACCUEIL — S4 : NOS SERVICES
   ========================================================================== */
/* Le titre respire davantage que dans les autres sections : les six blocs qui
   suivent sont denses (titre + check-liste), un écart standard les collait au
   chapeau de section. */
#accueil-s4 .section-head { margin-bottom: var(--sp-24); }
@media (max-width: 768px) { #accueil-s4 .section-head { margin-bottom: var(--sp-16); } }


/* --- Fond bleu et grand arc ----------------------------------------------
   L'arc est le `border-radius` de la section : deux rayons horizontaux de
   50 % qui se rejoignent au milieu forment une seule coupole, lisse au
   sommet. Leur somme fait 100 % pile, le navigateur ne les reduit pas. Une
   bande posee au-dessus en position absolue aurait du depasser la largeur de
   l'ecran pour rester franche, et aurait cree une barre de defilement
   horizontale ; un `border-radius` ne sort jamais de sa boite.

   Le fond est un degrade et non un aplat : le bleu tient le haut, et le bas
   rejoint exactement `--c-bg-panel`, la couleur du Simulateur qui suit. Le
   raccord entre les deux sections est donc invisible. Le remplissage bas
   reprend la hauteur du fondu, pour qu'aucun texte ne tombe dans la zone qui
   s'eclaircit : du blanc y deviendrait illisible.

   Rien n'est recolorie regle par regle : la section repointe ses JETONS, et
   chaque composant lit simplement d'autres valeurs avec sa regle d'origine.
   Contrastes sur #2558D6 : blanc 6,1:1, #E0E8F9 4,96:1 pour le secondaire,
   et le bouton inverse 6,1:1. */
#accueil-s4 {
  --eyebrow-color:        var(--c-text-on-accent);
  --c-text:               var(--c-text-on-accent);
  --c-text-muted:         #E0E8F9;
  --c-text-faint:         #E0E8F9;
  --c-accent:             var(--c-text-on-accent);
  --icon-box-bg:          rgba(255, 255, 255, .14);
  --icon-box-border:      rgba(255, 255, 255, .30);
  --btn-solid-bg:         #FFFFFF;
  --btn-solid-text:       var(--c-accent-deep);
  --btn-solid-border:     transparent;
  --btn-solid-shadow:     none;
  --btn-solid-bg-hover:   #E0E8F9;
  --btn-solid-text-hover: var(--c-accent-deep);

  color: var(--c-text-on-accent);
  background: linear-gradient(to bottom,
      var(--c-accent-deep) 0,
      var(--c-accent-deep) calc(100% - var(--fondu-services)),
      var(--c-bg-panel) 100%);
  /* Le haut de la section est droit : la courbe est dessinee par les trois
     cercles poses juste au-dessus, dans la marge qui leur est reservee.
     L’ancien `border-radius` dessinait deux quarts d’ELLIPSE — 720 px de
     rayon horizontal pour 110 de rayon vertical a 1440, un aplatissement
     de 6,5 pour 1 — et cela se voyait. */
  position: relative;
  margin-top: var(--arc-zone);
  /* Retrait haut resserre une seconde fois, a la demande : le surtitre vient
     presque toucher le creux de l’arc. Le haut de la section est PLEIN, c’est
     elle qui peint son propre fond ; les trois bandes claires sont au-dessus,
     dans la marge reservee. Le contraste y est mesure, pas suppose. */
  padding-top: var(--sp-2);
  /* Le retrait bas reprend la hauteur du fondu EN PLUS des 32 px voulus ici :
     sans cette reserve, le dernier element tomberait dans la zone qui
     s’eclaircit et le blanc y deviendrait illisible (mesure la derniere fois a
     1,65:1 sur le bouton « En savoir plus »). Le vide du bas tombe a 32 + 80
     en mobile et 32 + 144 a 1440, contre 32 + 120 et 96 + 259 avant. */
  padding-bottom: calc(var(--sp-8) + var(--fondu-services));
}
@media (min-width: 768px) {
  #accueil-s4 {
    padding-top: var(--sp-6);
    padding-bottom: calc(var(--sp-8) + var(--fondu-services));
  }
}

/* --- Les trois arcs de cercle ---------------------------------------------
   Une bande posee juste au-dessus de la section, dans la marge reservee par
   `margin-top`. Elle ne mord pas sur la section des realisations : sinon les
   arcs passeraient devant le bouton « Voir tout le Portfolio ».
   `overflow: hidden` fait deux choses : il ne garde des cercles que leur
   calotte, et il empeche des elements larges de trois ecrans de creer une
   barre de defilement horizontale.
   Elle descend 1 px plus bas que la ligne geometrique : a la hauteur exacte,
   le cercle bleu TOUCHE les deux coins du bas sans les depasser, ce qui
   laisserait un cheveu de blanc. */
.arc-services {
  position: absolute;
  left: 0; right: 0;
  bottom: calc(100% - 1px);
  height: calc(var(--arc-zone) + 1px);
  overflow: hidden;
  pointer-events: none;
}
/* `aspect-ratio: 1` avec `border-radius: 50 %` : un cercle PARFAIT, quelle
   que soit la largeur. C’est tout l’interet par rapport a un rayon de boite,
   qui suit les proportions de la boite et donne une ellipse. */
.arc-cercle {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  aspect-ratio: 1;
  border-radius: 50%;
}
/* Concentriques : chaque cercle gagne une epaisseur de rayon et descend
   d’autant moins, si bien que les trois centres tombent au meme point,
   a 2 epaisseurs + un demi-diametre du haut de la bande. */
.arc-cercle--1 {
  width: var(--arc-diametre);
  top: calc(var(--arc-epaisseur) * 2);
  background: var(--c-accent-deep);
}
.arc-cercle--2 {
  width: calc(var(--arc-diametre) + var(--arc-epaisseur) * 2);
  top: var(--arc-epaisseur);
  background: var(--arc-moyen);
}
.arc-cercle--3 {
  width: calc(var(--arc-diametre) + var(--arc-epaisseur) * 4);
  top: 0;
  background: var(--arc-pale);
}
/* La pastille du bouton etait blanche a fleche sombre, sur un bouton bleu.
   Le bouton etant devenu blanc, elle s'inverse a son tour : sans cela, blanc
   sur blanc, elle disparaissait. */
#accueil-s4 .btn-circle--white {
  background: var(--c-accent-deep);
  color: var(--c-text-on-accent);
}
/* L'image du bloc reste sur le bleu : un liseré clair la detache du fond. */
#accueil-s4 .flank-shot { border: 1px solid rgba(255, 255, 255, .22); }
.flank { display: grid; gap: var(--sp-12); }
.benefit h3 { margin-top: var(--sp-4); margin-bottom: var(--sp-2); }
.benefit p { font-size: var(--fs-xs); }

@media (min-width: 768px) and (max-width: 1023px) {
  .flank { grid-template-columns: 1fr 1fr; }
  .flank-media { grid-column: span 2; max-width: 253px; margin-inline: auto; order: -1; }
}

/* Trois lignes explicites : le bloc 1 partage sa ligne avec le bloc 4, le 2
   avec le 5, le 3 avec le 6. Les colonnes ne sont plus des conteneurs séparés
   — sinon chacune empile ses blocs à sa propre cadence et les check-listes,
   de longueurs différentes, désalignent tout. */
/* En grille, le conteneur des six blocs s'efface : ses enfants redeviennent
   des éléments de la grille et gardent leur placement explicite. */
.flank-stack { display: contents; }

@media (min-width: 1024px) {
  .flank {
    /* 253 px et non 380 : la colonne centrale — donc la photo — perd un
       tiers de sa largeur, et ce tiers revient aux deux colonnes de blocs. */
    grid-template-columns: 1fr minmax(0, 253px) 1fr;
    /* Deux rangées, pas trois : la section compte quatre blocs, deux par
       colonne. Le découpage en trois rangées datait des six blocs d'origine —
       il envoyait le 3e bloc sous les deux premiers, à GAUCHE, et laissait le
       4e seul en haut à droite. */
    grid-template-rows: repeat(2, auto);
    column-gap: var(--sp-16);
    row-gap: var(--sp-12);
    align-items: start;
  }
  .flank-media { grid-column: 2; grid-row: 1 / -1; align-self: center; }
  .flank .benefit:nth-of-type(1) { grid-column: 1; grid-row: 1; }
  .flank .benefit:nth-of-type(2) { grid-column: 1; grid-row: 2; }
  .flank .benefit:nth-of-type(3) { grid-column: 3; grid-row: 1; }
  .flank .benefit:nth-of-type(4) { grid-column: 3; grid-row: 2; }
}

/* ==========================================================================
   ACCUEIL — S5 : NOS RÉALISATIONS (carrousel)
   ========================================================================== */
.carousel { position: relative; }
/* Le portfolio presente deux series a la suite. La seconde est espacee de
   la premiere ; sans cela les deux pistes se touchent et on ne voit plus
   ou l'une finit et l'autre commence. */
.carousel--suite { margin-top: var(--sp-12); }
/* Le rognage horizontal est indispensable : c'est lui qui cache les
   diapositives voisines. Mais il rognait aussi en hauteur, et la carte
   agrandie de 2 % au survol se retrouvait coupée en haut et en bas. On ouvre
   la marge intérieure de quoi la laisser grandir — plus l'anneau bleu et un
   peu de l'ombre portée — et on annule ce supplément par une marge négative,
   pour que le rythme vertical de la section reste identique. */
.carousel-viewport {
  overflow: hidden;
  padding-block: var(--sp-4);
  margin-block: calc(var(--sp-4) * -1);
}
.carousel-track {
  display: flex; align-items: stretch;
  gap: var(--sp-6);
  transition: transform var(--dur-carousel) var(--ease-out-soft);
  will-change: transform;
}
.work-card {
  position: relative;
  flex: 0 0 auto;
  width: min(88vw, 760px);
  transition: opacity var(--dur-med) var(--ease-out-soft),
              transform var(--dur-med) var(--ease-out-soft),
              filter var(--dur-med) var(--ease-out-soft);
}
/* Les diapositives autres que l'active sont assombries et réduites… */
.work-card[aria-hidden="true"] {
  opacity: .35;
  transform: scale(.92);
}
/* …mais seules les deux voisines immédiates sont floutées : les douze autres
   sont hors cadre, les flouter revenait à faire re-rastériser douze grandes
   surfaces à chaque déplacement du carrousel. */
.work-card.is-near { filter: blur(7px); }

/* Toute la carte ouvre la réalisation : c'est un bouton, pas une image
   surmontée d'un bouton. La flèche bleue a disparu, la cible fait toute la
   surface. Le rayon et le rognage sont ici, de sorte que la vignette arrondit
   ses deux angles hauts et la légende ses deux angles bas. */
.work-open {
  display: block; width: 100%;
  margin: 0; padding: 0;
  font: inherit; color: inherit; text-align: left;
  background: var(--c-bg);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out-soft),
              border-color var(--dur-fast);
}
/* Un trait d'un pixel se perd contre une photo en haut et sous du blanc en
   bas : on double la bordure d'un anneau posé juste à l'extérieur, qui suit le
   même rayon et fait donc le tour complet, franchement visible. */
@media (hover: hover) and (pointer: fine) {
  .work-open:hover {
    transform: scale(1.02);
    border-color: var(--c-accent);
    box-shadow: 0 0 0 1px var(--c-accent), var(--shadow-soft);
  }
}
.work-open:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
  .work-open { transition: border-color var(--dur-fast); }
  .work-open:hover { transform: none; }
}

/* `--sp-5` n'existe pas dans le système : la déclaration était invalide et le
   retrait tombait à zéro sur les quatre côtés, le texte collé aux bords du
   bloc blanc. Retraits repris sur des jetons réels, avec plus d'air à gauche
   pour dégager le titre, et en haut comme en bas pour l'aérer de l'image et
   du bord inférieur. */
.work-caption {
  display: flex; flex-direction: column; gap: var(--sp-1);
  padding: var(--sp-6) var(--sp-6) var(--sp-6) var(--sp-8);
  background: var(--c-bg);
  border-top: 1px solid var(--c-border);
}
.work-title { font-size: var(--h3-size); font-weight: var(--h3-weight); letter-spacing: var(--h3-ls); color: var(--c-text); }
.work-sub { font-size: var(--fs-xs); color: var(--c-text-muted); }
/* « (Maquette) » a cote du nom : une precision, pas un second titre. Elle
   reprend donc exactement la taille et la couleur de la ligne d’activite
   qui la suit — aucune valeur nouvelle — et laisse au nom de l’entreprise
   le premier regard. `white-space: nowrap` pour que la parenthese ne se
   coupe jamais en deux lignes. */
.work-maquette {
  font-size: var(--fs-xs); font-weight: var(--fw-regular);
  letter-spacing: normal; color: var(--c-text-muted);
  white-space: nowrap;
}
/* Trois boutons ronds partagent exactement le même dessin et la même
   animation : la flèche du carrousel, la flèche qui ouvre une réalisation et la
   croix qui la referme. Une seule règle pour les trois — dupliquer le dessin
   les aurait laissés diverger à la première retouche.
   L'animation, c'est le passage au bleu clair avec inversion de la couleur du
   trait, sur `--dur-fast`. */
.carousel-arrow,
.viewer-close {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--btn-solid-bg);
  border: 1px solid transparent;
  box-shadow: var(--btn-solid-shadow);
  color: var(--btn-solid-text);
  transition: background var(--dur-fast), color var(--dur-fast);
}
.carousel-arrow:hover,
.viewer-close:hover {
  background: var(--btn-solid-bg-hover);
  color: var(--btn-solid-text-hover);
}

/* Seules les dimensions et le placement diffèrent d'un bouton à l'autre. */
.carousel-arrow {
  position: absolute; top: 50%; z-index: 5;
  transform: translateY(-50%);
  width: var(--carousel-arrow-size); height: var(--carousel-arrow-size);
}
.carousel-arrow .icon { width: 18px; height: 18px; }
/* Flèches ramenées vers le centre de la section. */
.carousel-arrow--prev { left: clamp(var(--sp-4), 8vw, 170px); }
.carousel-arrow--prev .icon { transform: scaleX(-1); }
.carousel-arrow--next { right: clamp(var(--sp-4), 8vw, 170px); }

.carousel-footer { margin-top: var(--sp-12); display: flex; justify-content: center; }

@media (max-width: 768px) {
  /* La légende n'est plus posée sur l'image : `left`, `right` et `bottom`
     n'ont plus d'objet, seul le retrait compte. */
  .work-caption { padding: var(--sp-4) var(--sp-4) var(--sp-4) var(--sp-6); }
  .work-title { font-size: var(--fs-sm); }
  .work-sub { font-size: var(--fs-2xs); }
  /* Le nom descend a 16 px : la mention suit la ligne d’activite a 12. */
  .work-maquette { font-size: var(--fs-2xs); }
  .carousel-arrow { width: 36px; height: 36px; }
  .carousel-arrow--prev { left: var(--sp-2); }
  .carousel-arrow--next { right: var(--sp-2); }
}
@media (prefers-reduced-motion: reduce) {
  .carousel-track { transition: none; }
}

/* ==========================================================================
   ACCUEIL — S6 : SIMULATEUR
   ========================================================================== */
.sim-section { background: var(--c-bg-panel); }
.sim-head { max-width: 720px; margin-bottom: var(--sp-16); }
.sim-title { font-size: var(--h2-size); line-height: var(--h2-lh); letter-spacing: var(--h2-ls); }
.sim-title em { font-style: normal; font-weight: var(--fw-medium); color: var(--c-accent); }
.sim-intro { margin-top: var(--sp-6); max-width: 46ch; }

.sim-grid { display: grid; gap: var(--sp-6); align-items: start; }
@media (min-width: 1024px) { .sim-grid { grid-template-columns: minmax(0, 340px) minmax(0, 1fr); gap: var(--sp-8); } }

.sim-panel {
  /* Élément de grille : sans `min-width: 0`, son contenu le plus large (le
     tableau de la méthode) le fait grossir au-delà de l'écran. */
  min-width: 0;
  padding: var(--card-pad-lg);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-bg);
}
.sim-field + .sim-field { margin-top: var(--sp-8); }
.sim-legend {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-4);
  font-size: var(--eyebrow-size); font-weight: var(--eyebrow-weight);
  letter-spacing: var(--eyebrow-ls); text-transform: var(--eyebrow-case);
  color: var(--c-text-faint);
}
.sim-legend::before { content: ""; width: var(--sp-4); height: 1px; background: currentColor; }

.sim-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.sim-chips--stack { flex-direction: column; align-items: flex-start; }
.sim-chip {
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  background: var(--c-bg);
  font-size: var(--fs-xs); font-weight: var(--fw-medium);
  color: var(--c-text);
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.sim-chip:hover { border-color: var(--c-hover-border); color: var(--c-hover-text); }
.sim-chip.is-active {
  background: var(--c-accent);
  border-color: var(--c-accent);
  color: var(--c-text-on-accent);
}

.sim-label {
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  letter-spacing: var(--eyebrow-ls); text-transform: uppercase;
  color: var(--c-text-faint);
}
.sim-figure {
  display: flex; align-items: baseline; gap: var(--sp-2);
  margin-top: var(--sp-2);
  font-size: var(--fs-3xl); font-weight: var(--fw-bold);
  letter-spacing: var(--h2-ls);
  color: var(--c-accent);
}
.sim-figure-unit { font-size: var(--fs-md); }
.sim-context { margin-top: var(--sp-3); max-width: 46ch; font-size: var(--fs-xs); }

.sim-bar-block { margin-top: var(--sp-8); }
/* Piste et valeur sur une même ligne : le pourcentage reste toujours à
   l'intérieur du cadre, avec une marge à gauche et à droite. */
.sim-bar {
  display: flex; align-items: center; gap: var(--sp-4);
  margin-top: var(--sp-3);
  padding-right: var(--sp-2);
}
.sim-bar-track {
  flex: 1 1 auto; min-width: 0;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--c-bg-elevated);
  overflow: hidden;
}
.sim-bar-fill {
  height: 100%; border-radius: var(--radius-pill);
  background: var(--c-accent);
  transition: width var(--dur-med) var(--ease-out-soft);
}
.sim-bar-fill--hors { width: 5%; }
.sim-bar-fill--top3 { width: 54%; }
.sim-bar-value {
  flex: 0 0 auto;
  min-width: 4ch; text-align: right;
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  color: var(--c-text-muted);
}

.sim-stats {
  display: grid; grid-template-columns: 1fr;
  margin-top: var(--sp-12);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.sim-stat { padding: var(--sp-4) var(--sp-6); border-top: 1px solid var(--c-border); }
.sim-stat:first-child { border-top: none; }
.sim-stat-figure {
  display: block;
  font-size: var(--fs-xl); font-weight: var(--fw-bold);
  letter-spacing: var(--h2-ls); color: var(--c-accent);
}
.sim-stat-label {
  display: block; margin-top: var(--sp-1);
  font-size: var(--fs-2xs); letter-spacing: .06em; text-transform: uppercase;
  color: var(--c-text-faint);
}
@media (min-width: 768px) {
  .sim-stats { grid-template-columns: repeat(3, 1fr); }
  .sim-stat { border-top: none; border-left: 1px solid var(--c-border); }
  .sim-stat:first-child { border-left: none; }
}

.sim-method-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-12); padding-top: var(--sp-6);
  width: 100%; border-top: 1px solid var(--c-border);
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  letter-spacing: var(--eyebrow-ls); text-transform: uppercase;
  color: var(--c-accent);
}
.sim-method-sign { font-size: var(--fs-sm); line-height: 1; }
.sim-method { margin-top: var(--sp-6); }
.sim-method p { font-size: var(--fs-xs); }
.sim-method p + p { margin-top: var(--sp-3); }
.sim-method strong { color: var(--c-text); font-weight: var(--fw-semibold); }
.sim-formula {
  /* Les formules n'ont pas d'espace où se couper : sans cette règle elles
     imposent leur largeur au panneau entier. */
  overflow-wrap: anywhere;
  margin-top: var(--sp-6) !important;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-sm);
  background: var(--c-bg-elevated);
  color: var(--c-text) !important;
  font-size: var(--fs-2xs) !important;
  letter-spacing: .02em;
}
.sim-table-wrap { margin-top: var(--sp-8); overflow-x: auto; min-width: 0; max-width: 100%; }
.sim-assumption { margin-top: var(--sp-6) !important; }
.sim-assumption strong { color: var(--c-accent); font-weight: var(--fw-semibold); }
.sim-table { width: 100%; min-width: 420px; font-size: var(--fs-2xs); }
.sim-table th, .sim-table td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--c-border);
  text-align: right;
}
.sim-table thead th { color: var(--c-text-faint); font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: .06em; }
.sim-table tbody th { text-align: left; font-weight: var(--fw-semibold); color: var(--c-text); }
.sim-table thead th:first-child { text-align: left; }

/* ==========================================================================
   ACCUEIL — S7 : COMPARATIF
   ========================================================================== */


/* Colonne OBT : un seul bloc plein, tous les coins arrondis. Le rayon est posé
   sur la première et la dernière cellule de la colonne. */

/* Fond de la section, plus de bloc noir. */


/* Séparateurs en tirets sur toute la largeur de la ligne, y compris au-dessus
   de la première. Sur la colonne OBT (fond bleu plein) les tirets passent en
   blanc pour rester visibles. */


/* Le tableau et le bouton ont besoin de respirer l'un par rapport à l'autre. */


/* ==========================================================================
   ACCUEIL — S8 : RÉASSURANCE + PREUVES
   ========================================================================== */
.stats-row { display: grid; gap: var(--sp-6); }
@media (min-width: 768px) { .stats-row { grid-template-columns: repeat(3, 1fr); } }

.stat-card {
  padding: var(--card-pad-lg);
  border: 1px solid var(--c-border);
  border-radius: var(--card-radius);
  background: var(--c-surface);
}
.stat-card--accent {
  background: linear-gradient(155deg, var(--c-accent-a08), var(--c-accent-a04));
  border-color: var(--c-accent-a18);
}
.stat-figure { font-size: var(--fs-2xl); font-weight: var(--fw-bold); letter-spacing: var(--h2-ls); color: var(--c-text); line-height: 1.1; }
.stat-label { margin-top: var(--sp-2); font-weight: var(--fw-semibold); color: var(--c-text); }
.stat-card p:last-child { margin-top: var(--sp-3); font-size: var(--fs-xs); }



/* ==========================================================================
   ACCUEIL — S9 : COMMENT ÇA SE PASSE
   ========================================================================== */
.steps-row { display: grid; gap: var(--sp-8); }
@media (min-width: 768px) { .steps-row { grid-template-columns: repeat(2, 1fr); gap: var(--sp-12); } }
@media (min-width: 1024px) { .steps-row { grid-template-columns: repeat(4, 1fr); } }
.step-num {
  display: block; margin-bottom: var(--sp-4);
  font-size: var(--fs-xl); font-weight: var(--fw-bold);
  letter-spacing: var(--h2-ls); color: var(--c-accent);
}
.step h3 { font-size: var(--fs-sm); font-weight: var(--fw-bold); margin-bottom: var(--sp-2); }
.step p { font-size: var(--fs-xs); }

/* ==========================================================================
   ACCUEIL — S10 / SERVICES — S6 : AVIS CLIENTS
   ========================================================================== */
.reviews-summary {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-8);
  padding: var(--card-pad-lg);
  margin-bottom: var(--sp-8);
  border: 1px solid var(--c-border);
  border-radius: var(--card-radius);
  background: var(--c-surface);
}
.reviews-score-figure { font-size: var(--fs-3xl); font-weight: var(--fw-bold); letter-spacing: var(--h2-ls); color: var(--c-text); line-height: 1; }
.reviews-score-count { margin-top: var(--sp-1); font-size: var(--fs-2xs); color: var(--c-text-faint); }
.reviews-score .stars { margin-top: var(--sp-2); }


.review-card {
  display: flex; flex-direction: column; gap: var(--sp-4);
  padding: var(--card-pad);
  border: 1px solid var(--c-border);
  border-radius: var(--card-radius);
  background: var(--c-surface);
}
.review-quote { font-size: var(--fs-xs); color: var(--c-text-muted); flex-grow: 1; }
.review-author { display: flex; align-items: center; gap: var(--sp-3); }
.review-avatar,
.testi-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  /* La couleur vient de l’avis lui-même (attribut `style` de l’avatar) :
     c’est celle que Google attribue à son auteur, elle ne fait pas partie
     du dessin du site. Repli sur l’accent pour tout avatar sans couleur. */
  background: var(--avatar-fond, var(--c-accent));
  color: var(--avatar-encre, var(--c-text-on-accent));
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  flex-shrink: 0;
}
.review-name { display: block; font-size: var(--fs-xs); font-weight: var(--fw-semibold); }
.review-meta { display: block; font-size: var(--fs-2xs); color: var(--c-text-faint); }
.review-verified { color: var(--c-accent); }

/* Avatar qui est une vraie photo et non une lettre generee. Il reprend la
   pastille des autres — meme taille, meme cercle, meme place dans la ligne —
   et seul le remplissage change : `object-fit: cover` remplit le cercle sans
   deformer la photo, quelles que soient ses proportions. Le fond sert le
   temps du chargement, pour que la ligne ne saute pas.
   La photo est servie depuis le site : `img-src 'self' data:` interdit les
   images externes, un lien vers googleusercontent serait bloque sans message,
   et ces adresses tournent regulierement. */
img.review-avatar,
img.avis-avatar,
img.testi-avatar {
  object-fit: cover;
  background: var(--c-bg-elevated);
}

/* --- Bande d'avis defilante (page Services) -------------------------------
   La piste reprend la mecanique des bandes de texte : un groupe duplique par
   main.js jusqu'a couvrir l'ecran, une translation d'exactement une largeur de
   groupe, donc un raccord invisible. Ce qui change ici, c'est le contenu : des
   cartes et non des mots.

   Largeur FIXE sur les cartes. Dans une piste en `width: max-content`, une
   carte sans largeur se reduit a son contenu le plus large : les deux avis,
   l'un d'une ligne et l'autre de six, n'auraient eu ni la meme largeur ni la
   meme hauteur, et le rythme de la bande se serait casse. `flex: none` les
   empeche aussi d'etre compressees quand la piste s'allonge.

   `align-items: stretch` et non `center` : toutes les cartes de la bande font
   la meme hauteur, celle de la plus haute, comme dans une grille.

   La bande se met en PAUSE au survol et quand le clavier entre dedans. Les
   etoiles de chaque carte sont des liens vers la fiche Google : viser un lien
   en mouvement est impraticable. Elle ne s'arrete jamais d'elle-meme, elle
   cede seulement quand quelqu'un tend la main vers une carte. */
.avis-bande .marquee-group { align-items: stretch; gap: var(--sp-6); padding-right: var(--sp-6); }
.avis-bande .review-card {
  flex: none;
  width: min(360px, 78vw);
  background: var(--c-bg);
}
/* `!important` : main.js ecrit `animationPlayState` dans l'attribut `style`
   de chaque bande pour les mettre en pause hors ecran. Une declaration en
   ligne l'emporte sur la feuille, et la pause au survol etait donc ecrasee
   par le « running » que le script venait d'ecrire (mesure : 4,3 px parcourus
   sous le curseur). C'est le cas ou ce mot-clef est legitime : reprendre la
   priorite sur une declaration en ligne posee par un script, sans toucher au
   mecanisme de pause hors ecran qui sert a toutes les bandes du site. */
.avis-bande:hover .marquee-track,
.avis-bande:focus-within .marquee-track { animation-play-state: paused !important; }

/* ==========================================================================
   ACCUEIL — S11 / SERVICES — S7 : CTA
   ========================================================================== */
.cta-banner {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-8);
  padding: var(--sp-16) var(--sp-12);
  border: 1px solid var(--c-border);
  border-radius: var(--card-radius);
  background: linear-gradient(135deg, var(--c-accent-a08), var(--c-accent-a04));
}
.cta-content { max-width: 520px; }
.cta-content h2 { margin-bottom: var(--sp-3); }
@media (max-width: 480px) {
  .cta-banner { padding: var(--sp-8) var(--sp-6); }
  .cta-banner .btn { width: 100%; }
}

/* ==========================================================================
   SERVICES — S1 : HERO
   Formes organiques transposées : orange sur noir (capture) → bleu sur blanc.
   ========================================================================== */
.svc-hero {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; justify-content: center;
  /* Pas tout à fait une hauteur d'écran : le haut de la section suivante
     dépasse sous la ligne de flottaison. */
  min-height: calc(100vh - var(--hero-peek));
  min-height: calc(100svh - var(--hero-peek));
  padding-top: calc(var(--header-height) + var(--sp-8));
  padding-bottom: var(--sp-24);
  background: var(--c-bg);
  overflow: hidden;
}
/* Page Contact : le hero ne porte plus que l'eyebrow et le titre. Lui laisser
   une hauteur d'écran entière ferait descendre le formulaire très bas pour
   rien ; il se cale sur son contenu, avec une marge confortable en dessous. */
#contact-s1.svc-hero {
  min-height: 0;
  padding-bottom: var(--sp-8);
}
/* Le formulaire remonte contre le titre, sans le toucher. */
#contact-s2.section { padding-top: var(--sp-8); }
/* Fondu de bas de hero repris de webild.io : le fond du hero (là-bas une vidéo,
   ici les taches bleues) est masqué par un dégradé vertical, opaque jusqu'à
   60 % puis transparent à 100 %. C'est ce qui fait la transition floue vers la
   section suivante. Valeurs relevées sur `.mask-fade-bottom` de webild.io. */
/* Fondu de bas de hero repris de webild.io : le fond du hero (là-bas une vidéo,
   ici les taches bleues) est masqué par un dégradé vertical, opaque jusqu'à
   60 % puis transparent à 100 %. C'est ce qui fait la transition floue vers la
   section suivante. Valeurs relevées sur `.mask-fade-bottom` de webild.io. */
.blobs {
  position: absolute; inset: 0; z-index: -1; overflow: hidden;
  -webkit-mask-image: linear-gradient(var(--mask-opaque) 0%, var(--mask-opaque) 50%, var(--mask-opaque) 60%, transparent 100%);
  mask-image: linear-gradient(var(--mask-opaque) 0%, var(--mask-opaque) 50%, var(--mask-opaque) 60%, transparent 100%);
}
.blob {
  position: absolute; display: block;
  border-radius: 50%;
  opacity: .55;
  will-change: transform;
  /* Pas de `filter: blur()` : le dégradé radial est déjà doux, et un filtre
     sur une surface de cette taille se recalcule à chaque image. */
  /* Le mouvement tourne en permanence ; main.js accélère la lecture au survol
     du hero via updatePlaybackRate (pas de saut, contrairement à un changement
     d'animation-duration). */
}

/* Six taches réparties sur toute la surface — deux en haut, deux au milieu,
   deux en bas — plutôt que groupées au centre. Amplitudes larges et cadences
   courtes : le fond respire visiblement. */
.blob--1 {
  top: -12%; left: -8%; width: 52%; height: 58%;
  background: var(--blob-bright);
  animation: blobDrift1 8s var(--ease-inout-soft) infinite;
}
.blob--2 {
  top: -10%; right: -10%; width: 50%; height: 56%;
  background: var(--blob-light);
  animation: blobDrift3 6.5s var(--ease-inout-soft) infinite;
}
.blob--3 {
  top: 26%; left: 24%; width: 46%; height: 48%;
  background: var(--blob-deep);
  opacity: .34;
  animation: blobDrift2 9.5s var(--ease-inout-soft) infinite;
}
.blob--4 {
  bottom: -14%; left: -6%; width: 48%; height: 54%;
  background: var(--blob-bright);
  opacity: .34;
  animation: blobDrift2 7.5s var(--ease-inout-soft) infinite reverse;
}
.blob--5 {
  bottom: -16%; right: -8%; width: 50%; height: 56%;
  background: var(--blob-light);
  animation: blobDrift1 10.5s var(--ease-inout-soft) infinite reverse;
}
.blob--6 {
  top: 34%; right: 18%; width: 40%; height: 44%;
  background: var(--blob-bright);
  opacity: .3;
  animation: blobDrift3 8.5s var(--ease-inout-soft) infinite;
}

/* Deux taches à l'échelle de la section entière : elles balayent tout le hero
   d'un bord à l'autre et donnent le mouvement de fond. */
.blob--full-a {
  inset: 0; width: 100%; height: 100%;
  border-radius: 40%;
  background: var(--blob-sweep-a);
  opacity: .3;
  animation: blobSweepA 11s var(--ease-inout-soft) infinite;
}
.blob--full-b {
  inset: 0; width: 100%; height: 100%;
  border-radius: 45%;
  background: var(--blob-sweep-b);
  opacity: .34;
  animation: blobSweepB 13s var(--ease-inout-soft) infinite;
}

@keyframes blobDrift1 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(22%, 16%) scale(1.26); }
}
@keyframes blobDrift2 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(-24%, 19%) scale(1.3); }
}
@keyframes blobDrift3 {
  0%, 100% { transform: translate(0, 0) scale(1.06); }
  50%      { transform: translate(-19%, 22%) scale(.82); }
}
@keyframes blobSweepA {
  0%, 100% { transform: translate(-14%, -8%) scale(1) rotate(0deg); }
  33%      { transform: translate(14%, 10%) scale(1.24) rotate(9deg); }
  66%      { transform: translate(16%, -11%) scale(1.08) rotate(-8deg); }
}
@keyframes blobSweepB {
  0%, 100% { transform: translate(13%, 7%) scale(1.06) rotate(0deg); }
  40%      { transform: translate(-16%, -10%) scale(1.3) rotate(-10deg); }
  75%      { transform: translate(-8%, 15%) scale(.9) rotate(8deg); }
}
@media (prefers-reduced-motion: reduce) {
  .blob { animation: none; }
}

.svc-hero-inner { position: relative; z-index: 1; }
.svc-hero-title {
  max-width: 16ch;
  font-size: var(--hero-size);
  line-height: var(--h1-lh);
  letter-spacing: var(--hero-ls);
  color: var(--c-text);
}
/* Même traitement que le mot bleu du hero d'accueil (`.accent`) : SEULE la
   couleur change. L'italique et la graisse allégée d'origine faisaient un
   deuxième signal en plus du bleu, et les deux titres ne se ressemblaient pas
   d'une page à l'autre. */
.svc-hero-title em { font-style: normal; font-weight: inherit; color: var(--c-accent); }
.svc-hero-sub { max-width: 48ch; margin-top: var(--sp-6); font-size: var(--lead-size); }
.svc-hero-cta { margin-top: var(--sp-8); display: flex; flex-wrap: wrap; gap: var(--sp-4); }

/* --- HEROS CENTRES : Realisations et Services ----------------------------
   Pose page par page et non sur `.svc-hero-inner` : six autres pages
   partagent ce gabarit (Contact, 404, mentions, confidentialite, plan du
   site), et le hero de Contact est volontairement aligne a gauche pour
   repondre au formulaire qui le suit.
   `text-align` suffit pour le surtitre et le titre ; le sous-titre a une
   largeur maximale, il lui faut en plus des marges automatiques, et la rangee
   de boutons est un conteneur flex, il lui faut `justify-content`. */
#realisations-s1 .svc-hero-inner,
#services-s1 .svc-hero-inner { text-align: center; }
/* Le titre a une largeur maximale : `text-align` centre ses lignes dans sa
   boite, il faut des marges automatiques pour centrer la boite elle-meme.
   Sans elles, mesure a 1440 px : titre decale de 464 px vers la gauche. */
#realisations-s1 .svc-hero-title,
#services-s1 .svc-hero-title,
#realisations-s1 .svc-hero-sub,
#services-s1 .svc-hero-sub { margin-inline: auto; }
#realisations-s1 .svc-hero-cta,
#services-s1 .svc-hero-cta { justify-content: center; }
/* Sous-titre de Realisations reduit d'un cran : centre, un chapeau de trois
   lignes en 20 px disputait le regard au titre. */
#realisations-s1 .svc-hero-sub { font-size: var(--fs-sm); }

@media (max-width: 768px) {
  /* Ce titre code sa taille en dur et echappe donc a la surcharge des
     jetons : on l'aligne ici sur la meme valeur. */
  .svc-hero-title { font-size: var(--fs-hero-title-m); line-height: var(--h2-lh); }
  .svc-hero-sub { font-size: var(--fs-sm); }
  .svc-hero-cta .btn { flex: 1 1 100%; }
}

/* ==========================================================================
   SERVICES — S2 : TYPES DE SYSTÈMES (8 cases, 2 lignes de 4)
   ========================================================================== */
/* Remontée sous le hero : le fondu de bas de hero occupe déjà l'espace, le
   padding complet de section creusait un trou. */
#services-s2 { padding-top: var(--sp-8); }
@media (min-width: 768px) { #services-s2 { padding-top: var(--sp-12); } }
/* `grid-auto-rows: 1fr` et non le seul étirement par défaut : sans lui, les
   deux rangées de deux cartes prennent chacune la hauteur de leur propre
   contenu et ne se correspondent pas. */
.systems-grid { display: grid; grid-template-columns: 1fr; gap: var(--sp-6); grid-auto-rows: 1fr; }
@media (min-width: 768px)  { .systems-grid { grid-template-columns: repeat(2, 1fr); } }
/* Deux colonnes, un point c'est tout : la section ne compte plus que quatre
   cartes, soit deux rangées pleines de deux. Trois colonnes auraient laissé
   une carte seule sur la seconde rangée. */


/* ==========================================================================
   SERVICES — S3 : NOTRE MÉTHODE (cartes empilées)
   ========================================================================== */
/* Quatre cartes identiques (même largeur, même hauteur — la hauteur est
   égalisée par main.js sur la plus haute) qui se superposent au défilement :
   chaque carte se colle sous le bandeau menu et la suivante vient la recouvrir
   en restant parfaitement nette (pas de flou, pas d'échelle). */
.stack-list {
  display: block;
  width: 88%;
  margin-inline: auto;
}
/* Le collage est borné par la BOÎTE DE CONTENU du bloc conteneur — un
   `padding-bottom` n'y change rien. Sans cette réserve en flux, la dernière
   carte atteint sa position collée à l'instant précis où la pile est libérée :
   elle recouvre la précédente sans jamais s'y arrêter. Le pseudo-élément, lui,
   allonge réellement le contenu et donne à la pile son temps de pause. */
.stack-list::after {
  content: "";
  display: block;
  height: var(--sp-32);
}
.stack-card {
  position: sticky;
  top: var(--stack-top, 0px);
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-6);
  align-items: start;
  padding: var(--card-pad-lg);
  border: 1px solid var(--c-border);
  border-radius: var(--card-radius);
  /* Fond opaque obligatoire : c'est lui qui masque la carte du dessous. */
  background: var(--c-bg-elevated);
  margin-bottom: var(--sp-6);
}
/* La dernière carte GARDE sa marge basse. Le collage est borné par la boîte de
   marge : sans cette marge, la dernière carte s'arrête 24 px plus bas que les
   autres au moment où la pile se libère, et ne recouvre plus exactement la
   carte 03. */
/* Toutes les cartes se collent au MÊME niveau : la suivante recouvre donc
   entièrement la précédente, sans laisser dépasser son bord haut. */
.stack-list .stack-card { --stack-top: calc(var(--header-height) + var(--sp-6)); }
.stack-list .stack-card:nth-child(1) { z-index: 1; }
.stack-list .stack-card:nth-child(2) { z-index: 2; }
.stack-list .stack-card:nth-child(3) { z-index: 3; }
.stack-list .stack-card:nth-child(4) { z-index: 4; }
.stack-list .stack-card:nth-child(5) { z-index: 5; }
.stack-list .stack-card:nth-child(6) { z-index: 6; }
/* Ombre portée : c'est elle qui donne à voir qu'une carte passe par-dessus
   une autre, maintenant qu'aucun décalage ne les distingue. */
.stack-card { box-shadow: var(--shadow-soft); }
.stack-index {
  display: block; margin-bottom: var(--sp-1);
  font-size: var(--fs-2xs); font-weight: var(--fw-bold);
  letter-spacing: .08em; color: var(--c-text-faint);
}
.stack-card p { margin-top: var(--sp-2); font-size: var(--fs-xs); }
/* Sous-titre de l'étape : même taille que le corps, mais appuyé — il annonce
   l'étape, il ne la raconte pas. */
.stack-lead { font-weight: var(--fw-semibold); color: var(--c-text); }
/* Puces en tirets, comme le tableau comparatif : la liste reste alignée sur le
   texte, le tiret déborde dans la marge. */
.stack-points {
  display: flex; flex-direction: column; gap: var(--sp-1);
  margin-top: var(--sp-3); padding-left: var(--sp-4);
}
.stack-points li { position: relative; font-size: var(--fs-xs); color: var(--c-text-muted); }
.stack-points li::before {
  content: "—"; position: absolute; left: calc(var(--sp-4) * -1);
  color: var(--c-accent);
}
.stack-goal { color: var(--c-text); }
.stack-goal strong { color: var(--c-accent); font-weight: var(--fw-semibold); }

@media (max-width: 768px) {
  .stack-list { width: 100%; }
  /* Les cartes se figent plus haut qu'en grand écran : 80 px au lieu de 112.
     La carte 01 monte donc plus près du bandeau, et il faut défiler 32 px de
     plus pour l'y amener — l'empilement démarre d'autant plus tard. On reste
     sous les surfaces opaques du menu, qui s'arrêtent à 71 px. */
  .stack-list .stack-card { --stack-top: calc(var(--header-height) - var(--sp-2)); }
}
@media (max-width: 480px) {
  .stack-card { grid-template-columns: 1fr; gap: var(--sp-4); padding: var(--card-pad); }
}

/* ==========================================================================
   SERVICES — S4 : INCLUS (timeline)
   ========================================================================== */
.timeline { display: flex; flex-direction: column; gap: var(--sp-8); }
.timeline-item { position: relative; display: grid; grid-template-columns: auto 1fr; gap: var(--sp-6); align-items: start; }
.timeline-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; border-radius: 50%;
  border: 1px solid var(--c-border);
  background: var(--c-surface);
  color: var(--c-text);
  flex-shrink: 0;
}
/* Filet reliant les pastilles */
.timeline-item:not(:last-child)::before {
  content: "";
  position: absolute; left: 28px; top: 56px;
  width: 1px; height: calc(100% + var(--sp-8) - 56px);
  background: var(--c-border);
}
.timeline-item h3 { margin-bottom: var(--sp-2); }
.timeline-item p { font-size: var(--fs-xs); max-width: 70ch; }

/* ==========================================================================
   PAGES LÉGALES — mentions légales, confidentialité
   Une colonne de texte suivi, à largeur de lecture. Aucune couleur ni taille
   nouvelle : tout vient des jetons déjà en place.
   ========================================================================== */
.legal-prose { max-width: 78ch; }
.legal-prose h2 {
  margin-top: var(--sp-12);
  font-size: var(--h3-size);
  letter-spacing: var(--h3-ls);
}
.legal-prose h2:first-child { margin-top: 0; }
.legal-prose p { margin-top: var(--sp-4); font-size: var(--fs-sm); color: var(--c-text-muted); }
.legal-prose a { color: var(--c-accent); text-decoration: underline; text-underline-offset: 3px; }
.legal-liste { margin-top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.legal-liste li { font-size: var(--fs-sm); color: var(--c-text-muted); }
.legal-liste strong { color: var(--c-text); font-weight: var(--fw-semibold); }
/* Ce qui manque encore pour publier : `--c-alert` est le jeton du défaut
   signalé, il rend ces trous impossibles à rater à la relecture. */

.legal-maj { margin-top: var(--sp-12); font-size: var(--fs-2xs); color: var(--c-text-faint); }

/* Plan du site : ce n'est pas du texte suivi, la colonne de lecture de 78ch
   n'a pas lieu d'être. Les blocs se rangent en colonnes dès qu'il y a la
   place. */
.plan-grid { display: grid; gap: var(--sp-12); }
@media (min-width: 768px)  { .plan-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .plan-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.plan-bloc h2 { font-size: var(--h3-size); letter-spacing: var(--h3-ls); }
.plan-bloc h2 a { color: inherit; text-decoration: none; }
.plan-bloc h2 a:hover { color: var(--c-accent); }
.plan-chapeau { margin-top: var(--sp-2); font-size: var(--fs-2xs); color: var(--c-text-faint); }
.plan-liste { margin-top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.plan-liste a {
  font-size: var(--fs-sm); color: var(--c-text-muted);
  text-decoration: underline; text-underline-offset: 3px;
  transition: color var(--dur-fast);
}
.plan-liste a:hover { color: var(--c-accent); }

/* ==========================================================================
   BAS DE PAGE
   ========================================================================== */
.site-footer {
  background: var(--c-bg-panel);
  border-top: 1px solid var(--footer-border);
  padding-top: var(--footer-pad-top);
  padding-bottom: var(--footer-pad-bottom);
  overflow: hidden;
}
.footer-top {
  display: grid; gap: var(--sp-8);
  padding-bottom: var(--sp-12);
}
@media (min-width: 1024px) {
  .footer-top { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
}
.footer-baseline {
  margin-top: var(--sp-6);
  max-width: 38ch;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
/* Intitulés de colonne : les jetons `--footer-label-*` existaient depuis le
   début du projet sans emploi, ils étaient prévus pour cela. */
.footer-col-title {
  margin-bottom: var(--sp-8);
  font-size: var(--footer-label-size);
  font-weight: var(--footer-label-weight);
  letter-spacing: var(--footer-label-ls);
  text-transform: var(--footer-label-case);
  color: var(--c-accent);
}
.footer-col ul { display: flex; flex-direction: column; gap: var(--sp-4); }
/* --- Reseaux sociaux du pied de page -------------------------------------
   Une rangee d'icones sous la signature de marque. Pas de libelle visible :
   le nom du reseau est porte par l'`aria-label` du lien, pour les lecteurs
   d'ecran. Le glyphe fait 20 px mais la zone cliquable 44 — le minimum
   confortable pour un doigt — d'ou le retrait negatif a gauche, qui ramene le
   premier glyphe a l'aplomb du texte du dessus : 44 - 20, divise par deux,
   vaut exactement les 12 px de `--sp-3`. */
.footer-social {
  display: flex; flex-wrap: wrap;
  gap: var(--sp-1);
  margin-top: var(--sp-4);
  margin-left: calc(var(--sp-3) * -1);
}
.footer-social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  color: var(--c-text);
  transition: color var(--dur-fast);
}
.footer-social a:hover { color: var(--c-hover-text); }
.footer-social .icon { width: 20px; height: 20px; }
.footer-col-plain { color: var(--c-text-muted); }
.footer-col a,
.footer-legal a {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--c-text);
  transition: color var(--dur-fast);
}
.footer-col a:hover,
.footer-legal a:hover { color: var(--c-hover-text); }
/* Chaque lien de la barre basse porte son propre soulignement, et non un trait
   qui courrait sous la suite : ce sont trois destinations distinctes. */
.footer-legal { display: flex; flex-wrap: wrap; gap: var(--sp-8); }
.footer-legal a { text-decoration: underline; text-underline-offset: 3px; }
/* À 375 px, les trois liens plus deux écarts de 32 px font 328 px pour 316 px
   disponibles : le troisième passait seul à la ligne. Vingt-quatre pixels les
   ramènent à 312 px, donc sur une seule ligne, sans rien resserrer ailleurs. */
@media (max-width: 480px) { .footer-legal { gap: var(--sp-6); } }
@media (min-width: 1024px) {
  .footer-legal { justify-content: center; }
}

.footer-bottom {
  display: grid; gap: var(--sp-4);
  padding-top: var(--sp-8);
  border-top: 1px solid var(--footer-border);
  font-size: var(--fs-2xs);
}
.footer-bottom p { color: var(--c-text-faint); }
.footer-bottom a { color: var(--c-text-faint); text-decoration: underline; text-underline-offset: 3px; }
.footer-bottom a:hover { color: var(--c-hover-text); }
.footer-top-link { display: inline-flex; align-items: center; gap: var(--sp-2); text-decoration: none !important; }
.footer-top-link .icon { width: 14px; height: 14px; }
@media (min-width: 768px) {
  .footer-bottom { grid-template-columns: 1fr auto 1fr; align-items: center; }
  .footer-bottom p:nth-child(2) { text-align: center; }
  .footer-bottom p:nth-child(3) { text-align: right; }
}

/* Signature typographique de bas de page.
   La capture est crème sur fond noir : sur fond blanc, la signature passe en
   gris très clair pour rester décorative et ne pas peser comme un titre. */
.footer-wordmark {
  margin-top: var(--sp-12);
  font-size: var(--footer-wordmark-size);
  font-weight: var(--fw-bold);
  line-height: .9;
  letter-spacing: -0.03em;
  text-align: center;
  white-space: nowrap;
  color: var(--c-footer-wordmark);
  user-select: none;
  /* Aucun masque : la signature reste pleinement opaque sur toute sa hauteur.
     Le fondu vers le bas, essayé un temps, éteignait le pied des lettres et
     donnait l'impression d'un mot en arrière-plan. */
}

/* ==========================================================================
   APPARITIONS AU DÉFILEMENT
   Les éléments sont marqués par main.js (liste de sélecteurs) puis révélés par
   un IntersectionObserver. Rien n'est masqué tant que `html.js` n'est pas
   posée : sans JavaScript, la page reste entièrement lisible.
   Deux variantes : translation + fondu par défaut, flou → net pour les titres.
   ========================================================================== */
.js .reveal {
  opacity: 0;
  transform: translateY(var(--reveal-shift));
  transition:
    opacity var(--reveal-dur) var(--ease-out-soft),
    transform var(--reveal-dur) var(--ease-out-soft),
    filter var(--reveal-dur) var(--ease-out-soft);
  transition-delay: calc(var(--reveal-i, 0) * var(--reveal-step));
  /* Pas de `will-change` ici : il promouvrait d'un coup une cinquantaine de
     calques, ce qui coûte plus de mémoire et de composition que le gain
     apporté sur une transition d'opacité déjà accélérée. */
}
/* Titres : le texte arrive flou puis se fixe net. */
.js .reveal--blur {
  filter: blur(var(--reveal-blur));
  transform: translateY(calc(var(--reveal-shift) * .5));
}
.js .reveal.is-visible {
  opacity: 1;
  transform: none;
  filter: none;
}

@media (prefers-reduced-motion: reduce) {
  .js .reveal,
  .js .reveal--blur {
    opacity: 1;
    transform: none;
    filter: none;
    transition: none;
  }
}

/* ==========================================================================
   DÉMO D'AUDIT + REFONTE (hero de l'accueil)
   Structure, timeline et animations reprises du hero d'aimcs.eu (relevées dans
   leur code, pas à l'œil), rhabillées aux tokens OBT : leur ocre `--or` devient
   `--c-accent`, leur crème devient le blanc du site. Les deux seules couleurs
   hors palette de marque sont les signaux d'état `--c-ok` / `--c-alert`.
   ========================================================================== */
.scan-wrap {
  position: relative;
  width: 100%;
  max-width: 560px;
  margin-inline: auto;
}
@media (hover: hover) and (pointer: fine) {
  .scan-wrap { perspective: 1400px; }
  .scan-browser { animation: browserFloat 9s ease-in-out infinite; }
}

.scan-browser {
  position: relative;
  background: var(--c-bg);
  border: 1px solid var(--c-border);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  transform-style: preserve-3d;
  transition: transform .5s var(--ease-out-soft), box-shadow .5s;
}
.scan-browser-bar {
  display: flex; align-items: center; gap: 7px;
  padding: 12px 14px;
  background: var(--c-bg-panel);
  border-bottom: 1px solid var(--c-border);
}
.scan-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.scan-dot--r { background: var(--c-alert); }
.scan-dot--y { background: var(--c-accent-light); }
.scan-dot--g { background: var(--c-ok); }
.scan-url {
  flex: 1; margin-left: 8px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--c-surface-strong);
  border-radius: 6px;
  padding: 6px 12px;
  font-size: var(--fs-2xs);
  color: var(--c-text-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: color .4s, background .4s;
}
.scan-url-lock {
  width: 8px; height: 8px; border-radius: 2px;
  border: 1.4px solid; position: relative; flex: 0 0 auto; opacity: .7;
}
.scan-url-lock::before {
  content: ""; position: absolute; left: 1px; right: 1px; top: -3px; height: 4px;
  border: 1.4px solid currentColor; border-bottom: none;
  border-radius: 3px 3px 0 0;
}
.scan-url-txt { font-variant-numeric: tabular-nums; }
.scan-caret { width: 1px; height: 11px; background: currentColor; opacity: 0; flex: 0 0 auto; }
.scan-browser.is-typing .scan-caret { opacity: 1; animation: scanCaret .7s steps(1) infinite; }
.scan-browser.is-after .scan-url { color: var(--c-accent); background: var(--c-accent-a08); }

.scan-viewport { position: relative; height: 320px; overflow: hidden; }
/* Écrans courts : la fenêtre de démonstration se réduit, et c'est elle qui
   fait remonter les jauges dans l'écran — la colonne de droite est centrée sur
   la gauche, donc tout ce qu'on lui retire la recentre plus haut.
   Ces deux règles doivent rester APRÈS la ligne ci-dessus : à spécificité
   égale, c'est la dernière déclarée qui l'emporte, et placées plus haut dans
   la feuille elles étaient purement et simplement ignorées. */
@media (min-width: 768px) and (max-height: 760px) { .scan-viewport { height: 220px; } }
@media (min-width: 768px) and (max-height: 620px) { .scan-viewport { height: 190px; } }
.scan-before, .scan-after { position: absolute; inset: 0; padding: 25px 27px; }
.scan-before { background: var(--c-bg-elevated); }
.scan-after { background: var(--c-bg); clip-path: inset(0 100% 0 0); }

/* --- l'ancien site --- */
.fb-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 27px; }
.fb-logo { font-weight: var(--fw-bold); font-size: var(--fs-xs); color: var(--c-text-muted); }
.fb-links { display: flex; gap: 7px; }
.fb-links span { width: 27px; height: 7px; background: var(--c-ph-border); display: block; }
.fb-hero { text-align: center; padding: 8px 0; }
.fb-wink { font-size: var(--fs-mock-md); color: var(--c-alert); margin-bottom: 12px; }
.fb-line { background: var(--c-ph-border); margin: 0 auto 8px; border-radius: 2px; }
.fb-line-lg { width: 80%; height: 16px; }
.fb-line-sm { width: 58%; height: 10px; margin-bottom: 22px; }
.fb-btn {
  display: inline-block;
  background: var(--c-alert); color: var(--c-text-on-accent);
  font-size: var(--fs-mock-md); font-weight: var(--fw-bold);
  padding: 10px 25px; border-radius: 2px;
}

/* --- le site refait : hero photographique sombre, d'après la capture ------
   Le fond dégradé tient lieu de photo tant que l'image réelle n'est pas
   fournie. Les dimensions sont en pixels — c'est une maquette à l'échelle,
   pas du contenu de page ; seules les couleurs et les tailles de texte
   viennent des tokens. */
.scan-after {
  background: linear-gradient(118deg,
              var(--c-mock-shot-a) 0%,
              var(--c-mock-shot-b) 52%,
              var(--c-mock-shot-a) 100%);
  clip-path: inset(0 100% 0 0);
  display: flex; flex-direction: column;
  color: var(--c-mock-on-shot);
}

.fa-topbar { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.fa-brand { display: flex; align-items: center; gap: 6px; font-size: var(--fs-mock-sm); font-weight: var(--fw-bold); }
.fa-brand-mark { width: 12px; height: 12px; border-radius: 3px; background: var(--c-mock-brand); flex: 0 0 auto; }
.fa-nav-pill {
  display: flex; align-items: center; gap: 2px;
  padding: 3px; border-radius: var(--radius-pill);
  background: var(--c-mock-glass); border: 1px solid var(--c-mock-glass-edge);
}
.fa-nav-pill span {
  padding: 3px 8px; border-radius: var(--radius-pill);
  font-size: var(--fs-gauge-label); color: var(--c-mock-on-shot-dim); white-space: nowrap;
}
.fa-nav-pill .fa-nav-on { background: var(--c-mock-glass-edge); color: var(--c-mock-on-shot); }
.fa-top-cta {
  padding: 5px 12px; border-radius: var(--radius-pill);
  background: var(--c-mock-brand-deep); color: var(--c-text-on-accent);
  font-size: var(--fs-gauge-label); font-weight: var(--fw-semibold); white-space: nowrap;
}

.fa-body { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; }
.fa-title { font-size: var(--fs-mock-title); font-weight: var(--fw-bold); line-height: 1.14; letter-spacing: var(--h2-ls); }
.fa-sub { margin-top: 7px; max-width: 62%; font-size: var(--fs-mock-xs); line-height: 1.45; color: var(--c-mock-on-shot-dim); }
.fa-cta-main {
  display: inline-flex; align-items: center; gap: 8px; align-self: flex-start;
  margin-top: 13px; padding: 4px 4px 4px 14px;
  border-radius: var(--radius-pill);
  background: var(--c-mock-on-shot); color: var(--c-mock-shot-a);
  font-size: var(--fs-mock-xs); font-weight: var(--fw-semibold); white-space: nowrap;
}
.fa-cta-dot { width: 18px; height: 18px; border-radius: 50%; background: var(--c-mock-brand); flex: 0 0 auto; }

.fa-foot { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); }
.fa-review {
  display: flex; align-items: center; gap: 7px;
  padding: 5px; border-radius: var(--radius-sm);
  background: var(--c-mock-glass); border: 1px solid var(--c-mock-glass-edge);
}
.fa-review-thumb { width: 26px; height: 22px; border-radius: 3px; background: var(--c-mock-glass-edge); flex: 0 0 auto; }
.fa-review-body { display: flex; flex-direction: column; gap: 1px; }
.fa-review-name { font-size: var(--fs-gauge-label); font-weight: var(--fw-semibold); }
.fa-stars { font-size: var(--fs-gauge-label); color: var(--c-mock-brand-light); letter-spacing: .04em; }
.fa-chips { display: grid; grid-template-columns: repeat(2, auto); gap: 5px; justify-content: end; }
.fa-chips span {
  padding: 5px 9px; border-radius: var(--radius-sm);
  background: var(--c-mock-glass); border: 1px solid var(--c-mock-glass-edge);
  font-size: var(--fs-gauge-label); color: var(--c-mock-on-shot); white-space: nowrap;
}

/* --- faisceau d'analyse, étiquettes de défauts, curseur fantôme --- */
.scan-line {
  position: absolute; top: 0; bottom: 0; left: 0; width: 2px; z-index: 3;
  background: linear-gradient(180deg, transparent, var(--c-accent) 15%, var(--c-accent) 85%, transparent);
  box-shadow: 0 0 18px 2px var(--c-accent-bright);
  opacity: 0; pointer-events: none;
}
.scan-tags { position: absolute; inset: 0; pointer-events: none; z-index: 4; }
.scan-tag {
  position: absolute; left: 14px;
  display: flex; align-items: center; gap: 6px;
  background: var(--c-text); color: var(--c-text-on-accent);
  font-size: var(--fs-mock-sm); padding: 5px 10px; border-radius: 4px;
  white-space: nowrap; opacity: 0;
  transform: translateX(-14px) scale(.94);
  transition: opacity .32s var(--ease-out-soft), transform .32s var(--ease-out-soft);
  box-shadow: var(--shadow-soft);
}
.scan-tag::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--c-alert); flex: 0 0 auto; }
.scan-tag.is-shown { opacity: 1; transform: translateX(0) scale(1); }
.scan-tag--right { left: auto; right: 14px; transform: translateX(14px) scale(.94); }
.scan-tag--right.is-shown { transform: translateX(0) scale(1); }

.scan-cursor {
  position: absolute; z-index: 7; left: 0; top: 0;
  width: 16px; height: 22px; pointer-events: none;
  opacity: 0; transition: opacity .35s;
  filter: drop-shadow(var(--shadow-cursor));
}
.scan-cursor.is-shown { opacity: 1; }
.scan-cursor svg { width: 100%; height: 100%; display: block; }
.scan-cursor svg path { fill: var(--c-text); stroke: var(--c-bg); stroke-width: 1.2; stroke-linejoin: round; }
.scan-cursor::after {
  content: ""; position: absolute; left: 2px; top: 2px;
  width: 26px; height: 26px; border-radius: 50%;
  border: 1.5px solid var(--c-accent); opacity: 0; transform: scale(.3);
}
.scan-cursor.is-clicking::after { animation: scanClick .5s ease-out 1; }

/* Reflet qui balaie la fenêtre */
.scan-glass { position: absolute; inset: 0; z-index: 6; pointer-events: none; overflow: hidden; border-radius: 14px; }
.scan-glass::after {
  content: ""; position: absolute; top: -60%; bottom: -60%; width: 38%; left: -50%;
  background: linear-gradient(100deg, transparent, var(--c-sheen), transparent);
  transform: rotate(8deg);
  animation: scanGlass 7.5s ease-in-out infinite;
}

/* --- badge d'état --- */
.scan-status {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  margin-top: 14px;
  font-size: var(--fs-2xs); letter-spacing: .1em; text-transform: uppercase;
  color: var(--c-text-faint);
  transition: color .4s;
}
.ss-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--c-alert); flex: 0 0 auto; position: relative; }
.ss-dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: currentColor; color: var(--c-alert);
  animation: ssPulse 1.6s ease-out infinite; pointer-events: none;
}
.scan-status.is-ok { color: var(--c-accent); }
.scan-status.is-ok .ss-dot { background: var(--c-ok); }
.scan-status.is-ok .ss-dot::after { color: var(--c-ok); }
.ss-txt { transition: opacity .25s; }
.ss-txt.is-swapping { opacity: 0; }

/* --- jauges de score --- */
.scan-scores {
  display: flex; justify-content: center; gap: 26px;
  margin-top: var(--sp-6);
  opacity: .45; transition: opacity .5s;
}
.scan-scores.is-live { opacity: 1; }
.scan-gauge {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  width: 64px;
  transition: transform .45s var(--ease-out-soft);
}
.scan-gauge.is-pop { transform: translateY(-4px); }
.scan-gauge svg { width: 56px; height: 56px; transform: rotate(-90deg); }
.sg-track { fill: none; stroke: var(--c-accent-a12); stroke-width: 5; }
.sg-fill {
  fill: none; stroke: var(--c-accent); stroke-width: 5; stroke-linecap: round;
  stroke-dasharray: 175.9; stroke-dashoffset: 175.9;
  transition: stroke .4s;
}
/* Relevé de l'ancien site : `--c-alert` est le jeton du défaut signalé. */
.scan-gauge.is-alerte .sg-fill { stroke: var(--c-alert); }
.scan-gauge.is-done .sg-fill { stroke: var(--c-ok); }
.sg-val {
  position: absolute; top: 18px; left: 0; right: 0; text-align: center;
  font-weight: var(--fw-bold); font-size: var(--fs-xs); color: var(--c-text);
  font-variant-numeric: tabular-nums;
}
.sg-label { font-size: var(--fs-gauge-label); color: var(--c-text-faint); text-align: center; }

@keyframes scanCaret { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes scanGlass { 0%, 62% { left: -55%; } 88%, 100% { left: 120%; } }
@keyframes scanClick { 0% { opacity: .9; transform: scale(.3); } 100% { opacity: 0; transform: scale(1.5); } }
@keyframes ssPulse { 0% { transform: scale(1); opacity: .55; } 70%, 100% { transform: scale(3.4); opacity: 0; } }
@keyframes browserFloat {
  0%, 100% { transform: translateY(0) rotateX(0deg) rotateY(0deg); }
  50%      { transform: translateY(-10px) rotateX(1.2deg) rotateY(-1.4deg); }
}

@media (max-width: 640px) {
  .scan-wrap { max-width: 340px; }
  .scan-viewport { height: 230px; }
  .scan-scores { gap: 16px; }
  /* Sur mobile la fenêtre reprend l'échelle d'origine. */
  .scan-before, .scan-after { padding: 20px 22px; }
  /* La pilule de navigation ne tient plus dans 290 px de large à côté de la
     marque et du bouton : c'est elle qui saute, pas le reste de la maquette. */
  .fa-nav-pill { display: none; }
  .fa-title { font-size: var(--fs-mock-title-m); }
  /* La fenêtre ne fait plus que 289 px de large pour 190 px de haut utiles :
     le sous-titre saute, sinon la carte d'avis et les étiquettes dépassent du
     cadre de 33 px. La maquette reste lisible — c'est une illustration. */
  .fa-sub { display: none; }
  .fa-cta-main { margin-top: 8px; }
  .fa-foot { flex-direction: column; align-items: flex-start; gap: 5px; }
  .fa-chips { justify-content: start; gap: 4px; }
  .fa-chips span { padding: 4px 8px; }
  /* Le cadre « après » respire moins que le cadre « avant » : il porte une
     composition entière (barre, titre, appel à l'action, avis, étiquettes)
     dans 230 px de haut. Le cadre « avant » garde son retrait d'origine. */
  .scan-after { padding: 14px 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .scan-glass::after, .scan-browser, .ss-dot::after { animation: none; }
  .scan-cursor { display: none; }
}

/* ==========================================================================
   TRANSITION ENTRE LES PAGES
   Fondu court entre l'ancienne et la nouvelle page, là où le navigateur le
   supporte (Chrome, Edge). Ailleurs, navigation classique — rien ne casse.
   ========================================================================== */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: pageOut var(--page-transition-dur) var(--ease-out-soft) both; }
::view-transition-new(root) { animation: pageIn var(--page-transition-dur) var(--ease-out-soft) both; }
@keyframes pageOut { to { opacity: 0; } }
@keyframes pageIn { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ==========================================================================
   TARIFS — S2 : TUNNEL « NOS OFFRES »
   Structure et logique reprises du tunnel d'aimcs.eu (secteur → formule →
   devis), rhabillées aux tokens OBT. Leur passage plein écran entre le choix
   de formule et le récapitulatif a été retiré : la sélection mène directement
   à l'étape suivante, ce qui fait un clic de moins vers le devis.
   ========================================================================== */
.tunnel {
  padding: var(--sp-12);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  background: var(--c-bg-panel);
}
.tunnel-progress {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-12);
  flex-wrap: wrap;
}
.progress-step {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-2xs); letter-spacing: .06em; text-transform: uppercase;
  color: var(--c-text-faint);
  transition: color var(--dur-fast);
}
.progress-step.is-active { color: var(--c-accent); }
.progress-step.is-done { color: var(--c-text-muted); }
.progress-dot {
  width: 8px; height: 8px; border-radius: 50%;
  border: 1px solid var(--c-border-strong); flex-shrink: 0;
  transition: background var(--dur-fast), border-color var(--dur-fast), box-shadow var(--dur-fast);
}
.progress-step.is-active .progress-dot { border-color: var(--c-accent); box-shadow: 0 0 0 3px var(--c-accent-a12); }
.progress-step.is-done .progress-dot { background: var(--c-accent); border-color: var(--c-accent); }
.progress-line { flex: 1 1 0; height: 1px; max-width: 40px; background: var(--c-border); list-style: none; }

.tunnel-step + .tunnel-step { margin-top: var(--sp-12); }
.tunnel-step-label {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  letter-spacing: var(--eyebrow-ls); text-transform: uppercase;
  color: var(--c-accent);
  margin-bottom: var(--sp-4);
}
.tunnel-step-label::before { content: ""; width: var(--sp-6); height: 1px; background: currentColor; }
.tunnel-question {
  font-size: var(--h2-size); line-height: var(--h2-lh); letter-spacing: var(--h2-ls);
  font-weight: var(--fw-bold);
  margin-bottom: var(--sp-8);
}
.tunnel-question em { font-style: normal; font-weight: var(--fw-medium); color: var(--c-accent); }

.sector-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
@media (min-width: 768px)  { .sector-grid { grid-template-columns: repeat(4, 1fr); } }
/* Étape 2 : quatre services, sur une seule ligne. La grille des secteurs
   (étape 1) en compte douze et garde ses quatre colonnes ; ce variant n'a plus
   besoin d'être distingué en largeur, mais il le reste pour que le nombre de
   colonnes suive le nombre de services si celui-ci change à nouveau. */
@media (min-width: 768px)  { .sector-grid--services { grid-template-columns: repeat(4, 1fr); } }
.sector-btn {
  padding: var(--sp-4) var(--sp-3);
  text-align: center;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-bg);
  transition: border-color var(--dur-fast), background var(--dur-fast), transform var(--dur-fast) var(--ease-out-soft);
}
.sector-btn:hover { border-color: var(--c-accent); background: var(--c-accent-a04); transform: translateY(-2px); }
.sector-btn.is-selected { border-color: var(--c-accent); background: var(--c-accent-a08); box-shadow: 0 0 0 1px var(--c-accent); }
.sector-btn-icon { display: block; margin-bottom: var(--sp-2); }
.sector-btn-icon .icon { margin-inline: auto; color: var(--c-accent); }
.sector-btn-name { display: block; font-size: var(--fs-2xs); font-weight: var(--fw-medium); color: var(--c-text); }


/* `grid-auto-rows: 1fr` : toutes les formules d'un même groupe ont la même
   hauteur, donc les boutons « Parlons de votre projet » s'alignent. */
.formule-grid { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); grid-auto-rows: 1fr; }
/* Sans cette ligne, l'attribut `hidden` ne masquait RIEN : la règle d'auteur
   `display: grid` ci-dessus l'emporte sur le `[hidden] { display: none }` de la
   feuille du navigateur. Les sept groupes de formules s'affichaient donc tous à
   l'étape 3, quel que soit le service choisi. */
.formule-grid[hidden] { display: none; }
@media (min-width: 900px) {
  /* `minmax(0, 1fr)` et non `1fr` : une colonne en `1fr` ne descend pas
     sous le min-content de son contenu, et le bouton
     « Parlons de votre projet » en réclame 220 px à lui seul pour une carte
     qui n'en offre que 174 à 900 px de large. La grille débordait, et la page
     avec elle : 54 px de défilement horizontal. */
  .formule-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .formule-grid--2 { grid-template-columns: repeat(2, 1fr); max-width: 760px; margin-inline: auto; }
  /* Un service sans grille de formules ne mérite pas une colonne étroite au
     milieu d'un vide : la carte unique est centrée et gardée à une largeur
     lisible. */
  .formule-grid--1 { grid-template-columns: minmax(0, 460px); justify-content: center; }
}
.formule-card {
  position: relative;
  display: flex; flex-direction: column;
  text-align: left;
  padding: var(--sp-8) var(--sp-6);
  border: 2px solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-bg);
  transition: border-color var(--dur-fast), transform var(--dur-fast) var(--ease-out-soft);
}
.formule-card:hover { border-color: var(--c-accent); transform: translateY(-3px); }
.formule-card.is-selected { border-color: var(--c-accent); background: var(--c-accent-a04); box-shadow: 0 0 0 1px var(--c-accent); }
.formule-recommended {
  position: absolute; top: -2px; left: 50%; transform: translateX(-50%);
  background: var(--c-accent); color: var(--c-text-on-accent);
  font-size: var(--fs-mock-xs); font-weight: var(--fw-bold);
  letter-spacing: .12em; text-transform: uppercase;
  padding: 4px 14px; border-radius: 0 0 4px 4px; white-space: nowrap;
}
.formule-name { font-size: var(--h3-size); font-weight: var(--fw-semibold); letter-spacing: var(--h3-ls); }
.formule-price {
  margin-top: var(--sp-2);
  font-size: var(--fs-xl); font-weight: var(--fw-bold);
  letter-spacing: var(--h2-ls); line-height: 1; color: var(--c-accent);
}
.formule-price-note { margin-top: var(--sp-1); font-size: var(--fs-2xs); color: var(--c-text-faint); }
/* « À partir de » devant le montant : le prix garde sa taille, la mention qui
   le précède reprend celle des légendes. Aucune nouvelle valeur typographique
   n'est introduite, seulement des jetons existants. */
.formule-price-avant {
  display: block;
  font-size: var(--fs-2xs); font-weight: var(--fw-regular);
  letter-spacing: normal; color: var(--c-text-faint);
}
/* Ancien montant d’une offre promotionnelle, barré, posé AU-DESSUS du prix
   appliqué et à l’intérieur de lui : la grille des prix n’a que trois
   rangées — mention, montant, légende — et les cartes s’alignent dessus
   d’une offre à l’autre. Le montant réel garde ainsi la ligne des autres
   prix, y compris le « Sur devis » de la carte voisine ; c’est l’ancien qui
   flotte au-dessus. Deux crans plus bas dans l’échelle et en demi-gras : il
   se lit, sans disputer la vedette au prix qu’on paie vraiment. */
.formule-price-barre {
  display: block;
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  letter-spacing: normal; color: var(--c-prix-barre);
  text-decoration-line: line-through;
  text-decoration-thickness: 2px;
  margin-bottom: 2px;
}

/* Deux façons de payer la même offre, présentées côte à côte : achat à gauche,
   location à droite, séparées par un « ou ». Les deux blocs partagent le même
   dessin que le prix simple des autres cartes — mêmes jetons, même hiérarchie :
   la mention en petit, le montant en grand, la précision en légende.
   Deux cartes en portent un : « Landing Page » et « Site Vitrine ». */
.formule-prix-duo {
  display: grid;
  /* Colonnes à la largeur de leur contenu plutôt qu'en `1fr` : à deux
     colonnes égales, chacune plafonnait à 119 px, et « 135 € / mois » —
     128 px — se repliait sur deux lignes. Le repli décalait le montant de
     droite vers le haut et sa légende vers le bas : plus rien ne s'alignait
     d'une offre à l'autre. `space-between` rend l'écart restant aux marges,
     l'achat reste à gauche, la location à droite. */
  grid-template-columns: auto auto auto;
  justify-content: space-between;
  column-gap: var(--sp-3);
  row-gap: 0;
  align-items: end;
  margin-top: var(--sp-2);
}
/* Les deux offres partagent les rangées de la grille : la mention, le montant
   et la légende de gauche se calent exactement sur ceux de droite. */
.formule-prix-duo > .formule-price-avant { grid-row: 1; grid-column: 1; }
.formule-prix-duo > .formule-price       { grid-row: 2; grid-column: 1; margin-top: 0; }
.formule-prix-duo > .formule-price-note  { grid-row: 3; grid-column: 1; }
.formule-prix-duo > .formule-prix--fin   { grid-column: 3; text-align: right; }
.formule-prix-duo > .formule-prix-ou     { grid-column: 2; grid-row: 1 / span 3; align-self: center; }
/* Un montant ne se coupe pas : c'est le repère qu'on lit en premier, et son
   repli désaligne les deux offres l'une par rapport à l'autre. */
.formule-prix-duo > .formule-price { white-space: nowrap; }
.formule-prix-ou {
  font-size: var(--fs-2xs); font-weight: var(--fw-bold);
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--c-text-faint);
}
.formule-price-unite { font-size: var(--fs-sm); font-weight: var(--fw-semibold); letter-spacing: normal; }
@media (max-width: 600px) {
  /* Les deux offres restent côte à côte, rangée par rangée : « À partir de »
     face à « À partir de », les deux montants sur la même ligne, les légendes
     sous eux. L'écart entre colonnes est resserré — à 12 px, les montants se
     repliaient dans une carte de 271 px. Les légendes se calent en haut de
     leur rangée : les deux offres n'ont pas le même nombre de lignes. */
  .formule-prix-duo {
    column-gap: var(--sp-1);
    align-items: start;
  }
  /* Un cran plus bas dans l'échelle pour les DEUX montants — la règle les
     couvre l'un et l'autre, ils gardent donc la même taille — et la mention
     « / mois » suit d'un cran. À 20/14 px, « 135 € / mois », le plus large des
     deux, tient sur une ligne jusqu'aux écrans de 320 px. */
  /* Cales en bas de leur rangee : le prix barre rend la rangee de gauche
     plus haute que celle de droite, et `align-items: start` — pose pour
     les legendes — aurait remonte le loyer au niveau du montant barre
     plutot qu’en face du prix applique. */
  .formule-prix-duo > .formule-price { font-size: var(--fs-md); align-self: end; }
  .formule-prix-duo .formule-price-unite { font-size: var(--fs-xs); }
  /* Dans CE groupe le montant réel descend à 20 px : l’ancien le suit,
     sinon les deux se ressemblent et la hiérarchie disparaît. 14 px sur
     #C62828 restent à 5,6:1 sur blanc. Ailleurs — fiche Google — les
     montants restent à 32 px : le barre y garde ses 16 px, soit la
     moitié, comme sur grand écran. */
  [data-formules-for="site"] .formule-price-barre { font-size: var(--fs-xs); }
  /* « Sur devis » n'est pas dans un double prix : il echappait a la regle
     ci-dessus et restait a 32 px, a cote du « 1 500 € » de la carte voisine
     descendu a 20. Dans ce groupe les trois cartes se lisent l'une apres
     l'autre, leurs montants doivent donc avoir la meme taille. Les trois
     autres groupes de services n'ont que des prix simples, deja homogenes
     entre eux : ils gardent 32 px. */
  [data-formules-for="site"] .formule-price { font-size: var(--fs-md); }
  /* Le « ou » se cale sur la rangée des montants, entre les deux, plutôt que
     centré sur les trois rangées du bloc. */
  .formule-prix-duo > .formule-prix-ou { grid-row: 2; align-self: center; }
}

/* Entre 900 et 1279 px, la grille est à trois colonnes et une carte ne
   mesure que 222 à 312 px : le double prix, qui réclame 276 px pour tenir
   ses deux offres côte à côte, n'y entre pas — à aucune taille de police,
   deux montants et leur « ou » sont simplement trop larges. Les deux offres
   s'empilent donc : l'achat, le « ou », puis la location. Le bloc redescend
   à 128 px de min-content, la carte retrouve le plancher du bouton et rien
   ne dépasse. À 1280 px la carte offre 288 px utiles pour 276 nécessaires :
   les deux offres reprennent alors leur place côte à côte. */
@media (min-width: 900px) and (max-width: 1279px) {
  .formule-prix-duo {
    grid-template-columns: 1fr;
    justify-content: stretch;
  }
  .formule-prix-duo > .formule-price-avant { grid-row: 1; grid-column: 1; }
  .formule-prix-duo > .formule-price       { grid-row: 2; grid-column: 1; }
  .formule-prix-duo > .formule-price-note  { grid-row: 3; grid-column: 1; }
  /* Le « ou » ne sépare plus deux colonnes mais deux blocs empilés : il
     prend sa propre rangée, entre les deux. */
  .formule-prix-duo > .formule-prix-ou     { grid-row: 4; grid-column: 1; align-self: start; }
  /* La location repasse à gauche : alignée à droite, elle ne répondrait plus
     à l'achat qui est au-dessus d'elle et non plus à côté. */
  .formule-prix-duo > .formule-prix--fin   { grid-column: 1; text-align: left; }
  .formule-prix-duo > .formule-price-avant.formule-prix--fin { grid-row: 5; }
  .formule-prix-duo > .formule-price.formule-prix--fin       { grid-row: 6; }
  .formule-prix-duo > .formule-price-note.formule-prix--fin  { grid-row: 7; }
}

/* --- Alignement ligne à ligne d'une carte d'offre à l'autre ---------------
   Chaque bloc d'une carte se cale sur son homologue des cartes voisines : les
   titres entre eux, les prix entre eux, les listes entre elles. Sans cela, une
   mention « À partir de » présente sur une seule carte, ou une phrase de
   présentation plus longue, décalait tout ce qui suivait.
   `subgrid` fait porter les rangées par la GRILLE, pas par chaque carte :
   chacune adopte les mêmes hauteurs de rangée, calées sur le contenu le plus
   haut. Les rangées sont numérotées explicitement, si bien qu'un bloc absent
   — le préfixe de prix, la mention d'abonnement — laisse simplement sa rangée
   vide au lieu de décaler les suivants d'un cran.

   TOUT est restreint à `.formule-grid`, la grille des offres du tunnel Tarifs.
   La page Services réemploie la classe `.formule-card` pour ses six cartes,
   dans une grille tout autre : une règle posée sur `.formule-card` seul
   débordait sur elles et les faisait passer de 675 à 2 568 px de haut.

   Là où `subgrid` manque, les cartes gardent leur empilement en colonne.

   RESTREINT À 900 px, le seuil où les cartes passent côte à côte. En dessous
   la grille n'a qu'une colonne : aligner les rangées d'une carte sur l'autre
   n'a plus de sens, et surtout les cartes au-delà de la première tombaient
   dans des rangées implicites — que `grid-auto-rows: 1fr` étirait à parts
   égales. « Site Vitrine » montait ainsi à 2 270 px contre 574 pour « Landing
   Page », son seul titre occupant 212 px. En mobile les cartes reprennent donc
   leur colonne flex, identique d'une formule à l'autre. */
@media (min-width: 900px) {
@supports (grid-template-rows: subgrid) {
  .formule-grid { grid-template-rows: repeat(9, auto); }
  .formule-grid > .formule-card {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 9;
    row-gap: 0;
  }
  .formule-grid > .formule-card > .formule-name        { grid-row: 1; }
  .formule-grid > .formule-card > .formule-price-avant { grid-row: 2; align-self: end; }
  .formule-grid > .formule-card > .formule-price       { grid-row: 3; align-self: end; }
  .formule-grid > .formule-card > .formule-price-note  { grid-row: 4; }
  /* Le double bloc de prix occupe à lui seul les trois rangées du prix, pour
     que les cartes voisines gardent leur alignement. */
  .formule-grid > .formule-card > .formule-prix-duo    { grid-row: 2 / span 3; align-self: end; }
  .formule-grid > .formule-card > .formule-lead        { grid-row: 5; }
  .formule-grid > .formule-card > .formule-features    { grid-row: 6; }
  .formule-grid > .formule-card > .formule-delay       { grid-row: 7; }
  .formule-grid > .formule-card > .formule-extra       { grid-row: 8; }
  /* `margin-top: auto` poussait le bouton en bas d'une colonne flex ; en
     grille c'est la rangée qui le place. */
  .formule-grid > .formule-card > .formule-choose      { grid-row: 9; align-self: end; margin-top: 0; }
}
}

/* Champ-piège anti-robot. Ni `display: none` ni `hidden` : certains robots
   sautent précisément ce qui est masqué de façon évidente. On le sort du flux
   et de l'écran, on le retire du parcours clavier par `tabindex`, et on le
   cache aux lecteurs d'écran par `aria-hidden` posé dans le HTML. */
.piege-robot {
  position: absolute !important;
  left: -9999px !important;
  width: 1px !important; height: 1px !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* Phrase de présentation sous le prix, et mention d'abonnement sous le délai :
   même traitement que les descriptions et les légendes déjà en place. */
.formule-card .formule-lead { margin-top: var(--sp-4); font-size: var(--fs-2xs); color: var(--c-text-muted); }
.formule-extra { margin-top: var(--sp-2); font-size: var(--fs-2xs); color: var(--c-text-faint); }
.formule-features { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-4); }
.formule-features li { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-2xs); color: var(--c-text-muted); }
.formule-check { color: var(--c-accent); flex-shrink: 0; }
.formule-delay {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-4); padding-top: var(--sp-3);
  border-top: 1px solid var(--c-border);
  font-size: var(--fs-2xs); color: var(--c-text-faint);
}
/* La carte n'est plus un bouton — un bouton ne peut pas en contenir un autre.
   C'est ce bouton-ci qui valide la formule ; `margin-top: auto` le colle au bas
   de la carte pour que toutes les formules l'alignent sur la même ligne. */
.formule-choose { margin-top: auto; padding-top: var(--sp-6); }
/* En dessous de 900 px les cartes sont empilées : `grid-auto-rows: 1fr` les
   mettait toutes à la hauteur de la plus haute, et le `margin-top: auto` du
   bouton absorbait la différence. L'écart entre le dernier texte et le bouton
   variait donc d'une carte à l'autre — 116 px sur « Landing Page », 180 px sur
   « Mise à niveau », 0 sur la carte la plus haute de chaque groupe. Chaque
   carte prend maintenant sa propre hauteur et le même retrait sous son texte. */
@media (max-width: 899.98px) {
  .formule-grid { grid-auto-rows: auto; }
  .formule-grid .formule-choose { margin-top: 0; padding-top: var(--sp-4); }
}
.formule-choose .btn { width: 100%; }


.tunnel-cta { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-6); }
.tunnel-reassurance { display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-6); margin-top: var(--sp-6); }
.tunnel-reassurance li {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-2xs); color: var(--c-text-faint);
}
.tunnel-reassurance li::before { content: "✓"; color: var(--c-accent); }
.tunnel-reset {
  margin-top: var(--sp-6);
  font-size: var(--fs-2xs); color: var(--c-text-faint);
  text-decoration: underline; text-underline-offset: 3px;
}
.tunnel-reset:hover { color: var(--c-text); }

@media (max-width: 680px) { .tunnel { padding: var(--sp-6); } }

/* ==========================================================================
   TARIFS — S4 : AVIS CLIENTS (réf. image « section 4 » du dossier Page Tarifs)
   ========================================================================== */

.testi-title span { color: var(--c-accent); }
.testi-grid { display: grid; gap: var(--sp-6); }
/* Deux colonnes et non trois : la fiche Google compte deux avis. */
@media (min-width: 900px) { .testi-grid { grid-template-columns: repeat(2, 1fr); } }
.testi-card {
  display: flex; flex-direction: column; gap: var(--sp-4);
  padding: var(--card-pad-lg);
  border: 1px solid var(--c-border);
  border-radius: var(--card-radius);
  background: var(--c-bg-panel);
}
.testi-card .stars .icon--star { width: 18px; height: 18px; }
.testi-quote { font-size: var(--fs-xs); color: var(--c-text-muted); flex-grow: 1; }
.testi-author { display: flex; align-items: center; gap: var(--sp-3); }
.testi-name { display: block; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--c-text); }
.testi-role { display: block; font-size: var(--fs-2xs); color: var(--c-text-faint); }


/* ==========================================================================
   CONTACT — S2 : FORMULAIRE DE DEVIS
   ========================================================================== */
.contact-layout { display: grid; gap: var(--sp-8); align-items: start; }
@media (min-width: 900px) { .contact-layout { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: var(--sp-12); } }

.form-card {
  padding: var(--card-pad-lg);
  border: 1px solid var(--c-border);
  border-radius: var(--card-radius);
  background: var(--c-bg-panel);
}
.form-card h2 { margin-bottom: var(--sp-8); }
.form-row { display: grid; gap: var(--sp-4); }
@media (min-width: 560px) { .form-row { grid-template-columns: 1fr 1fr; } }
.field { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.field label { font-size: var(--fs-2xs); font-weight: var(--fw-semibold); color: var(--c-text); }
.field input, .field select, .field textarea {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-bg);
  color: var(--c-text);
  font-size: var(--fs-xs);
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}
.field textarea { resize: vertical; min-height: 120px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px var(--c-accent-a12);
}
.field input:user-invalid, .field select:user-invalid, .field textarea:user-invalid { border-color: var(--c-alert); }
/* Mention d’information sous le bouton d’envoi : discrète, mais lisible.
   Elle remplace la case à cocher obligatoire, qui n’était pas une base
   légale valable pour une demande de contact. */
.form-rgpd {
  font-size: var(--fs-2xs);
  line-height: 1.5;
  color: var(--c-text-muted);
  margin-bottom: var(--sp-6);
}
.form-rgpd a { color: inherit; text-decoration: underline; }
.form-rgpd a:hover { color: var(--c-accent); }

.field--check { flex-direction: row; align-items: flex-start; gap: var(--sp-3); margin-bottom: var(--sp-8); }
.field--check input { width: auto; flex-shrink: 0; margin-top: 3px; accent-color: var(--c-accent); }
.field--check label { font-size: var(--fs-2xs); font-weight: var(--fw-regular); color: var(--c-text-muted); }
.form-submit { width: 100%; }
.form-feedback { margin-top: var(--sp-4); font-size: var(--fs-xs); color: var(--c-accent); }
/* Un envoi réussi et un envoi manqué ne se lisent pas de la même couleur :
   `--c-ok` et `--c-alert` sont les jetons déjà employés par les jauges du
   hero pour dire la même chose. */
.form-feedback.est-reussi   { color: var(--c-ok); font-weight: var(--fw-semibold); }
.form-feedback.est-en-echec { color: var(--c-alert); font-weight: var(--fw-semibold); }
/* Message d'échec du parcours de devis : même traitement, et les deux moyens
   de nous joindre restent cliquables. */
.tunnel-erreur {
  margin-bottom: var(--sp-4);
  font-size: var(--fs-xs); color: var(--c-alert); font-weight: var(--fw-semibold);
}
.tunnel-erreur a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* Message d'erreur sous un champ. Il n'existait pas : le formulaire de contact
   s'en remettait à `:user-invalid`, qui colore la bordure sans rien expliquer. */
.field-error { font-size: var(--fs-2xs); color: var(--c-alert); }
.field-optional { font-weight: var(--fw-regular); color: var(--c-text-faint); }

/* ---- Formulaire de la dernière étape du tunnel Tarifs ------------------- */

.tunnel-form {
  display: grid; gap: 0 var(--sp-4);
  grid-template-columns: 1fr;
  margin-top: var(--sp-8);
}
@media (min-width: 700px) { .tunnel-form { grid-template-columns: repeat(2, 1fr); } }
.tunnel-form .field--full { grid-column: 1 / -1; }
/* La case de consentement : la case et son libellé sur une ligne, le message
   d'erreur en dessous — `.field--check` passe le bloc en rangée, il faut donc
   rendre la ligne enveloppante au message. */
.tunnel-form .field--check { flex-wrap: wrap; }
.tunnel-form .field--check .field-error { flex: 1 0 100%; }
.tunnel-form .tunnel-cta { grid-column: 1 / -1; }
.tunnel-form .tunnel-reassurance { grid-column: 1 / -1; margin-top: var(--sp-4); }
/* Le remerciement remplace le formulaire. Sans cadre : à ce moment-là il n'y a
   plus rien d'autre à l'écran, une carte ne délimiterait rien. */
.tunnel-merci {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-16); margin-bottom: var(--sp-16);
  text-align: center;
  font-size: var(--fs-sm); color: var(--c-text-muted);
}
.tunnel-merci-titre {
  font-size: var(--h2-size); font-weight: var(--fw-bold);
  letter-spacing: var(--h2-ls); line-height: 1; color: var(--c-text);
}

.contact-aside { display: flex; flex-direction: column; gap: var(--sp-6); }
.contact-info-card {
  display: flex; flex-direction: column; gap: var(--sp-6);
  padding: var(--card-pad);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface);
}
.contact-info-row { display: flex; align-items: flex-start; gap: var(--sp-3); font-size: var(--fs-xs); }
.contact-info-title { display: block; font-weight: var(--fw-semibold); color: var(--c-text); margin-bottom: 2px; }
.contact-info-row a { color: var(--c-accent); text-decoration: underline; text-underline-offset: 3px; }


/* ==========================================================================
   CONTACT — S3 : FAQ EN ACCORDÉON
   ========================================================================== */
.faq-list { display: flex; flex-direction: column; gap: var(--sp-3); max-width: 860px; }
.faq-item {
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface);
  overflow: hidden;
}
.faq-heading { font-size: inherit; font-weight: inherit; }
.faq-question {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-6);
  text-align: left;
  font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--c-text);
  transition: color var(--dur-fast);
}
.faq-question:hover { color: var(--c-accent); }
.faq-sign { color: var(--c-accent); flex-shrink: 0; transition: transform var(--dur-fast) var(--ease-out-soft); }
.faq-question[aria-expanded="true"] .faq-sign { transform: rotate(45deg); }
.faq-answer { padding: 0 var(--sp-6) var(--sp-6); }
.faq-answer p { font-size: var(--fs-xs); max-width: 70ch; }
/* Repli de la FAQ : au-delà de la cinquième question, on n'encombre pas le
   défilement. Le pli est porté par une classe que JavaScript pose à
   l'initialisation, et le bouton naît `hidden` dans le HTML : sans JavaScript
   la liste s'affiche entière et le bouton n'apparaît pas, plutôt que sept
   questions rendues inatteignables. */
.faq-list.est-repliee .faq-item--extra { display: none; }
.faq-plus { display: flex; justify-content: center; margin-top: var(--sp-6); max-width: 860px; }

/* ==========================================================================
   CHECK-LISTES (blocs de services de l'accueil)
   Mise en page uniquement : couleurs et tailles viennent toutes des tokens
   déjà en place, aucune nouvelle valeur typographique ni chromatique.
   ========================================================================== */
.check-list {
  display: flex; flex-direction: column; gap: var(--sp-2);
  margin-top: var(--sp-3);
}
.check-list li {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
.check-mark { color: var(--c-accent); flex-shrink: 0; margin-top: 3px; }

/* Bouton sous les quatre étapes de la section « Résumé de notre méthode » */
.steps-cta { margin-top: var(--sp-12); }

/* --- Section « Nos services » : bouton sous l'image, et titre de la
       section « Pourquoi travailler avec OBT Agency ? » sur une seule ligne --- */
/* `--sp-6` et non `--sp-12` : le bouton se cale juste sous la photo, en
   gardant une marge franche. */
.flank-cta { margin-top: var(--sp-6); text-align: center; }
/* Mot mis en avant dans un titre. */
.accent { color: var(--c-accent); }

/* Le titre tient sur une ligne dès qu'il y a la place ; en dessous il
   revient au retour à la ligne naturel plutôt que de déborder. */
#accueil-s8 .section-head,
#services-s5 .section-head,
#realisations-s4 .section-head { max-width: none; }
@media (min-width: 1100px) { .title--nowrap { white-space: nowrap; } }

/* Unité du graphique, à droite de la légende */

/* Cartes d'offre de la page Services : même dessin que les formules du
   tunnel Tarifs, mais informatives — ni cliquables, ni sélectionnables. */
.formule-card--static {
  cursor: default;
  /* L'image débordant du retrait par marges négatives, c'est la carte qui
     découpe ses propres angles. */
  overflow: hidden;
  /* Plus de hauteur : la respiration vient du padding et d'un plancher de
     hauteur, pas de la gouttière — l'écart entre les cartes reste celui de la
     grille (--sp-6). */
  padding: var(--sp-12) var(--sp-8);
  min-height: var(--offer-card-min-h);
}
.formule-card--static:hover { border-color: var(--c-border); transform: none; }
.formule-card--static .formule-features { margin-top: var(--sp-6); }
@media (max-width: 1023px) { .formule-card--static { min-height: 0; } }

/* Bandeau image en haut de carte. Hauteur fixe et non `aspect-ratio` : c'est
   une part de la hauteur de la CARTE qui est demandée, pas de sa largeur — un
   ratio ferait varier le bandeau d'une colonne à l'autre.

   Les marges négatives annulent le retrait de la carte : l'image touche les
   deux bords et le haut, et son arrondi supérieur reprend celui de la carte
   moins l'épaisseur de la bordure (2 px), sans quoi un liseré de fond
   apparaîtrait dans les angles. */
.service-shot {
  height: var(--service-media-h);
  flex: 0 0 auto;
  margin: calc(var(--sp-12) * -1) calc(var(--sp-8) * -1) var(--sp-8);
  border: 0;
  border-radius: var(--radius-md) var(--radius-md) 0 0;   /* le rayon de la carte, à l'identique */
}
/* Largeur donnée explicitement : une image est un élément REMPLACÉ, elle ne
   s'étire pas à la largeur de son conteneur comme le ferait un bloc. Avec une
   largeur automatique, elle se calait sur sa hauteur et son ratio — 234 px
   dans une carte de 302, soit 66 px de vide à droite. La formule reprend la
   largeur de contenu plus les deux marges négatives qui la débordent.
   `cover` recadre au centre : le bandeau fait 94 px de haut pour une image de
   900 × 382, il y a forcément rognage — autant qu'il soit centré plutôt que
   déformant. */
.service-shot {
  width: calc(100% + var(--sp-8) * 2);
  /* `max-width: 100%` de la remise à zéro plafonnait cette largeur à celle du
     contenu : l'image débordant volontairement dans le retrait de la carte, le
     plafond doit sauter ici. */
  max-width: none;
  object-fit: cover; object-position: center;
  background: var(--c-bg-elevated);
}
/* Sous-titre sous le nom du service : un cran plus petit que les autres
   descriptions, il occupe quatre à cinq lignes dans une colonne étroite. */
.formule-lead {
  margin-top: var(--sp-3);
  font-size: var(--fs-2xs);
  color: var(--c-text-muted);
}
/* `margin-top: auto` colle le bouton au bas de la carte : comme toutes les
   cartes ont la même hauteur, tous les boutons s'alignent sur une même ligne. */
/* `margin-top: auto` colle le bouton au bas de la carte : toutes les cartes
   ayant la même hauteur, tous les boutons s'alignent. Le retrait au-dessus
   descend de 32 à 24 px — le vide restant vient de l’écart de longueur entre
   les check-lists, il ne se supprime pas sans désaligner les boutons. */
.formule-cta { margin-top: auto; padding-top: var(--sp-6); }
/* `white-space: normal` et `min-width: 0` : sans eux, le `nowrap` du bouton
   fixait la largeur MINIMALE de la colonne de grille (un `1fr` ne descend pas
   sous le contenu minimal de son élément), et les quatre colonnes débordaient
   du conteneur de 126 px à 1024 px. */
.formule-card--static { min-width: 0; }
/* Même dessin que le bouton « Demander un rendez-vous » du hero d'accueil :
   pilule pleine, pastille blanche poussée contre le bord droit. */
.formule-cta .btn { width: 100%; white-space: normal; justify-content: space-between; }

/* ==========================================================================
   MOBILE — ajustements propres aux petites largeurs
   ========================================================================== */
@media (max-width: 768px) {

  /* --- Titres : une seule taille, celle du titre hero d'accueil ---------
     Le titre hero de l'accueil est a 32 px sur mobile ; tous les autres
     titres etaient a 40 px, plus gros que lui. On aligne l'ensemble sur
     32 px en reprenant son propre jeton.

     On agit sur les JETONS et non sur chaque regle : toutes les regles de
     titre lisent `--h1-size` ou `--h2-size`. Cela laisse volontairement de
     cote les chiffres du site — `.stat-figure`, le score d'avis, les
     montants du simulateur — qui lisent `--fs-2xl` et `--fs-3xl`
     directement : ce ne sont pas des titres, ils gardent leur taille.
     Les sous-titres en `--h3-size` (plan du site, mentions legales)
     restent a 25 px : un niveau sous les titres de section. */
  :root {
    --h1-size: var(--fs-hero-title-m);
    --h2-size: var(--fs-hero-title-m);
  }

  /* --- Hero : taches ovales comme sur grand écran ------------------------
     Les tailles en pourcentage se lisent sur une section étroite et haute :
     les taches devenaient des ovales VERTICAUX (ratio 0,28) là où elles sont
     horizontales sur ordinateur (~1,45). On fixe donc la largeur et on laisse
     `aspect-ratio` déduire la hauteur : la forme est conservée. */
  .blob { height: auto; aspect-ratio: var(--blob-ratio); }
  .blob--1 { width: 105%; left: -22%; top: 2%; }
  .blob--2 { width: 100%; right: -20%; top: 0%; }
  .blob--3 { width: 95%;  left: 6%;   top: 28%; }
  .blob--4 { width: 105%; left: -25%; bottom: 6%; }
  .blob--5 { width: 100%; right: -22%; bottom: 2%; }
  .blob--6 { width: 90%;  right: 4%;  top: 52%; }
  .blob--full-a, .blob--full-b { width: 190%; inset: auto; aspect-ratio: var(--blob-ratio-full); }
  .blob--full-a { left: -45%; top: 4%; }
  .blob--full-b { right: -45%; bottom: 4%; }

  /* --- Hero : textes plus compacts --------------------------------------- */
  .hero-lead .eyebrow { font-size: var(--fs-hero-eyebrow-m); }
  .hero-title { font-size: var(--fs-hero-title-m); }
  .hero-subtitle { font-size: var(--fs-hero-sub-m); }

  /* --- Hero : rythme vertical resserré -----------------------------------
     Les écarts d'origine (24 / 32 / 48 px) éparpillaient le bloc. Comme le
     hero aligne son contenu en bas (`justify-content: flex-end`), resserrer
     ces écarts fait DESCENDRE le titre et le sous-titre — ce qui est demandé —
     tout en collant la note d'avis, le bouton et les deux cases. */
  .hero-subtitle { margin-top: var(--sp-3); }
  /* Le contenu du hero est plaqué en bas (`align-content: end`) : creuser cet
     écart REMONTE l'eyebrow, le titre et le sous-titre, le bouton ne bouge
     pas. C'est l'air demandé entre le texte et « Nous contacter ». */
  .hero-cta-row { margin-top: var(--sp-6); }
  /* Le bloc de texte occupe toute la hauteur d'écran disponible et son contenu
     est plaqué en bas (`align-content: end`) : les deux cases se posent donc au
     ras du bas de l'écran, et la démo d'audit passe sous la ligne de flottaison.
     Hauteur retirée : le bandeau menu (88) + le retrait haut du hero (32) + une
     respiration basse (32).
     `100vh` d'abord, `100svh` ensuite : là où `svh` manque, la première
     déclaration tient encore ; `svh` est la petite hauteur de viewport, celle
     qui vaut barre d'adresse déployée, donc rien ne dépasse au chargement. */
  .hero-main {
    gap: var(--sp-4);
    align-content: end;
    min-height: calc(100vh  - var(--header-height) - var(--sp-8) - var(--sp-8));
    min-height: calc(100svh - var(--header-height) - var(--sp-8) - var(--sp-8));
  }

  /* Le hero mobile est déjà plaqué en bas de l'écran : y ajouter de l'air
     au-dessus de l'eyebrow remonterait le bloc au lieu de le descendre. */
  .hero-lead .eyebrow { margin-top: 0; }
  /* Le bouton prend toute la largeur : la note passe dessous, centrée. */
  .hero-cta-row { gap: var(--sp-3); }
  .hero-rating { justify-content: center; width: 100%; }

  /* --- Hero : les deux cases tiennent sur une ligne ---------------------- */
  .hero-services { flex-wrap: nowrap; gap: var(--sp-3); }
  .hero-services .hero-chip {
    flex: 1 1 0; min-width: 0;
    padding: var(--sp-3) var(--sp-2);
    text-align: center;
  }

  /* --- Nos services : image et bouton en dernier, blocs qui s'empilent ---- */
  #accueil-s4 .flank { display: flex; flex-direction: column; gap: var(--sp-8); }
  /* `display: contents` fait remonter l'image et le bouton au niveau de la
     colonne : sans cela le bouton reste prisonnier de `.flank-media` et ne
     peut pas se glisser entre la dernière case et l'image. */
  #accueil-s4 .flank-media { display: contents; }
  #accueil-s4 .flank-stack { display: block; order: 1; }
  #accueil-s4 .flank-cta { order: 2; margin-top: 0; }
  /* La vraie photo comme le bloc gris qu'elle a remplacé : en dernier, après
     les six cases et le bouton. Ne viser que `.placeholder` laissait l'image
     remonter en tête de colonne, son `order` restant à 0. */

  /* La photo disparaît en mobile : la colonne enchaîne les six cases puis le
     bouton, une image de plus n'apporterait rien avant le pied de section. */
  #accueil-s4 .flank-shot { display: none; }
  /* Réserve de défilement : le collage s'arrête à la boîte de CONTENU du
     conteneur, un `padding-bottom` ne prolongerait rien. */
  #accueil-s4 .flank-stack::after { content: ""; display: block; height: var(--sp-12); }
  #accueil-s4 .benefit {
    position: sticky;
    top: calc(var(--header-height) + var(--sp-4));
    margin-bottom: var(--sp-6);
    padding: var(--card-pad);
    /* Bleu PROFOND et opaque, pas le fond clair d'origine : avec l'encre
       blanche de la section, celui-ci mettait le texte a 1,08:1. Opaque et
       non translucide, parce qu'une pile collante superpose les cartes et
       qu'une carte transparente laisserait voir celle du dessous.
       Blanc 8,3:1 et #E0E8F9 6,7:1 sur ce bleu : mieux que sur la section
       elle-meme, et la carte s'en detache tout en restant dans la teinte.
       Liseré clair : la bordure sombre d'origine ne se voyait pas. */
    border: 1px solid rgba(255, 255, 255, .26);
    border-radius: var(--card-radius);
    background: #1B46AE;
    box-shadow: var(--shadow-soft);
  }
  #accueil-s4 .benefit:nth-of-type(1) { z-index: 1; }
  #accueil-s4 .benefit:nth-of-type(2) { z-index: 2; }
  #accueil-s4 .benefit:nth-of-type(3) { z-index: 3; }
  #accueil-s4 .benefit:nth-of-type(4) { z-index: 4; }
  #accueil-s4 .benefit:nth-of-type(5) { z-index: 5; }
  #accueil-s4 .benefit:nth-of-type(6) { z-index: 6; }

  /* --- Résumé de notre méthode : même empilement -------------------------
     `--pile-h` est la hauteur commune des cartes, écrite par main.js après
     égalisation. Elle sert deux fois : à placer le point de collage au centre
     de l'écran, et à dimensionner la réserve de défilement.
     La réserve fait exactement une hauteur de carte : une fois la carte 04
     posée sur la 03, la pile reste immobile pendant toute cette hauteur avant
     que l'ensemble ne remonte. Avec l'ancienne réserve de 96 px, la carte 04
     arrivait et la pile repartait presque dans le même mouvement. */
  .steps-row { display: block; }
  .steps-row::after { content: ""; display: block; height: var(--pile-h, var(--sp-24)); }
  .step {
    position: sticky;
    /* `--pile-top` place la carte 01 au centre de l'écran ; il est écrit une
       fois par main.js en pixels. Pas de `svh` ni de `max()` ici : là où l'un
       des deux manque, la déclaration entière est rejetée et la carte se colle
       tout en haut de l'écran. Une valeur en pixels ne peut pas échouer. */
    top: var(--pile-top, calc(var(--header-height) + var(--sp-4)));
    margin-bottom: var(--sp-6);
    padding: var(--card-pad);
    border: 1px solid var(--c-border);
    border-radius: var(--card-radius);
    background: var(--c-bg-elevated);
    box-shadow: var(--shadow-soft);
  }
  .step:nth-of-type(1) { z-index: 1; }
  .step:nth-of-type(2) { z-index: 2; }
  .step:nth-of-type(3) { z-index: 3; }
  .step:nth-of-type(4) { z-index: 4; }

  /* --- Apparitions : pas de translation sur les cartes collées -----------
     `.reveal` décale l'élément de 26 px. Sur une carte `sticky`, ce décalage
     s'ajoute à la position collée : la superposition n'est plus exacte tant
     que l'animation n'est pas terminée, et une carte pas encore révélée reste
     26 px trop bas. Ici, seul le fondu subsiste. */
  .js .flank-stack.reveal,
  .js #accueil-s4 .benefit.reveal,
  .js .steps-row.reveal,
  .js .step.reveal { transform: none; }

  /* --- Simulateur : le bloc « méthode de calcul » reste dans le cadre ----- */
  .sim-method p { font-size: var(--fs-mobile-xs); }
  .sim-formula { font-size: var(--fs-mobile-xs) !important; padding: var(--sp-2) var(--sp-3); }
  .sim-table { min-width: 0; font-size: var(--fs-mobile-xs); }
  .sim-table th, .sim-table td { padding: var(--sp-2); }
  .sim-table-wrap { overflow-x: visible; }
  .sim-assumption { font-size: var(--fs-mobile-xs); }
  .sim-method-toggle { font-size: var(--fs-mobile-xs); }

  /* --- Graphique : il occupe presque toute la carte ----------------------
     Le retrait de la carte tombe à 8 px sur les côtés : il ne reste qu'un
     liseré entre le tracé et la bordure. Le retrait haut et bas reste à 12 px,
     le titre de la carte a besoin de respirer. */
  /* Le SVG n'est plus large que de 309 px : à 12 unités de viewBox, les
     graduations ne feraient que 3,9 px à l'écran, illisibles. */
}

/* ==========================================================================
   VOILE DE CHARGEMENT
   Affiché à l'ouverture et au rechargement, jamais d'une page à l'autre.
   Trois garde-fous, parce qu'un voile bloqué vaut un site mort :
   1. il n'a de mise en forme que sous `html.is-loading`, posée par le script
      en-tête — sans JavaScript, il n'apparaît donc jamais ;
   2. main.js le retire dès que la page est chargée ;
   3. une animation CSS le fait disparaître à 4 s quoi qu'il arrive, même si
      le script ne tourne pas jusqu'au bout.
   ========================================================================== */
.preloader { display: none; }
.is-loading .preloader {
  position: fixed; inset: 0; z-index: 2000;
  display: flex; align-items: center; justify-content: center;
  background: var(--c-bg);
  /* La sortie se fait par le haut : le voile se soulève comme un rideau et
     découvre la page. La transition porte sur `transform` seul — animer aussi
     l'opacité laisserait entrevoir la page à travers le voile pendant qu'il
     glisse, ce qui brouille le geste. */
  transition: transform var(--preloader-out) var(--ease-inout-soft);
  animation: preloader-secours var(--preloader-out) var(--ease-inout-soft) 4s forwards;
}
.preloader-inner { display: flex; flex-direction: column; align-items: center; }
/* Le logo se dévoile de gauche à droite. `clip-path` et non une largeur
   animée : le logo garde sa taille et sa place, seul le masque bouge, donc
   rien ne se déforme et rien ne se recalcule.

   Le départ est donné par main.js (`is-ready`), pas au moment où l'élément
   est créé. Une animation CSS démarre dès l'analyse du document : le temps que
   la feuille de style, la police et l'image du logo soient chargées, la plus
   grande partie du balayage s'était déjà jouée hors écran et on ne voyait
   apparaître que la fin — le rond bleu.

   La déclaration ci-dessous reste un repli, avec un retard suffisant pour que
   le logo se dévoile quand même si le script ne tourne pas. */
.preloader-logo {
  height: var(--preloader-logo-h); width: auto;
  clip-path: inset(0 100% 0 0);
  animation: preloader-logo var(--preloader-logo-dur) var(--ease-out-soft) 1.4s forwards;
}
/* Changer le NOM de l'animation la relance depuis zéro — un simple
   `animation-delay: 0s` la ferait reprendre en cours de route. */
.preloader.is-ready .preloader-logo {
  animation-name: preloader-logo-go;
  animation-delay: 0s;
}
.is-loading .preloader.is-done { transform: translateY(-100%); }
/* Compteur en bas à droite. `tabular-nums` : sans lui, la largeur des chiffres
   varie et le nombre tressaute à chaque incrément. */
.preloader-count {
  position: absolute;
  right: var(--container-pad); bottom: var(--container-pad);
  font-size: var(--preloader-count-size);
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: var(--h2-ls);
  color: var(--c-text);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 768px) {
  .preloader-count { font-size: var(--preloader-count-size-m); }
}

@keyframes preloader-logo {
  to { clip-path: inset(0 0 0 0); }
}
@keyframes preloader-logo-go {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
/* Filet : même geste que la sortie normale, déclenché par le CSS seul. */
@keyframes preloader-secours {
  to { transform: translateY(-100%); visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  /* Ni balayage ni glissement : le logo est là d'emblée et le voile s'efface. */
  .preloader-logo, .preloader.is-ready .preloader-logo { animation: none; clip-path: none; }
  .is-loading .preloader { transition: opacity var(--preloader-out) linear; }
  .is-loading .preloader.is-done { transform: none; opacity: 0; visibility: hidden; }
}


/* ==========================================================================
   VISIONNEUSE DE RÉALISATION
   Le site du client s'ouvre dans un cadre posé par-dessus la page. Le fond
   n'est pas opaque et le cadre garde une marge tout autour : le site de
   l'agence reste lisible derrière, on comprend qu'on ne l'a pas quitté.
   ========================================================================== */
.viewer {
  position: fixed; inset: 0; z-index: 1500;
  display: flex; align-items: center; justify-content: center;
  padding: var(--viewer-pad);
}
.viewer-backdrop {
  position: absolute; inset: 0;
  background: var(--c-viewer-backdrop);
  cursor: pointer;
}
.viewer-frame {
  position: relative;
  display: flex; flex-direction: column;
  width: 100%; height: 100%;
  max-width: var(--viewer-max-w);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--c-bg);
  box-shadow: var(--shadow-viewer);
}
.viewer-bar {
  display: flex; align-items: center; gap: var(--sp-4);
  flex: 0 0 var(--viewer-bar-h);
  padding: 0 var(--sp-3) 0 var(--sp-6);
  border-bottom: 1px solid var(--c-border);
  background: var(--c-bg-panel);
}
.viewer-title {
  flex: 1 1 auto; min-width: 0;
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  color: var(--c-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* La croix de fermeture reprend le dessin de la flèche d'ouverture (règle
   commune plus haut) ; elle n'a ici que sa taille, calée sur la hauteur du
   bandeau. */
.viewer-close { flex: 0 0 auto; width: 34px; height: 34px; }
.viewer-close .icon { width: 16px; height: 16px; }
/* L'iframe prend tout ce qui reste sous la barre. `height: 100%` et
   `min-height: 0` explicites, et non le seul `flex: 1 1 auto` : une iframe a
   une hauteur intrinsèque de 150 px, et dans plusieurs situations de mise en
   page c'est elle qui l'emporte sur l'étirement du conteneur. Le site invité
   se retrouve alors dans une fenêtre de 150 px de haut — il se charge, mais
   plus aucune animation liée au défilement ne se déclenche. */
.viewer-frame-page {
  flex: 1 1 auto;
  width: 100%; height: 100%; min-height: 0;
  border: 0;
  background: var(--c-bg);
}

/* Apparition : le fond se révèle, le cadre monte de quelques pixels. */
.viewer { opacity: 0; transition: opacity var(--viewer-dur) var(--ease-out-soft); }
.viewer-frame { transform: translateY(12px) scale(.99); transition: transform var(--viewer-dur) var(--ease-out-soft); }
.viewer.is-open { opacity: 1; }
.viewer.is-open .viewer-frame { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .viewer, .viewer-frame { transition: none; }
  .viewer-frame { transform: none; }
}


/* ==========================================================================
   AJUSTEMENTS DE HAUTEUR ET DE MARGE DEMANDÉS SECTION PAR SECTION
   ========================================================================== */

/* Demandé pour le MOBILE uniquement : le rendu sur grand écran ne bouge pas. */
@media (max-width: 768px) {
  /* Accueil : la section des réalisations remonte. Le retrait du BAS de la
     section précédente compte autant que le haut de celle-ci — les deux se
     cumulent, n'en réduire qu'un ne changerait presque rien. */
  #accueil-s5.section { padding-top: var(--sp-8); }

  /* Page Services : la section des huit services remonte. */
  #services-s2.section { padding-top: var(--sp-8); }

  /* Page Réalisations : le premier carrousel remonte, et le second se
     rapproche du bloc de cartes qui le précède — l'intitulé « Une sélection de
     nos maquettes » flottait loin au-dessus. */
  #realisations-s2.section { padding-top: var(--sp-8); }
  /* L'écart entre les cartes du haut et l'intitulé « Une sélection de nos
     maquettes » venait surtout du BAS de la section précédente, pas du haut de
     celle-ci : les deux retraits se cumulaient. */
  #realisations-s2.section { padding-bottom: var(--sp-8); }
  #realisations-s3.section { padding-top: var(--sp-4); }
  #realisations-s3 .section-head { margin-bottom: var(--sp-6); }
}


/* ==========================================================================
   PAGE CONTACT — CARTE D'AVIS QUI DÉFILE
   Remplace le bloc de carte géographique. La colonne est étirée sur toute la
   hauteur du formulaire (`.contact-aside` en colonne, la carte prend le
   reste) : les deux blocs se terminent donc à la même ligne.
   ========================================================================== */
/* Tout ce qui suit ne vaut QU'EN DEUX COLONNES, à partir de 900 px, le seuil
   où `.contact-layout` place la colonne à côté du formulaire. En dessous, la
   rangée de grille ne fait que la hauteur de son contenu : `flex-basis: 0` y
   ramenait les deux cartes à 50 px chacune, leur contenu débordant très
   au-delà de leur cadre — les quatre lignes de coordonnées s'affichaient hors
   de la carte censée les porter. En mobile, chaque carte prend donc sa propre
   hauteur, et le `gap` de `.contact-aside` les sépare. */
@media (min-width: 900px) {
  /* `.contact-layout` aligne ses colonnes en haut (`align-items: start`) : la
     colonne de droite s'arrêtait donc à son contenu, 62 px au-dessus du
     formulaire. On l'étire sur toute la hauteur de la rangée. */
  .contact-aside { align-self: stretch; }
  /* Les deux cartes se partagent la hauteur à parts égales : `flex-basis: 0`
     plutôt que `auto`, sinon la répartition partirait de leur contenu et la
     carte d'informations, plus courte, resterait plus petite. */
  .contact-aside > .contact-info-card,
  .contact-aside > .avis-card { flex: 1 1 0; min-height: 0; }
}
/* Contenu centré verticalement, retraits identiques de part et d'autre. */
.contact-info-card { justify-content: center; }
.avis-card {
  position: relative;
  display: flex; flex-direction: column;
  flex: 1 1 auto;              /* occupe la hauteur restante de la colonne */
  min-height: 0;
  padding: var(--card-pad);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  /* Même surface que la carte d'informations juste au-dessus : les deux blocs
     de la colonne forment un ensemble, pas deux objets différents. */
  background: var(--c-surface);
}
/* Les trois avis sont empilés au même endroit ; seul celui qui porte
   `is-active` est visible. La hauteur du bloc est celle du plus long, sinon
   elle sauterait à chaque changement. */
.avis-viewport { position: relative; flex: 1 1 auto; display: grid; align-content: center; }
.avis-slide {
  grid-area: 1 / 1;
  display: flex; flex-direction: column; gap: var(--sp-4);
  opacity: 0; visibility: hidden;
  transition: opacity var(--avis-fondu) var(--ease-out-soft),
              visibility 0s var(--avis-fondu);
}
.avis-slide.is-active {
  opacity: 1; visibility: visible;
  transition: opacity var(--avis-fondu) var(--ease-out-soft);
}
.avis-card .stars { display: inline-flex; gap: 2px; color: var(--c-accent); }
.avis-quote { font-size: var(--fs-xs); color: var(--c-text); }
.avis-author { display: flex; align-items: center; gap: var(--sp-3); margin-top: auto; }
.avis-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  /* Idem : la couleur de l’auteur si elle existe, sinon la pastille pâle
     d’origine. */
  background: var(--avatar-fond, var(--c-accent-a12));
  color: var(--avatar-encre, var(--c-accent));
  font-size: var(--fs-2xs); font-weight: var(--fw-bold);
  flex-shrink: 0;
}
.avis-name { display: block; font-size: var(--fs-2xs); font-weight: var(--fw-semibold); color: var(--c-text); }
.avis-meta { display: block; font-size: var(--fs-2xs); color: var(--c-text-faint); }
.avis-dots { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); }
.avis-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--c-border-strong);
  transition: background var(--dur-fast), transform var(--dur-fast);
}
.avis-dot.is-active { background: var(--c-accent); transform: scale(1.25); }

@media (prefers-reduced-motion: reduce) {
  .avis-slide { transition: none; }
}


/* ==========================================================================
   BARRE D'APPEL FLOTTANTE
   Deux boutons dans un cadre bleu, posé en bas d'écran au centre. Le cadre est
   plus large et plus haut que les boutons : c'est son retrait qui le montre.
   ========================================================================== */
.appel-flottant {
  position: fixed;
  left: 50%; bottom: var(--appel-bas);
  transform: translateX(-50%);
  transition: opacity var(--dur-med) var(--ease-out-soft),
              transform var(--dur-med) var(--ease-out-soft);
  z-index: var(--appel-z);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--appel-pad);
  border-radius: var(--radius-pill);
  background: var(--c-bg-elevated);
  box-shadow: var(--shadow-soft);
  max-width: calc(100vw - var(--sp-8));
}
/* Les deux boutons reprennent le dessin de celui du bandeau menu. Seules les
   couleurs changent : blanc à gauche, vert WhatsApp à droite. */
.appel-flottant .btn { white-space: nowrap; }
/* Blanc sur le gris du cadre : un filet le détache, la lueur bleue héritée du
   bouton plein le teinterait. */
.appel-flottant__contact {
  background: var(--c-bg);
  color: var(--c-text);
  border-color: var(--c-border);
  box-shadow: none;
}
.appel-flottant__contact:hover {
  /* Blanc cassé : le bouton se pose légèrement sans quitter sa famille de
     tons. Le texte reste sombre — un texte blanc y serait illisible. */
  background: var(--c-bg-panel);
  color: var(--c-text);
  border-color: var(--c-border-strong);
}
.appel-flottant__whatsapp {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: var(--c-whatsapp);
  color: var(--c-text-on-accent);
  border-color: transparent;
}
.appel-flottant__whatsapp:hover {
  background: var(--c-whatsapp-hover);
  color: var(--c-text-on-accent);
}
.appel-flottant__whatsapp .icon { width: 18px; height: 18px; }

/* Effacée devant les zones qui portent déjà leur propre appel à l'action, ou
   qu'elle recouvrirait : les heros, le pied de page, le formulaire de contact.
   `translateX(-50%)` est repris dans l'état masqué, sinon la barre repartirait
   du bord gauche en glissant. */
.appel-flottant.est-masquee {
  opacity: 0;
  transform: translateX(-50%) translateY(160%);
  pointer-events: none;
}

@media (max-width: 768px) {
  .appel-flottant { bottom: var(--appel-bas-m); }
}

@media (max-width: 480px) {
  .appel-flottant { gap: var(--sp-2); padding: var(--sp-2); width: max-content; }
  .appel-flottant .btn { padding-inline: var(--sp-4); }
}

@media (prefers-reduced-motion: reduce) {
  .appel-flottant { transition: opacity var(--dur-med) linear; }
  .appel-flottant.est-masquee { transform: translateX(-50%); }
}
