/* ==========================================================================
   HBT SHIFT — feuille de style principale
   Palette : fond clair + dégradé de marque (turquoise → vert → citron)
   Les noms de tokens (--void, --white…) datent du thème sombre d'origine et sont
   conservés pour ne pas toucher au HTML : --void est le fond de page, --white le
   texte principal.
   ========================================================================== */

/* --------------------------------------------------------------- 0. Polices
   Hébergées sur le site (assets/fonts/), aucune connexion à Google Fonts.
   Fichiers : versions variables de Fontsource 5.3.0, sous-ensemble latin
   (français, œ et € compris), non modifiés, licence SIL OFL 1.1 (textes dans
   assets/fonts/). Mêmes versions que celles servies par Google Fonts.
   - Les plages de graisse déclarées sont celles des fichiers variables.
   - Le fichier de Space Grotesk est préchargé dans le <head> des pages (police du titre).
   Remplacer un fichier = changer son nom (les polices sont en cache un an, voir _headers). */
/* Depuis le 2026-09-26 (couche immersive v2) : Space Grotesk pour les titres,
   DM Sans pour le texte, JetBrains Mono inchangé pour les sur-titres. Choix et
   planche de comparaison : README, « Les polices ». Bricolage Grotesque et
   Manrope restent dans assets/fonts/ mais ne sont plus déclarées, donc plus
   téléchargées. Fichiers Fontsource 5.3.0 (@fontsource-variable), sous-ensemble
   latin, non modifiés, licence SIL OFL 1.1 (assets/fonts/OFL-*.txt). */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/space-grotesk-latin-wght-normal.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: "DM Sans";
  font-style: normal;
  font-weight: 100 1000;
  font-display: swap;
  src: url("fonts/dm-sans-latin-wght-normal.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;
}
/* Polices de repli ajustées : Arial redimensionné aux métriques des polices du
   site, pour que le passage du repli à la vraie police ne décale rien (CLS).
   Valeurs calculées avec fontTools sur les fichiers ci-dessus : Space Grotesk
   instanciée en 700 contre Arial Bold (les titres), DM Sans en 400 contre Arial. */
@font-face {
  font-family: "Space Grotesk Repli";
  src: local("Arial Bold"), local("Arial-BoldMT"), local("Arial");
  font-weight: 700;
  size-adjust: 102.89%;
  ascent-override: 95.64%;
  descent-override: 28.38%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "DM Sans Repli";
  src: local("Arial"), local("ArialMT");
  size-adjust: 104.96%;
  ascent-override: 94.51%;
  descent-override: 29.53%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("fonts/jetbrains-mono-latin-wght-normal.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;
}

/* --------------------------------------------------------- 1. Design tokens */
:root {
  /* Fonds */
  --void: #ffffff;
  --ink: #f4f7f5;
  --panel: #f2f5f3;
  --panel-2: #e8eeea;
  --line: rgba(10, 20, 14, 0.10);
  --line-strong: rgba(10, 20, 14, 0.2);

  /* Textes */
  --white: #0b1410;
  --fog: #4c5a52;
  --fog-dim: #58645c;

  /* Marque (extraits du logo) */
  --teal: #12b9c4;
  --green: #2fc46a;
  --lime: #b9de1e;
  /* Versions foncées des couleurs de marque, lisibles en texte sur fond clair */
  --teal-ink: #0b8f99;
  --green-ink: #1f8f4e;
  --grad: linear-gradient(96deg, #12b9c4 0%, #2fc46a 48%, #b9de1e 100%);
  --grad-text: linear-gradient(96deg, #0ea3ad 0%, #22a65a 48%, #8fb011 100%);
  --grad-soft: linear-gradient(96deg, rgba(18, 185, 196, 0.16), rgba(185, 222, 30, 0.16));

  /* Typo */
  --display: "Space Grotesk", "Space Grotesk Repli", "Helvetica Neue", sans-serif;
  --body: "DM Sans", "DM Sans Repli", -apple-system, BlinkMacSystemFont, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", monospace;

  /* Rythme */
  --wrap: 1200px;
  --gut: clamp(20px, 5vw, 56px);
  --section: clamp(80px, 11vw, 150px);
  --r: 4px;
  --r-lg: 14px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ------------------------------------------------------------- 2. Reset/base */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 92px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--void);
  color: var(--white);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.7;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Grain très léger sur toute la page — donne de la matière au fond clair */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.02;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.03em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { margin: 0; padding: 0; list-style: none; }

::selection { background: var(--lime); color: #050806; }

:focus-visible {
  outline: 2px solid var(--teal-ink);
  outline-offset: 3px;
  border-radius: 2px;
}

/* -------------------------------------------------------- 3. Utilitaires mise en page */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gut);
}

.section { padding-block: var(--section); position: relative; }
.section--panel { background: var(--panel); border-block: 1px solid var(--line); }

.eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--fog);
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.eyebrow::before {
  content: "";
  width: 26px;
  height: 1px;
  background: var(--grad);
}

.h-sec { font-size: clamp(2.1rem, 5.4vw, 3.9rem); margin-top: 22px; }
.lead {
  color: var(--fog);
  font-size: clamp(1rem, 1.7vw, 1.18rem);
  max-width: 60ch;
  margin-top: 22px;
  text-wrap: pretty;
}

.grad-text {
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Filet décoratif repris du logo : trait dégradé + pastilles aux extrémités */
.rule {
  position: relative;
  height: 1px;
  background: linear-gradient(90deg, rgba(18, 185, 196, 0.6), rgba(185, 222, 30, 0.6));
  margin-block: 46px;
}
.rule::before,
.rule::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  transform: translateY(-50%);
}
.rule::before { left: -1px; border: 1.5px solid var(--teal); }
.rule::after { right: -1px; border: 1.5px solid var(--lime); }

/* ------------------------------------------------------------- 4. Boutons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--body);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.01em;
  padding: 16px 28px;
  border-radius: var(--r);
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.25s var(--ease), background 0.25s, color 0.25s, border-color 0.25s;
  position: relative;
  overflow: hidden;
  white-space: nowrap;
}
.btn svg { flex: 0 0 auto; }

.btn--primary { background: var(--grad); color: #05120a; }
.btn--primary::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(96deg, #b9de1e, #2fc46a 52%, #12b9c4);
  opacity: 0;
  transition: opacity 0.3s;
}
.btn--primary > * { position: relative; z-index: 1; }
.btn--primary:hover { transform: translateY(-2px); }
.btn--primary:hover::after { opacity: 1; }

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

.btn--sm { padding: 12px 20px; font-size: 14px; }

/* --------------------------------------------------------------- 5. Header */
.head {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 255, 255, 0.78);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s, background 0.3s;
}
.head.is-stuck { border-bottom-color: var(--line); background: rgba(255, 255, 255, 0.92); }

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 78px;
}

.brand { display: flex; align-items: center; gap: 12px; }
.brand img { height: 40px; width: auto; }
.brand-txt { display: flex; flex-direction: column; line-height: 1; }
.brand-txt b {
  font-family: var(--display);
  font-size: 20px;
  letter-spacing: -0.02em;
  font-weight: 800;
}
.brand-txt b span { background: var(--grad-text); -webkit-background-clip: text; background-clip: text; color: transparent; }
.brand-txt small {
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.19em;
  color: var(--fog-dim);
  text-transform: uppercase;
  margin-top: 5px;
}

.menu { display: flex; align-items: center; gap: 30px; }
.menu a {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--fog);
  position: relative;
  padding-block: 4px;
  transition: color 0.2s;
}
.menu a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 1.5px;
  background: var(--grad);
  transition: width 0.3s var(--ease);
}
.menu a:hover { color: var(--white); }
.menu a:hover::after { width: 100%; }

.nav-cta { display: flex; align-items: center; gap: 14px; }

.burger {
  display: none;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  background: none;
  cursor: pointer;
  padding: 0;
}
.burger i {
  display: block;
  width: 18px;
  height: 1.5px;
  background: var(--white);
  margin: 4px auto;
  transition: transform 0.3s var(--ease), opacity 0.2s;
}
.burger[aria-expanded="true"] i:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.burger[aria-expanded="true"] i:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] i:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* ----------------------------------------------------------------- 6. Hero */
.hero {
  position: relative;
  padding-top: clamp(56px, 8vw, 96px);
  padding-bottom: clamp(70px, 9vw, 120px);
  overflow: hidden;
}

/* Halo dégradé + éclats obliques inspirés du "H" du logo */
.hero-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.hero-bg .glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(110px);
  opacity: 0.5;
}
.hero-bg .glow-1 { width: 620px; height: 620px; top: -220px; right: -120px; background: rgba(18, 185, 196, 0.3); }
.hero-bg .glow-2 { width: 560px; height: 560px; bottom: -260px; left: -180px; background: rgba(185, 222, 30, 0.16); }
.hero-bg .shard {
  position: absolute;
  width: 1px;
  height: 150%;
  top: -25%;
  background: linear-gradient(180deg, transparent, rgba(47, 196, 106, 0.28), transparent);
  transform: rotate(11deg);
}
.hero-bg .shard:nth-child(3) { left: 12%; }
.hero-bg .shard:nth-child(4) { left: 46%; opacity: 0.5; }
.hero-bg .shard:nth-child(5) { left: 78%; opacity: 0.7; }

.hero-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1.12fr 0.88fr;
  gap: clamp(40px, 6vw, 80px);
  align-items: center;
}

.hero h1 {
  font-size: clamp(2.45rem, 5vw, 4.5rem);
  margin-top: 26px;
  letter-spacing: -0.04em;
}
.hero h1 em { font-style: normal; display: inline-block; }
.nowrap { white-space: nowrap; }

.hero .lead { font-size: clamp(1.02rem, 1.9vw, 1.22rem); margin-top: 28px; }

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 38px;
}

.trust {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  margin-top: 42px;
  padding-top: 30px;
  border-top: 1px solid var(--line);
}
.trust li {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fog);
  display: flex;
  align-items: center;
  gap: 9px;
}
.trust li::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 8px rgba(47, 196, 106, 0.9);
}

/* Composition visuelle du hero : cartes flottantes + filigrane du logo */
.hero-art { position: relative; min-height: 480px; }
.hero-art .logo-stage {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}
/* Halo diffus derrière le logo, pour l'ancrer dans le fond */
.hero-art .logo-stage::before {
  content: "";
  position: absolute;
  width: 78%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(47, 196, 106, 0.22), transparent 68%);
  filter: blur(50px);
}

/* Thème clair : la vidéo du logo (fond noir fusionné en mode screen) n'est plus
   utilisable, le mode screen blanchit le logo sur fond clair. On affiche le logo
   fixe à fond transparent, avec la même animation de flottement. */
.hero-art .logo-stage .logo-video { display: none; }
.hero-art .logo-stage .logo-static {
  display: block;
  position: relative;
  width: 78%;
  max-width: none;
  height: auto;
  filter: drop-shadow(0 24px 40px rgba(31, 143, 78, 0.22));
  animation: float 9s ease-in-out infinite, fade-in 1s var(--ease) 0.35s backwards;
}

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-12px); }
}

/* ------------------------------------------------------------- 7. Bandeau défilant */
.ticker {
  border-block: 1px solid var(--line);
  background: var(--ink);
  overflow: hidden;
  padding-block: 20px;
  position: relative;
}
.ticker::before,
.ticker::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 120px;
  z-index: 2;
  pointer-events: none;
}
.ticker::before { left: 0; background: linear-gradient(90deg, var(--ink), transparent); }
.ticker::after { right: 0; background: linear-gradient(270deg, var(--ink), transparent); }

.ticker-track {
  display: flex;
  width: max-content;
  animation: slide 42s linear infinite;
}
.ticker-track span {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.1rem, 2.3vw, 1.6rem);
  letter-spacing: -0.02em;
  color: var(--fog-dim);
  padding-inline: 26px;
  display: flex;
  align-items: center;
  gap: 52px;
  white-space: nowrap;
}
.ticker-track span::after {
  content: "";
  width: 7px;
  height: 7px;
  background: var(--grad);
  transform: rotate(45deg);
  flex: 0 0 auto;
}
@keyframes slide { to { transform: translateX(-50%); } }

/* --------------------------------------------------------------- 8. Constat */
.pain-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  margin-top: 56px;
}
.pain {
  background: var(--void);
  padding: 40px 34px 44px;
  transition: background 0.35s;
}
.pain:hover { background: var(--panel); }
.pain .num {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--fog-dim);
}
.pain h3 { font-size: 1.34rem; margin-top: 20px; letter-spacing: -0.02em; min-height: 2.75rem; }
.pain p { color: var(--fog); font-size: 15px; margin-top: 14px; }

/* -------------------------------------------------------------- 9. Services */
.svc-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 22px;
  margin-top: 60px;
}
.svc {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 42px 38px 46px;
  background: linear-gradient(160deg, var(--panel), var(--void) 70%);
  overflow: hidden;
  transition: border-color 0.35s, transform 0.35s var(--ease);
}
.svc::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease);
}
.svc:hover { border-color: var(--line-strong); transform: translateY(-4px); }
.svc:hover::before { transform: scaleX(1); }

.svc .idx {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--fog-dim);
}
.svc h3 { font-size: clamp(1.35rem, 2.4vw, 1.7rem); margin-top: 26px; }
.svc p { color: var(--fog); font-size: 15.5px; margin-top: 16px; max-width: 46ch; }
.svc ul { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 8px; }
.svc ul li {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fog);
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: 6px 12px;
}

/* --------------------------------------------------------------- 10. Offres */
.price-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  margin-top: 60px;
  align-items: start;
}
.price {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 38px 32px 36px;
  background: var(--void);
  display: flex;
  flex-direction: column;
  height: 100%;
  transition: border-color 0.3s, transform 0.35s var(--ease);
}
.price:hover { border-color: var(--line-strong); transform: translateY(-4px); }

.price--star {
  border-color: transparent;
  background:
    linear-gradient(var(--void), var(--void)) padding-box,
    var(--grad) border-box;
  border: 1px solid transparent;
  position: relative;
  box-shadow: 0 30px 70px -30px rgba(47, 196, 106, 0.35);
}
.price--star::after {
  content: "Le plus demandé";
  position: absolute;
  top: -11px;
  left: 32px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  background: var(--grad);
  color: #05120a;
  padding: 4px 12px;
  border-radius: 100px;
  font-weight: 700;
}

.price h3 { font-size: 1.55rem; }
.price .who { color: var(--fog); font-size: 14px; margin-top: 10px; min-height: 42px; }
.price .amount {
  font-family: var(--display);
  font-size: 3rem;
  font-weight: 800;
  letter-spacing: -0.045em;
  margin-top: 26px;
  line-height: 1;
}
.price .amount sup { font-size: 0.95rem; font-weight: 600; vertical-align: super; color: var(--fog); margin-left: 4px; }
.price .from { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--fog-dim); display: block; margin-bottom: 8px; }

.price .feats { margin-top: 30px; display: grid; gap: 13px; flex: 1; }
.price .feats li {
  display: flex;
  gap: 11px;
  font-size: 14.5px;
  color: var(--fog);
  line-height: 1.5;
}
.price .feats li::before {
  content: "";
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  margin-top: 4px;
  border-radius: 50%;
  background: var(--grad-soft);
  border: 1px solid rgba(47, 196, 106, 0.45);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.6 6.2l2.2 2.2 4.6-4.8' stroke='%232fc46a' stroke-width='1.7' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 11px;
  background-position: center;
  background-repeat: no-repeat;
}
.price .btn { margin-top: 32px; width: 100%; }

.price-note {
  margin-top: 26px;
  font-size: 13.5px;
  color: var(--fog-dim);
  text-align: center;
}
.lien-chat { color: var(--green-ink); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.lien-chat:hover { color: var(--teal-ink); }

/* -------------------------------------------------------------- 11. Méthode */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; margin-top: 64px; }
.step { position: relative; padding-top: 34px; display: flex; flex-direction: column; }
.step::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
}
.step::after {
  content: "";
  position: absolute;
  top: -4px;
  left: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--void);
  border: 1.5px solid var(--green);
}
.step:first-child::after { border-color: var(--teal); }
.step:last-child::after { border-color: var(--lime); }
.step .n {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--fog-dim);
}
.step h3 { font-size: 1.28rem; margin-top: 16px; }
.step p { color: var(--fog); font-size: 14.5px; margin-top: 12px; }
.step .when {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-top: auto;
  padding-top: 18px;
  color: var(--green-ink);
}

/* --------------------------------------------------------- 12. Réalisations */
.work {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(30px, 5vw, 64px);
  align-items: center;
  margin-top: 60px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: clamp(28px, 4vw, 52px);
  background: linear-gradient(150deg, var(--panel), var(--void) 65%);
}
.work-shot {
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel-2);
  box-shadow: 0 30px 70px -24px rgba(11, 20, 16, 0.28);
}
.work-shot .chrome {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  background: rgba(10, 20, 14, 0.03);
}
.work-shot .chrome i { width: 8px; height: 8px; border-radius: 50%; background: var(--line-strong); }
.work-shot .chrome .url {
  margin-left: 10px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--fog-dim);
  letter-spacing: 0.04em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.work-shot img { width: 100%; height: auto; display: block; }
.work-shot .fallback {
  aspect-ratio: 16 / 11;
  display: grid;
  place-content: center;
  gap: 10px;
  text-align: center;
  padding: 30px;
  background:
    radial-gradient(120% 90% at 20% 0%, rgba(18, 185, 196, 0.14), transparent 60%),
    radial-gradient(120% 90% at 90% 100%, rgba(185, 222, 30, 0.12), transparent 60%);
}
.work-shot .fallback b { font-family: var(--display); font-size: 1.5rem; letter-spacing: -0.02em; }
.work-shot .fallback span { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--fog-dim); }

.work-meta h3 { font-size: clamp(1.6rem, 3vw, 2.15rem); margin-top: 18px; }
.work-meta p { color: var(--fog); margin-top: 18px; font-size: 15.5px; }
.work-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 26px; }
.work-tags li {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: 6px 12px;
  color: var(--fog);
}
.work-quote {
  margin-top: 30px;
  padding-left: 20px;
  border-left: 2px solid;
  border-image: var(--grad) 1;
  font-size: 15.5px;
  color: var(--white);
  font-style: italic;
}
.work-quote cite { display: block; font-style: normal; font-size: 13px; color: var(--fog-dim); margin-top: 10px; font-family: var(--mono); letter-spacing: 0.06em; }

/* ------------------------------------------------------------- 13. Inclus */
.incl-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(36px, 6vw, 80px);
  align-items: start;
  margin-top: 20px;
}
.incl-list { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
.incl-list li {
  background: var(--void);
  padding: 24px 22px;
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  display: flex;
  gap: 12px;
  align-items: flex-start;
  transition: background 0.3s;
}
.incl-list li:hover { background: var(--panel); }
.incl-list li svg { flex: 0 0 auto; margin-top: 2px; }
.incl-list li small { display: block; font-weight: 400; color: var(--fog); font-size: 13px; margin-top: 4px; line-height: 1.5; }

/* -------------------------------------------------------------- 14. FAQ */
.faq { margin-top: 54px; border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  list-style: none;
  cursor: pointer;
  padding: 26px 48px 26px 0;
  position: relative;
  font-family: var(--display);
  font-size: clamp(1.05rem, 2vw, 1.32rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  transition: color 0.25s;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--green-ink); }
.faq summary::after {
  content: "";
  position: absolute;
  right: 6px;
  top: 50%;
  width: 13px;
  height: 13px;
  margin-top: -6px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M7 1v12M1 7h12' stroke='%234c5a52' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") center/contain no-repeat;
  transition: transform 0.35s var(--ease);
}
.faq details[open] summary::after { transform: rotate(135deg); }
.faq .answer { color: var(--fog); font-size: 15.5px; padding-bottom: 28px; max-width: 78ch; }
.faq .answer p + p { margin-top: 14px; }

/* ------------------------------------------------------------ 15. Contact */
.cta {
  position: relative;
  overflow: hidden;
  border-top: 1px solid var(--line);
  background: var(--ink);
}
.cta::before {
  content: "";
  position: absolute;
  width: 900px;
  height: 900px;
  border-radius: 50%;
  filter: blur(130px);
  background: rgba(18, 185, 196, 0.13);
  top: -420px;
  left: 50%;
  transform: translateX(-50%);
  pointer-events: none;
}
.cta-grid {
  position: relative;
  display: grid;
  grid-template-columns: 0.95fr 1.05fr;
  gap: clamp(38px, 6vw, 78px);
  align-items: start;
}
.contact-lines { margin-top: 40px; display: grid; gap: 4px; }
.contact-lines > a,
.contact-lines > span {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  color: var(--white);
  transition: color 0.2s, padding-left 0.3s var(--ease);
}
.contact-lines > a:hover { color: var(--green-ink); padding-left: 8px; }
.contact-lines .lbl {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fog-dim);
  width: 88px;
  flex: 0 0 auto;
}

/* Formulaire */
.form { display: grid; gap: 18px; }
.form .row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.field { display: grid; gap: 8px; }
.field label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fog);
}
.field input,
.field select,
.field textarea {
  font-family: var(--body);
  font-size: 15px;
  color: var(--white);
  background: var(--void);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 15px 16px;
  width: 100%;
  transition: border-color 0.25s, background 0.25s;
}
.field textarea { resize: vertical; min-height: 130px; line-height: 1.6; }
.field input::placeholder,
.field textarea::placeholder { color: var(--fog-dim); }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--green);
  background: var(--panel);
}
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5l5-5' stroke='%234c5a52' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 11px;
  padding-right: 42px;
}
.field select option { background: var(--ink); color: var(--white); }
.consent {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  font-size: 12.5px;
  color: var(--fog-dim);
  line-height: 1.6;
}
.consent input { accent-color: var(--green); margin-top: 3px; width: 15px; height: 15px; flex: 0 0 auto; }
.form-note { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--fog-dim); }

/* --------------------------------------------------------------- 16. Footer */
.foot { background: var(--void); border-top: 1px solid var(--line); padding-block: 60px 34px; }
.foot-top { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 40px; }
.foot-brand .brand { gap: 14px; }
.foot-brand .brand img { height: 52px; }
.foot-brand .brand-txt b { font-size: 23px; }
.foot-brand .brand-txt small { font-size: 9px; }
.foot-brand p { color: var(--fog); font-size: 14px; margin-top: 20px; max-width: 34ch; }
/* Titres du pied de page en h2 (ordre des titres), même rendu qu'avant */
.foot h2 {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fog-dim);
  font-weight: 500;
}
.foot ul { margin-top: 18px; display: grid; gap: 11px; }
.foot ul a { font-size: 14.5px; color: var(--fog); transition: color 0.2s; }
.foot ul a:hover { color: var(--green-ink); }
.foot-bot {
  margin-top: 50px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 12.5px;
  color: var(--fog-dim);
}

/* Barre d'action mobile */
.mobile-bar {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 90;
  padding: 12px var(--gut) calc(12px + env(safe-area-inset-bottom));
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
  gap: 10px;
}
.mobile-bar .btn { flex: 1; padding: 14px 12px; font-size: 14px; }

/* ------------------------------------------------ 17. Animations d'apparition */
/* Le masquage de départ n'est appliqué que si le JavaScript tourne (classe `js`
   posée par assets/js-actif.js). Sans lui, aucun script ne viendrait le lever
   et la page resterait vide. */
.js .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.75s var(--ease), transform 0.75s var(--ease);
}
.js .reveal.is-in { opacity: 1; transform: none; }

/* Même garde-fou que pour .reveal : sans JavaScript, le titre principal, le
   chapô et les boutons s'affichent d'emblée au lieu de dépendre d'une animation
   qui pourrait ne jamais démarrer. C'est le contenu du LCP, il ne doit jamais
   être suspendu à autre chose que lui-même. */
.js .hero .anim {
  opacity: 0;
  transform: translateY(20px);
  animation: rise 0.9s var(--ease) forwards;
}
.hero .anim:nth-child(1) { animation-delay: 0.05s; }
.hero .anim:nth-child(2) { animation-delay: 0.14s; }
.hero .anim:nth-child(3) { animation-delay: 0.23s; }
.hero .anim:nth-child(4) { animation-delay: 0.32s; }
.hero .anim:nth-child(5) { animation-delay: 0.41s; }
/* ==========================================================================
   23. LE TITRE PRINCIPAL N'ATTEND RIEN
   --------------------------------------------------------------------------
   Le h1 du hero est l'élément qui porte le LCP. Il partait d'`opacity: 0` avec
   la cascade d'entrée des sections 17 et 21.11 : sur un téléphone réunionnais
   en 4G, cela revenait à retarder la plus grande peinture de contenu du seul
   fait d'un effet décoratif. Le titre s'affiche donc immédiatement, à sa place
   définitive ; la cascade reste en place sur le sur-titre, le chapô, les
   boutons et la ligne de preuves, où elle ne coûte rien.

   L'encrage du mot « trouvé. » (section 22.6) est conservé : il n'anime que le
   dégradé de fond du mot, le texte est peint dès la première image et le LCP
   n'en dépend pas.
   ========================================================================== */
.js .hero h1.anim {
  opacity: 1;
  transform: none;
  animation: none;
}

/* Le fondu d'entrée du logo est porté par .logo-static (voir section 6). */

@keyframes rise { to { opacity: 1; transform: none; } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* `.js` repris à l'identique du sélecteur masquant, pour garder la priorité */
  .js .reveal, .js .hero .anim { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------ 18. Responsive */
@media (max-width: 1020px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-art { min-height: 340px; order: 2; }
  .pain-grid { grid-template-columns: 1fr; }
  .steps { grid-template-columns: 1fr 1fr; }
  .work { grid-template-columns: 1fr; }
  .incl-grid { grid-template-columns: 1fr; }
  .cta-grid { grid-template-columns: 1fr; }
  .price-grid { grid-template-columns: 1fr; }
  .price--star { order: -1; }
  .foot-top { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 860px) {
  .menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: rgba(255, 255, 255, 0.98);
    backdrop-filter: blur(18px);
    border-block: 1px solid var(--line);
    padding: 8px var(--gut) 22px;
  }
  .menu.is-open { display: flex; }
  .menu a { padding: 15px 0; border-bottom: 1px solid var(--line); font-size: 16px; }
  .menu a::after { display: none; }
  .burger { display: block; }
  .nav-cta .btn { display: none; }
  .svc-grid { grid-template-columns: 1fr; }
  .mobile-bar { display: flex; }
  body { padding-bottom: 74px; }
  .foot-top { grid-template-columns: 1fr; gap: 34px; }
}

@media (max-width: 620px) {
  .steps { grid-template-columns: 1fr; }
  .incl-list { grid-template-columns: 1fr; }
  /* le logo doit tenir entier dans la largeur du téléphone */
  .hero-art .logo-stage .logo-static { width: 70%; }
  .form .row { grid-template-columns: 1fr; }
  .hero-actions .btn { width: 100%; }
  .trust { gap: 10px 18px; }
}

/* ------------------------------------------------------- 19. Assistant (chat) */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.chat {
  position: fixed;
  right: max(18px, env(safe-area-inset-right));
  bottom: max(18px, env(safe-area-inset-bottom));
  z-index: 95;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 12px;
  font-family: var(--body);
}

.chat-bulle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 18px 13px 15px;
  border: 0;
  border-radius: 100px;
  background: var(--grad);
  color: #05120a;
  font-family: var(--body);
  font-weight: 700;
  font-size: 14px;
  cursor: pointer;
  box-shadow: 0 14px 34px -12px rgba(31, 143, 78, 0.55);
  transition: transform 0.25s var(--ease), box-shadow 0.25s;
}
.chat-bulle:hover { transform: translateY(-2px); box-shadow: 0 18px 38px -12px rgba(31, 143, 78, 0.6); }
.chat.is-open .chat-bulle-txt { display: none; }
.chat.is-open .chat-bulle { padding: 13px 15px; }

.chat-panneau {
  width: min(380px, calc(100vw - 36px));
  max-height: min(600px, calc(100vh - 110px));
  display: flex;
  flex-direction: column;
  background: var(--void);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: 0 30px 70px -24px rgba(11, 20, 16, 0.35);
  overflow: hidden;
  animation: chat-apparait 0.3s var(--ease);
}
@keyframes chat-apparait {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
/* L'attribut hidden doit l'emporter sur le display: flex ci-dessus : sans cette règle,
   le panneau restait affiché (vide) dès le chargement et ne se fermait plus. */
.chat-panneau[hidden] { display: none; }

.chat-tete {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}
.chat-tete img { height: 30px; width: auto; }
.chat-tete b { display: block; font-family: var(--display); font-size: 15px; letter-spacing: -0.01em; }
.chat-tete small { display: block; font-size: 12px; color: var(--fog); margin-top: 2px; }
.chat-fermer {
  margin-left: auto;
  width: 34px;
  height: 34px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--void);
  color: var(--fog);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}
.chat-fermer:hover { color: var(--white); border-color: var(--line-strong); }

.chat-fil {
  flex: 1;
  overflow-y: auto;
  padding: 18px 16px 6px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  scroll-behavior: smooth;
}
.chat-msg {
  max-width: 88%;
  padding: 11px 14px;
  border-radius: 14px;
  font-size: 14.5px;
  line-height: 1.55;
}
.chat-msg p + p { margin-top: 8px; }
.chat-msg--assistant {
  align-self: flex-start;
  background: var(--panel);
  color: var(--white);
  border-bottom-left-radius: 4px;
}
.chat-msg--user {
  align-self: flex-end;
  background: var(--grad);
  color: #05120a;
  font-weight: 600;
  border-bottom-right-radius: 4px;
}
.chat-msg--erreur { border: 1px dashed var(--line-strong); background: var(--void); color: var(--fog); }
.chat-msg--attente { color: var(--fog); letter-spacing: 0.2em; animation: chat-pulse 1.2s ease-in-out infinite; }
@keyframes chat-pulse { 50% { opacity: 0.35; } }

.chat-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 16px 4px;
}
.chat-suggestions:empty { display: none; }
.chat-suggestions button {
  font-family: var(--body);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--green-ink);
  background: var(--void);
  border: 1px solid rgba(31, 143, 78, 0.35);
  border-radius: 100px;
  padding: 7px 12px;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.chat-suggestions button:hover { background: var(--grad-soft); border-color: var(--green-ink); }

.chat-form {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 12px 12px 6px 16px;
  border-top: 1px solid var(--line);
}
.chat-form textarea {
  flex: 1;
  resize: none;
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.45;
  color: var(--white);
  background: var(--void);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 12px;
  max-height: 120px;
}
.chat-form textarea:focus { outline: none; border-color: var(--green); background: var(--panel); }
.chat-form button {
  width: 42px;
  height: 42px;
  flex: 0 0 auto;
  border: 0;
  border-radius: 10px;
  background: var(--grad);
  color: #05120a;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.chat-form button:disabled { opacity: 0.5; cursor: wait; }

.chat-note {
  font-size: 11px;
  color: var(--fog-dim);
  text-align: center;
  padding: 4px 16px 10px;
}

/* Carte d'estimation de devis dans le fil */
.chat-devis {
  align-self: stretch;
  border: 1px solid transparent;
  border-radius: 14px;
  padding: 16px 16px 14px;
  background:
    linear-gradient(var(--void), var(--void)) padding-box,
    var(--grad) border-box;
  box-shadow: 0 18px 40px -22px rgba(47, 196, 106, 0.4);
}
.chat-devis h3 { font-family: var(--display); font-size: 15.5px; letter-spacing: -0.01em; }
.chat-devis > small { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; color: var(--fog-dim); margin-top: 4px; }
.chat-devis ul { margin-top: 12px; display: grid; gap: 8px; }
.chat-devis li { display: flex; justify-content: space-between; gap: 12px; font-size: 13.5px; color: var(--fog); line-height: 1.45; }
.chat-devis li b { color: var(--white); white-space: nowrap; }
.chat-devis-total {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-family: var(--display);
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.02em;
}
.chat-devis-mention { font-size: 12px; color: var(--fog-dim); margin-top: 6px; line-height: 1.5; }
.chat-devis-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.chat-devis-actions .btn { white-space: normal; text-align: center; }
.chat-devis-actions .btn--primary { flex: 1 1 100%; }

/* Carte « Votre demande » : l'assistant a rempli la demande, le visiteur relit et envoie */
.chat-demande-champs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; margin-top: 12px; }
.chat-demande label { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--fog-dim); margin-bottom: 3px; }
.chat-demande input:not([type=checkbox]), .chat-demande textarea {
  width: 100%; font: 13.5px/1.4 var(--body); color: var(--white); background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--r); padding: 7px 9px;
}
.chat-demande textarea { resize: vertical; min-height: 92px; }
.chat-demande > label { margin-top: 10px; }
.chat-demande input:focus, .chat-demande textarea:focus { outline: none; border-color: var(--green); }
.chat-demande .chat-demande-accord { display: flex; gap: 8px; align-items: flex-start; margin-top: 10px; font-family: var(--body); font-size: 12px; letter-spacing: 0; text-transform: none; color: var(--fog); line-height: 1.45; }
.chat-demande-accord input { margin-top: 2px; accent-color: var(--green-ink); flex: none; }
.chat-demande-accord a { color: var(--green-ink); text-decoration: underline; }
.chat-demande-statut { font-size: 12.5px; font-weight: 600; color: #b3261e; margin-top: 6px; min-height: 0; }
.chat-demande-statut:empty { display: none; }
.chat-demande.is-envoyee { opacity: 0.75; }
@media (max-width: 420px) { .chat-demande-champs { grid-template-columns: 1fr; } }

@media (max-width: 860px) {
  /* au-dessus de la barre d'action mobile */
  .chat { bottom: calc(86px + env(safe-area-inset-bottom)); }
  .chat-bulle-txt { display: none; }
  .chat-bulle { padding: 13px 15px; }
  .chat-panneau { max-height: calc(100vh - 190px); }
}

@media (prefers-reduced-motion: reduce) {
  .chat-panneau, .chat-msg--attente { animation: none; }
}

/* --------------------------------------------------------- 20. Page 404 */
.liens-404 { display: flex; flex-wrap: wrap; gap: 12px 28px; }
.liens-404 a { font-size: 14.5px; font-weight: 600; color: var(--fog); transition: color 0.2s; }
.liens-404 a:hover { color: var(--white); }
.foot-bot--seul { margin-top: 0; border-top: none; padding-top: 0; }

/* ==========================================================================
   21. DIRECTION ÉDITORIALE — « Editorial Grid / Magazine »
   --------------------------------------------------------------------------
   Style nommé retenu dans la base ui-ux-pro-max (styles.csv, editorial-grid-magazine,
   variance 8 / motion 6) : grille asymétrique, typographie de magazine, folios
   numérotés, filets pleine largeur, lettrine, citation en exergue, papier chaud.
   Cette section est une couche de finition : elle surcharge les règles des
   sections 1 à 20 sans rien supprimer. Retirer ce bloc rend le thème précédent.

   Parti pris assumé (règle anti-classique) :
   - Typographie : Bricolage Grotesque poussée en « type-as-hero » (titre jusqu'à
     6,6 rem, graisse 800, interlettrage -0,055 em) + JetBrains Mono comme voix
     éditoriale (folios, bylines) + un serif système pour la lettrine et l'exergue
     (aucun fichier supplémentaire à télécharger).
   - Grille : asymétrique sur 12 colonnes (7/5 et 5/7), plus de cartes de largeur
     identique alignées trois par trois.
   - Matière : papier chaud (#fbfaf8), filets d'un pixel, angles vifs, aucune
     ombre douce ; la carte « Vitrine Pro » est inversée en encre.
   - Mouvement : révélation par volet (clip-path) sur les titres, décalage en
     cascade, respect intégral de prefers-reduced-motion.
   Contraintes tenues : contraste AA, focus visible, clavier, budget < 1 Mo,
   aucune bibliothèque d'animation ajoutée.
   ========================================================================== */

:root {
  /* Papier : blanc chaud plutôt que blanc d'écran, la base du rendu magazine */
  --void: #fbfaf8;
  --ink: #f4f1ea;
  --panel: #f5f2eb;
  --panel-2: #ece7dc;
  --line: rgba(11, 20, 16, 0.14);
  --line-strong: rgba(11, 20, 16, 0.32);
  /* Encre : fond des blocs inversés */
  --encre: #0b1410;
  /* Serif système pour lettrine et exergue : aucun octet supplémentaire */
  --editorial: Georgia, "Iowan Old Style", "Noto Serif", "Times New Roman", serif;
  --r: 0px;      /* angles vifs */
  --r-lg: 0px;
}

/* ------------------------------------------------------- 21.1 Folios de section */
/* Chaque section porte son numéro, comme les rubriques d'un magazine. */
main { counter-reset: folio; }
.section { counter-increment: folio; }

.eyebrow.folio {
  display: grid;
  grid-template-columns: auto auto minmax(24px, 1fr);
  align-items: center;
  gap: 16px;
  width: 100%;
  border-top: 1.5px solid var(--encre);
  padding-top: 16px;
  font-size: 11.5px;
  letter-spacing: 0.26em;
  color: var(--encre);
}
.eyebrow.folio::before {
  content: counter(folio, decimal-leading-zero);
  width: auto;
  height: auto;
  background: none;
  font-family: var(--display);
  font-size: clamp(1.9rem, 5vw, 3rem);
  font-weight: 800;
  line-height: 0.78;
  letter-spacing: -0.05em;
  color: var(--encre);
}
.eyebrow.folio::after {
  content: "";
  height: 1px;
  background: var(--grad);
  justify-self: stretch;
}

/* Titres de section : plus grands, plus serrés, jamais centrés */
.h-sec {
  font-size: clamp(2.3rem, 6.4vw, 4.4rem);
  font-weight: 800;
  letter-spacing: -0.045em;
  line-height: 0.96;
  margin-top: 26px;
  max-width: 20ch;
}
.lead { font-size: clamp(1rem, 1.6vw, 1.14rem); max-width: 56ch; }

/* Lettrine sur le chapô du constat : signature typographique du style */
.lead--capitale::first-letter {
  float: left;
  font-family: var(--editorial);
  font-size: 3.6em;
  line-height: 0.82;
  font-weight: 700;
  color: var(--encre);
  padding: 0.06em 0.12em 0 0;
}

/* ------------------------------------------------------------- 21.2 Hero */
/* Asymétrie franche : le texte occupe deux tiers, le logo est relégué en appui
   bas de colonne. Colonnes de la grille rendues visibles par des filets. */
.hero { padding-bottom: clamp(48px, 6vw, 84px); }
.hero-bg .glow { opacity: 0.26; }
.hero-bg .shard {
  transform: none;
  height: 100%;
  top: 0;
  background: linear-gradient(180deg, var(--line), transparent 75%);
}
.hero-bg .shard:nth-child(3) { left: 25%; }
.hero-bg .shard:nth-child(4) { left: 50%; opacity: 1; }
.hero-bg .shard:nth-child(5) { left: 75%; opacity: 1; }

.hero-grid { grid-template-columns: 1.5fr 0.5fr; align-items: end; }
.hero .eyebrow { color: var(--encre); }
.hero h1 {
  font-size: clamp(2.7rem, 8.6vw, 6.6rem);
  font-weight: 800;
  letter-spacing: -0.055em;
  line-height: 0.9;
  margin-top: 22px;
  max-width: 15ch;
}
/* Le mot mis en avant : trait d'encre sous le dégradé, comme un surlignage de maquette */
.hero h1 em.grad-text { position: relative; }
.hero h1 em.grad-text::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0.08em;
  bottom: 0.1em;
  height: 0.07em;
  background: var(--grad);
}
/* Chapô en colonne étroite, ferré par un filet : intro de magazine */
.hero .lead {
  max-width: 44ch;
  border-left: 2px solid var(--encre);
  padding-left: 20px;
  margin-top: 30px;
  font-size: clamp(1rem, 1.6vw, 1.1rem);
}
.hero-actions { margin-top: 34px; }

/* Bandeau de preuves : cellules séparées par des filets verticaux */
.trust {
  gap: 0;
  border-top: 1.5px solid var(--encre);
  border-bottom: 1px solid var(--line);
  padding-top: 0;
  margin-top: 46px;
}
.trust li {
  flex: 1 1 auto;
  padding: 16px 18px 16px 0;
  border-right: 1px solid var(--line);
  color: var(--encre);
  font-size: 11px;
}
.trust li:last-child { border-right: none; }
.trust li::before { box-shadow: none; border-radius: 0; width: 6px; height: 6px; background: var(--encre); }

.hero-art { min-height: 360px; }
.hero-art .logo-stage .logo-static { width: 100%; filter: none; }
.hero-art .logo-stage::before { opacity: 0.55; }

/* ------------------------------------------------------ 21.3 Blocs éditoriaux */
/* Le constat : un bloc majeur et deux blocs d'appui, jamais trois cases égales. */
.pain-grid {
  grid-template-columns: 7fr 5fr;
  border: none;
  background: none;
  gap: 0;
  border-top: 1.5px solid var(--encre);
}
.pain {
  padding: 34px 30px 38px 0;
  border-bottom: 1px solid var(--line);
  background: none;
}
.pain:first-child {
  grid-row: span 2;
  padding-right: 48px;
  border-right: 1px solid var(--line);
  border-bottom: none;
}
.pain:first-child h3 { font-size: clamp(1.6rem, 3.2vw, 2.4rem); }
.pain:first-child p { font-size: 16.5px; max-width: 42ch; }
.pain:not(:first-child) { padding-left: 40px; }
.pain:last-child { border-bottom: none; }
.pain:hover { background: none; }
.pain .num {
  font-family: var(--display);
  font-size: clamp(2.2rem, 4vw, 3.2rem);
  font-weight: 800;
  letter-spacing: -0.05em;
  line-height: 0.8;
  color: var(--encre);
  /* 0,16 donnait 1,4:1 sur le papier : le numéro est du texte, lu par les
     lecteurs d'écran, et doit tenir 3:1 comme tout grand texte. 0,5 = 3,44:1,
     et le chiffre reste deux fois plus léger que l'encre pleine. */
  opacity: 0.5;
}
.pain h3 { min-height: 0; margin-top: 14px; letter-spacing: -0.035em; }

/* Services : bento asymétrique 7/5 puis 5/7, filets au lieu de cartes */
.svc-grid { grid-template-columns: repeat(12, 1fr); gap: 0; border-top: 1.5px solid var(--encre); }
.svc {
  background: none;
  border: none;
  border-bottom: 1px solid var(--line);
  padding: 40px 42px 46px 0;
}
.svc:nth-child(1) { grid-column: span 7; border-right: 1px solid var(--line); }
.svc:nth-child(2) { grid-column: span 5; padding-left: 42px; }
.svc:nth-child(3) { grid-column: span 5; border-right: 1px solid var(--line); border-bottom: none; }
.svc:nth-child(4) { grid-column: span 7; padding-left: 42px; border-bottom: none; }
.svc::before { height: 2px; background: var(--grad); }
.svc:hover { transform: none; }
.svc:hover::before { transform: scaleX(1); }
.svc .idx { color: var(--encre); }
.svc h3 { letter-spacing: -0.035em; }
.svc ul li { border-radius: 0; }

/* ------------------------------------------------------------- 21.4 Offres */
.price-grid { gap: 0; border-top: 1.5px solid var(--encre); }
.price {
  border: none;
  border-right: 1px solid var(--line);
  padding: 38px 32px 40px;
  background: none;
}
.price:last-child { border-right: none; }
.price:hover { transform: none; border-color: var(--line); }
.price h3 { font-size: clamp(1.5rem, 2.6vw, 2rem); letter-spacing: -0.04em; }
.price .amount {
  font-family: var(--display);
  font-size: clamp(2.6rem, 5.4vw, 3.8rem);
  font-weight: 800;
  letter-spacing: -0.05em;
  line-height: 0.9;
  font-variant-numeric: tabular-nums;
}
/* L'offre principale passe en encre : contraste maximal, hiérarchie sans ombre */
.price--star {
  background: var(--encre);
  color: #ffffff;
  border-right-color: rgba(255, 255, 255, 0.18);
  margin-top: -26px;
  padding-top: 64px;
}
.price--star::after { display: none; }
.price--star h3,
.price--star .amount,
.price--star .feats li { color: #ffffff; }
.price--star .who,
.price--star .from,
.price--star .amount sup { color: rgba(255, 255, 255, 0.72); }
.price--star .feats li::before { filter: none; }
.price-note { max-width: 78ch; }
.price-note strong { color: var(--encre); }

/* ------------------------------------------------------------ 21.5 Méthode */
.steps { gap: 0; border-top: 1.5px solid var(--encre); margin-top: 56px; }
.step { padding: 30px 26px 34px 0; border-right: 1px solid var(--line); }
.step:last-child { border-right: none; }
.step:not(:first-child) { padding-left: 26px; }
.step::before { display: none; }
.step::after { display: none; }
.step .n {
  font-family: var(--display);
  font-size: clamp(1.8rem, 3vw, 2.6rem);
  font-weight: 800;
  letter-spacing: -0.05em;
  line-height: 0.8;
  color: var(--encre);
  /* 0,16 donnait 1,4:1 sur le papier : le numéro est du texte, lu par les
     lecteurs d'écran, et doit tenir 3:1 comme tout grand texte. 0,5 = 3,44:1,
     et le chiffre reste deux fois plus léger que l'encre pleine. */
  opacity: 0.5;
  text-transform: none;
}
.step h3 { margin-top: 14px; letter-spacing: -0.035em; }
.step .when { color: var(--encre); }

/* -------------------------------------------------------- 21.6 Réalisation */
.work-shot { border-radius: 0; }
.work-shot .chrome { border-radius: 0; }
.work-tags li { border-radius: 0; }
/* Exergue : guillemet de magazine en serif, hors marge */
.work-quote {
  position: relative;
  margin-top: 34px;
  padding: 0 0 0 54px;
  border: none;
  font-family: var(--editorial);
  font-style: italic;
  font-size: clamp(1.15rem, 2.1vw, 1.45rem);
  line-height: 1.45;
  color: var(--encre);
}
.work-quote::before {
  content: "«";
  position: absolute;
  left: 0;
  top: -0.18em;
  font-family: var(--editorial);
  font-style: normal;
  font-size: 3.4em;
  line-height: 1;
  color: var(--encre);
  opacity: 0.22;
}
.work-quote cite { font-family: var(--mono); font-style: normal; }

/* ------------------------------------------------------------- 21.7 Inclus */
.incl-list { border: none; border-top: 1.5px solid var(--encre); background: none; gap: 0; }
.incl-list li {
  background: none;
  border-bottom: 1px solid var(--line);
  padding: 22px 20px 22px 0;
}
.incl-list li:nth-child(odd) { border-right: 1px solid var(--line); padding-right: 24px; }
.incl-list li:nth-child(even) { padding-left: 24px; }
.incl-list li:hover { background: none; }
.incl-list li:nth-last-child(-n + 2) { border-bottom: none; }

/* --------------------------------------------------------------- 21.8 FAQ */
.faq { border-top: 1.5px solid var(--encre); }
.faq summary { font-weight: 700; letter-spacing: -0.03em; }

/* ------------------------------------------------------------ 21.9 Contact */
.cta::before { opacity: 0.5; }
.form .field input,
.form .field select,
.form .field textarea { background: var(--void); }
.contact-lines > a,
.contact-lines > span { border-bottom: 1px solid var(--line); }
.contact-lines > a:first-child,
.contact-lines > span:first-child { border-top: 1.5px solid var(--encre); }

/* ------------------------------------------------------- 21.10 Pied de page */
.foot { border-top: 1.5px solid var(--encre); }
.foot h2 { color: var(--encre); }

/* --------------------------------------------------------- 21.11 Mouvement */
/* Révélation par volet sur les titres de section (preset « Scroll Reveal /
   Standard » de motion.csv) : RETIRÉE le 2026-09-26.
   Le commentaire qui la précédait se refermait trop tôt ; le texte resté hors
   commentaire devenait le début du sélecteur, et le navigateur ignorait la règle
   entière. Le volet n'a donc jamais été appliqué en production : on le supprime
   plutôt que de le réactiver, puisque la règle du site est désormais qu'aucun
   texte ne se cache en attendant le défilement (section 24). Le seuil
   `threshold: [0, …]` de assets/main.js reste utile et ne doit pas repasser à 0.08. */
.js h2.h-sec.reveal,
.js h1.h-sec.reveal {
  transform: translateY(14px);
  transition: opacity 0.5s var(--ease), transform 0.72s var(--ease);
}
.js h2.h-sec.reveal.is-in,
.js h1.h-sec.reveal.is-in { clip-path: inset(-0.35em -0.6em -0.35em -0.6em); }

/* Le hero : entrée en cascade un peu plus ferme */
.js .hero .anim { transform: translateY(26px); }

@media (prefers-reduced-motion: reduce) {
  .js h2.h-sec.reveal,
  .js h1.h-sec.reveal { clip-path: none; transform: none; }
  /* Cette règle vient après celle du dessus, à spécificité égale : sans elle le
     décalage de 26 px resterait figé sous le nez d'un visiteur qui a justement
     demandé moins de mouvement. */
  .js .hero .anim { transform: none; }
  .hero-art .logo-stage .logo-static { animation: none; }
}

/* ------------------------------------------------------- 21.12 Adaptations */
@media (max-width: 1020px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-art { order: 2; min-height: 260px; max-width: 320px; }
  .pain-grid { grid-template-columns: 1fr; border-top: 1.5px solid var(--encre); }
  .pain, .pain:first-child {
    grid-row: auto;
    padding: 28px 0 30px;
    border-right: none;
    border-bottom: 1px solid var(--line);
  }
  .pain:not(:first-child) { padding-left: 0; }
  .pain:last-child { border-bottom: none; }
  .svc-grid { grid-template-columns: 1fr; }
  .svc, .svc:nth-child(1), .svc:nth-child(2), .svc:nth-child(3), .svc:nth-child(4) {
    grid-column: auto;
    padding: 32px 0 36px;
    border-right: none;
    border-bottom: 1px solid var(--line);
  }
  .svc:nth-child(4) { border-bottom: none; }
  .steps { grid-template-columns: 1fr 1fr; }
  .step, .step:not(:first-child) { padding-left: 0; padding-right: 22px; }
  .step:nth-child(2n) { border-right: none; padding-left: 22px; }
  .step:nth-child(2n) { padding-right: 0; }
}

@media (max-width: 860px) {
  .price-grid { grid-template-columns: 1fr; }
  .price { border-right: none; border-bottom: 1px solid var(--line); }
  .price--star { margin-top: 0; padding-top: 38px; border-bottom: none; }
  .trust { display: grid; grid-template-columns: 1fr 1fr; }
  .trust li { border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
  .trust li:nth-child(2n) { border-right: none; }
  .trust li:nth-last-child(-n + 2) { border-bottom: none; }
  .incl-list { grid-template-columns: 1fr; }
  .incl-list li,
  .incl-list li:nth-child(odd),
  .incl-list li:nth-child(even) {
    padding: 20px 0;
    border-right: none;
    border-bottom: 1px solid var(--line);
  }
  .incl-list li:last-child { border-bottom: none; }
}

@media (max-width: 620px) {
  .steps { grid-template-columns: 1fr; }
  .step, .step:not(:first-child), .step:nth-child(2n) {
    padding: 26px 0 28px;
    border-right: none;
    border-bottom: 1px solid var(--line);
  }
  .step:last-child { border-bottom: none; }
  .eyebrow.folio { grid-template-columns: auto 1fr; gap: 12px; }
  .eyebrow.folio::after { display: none; }
}

/* ------------------------------------------- 21.13 Corrections de la recette */
/* `.pain:first-child p` l'emportait sur `.pain .num` (spécificité) et écrasait
   le numéro du bloc majeur : on vise le seul paragraphe de description. */
.pain:first-child p { font-size: 15px; max-width: none; }
.pain:first-child h3 + p { font-size: 16.5px; max-width: 42ch; }
.pain:first-child .num { font-size: clamp(3rem, 6vw, 4.6rem); }

/* Note de tarifs : composition en colonne, pas de texte centré en magazine */
.price-note { text-align: left; margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--line); }

/* Réalisation : bloc à filets, image ferrée en haut, plus de carte en dégradé */
.work {
  align-items: start;
  border: none;
  border-top: 1.5px solid var(--encre);
  border-radius: 0;
  padding: 40px 0 0;
  background: none;
  grid-template-columns: 1.1fr 0.9fr;
}
.work-shot { border-radius: 0; box-shadow: none; border: 1px solid var(--line-strong); }
.work-meta .eyebrow { color: var(--encre); }

/* Lien d'évitement : premier élément au clavier, invisible tant qu'il n'a pas le focus */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--encre);
  color: #ffffff;
  padding: 14px 20px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.skip:focus-visible { left: 12px; top: 12px; outline: 2px solid var(--lime); outline-offset: 2px; }

/* Bloc majeur du constat : composition en colonne pleine hauteur (le texte
   descend au pied du bloc) plutôt qu'un vide involontaire sous le paragraphe. */
@media (min-width: 1021px) {
  .pain:first-child { display: flex; flex-direction: column; }
  .pain:first-child h3 + p { margin-top: auto; padding-top: 28px; }
}

/* ------------------------------------------- 21.14 Matière et coût de rendu */
/* Le grain était une couche fixe plein écran au-dessus de tout (z-index 9999,
   recomposée à chaque défilement). En thème papier, la même matière s'obtient
   par une texture pavée sur le fond du corps : aucune couche supplémentaire,
   aucun coût de composition. Mesuré sur Lighthouse mobile : TBT en baisse. */
body::after { display: none; }
body {
  background-color: var(--void);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23p)' opacity='0.035'/%3E%3C/svg%3E");
}

/* Masthead opaque plutôt que verre dépoli : plus lisible, et surtout pas de
   backdrop-filter à recalculer à chaque pixel de défilement sur téléphone. */
.head {
  background: rgba(251, 250, 248, 0.96);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.head.is-stuck { background: var(--void); border-bottom-color: var(--encre); }
.mobile-bar {
  background: var(--void);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-top: 1.5px solid var(--encre);
}

/* Halos : rayon de flou réduit, et supprimés sur téléphone (le flou d'un disque
   de 620 px est l'opération la plus chère de la page sur un mobile d'entrée de gamme). */
.hero-bg .glow { filter: blur(80px); }
@media (max-width: 860px) {
  .hero-bg .glow,
  .cta::before,
  .hero-art .logo-stage::before { display: none; }
}

/* Pied de page et FAQ : cibles tactiles plus généreuses (WCAG 2.2, 24 px mini) */
.foot ul { gap: 4px; }
.foot ul a { display: inline-block; padding: 7px 0; }
.contact-lines > a, .contact-lines > span { padding: 18px 0; }

/* ------------------------------------------------ 21.15 Contrastes AA (papier) */
/* Sur le papier chaud, les versions « ink » du vert et du turquoise tombaient
   sous 4,5:1 (3,95 et 3,73). Elles sont assombries : 5,58 et 5,51 sur le papier,
   5,21 et 5,15 sur les panneaux. Mesuré sur les trois pages, en 375 et 1280 px. */
:root {
  --teal-ink: #08717a;
  --green-ink: #17743f;
}
/* Adresse du navigateur factice de la capture : gris trop clair sur son bandeau */
.work-shot .chrome .url { color: #464f49; }

/* ==========================================================================
   22. COUCHE D'ANIMATION — vocabulaire « 21st.dev » porté sur du papier
   --------------------------------------------------------------------------
   Demande de David (2026-09-22) : « je veux des animations comme sur 21st.dev ».
   21st.dev est une bibliothèque React/Tailwind sombre (Animated heroes, Shaders,
   Liquid & metal, Backgrounds, Gradients, Shimmer Button, Number Ticker, marquee,
   spotlight card, beams, curseur magnétique). Ce qui est repris ici, c'est le
   SAVOIR-FAIRE d'animation, pas l'esthétique néon : chaque effet est retraduit
   dans la direction « Editorial Grid » de la section 21 (papier chaud, filets,
   folios, encre). Comme la section 21, cette section est une couche de finition :
   la retirer d'un bloc rend le site exactement tel qu'il était au commit 08b5ef1.

   Arbitrages (un effet = une ligne) :
   - Shaders / Liquid & metal : REFUSÉS. Canvas WebGL ou filtres de flou animés,
     c'est 100 % du budget mobile pour du décor ; en échange les deux halos
     blur(110px) du hero passent en radial-gradient (même rendu, zéro passe de flou).
   - Shimmer Button -> « filet de lumière » : un trait clair balaie le bouton au
     survol et au focus, et en boucle lente sur le seul bouton du hero ; pas de
     hover:scale-105 (ressort de SaaS), on garde le translateY(-2px) maison.
   - Number Ticker -> les montants des offres se composent à l'arrivée en vue ;
     le montant final reste écrit dans le HTML (SEO, sans JS) et la largeur est
     réservée avant l'animation, donc CLS inchangé.
   - Marquee -> le bandeau métiers existait : il se met en pause au survol.
   - Spotlight card -> « lueur d'encre » qui suit le curseur, déplacée en
     translate3d (composité, aucun repaint), sous la lettre, desktop pointeur fin.
   - Beams -> « filets qui se tracent » : les filets de folio, le filet du bloc
     inclus et les filets des étapes se tirent en scaleX à la révélation.
   - Gradient text -> un seul balayage d'encrage sur le mot du hero, pas de boucle
     infinie (un texte de 6,6 rem repeint 60 fois par seconde, c'est du TBT gratuit).
   - Animated hero -> parallaxe pilotée par scroll() natif (hors thread principal),
     seulement là où le navigateur la gère, seulement au-dessus de 768 px.
   - Curseur magnétique -> 5 px d'attraction maximum sur les boutons principaux,
     desktop pointeur fin.
   - Non fait : la lettrine ne s'anime pas (::first-letter n'accepte ni transform
     ni transition, et l'envelopper dans un span casse le rendu de la lettrine).

   Règle tenue partout : seules `transform` et `opacity` sont animées, aucune
   propriété de mise en page, aucune bibliothèque, aucune ressource tierce (CSP).
   ========================================================================== */

/* ------------------------------------------- 22.1 Halos du hero sans flou */
/* filter: blur(110px) sur 2 cercles de 600 px coûtait le plus gros poste de TBT
   mobile du site (mesure du 2026-09-22). Même dégradé, obtenu en peinture. */
.hero-bg .glow {
  filter: none;
  opacity: 1;
  background-repeat: no-repeat;
}
.hero-bg .glow-1 {
  background-image: radial-gradient(circle closest-side, rgba(18, 185, 196, 0.17), rgba(18, 185, 196, 0.07) 55%, rgba(18, 185, 196, 0) 82%);
  background-color: transparent;
}
.hero-bg .glow-2 {
  background-image: radial-gradient(circle closest-side, rgba(185, 222, 30, 0.13), rgba(185, 222, 30, 0.05) 55%, rgba(185, 222, 30, 0) 82%);
  background-color: transparent;
}

/* --------------------------------- 22.2 « Beams » : les filets se tracent */
/* Le filet du folio, le filet du bloc « toujours inclus » et le filet haut de
   chaque étape partent de zéro et se tirent vers la droite à la révélation. */
.eyebrow.folio::after {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.9s var(--ease) 0.12s;
}
.eyebrow.folio.is-in::after { transform: scaleX(1); }

.rule.reveal {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.95s var(--ease), opacity 0.5s var(--ease);
}
.rule.reveal.is-in { transform: scaleX(1); }

.step.reveal::before {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.8s var(--ease) 0.1s;
}
.step.reveal.is-in::before { transform: scaleX(1); }
.step.reveal::after {
  transform: scale(0);
  transition: transform 0.5s var(--ease) 0.5s;
}
.step.reveal.is-in::after { transform: scale(1); }

/* ------------------------------------ 22.3 « Shimmer » : filet de lumière */
.btn--primary::before {
  content: "";
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -45%;
  width: 34%;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(100deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.62), rgba(255, 255, 255, 0));
  transform: translate3d(0, 0, 0) skewX(-14deg);
}
.btn--primary:hover::before,
.btn--primary:focus-visible::before { animation: filet-lumiere 0.9s var(--ease); }
/* Un seul bouton du site entretient le balayage : celui du hero. */
.hero-actions .btn--primary::before { animation: filet-lumiere 4.6s var(--ease) 1.6s infinite; }

@keyframes filet-lumiere {
  0%   { opacity: 0; transform: translate3d(0, 0, 0) skewX(-14deg); }
  8%   { opacity: 1; }
  55%  { opacity: 1; }
  100% { opacity: 0; transform: translate3d(430%, 0, 0) skewX(-14deg); }
}

/* --------------------------------- 22.4 « Spotlight » : la lueur d'encre */
/* L'élément .spot est injecté par assets/anim.js, et seulement sur un poste
   à pointeur fin : le DOM mobile n'est pas touché. z-index -1 + isolation :
   la lueur passe au-dessus du fond de la carte et sous le texte (contraste). */
.svc, .price, .pain { isolation: isolate; }
.pain, .price { position: relative; }
.pain, .price, .svc { overflow: hidden; }

.spot {
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  width: 420px;
  height: 420px;
  margin: -210px 0 0 -210px;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(-9999px, 0, 0);
  transition: opacity 0.4s var(--ease);
  background: radial-gradient(circle closest-side, rgba(18, 185, 196, 0.16), rgba(47, 196, 106, 0.08) 45%, rgba(47, 196, 106, 0) 78%);
}
.price--star .spot {
  background: radial-gradient(circle closest-side, rgba(185, 222, 30, 0.2), rgba(18, 185, 196, 0.12) 45%, rgba(18, 185, 196, 0) 78%);
}
.svc:hover > .spot,
.price:hover > .spot,
.pain:hover > .spot { opacity: 1; }

/* La carte se soulève comme .svc le faisait déjà : même langage sur tout le site.
   Une seule et même transition sert à l'apparition (translateY) et au survol :
   deux durées différentes sur `transform` ne peuvent pas coexister. */
.price, .pain {
  transition: transform 0.5s var(--ease), opacity 0.75s var(--ease), background 0.35s, border-color 0.35s;
}
@media (hover: hover) and (pointer: fine) {
  .price:hover, .pain:hover { transform: translateY(-3px); }
}

/* ------------------------------------ 22.5 « Number ticker » : les montants */
.price .amount { font-variant-numeric: tabular-nums; }
.price .amount .compteur { display: inline-block; text-align: left; }

/* --------------------------- 22.6 « Gradient text » : l'encrage du hero */
/* L'animation part d'un dégradé élargi et décalé, et revient EXACTEMENT au
   rendu d'origine (100 % / 0) : l'état final du mot est inchangé. */
.hero h1 em.grad-text { animation: encrage 1.25s var(--ease) 0.4s both; }
@keyframes encrage {
  from { background-size: 320% 100%; background-position: 100% 0; }
  to   { background-size: 100% 100%; background-position: 0 0; }
}
/* Le trait d'encre sous le mot se tire en même temps */
.hero h1 em.grad-text::after {
  transform: scaleX(0);
  transform-origin: left center;
  animation: trait-encre 0.8s var(--ease) 0.75s forwards;
}
@keyframes trait-encre { to { transform: scaleX(1); } }

/* --------------------------------------------- 22.7 Bandeau métiers (marquee) */
.ticker:hover .ticker-track { animation-play-state: paused; }

/* --------------------------- 22.8 « Animated hero » : parallaxe au défilement */
/* scroll() natif : l'animation est pilotée par le compositeur, pas par un
   écouteur de scroll. Là où le navigateur ne la gère pas, il ne se passe rien. */
@supports (animation-timeline: scroll()) {
  @media (min-width: 769px) and (prefers-reduced-motion: no-preference) {
    .hero-art {
      animation: parallaxe-art linear both;
      animation-timeline: scroll(root);
      animation-range: 0 70vh;
    }
    .hero-bg .shard {
      animation: parallaxe-filet linear both;
      animation-timeline: scroll(root);
      animation-range: 0 70vh;
    }
    .hero-bg .shard:nth-child(4) { animation-range: 0 100vh; }
    .hero-bg .shard:nth-child(5) { animation-range: 0 55vh; }
  }
}
@keyframes parallaxe-art { to { transform: translate3d(0, -46px, 0); } }
@keyframes parallaxe-filet { to { transform: translate3d(0, -26px, 0); } }

/* --------------------------------------------- 22.9 Boutons magnétiques */
/* --mx / --my sont posés par anim.js (desktop, pointeur fin). Au repos ils
   valent 0 : la transition ramène le bouton en place. */
.btn--aimant { transform: translate3d(var(--mx, 0px), var(--my, 0px), 0); }
.btn--primary.btn--aimant:hover { transform: translate3d(var(--mx, 0px), calc(var(--my, 0px) - 2px), 0); }
.btn--ghost.btn--aimant:hover { transform: translate3d(var(--mx, 0px), calc(var(--my, 0px) - 2px), 0); }

/* ------------------------------------------- 22.10 Mouvement réduit */
/* Le bloc global de la section 17 coupe déjà animations et transitions.
   On remet ici, explicitement, chaque état final : un visiteur qui a réduit
   les animations voit un site complet et statique, jamais un site à moitié posé. */
@media (prefers-reduced-motion: reduce) {
  .eyebrow.folio::after,
  .rule.reveal,
  .step.reveal::before,
  .hero h1 em.grad-text::after { transform: none !important; }
  .step.reveal::after { transform: scale(1) !important; }
  .hero h1 em.grad-text {
    animation: none !important;
    background-size: 100% 100%;
    background-position: 0 0;
  }
  .btn--primary::before,
  .hero-actions .btn--primary::before { animation: none !important; opacity: 0 !important; }
  .spot { display: none; }
  .btn--aimant,
  .btn--primary.btn--aimant:hover,
  .btn--ghost.btn--aimant:hover { transform: none !important; }
  .hero-art, .hero-bg .shard { animation: none !important; }
  .price:hover, .pain:hover { transform: none !important; }
}

/* ==========================================================================
   24. COUCHE IMMERSIVE — « Parallax Storytelling » posé sur la grille éditoriale
   --------------------------------------------------------------------------
   Demande de David (2026-09-26) : le gabarit « site immersif » était trop
   difficile à comprendre ; on rend immersif CE site, sans rien perdre en clarté.
   Style nommé : Parallax Storytelling (styles.csv, parallax-storytelling) :
   récit porté par le défilement, une seule scène épinglée (RJ Plomberie), une
   variante mobile sans épinglage, et un repli complet sans animation.

   Règles de cette couche, dans l'ordre de priorité :
   1. La clarté d'abord : en cinq secondes sur un téléphone, on lit « sites pour
      artisans à La Réunion », les prix et le moyen de demander un devis.
   2. Aucun texte ne dépend du défilement pour devenir lisible : les blocs se
      déplacent en entrant, ils ne passent jamais par l'opacité 0. Le compteur des
      prix (qui affichait « 0 € » en passant) est retiré de assets/anim.js.
   3. Le mouvement accompagne : parallaxe du logo, cartes d'offres qui se posent,
      étapes qui s'allument (le texte est là dès le départ, seul l'accent change),
      capture RJ Plomberie qui passe en plein cadre, barre de progression.
   4. Rien de lourd : animation-timeline (compositeur) là où le navigateur la
      gère, IntersectionObserver ailleurs (assets/immersif.js), aucune bibliothèque.
   5. prefers-reduced-motion : site complet et immobile, vidéo remplacée par son
      affiche. Toutes les animations pilotées par le défilement sont déclarées
      DANS un bloc (prefers-reduced-motion: no-preference) : la règle globale de la
      section 17 (durée 0,01 ms) ne les arrête pas, leur durée étant ignorée.

   Parti pris assumé : le hero, le bandeau métiers, l'en-tête et le contact
   passent en « nuit » (l'encre #0b1410 du site), avec le citron du logo comme
   accent. Le papier reste pour tout ce qui se lit longtemps.
   Retirer cette section, sa balise <script> (assets/immersif.js) et les classes
   `nuit` du HTML rend la version éditoriale précédente.
   ========================================================================== */

/* -------------------------------------------- 24.1 Jetons de la zone « nuit » */
/* Toute la feuille passe par des jetons : les redéfinir sur un conteneur suffit
   à retourner une zone entière. Contrastes mesurés sur #0b1410 : texte 16,7:1,
   --fog 10,6:1, --fog-dim 8,1:1, citron 12,0:1. */
.nuit {
  --void: #0b1410;
  --ink: #0b1410;
  --panel: #111c17;
  --panel-2: #17241e;
  --white: #f4f1ea;
  --fog: #bcc5be;
  --fog-dim: #a3aea6;
  --line: rgba(244, 241, 234, 0.16);
  --line-strong: rgba(244, 241, 234, 0.38);
  --encre: #f4f1ea;
  --teal-ink: #5ad4de;
  --green-ink: #86e3a6;
  --grad-text: var(--grad);
  color: var(--white);
  background-color: var(--void);
}

/* -------------------------------------------------- 24.2 En-tête (bandeau) */
.head.nuit,
.head.nuit.is-stuck { background: var(--void); }
.head.nuit.is-stuck { border-bottom-color: var(--line); }
@media (max-width: 860px) {
  .head.nuit .menu { background: var(--void); }
}

/* Barre de progression de lecture, sous l'en-tête. Pilotée par le défilement
   (compositeur) ; absente là où le navigateur ne sait pas le faire. */
.progression {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
  display: none;
}

/* ----------------------------------------------------------- 24.3 Le hero */
.hero.nuit { padding-top: clamp(40px, 6vw, 72px); }
.hero-bg .glow-1 { background-image: radial-gradient(circle closest-side, rgba(18, 185, 196, 0.22), rgba(18, 185, 196, 0.08) 55%, rgba(18, 185, 196, 0) 82%); }
.hero-bg .glow-2 { background-image: radial-gradient(circle closest-side, rgba(185, 222, 30, 0.14), rgba(185, 222, 30, 0.05) 55%, rgba(185, 222, 30, 0) 82%); }

.hero-grid {
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr);
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
}
.hero-grid > div:first-child { position: relative; z-index: 1; }
.hero h1 { font-size: clamp(2.6rem, 6.1vw, 4.9rem); }
.hero .lead { margin-top: 26px; }

/* Le logo animé : le fond noir de la vidéo disparaît sur l'encre par le mode
   « screen » (noir + encre = encre). L'affiche porte le même traitement.
   Le mode de fusion est posé sur .hero-art, le conteneur le plus haut : son
   enfant .logo-stage est animé en transform, ce qui crée un contexte
   d'empilement ; posé plus bas, le « screen » ne verrait que ce contexte vide
   et laisserait un carré noir. */
.hero .hero-art {
  mix-blend-mode: screen;
  min-height: 0;
  max-width: none;
  /* le logo déborde jusqu'au bord de la fenêtre, à droite */
  margin-right: calc(-1 * var(--gut) - max(0px, (100vw - var(--wrap)) / 2));
}
.hero .hero-art .logo-stage {
  position: relative;
  inset: auto;
  display: block;
}
.hero .hero-art .logo-stage::before {
  filter: none;
  opacity: 1;
  inset: 8%;
  width: auto;
  background: radial-gradient(circle closest-side, rgba(47, 196, 106, 0.2), rgba(18, 185, 196, 0.06) 60%, transparent);
}
.hero-art .logo-stage .logo-video {
  display: block;
  position: relative;
  width: 100%;
  max-width: 560px;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  background: transparent;
}

/* La carte des tarifs : ce qu'un artisan cherche en premier, lisible d'un coup d'œil */
.tarifs-hero {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  max-width: 620px;
  margin-top: 30px;
  border-top: 1.5px solid var(--encre);
  border-bottom: 1px solid var(--line);
}
.tarifs-hero li { min-width: 0; }
.tarifs-hero li + li { border-left: 1px solid var(--line); }
.tarifs-hero a {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 12px;
  height: 100%;
  padding: 14px 16px 16px;
  transition: background 0.25s;
}
.tarifs-hero li:first-child a { padding-left: 0; }
.tarifs-hero a:hover { background: rgba(244, 241, 234, 0.06); }
.tarifs-hero .t-nom {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.3;
  color: var(--white);
}
.tarifs-hero .t-nom small {
  display: block;
  margin-top: 5px;
  font-family: var(--body);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--fog);
}
.tarifs-hero .t-prix {
  font-family: var(--display);
  font-size: clamp(1.25rem, 2.9vw, 2.05rem);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1;
  white-space: nowrap;
  color: var(--lime);
}
.tarifs-hero .t-prix small {
  font-family: var(--body);
  font-size: 0.5em;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--fog);
  margin-right: 0.2em;
}

/* Mobile et tablette : le logo passe derrière le titre, en filigrane.
   Opacité et masque réglés pour que le texte posé dessus garde son contraste
   (mesuré sur les images de la vidéo, voir README). */
@media (max-width: 1020px) {
  /* minmax(0, …) : le titre en nowrap ne doit pas élargir la colonne (320 px) */
  .hero-grid { grid-template-columns: minmax(0, 1fr); }
  .hero .hero-art {
    position: absolute;
    z-index: 0;
    top: -24px;
    right: -18vw;
    width: min(84vw, 460px);
    margin: 0;
    order: 0;
    opacity: 0.38;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(104deg, transparent 12%, #000 58%);
    mask-image: linear-gradient(104deg, transparent 12%, #000 58%);
  }
  .hero .hero-art .logo-stage::before { display: none; }
}
@media (max-width: 620px) {
  /* « Votre savoir-faire » tient sur une ligne jusqu'à 320 px */
  .hero h1 { font-size: min(2.6rem, 11.4vw); }
  .tarifs-hero a { padding: 12px 10px 14px; gap: 10px; }
  .tarifs-hero .t-nom { font-size: 10px; letter-spacing: 0.1em; }
  .tarifs-hero .t-nom small { font-size: 12px; }
  .tarifs-hero .t-prix small { display: block; font-size: 12px; margin: 0 0 4px; }
}
@media (max-width: 359px) {
  .tarifs-hero .t-prix { font-size: 1.1rem; }
}

/* Entrée du hero : le texte monte en place, il ne s'efface jamais */
.js .hero .anim { opacity: 1; }

/* ------------------------------------------------- 24.4 Bandeau métiers */
.ticker.nuit { border-block-color: var(--line); }

/* -------------------------------------------- 24.5 Lisibilité permanente */
/* Les blocs .reveal gardent leur entrée (translateY), plus jamais l'opacité 0. */
.js .reveal { opacity: 1; }

/* -------------------------------------------------- 24.6 Offres qui se posent */
/* Chaque carte arrive légèrement inclinée, puis se pose. Les prix restent
   lisibles pendant tout le mouvement : seul `transform` change. */
.js .price.reveal {
  transform: translateY(54px) rotate(-1.8deg);
  transform-origin: 20% 100%;
  transition: transform 0.95s cubic-bezier(0.2, 1.15, 0.32, 1), background 0.35s, border-color 0.35s;
}
.js .price.reveal:nth-child(2) { transform: translateY(80px) rotate(1.1deg); transform-origin: 50% 100%; }
.js .price.reveal:nth-child(3) { transform: translateY(54px) rotate(2deg); transform-origin: 80% 100%; }
.js .price.reveal.is-in { transform: none; }
@media (hover: hover) and (pointer: fine) {
  .js .price.reveal.is-in:hover { transform: translateY(-4px); }
}
/* Inclinées avant de se poser, les cartes débordaient d'un pixel à 320 px.
   `clip` (et non `hidden`) : aucun conteneur de défilement n'est créé. */
#offres { overflow-x: clip; }
/* L'offre principale reçoit l'accent citron du logo */
.price--star { box-shadow: inset 0 3px 0 var(--lime); }

/* ------------------------------------------- 24.7 Méthode : les étapes s'allument */
/* assets/immersif.js pose .allume sur chaque étape quand elle passe aux deux
   tiers de l'écran. Le texte est entier dès le départ : seuls le filet
   dégradé, le numéro et la pastille de délai changent. Sans JavaScript, les
   étapes sont allumées d'emblée. */
.steps .step::before {
  display: block;
  content: "";
  position: absolute;
  top: -1.5px;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--grad);
  transform: scaleX(1);
  transform-origin: left center;
  transition: transform 0.8s var(--ease) var(--d, 0s);
}
.js .steps .step:not(.allume)::before,
.js .steps .step.reveal.is-in:not(.allume)::before { transform: scaleX(0); }
.steps .step .n { transition: opacity 0.6s var(--ease) var(--d, 0s); }
.steps .step.allume .n { opacity: 1; }
.steps .step .when {
  align-self: flex-start;
  margin-left: -8px;
  padding: 4px 8px;
  transition: background-color 0.6s var(--ease) var(--d, 0s);
}
.steps .step.allume .when,
html:not(.js) .steps .step .when { background-color: var(--lime); }
@media (min-width: 1021px) {
  /* Sur une rangée de quatre, elles s'allument l'une après l'autre */
  .steps .step:nth-child(2) { --d: 0.3s; }
  .steps .step:nth-child(3) { --d: 0.6s; }
  .steps .step:nth-child(4) { --d: 0.9s; }
}

/* ------------------------------------------- 24.8 Réalisation : plein cadre */
/* Repli (et mobile) : la capture s'affiche en grand, bord à bord sous 1020 px. */
.rj-scene { margin-top: 56px; }
.rj-cadre {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gut);
}
.rj-cadre .work-shot { background: var(--panel-2); }
@media (max-width: 1020px) {
  .rj-cadre { padding-inline: 0; }
  .rj-cadre .work-shot { border-inline: none; }
}
/* L'étude de cas, sous la capture : récit à gauche, preuves à droite */
.work {
  display: block;
  margin-top: 48px;
  padding-top: 36px;
}
@media (min-width: 1021px) {
  .work-meta {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    column-gap: clamp(40px, 6vw, 88px);
    align-items: start;
  }
  .work-meta > * { grid-column: 1; }
  .work-meta > .work-tags { grid-column: 2; grid-row: 1 / 3; margin-top: 4px; }
  .work-meta > .work-quote { grid-column: 2; grid-row: 3 / 5; margin-top: 0; }
}

/* ----------------------------------------------- 24.9 Toujours inclus */
/* Les coches se tracent à l'arrivée du bloc (décor : le texte dit déjà tout). */
.js .incl-list.reveal li svg path {
  stroke-dasharray: 18;
  stroke-dashoffset: 18;
  transition: stroke-dashoffset 0.6s var(--ease);
}
.js .incl-list.reveal.is-in li svg path { stroke-dashoffset: 0; }
.js .incl-list.reveal li:nth-child(2) svg path { transition-delay: 0.08s; }
.js .incl-list.reveal li:nth-child(3) svg path { transition-delay: 0.16s; }
.js .incl-list.reveal li:nth-child(4) svg path { transition-delay: 0.24s; }
.js .incl-list.reveal li:nth-child(5) svg path { transition-delay: 0.32s; }
.js .incl-list.reveal li:nth-child(6) svg path { transition-delay: 0.4s; }

/* ------------------------------------------------------ 24.10 Contact « nuit » */
.cta.nuit .field input,
.cta.nuit .field select,
.cta.nuit .field textarea {
  background-color: rgba(244, 241, 234, 0.05);
  border-color: var(--line-strong);
}
.cta.nuit .field input:focus,
.cta.nuit .field select:focus,
.cta.nuit .field textarea:focus {
  background-color: var(--panel-2);
  border-color: var(--lime);
}
/* Le raccourci `background` de 21.9 remettait répétition, taille et position à
   zéro : la flèche du menu se répétait sur toute la largeur. */
.cta.nuit .field select {
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 11px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5l5-5' stroke='%23bcc5be' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
}
.cta.nuit .consent input { accent-color: var(--lime); }

/* -------------------------------------- 24.11 Mouvement piloté par le défilement */
/* L'ancienne parallaxe du hero (22.8) est remplacée par celle du logo. */
.hero .hero-art { animation: none; }

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Barre de progression */
    .progression {
      display: block;
      animation: progression linear both;
      animation-timeline: scroll(root);
    }

    /* Le logo recule et descend doucement quand on quitte le hero */
    .hero .hero-art .logo-stage {
      animation: logo-recul linear both;
      animation-timeline: scroll(root);
      animation-range: 0 90vh;
    }

    /* Les grands numéros du constat dérivent à contre-courant (parallaxe douce) */
    .pain .num {
      animation: derive linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
  }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Ordinateur : scène épinglée, la capture passe de la carte au plein cadre */
    @media (min-width: 1021px) {
      .rj-scene {
        height: 210vh;
        margin-top: 32px;
        view-timeline-name: --rj;
      }
      .rj-cadre {
        position: sticky;
        top: 78px;
        height: calc(100vh - 78px);
        max-width: none;
        padding: 0;
        overflow: hidden;
      }
      .rj-cadre .work-shot {
        display: flex;
        flex-direction: column;
        width: 100%;
        height: 100%;
        border: none;
        transform-origin: 50% 45%;
        animation: rj-plein-cadre linear both;
        animation-timeline: --rj;
        animation-range: contain 0% contain 72%;
      }
      .rj-cadre .work-shot picture {
        display: block;
        flex: 1;
        min-height: 0;
        overflow: hidden;
      }
      .rj-cadre .work-shot img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        object-position: 50% 0;
        transform-origin: 50% 0;
        animation: rj-image linear both;
        animation-timeline: --rj;
        animation-range: contain 0% contain 72%;
      }
    }
    /* Téléphone et tablette : pas d'épinglage, la capture s'approche au défilement */
    @media (max-width: 1020px) {
      .rj-cadre .work-shot {
        animation: rj-approche linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 45%;
      }
    }
  }
}

@keyframes progression { to { transform: scaleX(1); } }
@keyframes logo-recul { to { transform: translate3d(0, 64px, 0) scale(0.9); } }
@keyframes derive {
  from { transform: translate3d(0, 16px, 0); }
  to { transform: translate3d(0, -16px, 0); }
}
@keyframes rj-plein-cadre {
  from { transform: scale(0.6); }
  to { transform: none; }
}
@keyframes rj-image {
  from { transform: scale(1.16); }
  to { transform: none; }
}
@keyframes rj-approche {
  from { transform: scale(0.86); }
  to { transform: none; }
}

/* ------------------------------------------------ 24.12 Mouvement réduit */
/* Site complet et immobile : chaque état final est posé explicitement. */
@media (prefers-reduced-motion: reduce) {
  .js .price.reveal,
  .js .price.reveal:nth-child(2),
  .js .price.reveal:nth-child(3) { transform: none; }
  .steps .step::before,
  .js .steps .step:not(.allume)::before { transform: scaleX(1) !important; }
  .steps .step .n { opacity: 1; }
  .steps .step .when { background-color: var(--lime); }
  .js .incl-list.reveal li svg path { stroke-dashoffset: 0; }
  .progression { display: none; }
}

/* ==========================================================================
   25. TYPOGRAPHIE « TECH PREMIUM » (2026-09-26)
   --------------------------------------------------------------------------
   Space Grotesk va jusqu'à 700 : les titres réglés en 800 pour Bricolage
   passent explicitement en 700 (sinon le navigateur arrondit, mais on ne veut
   pas dépendre de ce comportement). Interlettrage un peu desserré : Space
   Grotesk est plus large et son dessin se lit mieux avec de l'air.
   ========================================================================== */
h1, h2, h3, h4,
.h-sec,
.hero h1,
.brand-txt b,
.price .amount,
.tarifs-hero .t-prix,
.eyebrow.folio::before,
.pain .num,
.step .n { font-weight: 700; }
.hero h1 { letter-spacing: -0.045em; line-height: 0.95; }
/* Plus large que Bricolage : sur ordinateur, le titre garde ses deux lignes
   et les boutons restent dans le premier écran (1280 × 800).
   Le logo était centré sur la hauteur de la colonne de texte : à l'arrivée de
   la police, cette hauteur bouge d'un rien et le logo se recentrait (CLS 0,075
   mesuré sur ordinateur). Il est désormais ancré en haut, à distance fixe. */
@media (min-width: 1021px) {
  .hero h1 { font-size: clamp(2.6rem, 5.05vw, 4.4rem); }
  .hero .hero-art { align-self: start; margin-top: clamp(40px, 7.5vw, 120px); }
  /* Même raison pour le halo du bas : posé depuis le bas du hero, il suivait sa
     hauteur ; posé depuis le haut, il ne bouge plus. */
  .hero-bg .glow-2 { bottom: auto; top: max(360px, 58vh); }
  /* Les largeurs en `ch` dépendent du chiffre 0 de la police : avec la police
     de repli, le titre passait sur trois lignes puis revenait à deux (CLS).
     En `em`, la largeur est la même avant et après le chargement. Valeurs
     reprises de la mesure avec Space Grotesk et DM Sans (15ch et 44ch). */
  .hero h1 { max-width: 9.8em; }
  .hero .lead { max-width: 30em; }
}
.h-sec { letter-spacing: -0.04em; line-height: 0.98; }
.price .amount,
.tarifs-hero .t-prix { letter-spacing: -0.035em; }
.ticker-track span { font-weight: 600; }
/* DM Sans : texte courant un poil plus confortable */
body { letter-spacing: 0.002em; }

/* ==========================================================================
   26. INTERACTIONS (2026-09-26) — avec assets/interactions.js
   --------------------------------------------------------------------------
   Cinq effets (le fichier JS explique les choix et ce qui a été écarté).
   Aucun ne touche au texte : le halo et le reflet passent SOUS le contenu,
   la loupe est posée par-dessus la seule capture, qui ne contient pas de texte
   du site. Au doigt, seul l'état « appuyé » change ; rien ne dépend du survol.
   ========================================================================== */

/* ------------------------------------------ 26.1 Halo citron du hero */
/* Posé dans .hero-bg, sous le texte. Au plus fort, 16 % de citron sur l'encre :
   le texte clair y garde plus de 11:1. */
.hero-halo {
  position: absolute;
  left: -260px;
  top: -260px;
  width: 520px;
  height: 520px;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s var(--ease);
  background: radial-gradient(circle closest-side, rgba(185, 222, 30, 0.16), rgba(185, 222, 30, 0.06) 50%, rgba(185, 222, 30, 0) 76%);
  will-change: transform;
}
.hero.survol .hero-halo { opacity: 1; }
.hero-halo.touche { animation: halo-touche 0.9s var(--ease); }
@keyframes halo-touche {
  0% { opacity: 0; }
  18% { opacity: 0.7; }
  100% { opacity: 0; }
}

/* ------------------------------------------ 26.2 Le logo qui s'incline */
.hero .logo-video { transform-origin: 50% 55%; }

/* ------------------------------------ 26.3 Offres : inclinaison et reflet */
.price::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s var(--ease);
  background: linear-gradient(115deg, rgba(185, 222, 30, 0) 35%, rgba(185, 222, 30, 0.2) 50%, rgba(185, 222, 30, 0) 65%);
  background-size: 260% 100%;
  background-position: var(--px, 50%) 0;
}
.price--star::before {
  background-image: linear-gradient(115deg, rgba(255, 255, 255, 0) 35%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 65%);
}
@media (hover: hover) and (pointer: fine) {
  .js .price.reveal.is-in.incline {
    transform: perspective(1100px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(-4px);
    transition: transform 0.18s ease-out, background 0.35s, border-color 0.35s;
  }
  .price.incline::before { opacity: 1; }
}

/* ------------------------------------------------ 26.4 Loupe RJ Plomberie */
.loupe {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 85;
  width: 200px;
  height: 200px;
  margin: -100px 0 0 -100px;
  border-radius: 50%;
  border: 2px solid var(--lime);
  box-shadow: 0 0 0 1px rgba(11, 20, 16, 0.55), 0 22px 44px -14px rgba(11, 20, 16, 0.55);
  background-color: #eef1f4;
  background-repeat: no-repeat;
  pointer-events: none;
  opacity: 0;
  scale: 0.6;
  translate: -999px -999px;
  transition: opacity 0.2s var(--ease), scale 0.25s var(--ease);
}
.loupe.visible { opacity: 1; scale: 1; }
.loupe::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--lime);
  box-shadow: 0 0 0 1px rgba(11, 20, 16, 0.6);
}
.rj-cadre picture.loupe-active { cursor: none; }

/* ------------------------------------------------ 26.5 FAQ qui s'ouvre */
.faq summary { transition: color 0.25s, padding-left 0.3s var(--ease), box-shadow 0.3s var(--ease); }
.faq details[open] summary { padding-left: 18px; box-shadow: inset 3px 0 0 var(--green); }
@supports (interpolate-size: allow-keywords) {
  @media (prefers-reduced-motion: no-preference) {
    .faq { interpolate-size: allow-keywords; }
    .faq details::details-content {
      block-size: 0;
      overflow: hidden;
      transition: block-size 0.45s var(--ease), content-visibility 0.45s allow-discrete;
    }
    .faq details[open]::details-content { block-size: auto; }
  }
}

/* ------------------------------------------------ 26.6 Formulaire */
.field label { transition: color 0.25s var(--ease); }
.cta.nuit .field:focus-within label { color: var(--lime); }
.cta.nuit .field input:user-valid,
.cta.nuit .field textarea:user-valid { border-color: rgba(134, 227, 166, 0.65); }
.cta.nuit .field:has(:user-invalid) label { color: #ffb8a8; }
.cta.nuit .field input:user-invalid,
.cta.nuit .field textarea:user-invalid { border-color: #ffb8a8; }
.form-note.flash { animation: note-flash 0.9s var(--ease); }
@keyframes note-flash {
  from { transform: translateX(-8px); color: var(--lime); }
  to { transform: none; }
}
.btn.envoi { animation: envoi 0.5s var(--ease); }
@keyframes envoi {
  35% { transform: scale(0.96); }
  100% { transform: none; }
}

/* ------------------------------------------ 26.7 Tactile : état « appuyé » */
@media (hover: none) {
  .btn,
  .tarifs-hero a,
  .contact-lines > a,
  .faq summary { transition: transform 0.15s var(--ease), background-color 0.15s; }
  .btn:active,
  .contact-lines > a:active { transform: scale(0.97); }
  .tarifs-hero a:active { transform: scale(0.97); background-color: rgba(185, 222, 30, 0.12); }
  .faq summary:active { background-color: var(--panel); }
  .js .price.reveal.is-in:active { transform: scale(0.985); transition-duration: 0.15s; }
}
.tarifs-hero a { -webkit-tap-highlight-color: transparent; }

/* ------------------------------------------------ 26.8 Mouvement réduit */
@media (prefers-reduced-motion: reduce) {
  .hero-halo, .loupe { display: none; }
  .hero .logo-video { transform: none !important; }
  .js .price.reveal.is-in.incline { transform: none; }
  .price::before { display: none; }
  .faq details[open] summary { padding-left: 0; }
}

/* ==========================================================================
   27. LE « H » EN VRAIE 3D (2026-09-27) — avec assets/logo-3d.js
   --------------------------------------------------------------------------
   Le canvas WebGL se pose exactement sur la vidéo (même boîte : 100 % de la
   scène, 560 px au plus, carré) et passe dessous le même mode de fusion
   « screen » (posé sur .hero-art, 24.3) : son fond noir opaque disparaît sur
   l'encre comme celui de la vidéo, et le fondu enchaîné est un vrai fondu
   (l'affiche est entièrement recouverte à la fin, puis masquée).
   Il n'existe que si assets/immersif.js l'a créé : sans WebGL, avec moins
   d'animations ou l'économie de données, rien de cette section ne s'applique.
   ========================================================================== */
.hero-art .logo-stage .logo-3d {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  width: 100%;
  max-width: 560px;
  height: auto;
  aspect-ratio: 1 / 1;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.45s var(--ease);
}
.hero-art .logo-stage.h3d-pret .logo-3d { opacity: 1; }
/* Une fois le fondu fini, l'affiche n'est plus peinte */
.hero-art .logo-stage.h3d-pret .logo-video {
  visibility: hidden;
  transition: visibility 0s linear 0.45s;
}
/* Au doigt : un geste horizontal dans le hero fait tourner le « H » ;
   le défilement vertical et le zoom restent au navigateur. */
.hero.logo-3d-actif { touch-action: pan-y pinch-zoom; }

@media (prefers-reduced-motion: reduce) {
  .hero-art .logo-stage .logo-3d { display: none; }
  .hero-art .logo-stage.h3d-pret .logo-video { visibility: visible; }
}
