/* ==========================================================================
   RECB82 — feuille de style unique
   Vanilla CSS, mobile-first. Aucune dépendance, aucune étape de build.
   Ordre : 1 tokens · 2 reset · 3 typo · 4 boutons · 5 layout · 6 header
           7 hero · 8 sections · 9 composants · 10 formulaire · 11 footer
           12 animations · 13 media queries · 14 reduced-motion / print
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Couleurs */
  --ink: #0b3558;          /* texte principal — jamais de noir pur */
  --blue: #006bff;         /* action primaire */
  --blue-dark: #0056cc;
  --slate: #476788;        /* texte secondaire */
  --mist: #a6bbd1;         /* texte désactivé, traits légers */
  --cloud: #f8f9fb;        /* canevas */
  --paper: #ffffff;        /* surfaces */
  --pebble: #f0f3f8;       /* champs, badges, hover */
  --hairline: #d4e0ed;     /* bordures */
  --cobalt: #004eba;       /* texte de badge */
  --magenta: #e55cff;      /* décor uniquement */
  --cyan: #0099ff;         /* décor uniquement */

  /* Typo */
  --font: 'Manrope', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-extra: 800;

  /* Échelle fluide : mobile d'abord, la valeur haute est le desktop */
  --t-caption: 12px;
  --t-small: 14px;
  --t-body: clamp(16px, 0.95rem + 0.2vw, 18px);
  --t-lead: clamp(17px, 1rem + 0.5vw, 20px);
  --t-h3: clamp(20px, 1.05rem + 1vw, 28px);
  --t-h2: clamp(28px, 1.4rem + 3.2vw, 50px);
  --t-h1: clamp(30px, 1.3rem + 4.6vw, 68px);
  --t-display: clamp(34px, 1.4rem + 5.4vw, 80px);

  /* Espacement — base 8 */
  --s-1: 8px;  --s-2: 16px; --s-3: 24px; --s-4: 32px;
  --s-5: 40px; --s-6: 48px; --s-7: 64px; --s-8: 96px;
  --section: clamp(56px, 8vw, 112px);

  /* Rayons */
  --r-sm: 4px; --r-btn: 8px; --r-input: 8px;
  --r-card: 16px; --r-panel: 24px; --r-pill: 9999px;

  /* Ombres teintées bleu — jamais de noir */
  --sh-1: rgba(71,103,136,.04) 0 4px 5px, rgba(71,103,136,.03) 0 4px 10px, rgba(71,103,136,.05) 0 10px 20px;
  --sh-2: rgba(71,103,136,.04) 0 4px 5px, rgba(71,103,136,.03) 0 8px 15px, rgba(71,103,136,.08) 0 30px 50px;
  --sh-3: rgba(71,103,136,.06) 0 8px 12px, rgba(71,103,136,.06) 0 18px 30px, rgba(71,103,136,.12) 0 40px 70px;

  /* Layout */
  --max: 1200px;
  --gutter: clamp(16px, 4vw, 32px);
  --header-h: 64px;

  /* Courbes */
  --ease: cubic-bezier(.22,.61,.36,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
  --spring: cubic-bezier(.34,1.56,.64,1);
}

/* Police auto-hébergée, variable 400→800, latin + latin-ext */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/manrope-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/manrope-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   2. RESET
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; overflow-x: clip; }
body {
  font-family: var(--font);
  font-size: var(--t-body);
  font-weight: var(--fw-regular);
  line-height: 1.65;
  color: var(--ink);
  background: var(--cloud);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  /* Place réservée à la barre d'appel fixe, présente sous 1000 px. */
  padding-bottom: calc(64px + env(safe-area-inset-bottom));
}
img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; top: -100px; left: var(--s-2); z-index: 200;
  background: var(--ink); color: var(--paper); padding: 12px 20px;
  border-radius: var(--r-btn); font-weight: var(--fw-semibold);
  transition: top .2s var(--ease);
}
.skip-link:focus { top: 12px; }

/* --------------------------------------------------------------------------
   3. TYPOGRAPHIE
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 { font-weight: var(--fw-extra); line-height: 1.12; letter-spacing: -.02em; }
h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); line-height: 1.25; letter-spacing: -.015em; }
h4 { font-size: var(--t-lead); font-weight: var(--fw-bold); line-height: 1.35; }
p { color: var(--slate); }
strong { font-weight: var(--fw-bold); color: var(--ink); }
.lead { font-size: var(--t-lead); line-height: 1.6; color: var(--slate); }
.eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--t-caption); font-weight: var(--fw-bold);
  letter-spacing: .12em; text-transform: uppercase; color: var(--cobalt);
  background: #e6f0ff; padding: 6px 14px; border-radius: var(--r-pill);
}
.eyebrow::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--blue); animation: pulse 2.4s var(--ease) infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .35; transform: scale(1.6); }
}
.txt-blue { color: var(--blue); }
.txt-slate { color: var(--slate); }
.center { text-align: center; }
.measure { max-width: 62ch; }
.center .measure, .measure.center { margin-inline: auto; }

/* Lien texte avec soulignement qui balaie */
.link {
  color: var(--ink); font-weight: var(--fw-semibold);
  background-image: linear-gradient(var(--blue), var(--blue));
  background-size: 0% 2px; background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size .4s var(--ease-out), color .25s var(--ease);
  padding-bottom: 2px;
}
.link:hover { background-size: 100% 2px; color: var(--blue); }

/* --------------------------------------------------------------------------
   4. BOUTONS
   -------------------------------------------------------------------------- */
.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 14px 24px;
  font-size: var(--t-body); font-weight: var(--fw-bold);
  border-radius: var(--r-btn);
  border: 1px solid transparent;
  text-align: center; white-space: nowrap;
  transform: translate3d(var(--tx, 0), var(--ty, 0), 0);
  transition: transform .35s var(--ease-out), box-shadow .35s var(--ease),
              background-color .25s var(--ease), color .25s var(--ease),
              border-color .25s var(--ease);
  overflow: hidden;
  isolation: isolate;
}
.btn svg { flex: none; }
/* Balayage lumineux permanent. Au survol il n'existait pas sur mobile, où il
   n'y a pas de survol : il tourne maintenant en boucle, accéléré au survol. */
.btn::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(110deg, transparent 22%, var(--sheen, rgba(255,255,255,.34)) 50%, transparent 78%);
  transform: translateX(-130%);
  animation: balayage 4.6s var(--ease-out) infinite;
  animation-delay: var(--bd, 0s);
}
@keyframes balayage {
  0%, 64%   { transform: translateX(-130%); }
  94%, 100% { transform: translateX(130%); }
}
.btn:hover::before { animation-duration: 1.5s; }
/* Retour tactile franc : le doigt n'a que la pression pour sentir le bouton. */
.btn:active { transform: translate3d(var(--tx, 0), var(--ty, 0), 0) scale(.965); transition-duration: .08s; }
.btn--ghost { --sheen: rgba(0,107,255,.16); }

.btn--primary { background: var(--blue); color: var(--paper); box-shadow: 0 6px 18px rgba(0,107,255,.28); }
.btn--primary:hover { background: var(--blue-dark); box-shadow: 0 14px 32px rgba(0,107,255,.36); }
.btn--dark { background: var(--ink); color: var(--paper); box-shadow: 0 6px 18px rgba(11,53,88,.22); }
.btn--dark:hover { background: #0a2c4a; box-shadow: 0 14px 32px rgba(11,53,88,.3); }
.btn--ghost { background: var(--paper); color: var(--ink); border-color: var(--hairline); box-shadow: var(--sh-1); }
.btn--ghost:hover { border-color: var(--blue); color: var(--blue); box-shadow: var(--sh-2); }
.btn--outline { background: transparent; color: var(--paper); border-color: rgba(255,255,255,.55); }
.btn--outline:hover { border-color: var(--paper); background: rgba(255,255,255,.1); }
.btn--lg { padding: 17px 30px; font-size: var(--t-lead); }
.btn--block { width: 100%; }

/* Groupe de boutons */
.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-2); }

/* Lien téléphone, forme compacte */
.tel-inline {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: var(--fw-extra); color: var(--ink); font-variant-numeric: tabular-nums;
  transition: color .25s var(--ease);
}
.tel-inline:hover { color: var(--blue); }

/* --------------------------------------------------------------------------
   5. LAYOUT
   -------------------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--max); margin-inline: auto; padding-inline: var(--gutter); }
/* Les révélations latérales décalent les blocs de 36 px avant de se jouer.
   `clip` les empêche d'allonger la page horizontalement sans créer de conteneur
   de défilement — donc sans casser les colonnes `position: sticky`. La marge
   laisse les ombres portées des cartes se peindre au-delà du bord. */
.section, .hero {
  overflow-x: clip;
  overflow-clip-margin: 48px;
}
.section { padding-block: var(--section); position: relative; }
.section--paper { background: var(--paper); }
.section--ink { background: var(--ink); color: var(--paper); }
.section--ink p, .section--ink .lead { color: #b9cee4; }
.section--tight { padding-block: clamp(40px, 6vw, 72px); }
/* Sous 860 px, .split-2 n'est pas une grille : ses deux colonnes s'empilent
   sans le moindre écart et le contenu de la seconde vient coller la première. */
.split-2 > * + * { margin-top: clamp(28px, 7vw, 40px); }
@media (min-width: 860px) { .split-2 > * + * { margin-top: 0; } }

.stack > * + * { margin-top: var(--s-2); }
.stack-lg > * + * { margin-top: var(--s-3); }
.grid { display: grid; gap: var(--s-3); }
.section-head { max-width: 720px; margin-bottom: var(--s-6); }
.section-head.center { margin-inline: auto; }
.section-head h2 { margin-block: var(--s-2) var(--s-2); }

/* --------------------------------------------------------------------------
   6. HEADER
   -------------------------------------------------------------------------- */
.progress {
  position: fixed; top: 0; left: 0; z-index: 120;
  height: 3px; width: 100%;
  background: linear-gradient(90deg, var(--blue), var(--cyan), var(--magenta));
  transform: scaleX(var(--p, 0)); transform-origin: 0 50%;
  will-change: transform;
}
.header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 110;
  height: var(--header-h);
  display: flex; align-items: center;
  background: rgba(248,249,251,.72);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border-bottom: 1px solid transparent;
  transition: background-color .35s var(--ease), border-color .35s var(--ease),
              box-shadow .35s var(--ease), transform .45s var(--ease-out);
}
.header.is-stuck { background: rgba(255,255,255,.9); border-bottom-color: var(--hairline); box-shadow: var(--sh-1); }
.header.is-hidden { transform: translateY(-100%); }
.header__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); width: 100%; }

.logo { display: inline-flex; align-items: center; gap: 10px; font-weight: var(--fw-extra); letter-spacing: -.03em; font-size: 20px; }
.logo__mark {
  width: 34px; height: 34px; border-radius: 9px; flex: none;
  background: var(--ink); color: var(--paper);
  display: grid; place-items: center; font-size: 13px; font-weight: var(--fw-extra); letter-spacing: 0;
  transition: transform .5s var(--spring), background-color .3s var(--ease);
}
.logo:hover .logo__mark { transform: rotate(-8deg) scale(1.08); background: var(--blue); }
.logo__82 { color: var(--blue); }

.nav { display: none; }
.nav__list { display: flex; align-items: center; gap: 4px; }
.nav__link {
  position: relative; display: block;
  padding: 9px 14px; border-radius: var(--r-btn);
  font-size: var(--t-small); font-weight: var(--fw-semibold); color: var(--ink);
  transition: color .25s var(--ease);
}
.nav__link::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--pebble); border-radius: var(--r-btn);
  transform: scale(.85); opacity: 0;
  transition: transform .35s var(--spring), opacity .25s var(--ease);
}
.nav__link:hover { color: var(--blue); }
.nav__link:hover::after { transform: scale(1); opacity: 1; }
.nav__link[aria-current="page"] { color: var(--blue); }
.nav__link[aria-current="page"]::after { transform: scale(1); opacity: 1; background: #e6f0ff; }

.header__cta { display: none; align-items: center; gap: var(--s-1); }

/* Burger */
.burger {
  width: 44px; height: 44px; display: grid; place-items: center;
  border-radius: var(--r-btn); border: 1px solid var(--hairline); background: var(--paper);
  transition: border-color .25s var(--ease), background-color .25s var(--ease);
}
.burger:hover { border-color: var(--blue); }
.burger__box { position: relative; width: 20px; height: 14px; }
.burger__box span {
  position: absolute; left: 0; height: 2px; width: 100%; border-radius: 2px; background: var(--ink);
  transition: transform .4s var(--ease-out), opacity .25s var(--ease), width .3s var(--ease);
}
.burger__box span:nth-child(1) { top: 0; }
.burger__box span:nth-child(2) { top: 6px; width: 70%; }
.burger__box span:nth-child(3) { top: 12px; }
.burger[aria-expanded="true"] .burger__box span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.burger[aria-expanded="true"] .burger__box span:nth-child(2) { opacity: 0; transform: translateX(-10px); }
.burger[aria-expanded="true"] .burger__box span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Menu mobile */
.drawer {
  position: fixed; inset: var(--header-h) 0 0; z-index: 105;
  background: var(--paper);
  padding: var(--s-4) var(--gutter) calc(var(--s-8) + 40px);
  overflow-y: auto;
  clip-path: inset(0 0 100% 0);
  visibility: hidden;
  transition: clip-path .55s var(--ease-out), visibility 0s linear .55s;
}
.drawer.is-open { clip-path: inset(0 0 0 0); visibility: visible; transition-delay: 0s, 0s; }
.drawer__list { display: grid; gap: 2px; margin-bottom: var(--s-4); }
.drawer__link {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 4px; font-size: clamp(22px, 6vw, 30px); font-weight: var(--fw-extra);
  letter-spacing: -.02em; border-bottom: 1px solid var(--hairline);
  opacity: 0; transform: translateY(26px);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out), color .25s var(--ease);
}
.drawer.is-open .drawer__link { opacity: 1; transform: none; transition-delay: calc(.1s + var(--i, 0) * .06s); }
.drawer__link svg { color: var(--mist); transition: transform .35s var(--spring), color .25s var(--ease); }
.drawer__link:hover { color: var(--blue); }
.drawer__link:hover svg { transform: translateX(6px); color: var(--blue); }
.drawer__foot {
  opacity: 0; transform: translateY(20px);
  transition: opacity .5s var(--ease-out) .35s, transform .5s var(--ease-out) .35s;
}
.drawer.is-open .drawer__foot { opacity: 1; transform: none; }
body.is-locked { overflow: hidden; }

/* Barre d'appel mobile, toujours visible */
.callbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 108;
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  padding: 10px var(--gutter) calc(10px + env(safe-area-inset-bottom));
  background: rgba(255,255,255,.94);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--hairline);
  transition: transform .45s var(--ease-out);
}
.js .callbar { transform: translateY(110%); }
.js .callbar.is-in { transform: none; }
.callbar .btn { padding: 12px 14px; font-size: 15px; }

/* --------------------------------------------------------------------------
   7. HERO
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  isolation: isolate;
  padding-top: calc(var(--header-h) + clamp(24px, 6vw, 72px));
  padding-bottom: clamp(48px, 8vw, 96px);
  overflow: hidden;
}
.hero__grid { display: grid; gap: clamp(40px, 6vw, 64px); align-items: center; }
.hero__badges { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--s-3); }
.hero h1 { margin-bottom: var(--s-3); font-size: var(--t-display); }
.hero .lead { margin-bottom: var(--s-4); max-width: 54ch; }
.hero__proof {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4);
  margin-top: var(--s-5); padding-top: var(--s-4);
  border-top: 1px solid var(--hairline);
}
.hero__proof-item { display: flex; flex-direction: column; gap: 2px; }
.hero__proof-item b { font-size: clamp(22px, 4vw, 30px); font-weight: var(--fw-extra); letter-spacing: -.03em; line-height: 1; }
.hero__proof-item span { font-size: var(--t-caption); color: var(--slate); font-weight: var(--fw-semibold); }

/* Taches décoratives — atmosphère uniquement, jamais fonctionnelles */
/* Sur mobile les taches passent derrière le texte du hero : l'opacité y est
   réduite pour ne pas dégrader le contraste de lecture. Sur grand écran elles
   se placent derrière la maquette et les bords, où elles peuvent respirer. */
.blob {
  position: absolute; border-radius: 50%;
  filter: blur(60px); opacity: .14; pointer-events: none; z-index: -1;
  will-change: transform;
  transform: translate3d(0, var(--py, 0px), 0);
}
.blob--magenta { background: var(--magenta); }
.blob--cyan { background: var(--cyan); }
.blob--float { animation: float 14s var(--ease) infinite alternate; }
@keyframes float {
  from { transform: translate3d(0, var(--py, 0px), 0) scale(1); }
  to   { transform: translate3d(18px, calc(var(--py, 0px) - 26px), 0) scale(1.12); }
}

/* --------------------------------------------------------------------------
   8. CARTES ET COMPOSANTS
   -------------------------------------------------------------------------- */
.card {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--r-panel);
  padding: var(--s-3);
  box-shadow: var(--sh-1);
  transition: transform .5s var(--ease-out), box-shadow .5s var(--ease), border-color .35s var(--ease);
  overflow: hidden;
  isolation: isolate;
}
/* halo qui suit le curseur */
.card--spot::before {
  content: ''; position: absolute; inset: 0; z-index: -1; opacity: 0;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), rgba(0,107,255,.09), transparent 62%);
  transition: opacity .4s var(--ease);
}
.card--spot:hover::before { opacity: 1; }
.card:hover { transform: translateY(-6px); box-shadow: var(--sh-2); border-color: #bcd3e8; }

/* Carte service */
.service {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-3);
  min-height: 100%;
}
.service__icon {
  width: 52px; height: 52px; flex: none; border-radius: 14px;
  display: grid; place-items: center;
  background: var(--pebble); color: var(--blue);
  transition: background-color .4s var(--ease), color .4s var(--ease),
              transform .55s var(--spring);
}
.service:hover .service__icon,
.card:hover .service__icon { background: var(--blue); color: var(--paper); transform: rotate(-6deg) scale(1.06); }
.service h3 { transition: color .3s var(--ease); }
.service:hover h3 { color: var(--blue); }
.service ul { display: grid; gap: 6px; margin-top: auto; padding-top: var(--s-1); }
.service li {
  position: relative; padding-left: 22px;
  font-size: var(--t-small); color: var(--slate); line-height: 1.5;
}
.service li::before {
  content: ''; position: absolute; left: 0; top: .55em;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--hairline);
  transition: background-color .3s var(--ease), transform .4s var(--spring);
  transition-delay: calc(var(--i, 0) * .04s);
}
.service:hover li::before, .card:hover .service li::before { background: var(--blue); transform: scale(1.25); }

/* Carte chiffre */
.stat { text-align: center; padding: var(--s-3) var(--s-2); }
.stat b {
  display: block; font-size: clamp(34px, 6vw, 54px); font-weight: var(--fw-extra);
  letter-spacing: -.04em; line-height: 1; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat span { display: block; margin-top: 10px; font-size: var(--t-small); color: var(--slate); font-weight: var(--fw-semibold); }
.section--ink .stat b { color: var(--paper); }
.section--ink .stat span { color: #93aecb; }

/* Maquette produit — remplace la photo tant que le client n'en fournit pas */
.mock {
  position: relative; z-index: 1;
  background: var(--paper); border-radius: var(--r-card);
  box-shadow: var(--sh-2);
  border: 1px solid var(--hairline);
  overflow: hidden;
  transform: perspective(1200px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateZ(0);
  transition: transform .6s var(--ease-out), box-shadow .6s var(--ease);
  will-change: transform;
}
.mock:hover { box-shadow: var(--sh-3); }
.mock__bar {
  display: flex; align-items: center; gap: 8px;
  padding: 14px var(--s-3); border-bottom: 1px solid var(--hairline); background: var(--paper);
}
.mock__dot { width: 9px; height: 9px; border-radius: 50%; background: var(--hairline); }
.mock__dot:nth-child(2) { background: #dbe6f2; }
.mock__dot:nth-child(3) { background: #e6eef7; }
.mock__title { margin-left: 6px; font-size: var(--t-caption); font-weight: var(--fw-bold); color: var(--slate); letter-spacing: .04em; text-transform: uppercase; }
.mock__body { padding: var(--s-3); display: grid; gap: 14px; }
.mock__line {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  padding: 13px 16px; border-radius: 12px; background: var(--cloud);
  border: 1px solid transparent;
  transition: background-color .3s var(--ease), border-color .3s var(--ease), transform .4s var(--ease-out);
}
.mock__line:hover { background: var(--paper); border-color: var(--hairline); transform: translateX(4px); }
.mock__line-label { display: flex; align-items: center; gap: 12px; font-size: var(--t-small); font-weight: var(--fw-bold); }
.mock__tick {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--blue); color: var(--paper);
}
.mock__tick svg { width: 12px; height: 12px; }
.mock__meta { font-size: var(--t-caption); font-weight: var(--fw-bold); color: var(--slate); }
.mock__foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  padding: var(--s-3); border-top: 1px solid var(--hairline); background: var(--cloud);
}
.mock__progress { height: 6px; border-radius: 99px; background: var(--pebble); overflow: hidden; }
.mock__progress i { display: block; height: 100%; border-radius: 99px; background: var(--blue); width: var(--w, 72%); }
.js .mock__progress i { width: 0; }
.js .is-in .mock__progress i { width: var(--w, 72%); transition: width 1.4s var(--ease-out) .35s; }

/* Pastille flottante devant la maquette */
.float-chip {
  position: absolute; z-index: 2;
  display: inline-flex; align-items: center; gap: 10px;
  padding: 12px 18px; border-radius: var(--r-pill);
  background: var(--paper); border: 1px solid var(--hairline);
  box-shadow: var(--sh-2);
  font-size: var(--t-small); font-weight: var(--fw-bold);
  animation: bob 5s var(--ease) infinite alternate;
}
.float-chip svg { color: var(--blue); }
@keyframes bob { from { transform: translateY(0); } to { transform: translateY(-12px); } }

/* Bandeau défilant des communes */
.marquee {
  position: relative; overflow: hidden;
  padding-block: var(--s-2);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track { display: flex; width: max-content; animation: slide 38s linear infinite; }
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__group { display: flex; align-items: center; gap: var(--s-4); padding-right: var(--s-4); }
.marquee__item {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: clamp(16px, 2.4vw, 22px); font-weight: var(--fw-bold);
  color: var(--mist); white-space: nowrap;
  transition: color .3s var(--ease);
}
.marquee__item:hover { color: var(--blue); }
.marquee__item::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
@keyframes slide { to { transform: translateX(-50%); } }

/* Étapes numérotées avec trait qui se remplit */
.steps { position: relative; display: grid; gap: var(--s-4); }
.steps::before {
  content: ''; position: absolute; left: 21px; top: 24px; bottom: 24px; width: 2px;
  background: var(--hairline);
}
.steps::after {
  content: ''; position: absolute; left: 21px; top: 24px; width: 2px;
  height: 0; background: var(--blue);
  transition: height 1.6s var(--ease-out) .2s;
}
.steps.is-in::after { height: calc(100% - 48px); }
.step { position: relative; display: grid; grid-template-columns: 44px 1fr; gap: var(--s-2); align-items: start; }
.step__num {
  width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
  background: var(--paper); border: 2px solid var(--hairline);
  font-weight: var(--fw-extra); font-size: var(--t-small); color: var(--slate);
  transition: border-color .4s var(--ease), color .4s var(--ease),
              background-color .4s var(--ease), transform .5s var(--spring);
  z-index: 1;
}
.steps.is-in .step__num { border-color: var(--blue); color: var(--paper); background: var(--blue); }
.steps.is-in .step:nth-child(1) .step__num { transition-delay: .25s; }
.steps.is-in .step:nth-child(2) .step__num { transition-delay: .6s; }
.steps.is-in .step:nth-child(3) .step__num { transition-delay: .95s; }
.steps.is-in .step:nth-child(4) .step__num { transition-delay: 1.3s; }
.step:hover .step__num { transform: scale(1.12); }
.step h3 { font-size: var(--t-lead); margin-bottom: 4px; }

/* Accordéon FAQ */
.faq { border-top: 1px solid var(--hairline); }
.faq__item { border-bottom: 1px solid var(--hairline); }
.faq__btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  padding: var(--s-3) 0; text-align: left;
  font-size: var(--t-lead); font-weight: var(--fw-bold); color: var(--ink);
  transition: color .25s var(--ease);
}
.faq__btn:hover { color: var(--blue); }
.faq__sign { position: relative; width: 24px; height: 24px; flex: none; }
.faq__sign::before, .faq__sign::after {
  content: ''; position: absolute; left: 50%; top: 50%; background: currentColor; border-radius: 2px;
  transform: translate(-50%, -50%);
  transition: transform .45s var(--spring), opacity .3s var(--ease);
}
.faq__sign::before { width: 14px; height: 2px; }
.faq__sign::after { width: 2px; height: 14px; }
.faq__btn[aria-expanded="true"] { color: var(--blue); }
.faq__btn[aria-expanded="true"] .faq__sign::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }
.faq__panel { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .5s var(--ease-out); }
.js .faq__panel { grid-template-rows: 0fr; }
.js .faq__panel[data-open="true"] { grid-template-rows: 1fr; }
.faq__panel > div { overflow: hidden; }
.faq__panel p { padding-bottom: var(--s-3); max-width: 70ch; }

/* Avant / après — curseur glissant */
.ba {
  position: relative; border-radius: var(--r-card); overflow: hidden;
  border: 1px solid var(--hairline); box-shadow: var(--sh-2);
  touch-action: pan-y; cursor: ew-resize; user-select: none;
  background: var(--pebble);
}
.ba__layer { display: block; width: 100%; }
.ba__after {
  position: absolute; inset: 0;
  clip-path: inset(0 0 0 var(--pos, 50%));
}
.ba__after > * { width: 100%; height: 100%; }
.ba__handle {
  position: absolute; top: 0; bottom: 0; left: 0; right: 0;
  transform: translateX(var(--pos, 50%));
  pointer-events: none;
}
.ba__handle::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: -1.5px;
  width: 3px; background: var(--paper); box-shadow: 0 0 0 1px rgba(11,53,88,.12);
}
/* Le champ `range` ne sert qu'au clavier : `pointer-events: none` l'empêche
   d'entrer en concurrence avec le glissement géré en JavaScript, sans lui
   retirer le focus au clavier. Il redevient visible quand il est focalisé. */
.ba__range {
  position: absolute; inset: 0; z-index: 3;
  width: 100%; height: 100%; margin: 0;
  opacity: 0; pointer-events: none;
  -webkit-appearance: none; appearance: none;
  background: transparent;
}
.ba__range::-webkit-slider-thumb { -webkit-appearance: none; width: 44px; height: 44px; }
.ba__range::-moz-range-thumb { width: 44px; height: 44px; border: 0; background: transparent; }
.ba__range:focus-visible { outline: 3px solid var(--blue); outline-offset: -3px; }

.ba__knob {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--paper); color: var(--ink);
  display: grid; place-items: center;
  box-shadow: var(--sh-2);
  transition: transform .35s var(--spring);
}
.ba:hover .ba__knob { transform: translate(-50%, -50%) scale(1.1); }
.ba__tag {
  position: absolute; top: 14px; z-index: 2;
  padding: 6px 14px; border-radius: var(--r-pill);
  font-size: var(--t-caption); font-weight: var(--fw-extra);
  letter-spacing: .08em; text-transform: uppercase;
  background: rgba(11,53,88,.82); color: var(--paper);
  backdrop-filter: blur(6px);
}
.ba__tag--before { left: 14px; }
.ba__tag--after { right: 14px; background: rgba(0,107,255,.9); }

/* Carte chantier */
.work { padding: 0; }
.work__media { position: relative; overflow: hidden; background: var(--pebble); }
.work__media > svg { transition: transform .8s var(--ease-out); width: 100%; height: auto; }
.work:hover .work__media > svg { transform: scale(1.06); }
.work__badge {
  position: absolute; top: 12px; left: 12px;
  padding: 5px 12px; border-radius: var(--r-pill);
  background: rgba(255,255,255,.92); color: var(--cobalt);
  font-size: var(--t-caption); font-weight: var(--fw-extra);
  letter-spacing: .06em; text-transform: uppercase;
}
.work__body { padding: var(--s-3); }
.work__meta { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: var(--s-2); }
.work__meta span {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--t-caption); font-weight: var(--fw-semibold); color: var(--slate);
}
.work__meta svg { color: var(--mist); }

/* Bandeau CTA foncé */
.cta-band { position: relative; overflow: hidden; border-radius: var(--r-panel); background: var(--ink); color: var(--paper); padding: clamp(32px, 6vw, 64px); }
.cta-band h2 { color: var(--paper); }
.cta-band p { color: #b9cee4; }
.cta-band .blob { opacity: .34; }

/* Liste de communes */
.towns { display: flex; flex-wrap: wrap; gap: 10px; }
.town {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 18px; border-radius: var(--r-pill);
  background: var(--paper); border: 1px solid var(--hairline);
  font-size: var(--t-small); font-weight: var(--fw-semibold);
  transition: transform .35s var(--spring), border-color .25s var(--ease),
              color .25s var(--ease), box-shadow .3s var(--ease);
}
.town:hover { transform: translateY(-3px); border-color: var(--blue); color: var(--blue); box-shadow: var(--sh-1); }
.town--link::after { content: '→'; font-weight: var(--fw-extra); transition: transform .3s var(--ease); }
.town--link:hover::after { transform: translateX(3px); }

/* Encadré d'information */
.note {
  border-left: 3px solid var(--blue);
  background: var(--pebble);
  padding: var(--s-3);
  border-radius: 0 var(--r-card) var(--r-card) 0;
}
.note h4 { margin-bottom: 6px; }

/* Fil d'Ariane */
.crumbs { display: flex; flex-wrap: wrap; gap: 8px; font-size: var(--t-caption); color: var(--slate); font-weight: var(--fw-semibold); }
.crumbs a:hover { color: var(--blue); }
.crumbs li:not(:last-child)::after { content: '/'; margin-left: 8px; color: var(--mist); }
.crumbs li { display: inline-flex; gap: 8px; }

/* Contenu rédactionnel des pages ville */
.prose > * + * { margin-top: var(--s-2); }
.prose h2 { margin-top: var(--s-6); }
.prose h3 { margin-top: var(--s-4); }
.prose ul { display: grid; gap: 10px; margin-top: var(--s-2); }
.prose ul li { position: relative; padding-left: 26px; color: var(--slate); }
.prose ul li::before {
  content: ''; position: absolute; left: 0; top: .6em;
  width: 10px; height: 2px; border-radius: 2px; background: var(--blue);
}

/* --------------------------------------------------------------------------
   10. FORMULAIRE
   -------------------------------------------------------------------------- */
.form { display: grid; gap: var(--s-2); }
.field { display: grid; gap: 6px; position: relative; }
.field label { font-size: var(--t-small); font-weight: var(--fw-bold); color: var(--ink); }
.field .hint { font-size: var(--t-caption); color: var(--slate); font-weight: var(--fw-regular); }
.field input, .field select, .field textarea {
  width: 100%; padding: 14px 16px;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--hairline); border-radius: var(--r-input);
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease), background-color .25s var(--ease);
}
.field input:hover, .field select:hover, .field textarea:hover { border-color: #bcd3e8; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 4px rgba(0,107,255,.14);
}
.field textarea { min-height: 120px; resize: vertical; }
.field select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23476788' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 16px center; padding-right: 44px; }
.field--hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form__legal { font-size: var(--t-caption); color: var(--slate); line-height: 1.55; }
.form__legal a { text-decoration: underline; }

/* --------------------------------------------------------------------------
   11. FOOTER
   -------------------------------------------------------------------------- */
.footer { background: var(--paper); border-top: 1px solid var(--hairline); padding-block: var(--s-7) var(--s-4); }
.footer__grid { display: grid; gap: var(--s-5); }
.footer h4 {
  font-size: var(--t-caption); font-weight: var(--fw-extra); text-transform: uppercase;
  letter-spacing: .1em; color: var(--slate); margin-bottom: var(--s-2);
}
.footer__links { display: grid; gap: 10px; }
.footer__links a {
  font-size: var(--t-small); font-weight: var(--fw-semibold); color: var(--ink);
  display: inline-block;
  transition: transform .3s var(--ease), color .25s var(--ease);
}
.footer__links a:hover { color: var(--blue); transform: translateX(4px); }
.footer__bottom {
  display: flex; flex-wrap: wrap; gap: var(--s-2); justify-content: space-between;
  margin-top: var(--s-6); padding-top: var(--s-3);
  border-top: 1px solid var(--hairline);
  font-size: var(--t-caption); color: var(--slate);
}

/* --------------------------------------------------------------------------
   12. ANIMATIONS D'ENTRÉE
   -------------------------------------------------------------------------- */
/* Tout état « caché avant animation » est conditionné à la classe .js posée en
   tête de document. Sans JavaScript, la page s'affiche telle quelle, complète. */
.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 28px, 0);
  transition: opacity .8s var(--ease-out), transform .8s var(--ease-out), filter .8s var(--ease-out);
  transition-delay: var(--d, 0ms);
  filter: blur(6px);
  will-change: opacity, transform;
}
.js [data-reveal="left"]  { transform: translate3d(-36px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(36px, 0, 0); }
.js [data-reveal="scale"] { transform: scale(.94); filter: blur(8px); }
.js [data-reveal="clip"]  { transform: none; filter: none; clip-path: inset(0 0 100% 0); }
.js [data-reveal].is-in {
  opacity: 1; transform: none; filter: none;
  will-change: auto;
}
/* `clip-path` reste réservé à la variante `clip` : posé sur toutes les
   révélations, il rogne les enfants en position absolue qui dépassent du bloc
   (les pastilles flottantes du hero, par exemple). */
.js [data-reveal="clip"].is-in { clip-path: inset(0 0 0 0); }

/* Révélation mot à mot des titres */
.split { display: block; }
.split .w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .08em; }
.split .w > i {
  display: inline-block; font-style: inherit;
  transform: translateY(105%);
  transition: transform .9s var(--ease-out);
  transition-delay: calc(var(--wi, 0) * 45ms + var(--d, 0ms));
}
.split.is-in .w > i { transform: none; }

/* Effets liés au défilement, là où le navigateur les gère nativement */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .scroll-parallax {
      animation: parallax linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes parallax { from { transform: translateY(46px); } to { transform: translateY(-46px); } }

    .scroll-zoom {
      animation: zoomin linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 55%;
    }
    @keyframes zoomin {
      from { transform: scale(.9) translateY(30px); opacity: .5; }
      to   { transform: none; opacity: 1; }
    }
  }
}

/* --------------------------------------------------------------------------
   13. MEDIA QUERIES — le CSS monte à partir du mobile
   -------------------------------------------------------------------------- */
@media (min-width: 560px) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
  .callbar { grid-template-columns: 1.2fr 1fr; }
}

@media (min-width: 860px) {
  .blob { opacity: .3; }
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--4 { grid-template-columns: repeat(2, 1fr); }
  .hero__grid { grid-template-columns: 1.05fr .95fr; }
  .split-2 { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 64px); align-items: center; }
  .footer__grid { grid-template-columns: 1.6fr 1fr 1fr 1fr; }
}

@media (min-width: 1000px) {
  :root { --header-h: 76px; }
  body { padding-bottom: 0; }
  .nav { display: block; }
  .header__cta { display: flex; }
  .burger, .callbar { display: none; }
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
  .section--sticky .sticky-col { position: sticky; top: calc(var(--header-h) + 32px); align-self: start; }
}

/* --------------------------------------------------------------------------
   14. ACCESSIBILITÉ ET IMPRESSION
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; clip-path: none !important; }
  .split .w > i, .split--char .c > i, .swap__l span { transform: none !important; }
  /* Sans animation, la phrase qui s'allume au défilement doit être lisible
     d'emblée, et la maquette rester droite. */
  .lit .w { opacity: 1 !important; }
  .mock { --srx: 0deg !important; --ssc: 1 !important; }
  .paths path { stroke-dashoffset: 0 !important; }
  /* Colonnes d'avis figées, faisceaux et balayages immobiles, schémas complets,
     comparateur posé à mi-course : rien ne bouge, tout reste lisible. */
  .hero__ba { animation: none !important; --pos: 50% !important; }
  .btn::before { animation: none !important; }
  .avis__track { animation: none !important; }
  .btn::after, .avis__card::after, .work::after { animation: none !important; }
  .btn--live { animation: none !important; }
  .work__media .draw > * { stroke-dashoffset: 0 !important; }
  .marquee__track { animation: none; }
  .blob { animation: none; }
  .callbar { transform: none; }
}

@media print {
  .header, .callbar, .drawer, .progress, .blob, .marquee { display: none !important; }
  body { background: #fff; }
  [data-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; }
  a[href^="http"]::after { content: ' (' attr(href) ')'; font-size: 11px; }
}

/* ==========================================================================
   15. EFFETS SÉLECTIONNÉS SUR 21ST.DEV
   Les composants d'origine sont en React + Tailwind + Framer Motion. Ils sont
   ici réinterprétés en CSS natif : même effet visuel, aucune dépendance,
   aucune étape de build. Tout est désactivé sous prefers-reduced-motion, et
   les effets de survol sont réservés aux pointeurs fins.
   ========================================================================== */

/* --- « Vertical Cut Reveal » : révélation caractère par caractère ---------
   Les mots restent insécables pour que la césure de ligne reste correcte. */
.split--char .w { white-space: nowrap; }
.split--char .c { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .08em; }
.split--char .c > i {
  display: inline-block; font-style: inherit;
  transform: translateY(105%);
  transition: transform .75s var(--ease-out);
  transition-delay: calc(var(--ci, 0) * 16ms + var(--d, 0ms));
}
.split--char.is-in .c > i { transform: none; }

/* --- « Text Reveal » : les mots s'allument au fil du défilement ----------- */
.lit {
  font-size: clamp(23px, 1.1rem + 2.4vw, 42px);
  font-weight: var(--fw-extra);
  line-height: 1.32;
  letter-spacing: -.02em;
  color: var(--ink);
  max-width: 28ch;
  text-wrap: pretty;
}
/* Les mots éteints restent lisibles comme un gris de fond : en dessous, le bloc
   paraît vide plutôt qu'en attente. */
.js .lit .w { opacity: .22; transition: opacity .18s linear; }
.lit .w { opacity: 1; }

/* --- « Container Scroll » : la maquette se redresse au défilement --------
   Composé avec l'inclinaison au survol : les deux angles s'additionnent. */
.mock {
  transform:
    perspective(1400px)
    rotateX(calc(var(--srx, 0deg) + var(--rx, 0deg)))
    rotateY(var(--ry, 0deg))
    scale(var(--ssc, 1));
}
.js .mock { --srx: 11deg; --ssc: .96; }

/* --- « Random Letter Swap » : les lettres se relaient au survol ----------
   Sur les liens texte uniquement, jamais sur un numéro de téléphone : on ne
   brouille pas une information qu'on demande au visiteur de lire. */
.swap { display: inline-flex; overflow: hidden; vertical-align: top; }
.swap__l { display: inline-block; position: relative; }
.swap__l span {
  display: inline-block;
  transition: transform .34s var(--ease-out);
  transition-delay: calc(var(--li, 0) * 22ms);
}
.swap__l span:last-child { position: absolute; left: 0; top: 0; transform: translateY(105%); }
@media (hover: hover) and (pointer: fine) {
  .link:hover .swap__l span:first-child,
  .btn:hover .swap__l span:first-child { transform: translateY(-105%); }
  .link:hover .swap__l span:last-child,
  .btn:hover .swap__l span:last-child { transform: none; }
}

/* --- « Background Paths » : tracés qui se dessinent dans le bandeau ------- */
.paths { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .5; }
.paths path {
  fill: none; stroke: var(--cyan); stroke-width: 1.4; stroke-linecap: round;
  stroke-dasharray: var(--len, 900);
  stroke-dashoffset: var(--len, 900);
}
.is-in .paths path {
  animation: trace 3.6s var(--ease-out) forwards;
  animation-delay: calc(var(--pi, 0) * 260ms);
}
@keyframes trace {
  to { stroke-dashoffset: 0; }
}

/* --- Marquee : seconde ligne en sens inverse ----------------------------- */
.marquee--retour .marquee__track { animation-duration: 52s; animation-direction: reverse; }
.marquee--retour .marquee__item { font-size: clamp(14px, 2vw, 18px); color: #bdcfe2; }


/* ==========================================================================
   16. LA LUMIÈRE QUI PARCOURT UN TRACÉ
   Quatre composants de 21st.dev réunis par un même langage : des lignes qui
   se dessinent et une lumière qui les parcourt. Hero (Background Paths +
   Cursor Spotlight), boutons (Border Beam), avis (Testimonials Columns),
   réalisations (Focus Cards). Toujours en CSS et JS natifs, sans build.
   ========================================================================== */

/* --- Boutons : « Border Beam » --------------------------------------------
   Un faisceau parcourt la bordure. Il tourne en continu sur le bouton d'appel
   du hero, et s'allume au survol partout ailleurs. Le dégradé conique est
   découpé en anneau par un masque : seule la bordure s'éclaire. */
@property --ang {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
.btn::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  padding: 1.5px;
  background: conic-gradient(from var(--ang), transparent 0 72%, var(--beam, var(--blue)) 88%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity .35s var(--ease);
  /* Pas d'animation au repos : le faisceau est invisible tant qu'on ne
     survole pas, et faire tourner un `conic-gradient` impose un recalcul de
     style et une repeinture a chaque image. Il ne tourne qu'une fois allume,
     plus bas. */
  pointer-events: none;
}
.btn:hover::after, .btn:focus-visible::after, .btn--live::after {
  opacity: 1;
  animation: faisceau 2.4s linear infinite;
}
/* Sans survol possible, le faisceau reste allumé : c'est là qu'il sert le plus. */
@media (hover: none) {
  .btn::after { opacity: 1; animation: faisceau 2.4s linear infinite; }
}
@keyframes faisceau { to { --ang: 360deg; } }
.btn--primary { --beam: #ffffff; }
.btn--dark    { --beam: var(--cyan); }
.btn--outline { --beam: #ffffff; }
.btn--ghost   { --beam: var(--blue); }
/* Le bouton d'appel du hero porte aussi une pulsation de son ombre bleue. */
.btn--live { animation: pulse-ombre 3.2s var(--ease) infinite; }
@keyframes pulse-ombre {
  0%, 100% { box-shadow: 0 6px 18px rgba(0,107,255,.28); }
  50%      { box-shadow: 0 10px 34px rgba(0,107,255,.46); }
}

/* --- Avis : « Testimonials Columns » --------------------------------------
   Trois colonnes qui montent à l'infini, chacune à sa vitesse, fondues en
   haut et en bas. Le contenu de chaque colonne est dupliqué : le retour au
   point de départ est invisible. */
.avis {
  display: grid; gap: 20px;
  height: clamp(480px, 70vh, 620px);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(transparent, #000 12%, #000 88%, transparent);
}
.avis__col { overflow: hidden; }
.avis__track {
  display: flex; flex-direction: column; gap: 20px;
  animation: monte var(--t, 42s) linear infinite;
  animation-delay: var(--dl, 0s);
}
.avis:hover .avis__track { animation-play-state: paused; }
@keyframes monte { to { transform: translateY(calc(-50% - 10px)); } }
.avis__card {
  position: relative;
  background: var(--paper); border: 1px solid var(--hairline);
  border-radius: var(--r-card); padding: 22px 22px 20px;
  box-shadow: var(--sh-1);
  transition: border-color .3s var(--ease), box-shadow .4s var(--ease), transform .4s var(--ease-out);
  isolation: isolate;
}
.avis__card:hover { border-color: #bcd3e8; box-shadow: var(--sh-2); transform: translateY(-3px); }
/* Même faisceau que les boutons : c'est la signature commune. */
.avis__card::after {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; padding: 1.5px;
  background: conic-gradient(from var(--ang), transparent 0 72%, var(--blue) 88%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity .35s var(--ease);
  /* Pas d'animation au repos : le faisceau est invisible tant qu'on ne
     survole pas, et faire tourner un `conic-gradient` impose un recalcul de
     style et une repeinture a chaque image. Il ne tourne qu'une fois allume,
     plus bas. */
  pointer-events: none;
}
.avis__card:hover::after { opacity: 1; animation: faisceau 2.4s linear infinite; }
.avis__quote { font-size: 15px; line-height: 1.6; color: var(--ink); }
.avis__quote::before { content: '« '; color: var(--blue); font-weight: var(--fw-extra); }
.avis__quote::after  { content: ' »'; color: var(--blue); font-weight: var(--fw-extra); }
.avis__meta { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
.avis__avatar {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--pebble); color: var(--cobalt);
  font-size: 13px; font-weight: var(--fw-extra);
}
.avis__name { font-size: 14px; font-weight: var(--fw-bold); line-height: 1.3; }
.avis__place { font-size: 12px; color: var(--slate); font-weight: var(--fw-semibold); }
.avis__stars { display: flex; gap: 2px; color: var(--blue); margin-bottom: 10px; }
.avis__stars svg { width: 14px; height: 14px; }
/* Badge d'exemple : visible tant que de vrais avis n'ont pas remplacé ces cartes. */
.avis__demo {
  position: absolute; top: 12px; right: 12px;
  font-size: 10px; font-weight: var(--fw-extra); letter-spacing: .1em; text-transform: uppercase;
  color: #8a5a00; background: #fff3d6; border: 1px solid #f2d48a;
  padding: 3px 8px; border-radius: var(--r-pill);
}
/* Une colonne sur téléphone, deux sur tablette, trois au-delà : les colonnes
   absentes sont retirées du flux, pas seulement rognées — elles n'animent rien. */
.avis__col:nth-child(n+2) { display: none; }
@media (min-width: 560px) {
  .avis { grid-template-columns: 1fr 1fr; }
  .avis__col:nth-child(2) { display: block; }
}
@media (min-width: 860px) {
  .avis { grid-template-columns: repeat(3, 1fr); }
  .avis__col:nth-child(3) { display: block; }
}

/* --- Consentement aux traceurs -------------------------------------------
   Carte bleu encre posée en bas, aux couleurs de la marque. Elle ne bloque
   pas la page : la CNIL n'impose pas de mur, et un bandeau qui séquestre le
   visiteur fait fuir plus qu'il ne rassure. Accepter et refuser sont deux
   boutons de même taille, côte à côte — refuser doit être aussi simple. */
.consent {
  position: fixed; z-index: 90;
  left: var(--gutter); right: var(--gutter);
  /* La barre d'appel occupe déjà le bas sur téléphone : on se pose au-dessus
     d'elle, encoche comprise. Elle disparaît au-delà de 860 px. */
  bottom: calc(68px + env(safe-area-inset-bottom) + 12px);
}
.consent[hidden] { display: none; }
.consent__inner {
  margin: 0 auto; max-width: 880px;
  display: grid; gap: 13px;
  padding: 15px 17px;
  background: var(--ink); color: var(--paper);
  border-radius: var(--r-card);
  box-shadow: 0 24px 60px rgba(6, 31, 55, .34), 0 2px 10px rgba(6, 31, 55, .2);
  /* Filet bleu en haut : la même signature que les cartes du site. */
  border-top: 3px solid var(--blue);
  opacity: 0; transform: translateY(18px);
  transition: opacity .34s var(--ease), transform .46s var(--ease-out);
}
.consent.is-in .consent__inner { opacity: 1; transform: none; }

.consent__titre {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 6px;
  font-size: 15px; font-weight: var(--fw-extra);
  /* La regle globale sur <p> l'emporte sur la couleur heritee : sans cette
     ligne le titre sortait en gris ardoise sur fond bleu encre. */
  color: var(--paper);
}
.consent__titre svg { width: 19px; height: 19px; color: #6cb4ff; flex: none; }
.consent__phrase { margin: 0; font-size: 13px; line-height: 1.5; color: #c8dcf0; }
.consent__lien { color: #8cc6ff; font-weight: var(--fw-bold); text-decoration: underline; text-underline-offset: 2px; }
.consent__lien:hover { color: #fff; }

/* Les deux boutons cote a cote des le telephone : empiles, le bandeau
   occupait 400 px sur un ecran de 844 et masquait la moitie de la page. */
.consent__actions { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.consent__actions .btn { width: 100%; justify-content: center; padding-inline: 12px; }
.consent__regler { grid-column: 1 / -1; }
.consent__regler {
  font-size: 12.5px; font-weight: var(--fw-bold);
  color: #a9c4dd; text-decoration: underline; text-underline-offset: 3px;
  padding: 3px; border-radius: 8px;
}
.consent__regler:hover { color: #fff; }

@media (min-width: 860px) {
  .consent { bottom: 20px; }
}
@media (min-width: 720px) {
  .consent__inner {
    grid-template-columns: 1fr auto;
    align-items: center; gap: 26px;
    padding: 20px 24px;
  }
  .consent__actions {
    grid-template-columns: auto auto;
    align-items: center; gap: 10px 12px;
  }
  .consent__actions .btn { width: auto; white-space: nowrap; }
  .consent__regler { grid-column: 1 / -1; justify-self: center; }
}

/* --- Panneau de réglages : boîte de dialogue native ---------------------- */
.consent-modal {
  width: min(620px, calc(100vw - 2 * var(--gutter)));
  max-height: min(84vh, 720px);
  padding: 0; border: 0;
  /* Le reset global pose `* { margin: 0 }`, ce qui écrase la marge
     automatique par laquelle un <dialog> se centre tout seul. */
  margin: auto;
  border-radius: var(--r-card);
  background: var(--paper); color: var(--ink);
  box-shadow: 0 40px 90px rgba(11, 53, 88, .3);
}
.consent-modal::backdrop { background: rgba(6, 31, 55, .6); backdrop-filter: blur(3px); }
.consent-modal[open] { animation: consent-modal-entree .32s var(--ease-out); }
@keyframes consent-modal-entree {
  from { opacity: 0; transform: translateY(14px) scale(.98); }
  to { opacity: 1; transform: none; }
}
.consent-modal form { padding: 26px 24px 20px; }
.consent-modal__titre { font-size: var(--t-h3); margin: 0 0 8px; }
.consent-modal__intro { font-size: 14px; line-height: 1.55; color: var(--slate); margin: 0 0 20px; }

.consent-cat {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 18px;
  padding: 16px 0;
  border-top: 1px solid var(--hairline);
}
.consent-cat__nom { margin: 0 0 4px; font-size: 15px; font-weight: var(--fw-bold); }
.consent-cat__desc { margin: 0; font-size: 13px; line-height: 1.5; color: var(--slate); }
.consent-cat__desc code {
  font-size: 12px; background: var(--pebble);
  padding: 1px 5px; border-radius: 4px;
}
.consent-cat__fige {
  flex: none; font-size: 12px; font-weight: var(--fw-extra);
  color: var(--slate); background: var(--pebble);
  padding: 6px 11px; border-radius: var(--r-pill);
}

/* Interrupteur : une case à cocher native, habillée. Le clavier et les
   technologies d'assistance continuent de voir une case à cocher. */
.switch { flex: none; position: relative; display: inline-flex; cursor: pointer; }
.switch input {
  position: absolute; inset: 0; opacity: 0; margin: 0;
  width: 100%; height: 100%; cursor: pointer;
}
.switch__piste {
  width: 46px; height: 27px; border-radius: 99px;
  background: #cfdcea;
  transition: background-color .28s var(--ease);
  display: block; position: relative;
}
.switch__piste::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 21px; height: 21px; border-radius: 50%;
  background: #fff; box-shadow: 0 2px 5px rgba(11, 53, 88, .28);
  transition: transform .28s var(--spring);
}
.switch input:checked + .switch__piste { background: var(--blue); }
.switch input:checked + .switch__piste::after { transform: translateX(19px); }
.switch input:focus-visible + .switch__piste { outline: 3px solid var(--blue); outline-offset: 3px; }

/* Deux rangs assumes plutot qu'un repli hasardeux : les deux choix en bloc
   se font face, l'enregistrement occupe toute la largeur en dessous. */
.consent-modal__pied {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  padding-top: 18px; margin-top: 4px;
  border-top: 1px solid var(--hairline);
}
.consent-modal__pied .btn { justify-content: center; }
.consent-modal__pied .btn--primary { grid-column: 1 / -1; }

/* --- Tableau des cookies, page /cookies ---------------------------------- */
.table-cookies {
  width: 100%; border-collapse: collapse;
  margin: 18px 0; font-size: 14px;
  display: block; overflow-x: auto;
}
.table-cookies th, .table-cookies td {
  text-align: left; padding: 11px 14px;
  border-bottom: 1px solid var(--hairline);
  white-space: nowrap;
}
.table-cookies th {
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--slate); background: var(--pebble);
}
.table-cookies td code { font-size: 13px; background: var(--pebble); padding: 2px 6px; border-radius: 4px; }
.note { font-size: 14px; color: var(--slate); }

@media (prefers-reduced-motion: reduce) {
  .consent__inner, .consent-modal[open], .switch__piste::after {
    animation: none !important; transition-duration: .01ms !important;
  }
  .consent__inner { opacity: 1; transform: none; }
}

/* --- Méga-menu des prestations -------------------------------------------
   Ouvert au survol ET à la tabulation par le seul CSS : sans JavaScript, il
   reste utilisable au doigt comme au clavier. Le clic n'ajoute que le confort
   d'un panneau qui reste ouvert quand la souris s'en va. */
/* Le panneau se cale sur la barre entiere, pas sur le lien : centre sur un
   lien place a gauche, il sortait de l'ecran. */
.header__inner { position: relative; }
.nav__item { position: static; }
.nav__link--mega {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; color: inherit; cursor: pointer;
}
.nav__chevron { transition: transform .3s var(--ease-out); }

.mega {
  position: absolute; top: calc(100% + 14px); left: 50%;
  width: min(940px, calc(100vw - 2 * var(--gutter)));
  transform: translate(-50%, -10px);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .22s var(--ease), transform .3s var(--ease-out),
              visibility 0s linear .3s;
  z-index: 60;
}
/* Pont invisible entre le lien et le panneau : sans lui, la souris traverse
   un vide de 14 px et le survol se coupe en chemin. */
.mega::before {
  content: ''; position: absolute; left: 0; right: 0; top: -18px; height: 18px;
}
.mega__inner {
  display: grid; gap: 8px 28px;
  grid-template-columns: 1fr 1fr minmax(240px, .85fr);
  padding: 24px;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  box-shadow: 0 28px 60px rgba(11, 53, 88, .16), 0 2px 8px rgba(11, 53, 88, .06);
}
.nav__item--mega:focus-within .mega,
.nav__item--mega .mega.is-open {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translate(-50%, 0);
  transition-delay: 0s;
}
.nav__item--mega:focus-within .nav__chevron,
.nav__link--mega[aria-expanded="true"] .nav__chevron { transform: rotate(180deg); }
@media (hover: hover) and (pointer: fine) {
  .nav__item--mega:hover .mega {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: translate(-50%, 0);
    transition-delay: 0s;
  }
  .nav__item--mega:hover .nav__chevron { transform: rotate(180deg); }
}

.mega__titre {
  font-size: 11px; font-weight: var(--fw-extra);
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--slate); margin: 4px 0 10px 12px;
}
.mega__liste { list-style: none; margin: 0; padding: 0; }
.mega__link {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 10px 12px; border-radius: 10px;
  color: var(--ink); text-decoration: none;
  transition: background-color .22s var(--ease), transform .28s var(--ease-out);
}
.mega__link:hover { background: var(--pebble); transform: translateX(3px); }
.mega__link[aria-current="page"] { background: var(--pebble); }
.mega__icon {
  flex: none; width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--sky); color: var(--blue);
  transition: background-color .22s var(--ease), color .22s var(--ease);
}
.mega__icon svg { width: 19px; height: 19px; }
.mega__link:hover .mega__icon { background: var(--blue); color: #fff; }
.mega__texte { display: block; }
.mega__nom { display: block; font-size: 15px; font-weight: var(--fw-bold); line-height: 1.35; }
.mega__phrase { display: block; font-size: 13px; line-height: 1.45; color: var(--slate); margin-top: 2px; }

.mega__col--encart {
  background: var(--pebble); border-radius: 12px; padding: 20px;
  display: flex; flex-direction: column; gap: 12px;
}
.mega__col--encart .mega__titre { margin: 0; }
.mega__encart-texte { font-size: 13px; line-height: 1.5; color: var(--slate); margin: 0; }
.mega__tel {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 15px; font-weight: var(--fw-extra); color: var(--ink); text-decoration: none;
}
.mega__tel svg { width: 17px; height: 17px; color: var(--blue); }
.mega__horaires { font-size: 12px; color: var(--slate); margin: 0; }

/* Les liens entrent l'un après l'autre : le même décalage que les grilles du
   site, pour que le menu appartienne au même ensemble. */
.nav__item--mega:hover .mega__link,
.nav__item--mega:focus-within .mega__link,
.mega.is-open .mega__link {
  animation: mega-entree .34s var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 28ms + 40ms);
}
@keyframes mega-entree {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: none; }
}

/* --- Tiroir mobile : mêmes entrées, mises à plat ------------------------- */
.drawer__titre {
  font-size: 11px; font-weight: var(--fw-extra);
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--slate); margin: 22px 0 6px;
}
.drawer__titre:first-child { margin-top: 4px; }
.drawer__icon {
  flex: none; width: 36px; height: 36px; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--sky); color: var(--blue);
}
.drawer__icon svg { width: 20px; height: 20px; }
.drawer__texte { flex: 1; min-width: 0; }
.drawer__nom { display: block; font-size: 16px; font-weight: var(--fw-bold); line-height: 1.3; }
.drawer__phrase { display: block; font-size: 13px; line-height: 1.4; color: var(--slate); margin-top: 2px; }

@media (prefers-reduced-motion: reduce) {
  .mega, .mega__link, .nav__chevron { transition-duration: .01ms !important; animation: none !important; }
}

/* --- Avis : un témoignage vérifié, photo à l'appui ------------------------
   Les colonnes défilantes supposaient six avis. Il y en a un de vérifiable :
   une seule pièce, mise en avant, vaut mieux que six inventées. */
.temoin {
  display: grid; gap: 0;
  margin: 0 auto; max-width: 880px;
  background: var(--paper); border: 1px solid var(--hairline);
  border-radius: var(--r-card); overflow: hidden;
  box-shadow: var(--sh-1);
  transition: border-color .3s var(--ease), box-shadow .4s var(--ease), transform .4s var(--ease-out);
  isolation: isolate;
}
.temoin:hover { border-color: #bcd3e8; box-shadow: var(--sh-2); transform: translateY(-3px); }
/* Le même faisceau que les boutons et les cartes : signature commune. */
.temoin::after {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; padding: 1.5px;
  background: conic-gradient(from var(--ang), transparent 0 72%, var(--blue) 88%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity .35s var(--ease);
  /* Pas d'animation au repos : le faisceau est invisible tant qu'on ne
     survole pas, et faire tourner un `conic-gradient` impose un recalcul de
     style et une repeinture a chaque image. Il ne tourne qu'une fois allume,
     plus bas. */
  pointer-events: none;
}
.temoin { position: relative; }
.temoin:hover::after { opacity: 1; animation: faisceau 2.4s linear infinite; }
.temoin__photo {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
  background: var(--pebble);
}
.temoin__texte { padding: 24px 22px 22px; }
.temoin__quote {
  margin: 0; font-size: clamp(17px, 2.4vw, 20px); line-height: 1.55;
  font-weight: var(--fw-semibold); color: var(--ink);
}
.temoin__quote::before { content: '« '; color: var(--blue); font-weight: var(--fw-extra); }
.temoin__quote::after  { content: ' »'; color: var(--blue); font-weight: var(--fw-extra); }
.temoin__lien { margin-top: var(--s-3); text-align: center; }
/* Les avis suivants, en colonnes CSS : chaque carte fait la hauteur de son
   texte. Une grille alignerait tout sur le plus long avis et creuserait des
   trous sous les plus courts. */
.avis-grille {
  columns: 1; column-gap: 20px;
  margin-top: var(--s-3);
  /* Meme largeur que le temoignage mis en avant : le bloc se lit d'un tenant. */
  max-width: 880px; margin-inline: auto;
}
.avis-grille .avis__card {
  break-inside: avoid;
  margin: 0 0 20px;
}
/* Une carte peut porter la photo jointe a l'avis : elle occupe toute la
   largeur, le rembourrage de la carte passe donc sur le contenu seul. */
.avis-grille .avis__card:has(.avis__photo) { padding: 0 0 20px; }
.avis__photo {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
  margin-bottom: 18px;
  border-radius: calc(var(--r-card) - 1px) calc(var(--r-card) - 1px) 0 0;
  background: var(--pebble);
}
.avis__card:has(.avis__photo) .avis__stars,
.avis__card:has(.avis__photo) .avis__quote,
.avis__card:has(.avis__photo) .avis__meta { margin-inline: 22px; }
@media (min-width: 640px) { .avis-grille { columns: 2; } }
/* Trois colonnes seulement quand il y a de quoi les remplir. */
@media (min-width: 1040px) {
  .avis-grille--large { max-width: none; columns: 3; }
}
@media (min-width: 860px) {
  .temoin { grid-template-columns: 420px 1fr; align-items: stretch; }
  .temoin__photo { height: 100%; aspect-ratio: auto; }
  .temoin__texte { padding: 32px 34px; align-self: center; }
}

/* --- Réalisations : « Focus Cards » + tracé des schémas -------------------
   La carte survolée s'avance, les autres s'effacent. Et chaque schéma se
   dessine à l'apparition, trait après trait : le même geste que les lignes
   du hero. */
.work { transition: filter .45s var(--ease), opacity .45s var(--ease), transform .5s var(--ease-out), box-shadow .5s var(--ease), border-color .35s var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .grid:has(.work:hover) .work:not(:hover) { filter: blur(2px) saturate(.85); opacity: .55; transform: scale(.985); }
  .work:hover { transform: translateY(-8px) scale(1.012); box-shadow: var(--sh-3); }
}
.js .work__media .draw > * { stroke-dasharray: 1; stroke-dashoffset: 1; }
.js .is-in .work__media .draw > * {
  animation: trace 1.5s var(--ease-out) forwards;
  animation-delay: calc(var(--k, 0) * 140ms + .25s);
}
/* Le même faisceau sur la carte survolée. */
.work::after {
  content: ''; position: absolute; inset: 0; z-index: 2; border-radius: inherit; padding: 1.5px;
  background: conic-gradient(from var(--ang), transparent 0 72%, var(--blue) 88%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity .35s var(--ease);
  /* Pas d'animation au repos : le faisceau est invisible tant qu'on ne
     survole pas, et faire tourner un `conic-gradient` impose un recalcul de
     style et une repeinture a chaque image. Il ne tourne qu'une fois allume,
     plus bas. */
  pointer-events: none;
}
.work:hover::after { opacity: 1; animation: faisceau 2.4s linear infinite; }


/* ==========================================================================
   17. HERO PHOTOGRAPHIQUE
   Le chantier lui-même en pleine page : l'avant se change en après au
   chargement, puis le visiteur fait glisser. Photos réelles de RECB82.
   ========================================================================== */
/* Mobile : la photo occupe une bande en haut, le texte s'installe dessous sur
   un aplat sombre. Un paragraphe posé sur une salle de bain claire ne se lit
   pas, quelle que soit la force du voile. */
.hero--photo {
  position: relative;
  display: grid; grid-template-rows: auto 1fr;
  padding-top: var(--header-h);
  padding-bottom: clamp(28px, 5vw, 64px);
  background: #061f37;
  overflow: hidden;
  isolation: isolate;
  color: var(--paper);
}
/* Le décor se tait pendant un glissé : balayages, pulsations et bandeau
   défilant n'apportent rien tant que la main tient le curseur, et chacun coûte
   une part du fil principal. Reprise immédiate au relâchement. */
html.is-glisse .btn::before,
html.is-glisse .eyebrow::before,
html.is-glisse .marquee__track,
html.is-glisse .blob--float { animation-play-state: paused; }

/* `will-change` uniquement pendant le glissé : le laisser en permanence
   garderait des couches en mémoire pour rien. */
.hero__ba.is-glisse .hero__after,
.hero__ba.is-glisse .hero__after img,
.hero__ba.is-glisse .hero__handle,
.ba.is-glisse .ba__after,
.ba.is-glisse .ba__handle { will-change: transform; }

.hero__ba {
  position: relative;
  aspect-ratio: 4 / 3;
  cursor: ew-resize;
  touch-action: pan-y;
  --pos: 0%;
}
.hero__ba img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 62%;
}
/* Découpage plutôt que translations : la paire de translations qui s'annulent
   passerait au compositeur, mais la couche cesse d'être peinte dès que le
   décalage dépasse zéro — mesuré, la photo « après » disparaît entièrement.
   `clip-path` rend juste, et le coût par image reste faible une fois les
   animations de décor éteintes. */
.hero__after { position: absolute; inset: 0; clip-path: inset(0 0 0 var(--pos)); }
.js .hero__ba { animation: revele-ba 2.2s var(--ease-out) .35s both; }
@keyframes revele-ba { from { --pos: 0%; } to { --pos: 52%; } }
@property --pos { syntax: '<percentage>'; inherits: true; initial-value: 0%; }

/* Pleine largeur et translatée, plutôt qu'un `left` en pourcentage : déplacer
   un bord déclenche une mise en page, déplacer une couche non. Le trait est
   tracé sur son arête gauche. */
.hero__handle {
  position: absolute; top: 0; bottom: 0; left: 0; right: 0;
  transform: translateX(var(--pos));
  z-index: 2; pointer-events: none;
}
.hero__handle::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: -1px;
  width: 2px; background: rgba(255,255,255,.9);
  box-shadow: 0 0 22px rgba(0,0,0,.35);
}
.hero__knob {
  position: absolute; top: 50%; left: 0; transform: translate(-50%, -50%);
  width: 52px; height: 52px; border-radius: 50%;
  background: rgba(255,255,255,.96); color: var(--ink);
  display: grid; place-items: center;
  box-shadow: 0 10px 30px rgba(0,0,0,.3);
  /* Le trait reste transparent aux événements — pleine hauteur, il bloquerait
     le texte dessous — mais le bouton rond, lui, se saisit. `touch-action:
     none` garantit qu'un doigt posé dessus glisse au lieu de faire défiler. */
  /* `pan-y` et non `none` : le doigt doit pouvoir faire defiler la page en
     partant du bouton, qui tombe au milieu de la bande photo sur telephone.
     Le defilement horizontal, lui, nous revient — c'est tout ce qu'il faut. */
  pointer-events: auto; touch-action: pan-y; cursor: ew-resize;
  transition: transform .25s var(--spring), box-shadow .3s var(--ease);
}
/* Zone de saisie elargie de 14 px tout autour, invisible : viser un rond de
   52 px a la souris comme au doigt demande sinon trop de precision. */
.hero__knob::before {
  content: ''; position: absolute; inset: -14px; border-radius: 50%;
}
.hero__ba:hover .hero__knob { transform: translate(-50%, -50%) scale(1.06); }
.hero__knob:active { transform: translate(-50%, -50%) scale(.94); }
.hero__tag {
  position: absolute; z-index: 3; bottom: 14px; pointer-events: none;
  padding: 6px 14px; border-radius: var(--r-pill);
  font-size: var(--t-caption); font-weight: var(--fw-extra);
  letter-spacing: .1em; text-transform: uppercase;
  /* Aplat translucide plutôt qu'un flou de fond : posée sur une photo qui
     change à chaque image pendant un glissé, la pastille obligeait le
     navigateur à refaire le flou soixante fois par seconde. */
  background: rgba(6,31,55,.82); color: #fff;
}
.hero__tag--avant { left: var(--gutter); }
.hero__tag--apres { right: var(--gutter); background: rgba(0,107,255,.88); }

/* Voile sombre : le texte se lit sur une photo claire de salle de bain. */
.hero__scrim {
  /* Sans objet tant que la photo est en bande : il ne sert qu'en plein cadre. */
  display: none;
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(180deg, rgba(6,31,55,.62) 0%, rgba(6,31,55,.25) 28%, rgba(6,31,55,.78) 62%, rgba(6,31,55,.96) 100%);
}
/* Plus contenu que le titre de l'ancien hero : à 80 px il débordait sur quatre
   lignes et forçait la photo à se recadrer trop près. */
.hero--photo h1 {
  color: var(--paper);
  font-size: clamp(30px, 1.4rem + 2.9vw, 52px);
  margin-bottom: var(--s-3);
}
.hero__content { padding-block: clamp(26px, 6vw, 44px); }
.hero--photo .lead { color: #d8e6f5; max-width: 52ch; margin-bottom: var(--s-3); }
.hero--photo .eyebrow { background: rgba(9,38,66,.58); color: #fff; }
.hero--photo .eyebrow::before { background: #6cb4ff; }
.hero__content {
  position: relative; z-index: 2; width: 100%;
  /* Le bloc s'étend sur toute la largeur et recouvrait la photo : plus aucun
     glissé n'était possible sur grand écran. Il laisse désormais passer les
     événements, sa colonne de texte les reprenant pour elle seule. */
  pointer-events: none;
}
/* Seuls le texte et les commandes reprennent les evenements, pas la boite qui
   les contient : sinon la colonne entiere bloque le glisse de la photo sur
   toute sa hauteur, et l'on croit le curseur casse. */
.hero__content > div { pointer-events: none; }
.hero--photo .hero__content :where(h1, p, a, button, span, li) { pointer-events: auto; }
.hero--photo .hero__proof { border-top-color: rgba(255,255,255,.22); }
.hero--photo .hero__proof-item b { color: var(--paper); }
.hero--photo .hero__proof-item span { color: #a9c4dd; }
.hero--photo .btn--ghost { background: rgba(255,255,255,.96); border-color: transparent; }
.hero__legende {
  margin-top: var(--s-3); font-size: var(--t-caption); color: #9fbbd6;
  display: flex; align-items: center; gap: 8px;
}
/* Sur grand écran la photo repasse en plein cadre derrière le texte : le voile
   latéral suffit alors, la colonne de texte n'occupant que la moitié gauche. */
@media (min-width: 860px) {
  .hero--photo {
    display: flex; align-items: center;
    min-height: min(90svh, 800px);
    padding-top: calc(var(--header-h) + 24px);
  }
  /* `z-index: auto` : la photo ne fabrique plus de contexte d'empilement, si
     bien que sa poignée peut passer au-dessus du texte au lieu d'y rester
     prisonnière. Les deux images, en z-index automatique, restent dessous. */
  .hero__ba { position: absolute; inset: 0; z-index: auto; aspect-ratio: auto; }
  .hero__handle { z-index: 4; }
  .hero__scrim {
    display: block;
    background:
      linear-gradient(95deg, rgba(6,31,55,.96) 0%, rgba(6,31,55,.9) 32%, rgba(6,31,55,.52) 52%, rgba(6,31,55,.1) 72%, rgba(6,31,55,.32) 100%),
      linear-gradient(180deg, rgba(6,31,55,.5) 0%, transparent 32%, rgba(6,31,55,.45) 100%);
  }
  .hero__content > div { max-width: 620px; }
  /* Le repère « Avant » tomberait derrière le voile : seul « Après » reste,
     du côté où la photo se voit vraiment. */
  .hero__tag { top: calc(var(--header-h) + 20px); bottom: auto; }
  .hero__tag--avant { display: none; }
}

@media (hover: none) {
  .hero__knob { width: 44px; height: 44px; }
}

/* En-tête posé sur la photo : transparent en haut, plein une fois décollé. */
.header--over:not(.is-stuck) {
  background: linear-gradient(180deg, rgba(6,31,55,.55), transparent);
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.header--over:not(.is-stuck) .nav__link,
.header--over:not(.is-stuck) .logo { color: var(--paper); }
.header--over:not(.is-stuck) .nav__link::after { background: rgba(255,255,255,.16); }
.header--over:not(.is-stuck) .burger { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.3); }
.header--over:not(.is-stuck) .burger__box span { background: var(--paper); }

/* Logo : la marque réelle de l'entreprise, sur pastille blanche pour tenir
   aussi bien sur l'en-tête clair que sur la photo sombre. */
.logo__mark {
  background: var(--paper);
  border: 1px solid var(--hairline);
  padding: 3px;
  overflow: hidden;
}
.logo__mark img { width: 100%; height: 100%; object-fit: contain; }
.logo:hover .logo__mark { background: var(--paper); transform: rotate(-6deg) scale(1.06); }

/* --------------------------------------------------------------------------
   18. PHOTOS DE CHANTIER DANS LES SECTIONS
   -------------------------------------------------------------------------- */
/* Cartes de prestation : la photo remplace l'aplat, l'icône reste en pastille. */
.service--photo { padding: 0; overflow: hidden; }
.service__photo { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--pebble); }
.service__photo img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease-out); }
.card:hover .service__photo img { transform: scale(1.06); }
.service__photo .service__icon {
  position: absolute; left: 14px; bottom: 14px;
  background: rgba(255,255,255,.94); backdrop-filter: blur(6px);
}
.service--photo > .service__body { padding: var(--s-3); display: flex; flex-direction: column; gap: var(--s-2); flex: 1; }

/* Réalisations : vraies photos avant/après, cadrées à l'identique. */
.work__media { aspect-ratio: 4 / 3; }
.work__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease-out); }
.work:hover .work__media img { transform: scale(1.06); }

/* Zone d'intervention : la carte réelle, et des pastilles compactes — la liste
   pleine taille occupait un écran entier de téléphone pour rien. */
.carte {
  position: relative; border-radius: var(--r-card); overflow: hidden;
  border: 1px solid var(--hairline); box-shadow: var(--sh-1);
}
.carte img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 5 / 2; }
.carte__pin {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -100%);
  color: var(--blue); filter: drop-shadow(0 4px 8px rgba(11,53,88,.35));
}
.carte__pin svg { width: 34px; height: 34px; }
.carte__adresse {
  position: absolute; left: 10px; right: 10px; bottom: 10px;
  background: rgba(255,255,255,.95); backdrop-filter: blur(8px);
  border-radius: 9px; padding: 8px 12px;
  font-size: 13px; font-weight: var(--fw-bold); line-height: 1.35;
}
.carte__adresse span { display: block; font-weight: var(--fw-regular); color: var(--slate); font-size: 11.5px; }
/* Le repere se cale au-dessus du bandeau d'adresse, sinon il disparait dessous. */
.carte__pin { top: 38%; }
/* Seize communes en pastilles pleine taille occupaient un ecran entier de
   telephone. Densifiees, et sans repere repete seize fois. */
.towns--compact { gap: 6px; }
.towns--compact .town { padding: 5px 11px; font-size: 12.5px; font-weight: var(--fw-semibold); }
.towns--compact .town svg { display: none; }
@media (min-width: 560px) {
  .towns--compact .town svg { display: block; width: 12px; height: 12px; }
}

/* Le bouton de la colonne méthode restait orphelin sous l'en-tête sur mobile :
   il n'apparaît que là où la colonne est réellement collante. */
.steps-cta { display: none; }
@media (min-width: 1000px) { .steps-cta { display: flex; } }

/* Aucune ancre ne doit atterrir sous l'en-tête fixe. */
[id] { scroll-margin-top: calc(var(--header-h) + 16px); }

/* ==========================================================================
   19. CARROUSEL DE PHOTOS
   Défilement natif avec accroche : il fonctionne au doigt, à la molette et
   sans JavaScript. Les flèches et les points ne font qu'ajouter du confort.
   ========================================================================== */
.carrousel { position: relative; }
.carrousel__piste {
  display: flex; gap: var(--s-2);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  padding-bottom: 4px;
  /* La photo entière tient dans la vue, la suivante amorce à droite. */
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
  scroll-padding-inline-start: var(--gutter);
}
.carrousel__piste::-webkit-scrollbar { display: none; }
.carrousel__item {
  flex: 0 0 min(86%, 420px);
  /* Accroche au bord gauche : au repos la premiere photo est bien la
     premiere, et « photo 2 sur 5 » designe ce que l'on voit a gauche. */
  scroll-snap-align: start;
  margin: 0;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: var(--sh-1);
}
.carrousel__item img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
  background: var(--pebble);
}
.carrousel__item figcaption {
  padding: 14px 16px;
  font-size: 14px; line-height: 1.5; color: var(--slate);
}
.carrousel__nav {
  position: absolute; top: calc(50% - 30px); z-index: 2;
  width: 44px; height: 44px; border-radius: 50%;
  display: none; place-items: center;
  background: rgba(255,255,255,.96); color: var(--ink);
  border: 1px solid var(--hairline);
  box-shadow: var(--sh-2);
  transition: transform .3s var(--spring), color .25s var(--ease), opacity .25s var(--ease);
}
.carrousel__nav:hover { transform: scale(1.08); color: var(--blue); }
.carrousel__nav[disabled] { opacity: .35; pointer-events: none; }
.carrousel__nav--prev { left: -6px; }
.carrousel__nav--next { right: -6px; }
@media (hover: hover) and (pointer: fine) {
  .carrousel__nav { display: grid; }
}
.carrousel__points {
  display: flex; justify-content: center; gap: 0;
  /* L'écart entre les points vient désormais de leur zone touchable, et la
     marge du dessus rattrape les 8 px de rembourrage. */
  margin-top: calc(var(--s-2) - 8px);
}
.carrousel__point {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--hairline);
  /* Le point reste petit, la zone touchable fait 23 px : viser une pastille
     de 7 px au doigt est intenable. */
  padding: 8px 7px; box-sizing: content-box; background-clip: content-box;
  transition: background-color .3s var(--ease), width .3s var(--ease-out);
}
.carrousel__point[aria-current="true"] { background: var(--blue); background-clip: content-box; width: 22px; border-radius: 99px; }
.carrousel__legende {
  margin-top: var(--s-2); font-size: var(--t-caption); color: var(--slate);
  display: flex; align-items: center; gap: 8px;
}
@media (min-width: 860px) {
  .carrousel__item { flex-basis: min(60%, 460px); }
}
