/* =========================================================
   FREEZON — Monochrome Editorial
   Refonte complete du design system.

   Principes :
   - Palette strictement noir / gris / blanc. Les accents se font par
     CONTRASTE et par DEGRADE de texte, jamais par une couleur d'appoint.
   - Deux themes de premier rang, pilotes par le reglage de l'appareil
     (prefers-color-scheme). Aucun theme n'est un simple "inverse" de
     l'autre : chaque palette a ses propres valeurs, verifiees a >= 4.5:1.
   - Profondeur reelle : perspective + translateZ, pas des ombres plaquees.
   - Toute animation passe par transform/opacity, et s'efface entierement
     sous prefers-reduced-motion.
   ========================================================= */

/* ---------------------------------------------------------
   Fonts
   --------------------------------------------------------- */
@font-face {
  font-family: 'Satoshi';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/Satoshi-Medium.otf') format('opentype');
}
@font-face {
  font-family: 'Satoshi';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/Satoshi-Bold.otf') format('opentype');
}
@font-face {
  font-family: 'FrauncesLocal';
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/Fraunces72pt-SemiBoldItalic.otf') format('opentype');
}

/* ---------------------------------------------------------
   Tokens — THEME CLAIR (defaut)
   Contrastes mesures sur --bg #FFFFFF :
     --text 19.3:1 · --text-dim 8.9:1 · --text-faint 5.4:1
   --------------------------------------------------------- */
:root {
  color-scheme: light dark;

  --bg:          #FFFFFF;
  --bg-2:        #F5F5F6;
  --bg-3:        #EDEDEF;
  --surface:     #FFFFFF;
  --surface-2:   #FAFAFB;

  --text:        #0B0B0D;
  --text-dim:    #4B4B52;
  --text-faint:  #6B6B73;
  --text-invert: #FFFFFF;

  --line:        rgba(11, 11, 13, 0.12);
  --line-2:      rgba(11, 11, 13, 0.22);
  --line-3:      rgba(11, 11, 13, 0.34);

  /* Surface pleine "marque" : noir en clair, blanc en sombre. */
  --brand:       #0B0B0D;
  --brand-soft:  rgba(11, 11, 13, 0.06);
  --brand-line:  rgba(11, 11, 13, 0.20);
  --on-brand:    #FFFFFF;

  /* Degrade applique au texte de titre (.grad-gold conserve son nom
     pour ne pas casser le HTML existant). */
  --grad-text:   linear-gradient(100deg, #0B0B0D 0%, #6E6E78 45%, #0B0B0D 100%);
  --grad-line:   linear-gradient(90deg, transparent, rgba(11,11,13,0.45), transparent);
  --grad-brand:  linear-gradient(135deg, #26262C 0%, #0B0B0D 55%, #000000 100%);

  --ok:          #15803D;
  --warn:        #A16207;
  --err:         #B91C1C;

  --shadow-sm:   0 1px 2px rgba(11,11,13,0.06), 0 4px 12px -6px rgba(11,11,13,0.10);
  --shadow-md:   0 8px 24px -10px rgba(11,11,13,0.16), 0 2px 6px -2px rgba(11,11,13,0.08);
  --shadow-lg:   0 28px 70px -28px rgba(11,11,13,0.30), 0 8px 24px -12px rgba(11,11,13,0.14);
  --shadow-3d:   0 40px 90px -40px rgba(11,11,13,0.38);

  --glass:       rgba(255, 255, 255, 0.72);
  --glass-solid: rgba(255, 255, 255, 0.92);

  --ease:        cubic-bezier(.19, 1, .22, 1);
  --ease-out:    cubic-bezier(.22, .61, .36, 1);
  --content:     1200px;
  --persp:       1200px;
  --radius:      18px;
  --radius-lg:   26px;

  /* Triplets RGB consommes par la config Tailwind sous la forme
     rgb(var(--x-rgb) / <alpha-value>), pour que les utilitaires a opacite
     (bg-gold/10, border-gold/30, bg-white/5) restent fonctionnels tout en
     suivant le theme. */
  --text-rgb:       11 11 13;
  --text-dim-rgb:   75 75 82;
  --text-faint-rgb: 107 107 115;
  --bg-rgb:         255 255 255;
  --surface-rgb:    245 245 246;
  --line-rgb:       11 11 13;
}

/* ---------------------------------------------------------
   Tokens — THEME SOMBRE (si l'appareil est en sombre)
   Contrastes mesures sur --bg #08080A :
     --text 18.6:1 · --text-dim 9.6:1 · --text-faint 5.6:1
   --------------------------------------------------------- */
/* Le choix manuel doit primer sur le reglage de l'appareil, dans les DEUX sens :
   - reglage sombre + choix clair  -> le :not([data-theme="light"]) neutralise le media
   - reglage clair  + choix sombre -> le bloc [data-theme="dark"] prend le relais
   Les memes tokens sont donc declares deux fois, volontairement. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:          #08080A;
    --bg-2:        #0E0E12;
    --bg-3:        #15151A;
    --surface:     #121216;
    --surface-2:   #17171D;

    --text:        #FAFAFA;
    --text-dim:    #B0B0B8;
    --text-faint:  #8A8A93;
    --text-invert: #08080A;

    --line:        rgba(255, 255, 255, 0.11);
    --line-2:      rgba(255, 255, 255, 0.20);
    --line-3:      rgba(255, 255, 255, 0.32);

    --brand:       #FAFAFA;
    --brand-soft:  rgba(250, 250, 250, 0.08);
    --brand-line:  rgba(250, 250, 250, 0.22);
    --on-brand:    #08080A;

    --grad-text:   linear-gradient(100deg, #FFFFFF 0%, #9A9AA6 45%, #FFFFFF 100%);
    --grad-line:   linear-gradient(90deg, transparent, rgba(255,255,255,0.40), transparent);
    --grad-brand:  linear-gradient(135deg, #FFFFFF 0%, #E4E4E8 55%, #C9C9D0 100%);

    --ok:          #4ADE80;
    --warn:        #FBBF24;
    --err:         #F87171;

    --shadow-sm:   0 1px 2px rgba(0,0,0,0.55), 0 4px 14px -6px rgba(0,0,0,0.60);
    --shadow-md:   0 10px 28px -12px rgba(0,0,0,0.75), 0 2px 8px -2px rgba(0,0,0,0.50);
    --shadow-lg:   0 30px 80px -30px rgba(0,0,0,0.85), 0 10px 30px -14px rgba(0,0,0,0.60);
    --shadow-3d:   0 44px 100px -44px rgba(0,0,0,0.90);

    --glass:       rgba(14, 14, 18, 0.62);
    --glass-solid: rgba(8, 8, 10, 0.88);

    --text-rgb:       250 250 250;
    --text-dim-rgb:   176 176 184;
    --text-faint-rgb: 138 138 147;
    --bg-rgb:         8 8 10;
    --surface-rgb:    18 18 22;
    --line-rgb:       255 255 255;
  }
}

:root[data-theme="dark"] {
    --bg:          #08080A;
    --bg-2:        #0E0E12;
    --bg-3:        #15151A;
    --surface:     #121216;
    --surface-2:   #17171D;

    --text:        #FAFAFA;
    --text-dim:    #B0B0B8;
    --text-faint:  #8A8A93;
    --text-invert: #08080A;

    --line:        rgba(255, 255, 255, 0.11);
    --line-2:      rgba(255, 255, 255, 0.20);
    --line-3:      rgba(255, 255, 255, 0.32);

    --brand:       #FAFAFA;
    --brand-soft:  rgba(250, 250, 250, 0.08);
    --brand-line:  rgba(250, 250, 250, 0.22);
    --on-brand:    #08080A;

    --grad-text:   linear-gradient(100deg, #FFFFFF 0%, #9A9AA6 45%, #FFFFFF 100%);
    --grad-line:   linear-gradient(90deg, transparent, rgba(255,255,255,0.40), transparent);
    --grad-brand:  linear-gradient(135deg, #FFFFFF 0%, #E4E4E8 55%, #C9C9D0 100%);

    --ok:          #4ADE80;
    --warn:        #FBBF24;
    --err:         #F87171;

    --shadow-sm:   0 1px 2px rgba(0,0,0,0.55), 0 4px 14px -6px rgba(0,0,0,0.60);
    --shadow-md:   0 10px 28px -12px rgba(0,0,0,0.75), 0 2px 8px -2px rgba(0,0,0,0.50);
    --shadow-lg:   0 30px 80px -30px rgba(0,0,0,0.85), 0 10px 30px -14px rgba(0,0,0,0.60);
    --shadow-3d:   0 44px 100px -44px rgba(0,0,0,0.90);

    --glass:       rgba(14, 14, 18, 0.62);
    --glass-solid: rgba(8, 8, 10, 0.88);

    --text-rgb:       250 250 250;
    --text-dim-rgb:   176 176 184;
    --text-faint-rgb: 138 138 147;
    --bg-rgb:         8 8 10;
    --surface-rgb:    18 18 22;
    --line-rgb:       255 255 255;
}

/* ---------------------------------------------------------
   Base
   --------------------------------------------------------- */
* { box-sizing: border-box; }

/* Progression 0 -> 1 du rail "Sous le capot". Declaree en @property pour
   etre interpolable : sans type enregistre, un nombre en custom property
   saute d'une valeur a l'autre au lieu de glisser. `inherits` permet au
   <li> anime de piloter a la fois son numero et sa barre. */
@property --on {
  syntax: '<number>';
  initial-value: 0;
  inherits: true;
}

/* Enfoncement d'une carte dans la pile "Sous le capot" : 0 devant,
   4 tout au fond. Enregistree pour la meme raison que --on, et
   heritee pour que le voile ::after la lise. */
@property --sink {
  syntax: '<number>';
  initial-value: 0;
  inherits: true;
}

/* overflow-x doit etre clippe sur html AUSSI, pas seulement sur body :
   sinon le depassement remonte au bloc conteneur initial, les elements
   position:fixed s'y dimensionnent, et le mobile garde un scroll
   horizontal (389px pour un ecran de 375px).

   `clip` et non `hidden` : `hidden` fait de l'element une boite de
   defilement, et tout `position:sticky` a l'interieur se cale alors sur
   <body> — qui ne defile pas — donc ne colle jamais. `clip` coupe le
   depassement sans creer de boite de defilement, et la section epinglee
   "Sous le capot" fonctionne. Repli en `hidden` si `clip` manque. */
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  overflow-x: hidden;
  max-width: 100%;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Satoshi', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-weight: 500;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  transition: background-color .4s var(--ease), color .4s var(--ease);
}
/* Apres les deux regles ci-dessus, sinon `hidden` reprend la main. */
@supports (overflow-x: clip) {
  html, body { overflow-x: clip; }
}

h1, h2, h3, h4, h5, h6 {
  font-family: 'Satoshi', system-ui, sans-serif;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.12;
  color: var(--text);
  margin: 0;
  text-wrap: balance;
}

p { text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
img, svg, video, canvas { max-width: 100%; display: block; }
::selection { background: var(--text); color: var(--bg); }

:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
  border-radius: 6px;
}
button:focus:not(:focus-visible),
a:focus:not(:focus-visible) { outline: none; }

/* NE PAS redefinir .hidden ici : Tailwind fournit deja cette classe, et
   un `!important` ecraserait toutes ses variantes responsives
   (hidden md:inline-flex resterait masque a toutes les largeurs). */

.wrap { max-width: var(--content); margin: 0 auto; padding: 0 20px; }
@media (min-width: 1024px) { .wrap { padding: 0 32px; } }

.section { position: relative; padding: 96px 0; }
@media (min-width: 768px) { .section { padding: 128px 0; } }
.sub-sec { position: relative; padding: 56px 0; }

/* ---------------------------------------------------------
   Typographie
   --------------------------------------------------------- */
.serif {
  font-family: 'FrauncesLocal', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.script { font-family: 'Caveat', cursive; }

.eyebrow {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.h-sec {
  font-size: clamp(30px, 5vw, 52px);
  letter-spacing: -0.035em;
  margin-top: 14px;
}

.hero-title {
  font-size: clamp(34px, 6.4vw, 68px);
  letter-spacing: -0.04em;
  line-height: 1.06;
}

.hero-lead {
  font-size: clamp(14px, 1.7vw, 16.5px);
  line-height: 1.6;
  color: var(--text-dim);
}

/* Degrade de texte — nom conserve pour compatibilite du HTML */
.grad-gold {
  background: var(--grad-text);
  background-size: 220% auto;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: gradFlow 9s ease-in-out infinite;
}
@keyframes gradFlow {
  0%, 100% { background-position: 0% center; }
  50%      { background-position: 130% center; }
}

.link {
  color: var(--text-dim);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--line-2);
  transition: color .2s, text-decoration-color .2s;
}
.link:hover { color: var(--text); text-decoration-color: var(--text); }

.u { color: var(--text); }
.n { font-size: 30px; font-weight: 700; color: var(--text); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.l { font-size: 12.5px; color: var(--text-faint); margin-top: 2px; }
.q { font-weight: 700; color: var(--text); }
.lbl { font-size: 12.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint); }
.blk { display: block; }
.row { display: flex; align-items: center; gap: 10px; }

/* ---------------------------------------------------------
   Fond ambiant — champ neutre, halos gris, grain
   --------------------------------------------------------- */
.field {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 50% -10%, var(--brand-soft), transparent 55%),
    linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 45%, var(--bg) 100%);
}
.field::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity: 0.035;
  mix-blend-mode: multiply;
}
:root[data-theme="dark"] .field::after { mix-blend-mode: overlay; opacity: 0.05; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .field::after { mix-blend-mode: overlay; opacity: 0.05; }
}

.aurora {
  position: fixed;
  border-radius: 50%;
  filter: blur(110px);
  opacity: 0.55;
  z-index: -1;
  pointer-events: none;
  will-change: transform;
}
.aurora--1 {
  width: 55vw; height: 55vw; max-width: 720px; max-height: 720px; top: -12%; left: -8%;
  background: radial-gradient(circle at 40% 40%, var(--brand-soft), transparent 70%);
  animation: drift1 26s var(--ease) infinite alternate;
}
.aurora--2 {
  width: 48vw; height: 48vw; max-width: 640px; max-height: 640px; bottom: -18%; right: -10%;
  background: radial-gradient(circle at 60% 40%, var(--brand-soft), transparent 72%);
  animation: drift2 32s var(--ease) infinite alternate;
}
@keyframes drift1 { from { transform: translate3d(0,0,0) scale(1); }   to { transform: translate3d(60px,80px,0) scale(1.15); } }
@keyframes drift2 { from { transform: translate3d(0,0,0) scale(1); }   to { transform: translate3d(-70px,-50px,0) scale(1.1); } }
@media (max-width: 640px) { .aurora { filter: blur(70px); opacity: 0.4; } }

/* ---------------------------------------------------------
   Barre de progression de lecture
   --------------------------------------------------------- */
.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px;
  background: var(--text);
  transform-origin: left center;
  transform: scaleX(0);
  z-index: 60;
  pointer-events: none;
}

/* ---------------------------------------------------------
   Header flottant
   --------------------------------------------------------- */
#site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  padding: 14px 16px 0;
  transition: padding .35s var(--ease);
}
#site-header .nav-row {
  height: 62px;
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 0 12px 0 20px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--line);
  backdrop-filter: blur(20px) saturate(150%);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  box-shadow: var(--shadow-md);
  transition: background .35s var(--ease), border-color .35s var(--ease), box-shadow .35s var(--ease);
}
#site-header.is-scrolled { padding-top: 10px; }
#site-header.is-scrolled .nav-row {
  background: var(--glass-solid);
  border-color: var(--line-2);
  box-shadow: var(--shadow-lg);
}
#site-header .nav-links { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); }

/* Sur ordinateur, la pastille se resserre sur son contenu au lieu de
   barrer toute la largeur. La navigation repasse dans le flux : en
   absolu elle ne compterait pas dans la largeur, et la pastille se
   refermerait sur le logo et les boutons en laissant les liens dehors. */
@media (min-width: 1024px) {
  #site-header .nav-row {
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;
    justify-content: flex-start;
    gap: 34px;
    padding: 0 10px 0 22px;
  }
  #site-header .nav-links { position: static; transform: none; }
}

/* --------------------------------------------------------------------
   Pastille inversee.
   Le fond prend la couleur pleine de la marque, et tout le jeu de
   tokens bascule sur le theme oppose a l'interieur. Les enfants lisent
   var(--text), var(--line), var(--brand)... : ils s'inversent donc
   seuls, y compris le bouton "Etudier mon projet" et l'interrupteur.
   Le fond est ecrit en dur parce que --brand est justement redefini
   deux lignes plus bas — var(--brand) y lirait la valeur inversee.
   -------------------------------------------------------------------- */
#site-header .nav-row {
  background: #0B0B0D;
  border-color: rgba(255, 255, 255, 0.12);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  /* Indispensable : redefinir --text ne touche que les elements qui
     l'appellent explicitement. Le burger, lui, herite simplement de
     `color` — donc de <body>, donc de la couleur de la PAGE. Sans cette
     ligne il ressort blanc sur pastille blanche. */
  color: var(--text);

  --text:        #FAFAFA;
  --text-dim:    #B0B0B8;
  --text-faint:  #8A8A93;
  --bg:          #08080A;
  --bg-2:        #0E0E12;
  --bg-3:        #15151A;
  --line:        rgba(255, 255, 255, 0.11);
  --line-2:      rgba(255, 255, 255, 0.20);
  --line-3:      rgba(255, 255, 255, 0.32);
  --brand:       #FAFAFA;
  --brand-soft:  rgba(250, 250, 250, 0.08);
  --brand-line:  rgba(250, 250, 250, 0.22);
  --on-brand:    #08080A;
  --grad-brand:  linear-gradient(135deg, #FFFFFF 0%, #E4E4E8 55%, #C9C9D0 100%);
  --text-rgb:       250 250 250;
  --text-dim-rgb:   176 176 184;
  --text-faint-rgb: 138 138 147;
}
/* Au defilement, la pastille se fige un cran plus contrastee. */
#site-header.is-scrolled .nav-row {
  background: #000000;
  border-color: rgba(255, 255, 255, 0.18);
}

/* Page sombre : la pastille passe au clair, et les tokens repassent au
   jeu clair. Declare deux fois pour la meme raison que les themes eux-
   memes : le reglage systeme et l'interrupteur manuel sont deux chemins
   distincts. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) #site-header .nav-row {
    background: #FAFAFA;
    border-color: rgba(11, 11, 13, 0.14);
    --text:        #0B0B0D;
    --text-dim:    #4B4B52;
    --text-faint:  #6B6B73;
    --bg:          #FFFFFF;
    --bg-2:        #F5F5F6;
    --bg-3:        #EDEDEF;
    --line:        rgba(11, 11, 13, 0.12);
    --line-2:      rgba(11, 11, 13, 0.22);
    --line-3:      rgba(11, 11, 13, 0.34);
    --brand:       #0B0B0D;
    --brand-soft:  rgba(11, 11, 13, 0.06);
    --brand-line:  rgba(11, 11, 13, 0.20);
    --on-brand:    #FFFFFF;
    --grad-brand:  linear-gradient(135deg, #26262C 0%, #0B0B0D 55%, #000000 100%);
    --text-rgb:       11 11 13;
    --text-dim-rgb:   75 75 82;
    --text-faint-rgb: 107 107 115;
  }
  :root:not([data-theme="light"]) #site-header.is-scrolled .nav-row {
    background: #FFFFFF;
    border-color: rgba(11, 11, 13, 0.20);
  }
}
:root[data-theme="dark"] #site-header .nav-row {
  background: #FAFAFA;
  border-color: rgba(11, 11, 13, 0.14);
  --text:        #0B0B0D;
  --text-dim:    #4B4B52;
  --text-faint:  #6B6B73;
  --bg:          #FFFFFF;
  --bg-2:        #F5F5F6;
  --bg-3:        #EDEDEF;
  --line:        rgba(11, 11, 13, 0.12);
  --line-2:      rgba(11, 11, 13, 0.22);
  --line-3:      rgba(11, 11, 13, 0.34);
  --brand:       #0B0B0D;
  --brand-soft:  rgba(11, 11, 13, 0.06);
  --brand-line:  rgba(11, 11, 13, 0.20);
  --on-brand:    #FFFFFF;
  --grad-brand:  linear-gradient(135deg, #26262C 0%, #0B0B0D 55%, #000000 100%);
  --text-rgb:       11 11 13;
  --text-dim-rgb:   75 75 82;
  --text-faint-rgb: 107 107 115;
}
:root[data-theme="dark"] #site-header.is-scrolled .nav-row {
  background: #FFFFFF;
  border-color: rgba(11, 11, 13, 0.20);
}

.logo { display: inline-flex; align-items: center; gap: 10px; }
.logo__word { font-weight: 700; font-size: 19px; letter-spacing: -0.02em; color: var(--text); }
.logo__dot { width: 5px; height: 5px; border-radius: 50%; background: var(--text); margin-left: 1px; margin-top: 10px; }

/* Le logo est un PNG clair : on le force en monochrome sur le ton du
   texte, donc noir en theme clair et blanc en theme sombre. */
.brand-logo {
  height: 36px; width: auto;
  filter: brightness(0) saturate(100%);
  transition: filter .25s var(--ease), transform .25s var(--ease);
}
/* Le logo doit suivre le CHOIX de theme, pas seulement le reglage de
   l'appareil : sinon, appareil sombre + choix clair = logo blanc sur blanc. */
:root[data-theme="dark"] .brand-logo { filter: brightness(0) invert(1); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-logo { filter: brightness(0) invert(1); }
}
/* Dans l'en-tete, le logo s'inverse a CONTRE-COURANT du reste du site :
   la pastille est sombre quand la page est claire. Sans ces deux regles,
   on obtiendrait un logo noir sur pastille noire. Le logo du pied de
   page, lui, garde le comportement normal. */
#site-header .brand-logo { filter: brightness(0) invert(1); }
:root[data-theme="dark"] #site-header .brand-logo { filter: brightness(0) saturate(100%); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) #site-header .brand-logo { filter: brightness(0) saturate(100%); }
}
@media (min-width: 640px) { .brand-logo { height: 42px; } }
.logo:hover .brand-logo { transform: translateY(-1px) scale(1.02); }
.brand-logo--footer { height: 48px; }
@media (min-width: 640px) { .brand-logo--footer { height: 56px; } }

/* Liens de reseaux du pied de page : le nom, une fleche de sortie, rien
   d'autre. Les glyphes de marque ont ete retires — a cette taille ils se
   lisaient mal et cassaient le monochrome. */
.footer-social {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--text-dim);
  transition: color .2s var(--ease);
}
.footer-social svg {
  flex: none;
  color: var(--text-faint);
  transition: transform .25s var(--ease), color .2s var(--ease);
}
.footer-social:hover { color: var(--text); }
.footer-social:hover svg { color: var(--text); transform: translate(2px, -2px); }

/* =========================================================
   Section de sortie — le dernier appel a l'action
   Pleine page, aeree, un seul bouton. Elle et le pied de page
   partagent le meme filigrane, qui court de l'une a l'autre.
   ========================================================= */
/* --------------------------------------------------------------------
   Fin de page inversee.
   La section de sortie et le pied de page forment un seul bloc plein,
   a l'oppose de la page : noir sur page claire, blanc sur page sombre.
   Meme procede que la pastille de l'en-tete — le fond est ecrit en dur
   et tout le jeu de tokens bascule sur le theme oppose, donc les
   liens, le bouton et les traits s'inversent seuls.
   -------------------------------------------------------------------- */
.outro, .page-end {
  background: #0B0B0D;
  color: var(--text);

  --text:        #FAFAFA;
  --text-dim:    #B0B0B8;
  --text-faint:  #8A8A93;
  --bg:          #08080A;
  --bg-2:        #0E0E12;
  --bg-3:        #15151A;
  --surface:     #121216;
  --line:        rgba(255, 255, 255, 0.11);
  --line-2:      rgba(255, 255, 255, 0.20);
  --line-3:      rgba(255, 255, 255, 0.32);
  --brand:       #FAFAFA;
  --brand-soft:  rgba(250, 250, 250, 0.08);
  --brand-line:  rgba(250, 250, 250, 0.22);
  --on-brand:    #08080A;
  --ok:          #4ADE80;
  --grad-brand:  linear-gradient(135deg, #FFFFFF 0%, #E4E4E8 55%, #C9C9D0 100%);
  --grad-text:   linear-gradient(100deg, #FFFFFF 0%, #9A9AA6 45%, #FFFFFF 100%);
  --text-rgb:       250 250 250;
  --text-dim-rgb:   176 176 184;
  --text-faint-rgb: 138 138 147;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .outro,
  :root:not([data-theme="light"]) .page-end {
    background: #FAFAFA;
    --text:        #0B0B0D;
    --text-dim:    #4B4B52;
    --text-faint:  #6B6B73;
    --bg:          #FFFFFF;
    --bg-2:        #F5F5F6;
    --bg-3:        #EDEDEF;
    --surface:     #FFFFFF;
    --line:        rgba(11, 11, 13, 0.12);
    --line-2:      rgba(11, 11, 13, 0.22);
    --line-3:      rgba(11, 11, 13, 0.34);
    --brand:       #0B0B0D;
    --brand-soft:  rgba(11, 11, 13, 0.06);
    --brand-line:  rgba(11, 11, 13, 0.20);
    --on-brand:    #FFFFFF;
    --ok:          #15803D;
    --grad-brand:  linear-gradient(135deg, #26262C 0%, #0B0B0D 55%, #000000 100%);
    --grad-text:   linear-gradient(100deg, #0B0B0D 0%, #6E6E78 45%, #0B0B0D 100%);
    --text-rgb:       11 11 13;
    --text-dim-rgb:   75 75 82;
    --text-faint-rgb: 107 107 115;
  }
}
:root[data-theme="dark"] .outro,
:root[data-theme="dark"] .page-end {
  background: #FAFAFA;
  --text:        #0B0B0D;
  --text-dim:    #4B4B52;
  --text-faint:  #6B6B73;
  --bg:          #FFFFFF;
  --bg-2:        #F5F5F6;
  --bg-3:        #EDEDEF;
  --surface:     #FFFFFF;
  --line:        rgba(11, 11, 13, 0.12);
  --line-2:      rgba(11, 11, 13, 0.22);
  --line-3:      rgba(11, 11, 13, 0.34);
  --brand:       #0B0B0D;
  --brand-soft:  rgba(11, 11, 13, 0.06);
  --brand-line:  rgba(11, 11, 13, 0.20);
  --on-brand:    #FFFFFF;
  --ok:          #15803D;
  --grad-brand:  linear-gradient(135deg, #26262C 0%, #0B0B0D 55%, #000000 100%);
  --grad-text:   linear-gradient(100deg, #0B0B0D 0%, #6E6E78 45%, #0B0B0D 100%);
  --text-rgb:       11 11 13;
  --text-dim-rgb:   75 75 82;
  --text-faint-rgb: 107 107 115;
}

/* Le logo du pied de page s'inverse a contre-courant du reste du site,
   comme celui de l'en-tete : le bloc est sombre quand la page est
   claire. Specificite calculee pour battre les regles de theme sur
   .brand-logo, qui pesent (0,3,0). */
.page-end .brand-logo { filter: brightness(0) invert(1); }
:root[data-theme="dark"] .page-end .brand-logo { filter: brightness(0) saturate(100%); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .page-end .brand-logo { filter: brightness(0) saturate(100%); }
}

.outro {
  position: relative;
  text-align: center;
  padding: 128px 0 104px;
}
@media (min-width: 768px) { .outro { padding: 168px 0 132px; } }
.outro__inner { position: relative; z-index: 1; }

/* Surtitre encadre de deux equerres, en echo au cadrage d'un viseur. */
.outro__eyebrow {
  display: inline-block;
  position: relative;
  padding: 7px 16px;
  font-size: 12.5px;
  color: var(--text-dim);
}
.outro__eyebrow::before,
.outro__eyebrow::after {
  content: "";
  position: absolute;
  width: 11px; height: 11px;
  border: 1px solid var(--line-3);
}
.outro__eyebrow::before { left: 0; bottom: 0; border-top: 0; border-right: 0; }
.outro__eyebrow::after  { right: 0; top: 0;   border-bottom: 0; border-left: 0; }

.outro__title {
  margin: 22px auto 0;
  max-width: 16ch;
  font-size: clamp(32px, 5.2vw, 62px);
  line-height: 1.06;
  letter-spacing: -0.035em;
}
.outro__lead {
  margin: 22px auto 0;
  max-width: 52ch;
  font-size: 15.5px;
  line-height: 1.7;
  color: var(--text-dim);
}
.outro__cta { margin-top: 38px; }
.btn--xl { min-height: 56px; padding: 0 30px; font-size: 15.5px; }

.outro__note {
  display: inline-flex; align-items: center; gap: 9px;
  margin-top: 22px;
  font-size: 13px;
  color: var(--text-faint);
}
.outro__note a { color: var(--text-dim); text-decoration: underline; text-underline-offset: 3px; }
.outro__note a:hover { color: var(--text); }
.outro__dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ok); flex: none;
}

/* =========================================================
   Filigrane du pied de page
   Un embleme geant, presque efface, derriere le contenu. Il ferme la
   page sur la marque sans rien ajouter a lire.

   L'embleme n'existe pas en fichier separe : icon.png a un fond noir
   opaque, inutilisable en filigrane. On recadre donc a la volee le
   lockup new-logo.png, dont l'embleme occupe exactement x 71->274 et
   y 65->281 sur 749x333. Les pourcentages rendent le recadrage
   independant de la taille d'affichage : la largeur de l'image vaut
   749/204 de la boite, et son decalage 71/204 vers la gauche.
   ========================================================= */
footer { position: relative; }
footer > .wrap { position: relative; z-index: 1; }

/* Le filigrane est ancre au pied de page mais deborde largement vers le
   HAUT, pour courir aussi derriere la section de sortie — c'est ce qui
   relie les deux blocs en une seule fin de page.

   z-index: 0 et non -1 : depuis que la fin de page porte un fond plein,
   un element negatif passerait SOUS ce fond et disparaitrait — les
   fonds de blocs en flux se peignent apres les couches negatives. A
   zero, l'embleme etant positionne, il passe au-dessus des deux fonds
   et reste sous le contenu, qui est cale a z-index 1. */
.footer-mark {
  position: absolute;
  left: 50%;
  bottom: -70px;
  height: clamp(430px, 54vw, 780px);
  aspect-ratio: 204 / 217;
  max-width: 88vw;
  transform: translateX(-50%);
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  /* Assez present pour se deviner, assez faible pour ne jamais disputer
     la lisibilite du texte pose dessus. */
  opacity: 0.06;
  /* Le PNG est blanc et le bloc est sombre en theme clair : on le laisse
     tel quel. C'est l'inverse du reste du site, comme le logo. */
  filter: none;
}
.footer-mark img {
  position: absolute;
  width: calc(749 / 204 * 100%);
  height: auto;
  max-width: none;
  left: calc(-71 / 204 * 100%);
  top: calc(-65 / 217 * 100%);
}
/* Page sombre : le bloc de fin passe au blanc, l'embleme doit donc
   virer au noir. */
:root[data-theme="dark"] .footer-mark { filter: brightness(0) saturate(100%); opacity: 0.07; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .footer-mark { filter: brightness(0) saturate(100%); opacity: 0.07; }
}
@media (max-width: 639px) {
  .footer-mark { height: auto; width: 92vw; bottom: -40px; }
}

.nav-links { display: none; }
@media (min-width: 1024px) { .nav-links { display: flex; align-items: center; gap: 30px; } }
.nav-link-anim {
  position: relative; font-size: 14px; color: var(--text-dim);
  transition: color .2s; padding: 4px 0;
}
.nav-link-anim::after {
  content: ""; position: absolute; left: 0; bottom: -2px; height: 1.5px; width: 0;
  background: var(--text); border-radius: 2px; transition: width .25s var(--ease);
}
.nav-link-anim:hover, .nav-link-anim.is-active { color: var(--text); }
.nav-link-anim:hover::after, .nav-link-anim.is-active::after { width: 100%; }

/* ---------------------------------------------------------
   Boutons
   --------------------------------------------------------- */
.btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 46px; padding: 0 24px; border-radius: 999px;
  font-size: 14.5px; font-weight: 700; letter-spacing: 0.01em;
  cursor: pointer; border: 0; white-space: nowrap;
  transform: translateZ(0);
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), background-color .25s, color .25s, border-color .25s;
  isolation: isolate;
}
.btn svg { transition: transform .25s var(--ease); }

/* Paire de boutons. Cote a cote tant qu'ils tiennent ; en dessous ils
   passent en colonne PLEINE LARGEUR. Sans ca, `flex-wrap` les empile en
   gardant leur largeur propre — deux pastilles de tailles differentes
   collees a gauche, ce qui a l'air d'un accident de mise en page. */
.btn-row { display: flex; flex-wrap: wrap; gap: 12px; }
@media (max-width: 520px) {
  .btn-row { display: grid; grid-template-columns: 1fr; }
  .btn-row .btn { width: 100%; }
}

/* .btn--gold : nom conserve, rendu desormais monochrome plein */
.btn--gold {
  color: var(--on-brand);
  background: var(--grad-brand);
  box-shadow: var(--shadow-md);
}
.btn--gold:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
.btn--gold:hover svg { transform: translateX(3px); }
.btn--gold:active { transform: translateY(0) scale(.98); }

.btn--ghost {
  color: var(--text);
  background: transparent;
  border: 1px solid var(--line-2);
}
.btn--ghost:hover { border-color: var(--text); background: var(--brand-soft); transform: translateY(-2px); }
.btn--ghost:active { transform: translateY(0) scale(.98); }

.btn--icon { width: 46px; padding: 0; border-radius: 50%; }

.btn-glass-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--brand-soft);
  border: 1px solid var(--line);
  color: var(--text);
  cursor: pointer;
  transition: background .2s, border-color .2s, transform .2s var(--ease);
}
.btn-glass-icon:hover { background: var(--bg-3); border-color: var(--line-2); transform: translateY(-1px); }

.magnetic { transition: transform .25s var(--ease); }

/* ---------------------------------------------------------
   Surfaces
   --------------------------------------------------------- */
.panel {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.panel--pad { padding: 28px; }
@media (min-width: 768px) { .panel--pad { padding: 40px; } }

.pill {
  display: inline-flex; align-items: center;
  padding: 4px 11px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .16em;
  background: var(--brand-soft);
  border: 1px solid var(--brand-line);
  color: var(--text);
}

.tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border-radius: 999px;
  font-size: 13.5px; font-weight: 700; white-space: nowrap;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--text-dim);
}

.ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 12px;
  background: var(--brand-soft);
  border: 1px solid var(--line);
  color: var(--text);
}

.badge-soon {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  background: var(--bg-3); border: 1px solid var(--line-2); color: var(--text-dim);
}

/* Epingle en haut a droite de la carte SEO (la carte est position:relative) */
.seo-badge {
  position: absolute; top: 22px; right: 22px;
  display: inline-flex; align-items: baseline; gap: 3px;
  padding: 4px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 700;
  background: var(--brand-soft); border: 1px solid var(--brand-line); color: var(--text);
}

/* ---------------------------------------------------------
   PROFONDEUR 3D — inclinaison des cartes au survol
   --------------------------------------------------------- */
.cap-grid, .steps { perspective: var(--persp); }

.card-lift {
  transform-style: preserve-3d;
  transition: transform .5s var(--ease), box-shadow .5s var(--ease), border-color .3s;
  will-change: transform;
}
@media (hover: hover) and (pointer: fine) {
  .card-lift:hover {
    transform: translate3d(0, -8px, 24px) rotateX(3.5deg) rotateY(-3.5deg);
    box-shadow: var(--shadow-3d);
    border-color: var(--line-2);
  }
  .card-lift:hover .cap__num { transform: translateZ(30px); }
  .card-lift:hover .cap__title { transform: translateZ(18px); }
}

/* ---------------------------------------------------------
   MOUVEMENT — glissements au scroll
   `.is-in-view` est pose par app.js via IntersectionObserver.
   --------------------------------------------------------- */
/* Apparitions au defilement.
   Reglage volontairement discret : le mouvement doit accompagner la
   lecture, pas l'annoncer. Trois choses le rendent invisible en tant
   qu'effet — une course courte (18 px, pas 34), une duree franche
   (0,5 s, pas 0,85) et surtout un declenchement en avance, cale dans
   l'observateur : quand l'oeil arrive sur le bloc, il est deja pose.
   La rotation 3D des entrees laterales a saute : a 6 degres elle
   signait l'animation au lieu de la faire oublier. */
.reveal, .reveal-left, .reveal-right, .reveal-stagger > * {
  opacity: 0;
  transition: opacity .5s var(--ease-out), transform .58s var(--ease);
  will-change: transform, opacity;
}
.reveal        { transform: translate3d(0, 18px, 0); }
.reveal-left   { transform: translate3d(-22px, 0, 0); }
.reveal-right  { transform: translate3d(22px, 0, 0); }
.reveal-stagger > * { transform: translate3d(0, 14px, 0); }

.reveal.is-in-view,
.reveal-left.is-in-view,
.reveal-right.is-in-view {
  opacity: 1;
  transform: translate3d(0, 0, 0) rotateY(0);
}
.reveal-stagger.is-in-view > * { opacity: 1; transform: translate3d(0, 0, 0); }
/* Decalages resserres : 0,45 s d'attente pour le sixieme element se
   voyait comme un chargement. Le dernier part maintenant a 0,25 s. */
.reveal-stagger.is-in-view > *:nth-child(1) { transition-delay: .03s; }
.reveal-stagger.is-in-view > *:nth-child(2) { transition-delay: .08s; }
.reveal-stagger.is-in-view > *:nth-child(3) { transition-delay: .13s; }
.reveal-stagger.is-in-view > *:nth-child(4) { transition-delay: .17s; }
.reveal-stagger.is-in-view > *:nth-child(5) { transition-delay: .21s; }
.reveal-stagger.is-in-view > *:nth-child(6) { transition-delay: .25s; }
/* Fois posee, la carte reprend ses propres transitions — sinon le delay
   d'entree fuit sur le hover et la carte met 130-450 ms a s'incliner. */
.reveal-stagger.is-in-view > .card-lift.is-tilting,
.reveal-stagger.is-in-view > .card-lift:hover { transition-delay: 0s; }

/* Entree du hero — pilotee par .freezon-ready pose au DOMContentLoaded */
.freezon-js .hero-anim { opacity: 0; transform: translate3d(0, 30px, 0); filter: blur(12px); }
.freezon-ready .hero-anim {
  opacity: 1; transform: none; filter: blur(0);
  transition: opacity 1s var(--ease), transform 1s var(--ease), filter 1s var(--ease);
}
.freezon-ready .hero-anim.d1 { transition-delay: .30s; }
.freezon-ready .hero-anim.d2 { transition-delay: .44s; }
.freezon-ready .hero-anim.d3 { transition-delay: .58s; }
.freezon-ready .hero-anim.d4 { transition-delay: .72s; }
.freezon-ready .hero-anim.d5 { transition-delay: .86s; }

.freezon-ready .reveal-chars .ch { animation: chIn .7s var(--ease) forwards; }
@keyframes chIn { from { opacity: 0; transform: translate3d(0, .5em, 0); } to { opacity: 1; transform: none; } }

/* ---------------------------------------------------------
   Hero
   --------------------------------------------------------- */
/* Hero compact : il occupait tout l'ecran (100svh), ce qui repoussait
   la premiere preuve sous la ligne de flottaison. Hauteur libre et
   rembourrage mesure : le visiteur voit deja la suite en arrivant. */
.hero-section {
  position: relative;
  min-height: 0;
  display: flex;
  align-items: center;
  padding: 132px 0 64px;
  perspective: var(--persp);
}
.hero-inner { position: relative; z-index: 2; width: 100%; }

.hero-vignette {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(70% 55% at 50% 45%, transparent 40%, var(--bg) 100%);
}

#hero-canvas { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; }

.hero-badge {
  display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 18px 9px 9px; border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--line);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  font-size: 13.5px;
  color: var(--text-dim);
  box-shadow: var(--shadow-sm);
}
.hero-badge b { color: var(--text); font-weight: 700; }

.hero-mock { position: relative; transform-style: preserve-3d; }

/* ---------------------------------------------------------
   Bandeau defilant (secteurs)
   --------------------------------------------------------- */
.marquee {
  display: flex; align-items: center; gap: 14px; width: max-content;
  animation: marquee 38s linear infinite;
}
@keyframes marquee { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }
.marquee:hover { animation-play-state: paused; }
.marquee-mask {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

/* ---------------------------------------------------------
   Cartes "savoir-faire"
   --------------------------------------------------------- */
/* Grille bento : une carte dominante, puis des tailles decroissantes.
   Quatre cartes identiques alignees n'etablissent aucune hierarchie ;
   ici l'oeil sait par ou commencer. */
.cap-grid { display: grid; gap: 20px; }
@media (min-width: 768px) {
  .cap-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1100px) {
  .cap-grid { grid-template-columns: repeat(12, 1fr); grid-auto-rows: minmax(0, auto); }
  .cap--tall { grid-column: span 5; grid-row: span 2; }
  .cap--wide { grid-column: span 7; }
  .cap--md   { grid-column: span 4; }
  .cap--sm   { grid-column: span 3; }
}

.cap {
  position: relative;
  display: flex; flex-direction: column;
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.cap__stage { margin-top: auto; padding-top: 22px; }
.cap__num { font-size: 11.5px; font-weight: 700; letter-spacing: .18em; color: var(--text-faint); transition: transform .5s var(--ease); }
.cap__title { font-size: 19px; font-weight: 700; margin-top: 8px; color: var(--text); transition: transform .5s var(--ease); }
.cap__desc { font-size: 14.5px; line-height: 1.6; color: var(--text-dim); margin-top: 10px; }

/* --- vignette 01 : WEB (blocs qui se construisent) --- */
.demo-web {
  height: 130px; border-radius: 12px; padding: 12px; overflow: hidden;
  border: 1px solid var(--line); background: var(--brand-soft);
}
.demo-web .row {
  height: 9px; border-radius: 4px; background: var(--line-2); margin-bottom: 8px;
  transform-origin: left; animation: buildRow 3.2s var(--ease) infinite;
}
.demo-web .row:nth-child(1) { width: 40%; background: var(--line-3); }
.demo-web .row:nth-child(2) { width: 88%; animation-delay: .15s; }
.demo-web .row:nth-child(3) { width: 70%; animation-delay: .3s; }
.demo-web .blk {
  height: 42px; border-radius: 8px; border: 1px solid var(--line-2);
  background: linear-gradient(135deg, var(--brand-soft), transparent);
  animation: buildRow 3.2s var(--ease) .45s infinite;
}
@keyframes buildRow { 0% { transform: scaleX(0); opacity: 0; } 18%, 100% { transform: scaleX(1); opacity: 1; } }

/* --- vignette 02 : ANIMATION (satellite en orbite) --- */
.demo-anim { height: 130px; display: grid; place-items: center; }
.orbit { position: relative; width: 110px; height: 110px; }
.orbit__core {
  position: absolute; inset: 42px; border-radius: 50%;
  background: radial-gradient(circle, var(--text), var(--text-dim));
}
.orbit__ring { position: absolute; inset: 0; border-radius: 50%; border: 1px dashed var(--line-2); animation: spin 9s linear infinite; }
.orbit__ring:nth-child(2) { inset: 18px; border-style: solid; border-color: var(--line); animation-duration: 6s; animation-direction: reverse; }
.orbit__sat {
  position: absolute; top: -4px; left: 50%; width: 10px; height: 10px;
  border-radius: 50%; background: var(--text); transform: translateX(-50%);
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --- vignette 03 : SEO (histogramme qui grimpe) ---
   flex + align-items:flex-end : sans cela les barres prennent toute la
   largeur et s'empilent en un aplat gris. */
.demo-seo { height: 130px; display: flex; align-items: flex-end; gap: 8px; }
.demo-seo .bar {
  flex: 1; border-radius: 6px 6px 0 0;
  background: linear-gradient(180deg, var(--text), var(--text-faint));
  transform-origin: bottom; animation: grow 3s var(--ease) infinite;
}
.demo-seo .bar:nth-child(1) { animation-delay: 0s; }
.demo-seo .bar:nth-child(2) { animation-delay: .2s; }
.demo-seo .bar:nth-child(3) { animation-delay: .4s; }
.demo-seo .bar:nth-child(4) { animation-delay: .6s; }
.demo-seo .bar:nth-child(5) { animation-delay: .8s; }
@keyframes grow { 0% { transform: scaleY(.15); } 50% { transform: scaleY(1); } 100% { transform: scaleY(.35); } }

/* --- vignette 04 : SYSTEMES (graphe SVG) ---
   .node / .link / .ping sont des elements SVG : ils se peignent avec
   fill/stroke, pas avec background. */
.demo-sys { height: 130px; }
.demo-sys svg { width: 100%; height: 100%; }
.demo-sys .link { stroke: var(--line-3); stroke-width: 1.5; fill: none; stroke-dasharray: 5 6; animation: dash 2.4s linear infinite; }
.demo-sys .node { fill: var(--bg); stroke: var(--text); stroke-width: 1.5; }
.demo-sys .node--core { fill: var(--text); }
/* Les deux noeuds actifs n'ont plus de cercle du tout : le logo du
   service branche prend toute la place, a une taille bien superieure
   aux pastilles restantes. Les deux traits qui y menent s'arretent
   court — les logos ont des zones transparentes, un trait pointille
   passant dessous se serait vu au travers.

   L'ancienne animation `ping` faisait varier r, sans effet sur une
   <image> : on respire donc en opacite. */
.demo-sys .node-logo { animation: nodeLogo 2.4s ease-in-out infinite; }
@keyframes dash { to { stroke-dashoffset: -22; } }
@keyframes nodeLogo { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .demo-sys .node-logo { animation: none; opacity: 1; }
}

.phone-ring { animation: ring 3.4s var(--ease) infinite; transform-origin: 50% 10%; }
@keyframes ring {
  0%, 100% { transform: rotate(0deg); }
  10% { transform: rotate(12deg); } 20% { transform: rotate(-10deg); }
  30% { transform: rotate(8deg); }  40% { transform: rotate(0deg); }
}

/* =========================================================
   SECTION "SOUS LE CAPOT" — le jeu de couches
   Cinq cartes s'enfilent sur une pile pendant que la section reste
   epinglee. Chaque carte porte une miniature de ce que la couche fait
   vraiment ; celles deja posees reculent et ne laissent voir que leur
   onglet, comme des intercalaires.

   ETAT DE BASE (ci-dessous) = version statique, complete et lisible :
   pas d'epinglage, pas de hauteur demesuree, les cinq textes en liste.
   C'est ce que voient les navigateurs sans animations de defilement,
   et les utilisateurs en mouvement reduit. Toute la mise en scene vit
   dans le bloc @supports plus bas.
   ========================================================= */
.deck-section { position: relative; padding: 96px 0; }
.deck-head { max-width: 640px; margin: 0 auto; text-align: center; }
.deck-lead { font-size: 15.5px; line-height: 1.65; color: var(--text-dim); }

.deck { display: grid; gap: 44px; align-items: center; margin-top: 48px; }
@media (min-width: 1024px) { .deck { grid-template-columns: 1fr 1fr; gap: 64px; } }

/* --- La pile --- */
.deck-stage {
  position: relative;
  height: 300px;
  display: grid;
  place-items: center;
  perspective: 1500px;
  perspective-origin: 50% 38%;
  transform-style: preserve-3d;
}
@media (min-width: 640px) { .deck-stage { height: 360px; } }

.deck-card {
  position: absolute;
  width: min(84vw, 340px);
  aspect-ratio: 16 / 10;
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  border: 1px solid var(--line-2);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  /* --sink = nombre de cartes posees par-dessus celle-ci. Un seul
     nombre pilote la pose ET l'enfoncement visuel. */
  --step-y: -28px;
  --step-z: -118px;
  transform: translate3d(0, calc(var(--step-y) * var(--sink, 0)), calc(var(--step-z) * var(--sink, 0))) rotateX(6deg);
}
/* Voile d'enfoncement. On assombrit la carte au lieu de la rendre
   translucide : une carte a demi transparente laisse voir celle du
   dessous a travers, et la pile devient illisible. */
.deck-card::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: var(--bg);
  opacity: calc(var(--sink, 0) * 0.15);
}
.deck-card:nth-child(1) { --sink: 4; }
.deck-card:nth-child(2) { --sink: 3; }
.deck-card:nth-child(3) { --sink: 2; }
.deck-card:nth-child(4) { --sink: 1; }
.deck-card:nth-child(5) { --sink: 0; }
@media (max-width: 1023px) {
  .deck-card { width: min(76vw, 290px); --step-y: -16px; --step-z: -88px; }
}

/* L'onglet reste visible quand la carte est enfouie : c'est lui qui
   donne l'image des couches empilees. */
.deck-card__tab {
  flex: none;
  display: flex; align-items: center; gap: 10px;
  height: 34px; padding: 0 14px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
.deck-card__n {
  font-size: 10px; font-weight: 700; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.deck-card__tag {
  font-size: 10.5px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--text-dim); white-space: nowrap;
}

/* --- Miniatures : chaque carte montre sa couche --- */
.mini {
  flex: 1; min-height: 0;
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 6px;
  position: relative;
}
.mini--center { justify-content: center; align-items: center; gap: 12px; }

.mini__bar { display: block; height: 5px; border-radius: 3px; background: var(--line); width: 100%; }
.mini__bar--xl { height: 9px; width: 72%; background: var(--line-3); }
.mini__bar--l  { width: 82%; }
.mini__bar--m  { width: 56%; }
.mini__bar--s  { width: 38%; }
.mini__bar--hi { height: 7px; background: var(--line-3); }

.mini__code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 8.5px; color: var(--text-faint); letter-spacing: .02em;
}
.mini__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 2px; }
.mini__grid i { height: 26px; border-radius: 5px; border: 1px solid var(--line); background: var(--bg-2); }

.mini__spec { display: flex; align-items: center; gap: 14px; }
.mini__aa {
  font-family: 'FrauncesLocal', Georgia, serif; font-style: italic;
  font-size: 34px; line-height: 1; color: var(--text);
}
.mini__specL { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.mini__ramp { display: flex; gap: 4px; margin-top: auto; }
.mini__ramp i { flex: 1; height: 22px; border-radius: 4px; border: 1px solid var(--line); }
.mini__ramp i:nth-child(1) { background: var(--text); }
.mini__ramp i:nth-child(2) { background: var(--text-dim); }
.mini__ramp i:nth-child(3) { background: var(--text-faint); }
.mini__ramp i:nth-child(4) { background: var(--line-3); }
.mini__ramp i:nth-child(5) { background: var(--bg-3); }
.mini__ramp i:nth-child(6) { background: var(--surface); }

.mini__curve { width: 78%; height: auto; color: var(--text); opacity: .75; }
.mini__dot { display: none; }
.mini__meta {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9px; color: var(--text-faint); letter-spacing: .01em;
}

.mini__rank {
  position: absolute; top: 12px; right: 14px;
  padding: 3px 8px; border-radius: 999px;
  font-size: 9px; font-weight: 700;
  background: var(--brand); color: var(--on-brand);
}
.mini__serp {
  display: flex; flex-direction: column; gap: 5px;
  padding: 8px 10px; border-radius: 7px;
  border: 1px solid var(--line); background: var(--bg-2);
}
.mini__serp--dim { opacity: .45; }
.mini__url { font-size: 8.5px; color: var(--text-faint); }

.mini__flow { display: flex; align-items: center; gap: 6px; }
.mini__node {
  font-style: normal; font-size: 9px; font-weight: 700;
  padding: 5px 9px; border-radius: 6px;
  border: 1px solid var(--line-2); background: var(--bg-2); color: var(--text-dim);
  white-space: nowrap;
}
.mini__link { width: 14px; height: 1px; background: var(--line-3); flex: none; }

/* --- La colonne de texte --- */
.deck-copy { list-style: none; margin: 0; padding: 0; display: grid; gap: 22px; }
.deck-copy__item { position: relative; padding-left: 46px; }
.deck-copy__n {
  position: absolute; left: 0; top: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--line-2);
  font-size: 12px; font-weight: 700; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.deck-copy__t { font-size: 19px; font-weight: 700; color: var(--text); padding-top: 5px; }
.deck-copy__d { font-size: 14.5px; line-height: 1.65; color: var(--text-dim); margin: 6px 0 0; }

/* --- Le rail de progression : masque tant qu'il n'y a rien a suivre --- */
.deck-rail { display: none; }

/* =========================================================
   SECTION "CHAQUE ECRAN" — trois appareils en perspective
   ========================================================= */
.screens3d {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: clamp(14px, 4vw, 46px);
  perspective: 1300px;
  padding: 10px 0 6px;
}
.dev { transform-style: preserve-3d; text-align: center; }
.dev__screen {
  position: relative;
  display: flex; flex-direction: column; gap: 7px;
  padding: 13px;
  border-radius: 12px;
  border: 1px solid var(--line-2);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.dev__bar { height: 7px; border-radius: 4px; background: var(--line-2); width: 82%; }
.dev__bar--w { width: 96%; }
.dev__bar--m { width: 58%; background: var(--line-3); }
.dev__block { margin-top: auto; height: 34%; min-height: 40px; border-radius: 8px; background: var(--brand-soft); border: 1px solid var(--line); }
.dev__label {
  display: block; margin-top: 12px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-faint);
}

.dev--desk  .dev__screen { width: min(46vw, 300px); height: 196px; }
.dev--tab   .dev__screen { width: min(26vw, 156px); height: 168px; }
.dev--phone .dev__screen { width: min(18vw, 92px);  height: 146px; border-radius: 16px; }

/* --ry / --tz sont partages par la pose de repos ET par l'animation de
   scroll plus bas, pour qu'il n'y ait qu'une seule source de verite. */
.dev--desk  { --ry:  19deg; --tz: -30px; }
.dev--tab   { --ry:   0deg; --tz:  10px; }
.dev--phone { --ry: -19deg; --tz: -30px; }
.dev { transform: rotateY(var(--ry)) translateZ(var(--tz)); }

/* ---------------------------------------------------------
   Maquette navigateur (section Apercu)
   --------------------------------------------------------- */
.demo-frame {
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface-2);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transform-style: preserve-3d;
  transition: transform .6s var(--ease), box-shadow .6s var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  /* `animation: none` pour la meme raison que .card-lift.is-tilting :
     sans cela, frameStand (fill: both) ecraserait ce transform. */
  .demo-frame:hover { animation: none !important; transform: translate3d(0,-6px,30px) rotateX(2deg); box-shadow: var(--shadow-3d); }
}
.demo-frame__bar, .mock-chrome {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  background: var(--bg-3);
  border-bottom: 1px solid var(--line);
}
.mock-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line-3); }
.demo-frame__url, .mock-url {
  font-size: 11px; color: var(--text-faint);
  padding: 3px 10px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
}

.domain-dropdown-panel {
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

/* ---------------------------------------------------------
   Methode (etapes)
   --------------------------------------------------------- */
.steps { display: grid; gap: 18px; }
@media (min-width: 768px)  { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1200px) { .steps { grid-template-columns: repeat(4, 1fr); } }

.step {
  position: relative;
  padding: 26px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.step__n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand);
  font-weight: 700; font-size: 14px;
}
.step__t { font-size: 17px; font-weight: 700; margin-top: 16px; color: var(--text); }
.step__d { font-size: 14.5px; line-height: 1.6; color: var(--text-dim); margin-top: 8px; }

/* ---------------------------------------------------------
   Tarifs
   --------------------------------------------------------- */
.price-table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
.price-table th, .price-table td { padding: 14px 16px; text-align: left; border-bottom: 1px solid var(--line); }
.price-table thead th {
  font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 700;
}
.price-table td { color: var(--text-dim); }
.price-table tbody tr:hover { background: var(--brand-soft); }

.pricing-card-disabled { opacity: .62; }
.pricing-card-disabled .btn { pointer-events: none; }

/* ---------------------------------------------------------
   FAQ
   --------------------------------------------------------- */
details.fld, .fld {
  border-bottom: 1px solid var(--line);
  padding: 4px 0;
}
.fld summary {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 18px 2px; cursor: pointer; list-style: none;
  font-size: 16px; font-weight: 700; color: var(--text);
  transition: color .2s;
}
.fld summary::-webkit-details-marker { display: none; }
.fld summary:hover { color: var(--text-dim); }
.fld[open] summary { color: var(--text); }
.fld p { padding: 0 2px 20px; margin: 0; color: var(--text-dim); font-size: 15px; line-height: 1.7; }

/* Corps de reponse de la FAQ (class="a" dans le HTML) */
#faq-list .a, .fld .a {
  color: var(--text-dim);
  font-size: 15px;
  line-height: 1.7;
  padding: 0 4px 22px;
  max-width: 760px;
}

/* ---------------------------------------------------------
   Formulaire
   --------------------------------------------------------- */
input, textarea, select {
  width: 100%;
  font: inherit; font-size: 15px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 12px;
  padding: 13px 15px;
  transition: border-color .2s, box-shadow .2s, background .2s;
}
input::placeholder, textarea::placeholder { color: var(--text-faint); }
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--text);
  box-shadow: 0 0 0 3px var(--brand-soft);
}
.placeholder-required::placeholder { color: var(--err); }

/* Etats de validation poses par app.js */
.text-accent   { color: var(--text) !important; }
.bg-accent-light { background: var(--brand-soft) !important; }
.border-accent-border { border-color: var(--brand-line) !important; }
.border-canvas-line   { border-color: var(--line) !important; }
.text-ink-500  { color: var(--text-faint) !important; }
.bg-ink-400    { background: var(--text-faint) !important; }

/* ---------------------------------------------------------
   Menu mobile
   --------------------------------------------------------- */
.m-nav { display: flex; flex-direction: column; }
.m-menu-label {
  font-size: 11px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
  color: var(--text-faint); padding: 2px 12px 8px;
}
.m-link {
  display: flex; align-items: center; gap: 14px;
  min-height: 56px; padding: 10px 12px; border-radius: 14px;
  color: var(--text);
  transition: background .2s, transform .2s var(--ease);
}
.m-link:hover, .m-link:focus-visible { background: var(--brand-soft); transform: translateX(4px); }
.m-link__ico { display: inline-flex; width: 24px; justify-content: center; color: var(--text-faint); }
.m-link__label { flex: 1; font-size: 16.5px; font-weight: 700; }
.m-link__chev { color: var(--text-faint); }

/* Le panneau est un simple <div> sans classe de positionnement dans le HTML :
   il DOIT etre sorti du flux ici, sinon il pousse tout le contenu vers le bas. */
#mobile-menu {
  position: fixed;
  top: 84px; left: 12px; right: 12px;
  z-index: 39;
  max-height: calc(100dvh - 104px);
  overflow-y: auto;
  padding: 8px 4px 12px;
  background: var(--glass-solid);
  backdrop-filter: blur(22px) saturate(150%);
  -webkit-backdrop-filter: blur(22px) saturate(150%);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  opacity: 0; transform: translate3d(0, -10px, 0); pointer-events: none;
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
@media (min-width: 1024px) { #mobile-menu { display: none; } }
#mobile-menu[data-open="true"] { opacity: 1; transform: none; pointer-events: auto; }
body.menu-open { overflow: hidden; }
#burger .burger-close, #burger[aria-expanded="true"] .burger-open { display: none; }
#burger[aria-expanded="true"] .burger-close { display: block; }

/* ---------------------------------------------------------
   Modales
   --------------------------------------------------------- */
.modal-panel {
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  animation: modalIn .3s var(--ease) both;
}
@keyframes modalIn { from { opacity: 0; transform: translate3d(0,16px,0) scale(.985); } to { opacity: 1; transform: none; } }
body.modal-open { overflow: hidden; }
#calendly-iframe.is-loaded { opacity: 1 !important; }
@media (max-width: 1023.98px) {
  #booking-modal .modal-panel {
    border-radius: 0 !important; max-width: 100% !important;
    height: 100dvh !important; max-height: 100dvh !important;
  }
}
.is-closing { animation: modalOut .2s var(--ease-out) both; }
@keyframes modalOut { to { opacity: 0; transform: translate3d(0,10px,0) scale(.99); } }

/* ---------------------------------------------------------
   Barre de defilement
   --------------------------------------------------------- */
@media (min-width: 768px) {
  ::-webkit-scrollbar { width: 11px; height: 11px; }
  ::-webkit-scrollbar-track { background: var(--bg-2); }
  ::-webkit-scrollbar-thumb { background: var(--line-3); border-radius: 999px; border: 3px solid var(--bg-2); }
  ::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
}

/* =========================================================
   CHOREGRAPHIE DE SCROLL
   Moteur natif (animation-timeline) : aucune dependance ajoutee,
   les animations sont pilotees par le compositeur et non par un
   listener de scroll, donc pas de jank.
   Le socle .is-in-view (IntersectionObserver, app.js) reste la
   base : ce bloc ne fait que l'enrichir la ou le navigateur suit.
   ========================================================= */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* Titres de section : montee courte, scrubbee sur le defilement.
       C'est ce chemin-la que voient les navigateurs recents, pas la
       transition pilotee par l'observateur plus haut.

       Le reglage precedent etirait l'arrivee sur 4 % -> 62 % de la plage
       d'entree, avec 46 px de course et 7 px de flou : le bloc se
       montait sous les yeux, et on regardait l'animation au lieu de lire.
       Il se resout maintenant entre 6 % et 30 %, donc bien avant que le
       bloc atteigne le milieu de l'ecran — quand l'oeil y arrive, c'est
       deja pose. Course reduite a 20 px, flou a 3 px. */
    .reveal, .reveal-left, .reveal-right {
      opacity: 1;
      transform: none;
      transition: none;
      animation: sectionRise linear both;
      animation-timeline: view();
      animation-range: entry 6% entry 30%;
    }
    @keyframes sectionRise {
      from { opacity: 0; transform: translate3d(0, 20px, 0); filter: blur(3px); }
      to   { opacity: 1; transform: none; filter: blur(0); }
    }

    /* Les entrees laterales perdent leur rotation et leur recul en
       profondeur : a 16 degres et -120 px, elles signaient l'effet. */
    .reveal-left  { animation-name: sectionSlideL; }
    .reveal-right { animation-name: sectionSlideR; }
    @keyframes sectionSlideL {
      from { opacity: 0; transform: translate3d(-26px, 0, 0); filter: blur(3px); }
      to   { opacity: 1; transform: none; filter: blur(0); }
    }
    @keyframes sectionSlideR {
      from { opacity: 0; transform: translate3d(26px, 0, 0); filter: blur(3px); }
      to   { opacity: 1; transform: none; filter: blur(0); }
    }

    /* ---- Piece maitresse : les quatre metiers ----
       Les cartes arrivent comme un jeu de cartes qu'on abat : reculees
       dans la profondeur, pivotees, puis remises a plat. Le decalage
       se fait en deplacant la PLAGE de scroll de chaque carte plutot
       qu'avec un delay, pour que l'effet reste colle au scroll. */
    .cap-grid .cap {
      opacity: 1;
      transform: none;
      transition: none;
      animation: capDeck linear both;
      animation-timeline: view();
      animation-range: entry 6% entry 46%;
      transform-origin: 50% 100%;
    }
    .cap-grid .cap:nth-child(2) { animation-range: entry 12% entry 52%; }
    .cap-grid .cap:nth-child(3) { animation-range: entry 18% entry 58%; }
    .cap-grid .cap:nth-child(4) { animation-range: entry 24% entry 64%; }

    /* Reste la piece la plus animee de la page, mais divisee par deux :
       la pose partait de 110 px plus bas, 320 px en arriere, avec deux
       rotations et 8 px de flou, sur une plage qui courait jusqu'a 30 %
       de couverture. La carte finissait de se poser une fois deja lue. */
    @keyframes capDeck {
      from {
        opacity: 0;
        transform: perspective(var(--persp)) translate3d(0, 44px, -130px) rotateX(11deg) scale(.965);
        filter: blur(4px);
      }
      55% { opacity: 1; }
      to {
        opacity: 1;
        transform: perspective(var(--persp)) translate3d(0,0,0) rotateX(0) scale(1);
        filter: blur(0);
      }
    }

    /* Le numero et le titre remontent en profondeur, un cran apres */
    .cap__num, .cap__title {
      animation: capLift linear both;
      animation-timeline: view();
      animation-range: entry 16% entry 54%;
    }
    @keyframes capLift {
      from { opacity: 0; transform: translate3d(0, 12px, 0); }
      to   { opacity: 1; transform: none; }
    }

    /* Balayage lumineux qui traverse la carte quand elle se pose */
    .cap::after {
      content: "";
      position: absolute; inset: 0;
      pointer-events: none;
      background: linear-gradient(115deg, transparent 42%, var(--brand-soft) 50%, transparent 58%);
      opacity: 0;
      animation: capSheen linear both;
      animation-timeline: view();
      animation-range: entry 22% entry 62%;
    }
    @keyframes capSheen {
      from { opacity: 0; transform: translate3d(-130%, 0, 0); }
      45%  { opacity: 1; }
      to   { opacity: 0; transform: translate3d(130%, 0, 0); }
    }

    /* Parallaxe de profondeur sur les couches de fond */
    .aurora--1 {
      animation: parallaxSlow linear both;
      animation-timeline: scroll(root);
    }
    .aurora--2 {
      animation: parallaxFast linear both;
      animation-timeline: scroll(root);
    }
    @keyframes parallaxSlow { to { transform: translate3d(40px, -140px, 0) scale(1.18); } }
    @keyframes parallaxFast { to { transform: translate3d(-60px, 180px, 0) scale(1.12); } }

    /* Les etapes de la methode glissent en alternance */
    .steps .step {
      animation: stepIn linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 48%;
    }
    .steps .step:nth-child(even) { animation-name: stepInAlt; }
    @keyframes stepIn {
      from { opacity: 0; transform: perspective(var(--persp)) translate3d(-18px, 22px, -60px); }
      to   { opacity: 1; transform: none; }
    }
    @keyframes stepInAlt {
      from { opacity: 0; transform: perspective(var(--persp)) translate3d(18px, 22px, -60px); }
      to   { opacity: 1; transform: none; }
    }

    /* =====================================================
       "SOUS LE CAPOT" — la section s'epingle, les cartes s'enfilent

       La section fait plusieurs ecrans de haut et porte une
       view-timeline nommee. Sa plage `contain` couvre exactement la
       fenetre pendant laquelle le panneau colle : de l'instant ou le
       haut de la section touche le haut de l'ecran jusqu'a l'instant
       ou son bas touche le bas. Tout se cale sur ces 0 -> 100 %.

       Cadence : une carte tous les 18 %, atterrissage sur 14 % puis
       4 % de pause. Cinq cartes de 2 % a 92 %, le reste sert de
       respiration avant le desepinglage.
       ===================================================== */
    /* 440vh - 100vh d'ecran = 340vh d'epinglage, soit environ 68vh de
       defilement par carte. Plus court, les cartes se marchent dessus ;
       plus long, on a l'impression d'etre bloque dans la section. */
    .deck-section {
      min-height: 440vh;
      padding: 0;
      view-timeline-name: --deck;
      view-timeline-axis: block;
    }
    /* `height` et non `min-height` : un panneau plus haut que la fenetre
       ne serait jamais entierement visible, et son bas — la ou les cartes
       arrivent — resterait sous la ligne de flottaison. Tout le contenu
       doit donc tenir dans un ecran, d'ou les mesures relatives. */
    .deck-sticky {
      position: sticky;
      top: 0;
      height: 100svh;
      display: flex;
      flex-direction: column;
      justify-content: center;
      padding: 78px 0 26px;
      overflow: hidden;
    }
    .deck { margin-top: 48px; gap: 24px; }
    .deck-head .h-sec { font-size: clamp(26px, 4vw, 44px); }
    /* La scene doit loger la carte de devant PLUS la centaine de pixels
       que la pile gagne vers le haut, sinon le sommet vient mordre le
       rail place juste au-dessus. */
    .deck-stage { height: clamp(280px, 42vh, 380px); }
    @media (max-width: 1023px) {
      /* Ecran etroit : la pile et le texte se superposent en colonne, il
         faut rendre de la place. Le rail dit deja ou l'on en est. */
      .deck-lead { display: none; }
      .deck-sticky { padding: 64px 0 18px; }
      .deck-stage { height: clamp(210px, 36vh, 290px); }
      .deck-rail { margin-top: 18px; }
      .deck { margin-top: 34px; gap: 16px; }
    }

    /* --- Les cartes ---
       Les poses sont declarees une fois ici et les images-cles ne font
       que les enchainer, pour que le reglage tienne en un seul endroit. */
    .deck-card {
      --p-in: translate3d(0, 100px, 170px) rotateX(22deg);
      --p-0:  translate3d(0, 0, 0) rotateX(6deg);
      --p-1:  translate3d(0, calc(var(--step-y) * 1), calc(var(--step-z) * 1)) rotateX(6deg);
      --p-2:  translate3d(0, calc(var(--step-y) * 2), calc(var(--step-z) * 2)) rotateX(6deg);
      --p-3:  translate3d(0, calc(var(--step-y) * 3), calc(var(--step-z) * 3)) rotateX(6deg);
      --p-4:  translate3d(0, calc(var(--step-y) * 4), calc(var(--step-z) * 4)) rotateX(6deg);
      /* Longhands uniquement : le raccourci `animation` remettrait
         animation-timeline et animation-range a zero depuis la regle
         :nth-child, qui est plus specifique. */
      animation-duration: auto;
      animation-fill-mode: both;
      /* Signature de la marque : arrivee franche, pose lente. */
      animation-timing-function: var(--ease);
      animation-timeline: --deck;
      animation-range: contain 0% contain 100%;
      will-change: transform, opacity;
    }
    .deck-card:nth-child(1) { animation-name: deckCard1; }
    .deck-card:nth-child(2) { animation-name: deckCard2; }
    .deck-card:nth-child(3) { animation-name: deckCard3; }
    .deck-card:nth-child(4) { animation-name: deckCard4; }
    .deck-card:nth-child(5) { animation-name: deckCard5; }

    @keyframes deckCard1 {
      0%,   2%   { transform: var(--p-in); opacity: 0; --sink: 0; }
      16%,  20%  { transform: var(--p-0);  opacity: 1; --sink: 0; }
      34%,  38%  { transform: var(--p-1);  opacity: 1; --sink: 1; }
      52%,  56%  { transform: var(--p-2);  opacity: 1; --sink: 2; }
      70%,  74%  { transform: var(--p-3);  opacity: 1; --sink: 3; }
      88%,  100% { transform: var(--p-4);  opacity: 1; --sink: 4; }
    }
    @keyframes deckCard2 {
      0%,   20%  { transform: var(--p-in); opacity: 0; --sink: 0; }
      34%,  38%  { transform: var(--p-0);  opacity: 1; --sink: 0; }
      52%,  56%  { transform: var(--p-1);  opacity: 1; --sink: 1; }
      70%,  74%  { transform: var(--p-2);  opacity: 1; --sink: 2; }
      88%,  100% { transform: var(--p-3);  opacity: 1; --sink: 3; }
    }
    @keyframes deckCard3 {
      0%,   38%  { transform: var(--p-in); opacity: 0; --sink: 0; }
      52%,  56%  { transform: var(--p-0);  opacity: 1; --sink: 0; }
      70%,  74%  { transform: var(--p-1);  opacity: 1; --sink: 1; }
      88%,  100% { transform: var(--p-2);  opacity: 1; --sink: 2; }
    }
    @keyframes deckCard4 {
      0%,   56%  { transform: var(--p-in); opacity: 0; --sink: 0; }
      70%,  74%  { transform: var(--p-0);  opacity: 1; --sink: 0; }
      88%,  100% { transform: var(--p-1);  opacity: 1; --sink: 1; }
    }
    @keyframes deckCard5 {
      0%,   74%  { transform: var(--p-in); opacity: 0; --sink: 0; }
      88%,  100% { transform: var(--p-0);  opacity: 1; --sink: 0; }
    }

    /* Halo qui respire sous la pile — la couche d'ambiance, celle qui
       empeche la scene de paraitre posee sur du vide. */
    .deck-stage::before {
      content: "";
      position: absolute;
      left: 50%; top: 54%;
      width: min(96vw, 460px); aspect-ratio: 1;
      transform: translate(-50%, -50%);
      border-radius: 50%;
      background: radial-gradient(circle, var(--brand-soft), transparent 68%);
      pointer-events: none;
      animation: deckHalo linear both;
      animation-timeline: --deck;
      animation-range: contain 0% contain 40%;
    }
    @keyframes deckHalo {
      from { opacity: 0; transform: translate(-50%, -50%) scale(.6); }
      to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    }

    /* --- Le texte : un bloc a la fois, cale sur l'atterrissage --- */
    .deck-copy { display: grid; }
    .deck-copy__item {
      grid-area: 1 / 1;
      animation: deckCopy linear both;
      animation-timeline: --deck;
      animation-timing-function: var(--ease-out);
    }
    @keyframes deckCopy {
      0%        { opacity: 0; transform: translate3d(0, 20px, 0); filter: blur(7px); }
      32%, 68%  { opacity: 1; transform: none;                    filter: blur(0); }
      100%      { opacity: 0; transform: translate3d(0, -16px, 0); filter: blur(7px); }
    }
    @keyframes deckCopyIn {
      from { opacity: 0; transform: translate3d(0, 20px, 0); filter: blur(7px); }
      to   { opacity: 1; transform: none;                    filter: blur(0); }
    }
    .deck-copy__item:nth-child(1) { animation-range: contain 4%  contain 32%; }
    .deck-copy__item:nth-child(2) { animation-range: contain 22% contain 50%; }
    .deck-copy__item:nth-child(3) { animation-range: contain 40% contain 68%; }
    .deck-copy__item:nth-child(4) { animation-range: contain 58% contain 86%; }
    /* La derniere ne repart pas : elle tient jusqu'au desepinglage. */
    .deck-copy__item:nth-child(5) {
      animation-name: deckCopyIn;
      animation-range: contain 76% contain 90%;
    }

    /* --- Rail de progression : cinq segments, un par couche --- */
    .deck-rail {
      display: flex;
      gap: 10px;
      list-style: none;
      margin: 28px auto 0;
      padding: 0;
      max-width: 460px;
    }
    .deck-rail li { flex: 1; display: flex; flex-direction: column; gap: 7px; }
    .deck-rail__n {
      font-size: 10px; font-weight: 700; letter-spacing: .12em;
      color: var(--text-faint);
      font-variant-numeric: tabular-nums;
      opacity: calc(.35 + .65 * var(--on, 0));
    }
    .deck-rail__t {
      display: block; height: 2px; border-radius: 2px;
      background: var(--line);
      position: relative; overflow: hidden;
    }
    .deck-rail__t::after {
      content: "";
      position: absolute; inset: 0;
      background: var(--text);
      transform: scaleX(var(--on, 0));
      transform-origin: left;
    }
    .deck-rail li {
      animation: deckRail linear both;
      animation-timeline: --deck;
      animation-timing-function: var(--ease-out);
    }
    @keyframes deckRail { from { --on: 0; } to { --on: 1; } }
    .deck-rail li:nth-child(1) { animation-range: contain 2%  contain 16%; }
    .deck-rail li:nth-child(2) { animation-range: contain 20% contain 34%; }
    .deck-rail li:nth-child(3) { animation-range: contain 38% contain 52%; }
    .deck-rail li:nth-child(4) { animation-range: contain 56% contain 70%; }
    .deck-rail li:nth-child(5) { animation-range: contain 74% contain 88%; }

    /* Le point qui parcourt la courbe d'acceleration : la carte
       "Mouvement" demontre ce qu'elle raconte. Il vit DANS le <svg>,
       donc son chemin est exprime dans les unites du viewBox et suit
       la courbe quelle que soit la taille de rendu. */
    .mini__dot {
      display: block;
      offset-path: path("M5 46 C 34 46, 28 6, 135 6");
      offset-rotate: 0deg;
      animation: deckDot 2.6s var(--ease) infinite;
    }
    @keyframes deckDot {
      0%,  8%   { offset-distance: 0%;   opacity: 0; }
      14%       { opacity: 1; }
      70%, 100% { offset-distance: 100%; opacity: 0; }
    }

    /* Les appareils pivotent depuis un angle ferme vers leur pose finale */
    .screens3d .dev {
      animation: devTurn linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 52%;
    }
    @keyframes devTurn {
      from {
        opacity: 0;
        transform: rotateY(calc(var(--ry) * 1.6)) translateZ(-80px) translateY(22px);
      }
      to {
        opacity: 1;
        transform: rotateY(var(--ry)) translateZ(var(--tz));
      }
    }

    /* La maquette navigateur se redresse au scroll */
    .demo-frame {
      animation: frameStand linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 50%;
    }
    @keyframes frameStand {
      from { transform: perspective(var(--persp)) translate3d(0, 26px, -90px) rotateX(8deg) scale(.975); }
      to   { transform: perspective(var(--persp)) translate3d(0,0,0) rotateX(0) scale(1); }
    }
  }
}

/* ---------------------------------------------------------
   Inclinaison 3D suivant le pointeur
   Les variables --rx / --ry / --gx / --gy sont ecrites par app.js.
   Sans JS, on retombe sur l'inclinaison fixe definie plus haut.
   --------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  /* Une animation CSS l'emporte sur une declaration ordinaire : tant que
     `capDeck` (fill: both) reste attachee, elle ecraserait le transform de
     survol. On la coupe pendant l'inclinaison — la carte est de toute facon
     deja posee quand le curseur l'atteint, donc rien ne saute a l'ecran. */
  .card-lift.is-tilting { animation: none !important; }
  .card-lift.is-tilting::after { animation: none !important; opacity: 0 !important; }

  .card-lift.is-tilting {
    transform: perspective(var(--persp))
               translate3d(0, -8px, 30px)
               rotateX(var(--rx, 0deg))
               rotateY(var(--ry, 0deg));
    box-shadow: var(--shadow-3d);
    border-color: var(--line-2);
    transition: transform .12s linear, box-shadow .4s var(--ease);
  }
  /* Reflet qui suit le curseur */
  .card-lift.is-tilting::before {
    content: "";
    position: absolute; inset: 0;
    pointer-events: none;
    background: radial-gradient(340px circle at var(--gx, 50%) var(--gy, 50%), var(--brand-soft), transparent 65%);
    opacity: 1;
  }
  .card-lift::before { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity .3s; }
}

/* ---------------------------------------------------------
   Accessibilite du mouvement
   --------------------------------------------------------- */
@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;
  }
  .freezon-js .hero-anim { opacity: 1 !important; transform: none !important; filter: none !important; }
  .reveal, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; }
  .reveal-chars .ch { opacity: 1 !important; transform: none !important; }
  .card-lift:hover, .demo-frame:hover { transform: none !important; }
  .marquee { animation: none !important; }

  /* Neutralise entierement la choregraphie de scroll : chaque element
     est rendu directement dans son etat final lisible. */
  /* Les cartes et les appareils gardent leur pose 3D statique : ce n'est
     pas du mouvement, et l'aplatir empilerait les cinq cartes au meme
     endroit. On ne coupe que l'animation. */
  .screens3d .dev { animation: none !important; opacity: 1 !important; }
  /* La section "Sous le capot" n'est jamais epinglee ici : le bloc
     @supports qui l'epingle est deja sous `prefers-reduced-motion:
     no-preference`, donc l'etat de base — statique et complet — sert
     seul. Le point qui parcourt la courbe, lui, boucle : on le coupe. */
  .mini__dot { animation: none !important; display: none !important; }

  .cap-grid .cap, .cap__num, .cap__title, .steps .step, .demo-frame,
  .aurora--1, .aurora--2 {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  .cap::after { animation: none !important; opacity: 0 !important; }
  .card-lift.is-tilting { transform: none !important; }
  .card-lift.is-tilting::before { opacity: 0 !important; }
}

/* ---------------------------------------------------------
   Impression
   --------------------------------------------------------- */
@media print {
  #site-header, #booking-modal, #invoice-check-modal, .field, .aurora, #hero-canvas, .scroll-progress { display: none !important; }
  body { background: #fff; color: #000; }
}

/* ---------------------------------------------------------
   Fenetre video "Qui sommes-nous ?"
   --------------------------------------------------------- */
.video-panel { background: #000; border-color: var(--line-2); padding: 0; }
.video-el { display: block; width: 100%; height: auto; max-height: 82vh; background: #000; }

.video-close {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff; cursor: pointer;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  transition: background .2s, transform .2s var(--ease);
}
.video-close:hover { background: rgba(0, 0, 0, 0.8); transform: scale(1.06); }

/* Le navigateur interdit l'autoplay avec son : la lecture demarre en muet
   et ce bouton rend la main a l'utilisateur. Il disparait des qu'il sert. */
.video-unmute {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 2;
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 20px; border-radius: 999px;
  font-size: 14px; font-weight: 700;
  background: rgba(255, 255, 255, 0.94); color: #0B0B0D;
  border: 0; cursor: pointer;
  box-shadow: 0 10px 30px -8px rgba(0, 0, 0, 0.7);
  transition: transform .2s var(--ease), background .2s;
}
.video-unmute:hover { transform: translateX(-50%) translateY(-2px); background: #fff; }
.video-unmute[hidden] { display: none; }

@media (max-width: 640px) {
  .video-panel { border-radius: 16px; }
  .video-unmute { bottom: 14px; font-size: 13px; padding: 0 16px; }
}

/* Badge du hero reduit au seul mot "AGENCE" : padding symetrique (l'ancien
   etait asymetrique pour loger la pastille interne) et traitement typographique
   de l'ancienne pastille, repris ici puisqu'elle a disparu. */
.hero-badge--solo {
  padding: 9px 20px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text);
}

/* Croix de fermeture du deroulant "Choisir mon domaine" */
.domain-close {
  position: absolute; top: 10px; right: 10px; z-index: 3;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--brand-soft); border: 1px solid var(--line);
  color: var(--text-dim); cursor: pointer;
  transition: background .2s, color .2s, transform .2s var(--ease);
}
.domain-close:hover { background: var(--bg-3); color: var(--text); transform: scale(1.06); }
.domain-close[hidden] { display: none; }

/* En-tete du menu mobile : le libelle et sa croix de fermeture.
   Le burger se transforme deja en X dans le header, mais il est hors du
   panneau : une croix a l'interieur est l'affordance attendue. */
.m-menu-head { display: flex; align-items: center; justify-content: space-between; padding: 2px 12px 8px; }
.m-menu-head .m-menu-label { padding: 0; }
.m-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--brand-soft); border: 1px solid var(--line);
  color: var(--text-dim); cursor: pointer;
  transition: background .2s, color .2s, transform .2s var(--ease);
}
.m-close:hover { background: var(--bg-3); color: var(--text); transform: scale(1.06); }

/* Variante compacte du bouton, pour le header sur grand ecran */
.btn--sm {
  min-height: 34px;
  padding: 0 14px;
  font-size: 13px;
  gap: 6px;
}
.btn--sm svg { width: 13px; height: 13px; }

/* ---------------------------------------------------------
   Interrupteur de theme (glissant)
   --------------------------------------------------------- */
.theme-switch {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;               /* cible tactile, le visuel est plus petit */
  padding: 0; border: 0; background: none; cursor: pointer;
}
.theme-switch__track {
  position: relative; display: block;
  width: 42px; height: 24px; border-radius: 999px;
  background: var(--brand-soft);
  border: 1px solid var(--line-2);
  transition: background .3s var(--ease), border-color .3s var(--ease);
}
.theme-switch:hover .theme-switch__track { border-color: var(--text-faint); }
.theme-switch__thumb {
  position: absolute; top: 2px; left: 2px;
  display: flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--text); color: var(--bg);
  transition: transform .32s var(--ease), background .3s var(--ease);
}
/* En sombre, le curseur glisse a droite */
:root[data-theme="dark"] .theme-switch__thumb { transform: translateX(18px); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-switch__thumb { transform: translateX(18px); }
}

/* Une seule icone a la fois : soleil en clair, lune en sombre */
.theme-switch__moon { display: none; }
:root[data-theme="dark"] .theme-switch__sun  { display: none; }
:root[data-theme="dark"] .theme-switch__moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-switch__sun  { display: none; }
  :root:not([data-theme="light"]) .theme-switch__moon { display: block; }
}

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

/* =========================================================
   Eventail de maquettes (section "Une seule page")
   Portage vanilla du carrousel en eventail : le composant d'origine
   etait en React + GSAP, incompatible avec ce site sans build.
   Les positions sont posees en variables par js/app.js, la transition
   est faite en CSS — pas de dependance ajoutee.
   ========================================================= */
.fan { position: relative; }

.fan__stage {
  position: relative;
  display: grid;
  place-items: center;
  height: 26rem;
  perspective: 1400px;
}
@media (min-width: 640px)  { .fan__stage { height: 30rem; } }
@media (min-width: 1024px) { .fan__stage { height: 36rem; } }

.fan-card {
  position: absolute;
  width: clamp(9rem, 22vw, 15rem);
  aspect-ratio: 793 / 1400;
  padding: 0;
  border: 1px solid var(--line-2);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  cursor: pointer;
  transform-origin: 50% 100%;
  /* pose par le JS */
  transform: translate3d(var(--fx, 0), var(--fy, 0), 0) rotate(var(--fr, 0deg)) scale(var(--fs, 1));
  opacity: var(--fo, 1);
  z-index: var(--fz, 1);
  transition: transform .55s cubic-bezier(.22, 1.2, .36, 1), opacity .4s ease, box-shadow .4s var(--ease);
}
.fan-card img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.fan-card:focus-visible { outline: 2px solid var(--text); outline-offset: 4px; }

@media (hover: hover) and (pointer: fine) {
  .fan-card:hover { box-shadow: var(--shadow-3d); }
}

.fan__nav { display: flex; align-items: center; justify-content: center; gap: 16px; margin-top: 28px; }
.fan__arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--brand-soft); border: 1px solid var(--line-2);
  color: var(--text-dim); cursor: pointer;
  transition: background .2s, color .2s, border-color .2s, transform .2s var(--ease);
}
.fan__arrow:hover { background: var(--bg-3); color: var(--text); border-color: var(--text-faint); transform: scale(1.06); }
.fan__arrow:active { transform: scale(.96); }

.fan__dots { display: flex; align-items: center; gap: 8px; }
.fan__dot {
  width: 8px; height: 8px; padding: 0; border: 0; border-radius: 50%;
  background: var(--line-3); cursor: pointer;
  transition: background .3s, transform .3s var(--ease);
}
.fan__dot[aria-selected="true"] { background: var(--text); transform: scale(1.35); }

/* Avertissement : lisible mais volontairement en retrait */
.fan__note {
  max-width: 46rem;
  margin: 22px auto 0;
  text-align: center;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text-faint);
  opacity: 0.75;
}

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

/* =========================================================
   Cartes de tarifs — deux paliers contrastes
   La carte haute est en inverse du theme courant : c'est le contraste
   qui hierarchise, pas une couleur d'accent.
   ========================================================= */
.tiers { display: grid; gap: 20px; align-items: start; }
@media (min-width: 900px) { .tiers { grid-template-columns: 1fr 1fr; gap: 24px; } }

.tier {
  position: relative;
  display: flex; flex-direction: column;
  padding: 32px 28px 28px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}
@media (min-width: 640px) { .tier { padding: 40px 36px 32px; } }

.tier--light { background: var(--surface); color: var(--text); }
/* Inverse du theme : sombre sur clair, clair sur sombre */
.tier--dark  { background: var(--brand); color: var(--on-brand); border-color: transparent; box-shadow: var(--shadow-lg); }

.tier__name {
  font-size: 20px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: currentColor;
  display: flex; align-items: center; gap: 10px;
}
.tier__dot { width: 9px; height: 9px; border-radius: 50%; background: #34D399; flex: none; }

.tier__pitch { margin-top: 12px; font-size: 14.5px; line-height: 1.6; opacity: .72; }

.tier__price { margin-top: 26px; display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; }
.tier__from { font-size: 15px; opacity: .6; }
.tier__amount { font-size: clamp(30px, 5vw, 42px); font-weight: 700; letter-spacing: -0.03em; }

.tier__list {
  list-style: none; margin: 26px 0 0; padding: 26px 0 0;
  border-top: 1px solid var(--line);
  display: grid; gap: 13px;
}
.tier--dark .tier__list { border-top-color: rgba(127,127,127,0.25); }

.tier__feat { display: flex; align-items: flex-start; gap: 11px; font-size: 14.5px; font-weight: 500; line-height: 1.45; }
.tier__check {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 19px; height: 19px; margin-top: 1px; border-radius: 6px;
  background: var(--brand-soft); border: 1px solid var(--line); color: currentColor;
}
.tier--dark .tier__check { background: rgba(127,127,127,0.2); border-color: rgba(127,127,127,0.3); }

/* Le bouton de la carte sombre doit s'inverser a son tour */
.tier--dark .btn--gold { background: var(--bg); color: var(--text); }

.tier__note { margin-top: 14px; text-align: center; font-size: 12px; line-height: 1.55; opacity: .55; }

.tiers__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 10px 22px; margin-top: 26px;
  font-size: 12.5px; color: var(--text-faint);
}
.tiers__pay { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; color: var(--text-dim); }
.tiers__invoice {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--text-dim); text-decoration: underline; text-underline-offset: 3px;
  font: inherit;
}
.tiers__invoice:hover { color: var(--text); }


/* Carte dominante du bento : plus d'air et une vignette plus grande */
@media (min-width: 1100px) {
  .cap--tall { padding: 36px; }
  .cap--tall .cap__title { font-size: 23px; }
  .cap--tall .cap__desc  { font-size: 15px; }
  .cap--tall .cap__stage { padding-top: 34px; }
  .cap--tall .demo-web   { height: 210px; }
  .cap--wide .cap__stage { padding-top: 26px; }
}

/* =========================================================
   FAQ — liste aeree, sans cadre
   Le cadre d'origine enfermait les questions ; des separateurs fins
   laissent respirer et rapprochent la lecture d'un sommaire.
   ========================================================= */
.faq-list > details {
  border-bottom: 1px solid var(--line);
}
.faq-list > details:first-of-type { border-top: 1px solid var(--line); }

.faq-list summary {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 26px 4px;
  cursor: pointer; list-style: none;
  transition: color .2s;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list .q { font-size: 17px; font-weight: 600; line-height: 1.35; color: var(--text); }
@media (min-width: 768px) { .faq-list .q { font-size: 18.5px; } }
.faq-list summary:hover .q { color: var(--text-dim); }

/* L'indicateur passe de + a - a l'ouverture : la barre verticale disparait */
.faq-list .ic {
  flex: none;
  width: 34px; height: 34px; border-radius: 50%;
  background: transparent; border: 1px solid var(--line-2);
  color: var(--text-dim);
  transition: transform .35s var(--ease), border-color .2s, color .2s;
}
.faq-list summary:hover .ic { border-color: var(--text-faint); color: var(--text); }
.faq-list details[open] .ic { transform: rotate(180deg); }
.faq-list details[open] .ic line:first-of-type { opacity: 0; }
.faq-list .ic line { transition: opacity .25s var(--ease); }

.faq-list .a { padding: 0 4px 26px; max-width: 62ch; }

/* Carte d'aide en bas de colonne gauche */
.faq-help {
  padding: 26px;
  border-radius: var(--radius);
  background: var(--brand-soft);
  border: 1px solid var(--line);
}
.faq-help__title { font-size: 16.5px; font-weight: 700; color: var(--text); line-height: 1.35; }
.faq-help__sub { margin-top: 8px; font-size: 13.5px; line-height: 1.6; color: var(--text-dim); }
.faq-help__actions { margin-top: 18px; display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }
.faq-help__tel { font-size: 14px; font-weight: 700; color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.faq-help__tel:hover { text-decoration: none; }

/* =========================================================
   Hero — surtitre et barre de disponibilite
   Remplace l'ancien badge "AGENCE WEB", qui n'apportait aucune
   information. Ici : ce que vous faites, votre disponibilite,
   et une action, sur une seule ligne.
   ========================================================= */
.hero-kicker {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  text-align: center;
}

.avail {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  justify-content: center;
  gap: 4px 10px;
  padding: 4px 5px 4px 5px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--line);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  box-shadow: var(--shadow-sm);
  font-size: 12px;
}

/* Seule tache de couleur du site. --ok est deja declare par theme
   (#15803D en clair, #4ADE80 en sombre) : un vert en dur passerait a
   1,9:1 sur fond clair, illisible. */
.avail__state {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px; border-radius: 999px;
  background: rgba(52, 211, 153, 0.12);
  color: var(--ok);
  font-weight: 700;
}
.avail__dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--ok); flex: none;
  box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55);
  animation: availPulse 2.4s var(--ease) infinite;
}
@keyframes availPulse {
  0%   { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55); }
  70%  { box-shadow: 0 0 0 7px rgba(52, 211, 153, 0); }
  100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
}

.avail__txt { color: var(--text-dim); }
.avail__sep { width: 1px; height: 13px; background: var(--line-2); }

.avail__cta {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 4px 4px 3px;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-weight: 700; color: var(--text);
}
.avail__arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--brand-soft); border: 1px solid var(--line-2);
  transition: background .2s, transform .25s var(--ease);
}
.avail__cta:hover .avail__arrow { background: var(--bg-3); transform: translate(2px, -2px); }

/* Sur mobile : la pastille passe AVANT le surtitre (ordre inverse du
   desktop), redevient un seul pill horizontal compact, et perd son
   action "Prendre rendez-vous" — deja presente juste en dessous via le
   bouton dore du hero, elle serait redondante ici. */
@media (max-width: 560px) {
  .hero-anim.d1 { flex-direction: column-reverse; gap: 10px; }
  .avail { padding: 4px 4px 4px 5px; gap: 0; font-size: 11px; }
  /* Le delai de reponse est un detail, pas le signal. On le passe sous
     la pastille verte pour que "3 places" reste ce qu'on lit en premier. */
  .avail__txt { padding-right: 10px; font-size: 10.5px; }
  .avail__state { padding: 4px 9px; }
  .avail__sep:last-of-type,
  .avail__cta { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .avail__dot { animation: none; }
}

/* Carte 01 WEB : detourage transparent du telephone.
   Le PNG fait 636x900 mais le sujet n'en occupe que 403x774 — plus d'un
   tiers de la largeur est du vide. Dimensionner l'image entiere revenait
   donc a payer ces marges : le telephone ne faisait que 143 px de large
   dans une scene de 370. On recadre au sujet (x 95->537, y 54->700, le
   poignet coupe) et on dimensionne CE cadre. A place egale le telephone
   gagne environ 70 %.

   Les bornes viennent d'un releve du canal alpha, pas d'une estimation.
   Les pourcentages rendent le recadrage independant de la taille finale. */
.cap__stage--photo {
  position: relative;
  /* `auto` et non une valeur fixe : la carte est une colonne flex, et
     c'est cette marge automatique qui plaque la scene au bas. Avec
     20 px, l'image flottait 93 px au-dessus du bord. */
  margin-top: auto;
  padding-top: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
  min-height: 0;
  /* Mord le rembourrage bas de la carte : la main entre par le bord du
     cadre au lieu de flotter au milieu. */
  margin-bottom: -36px;
}
.cap--tall .cap__stage--photo { padding-top: 0; }

/* Hauteur explicite, pas 100 % : la scene est dimensionnee PAR son
   contenu (margin-top: auto dans une colonne flex), donc un enfant en
   pourcentage de hauteur les fait s'effondrer tous les deux a zero. */
.cap__photo-crop {
  position: relative;
  height: clamp(220px, 27vw, 360px);
  aspect-ratio: 442 / 646;
  overflow: hidden;
  flex: none;
}
.cap__photo {
  position: absolute;
  width: calc(636 / 442 * 100%);
  height: auto;
  max-width: none;
  left: calc(-95 / 442 * 100%);
  top: calc(-54 / 646 * 100%);
  display: block;
}

/* Pastilles "plateformes" : posees SUR un grand panneau liquid glass,
   pas directement sur le fond de la carte. Le panneau est le "gros"
   verre transparent, les pastilles flottent dessus. */
.cap__platforms { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.cap__platforms .tag { font-size: 12px; padding: 5px 12px; }
.cap__platform-icon { width: 13px; height: 13px; object-fit: contain; flex: none; }

/* Plateforme sous la grille bento : les cartes ne flottent plus sur le fond
   de page, elles reposent sur un socle legerement contraste. C'est ce qui
   donne l'effet "cartes posees" plutot que "cartes eparpillees". */
.cap-stage-wrap {
  padding: 14px;
  border-radius: calc(var(--radius-lg) + 8px);
  background: var(--bg-2);
  border: 1px solid var(--line);
}
@media (min-width: 768px) { .cap-stage-wrap { padding: 20px; } }
/* Sur telephone, le socle + le panneau + le padding interne cumulaient
   68 px de marge a gauche : la colonne de texte tombait a 239 px. */
@media (max-width: 520px) { .cap-stage-wrap { padding: 8px; } }
