/* ==========================================================================
   Wexa — Site vitrine one-page
   ========================================================================== */

/* ---- Palette « terre cuite » ----
   Une seule famille chromatique, chaude, du brun terre au presque-noir. Le bleu
   d'origine tirait l'image vers la tech ; ici la teinte parle d'atelier et de
   matière, ce qui est le sujet du site.
   Les trois valeurs d'accent ne sont PAS une coquetterie : la terre cuite vive
   ne passe qu'à 3,7:1 sur blanc, insuffisant pour du petit texte (les kickers
   sont en 0,72rem capitales espacées). D'où une version foncée pour le petit
   texte sur fond clair, la vive pour les aplats et les gros titres, et une
   version claire pour le petit texte sur fond sombre. */
:root {
  --ink: #5B2F1F;           /* brun terre : texte & éléments principaux (11:1 sur blanc) */
  --accent: #D9622B;        /* terre cuite vive : aplats, filets, dégradés, gros titres  */
  --accent-ink: #A8461B;    /* accent foncé : PETIT texte sur fond clair (5,9:1)         */
  --accent-soft: #F5CBB2;   /* accent clair : PETIT texte sur fond sombre (7,8:1)        */
  --white: #FFFFFF;
  --body: rgba(91, 47, 31, 0.76);
  --line: rgba(91, 47, 31, 0.12);
  --bg-soft: #FBF5F0;
  --deep: #331E16;          /* sections sombres : showcase & closing */
  --deep-2: #47291E;
  --on-deep: rgba(255, 255, 255, 0.72);
  --line-deep: rgba(255, 255, 255, 0.12);
  --grad-primary: linear-gradient(120deg, #5B2F1F 0%, #D9622B 100%);
  --shadow-card: 0 22px 48px -24px rgba(58, 26, 15, 0.28);
  --shadow-lg: 0 40px 90px -30px rgba(42, 23, 18, 0.45);
  --f-head: 'Space Grotesk', sans-serif;
  --f-body: 'Inter', sans-serif;
  /* ---- Parcours chromatique ----
     Deux moitiés, et rien entre les deux : une moitié haute lumineuse (blanc →
     brume à peine rosée) et une moitié basse « nuit » (brun quasi noir).
     AUCUNE terre cuite moyenne saturée en aplat de fond : une teinte franche à
     mi-chemin lit toujours « corporate », jamais premium. Le contraste entre
     les deux moitiés devient l'unique geste fort de la page.
     Les brumes chaudes sont volontairement un cran plus soutenues que les
     bleues qu'elles remplacent : à luminance égale, un ton chaud paraît plus
     clair, et les paliers s'écrasaient.
     Il n'existe plus de palier intermédiaire entre la brume et la nuit : le
     passage de l'une à l'autre est une arête franche, à toutes les largeurs. */
  --mist-1:  #FDF9F6;   /* Services, haut                                     */
  --mist-2:  #F4E9E0;   /* Services, bas                                      */
  --night-1: #3A241C;   /* haut des sections sombres (Réalisations ET Contact) */
  --night-2: #281812;   /* bas des sections sombres                            */
  --night-3: #150C09;   /* footer : le point le plus bas du parcours           */
}

/* ---------- Reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  scroll-behavior: auto;
  /* Toile de fond du rebond élastique iOS : quand on tire la page au-delà de
     son bord (geste natif, non désactivable sur le scroller racine), le
     navigateur révèle le fond de <html>. En blanc, ça faisait une « zone
     blanche » criarde au-dessus du hero dans les webviews (appli Google).
     On peint cette toile à la teinte du haut du hero : le rebond devient
     invisible. Contrepartie assumée : tirer au-delà du footer sombre révèle
     brièvement cette même teinte claire. */
  background-color: var(--mist-1);
}
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }

body {
  font-family: var(--f-body);
  color: var(--ink);
  /* Teinte du BAS du dégradé du hero (cf. .hero-bg), et non du blanc : sur
     téléphone, quand les barres du navigateur se rétractent, l'écran devient
     plus haut que la hauteur mesurée au chargement et une bande de <body>
     apparaît un instant sous la scène 3D. En blanc, elle se voyait comme une
     barre en bas de l'animation ; à cette teinte, elle est invisible.
     Ailleurs, chaque section peint son propre fond : rien d'autre ne change. */
  background: #F2E4DA;
  line-height: 1.6;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--accent); color: var(--white); }

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 { font-family: var(--f-head); line-height: 1.12; letter-spacing: -0.02em; }
h2 { font-size: clamp(1.9rem, 4vw, 2.9rem); font-weight: 700; }
h3 { font-size: clamp(1.25rem, 2.2vw, 1.6rem); font-weight: 600; }
p  { color: var(--body); }

.eyebrow {
  font-family: var(--f-head);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin-bottom: 1rem;
}

.lead { font-size: clamp(1.02rem, 1.5vw, 1.15rem); max-width: 46ch; }

.section { padding: clamp(5.5rem, 11vh, 9rem) 1.5rem; position: relative; }
.wrap { max-width: 1180px; margin: 0 auto; position: relative; z-index: 1; }

em { font-style: normal; color: var(--accent); }

/* ---------- Éléments d'identité premium ---------- */

/* Étiquette de section : filet + numéro + libellé */
.kicker {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--f-head);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Capitales espacées en 0,78rem : c'est le cas typique où l'accent vif
     décroche en lisibilité. Le filet, lui, reste vif — il est graphique. */
  color: var(--accent-ink);
}
.kicker::before {
  content: '';
  width: 30px; height: 2px;
  background: var(--accent);
  border-radius: 2px;
}
.kicker--light { color: var(--accent-soft); }   /* même étiquette, sur fond sombre */

/* En-tête de section (label + gros titre + intro) */
.sec-head {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: end;
  margin-bottom: clamp(2.8rem, 5vw, 4rem);
}
.sec-head h2 { margin-top: 1.1rem; }
.sec-intro { color: var(--body); font-size: clamp(1rem, 1.35vw, 1.12rem); max-width: 42ch; }

/* Grand numéro fantôme en fond de section */
.watermark {
  position: absolute;
  font-family: var(--f-head);
  font-weight: 700;
  line-height: 0.8;
  letter-spacing: -0.04em;
  pointer-events: none;
  user-select: none;
  z-index: 0;
  will-change: transform;
}

/* Titres révélés ligne par ligne (masque + glissement) */
[data-lines] .line { display: block; overflow: hidden; }
[data-lines] .line-in { display: block; will-change: transform; }

/* ---------- Boutons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--f-head);
  font-weight: 600;
  font-size: 0.95rem;
  padding: 0.85em 1.7em;
  border-radius: 999px;
  transition: background 0.3s, color 0.3s, transform 0.3s, box-shadow 0.3s;
  cursor: pointer;
}
.btn svg { width: 1.1em; height: 1.1em; transition: transform 0.3s; }
.btn:hover svg { transform: translateX(4px); }

.btn-primary {
  background: var(--ink);
  background-image: var(--grad-primary);
  color: var(--white);
  box-shadow: 0 10px 24px -8px rgba(91, 47, 31, 0.5);
}
.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 16px 34px -8px rgba(217, 98, 43, 0.55);
}

.btn-ghost {
  border: 1.5px solid var(--line);
  color: var(--ink);
}
.btn-ghost:hover {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--white);
  transform: translateY(-2px);
}

.btn-big { font-size: 1.12rem; padding: 1.05em 2.4em; }

/* ---------- Loader ---------- */
#loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--white);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.6rem;
}
#loader img { width: 56px; animation: loader-pulse 1.4s ease-in-out infinite; }
@keyframes loader-pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(0.88); opacity: 0.6; }
}
.loader-bar {
  width: 120px; height: 3px;
  background: var(--line);
  border-radius: 99px;
  overflow: hidden;
}
.loader-bar span {
  display: block; height: 100%; width: 40%;
  background: var(--accent);
  border-radius: 99px;
  animation: loader-slide 1.1s ease-in-out infinite;
}
@keyframes loader-slide {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(320%); }
}

/* ---------- Navigation ---------- */
#nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0.85rem clamp(1.2rem, 4vw, 2.5rem);
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
  transform: translateY(-100%);
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
#nav.nav--visible { transform: translateY(0); }

.nav-brand { display: inline-flex; align-items: center; }
.brand-logo { height: clamp(28px, 3.2vw, 34px); width: auto; display: block; }
.brand-icon { display: none; }   /* symbole seul : uniquement en mobile (≤ 900px) */

/* Liens centrés (le bouton de droite a été retiré) */
#nav nav { display: flex; gap: clamp(1.2rem, 3vw, 2.2rem); margin: 0 auto; padding-right: clamp(0px, 4vw, 3rem); }
#nav nav a {
  font-size: 0.92rem;
  font-weight: 500;
  position: relative;
  padding: 0.3em 0;
  transition: color 0.25s;
}
#nav nav a::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 2px;
  background: var(--accent);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
#nav nav a:hover { color: var(--accent-ink); }
#nav nav a.active { color: var(--accent-ink); }
#nav nav a.active::after { transform: scaleX(1); }

.btn-nav { font-size: 0.85rem; padding: 0.65em 1.4em; }

/* ---------- Menu mobile (hamburger + panneau latéral) ---------- */
.nav-toggle {
  display: none;              /* masqué en desktop, affiché ≤ 900px */
  width: 42px; height: 42px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 24px; height: 2px;
  border-radius: 2px;
  background: var(--ink);
  transition: transform 0.35s cubic-bezier(0.22,1,0.36,1), opacity 0.2s;
}
.nav-toggle.is-open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle.is-open span:nth-child(2) { opacity: 0; }
.nav-toggle.is-open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Panneau latéral : au-dessus du header (z-50) car il porte sa propre croix ;
   le voile laisse deviner la page derrière, comme un tiroir de nav classique. */
.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;             /* affiché en flux ≤ 900px */
  visibility: hidden;
  transition: visibility 0.45s;
}
.menu-overlay.is-open { visibility: visible; transition-delay: 0s; }

.menu-scrim {
  position: absolute;
  inset: 0;
  background: rgba(42, 23, 18, 0.42);
  opacity: 0;
  transition: opacity 0.4s ease;
}
.menu-overlay.is-open .menu-scrim { opacity: 1; }

.menu-panel {
  position: relative;
  width: min(84vw, 340px);
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--white);
  box-shadow: 0 0 60px -12px rgba(42, 23, 18, 0.45);
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateX(-100%);
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.menu-overlay.is-open .menu-panel { transform: translateX(0); }

.menu-panel-top { padding: 0.5rem 0.6rem 0.6rem; }
.menu-close {
  width: 44px; height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 50%;
  padding: 0;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.25s;
}
.menu-close:hover { background: rgba(91, 47, 31, 0.07); }
.menu-close svg { width: 22px; height: 22px; }

.menu-panel nav { display: flex; flex-direction: column; padding: 0.6rem 1.5rem 2rem; }
.menu-panel nav a {
  font-family: var(--f-head);
  font-size: 1.12rem;
  font-weight: 600;
  color: var(--ink);
  padding: 0.75rem 0;
  opacity: 0;
  transform: translateX(-14px);
  transition: color 0.25s, opacity 0.4s ease, transform 0.4s cubic-bezier(0.22,1,0.36,1);
}
.menu-panel nav a:hover, .menu-panel nav a.active { color: var(--accent-ink); }
.menu-overlay.is-open .menu-panel nav a { opacity: 1; transform: none; }
.menu-overlay.is-open .menu-panel nav a:nth-child(1) { transition-delay: 0.10s; }
.menu-overlay.is-open .menu-panel nav a:nth-child(2) { transition-delay: 0.15s; }
.menu-overlay.is-open .menu-panel nav a:nth-child(3) { transition-delay: 0.20s; }
.menu-overlay.is-open .menu-panel nav a:nth-child(4) { transition-delay: 0.25s; }
.menu-overlay.is-open .menu-panel nav a:nth-child(5) { transition-delay: 0.30s; }

.menu-panel-foot {
  margin-top: auto;
  padding: 1.1rem 1.5rem calc(1.1rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.menu-foot-label {
  display: block;
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--body);
  margin-bottom: 0.35rem;
}
.menu-foot-mail { font-size: 0.92rem; font-weight: 500; color: var(--accent-ink); }

/* ---------- Hero 3D ---------- */
/* z-index 2 : le hero (épinglé) doit couvrir le haut de #apropos, qui est
   remonté de 100vh sous lui (.wrap y est en z-index 1). main.js le fait
   disparaître en fin de zoom pour révéler la vraie section, pile en place. */
#hero {
  position: relative;
  z-index: 2;
  /* lvh, PAS svh. svh = hauteur du viewport barre d'URL AFFICHÉE ; quand Safari
     l'escamote au premier défilement, l'écran visible grandit d'environ 90 px
     et le hero, resté à sa taille, laisse une bande vide en bas — par laquelle
     #apropos transparaissait sous la scène 3D.
     lvh = hauteur barre escamotée : le hero couvre donc TOUJOURS l'écran, quitte
     à ce que son bas passe sous la barre au chargement. C'est sans conséquence,
     la composition est centrée. #apropos et #realisations DOIVENT utiliser la
     même unité, sinon le zoom n'atterrit plus au bon endroit. */
  height: 100vh;
  height: 100lvh;
  /* La référence : hauteur mesurée en JS (voir --vhero dans main.js). Les
     webviews d'applis figent lvh sur le viewport initial ; la mesure JS, elle,
     suit les barres qui s'escamotent. Les deux lignes au-dessus ne sont que le
     filet sans JS. */
  height: var(--vhero, 100lvh);
  overflow: hidden;
  /* « Jupe » sous le hero : une ombre portée pleine, sans flou, décalée vers le
     bas. Elle peint une bande de 72px SOUS le bord inférieur du hero.
     À quoi ça sert : certains navigateurs intégrés aux applis (celui de Google)
     ne comptent pas l'encoche du bas de l'iPhone dans innerHeight, mais
     peignent quand même le document dedans. Le hero se retrouve ~34px trop
     court et #apropos, en blanc franc, apparaît dans l'écart.
     Pourquoi une ombre plutôt qu'une hauteur en plus : elle ne change AUCUNE
     mesure de mise en page. Là où il n'y a pas d'écart (Safari, Chrome), la
     bande tombe hors de l'écran et reste invisible ; là où il y en a un, elle
     le comble. La teinte est celle du bas de .hero-bg. Elle suit l'opacité du
     hero, donc disparaît avec lui en fin de zoom. */
  box-shadow: 0 max(72px, calc(env(safe-area-inset-bottom, 0px) + 40px)) 0 0 #F2E4DA;
  background: linear-gradient(178deg, #FFFFFF 0%, #FDF7F3 60%, #F8EDE5 100%);
}

#webgl {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
}

/* Fond décoratif du hero : dégradé doux + halos + trame de points.
   S'efface (opacity pilotée par JS) quand l'écran du laptop remplit le viewport. */
.hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background:
    radial-gradient(rgba(91, 47, 31, 0.055) 1px, transparent 1.5px) 0 0 / 30px 30px,
    linear-gradient(180deg, #FDF9F5 0%, #F8EFE8 55%, #F2E4DA 100%);
  will-change: opacity;
}
/* Zones bleues mobiles : créées et animées par main.js — leur vitesse
   de déplacement augmente avec la vélocité du scroll */
.hero-bg .blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(22px);
  will-change: transform;
  pointer-events: none;
}

.hero-scrollhint {
  position: absolute;
  /* Le hero fait 100lvh : au chargement, son bas est masqué par la barre d'URL.
     (100lvh - 100svh) vaut exactement la hauteur de cette barre — zéro sur
     ordinateur, ~90px sur iPhone. L'indicateur se cale donc juste au-dessus
     d'elle sur mobile, et à 3vh du bas sur ordinateur, sans média-requête. */
  bottom: 4vh;
  bottom: calc(var(--vhero, 100lvh) - 100svh + 3vh);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
  pointer-events: none;
}
.hero-scrollhint span:first-child {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--body);
}
.hero-scrollhint-line {
  width: 2px; height: 44px;
  background: var(--line);
  border-radius: 2px;
  position: relative;
  overflow: hidden;
}
.hero-scrollhint-line::after {
  content: '';
  position: absolute;
  left: 0; top: 0;
  width: 100%; height: 40%;
  background: var(--accent);
  border-radius: 2px;
  animation: hint-drop 1.6s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes hint-drop {
  0% { transform: translateY(-110%); }
  100% { transform: translateY(280%); }
}

/* Accroche « page d'accueil » sous les lettres 3D « wexa » (left/top posés par main.js) */
.hero-tagline {
  position: absolute;
  z-index: 2;
  transform: translate(-50%, 0);
  width: min(92vw, 40rem);
  text-align: center;
  pointer-events: none;
  opacity: 0; /* révélée par main.js une fois la scène prête */
}
/* Échelle pilotée par la HAUTEUR autant que par la largeur.
   La scène 3D (taille des lettres, du laptop, écart entre les deux) est
   proportionnelle à la hauteur du viewport : le FOV vertical de la caméra est
   fixe, donc tout ce qui est rendu en WebGL se met à l'échelle de innerHeight.
   Une accroche dimensionnée en vw seuls restait, elle, à sa taille plafond sur
   un écran de portable (large mais bas) pendant que le capot du laptop
   remontait — d'où le texte qui débordait dessus. Le min(vw, vh) remet les deux
   dans la même échelle ; au-delà de ~770px de haut c'est le plafond de 2.5rem
   qui s'applique, le rendu grand écran ne bouge donc pas d'un pixel. */
/* Signature de marque : elle se lit comme la baseline des lettres 3D « wexa »
   qui la surplombent, d'où les capitales très espacées et la taille contenue. */
.hero-eyebrow {
  display: block;
  font-family: var(--f-head);
  font-size: clamp(0.68rem, min(0.95vw, 1.8vh), 0.78rem);
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin-bottom: clamp(0.3rem, min(0.8vw, 1.15vh), 0.7rem);
}
.hero-headline {
  font-family: var(--f-head);
  font-size: clamp(1.4rem, min(3.4vw, 4.75vh), 2.5rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-bottom: clamp(0.5rem, min(1.3vw, 1.8vh), 0.95rem);
}
.hero-sub {
  font-size: clamp(0.85rem, min(1.55vw, 2.4vh), 1.12rem);
  font-weight: 500;
  line-height: 1.5;
  color: var(--body);
  max-width: 40rem;
  margin: 0 auto;
}
/* La statistique est l'hameçon de la page : le chiffre porte l'accent. Version
   foncée de l'accent — la terre cuite vive ne tient pas le seuil de lisibilité
   à cette taille sur le fond très clair du hero. */
.hero-sub em { color: var(--accent-ink); font-weight: 600; }
/* Écran bas : l'accroche remonte d'un cheveu. L'écart sous les lettres 3D est
   lui aussi proportionnel à la hauteur du viewport ; on en reprend une part
   pour dégager franchement le capot. (main.js ne pose que left/top, jamais
   transform — cette règle ne lui marche pas dessus.) */
@media (max-height: 780px) {
  .hero-tagline { transform: translate(-50%, -2vh); }
}
/* Fallback sans 3D : l'accroche devient le contenu statique et centré du hero */
.no-3d .hero-tagline {
  position: static;
  transform: none;
  opacity: 1;
  margin: 0 auto;
}


/* ---------- À propos ----------
   La marge négative annule le dernier écran du hero épinglé : sans elle, le
   pin rend le hero (100vh) en fin de course et la section ne commencerait
   qu'un viewport plus bas. Avec elle, scrollY = heroST.end place le haut de
   #apropos pile en haut du viewport — c'est là que le zoom atterrit.
   Les unités suivent celles de #hero (vh + svh) pour rester synchronisées. */
#apropos {
  margin-top: -100vh;
  margin-top: -100lvh;
  margin-top: calc(-1 * var(--vhero, 100lvh));   /* doit rester identique à la hauteur de #hero */
  padding-top: clamp(5rem, 9vh, 7.5rem);   /* le marqueur ne doit pas coller au nav fixe */
  /* Blanc franc sur TOUTE la section, à toutes les largeurs. Le virage vers
     --mist-1 sur les 320 derniers px n'existe plus : la page assume partout
     des bandes à arêtes franches, la coupure vient du seul saut de couleur.
     Le blanc est aussi celui que drawScreen réplique dans l'écran du laptop —
     un aplat lui donne une réplique exacte, ce qu'un dégradé ne permettait pas. */
  background-color: #FFFFFF;
}
.no-3d #apropos { margin-top: 0; }   /* pas de pin sans 3D : pas de compensation */
.wm-apropos {
  /* Plus bas qu'avant : en haut de section, il tombait sous la barre de menu
     à l'atterrissage du zoom et disparaissait aussitôt. */
  top: clamp(4.5rem, 9vw, 7.5rem);
  right: clamp(-0.5rem, 2vw, 2rem);
  font-size: clamp(9rem, 22vw, 20rem);
  color: rgba(91, 47, 31, 0.1);     /* 0.075 passait inaperçu sur le blanc */
}

/* Blocs de la section (Pour qui / Engagements / Méthode) */
.ap-block { margin-bottom: clamp(4rem, 8vw, 6.5rem); }
.ap-block:last-child { margin-bottom: 0; }
.ap-head { max-width: 760px; margin-bottom: clamp(2rem, 4vw, 3rem); }
.ap-title { font-size: clamp(1.6rem, 3.3vw, 2.4rem); font-weight: 700; margin-top: 1rem; }
.ap-lead { color: var(--body); font-size: clamp(1rem, 1.4vw, 1.15rem); max-width: 54ch; margin-top: 1.4rem; }

/* Grille « Pour qui » */
.audience-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
.aud-item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.05rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--white);
  box-shadow: var(--shadow-card);
  font-family: var(--f-head);
  font-weight: 600;
  font-size: 1rem;
  color: var(--ink);
  transition: transform 0.35s cubic-bezier(0.22,1,0.36,1), border-color 0.35s, box-shadow 0.35s;
}
.aud-item:hover {
  transform: translateY(-5px);
  border-color: rgba(217, 98, 43, 0.4);
  box-shadow: 0 24px 48px -24px rgba(91, 47, 31, 0.3);
}
.aud-ic {
  flex: none;
  width: 46px; height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 13px;
  background: rgba(217, 98, 43, 0.12);
  color: var(--accent);
}
.aud-ic svg { width: 23px; height: 23px; }

.pillars {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}
.pillar {
  position: relative;
  overflow: hidden;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 22px;
  padding: 2.4rem 2rem 2.2rem;
  box-shadow: var(--shadow-card);
  transition: transform 0.4s cubic-bezier(0.22,1,0.36,1), box-shadow 0.4s, border-color 0.4s;
}
.pillar::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--grad-primary);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.45s cubic-bezier(0.22,1,0.36,1);
}
.pillar:hover {
  transform: translateY(-8px);
  border-color: rgba(217, 98, 43, 0.4);
  box-shadow: 0 30px 60px -28px rgba(91, 47, 31, 0.35);
}
.pillar:hover::before { transform: scaleX(1); }
.pillar-num {
  position: absolute;
  top: 1.5rem; right: 1.8rem;
  font-family: var(--f-head);
  font-weight: 700;
  font-size: 1rem;
  color: rgba(91, 47, 31, 0.16);
  letter-spacing: 0.05em;
}
.pillar-icon {
  width: 54px; height: 54px;
  border-radius: 16px;
  background: var(--grad-primary);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1.4rem;
  box-shadow: 0 12px 24px -10px rgba(91, 47, 31, 0.5);
}
.pillar-icon svg { width: 26px; height: 26px; }
.pillar h3 { margin-bottom: 0.7rem; }
.pillar p { font-size: 0.95rem; }

/* Méthode : stepper relié */
.process-block { position: relative; }
.process-head { margin-bottom: 2.4rem; }
.process-head h3 { margin-top: 0.9rem; font-size: clamp(1.4rem, 2.6vw, 2rem); }
.process {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  position: relative;
}
.process::before { /* ligne de liaison horizontale */
  content: '';
  position: absolute;
  top: 22px; left: 8%; right: 8%;
  height: 2px;
  background: repeating-linear-gradient(90deg, rgba(217, 98, 43,0.35) 0 8px, transparent 8px 16px);
}
.process li { position: relative; padding-top: 3.6rem; }
.process-num {
  position: absolute;
  top: 0; left: 0;
  width: 44px; height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--white);
  border: 2px solid var(--accent);
  font-family: var(--f-head);
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--ink);
  letter-spacing: 0;
}
.process h4 { font-size: 1.2rem; margin: 0 0 0.5rem; }
.process p { font-size: 0.94rem; max-width: 32ch; }

/* ---------- Services ----------
   Bande claire à part entière : une descente courte et monotone de --mist-1 à
   --mist-2, et rien d'autre. Elle ne fond PAS vers la section suivante — c'est
   l'arête franche avec #realisations qui fait la coupure, à toutes les largeurs.
   Aucun halo radial ici : il réchauffait le haut de la section et le creux entre
   les deux donnait l'impression de repasser par le blanc. Ni coins arrondis ni
   ombre non plus : ce sont des arêtes, l'inverse de ce qu'on cherche.
   Le padding-bottom généreux ne réserve plus la place d'un fondu : il est
   désormais la respiration claire qui précède la bascule dans la nuit, et c'est
   lui qui donne à l'arête toute sa force. Il vaut pour toutes les largeurs. */
#services {
  padding-bottom: clamp(13rem, 20vh, 16rem);
  background: linear-gradient(180deg, var(--mist-1) 0%, var(--mist-2) 100%);
}
/* Séparateur : filet qui naît et meurt dans le vide, centré et bien plus court
   que la page. Un trait pleine largeur découpe la page ; celui-ci l'articule. */
#services::before {
  content: '';
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  width: min(1180px, 82%);
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%, rgba(91, 47, 31, 0.20) 28%, rgba(91, 47, 31, 0.20) 72%, transparent 100%);
}
.wm-services {
  /* À droite, comme le 03 : à gauche, il se cachait derrière le grand titre. */
  top: clamp(1.5rem, 5vw, 4rem);
  right: clamp(-0.5rem, 1vw, 1.5rem);
  font-size: clamp(9rem, 22vw, 19rem);
  color: rgba(91, 47, 31, 0.11);    /* un peu plus soutenu : le fond est teinté */
}

.services-head {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 3rem;
  align-items: end;
  margin-bottom: clamp(3rem, 6vw, 4.5rem);
}

.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* site, fiche Google, pack */
  gap: 1.4rem;
  align-items: stretch;
}
.service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 22px;
  padding: 2.2rem 2rem;
  box-shadow: var(--shadow-card);
  transition: transform 0.4s cubic-bezier(0.22,1,0.36,1), box-shadow 0.4s, border-color 0.4s;
}
.service-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  border-radius: 22px 22px 0 0;
  background: var(--grad-primary);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.45s cubic-bezier(0.22,1,0.36,1);
}
.service-card:hover {
  transform: translateY(-8px);
  border-color: rgba(217, 98, 43, 0.4);
  box-shadow: 0 32px 64px -28px rgba(91, 47, 31, 0.35);
}
.service-card:hover::before { transform: scaleX(1); }

.service-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.4rem;
}
.service-tag {
  font-family: var(--f-head);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: rgba(217, 98, 43, 0.12);
  padding: 0.42em 0.95em;
  border-radius: 999px;
}
.service-num {
  font-family: var(--f-head);
  font-weight: 700;
  font-size: 1.1rem;
  color: rgba(91, 47, 31, 0.18);
}
.service-icon {
  width: 56px; height: 56px;
  border-radius: 16px;
  background: rgba(91, 47, 31, 0.06);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1.4rem;
  transition: background 0.35s, color 0.35s;
}
.service-card:hover .service-icon {
  background: var(--grad-primary);
  color: var(--white);
}
.service-icon svg { width: 27px; height: 27px; }
.service-card h3 { margin-bottom: 0.7rem; }
.service-card > p { font-size: 0.95rem; flex: 1; }

/* Bloc tarif : placé après la description (qui absorbe l'espace restant), il
   s'aligne donc à la même hauteur d'une carte à l'autre malgré des titres et
   des textes de longueurs différentes. Le filet le détache du descriptif. */
.service-price {
  margin-top: 1.5rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--line);
}
/* Réservé aux lecteurs d'écran : retiré visuellement, mais lu à voix haute.
   Sans ces mentions, « 890 € 499,99 € » est annoncé d'une traite et devient
   incompréhensible — la barre du <s> ne s'entend pas. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Bandeau d'offre : pastille pleine, dans le même vocabulaire que .service-tag
   pour rester cohérent avec le reste des cartes. Assez visible pour signaler
   la promotion, assez sobre pour ne pas virer à l'autocollant de soldes. */
.sp-flag {
  display: inline-block;
  font-family: var(--f-head);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: rgba(217, 98, 43, 0.12);
  padding: 0.38em 0.8em;
  border-radius: 999px;
  margin-bottom: 0.7rem;
}
.service-card--featured .sp-flag {
  color: var(--accent-soft);
  background: rgba(217, 98, 43, 0.22);
}

/* Ancien prix : nettement plus petit et remonté sur la ligne, pour que le
   regard tombe d'abord sur le prix actuel. Le barré doit rester lisible —
   d'où l'épaisseur forcée, la valeur par défaut disparaît à cette taille. */
.sp-amount s {
  font-size: 0.66em;
  font-weight: 700;
  color: rgba(91, 47, 31, 0.62);
  /* 1px : à 22px de corps, un trait épais recouvre la barre horizontale des
     chiffres (le 9, le 8, le 0) et rend le montant illisible. Il doit signaler
     l'annulation, pas concurrencer le chiffre. */
  text-decoration-thickness: 1px;
  margin-right: 0.42em;
  vertical-align: 0.16em;
}
.service-card--featured .sp-amount s { color: rgba(255, 255, 255, 0.72); }

/* « À partir de » : mention de seuil, pas un montant. Nettement plus petite que
   le chiffre et alignée sur le haut de celui-ci, pour qu'on lise « à partir de
   399,99 € » d'un seul tenant sans qu'elle vole la vedette au prix. */
.sp-from {
  /* Sur sa propre ligne, pas en préfixe inline : « À partir de 399,99 € » sur
     une seule ligne déborde dès que la carte se resserre, et le retour à la
     ligne semble alors accidentel. En bloc, la coupure est voulue à toutes
     les largeurs. */
  display: block;
  font-size: 0.4em;
  font-weight: 600;
  line-height: 1.2;
  color: rgba(91, 47, 31, 0.6);
  margin-bottom: 0.15em;
}
.service-card--featured .sp-from { color: rgba(255, 255, 255, 0.7); }

.sp-amount {
  display: block;
  font-family: var(--f-head);
  font-weight: 700;
  font-size: 2.1rem;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.sp-cur { font-size: 0.62em; font-weight: 600; }
.sp-meta {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.78rem;
  line-height: 1.45;
  color: rgba(91, 47, 31, 0.62);
}
.sp-meta strong { font-weight: 600; color: var(--ink); }

.service-card--featured .service-price { border-top-color: rgba(255, 255, 255, 0.16); }
.service-card--featured .sp-amount { color: var(--white); }
.service-card--featured .sp-meta { color: var(--on-deep); }
.service-card--featured .sp-meta strong { color: var(--accent-soft); }

/* Appel à l'action : bouton plein pleine largeur plutôt qu'un lien fléché.
   Sur une grille de trois cartes, un simple lien texte se confond avec le
   descriptif ; la surface pleine dit sans ambiguïté « c'est cliquable ». */
.service-btn {
  margin-top: 1.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  width: 100%;
  padding: 0.95em 1.5em;
  border-radius: 999px;
  font-family: var(--f-head);
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--white);
  background: var(--ink);
  background-image: var(--grad-primary);
  box-shadow: 0 10px 24px -8px rgba(91, 47, 31, 0.5);
  cursor: pointer;
  transition: transform 0.3s, box-shadow 0.3s, background 0.3s, color 0.3s;
}
.service-btn svg { width: 1.05em; height: 1.05em; transition: transform 0.3s; }
.service-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 16px 34px -8px rgba(217, 98, 43, 0.55);
}
.service-btn:hover svg { transform: translateX(4px); }

/* Variante pour la carte sombre : le dégradé bleu s'y noierait. */
.service-btn--light {
  background: var(--white);
  background-image: none;
  color: var(--ink);
  box-shadow: 0 12px 28px -10px rgba(0, 0, 0, 0.5);
}
.service-btn--light:hover {
  background: #FBEFE7;
  color: var(--ink);
  box-shadow: 0 18px 36px -10px rgba(0, 0, 0, 0.55);
}

/* Micro-réassurance sous l'appel à l'action : c'est juste avant de cliquer que
   remontent les dernières objections (« ça va me coûter combien ? », « je vais
   être relancé ? »). Y répondre à cet endroit précis lève le dernier frein. */
.service-note {
  /* Sans ce flex:none, la note hérite du flex:1 de `.service-card > p` et se
     partage l'espace libre avec le descriptif : le bloc tarif de cette carte
     ne tomberait plus à la même hauteur que celui des deux autres. */
  flex: none;
  margin-top: 0.7rem;
  font-size: 0.74rem;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.55);
}

/* Carte mise en avant : carte sombre premium qui tranche */
.service-card--featured {
  background: var(--deep);
  background-image: radial-gradient(120% 100% at 100% 0%, rgba(217, 98, 43,0.28) 0%, transparent 55%);
  border-color: transparent;
  box-shadow: 0 40px 80px -30px rgba(42, 23, 18, 0.6);
}
.service-card--featured::before { transform: scaleX(1); }
.service-card--featured h3 { color: var(--white); }
.service-card--featured > p { color: var(--on-deep); }
.service-card--featured .service-num { color: rgba(255, 255, 255, 0.28); }
.service-card--featured .service-tag {
  color: var(--accent-soft);
  background: rgba(217, 98, 43, 0.22);
}
.service-card--featured .service-icon,
.service-card--featured:hover .service-icon {
  background: var(--grad-primary);
  color: var(--white);
  box-shadow: 0 14px 26px -10px rgba(217, 98, 43, 0.6);
}
.service-card--featured:hover { transform: translateY(-8px); box-shadow: 0 46px 90px -30px rgba(42, 23, 18, 0.7); }

.service-badge {
  position: absolute;
  top: -13px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  font-family: var(--f-head);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--white);
  background: var(--grad-primary);
  padding: 0.45em 1.05em;
  border-radius: 999px;
  white-space: nowrap;
  box-shadow: 0 10px 24px -6px rgba(217, 98, 43, 0.6);
}

/* ---------- Réalisations (galerie pinée sombre, fondu + glissement) ---------- */
#realisations {
  position: relative;
  min-height: 100vh;
  min-height: 100lvh;
  min-height: var(--vhero, 100lvh);
  display: flex;
  flex-direction: column;
  /* Plus de fondu entrant à absorber : le titre peut remonter vers l'arête. */
  padding: clamp(4.5rem, 8vh, 6.5rem) clamp(1.5rem, 5vw, 4rem) 2.5rem;
  /* Bascule dans la nuit : c'est LE geste fort de la page. Brun quasi noir,
     réveillé par deux halos très larges et très doux (l'un chaud en haut à
     droite, l'autre profond en bas) — c'est ce qui empêche l'aplat sombre de
     paraître plat et lui donne sa profondeur. La section démarre directement
     sur --night-1 : aucune couche de fondu, l'arête est franche partout. */
  background:
    radial-gradient(70% 50% at 78% 2%, rgba(217, 98, 43, 0.22) 0%, transparent 60%),
    radial-gradient(90% 60% at 20% 100%, rgba(91, 47, 31, 0.35) 0%, transparent 65%),
    linear-gradient(180deg, var(--night-1) 0%, var(--night-2) 100%);
  color: var(--on-deep);
  overflow: hidden;
}
.wm-real {
  top: clamp(1.5rem, 5vh, 4rem);
  right: clamp(-0.5rem, 1vw, 1.5rem);
  font-size: clamp(9rem, 20vw, 18rem);
  color: rgba(255, 255, 255, 0.045);
}

.real-head {
  max-width: 1160px;
  width: 100%;
  margin: 0 auto clamp(1.5rem, 3vh, 2.5rem);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
}
.real-head h2 { color: var(--white); }
.real-counter {
  font-family: var(--f-head);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--on-deep);
  white-space: nowrap;
}
#real-index { color: var(--accent); font-size: 1.4rem; }

/* ---- Coverflow : scène 3D ---- */
.real-stage {
  position: relative;
  flex: 1;
  width: 100%;
  margin: 0 auto;
  min-height: clamp(500px, 70vh, 720px);
  perspective: 1700px;
  touch-action: pan-y;      /* le glissement horizontal est géré par le JS,
                               le vertical reste le scroll natif de la page */
  cursor: grab;
}
.real-stage.is-grabbing { cursor: grabbing; }

.real-card {
  position: absolute;
  top: 50%; left: 50%;
  /* 46vw : les cartes grandissent avec l'écran (les captures de sites doivent
     être lisibles) sans jamais dépasser 520 px, au-delà de quoi la carte
     mangerait ses voisines. L'écartement du coverflow suit cette largeur —
     voir renderReal() dans main.js, qui la mesure au lieu de la supposer. */
  width: clamp(300px, 46vw, 520px);
  background: #3D2318;
  border: 1px solid var(--line-deep);
  border-radius: 22px;
  overflow: hidden;
  box-shadow: 0 45px 80px -35px rgba(0, 0, 0, 0.8);
  transform-style: preserve-3d;
  will-change: transform, opacity;
  pointer-events: none;     /* seule la carte active redevient cliquable (JS) */
}
.real-card.is-active { pointer-events: auto; }

/* Média : fausse barre de navigateur + capture réelle du site.
   Pas d'aspect-ratio sur .mock — c'est l'image qui porte le sien, la barre
   s'ajoute au-dessus. La hauteur reste donc juste à toutes les largeurs. */
.real-card .mock {
  width: 100%;
  overflow: hidden;
  background: var(--white);
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid var(--line-deep);
}
.mock-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 12px;
  background: #F6EDE6;
}
.mock-bar i { width: 8px; height: 8px; border-radius: 50%; background: rgba(91, 47, 31, 0.18); }
.mock-url {
  margin-left: 8px;
  flex: 1;
  font-size: 0.62rem;
  color: var(--body);
  background: var(--white);
  border-radius: 99px;
  padding: 3px 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Le ratio correspond au recadrage des captures (1440 × 860, soit tout le héro
   des sites) : rien n'est rogné. C'est lui qui donne sa hauteur à la carte —
   pour l'agrandir encore, recadrer les sources plus haut et ajuster ici.
   object-position:top garde le haut du site visible si le ratio évoluait. */
.mock-shot {
  display: block;
  width: 100%;
  aspect-ratio: 1440 / 860;
  object-fit: cover;
  object-position: top center;
  background: #F6EDE6;
}

/* Corps de la carte */
.rc-body { padding: 1.4rem 1.5rem 1.6rem; display: flex; flex-direction: column; }
.rc-body h3 { color: var(--white); font-size: 1.35rem; margin-bottom: 0.35rem; }
.rc-body .real-meta {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-soft);
  margin-bottom: 0.9rem;
}
.rc-desc {
  color: var(--on-deep);
  font-size: 0.9rem;
  line-height: 1.55;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Nature de l'intervention. Distinguer ce qu'on a réalisé de ce qu'on a
   accompagné n'est pas un détail juridique : c'est ce qui rend le portfolio
   crédible. D'où une mention explicite plutôt qu'un tag noyé dans les autres. */
.rc-role {
  display: flex;
  align-items: flex-start;   /* la puce s'aligne sur la 1re ligne, pas au milieu du bloc */
  gap: 0.5rem;
  margin-top: 0.85rem;
  font-family: var(--f-head);
  font-size: 0.74rem;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: 0.02em;
  color: var(--accent-soft);
}
.rc-role::before {
  content: '';
  flex: none;
  width: 6px; height: 6px;
  margin-top: 0.42em;
  border-radius: 50%;
  background: currentColor;
}
.rc-role--alt { color: rgba(255, 255, 255, 0.5); }

.real-tags { display: flex; gap: 0.5rem; margin-top: 1rem; flex-wrap: wrap; }
.real-tags span {
  font-size: 0.72rem;
  font-weight: 500;
  padding: 0.35em 0.85em;
  border: 1px solid var(--line-deep);
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.82);
  background: rgba(255, 255, 255, 0.04);
}
/* ---- Contrôles : pastilles + barre draggable + hint ---- */
.real-controls {
  width: 100%;
  max-width: 620px;
  margin: clamp(1rem, 3vh, 2rem) auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.real-dots { display: flex; gap: 0.55rem; }
.real-dots button {
  width: 9px; height: 9px;
  border-radius: 99px;
  border: none;
  background: rgba(255, 255, 255, 0.22);
  cursor: pointer;
  padding: 0;
  transition: background 0.3s, width 0.3s;
}
.real-dots button.active { background: var(--accent); width: 26px; }

.real-scrub {
  position: relative;
  width: min(520px, 88vw);
  height: 6px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.12);
  cursor: pointer;
  touch-action: none;
}
.real-scrub:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; }
.real-scrub-thumb {
  position: absolute;
  top: 50%;
  left: 0;
  height: 12px;
  border-radius: 99px;
  background: var(--grad-primary);
  transform: translateY(-50%);
  box-shadow: 0 4px 14px -4px rgba(217, 98, 43, 0.8);
  /* width & left posés par le JS */
}
.real-hint {
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  color: rgba(255, 255, 255, 0.45);
  text-align: center;
}

/* ---------- Contact (closing sombre) ---------- */
/* EXACTEMENT la même nuit que #realisations : les deux sections partagent la
   couleur, et c'est le halo lumineux en haut qui signale à lui seul qu'on entre
   dans une nouvelle partie. Chaque section sombre repart en haut sur --night-1
   puis s'assombrit : ce petit rebond de valeur, plus l'arc de lumière, suffisent
   à marquer la coupure — pas besoin de filet ni de changement de teinte. */
#contact {
  background:
    radial-gradient(62% 48% at 50% 0%, rgba(217, 98, 43, 0.20) 0%, transparent 64%),
    linear-gradient(180deg, var(--night-1) 0%, var(--night-2) 100%);
  color: var(--on-deep);
}
.wm-contact {
  top: clamp(1.5rem, 5vh, 4rem);
  left: 50%;
  transform: translateX(-50%);
  font-size: clamp(10rem, 30vw, 26rem);
  color: rgba(255, 255, 255, 0.03);
}
.contact-wrap { text-align: center; }
.contact-wrap h2 { color: var(--white); font-size: clamp(2.3rem, 5vw, 3.6rem); margin-bottom: 1.2rem; }
.contact-wrap .lead { margin: 0 auto; color: var(--on-deep); }

/* Coordonnées : infos épurées, centrées, posées sur le fond (sans encadré) */
.contact-info {
  margin-top: clamp(2.8rem, 6vw, 4rem);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(1.6rem, 4vw, 3.6rem);
  flex-wrap: wrap;
}
.ci-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
}
.ci-label {
  font-family: var(--f-head);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-soft);
}
.ci-value {
  font-size: clamp(1.05rem, 1.7vw, 1.28rem);
  font-weight: 500;
  color: #fff;
  transition: color 0.25s;
}
.ci-value:hover { color: var(--accent); }
/* Réseaux : marques dessinées plutôt que libellés. Chaque lien devient une
   cible carrée — un mot se vise au pixel près, une icône seule a besoin d'une
   surface, surtout au doigt. La hauteur est calée sur celle d'une ligne de
   .ci-value pour que les trois étiquettes (Email / Téléphone / Réseaux)
   restent alignées : .contact-info centre chaque colonne verticalement, une
   rangée d'icônes plus haute décalerait la sienne. */
.ci-socials { display: flex; gap: 0.35rem; }
.ci-socials a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px; height: 34px;
  color: rgba(255, 255, 255, 0.9);
  transition: color 0.25s, transform 0.25s;
}
.ci-socials a svg {
  width: clamp(21px, 1.7vw, 24px);
  height: clamp(21px, 1.7vw, 24px);
}
/* L'accent vif assombrirait l'icône sur ce fond : le survol doit l'éclairer,
   pas la ternir. D'où la version claire de l'accent. */
.ci-socials a:hover { color: var(--accent-soft); transform: translateY(-2px); }
.ci-socials a:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 2px; border-radius: 8px; }
.ci-sep { width: 1px; height: 46px; background: var(--line-deep); }

/* ---------- Footer (sombre, continu avec le contact) ---------- */
footer {
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  padding: 2.2rem 1.5rem;
  background: var(--night-3);   /* point le plus bas du parcours */
  color: rgba(255, 255, 255, 0.6);
}
footer .nav-brand { color: var(--white); }
.footer-wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}
footer p { font-size: 0.85rem; }
.footer-note { color: rgba(255, 255, 255, 0.35); }

/* ---------- Animations d'apparition (état initial géré par GSAP) ---------- */
.reveal { will-change: transform, opacity; }

/* ---------- Fallback sans WebGL / échec de chargement du modèle ---------- */
.no-3d #webgl, .no-3d .hero-scrollhint, .no-3d .hero-bg { display: none; }
.no-3d #hero { height: auto; min-height: 100vh; display: flex; flex-direction: column; justify-content: center; padding: 7rem 1.5rem 4rem; }
.no-3d #nav { transform: translateY(0); }

/* ==========================================================================
   DESKTOP : uniquement une question de RESPIRATION
   --------------------------------------------------------------------------
   Les bandes pleine largeur à arêtes franches ne sont plus un traitement
   desktop : elles sont désormais le comportement par défaut, à toutes les
   largeurs, et les fonds sont définis une seule fois dans chaque section.
   Le dégradé continu qui existait au mobile a été supprimé — il fondait
   #services dans #realisations via --dusk, et la bascule dans la nuit y
   perdait toute sa force.
   Il ne reste donc ici que ce qui dépend vraiment de la largeur : sur grand
   écran on embrasse deux ou trois sections d'un coup, et il faut plus d'air
   autour du contenu pour que la coupure se lise. C'est le blanc autour du
   contenu qui fait la séparation autant que le saut de couleur.
   ========================================================================== */
@media (min-width: 901px) {
  .section { padding-top: clamp(7rem, 13vh, 10.5rem); padding-bottom: clamp(7rem, 13vh, 10.5rem); }
}

/* ---------- Responsive ---------- */
@media (max-width: 1080px) and (min-width: 901px) {
  .services-grid { grid-template-columns: repeat(2, 1fr); }
  #pack { grid-column: 1 / -1; }   /* le pack passe en bandeau plutôt qu'en orphelin */
}

@media (max-width: 900px) {
  #nav nav { display: none; }             /* les liens inline passent dans le panneau latéral */
  .menu-overlay { display: block; }

  /* Header mobile : burger à gauche, symbole seul centré (3e colonne vide
     pour que le logo reste au centre exact malgré le burger). */
  #nav {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 0;
    padding: 0.7rem 0.75rem;
  }
  .nav-toggle { display: inline-flex; grid-area: 1 / 1; justify-self: start; }
  .nav-brand  { grid-area: 1 / 2; justify-self: center; }
  .brand-logo { display: none; }
  .brand-icon { display: block; height: 30px; width: auto; }

  .sec-head, .apropos-head, .services-head { grid-template-columns: 1fr; align-items: start; gap: 1.2rem; }
  .pillars, .process, .contact-grid, .services-grid { grid-template-columns: 1fr; }
  .audience-grid { grid-template-columns: repeat(2, 1fr); }
  .service-card--featured { margin-top: 0.5rem; }

  /* Stepper vertical : plus de ligne horizontale, un léger décalage */
  .process { gap: 1.4rem; }
  .process::before { display: none; }
  .process li { padding-top: 0; padding-left: 3.8rem; }
  .process-num { top: 0.1rem; }

  /* Watermarks discrets sur petit écran */
  .watermark { font-size: clamp(7rem, 34vw, 12rem) !important; }

  .real-head { flex-direction: row; }
  .real-stage { min-height: clamp(400px, 66vh, 520px); }
}

@media (max-width: 640px) {
  .contact-info { flex-direction: column; gap: 1.8rem; }
  .ci-sep { display: none; }

  /* Hero : accroche plus compacte pour dégager l'espace au-dessus du laptop.
     En portrait la caméra recule (camStart.z passe à 15.5 sous un ratio de 0,8,
     cf. main.js) : toute la scène 3D rétrécit et l'écart entre le bas des
     lettres et le capot tombe à ~150 px, alors que le texte, lui, bute sur les
     planchers de ses clamp() — la largeur du viewport ne lui laisse pas de quoi
     suivre. D'où ces valeurs explicites : c'est le seul endroit du hero réglé
     en absolu, et il faut le retoucher si l'accroche s'allonge encore. */
  /* Tailles pilotées par la HAUTEUR et non figées en rem : l'écart entre le bas
     des lettres 3D et le capot vaut ~18 % de la hauteur du hero, il fond donc
     sur un petit téléphone alors qu'un texte en rem, lui, ne bougeait pas —
     c'est ce qui faisait chevaucher l'accroche et le laptop au démarrage. */
  .hero-tagline { transform: translate(-50%, -1.2vh); }
  .hero-eyebrow { font-size: clamp(0.55rem, 1.25vh, 0.7rem); letter-spacing: 0.18em; margin-bottom: 0.28rem; }
  .hero-headline { font-size: clamp(1.02rem, 2.42vh, 1.32rem); margin-bottom: 0.45rem; }
  .hero-sub { font-size: clamp(0.7rem, 1.52vh, 0.85rem); line-height: 1.35; }
}

/* Viewport très bas (portable en 125% d'échelle, téléphone en paysage) : les
   planchers des clamp() du hero, calibrés pour le mobile en portrait, sont les
   seuls à empêcher l'accroche de suivre l'échelle de la 3D. On les abaisse.
   Ce bloc vient APRÈS celui du mobile : sur un petit écran en paysage, les deux
   s'appliquent et c'est bien la taille pilotée par la hauteur qui doit gagner. */
@media (max-height: 560px) {
  .hero-eyebrow { font-size: clamp(0.5rem, min(0.95vw, 1.8vh), 0.78rem); margin-bottom: 0.25rem; }
  .hero-headline { font-size: clamp(1.05rem, min(3.4vw, 4.75vh), 2.5rem); }
  .hero-sub { font-size: clamp(0.78rem, min(1.55vw, 2.4vh), 1.12rem); line-height: 1.4; }
}

/* Petit téléphone EN PORTRAIT (iPhone SE et assimilés) : écran étroit ET bas.
   C'est le cas le plus contraint de tous — l'écart entre le bas des lettres 3D
   et le capot n'y fait qu'une centaine de pixels, alors que l'accroche en
   réclame davantage. Sans ce bloc, le texte chevauche le laptop de ~23px.
   Il DOIT rester après celui de max-height:560px : ce dernier vise les
   téléphones en paysage (larges et bas) et, sans cette correction, il
   ré-agrandissait le texte précisément sur les écrans qui manquent de place.
   Oui, le texte y est petit — c'est le prix à payer pour une accroche de
   quatre lignes sur un écran de cette taille, et cela reste préférable à un
   chevauchement. */
@media (max-width: 640px) and (max-height: 700px) {
  .hero-eyebrow { font-size: clamp(0.45rem, 1.2vh, 0.7rem); margin-bottom: 0.2rem; }
  .hero-headline { font-size: clamp(0.85rem, 2.2vh, 1.32rem); margin-bottom: 0.35rem; }
  .hero-sub { font-size: clamp(0.6rem, 1.35vh, 0.85rem); line-height: 1.3; }
}

@media (max-width: 520px) {
  .btn-nav { display: none; }
  .audience-grid { grid-template-columns: 1fr; }
}

/* ---------- Accessibilité : mouvement réduit ----------
   NB : ne jamais utiliser « * { transition-duration: … } » ici — cela crée des
   transitions sur les pin-spacers de ScrollTrigger et fausse toutes ses mesures. */
@media (prefers-reduced-motion: reduce) {
  .hero-scrollhint-line::after, #loader img, .loader-bar span { animation: none; }
  .btn, .btn svg, #nav, #nav nav a, #nav nav a::after,
  .pillar, .real-dots button, .contact-card a { transition: none; }
}

/* Arrivée par une ancre de carte (#ebook, #accompagnement, #cle-en-main) :
   sans cette marge, le haut de la carte se glisse sous la barre fixe. */
.service-card { scroll-margin-top: 84px; }

/* ==========================================================================
   Services : deux tuiles cliquables + fenêtres d'offres (<dialog>).
   Aucune couleur ni police nouvelle : on réemploie .service-card,
   .service-tag, .sp-amount, .sp-flag, .service-btn et .kicker.
   ========================================================================== */

/* ---------- Tuiles ---------- */
.svc-tile { cursor: pointer; }               /* toute la carte ouvre la fenêtre */
button.service-btn { border: 0; }            /* bordure grise par défaut des <button> */
.svc-tile h3 { font-size: clamp(1.6rem, 3vw, 2.1rem); margin-bottom: 0.4rem; }
.service-card.svc-tile > p { flex: none; }
.svc-tile-icon { width: 64px; height: 64px; border-radius: 18px; }
.svc-tile-icon svg { width: 30px; height: 30px; }
.svc-tile .svc-chips { margin: 1.3rem 0 1.8rem; }
/* margin-top:auto : le prix et le bouton tombent à la même hauteur dans
   les deux tuiles, quelle que soit la longueur de la phrase au-dessus. */
.svc-tile-foot { margin-top: auto; padding-top: 1.3rem; border-top: 1px solid var(--line); }
.svc-from {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: rgba(91, 47, 31, 0.6);
}
.svc-after { display: block; margin-top: 0.4rem; font-size: 0.8rem; color: rgba(91, 47, 31, 0.62); }
/* Tuile sans prix affiché (le pack) : une phrase occupe la place du montant */
.svc-teaser { display: block; font-family: var(--f-head); font-size: 1.05rem; font-weight: 600; line-height: 1.3; color: var(--ink); }
.service-card--featured .svc-teaser { color: var(--white); }

/* Tuile sombre (le pack) : les éléments clairs doivent repasser en clair */
.service-card--featured .svc-chips li { color: var(--accent-soft); background: rgba(255, 255, 255, 0.12); }
.service-card--featured .svc-chips li.svc-chip--accent { color: var(--white); background: rgba(217, 98, 43, 0.45); }
.service-card--featured .svc-tile-foot { border-top-color: rgba(255, 255, 255, 0.16); }
.service-card--featured .svc-from { color: rgba(255, 255, 255, 0.7); }
.service-card--featured .svc-after { color: var(--accent-soft); }

/* Pastilles : les atouts en un coup d'œil, sans phrase à lire */
.svc-chips {
  list-style: none;
  margin: 0.8rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.svc-chips li {
  font-size: 0.8rem;
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink);
  background: rgba(91, 47, 31, 0.06);
  padding: 0.5em 0.85em;
  border-radius: 999px;
}
.svc-chips li.svc-chip--accent {           /* l'offre de lancement ressort */
  font-weight: 600;
  color: var(--accent-ink);
  background: rgba(217, 98, 43, 0.14);
}

/* Réassurance commune, sous les tuiles */
.services-note {
  margin-top: 1.6rem;
  text-align: center;
  font-size: 0.8rem;
  line-height: 1.5;
  color: rgba(91, 47, 31, 0.62);
}

/* ---------- Fenêtre d'offres ---------- */
.svc-modal {
  margin: auto;        /* la remise à zéro globale (margin:0) annulait le centrage natif */
  width: min(820px, calc(100% - 2rem));
  max-width: none;
  max-height: min(88vh, 900px);
  padding: 0;
  border: 0;
  border-radius: 26px;
  background: var(--white);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
/* display seulement quand elle est ouverte : un display posé sans [open]
   afficherait la fenêtre en permanence. */
.svc-modal[open] {
  display: flex;
  flex-direction: column;
  animation: svc-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes svc-in {
  from { opacity: 0; transform: translateY(24px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
.svc-modal::backdrop {
  background: rgba(51, 30, 22, 0.55);
  backdrop-filter: blur(4px);
}
.svc-modal-inner {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;       /* le défilement ne passe pas à la page */
  padding: clamp(1.4rem, 3vw, 2.4rem);
}
.svc-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.6rem;
}
.svc-modal-head h3 { margin-top: 0.8rem; font-size: clamp(1.4rem, 2.6vw, 1.9rem); }
.svc-close {
  flex: none;
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.25s, transform 0.25s;
}
.svc-close:hover { background: var(--bg-soft); transform: rotate(90deg); }
/* Le focus initial de la fenêtre tombe sur la croix : anneau aux couleurs du
   site plutôt que le contour noir du navigateur, et aucun cadre autour de la
   fenêtre elle-même (ni de sa zone qui défile). */
.svc-modal, .svc-modal-inner { outline: none; }
.svc-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.svc-close svg { width: 20px; height: 20px; }

/* En-tête : grande icône en dégradé, pour distinguer d'un coup d'œil */
.svc-modal-title { display: flex; align-items: flex-start; gap: 1rem; }
.svc-modal-icon {
  flex: none;
  width: 56px; height: 56px;
  border-radius: 16px;
  background: var(--grad-primary);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 14px 26px -10px rgba(217, 98, 43, 0.6);
}
.svc-modal-icon svg { width: 26px; height: 26px; }
.svc-modal-head h3 { margin-top: 0.55rem; }
.svc-intro { margin-top: 0.3rem; font-size: 0.92rem; color: var(--body); }

/* Groupes d'offres (« On s'occupe de tout » / « Vous préférez faire vous-même ? ») */
.offer-group + .offer-group {
  margin-top: 2rem;
  padding-top: 1.8rem;
  border-top: 1px solid var(--line);
}
.offer-group-head { margin-bottom: 1rem; }
.offer-group-title { margin-top: 0.6rem; font-size: 1.15rem; }
.offer-list { display: grid; gap: 0.8rem; }

/* Une offre = une carte : nom + prix, deux boutons, puis le détail */
.offer {
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--white);
  box-shadow: var(--shadow-card);
  transition: border-color 0.3s;
}
.offer.is-open { border-color: rgba(217, 98, 43, 0.45); }
/* « OFFERT » à la place d'un prix (entretien) */
.offer .svc-price--offert { color: var(--accent); text-transform: uppercase; letter-spacing: 0.02em; }   /* .offer : doit passer devant .svc-price, défini plus bas */
.svc-price--offert + .offer-price-note { color: var(--accent-ink); font-weight: 600; }

/* Bandeau « Offres de lancement », en tête de chaque fenêtre */
.launch-banner {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin: -0.4rem 0 1.6rem;
  padding: 0.95rem 1.2rem;
  border-radius: 16px;
  color: var(--white);
  background: var(--grad-primary);
  box-shadow: 0 14px 30px -14px rgba(217, 98, 43, 0.7);
}
.launch-icon {
  flex: none;
  width: 40px; height: 40px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.18);
  display: flex;
  align-items: center;
  justify-content: center;
}
.launch-icon svg { width: 22px; height: 22px; }
.launch-text strong { display: block; font-family: var(--f-head); font-size: 1.05rem; }
.launch-text span { font-size: 0.88rem; line-height: 1.4; color: rgba(255, 255, 255, 0.9); }
.offer-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.9rem 1rem;
}
.offer-icon {
  width: 44px; height: 44px;
  border-radius: 12px;
  background: rgba(91, 47, 31, 0.06);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
}
.offer-icon svg { width: 22px; height: 22px; }
.offer .sp-flag { margin-bottom: 0.35rem; }
.offer-name { font-family: var(--f-head); font-size: 1.05rem; font-weight: 600; line-height: 1.25; }
.offer-sub { display: block; margin-top: 0.15rem; font-size: 0.82rem; line-height: 1.4; color: var(--body); }
.offer-price { text-align: right; }
.offer-price .svc-from { margin-bottom: 0.2rem; }   /* « À partir de » juste au-dessus du montant */
.offer-price-note {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.72rem;
  white-space: nowrap;
  color: rgba(91, 47, 31, 0.6);
}
/* Ancien tarif mensuel barré, sur la même ligne que le nouveau */
.offer-price-note s { color: rgba(91, 47, 31, 0.45); text-decoration-thickness: 1px; margin-right: 0.2em; }
.svc-price {
  font-family: var(--f-head);
  font-weight: 700;
  font-size: 1.6rem;
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
  color: var(--ink);
}
.svc-price s {
  font-size: 0.62em;
  font-weight: 700;
  color: rgba(91, 47, 31, 0.55);
  text-decoration-thickness: 1px;
  margin-right: 0.35em;
  vertical-align: 0.14em;
}

.offer-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1rem; }
.offer-btn {
  flex: 1 1 0;
  min-width: 10rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.75em 1.1em;
  border: 0;
  border-radius: 999px;
  font-family: var(--f-head);
  font-weight: 600;
  font-size: 0.86rem;
  cursor: pointer;
  transition: transform 0.25s, box-shadow 0.25s, background 0.25s;
}
.offer-btn svg { width: 1em; height: 1em; transition: transform 0.3s; }
.offer-btn--ghost { background: rgba(91, 47, 31, 0.07); color: var(--ink); }
.offer-btn--ghost:hover { background: rgba(91, 47, 31, 0.12); }
.offer-btn--ghost[aria-expanded="true"] svg { transform: rotate(180deg); }
.offer-btn--solid {
  color: var(--white);
  background: var(--ink);
  background-image: var(--grad-primary);
  box-shadow: 0 10px 22px -10px rgba(91, 47, 31, 0.55);
}
.offer-btn--solid:hover { transform: translateY(-2px); }
.offer-btn--solid:hover svg { transform: translateX(3px); }
.offer-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.offer-detail { margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed var(--line); }
.svc-checks { list-style: none; margin: 0; padding: 0; }
.svc-checks li {
  position: relative;
  padding-left: 1.55rem;
  margin-bottom: 0.55rem;
  font-size: 0.88rem;
  line-height: 1.45;
  color: var(--ink);
}
.svc-checks li::before {
  content: '';
  position: absolute;
  left: 0.1rem;
  top: 0.42em;
  width: 0.72rem;
  height: 0.4rem;
  border-left: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}

/* Téléphone : offres empilées et fenêtre en plein écran */
@media (max-width: 640px) {
  .offer-head { grid-template-columns: auto 1fr; }
  .offer-price {                        /* le prix passe sous le nom */
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    text-align: left;
  }
  .offer-price-note { margin-top: 0; }
  /* Fenêtre en plein écran. Le panneau « qui monte du bas » (margin: auto 0 0
     + max-height en dvh) était mal placé par les navigateurs intégrés aux
     applis (Instagram sur iOS) : la fenêtre s'ouvrait à moitié sous l'écran.
     Ici, position et dimensions sont imposées, sans marge automatique ni
     hauteur d'écran à deviner. env(safe-area-inset-*) évite l'encoche et la
     barre gestuelle. */
  .svc-modal {
    position: fixed;
    inset: 0;
    width: 100%;
    max-width: 100%;
    /* Hauteur : on vise volontairement TROP GRAND plutôt que juste.
       Sur iPhone, les barres du navigateur se rétractent au défilement : toute
       hauteur mesurée à un instant donné (100 %, 100dvh, mesure en JS) devient
       fausse dès que les barres reviennent, et une bande du site réapparaît
       sous la fenêtre. 100lvh = hauteur de l'écran barres rétractées, donc
       toujours supérieure ou égale au visible : plus aucun espace, quel que
       soit le moment où la fenêtre est ouverte. La contrepartie — un bas de
       fenêtre qui peut passer sous une barre — est réglée par la marge basse
       généreuse de .svc-modal-inner. */
    height: 100%;
    height: 100lvh;
    max-height: none;
    margin: 0;
    border-radius: 0;
  }
  .svc-modal-inner { -webkit-overflow-scrolling: touch; }
  /* Aucune marge en haut : c'est l'en-tête lui-même qui la porte, sinon une
     bande vide apparaît au-dessus de la barre, entre elle et le bord de l'écran. */
  .svc-modal-inner {
    /* Marge basse large : le dernier bouton reste atteignable même quand la
       barre du navigateur réapparaît par-dessus le bas de la fenêtre. */
    padding: 0 1.2rem calc(5.5rem + env(safe-area-inset-bottom));
  }
  /* Voile OPAQUE, de la couleur du fond du site : quoi qu'il arrive avec les
     barres du navigateur, la bande éventuellement laissée sous la fenêtre ne
     montre plus le site — elle se confond avec elle. Le voile, lui, est
     toujours dimensionné sur l'écran entier. */
  .svc-modal::backdrop {
    background: var(--white);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* L'en-tête, donc la croix, reste visible pendant qu'on fait défiler. Même
     traitement que la barre de navigation du site : fond translucide + flou,
     on voit le contenu passer dessous au lieu d'un bandeau blanc opaque.
     Le padding du haut intègre l'encoche : la barre touche le bord de l'écran. */
  .svc-modal-head {
    position: sticky;
    top: 0;
    z-index: 2;
    margin: 0 -1.2rem 1.2rem;
    padding: calc(0.9rem + env(safe-area-inset-top)) 1.2rem 0.9rem;
    background: rgba(255, 255, 255, 0.82);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--line);
  }
}
/* Écran tactile : la page derrière ne doit pas défiler sous le doigt. Pas sur
   ordinateur, où masquer la barre de défilement décalerait toute la page. */
@media (pointer: coarse) {
  html:has(.svc-modal[open]), html:has(.svc-modal[open]) body { overflow: hidden; }
  /* Fenêtre ouverte : on masque tout le site derrière. Deuxième sécurité contre
     la bande qui réapparaissait en bas quand les barres du navigateur se
     rétractent — il n'y a alors plus rien à voir derrière, juste du blanc.
     visibility (et non display) : aucune remise en page, donc aucun risque
     pour le zoom du hero ni pour les animations au défilement. */
  html:has(.svc-modal[open]) main,
  html:has(.svc-modal[open]) footer,
  html:has(.svc-modal[open]) #nav { visibility: hidden; }
  html:has(.svc-modal[open]) .svc-modal,
  html:has(.svc-modal[open]) .svc-modal * { visibility: visible; }
}
@media (prefers-reduced-motion: reduce) {
  .svc-modal[open] { animation: none; }
}

/* ==========================================================================
   Formulaire de contact (sur fond sombre)
   ========================================================================== */
.contact-form {
  max-width: 720px;
  margin: clamp(2.2rem, 5vw, 3rem) auto 0;
  padding: clamp(1.4rem, 3vw, 2.2rem);
  text-align: left;
  border-radius: 24px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--line-deep);
}
.cf-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.1rem; }
.cf-field { display: flex; flex-direction: column; gap: 0.45rem; }
.cf-field--full { grid-column: 1 / -1; }
.cf-field > span {
  font-family: var(--f-head);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-soft);
}
/* 1rem minimum : en dessous, iPhone zoome sur le champ au toucher */
.cf-field input,
.cf-field select,
.cf-field textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  color: #fff;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 14px;
  padding: 0.8em 1em;
  transition: border-color 0.25s, background 0.25s;
}
.cf-field textarea { min-height: 8rem; resize: vertical; }
.cf-field select {
  appearance: none;
  padding-right: 2.6em;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F5CBB2' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1em center;
  background-size: 1em;
}
.cf-field select option,
.cf-field select optgroup { color: var(--ink); background: #fff; }
.cf-field ::placeholder { color: rgba(255, 255, 255, 0.4); }
.cf-field input:focus,
.cf-field select:focus,
.cf-field textarea:focus {
  outline: none;
  border-color: var(--accent);
  background-color: rgba(255, 255, 255, 0.09);
}
.cf-hp { position: absolute; left: -9999px; }   /* piège à robots, invisible */
.cf-submit { margin-top: 1.4rem; }
.cf-submit:disabled { opacity: 0.6; cursor: wait; }
.cf-status { min-height: 1.4em; margin-top: 0.9rem; font-size: 0.92rem; text-align: center; }
.cf-status.is-ok { color: var(--accent-soft); font-weight: 600; }
.cf-status.is-error { color: #FFB4A2; }
.cf-legal {
  margin-top: 0.3rem;
  font-size: 0.74rem;
  line-height: 1.45;
  text-align: center;
  color: rgba(255, 255, 255, 0.5);
}
@media (max-width: 640px) {
  .cf-grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Écrans tactiles : neutraliser les effets de survol.
   Sur iPhone, :hover se déclenche au toucher et reste actif : en faisant
   défiler avec le doigt posé sur un bouton, on voit le bouton « s'enfoncer »
   comme s'il avait été pressé. Ces règles rendent le défilement franc.
   ========================================================================== */
@media (hover: none) {
  .service-card:hover,
  .svc-tile:hover,
  .service-card--featured:hover,
  .offer-btn--solid:hover,
  .service-btn:hover,
  .btn:hover { transform: none; box-shadow: inherit; }
  .service-card:hover::before { transform: scaleX(0); }
  .service-card--featured:hover::before { transform: scaleX(1); }
  .offer-btn--ghost:hover { background: rgba(91, 47, 31, 0.07); }
  .svc-close:hover { transform: none; background: var(--white); }
  .offer-btn--solid:hover svg,
  .service-btn:hover svg,
  .svc-link:hover svg { transform: none; }
}

/* ==========================================================================
   Pages de commande de l'e-book (/ebook/ et /ebook/merci.html)
   Pages autonomes : pas de scène 3D, pas de défilement animé. On réemploie
   les mêmes jetons de couleur, les mêmes polices et les mêmes composants
   (.service-tag, .svc-price, .svc-checks, .service-btn) que le site.
   ========================================================================== */
.page-achat {
  background: linear-gradient(180deg, var(--mist-1) 0%, var(--mist-2) 100%);
  min-height: 100vh;
  min-height: 100lvh;
  display: flex;
  flex-direction: column;
}
.achat-entete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem clamp(1.2rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.achat-retour {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--f-head);
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--ink);
}
.achat-retour svg { width: 1.05em; height: 1.05em; transition: transform 0.3s; }
.achat-retour:hover svg { transform: translateX(-3px); }
.achat-logo { height: 26px; width: auto; }

.achat-wrap {
  flex: 1;
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(1.8rem, 5vw, 3.5rem) clamp(1.2rem, 4vw, 2.5rem) 3rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.6rem, 4vw, 3rem);
  align-items: start;
}
.achat-wrap--merci { grid-template-columns: minmax(0, 620px); justify-content: center; }

.achat-produit h1 { margin: 0.9rem 0 0.6rem; font-size: clamp(1.8rem, 3.6vw, 2.5rem); }
.achat-sous { font-size: 1.02rem; line-height: 1.6; color: var(--body); }
.achat-prix {
  margin: 1.6rem 0 1.4rem;
  padding-top: 1.3rem;
  border-top: 1px solid var(--line);
}
.achat-prix .svc-price { font-size: 2.4rem; }
.achat-prix-note { display: block; margin-top: 0.4rem; font-size: 0.82rem; color: rgba(91, 47, 31, 0.62); }
.achat-liste { margin-bottom: 1.6rem; }

.achat-reassurance {
  padding: 1.1rem 1.2rem;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.7);
  border: 1px solid var(--line);
}
.achat-reassurance p { font-size: 0.86rem; line-height: 1.5; color: var(--body); }
.achat-legal { margin-top: 0.7rem; font-size: 0.78rem; line-height: 1.45; color: rgba(91, 47, 31, 0.62); }
.achat-legal a, .achat-aide a, .achat-pied a { color: var(--accent-ink); font-weight: 600; }
.achat-aide { margin-top: 1.1rem; font-size: 0.86rem; color: var(--body); }

/* Cadre du formulaire de carte. Stripe l'affiche dans un cadre isolé : on lui
   donne juste un fond blanc et de l'air, sans tenter de le styler. */
.achat-paiement { position: sticky; top: 1.5rem; }
.achat-cadre {
  min-height: 420px;
  padding: clamp(1rem, 2.5vw, 1.6rem);
  border-radius: 22px;
  background: var(--white);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
}
.achat-etat {
  display: block;
  padding: 2.5rem 1rem;
  text-align: center;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--body);
}
.achat-etat--erreur { color: var(--accent-ink); font-weight: 500; }
.achat-lien { display: inline-block; margin-top: 0.6rem; color: var(--accent-ink); font-weight: 600; }

/* Page de remerciement */
.achat-merci { text-align: center; }
.achat-merci .service-btn { max-width: 360px; margin: 1.6rem auto 0; }
.achat-telecharger svg { width: 1.05em; height: 1.05em; }
.achat-merci .achat-legal { margin-top: 1.2rem; }

.achat-pied {
  padding: 1.4rem clamp(1.2rem, 4vw, 2.5rem) 2rem;
  text-align: center;
  font-size: 0.8rem;
  color: rgba(91, 47, 31, 0.6);
  border-top: 1px solid var(--line);
}

@media (max-width: 860px) {
  .achat-wrap { grid-template-columns: 1fr; }
  .achat-paiement { position: static; }
}
