/* ═══════════════════════════════════════════════════════════════════════
   THE PRIVATE FINDER — refonte
   Mobile first : 80 % du trafic. Le desktop est la montée en charge.
   Zéro dépendance, zéro requête externe.
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── Polices, servies en local (latin uniquement) ─────────────────────── */
@font-face {
  font-family: 'Barlow Condensed'; font-style: normal; font-weight: 600;
  font-display: swap; src: url('../assets/fonts/barlow-condensed-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Barlow Condensed'; font-style: normal; font-weight: 700;
  font-display: swap; src: url('../assets/fonts/barlow-condensed-700.woff2') format('woff2');
}
@font-face {
  font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 300;
  font-display: swap; src: url('../assets/fonts/cormorant-garamond-300.woff2') format('woff2');
}
@font-face {
  font-family: 'Cormorant Garamond'; font-style: italic; font-weight: 300;
  font-display: swap; src: url('../assets/fonts/cormorant-garamond-300-italic.woff2') format('woff2');
}

/* ─── Tokens ───────────────────────────────────────────────────────────
   L'or est le trio tranché au brand book, pas le #c4a96a du site actuel.
   B8975A est la valeur de surface : c'est celle qui remplace l'ancienne.
   ─────────────────────────────────────────────────────────────────────── */
:root {
  --black:      #080706;
  --near:       #0a0908;
  --charcoal:   #141210;
  --grey-dark:  #2e2b27;
  --grey-mid:   #6a6762;
  --grey-light: #9a9690;
  --off-white:  #f2efe9;
  --warm-white: #faf8f4;

  --gold-deep:  #9a7a2e;
  --gold:       #b8975a;
  --gold-light: #cdaf78;
  --gold-rgb:   184, 151, 90;
  --gold-dim:   rgba(184,151,90,0.5);

  --rule:       rgba(242,239,233,0.10);
  --rule-med:   rgba(242,239,233,0.20);
  --rule-dark:  rgba(8,7,6,0.08);

  --px: clamp(22px, 6vw, 96px);
  --py: clamp(64px, 8vh, 120px);

  --ease:  cubic-bezier(0.16, 1, 0.3, 1);   /* attaque franche, longue pose */
  --ease-cut: cubic-bezier(0.77, 0, 0.18, 1);

  --cond:  'Barlow Condensed', 'Arial Narrow', sans-serif;
  --serif: 'Cormorant Garamond', Georgia, serif;
  --sans:  'Helvetica Neue', Helvetica, Arial, sans-serif;

  /* Ident */
  --deep:     #040303;
  --gold-hot: #f7e0a9;
  --slam:     cubic-bezier(0.7, 0, 0.15, 1);   /* les ouvertures : aucun amorti */
  --k0:       clamp(58px, 9vmin, 96px);        /* largeur initiale du trou */

  /* Le pied que le CTA flottant réserve au bas de l'écran : sa hauteur,
     son décalage, et l'air entre les deux. */
  --cta-space: 84px;
}

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

/* `clip` et non `hidden` : `overflow-x: hidden` fait calculer `overflow-y:
   auto`, ce qui transforme le body en conteneur de défilement — un
   conteneur qui ne défile jamais, puisque c'est le document qui scrolle.
   Toute animation liée au scroll se résout alors contre ce conteneur mort
   et reste figée. `clip` coupe le débordement sans créer de conteneur. */
html {
  width: 100%; max-width: 100%;
  overflow-x: clip;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  width: 100%; max-width: 100%;
  background: var(--black);
  color: var(--off-white);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

img, picture, svg { display: block; max-width: 100%; }
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { font-weight: inherit; }

::selection { background: rgba(var(--gold-rgb), 0.28); color: var(--off-white); }

:focus-visible {
  outline: 1px solid var(--gold-light);
  outline-offset: 3px;
}

.cap {
  font-size: clamp(10px, 1vw, 12px);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--grey-mid);
}

/* ═══════════════════════ IDENT · LA SERRURE ═══════════════════════
   Un vrai trou de serrure percé dans le noir : le voile porte un masque en
   forme de serrure composé en `exclude`, la photo est intacte derrière. Une
   seconde de fixe, puis le trou s'ouvre d'un coup en 900 ms, sans amorti.

   Repris tel quel du banc d'essai (`prototypes/ident-lab.html`), avec les
   quatre corrections qui y ont été faites :
   · le voile se dissout pendant qu'on voit encore une serrure, la géométrie
     dégénérée n'est jamais à l'écran ;
   · masque et filet sont tous deux centrés à 50 %, seule position où les deux
     modèles de calcul coïncident à toutes les tailles ;
   · le filet est un SVG à trait non-scalé, il ne grossit pas avec le trou ;
   · la photo entre à `translateY(35%)` : un relevé de luminance montre que la
     seule zone claire est entre 2 % et 27 % de la hauteur. Trou centré sur la
     photo non décalée = trou sur du noir.

   Ne joue qu'une fois par session, jamais en `reduced-motion`. Sans JS, la
   classe `.ident-play` n'arrive pas et rien de tout ceci n'existe.
   ─────────────────────────────────────────────────────────────────────── */
.ident { display: none; }
.ident-play .ident { display: block; }

.ident__veil {
  position: fixed; inset: 0; z-index: 9990;
  background: var(--deep);
  pointer-events: none;
  --key: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 150'%3E%3Cpath fill='%23fff' d='M48 14C31 14 18 27 18 44c0 11 6 20 15 24l-7 64c-1 6 3 10 9 10h26c6 0 10-4 9-10l-7-64c9-4 15-13 15-24 0-17-13-30-30-30z'/%3E%3C/svg%3E");
  -webkit-mask-image: var(--key), linear-gradient(#fff, #fff);
          mask-image: var(--key), linear-gradient(#fff, #fff);
  -webkit-mask-position: center, center;  mask-position: center, center;
  -webkit-mask-repeat: no-repeat;         mask-repeat: no-repeat;
  -webkit-mask-size: var(--k0) auto, cover;  mask-size: var(--k0) auto, cover;
  -webkit-mask-composite: xor;            mask-composite: exclude;
  animation: keyOpen 900ms var(--slam) 1000ms both;
}

.ident__rim {
  position: fixed; left: 50%; top: 50%; z-index: 9992;
  width: var(--k0);
  translate: -50% -50%;
  transform-origin: 50% 50%;
  opacity: 0; pointer-events: none;
  filter: drop-shadow(0 0 6px rgba(var(--gold-rgb), 0.85))
          drop-shadow(0 0 22px rgba(var(--gold-rgb), 0.45));
  animation: rimGlow  1000ms ease-out both,
             rimClick  260ms var(--slam)  740ms both,
             rimOpen   900ms var(--slam) 1000ms both;
}
.ident__rim svg { display: block; width: 100%; height: auto; overflow: visible; }
.ident__rim path {
  fill: none; stroke: var(--gold-hot); stroke-width: 1.1;
  vector-effect: non-scaling-stroke;
}

@keyframes keyOpen {
  0%   { -webkit-mask-size: var(--k0) auto, cover; mask-size: var(--k0) auto, cover; opacity: 1; }
  38%  { opacity: 1; }
  100% { -webkit-mask-size: 150vmin auto, cover;   mask-size: 150vmin auto, cover;   opacity: 0; }
}
@keyframes rimGlow  { 0% { opacity: 0; } 30% { opacity: 0.95; } 100% { opacity: 0.95; } }
@keyframes rimClick { 0% { scale: 1; } 42% { scale: 1.13; } 100% { scale: 1; } }
@keyframes rimOpen  { 0% { width: var(--k0); opacity: 0.95; } 38% { opacity: 0.8; } 100% { width: 150vmin; opacity: 0; } }

/* La photo est déjà là, déjà en mouvement : on n'était pas invité. */
@keyframes filmPeek {
  0%   { filter: brightness(0.98) contrast(1.9) saturate(0.4); transform: scale(1.45) translateY(35%); }
  46%  { filter: brightness(1.02) contrast(1.4) saturate(0.66); }
  100% { filter: brightness(1.06) contrast(1)   saturate(0.92); transform: scale(1) translateY(0); }
}

/* Le hero attend le trou : chaque élément reprend sa place dans la partition
   du banc d'essai. Sans ident, les délais d'origine s'appliquent. */
.ident-play .hero__bg {
  animation: filmPeek 2600ms var(--ease) 120ms both,
             kenBurns 22s 2720ms ease-in-out infinite alternate;
}
.ident-play .hero__title .line:nth-child(1) .line__inner { animation-delay: 1420ms; }
.ident-play .hero__title .line:nth-child(2) .line__inner { animation-delay: 1620ms; }
.ident-play .hero__signal { animation-delay: 2280ms; }
.ident-play .hero__bottom { animation-delay: 2700ms; }
/* La nav n'est pas animée : sur le hero elle est masquée (le titre porte
   déjà le nom), elle n'entre qu'une fois le premier écran passé via
   `is-shown`. Rien à jouer pendant l'ident. */

/* Un scroll, un doigt, un clic : on n'attend pas. Le voile part en 200 ms,
   le hero finit sa course. */
.ident-skip .ident__veil,
.ident-skip .ident__rim {
  animation: none;
  opacity: 0;
  transition: opacity 200ms linear;
}

/* ═══════════════════════ B00 · NAV ═══════════════════════
   Au repos : le nom seul, centré. Rien d'autre. On arrive sur une maison,
   pas sur un menu.
   Une fois le hero passé : le voile tombe et le CTA se pose à droite. Il
   n'existe qu'à partir du moment où il sert.
   ─────────────────────────────────────────────────────────────────────── */
#main-nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 900;
  display: flex; align-items: center; justify-content: center;
  min-height: 56px;
  padding: 14px var(--px);
  padding-top: max(14px, env(safe-area-inset-top));
  pointer-events: none;
  /* Aucun fond, aucun voile : le nom s'encre à même la page. Il se lit en
     clair sur les sections sombres, en foncé sur les claires — c'est le JS
     qui pose `nav--light` selon la section qui croise la barre. Le toggle de
     langue est monté dès le départ (filet pour la mauvaise langue) ; le NOM,
     lui, n'entre qu'une fois le hero passé (le titre géant le porte déjà,
     deux « The Private Finder » feraient doublon). */
}

.nav__logo {
  pointer-events: none;
  font-family: var(--cond);
  font-size: clamp(10px, 2.6vw, 14px);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  color: var(--off-white);
  /* Le nom seul entre après le hero ; le toggle de langue, lui, reste là. */
  opacity: 0;
  transform: translateY(-8px);
  transition: color 0.4s ease, letter-spacing 0.6s var(--ease),
              opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
#main-nav.is-shown .nav__logo {
  pointer-events: auto;
  opacity: 1;
  transform: translateY(0);
}
/* Sur une section claire, le nom passe à l'encre foncée. */
#main-nav.nav--light .nav__logo { color: var(--black); }

/* ═══════════════════════ TOGGLE DE LANGUE ═══════════════════════
   Celui de la nav est joignable dès le hero, avant tout scroll : c'est un
   filet de secours pour un visiteur tombé sur la mauvaise langue. Il ne suit
   PAS le sort du nom (qui, lui, n'entre qu'après le hero) — il reste posé en
   haut à droite en permanence.
   Celui du pied double la mise, joignable en fin de page.
   ─────────────────────────────────────────────────────────────────────── */
.lang {
  display: flex; align-items: center; gap: 7px;
  font-family: var(--cond);
  font-size: 10px; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase;
  line-height: 1;
}
.lang__link {
  pointer-events: auto;
  color: rgba(242,239,233,0.42);
  transition: color 0.35s ease;
}
.lang__link:hover { color: rgba(242,239,233,0.78); }
.lang__link[aria-current] { color: var(--gold); cursor: default; }
.lang__sep { color: rgba(242,239,233,0.18); }

/* Sur une section claire, le toggle passe lui aussi à l'encre foncée. */
#main-nav.nav--light .lang__link { color: rgba(8,7,6,0.5); }
#main-nav.nav--light .lang__link:hover { color: rgba(8,7,6,0.82); }
#main-nav.nav--light .lang__link[aria-current] { color: var(--gold-deep); }
#main-nav.nav--light .lang__sep { color: rgba(8,7,6,0.22); }

/* Hors du flux : le nom doit rester exactement centré dans la nav, le
   toggle ne doit pas le pousser. */
.lang--nav {
  position: absolute;
  right: var(--px);
  top: 50%; transform: translateY(-50%);
}
/* Une lueur dorée aide la lecture sur la photo du hero ; sur une section
   claire elle n'a pas lieu d'être. */
.lang--nav .lang__link { text-shadow: 0 0 10px rgba(var(--gold-rgb), 0.26); }
#main-nav.nav--light .lang--nav .lang__link { text-shadow: none; }

/* ═══════════════════════ CTA FLOTTANT ═══════════════════════
   Sorti de la nav. Centré en bas, à portée de pouce sur les deux mains.
   Absent tant qu'on est sur le hero, et absent à nouveau quand la carte
   Private Invitation entre à l'écran : jamais deux CTA en même temps.
   ─────────────────────────────────────────────────────────────────────── */
.cta-float {
  position: fixed; z-index: 880;
  left: 50%; bottom: max(20px, calc(env(safe-area-inset-bottom) + 14px));

  display: inline-flex; align-items: center; justify-content: center;
  gap: 14px;
  min-height: 48px;
  padding: 12px clamp(20px, 5vw, 30px);
  border-radius: 999px;

  font-family: var(--sans);
  font-size: clamp(9px, 2.4vw, 11px);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;

  color: var(--black);
  background: linear-gradient(135deg, var(--gold-light), var(--gold));
  border: 1px solid rgba(205,175,120,0.42);
  /* Pas de halo doré : un halo fait lire un bouton web. La pastille est
     posée, pas allumée. */
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 6px 22px rgba(8,7,6,0.42);

  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translate(-50%, 18px) scale(0.94);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease),
              visibility 0s linear 0.55s, box-shadow 0.35s ease, background 0.35s ease;
}
.cta-float.is-shown {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translate(-50%, 0) scale(1);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease),
              visibility 0s linear 0s, box-shadow 0.35s ease, background 0.35s ease;
}
.cta-float:hover {
  background: linear-gradient(135deg, #dcc08d, var(--gold-light));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.26), 0 8px 28px rgba(8,7,6,0.46);
}
.cta-float__arrow {
  font-family: var(--serif); font-size: 15px; line-height: 1; letter-spacing: 0;
  transition: transform 0.45s var(--ease);
}
.cta-float:hover .cta-float__arrow { transform: translateX(5px); }

/* ═══════════════════════ B01 · HERO ═══════════════════════ */
#hero {
  position: relative;
  height: 92svh; min-height: min(560px, 92svh);
  background-color: var(--black);
  overflow: clip;
  display: flex; flex-direction: column;
}

.hero__bg {
  position: absolute; inset: -6%;
  width: 112%; height: 112%;
  max-width: none;              /* le reset global plafonne les img à 100 % */
  z-index: 0;
  object-fit: cover;
  object-position: 42% center;
  filter: brightness(0.05) saturate(0);
  transform: scale(1.16);
  animation: heroBgIn 2.6s var(--ease) forwards,
             kenBurns 22s 2.6s ease-in-out infinite alternate;
  transform-origin: center center;
}
@keyframes heroBgIn {
  to { filter: brightness(1.08) saturate(1); transform: scale(1); }
}
@keyframes kenBurns {
  from { transform: scale(1)    translate3d(0,0,0); }
  to   { transform: scale(1.06) translate3d(-1.2%, -0.8%, 0); }
}

/* Voile : le titre doit tenir sur la photo à toute taille */
#hero::before {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(rgba(0,0,0,0.22), rgba(0,0,0,0.22)),
    radial-gradient(ellipse at 50% 46%, transparent 0%, rgba(0,0,0,0.06) 48%, rgba(0,0,0,0.18) 100%),
    linear-gradient(to bottom, rgba(0,0,0,0.86) 0%, rgba(0,0,0,0.48) 12%, rgba(0,0,0,0.10) 26%, transparent 36%),
    linear-gradient(to top,    rgba(0,0,0,0.94) 0%, rgba(0,0,0,0.68) 14%, rgba(0,0,0,0.24) 28%, transparent 44%);
}

#hero-shimmer {
  position: absolute; bottom: 0; left: 0; right: 0; height: 1px; z-index: 3;
  pointer-events: none;
  background: linear-gradient(to right,
    rgba(var(--gold-rgb),0) 0%, rgba(var(--gold-rgb),0.22) 50%, rgba(var(--gold-rgb),0) 100%);
}

.hero__content {
  flex: 1; position: relative; z-index: 2;
  display: flex; flex-direction: column; justify-content: flex-end;
  /* Le CTA flotte au-dessus du hero dès l'arrivée : le contenu remonte pour
     lui laisser son pied, au lieu de passer dessous. */
  padding: 0 var(--px) calc(clamp(38px, 7vh, 80px) + var(--cta-space));
  padding-bottom: calc(max(clamp(38px, 7vh, 80px), env(safe-area-inset-bottom)) + var(--cta-space));
}

/* Le titre : masques de ligne. Le texte est découvert, il ne vole pas.
   142 % couvre le débord de glyphe à line-height .86, plus le cisaillement. */
.hero__title {
  font-family: var(--cond);
  font-size: calc(8vw + 26px);          /* passe par 58,5 px à 390 et 144 px à 1440 */
  font-weight: 600;
  line-height: 0.86;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--off-white);
}
.hero__title .line { display: block; }
/* Même apparition que les titres de section : la chasse se resserre + fondu
   (plus de slide masqué). */
.hero__title .line__inner {
  display: block;
  opacity: 0;
  letter-spacing: 0.14em;
  animation: lineUp 1.6s var(--ease) forwards;
}
.hero__title .line:nth-child(1) .line__inner { animation-delay: 0.9s; }
.hero__title .line:nth-child(2) .line__inner { animation-delay: 1.02s; }
@keyframes lineUp {
  to { opacity: 1; letter-spacing: 0; }
}

.hero__bottom {
  margin-top: clamp(18px, 3vh, 40px);
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px;
  opacity: 0; animation: fadeUp 0.9s 1.5s var(--ease) forwards;
}

.hero__referral {
  font-size: 11px; letter-spacing: 0.24em; text-transform: uppercase;
  color: rgba(242,239,233,0.52); line-height: 1.9;
  text-shadow: 0 1px 12px rgba(8,7,6,0.9);
}
.hero__referral-main, .hero__referral-location { display: block; }

/* Le signal Malta–Paris : deux nœuds, une liaison, une correspondance */
.hero__signal {
  position: relative; width: min(304px, 100%); z-index: 2; pointer-events: none;
  margin-top: clamp(16px, 2.5vh, 28px);
  opacity: 0; animation: fadeUp 0.9s 1.35s var(--ease) forwards;
}
.hero__signal-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 9px; }
.hero__signal-city {
  font-size: 8px; line-height: 1; letter-spacing: 0.18em; text-transform: uppercase;
  color: rgba(242,239,233,0.72);
  text-shadow: 0 0 10px rgba(var(--gold-rgb), 0.22);
}
.hero__signal-city--malta { animation: signalPulseMalta 7.4s 2.2s ease-in-out infinite; }
.hero__signal-city--paris { animation: signalPulseParis 7.4s 2.2s ease-in-out infinite; }

.hero__signal-track { position: relative; height: 20px; }
.hero__signal-track::before {
  content: ''; position: absolute; left: 3px; right: 3px; top: 50%; height: 1px;
  transform: translateY(-50%);
  background: linear-gradient(to right,
    rgba(var(--gold-rgb),0.18), rgba(242,239,233,0.12), rgba(var(--gold-rgb),0.18));
}
.hero__signal-line {
  position: absolute; left: 3px; right: 3px; top: 50%; height: 1px;
  transform: translateY(-50%) scaleX(0); transform-origin: left center;
  background: linear-gradient(to right,
    rgba(var(--gold-rgb),0.08), rgba(var(--gold-rgb),0.96), rgba(var(--gold-rgb),0.16));
  box-shadow: 0 0 16px rgba(var(--gold-rgb), 0.28);
  animation: signalLine 7.4s 2.2s var(--ease-cut) infinite;
}
.hero__signal-node {
  position: absolute; top: 50%; width: 6px; height: 6px; border-radius: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid rgba(var(--gold-rgb), 0.78);
  background: rgba(8,7,6,0.76);
  box-shadow: 0 0 0 5px rgba(var(--gold-rgb), 0.06), 0 0 15px rgba(var(--gold-rgb), 0.34);
}
.hero__signal-node--malta { left: 0; }
.hero__signal-node--paris { left: 100%; }
.hero__signal-correspondence {
  position: absolute; left: 0; top: 50%; width: 5px; height: 5px; border-radius: 50%;
  transform: translate(-50%, -50%) scale(0.82);
  background: rgba(var(--gold-rgb), 0.92);
  box-shadow: 0 0 0 4px rgba(var(--gold-rgb), 0.055), 0 0 14px rgba(var(--gold-rgb), 0.58);
  animation: signalMove 7.4s 2.2s var(--ease-cut) infinite;
}
@keyframes signalLine {
  0%, 6%    { transform: translateY(-50%) scaleX(0); }
  26%, 74%  { transform: translateY(-50%) scaleX(1); }
  100%      { transform: translateY(-50%) scaleX(1); }
}
@keyframes signalMove {
  0%, 10%   { left: 0;    opacity: 0; transform: translate(-50%,-50%) scale(0.82); }
  16%       { opacity: 1; }
  52%       { left: 100%; opacity: 1; transform: translate(-50%,-50%) scale(1.45); }
  64%       { left: 100%; opacity: 0; transform: translate(-50%,-50%) scale(0.9); }
  100%      { left: 100%; opacity: 0; }
}
@keyframes signalPulseMalta {
  0%, 12%  { color: rgba(242,239,233,0.72); }
  16%      { color: rgba(var(--gold-rgb), 0.98); }
  34%,100% { color: rgba(242,239,233,0.72); }
}
@keyframes signalPulseParis {
  0%, 48%  { color: rgba(242,239,233,0.72); }
  56%      { color: rgba(var(--gold-rgb), 0.98); }
  74%,100% { color: rgba(242,239,233,0.72); }
}

.hero__scroll {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  opacity: 0; animation: fadeUp 1s 2s var(--ease) forwards;
}
.hero__scroll-line {
  width: 1px; height: 40px;
  background: linear-gradient(to bottom, transparent, rgba(242,239,233,0.3));
  animation: scrollPulse 2.5s 2.5s ease-in-out infinite;
}
@keyframes scrollPulse { 0%,100% { opacity: 0.35; } 50% { opacity: 1; } }

@keyframes fadeUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }

/* ═══════════════════════ B14 · ABOUT ═══════════════════════
   Composition asymétrique : le titre en pleine largeur, la photo qui sort
   du cadre à droite, le texte tassé en bas à gauche. La photo n'est pas
   centrée dans une colonne — c'est ce qui distingue une page éditoriale
   d'une grille de gabarit.
   ─────────────────────────────────────────────────────────────────────── */
#about {
  position: relative;
  background: var(--warm-white); color: var(--black);
  padding: clamp(72px, 11vh, 150px) var(--px);
  /* `clip`, jamais `hidden` : un `overflow: hidden` devient conteneur de
     défilement et capte la `view()` de ses enfants, qui restent figés. */
  overflow: clip;
  display: grid; grid-template-columns: 1fr;
  gap: 0;
}
#about::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(ellipse 60% 50% at 88% 30%, rgba(var(--gold-rgb),0.07), transparent 62%);
}
#about > * { position: relative; z-index: 1; }

/* Pas de filet au-dessus : aucune autre section n'en a. */
.about__eyebrow { color: var(--grey-mid); }

/* Deux voix dans le même titre, comme le marqueur de « How it works ». */
.about__headline {
  margin-top: clamp(18px, 3vh, 34px);
  line-height: 0.9;
}
.about__headline-main {
  display: block;
  font-family: var(--cond);
  font-size: clamp(46px, 13vw, 118px);
  font-weight: 600; letter-spacing: 0.01em;
  text-transform: uppercase; color: var(--black);
}
.about__headline-alt {
  display: block;
  margin-top: 0.1em;
  padding-left: clamp(10px, 4vw, 96px);
  font-family: var(--serif);
  /* Plus courte que la ligne capitale : elle se pose dessous, elle ne
     rivalise pas avec elle. */
  font-size: clamp(27px, 7.6vw, 70px);
  font-style: italic; font-weight: 300;
  line-height: 1.05;
  letter-spacing: 0; text-transform: none;
  color: var(--gold-deep);
}

.about__media {
  margin: clamp(34px, 6vh, 68px) 0 0;
  /* Elle sort du cadre : le sujet continue au-delà de la page. */
  margin-left: calc(-1 * var(--px));
}
.about__media img {
  width: 100%; height: auto;
  aspect-ratio: 3 / 2; object-fit: cover;
  filter: contrast(1.04);
}
.about__text {
  margin-top: clamp(30px, 5vh, 56px);
  font-family: var(--serif);
  font-size: clamp(17px, 1.7vw, 23px);
  font-style: italic; font-weight: 300;
  color: #5e5a52; line-height: 1.68;
  max-width: 40ch;
}
.about__text p + p { margin-top: 1.1em; }

/* ═══════════════════════ B10 · THE JOURNEY ═══════════════════════════
   Une roue « montre » cropée sur le côté gauche : au scroll, elle tourne et
   amène chaque étape (01→06) au point de focus, une à une, pendant que la
   section est épinglée. Sans JS : liste lisible (fallback). */
#journey { position: relative; background: var(--black); color: var(--off-white); overflow: clip; }
.journey__stage { position: relative; }
.journey__pin { position: relative; padding: var(--py) var(--px); }
.journey__video { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.journey__video-el { width: 100%; height: 100%; object-fit: cover; filter: grayscale(1) contrast(1.05) brightness(0.88); display: block; }
.journey__scrim { position: absolute; inset: 0; background: linear-gradient(90deg, rgba(6,6,6,0.72), rgba(6,6,6,0.5) 42%, rgba(6,6,6,0.88)); }

.journey__wheel-wrap { display: none; }
.journey__active { display: none; }
.journey__panel { position: relative; z-index: 2; }

.journey__title { margin-top: clamp(10px,1.8vh,20px); font-family: var(--cond); font-weight: 600; text-transform: uppercase; font-size: clamp(40px,7vw,96px); line-height: 0.9; letter-spacing: 0.01em; color: var(--off-white); text-wrap: balance; }
.journey__title em { display: block; margin-top: 0.06em; font-family: var(--serif); font-style: italic; font-weight: 300; text-transform: none; letter-spacing: 0; color: var(--gold-light); font-size: 0.62em; line-height: 1.02; }
.journey__intro { margin-top: clamp(16px,2.6vh,28px); max-width: 34ch; font-family: var(--serif); font-style: italic; font-weight: 300; font-size: clamp(16px,1.55vw,21px); color: var(--grey-light); line-height: 1.6; }

/* Fallback : liste des étapes (composant member) */
.journey__list { display: block; position: relative; list-style: none; margin-top: clamp(28px,5vw,44px); }
.journey__list::before { content:''; position:absolute; left:0; top:30px; bottom:30px; width:1px; background: linear-gradient(to bottom, var(--rule), var(--rule-med), var(--rule)); }
.journey__step-data { position: relative; display: grid; grid-template-columns: 52px minmax(0,1fr); gap:14px; padding: clamp(22px,5vw,30px) 0 clamp(22px,5vw,30px) 22px; border-bottom: 1px solid var(--rule); }
.journey__step-data:last-child { border-bottom: none; }
.journey__list-num { font-family: var(--cond); font-weight: 700; line-height: 1; font-size: clamp(30px,6vw,52px); letter-spacing: 0.04em; color: rgba(242,239,233,0.20); }
.journey__list-title { font-family: var(--cond); font-weight: 600; font-size: clamp(12px,1.3vw,15px); letter-spacing: 0.16em; text-transform: uppercase; color: var(--off-white); margin-bottom: 8px; }
.journey__list-sub { font-family: var(--serif); font-style: italic; font-weight: 300; font-size: clamp(16px,1.5vw,21px); color: var(--grey-light); line-height: 1.5; }

/* ══════ Enrichi (JS) : la roue épinglée ══════ */
#journey.journey--wheel .journey__stage { height: 340vh; }
#journey.journey--wheel .journey__pin {
  position: sticky; top: 0; height: 100vh; overflow: hidden; padding: 0 var(--px);
}
#journey.journey--wheel .journey__list { display: none; }
#journey.journey--wheel .journey__wheel-wrap { display: block; }
/* L'étape active se pose AU FOCUS, entre le cadran (gauche) et le titre (droite). */
#journey.journey--wheel .journey__active {
  display: block; position: absolute; top: 50%; right: 46vw; transform: translateY(-50%);
  z-index: 3; max-width: 16ch; text-align: right;
}

/* Le centre du cadran : la connexion Malta → Paris (fixe, ne tourne pas). */
.journey__center { display: none; }
#journey.journey--wheel .journey__center {
  display: flex; align-items: center; gap: clamp(10px, 1vw, 16px);
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 2; white-space: nowrap;
}
.journey__center-city { font-family: var(--serif); font-style: italic; font-weight: 300; font-size: clamp(17px, 1.7vw, 24px); color: rgba(var(--gold-rgb), 0.92); }
.journey__center-link { width: clamp(64px, 7vw, 108px); height: auto; opacity: 0.9; }

/* ─── Apparition de la section : le cadran se FORME ────────────────────
   À l'entrée en vue (is-in) : l'anneau se trace (la montre se compose), le
   cadran se révèle, puis « Malta -> Paris », le titre et l'étape montent en
   cascade. Sans JS / reduced-motion : tout est visible d'emblée. */
.js-rythme #journey.journey--wheel .journey__ring-c { stroke-dasharray: 296; stroke-dashoffset: 296; }
.js-rythme #journey.journey--wheel.is-in .journey__ring-c { animation: journeyDraw 2.2s cubic-bezier(.4,0,.2,1) 0.15s forwards; }
@keyframes journeyDraw { to { stroke-dashoffset: 0; } }

.js-rythme #journey.journey--wheel .journey__wheel-wrap { opacity: 0; }
.js-rythme #journey.journey--wheel.is-in .journey__wheel-wrap { animation: journeyFade 1.5s var(--ease) forwards; }

.js-rythme #journey.journey--wheel .journey__center { opacity: 0; }
.js-rythme #journey.journey--wheel.is-in .journey__center { animation: journeyFade 1.1s var(--ease) 1.5s forwards; }

.js-rythme #journey.journey--wheel .journey__panel > * { opacity: 0; transform: translateY(22px); }
/* Le texte actif est centré par translateY(-50%) : son entrée doit partir de
   (-50% + 22px) et revenir à -50%, sinon l'anim l'écrase en `none` et le texte
   retombe hors du centre du cadran (visible surtout en mobile). */
.js-rythme #journey.journey--wheel .journey__active { opacity: 0; transform: translateY(calc(-50% + 22px)); }
.js-rythme #journey.journey--wheel.is-in .journey__panel > * { animation: journeyUp 1s var(--ease) forwards; }
.js-rythme #journey.journey--wheel.is-in .journey__panel .cap            { animation-delay: 0.35s; }
.js-rythme #journey.journey--wheel.is-in .journey__panel .journey__title { animation-delay: 0.5s; }
.js-rythme #journey.journey--wheel.is-in .journey__panel .journey__intro { animation-delay: 0.68s; }
.js-rythme #journey.journey--wheel.is-in .journey__active { animation: journeyUpActive 1s var(--ease) 1.25s forwards; }

@keyframes journeyFade { to { opacity: 1; } }
@keyframes journeyUp { to { opacity: 1; transform: none; } }
@keyframes journeyUpActive { to { opacity: 1; transform: translateY(-50%); } }

#journey.journey--wheel .journey__panel {
  position: absolute; top: 50%; left: var(--px); transform: translateY(-50%);
  width: min(38ch, 31vw); z-index: 2;
}

.journey__wheel-wrap { position: absolute; right: -26vh; top: 50%; transform: translateY(-50%); width: 92vh; height: 92vh; z-index: 1; pointer-events: none; }
.journey__ring { position: absolute; inset: 0; width: 100%; height: 100%; }
.journey__chips { position: absolute; inset: 0; }
.journey__chip { position: absolute; transform: translate(-50%, -50%); }
.journey__chip-num { display: block; font-family: var(--cond); font-weight: 700; line-height: 1; font-size: clamp(22px, 2.8vw, 40px); letter-spacing: 0.04em; color: rgba(242,239,233,0.28); transition: color 0.35s var(--ease), transform 0.35s var(--ease); }
.journey__chip.is-focus .journey__chip-num { color: var(--gold-light); transform: scale(1.35); }
.journey__focus-mark { position: absolute; left: 6%; top: 50%; width: 8px; height: 8px; border-radius: 50%; transform: translate(-50%,-50%); background: var(--gold); box-shadow: 0 0 0 5px rgba(var(--gold-rgb),0.12), 0 0 16px rgba(var(--gold-rgb),0.5); }

.journey__active-num { font-family: var(--cond); font-weight: 600; font-size: clamp(13px,1.2vw,16px); letter-spacing: 0.26em; color: var(--gold); }
.journey__active-label { font-family: var(--cond); font-weight: 600; text-transform: uppercase; font-size: clamp(28px,3.4vw,50px); letter-spacing: 0.05em; line-height: 1; color: var(--off-white); margin-top: 10px; }
.journey__active-sub { font-family: var(--serif); font-style: italic; font-weight: 300; font-size: clamp(18px,1.9vw,27px); color: var(--grey-light); margin-top: 14px; }

@media (max-width: 860px) and (orientation: portrait) {
  #journey.journey--wheel .journey__pin { display: block; }
  /* Le titre revient AU-DESSUS du cadran, centré pour s'aligner sur lui. */
  #journey.journey--wheel .journey__panel {
    display: block; position: absolute; top: clamp(52px, 9vh, 96px); left: var(--px); right: var(--px);
    width: auto; transform: none; text-align: center; z-index: 3;
  }
  #journey.journey--wheel .journey__intro { display: none; }
  #journey.journey--wheel .journey__center { display: none; }
  #journey.journey--wheel .journey__title { font-size: clamp(40px, 12vw, 64px); }
  /* Cadran plein largeur, posé sous le titre ; l'étape active en son centre. */
  .journey__wheel-wrap { left: 50%; right: auto; top: 62%; transform: translate(-50%, -50%); width: 96vw; height: 96vw; }
  #journey.journey--wheel .journey__active {
    top: 62%; left: var(--px); right: var(--px); width: auto; max-width: none;
    text-align: center; padding: 0 6vw;
  }
  .journey__active-label { font-size: clamp(30px, 9vw, 48px); }
  .journey__active-sub { font-size: clamp(17px, 4.6vw, 22px); }
  .journey__active-num { font-size: 13px; }
}

/* Mobile PAYSAGE : la hauteur d'écran est très courte, donc un cadran en `vw`
   (comme en portrait) déborde largement. On revient à la logique desktop
   (panneau à gauche, cadran à droite, étape active entre les deux), mais le
   cadran est dimensionné en `vh` pour tenir dans la hauteur. */
@media (max-width: 900px) and (orientation: landscape) {
  #journey.journey--wheel .journey__pin { display: block; }
  #journey.journey--wheel .journey__panel {
    display: block; position: absolute; top: 50%; left: var(--px); right: auto;
    width: min(42vw, 36ch); transform: translateY(-50%); text-align: left; z-index: 3;
  }
  #journey.journey--wheel .journey__title { font-size: clamp(28px, 5.4vw, 52px); }
  #journey.journey--wheel .journey__intro { display: none; }
  #journey.journey--wheel .journey__center { display: none; }
  .journey__wheel-wrap {
    left: auto; right: -14vh; top: 50%;
    transform: translateY(-50%); width: 92vh; height: 92vh;
  }
  #journey.journey--wheel .journey__active {
    top: 50%; left: auto; right: 40vw; width: auto; max-width: 14ch;
    text-align: right; padding: 0; transform: translateY(-50%);
  }
  .journey__active-label { font-size: clamp(24px, 6vh, 40px); }
  .journey__active-sub { font-size: clamp(15px, 3.6vh, 20px); }
  .journey__active-num { font-size: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  #journey.journey--wheel .journey__stage { height: auto; }
  #journey.journey--wheel .journey__pin { position: relative; height: auto; overflow: visible; display: block; }
  #journey.journey--wheel .journey__wheel-wrap, #journey.journey--wheel .journey__active { display: none; }
  #journey.journey--wheel .journey__list { display: block; }
}

/* ═══════════════════════ B04 · FOUR DOMAINS ═══════════════════════ */
#domains {
  background: var(--near);
  padding: var(--py) var(--px);
  display: flex; flex-direction: column; justify-content: center;
}

.domains__head {
  position: relative;
  display: flex; flex-direction: column; gap: 24px;
  padding-bottom: clamp(28px, 5vh, 56px);
  border-bottom: 1px solid var(--rule);
  margin-bottom: clamp(28px, 5vh, 56px);
}
.domains__headline {
  font-family: var(--cond);
  font-size: clamp(40px, 11vw, 80px);
  font-weight: 600; line-height: 0.95; letter-spacing: 0.02em;
  text-transform: uppercase; color: var(--off-white);
  margin-top: 16px; text-wrap: balance;
}
.domains__sub {
  font-family: var(--serif);
  font-size: clamp(15px, 1.4vw, 18px);
  font-style: italic; font-weight: 300;
  color: var(--grey-mid); line-height: 1.6; max-width: 34ch;
}

/* Le sceau : une lumière qui court le trait, pas un cadre statique */
.domains__path {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  pointer-events: none; overflow: visible;
  background: linear-gradient(to right, transparent, rgba(242,239,233,0.12), transparent);
}
.domains__path-progress {
  position: absolute; left: 0; top: 0; width: 0; height: 1px;
  background: linear-gradient(to right, rgba(var(--gold-rgb),0.18), rgba(var(--gold-rgb),0.96));
  box-shadow: 0 0 14px rgba(var(--gold-rgb), 0.24);
}
.domains__path-progress::after {
  content: ''; position: absolute; right: -3px; top: 50%;
  width: 6px; height: 6px; border-radius: 50%;
  transform: translateY(-50%) scale(0.84);
  background: rgba(var(--gold-rgb), 0.98);
  box-shadow: 0 0 0 6px rgba(var(--gold-rgb), 0.08), 0 0 16px rgba(var(--gold-rgb), 0.42);
}
#domains.visible-section .domains__path-progress {
  animation: domainsPath 8.8s var(--ease-cut) 0.2s infinite;
}
@keyframes domainsPath {
  0%   { width: 0;    opacity: 0; }
  6%   { opacity: 1; }
  76%  { width: 100%; opacity: 1; }
  90%  { width: 100%; opacity: 0; }
  100% { width: 100%; opacity: 0; }
}

.domains__grid { display: grid; grid-template-columns: 1fr; gap: 0; }

.domain {
  padding-bottom: 24px;
  border-bottom: 1px solid var(--rule);
}
.domain + .domain { padding-top: 24px; }
.domain:last-child { border-bottom: none; padding-bottom: 0; }

.domain__num {
  font-family: var(--cond);
  font-size: clamp(36px, 9vw, 52px);
  font-weight: 700; line-height: 1; letter-spacing: 0.04em;
  color: var(--grey-dark);
  transform-origin: left center;
  transition: color 0.5s var(--ease);
}
#domains.visible-section .domain:nth-child(1) .domain__num { animation: domainNum 8.8s var(--ease-cut) 0.2s infinite; }
#domains.visible-section .domain:nth-child(2) .domain__num { animation: domainNum 8.8s var(--ease-cut) 1.8s infinite; }
#domains.visible-section .domain:nth-child(3) .domain__num { animation: domainNum 8.8s var(--ease-cut) 3.4s infinite; }
#domains.visible-section .domain:nth-child(4) .domain__num { animation: domainNum 8.8s var(--ease-cut) 5.0s infinite; }
@keyframes domainNum {
  0%, 4%   { color: var(--grey-dark); }
  9%       { color: rgba(var(--gold-rgb), 0.92); }
  22%,100% { color: var(--grey-dark); }
}

.domain__name {
  font-size: clamp(11px, 1vw, 13px);
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--off-white); line-height: 1.5; margin-top: 12px;
}
.domain__detail {
  font-family: var(--serif);
  font-size: clamp(15px, 1.3vw, 17px);
  font-style: italic; font-weight: 300;
  color: var(--grey-mid); line-height: 1.5; margin-top: 10px;
}

/* ═══════════════════════ B09 · ONE REQUEST / RELATIONSHIP ═══════════════════════ */
#member {
  position: relative;
  background: var(--warm-white); color: var(--black);
  padding: clamp(70px, 10vh, 150px) var(--px);
  overflow: clip;
}
#member::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(115deg, rgba(8,7,6,0.035) 0%, transparent 42%),
    linear-gradient(to bottom, transparent 0%, rgba(var(--gold-rgb),0.055) 55%, transparent 100%);
}
#member > * { position: relative; z-index: 1; }
#member .cap { color: #8a8680; }

.member__headline {
  font-family: var(--cond);
  font-size: clamp(42px, 12vw, 126px);
  font-weight: 600; line-height: 0.9; letter-spacing: 0.01em;
  text-transform: uppercase; color: var(--black);
  margin-top: 20px; max-width: 1080px; text-wrap: balance;
}
.member__intro {
  margin-top: clamp(20px, 3vh, 36px);
  font-family: var(--serif);
  font-size: clamp(18px, 2vw, 30px);
  font-style: italic; font-weight: 300;
  color: #5e5a52; line-height: 1.6; max-width: 36ch;
}

.member__journey {
  margin-top: clamp(42px, 8vh, 96px);
  display: grid; grid-template-columns: 1fr;
  gap: 28px; align-items: start;
}
.member__marker {
  font-family: var(--cond);
  font-size: clamp(32px, 10vw, 78px);
  font-weight: 600; line-height: 0.92; letter-spacing: 0.04em;
  text-transform: uppercase; color: rgba(8,7,6,0.16);
}
.member__marker span {
  display: block;
  font-family: var(--serif); font-style: italic; font-weight: 300;
  letter-spacing: 0; text-transform: none;
  color: rgba(var(--gold-rgb), 0.92);
}

.member__path { position: relative; }
.member__path::before {
  content: ''; position: absolute; left: 0; top: 34px; bottom: 34px; width: 1px;
  z-index: 1; pointer-events: none;
  background: linear-gradient(to bottom, rgba(8,7,6,0.08), rgba(8,7,6,0.18), rgba(8,7,6,0.08));
}
.member__path-progress {
  position: absolute; left: 0; top: 34px; width: 1px; height: 0;
  z-index: 2; pointer-events: none;
  background: linear-gradient(to bottom, rgba(var(--gold-rgb),0.18), rgba(var(--gold-rgb),0.96));
  box-shadow: 0 0 14px rgba(var(--gold-rgb), 0.26);
}
.member__path-progress::after {
  content: ''; position: absolute; left: 50%; bottom: -3px;
  width: 7px; height: 7px; border-radius: 50%;
  transform: translateX(-50%);
  background: rgba(var(--gold-rgb), 0.96);
  box-shadow: 0 0 0 7px rgba(var(--gold-rgb), 0.08), 0 0 16px rgba(var(--gold-rgb), 0.38);
}
.member__path.is-animating .member__path-progress {
  animation: memberPath 8.8s var(--ease-cut) 0.25s infinite;
}
@keyframes memberPath {
  0%   { height: 0; opacity: 0; }
  6%   { opacity: 1; }
  76%  { height: calc(100% - 68px); opacity: 1; }
  90%  { height: calc(100% - 68px); opacity: 0; }
  100% { height: calc(100% - 68px); opacity: 0; }
}

.member__step {
  position: relative;
  display: grid; grid-template-columns: 48px minmax(0, 1fr);
  gap: 14px;
  padding: 28px 0 28px 22px;
  border-bottom: 1px solid var(--rule-dark);
}
.member__step:last-child { border-bottom: none; }
.member__step-num {
  font-family: var(--cond);
  font-size: clamp(30px, 10vw, 58px);
  font-weight: 700; letter-spacing: 0.04em; line-height: 1;
  color: rgba(8,7,6,0.18);
  transition: color 0.35s ease;
}
.member__path.is-animating .member__step:nth-of-type(1) .member__step-num { animation: memberNum 8.8s var(--ease-cut) 0.25s infinite; }
.member__path.is-animating .member__step:nth-of-type(2) .member__step-num { animation: memberNum 8.8s var(--ease-cut) 2.4s infinite; }
.member__path.is-animating .member__step:nth-of-type(3) .member__step-num { animation: memberNum 8.8s var(--ease-cut) 4.5s infinite; }
@keyframes memberNum {
  0%, 3%   { color: rgba(8,7,6,0.18); }
  8%       { color: rgba(var(--gold-rgb), 0.95); }
  24%,100% { color: rgba(8,7,6,0.18); }
}

.member__step-title {
  font-size: clamp(11px, 1.15vw, 15px);
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--black); margin-bottom: 10px; line-height: 1.35;
}
.member__step-text {
  font-family: var(--serif);
  font-size: clamp(16px, 1.6vw, 22px);
  font-style: italic; font-weight: 300;
  color: #6a6760; line-height: 1.7; max-width: 720px;
}

/* ═══════════════════════ B12 · CONTACT ═══════════════════════ */
#contact {
  position: relative;
  background: var(--black); color: var(--off-white);
  padding: var(--py) var(--px);
  display: grid; grid-template-columns: 1fr;
  gap: clamp(24px, 4vw, 40px);
  align-items: center;
}
#contact .cap { color: var(--gold); }
.contact__headline {
  font-family: var(--cond);
  font-size: clamp(56px, 12vw, 132px);
  font-weight: 600; line-height: 0.9; letter-spacing: 0.02em;
  text-transform: uppercase; color: var(--off-white);
  margin-top: 18px; text-wrap: balance;
}
.contact__body {
  font-family: var(--serif);
  font-size: clamp(16px, 1.5vw, 20px);
  font-style: italic; font-weight: 300;
  color: var(--grey-light); line-height: 1.8;
  max-width: 36ch; margin-bottom: 30px;
}

/* ─── La photo de la maison, ajoutée à la section ──────────────────────
   Un plateau portrait, contenu et centré — pas une bannière. La source est
   verticale : on la respecte (4/5) pour que les silhouettes restent
   naturelles, et on borne la largeur pour qu'elle ponctue sans écraser. */
.contact__photo { margin: 0 auto; width: min(100%, 460px); }
/* Conteneur à ratio fixe : le padding fait la hauteur (5/4 = 125 %), l'image
   remplit en absolu. Robuste partout, indépendant du chargement de l'image. */
.contact__photo-frame {
  position: relative; width: 100%; padding-top: 125%;
  overflow: hidden;   /* bords droits, comme les autres images du site */
}
.contact__photo-frame img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 34%;
  filter: grayscale(1) contrast(1.03);
}
.contact__photo figcaption {
  margin-top: 12px; text-align: center;
  font-family: var(--cond); text-transform: uppercase;
  letter-spacing: 0.24em; font-size: 10.5px; font-weight: 600; color: #888480;
}

/* ─── Le cadre où le CTA flottant finit sa course ──────────────────────
   La pastille se retire à l'entrée de ce bloc et réapparaît ici, posée.
   Le cadre se dessine puis un sceau court son périmètre, comme sur les
   cartes de la maison. `pathLength="1"` rend le tracé indépendant de la
   taille du bloc : un seul jeu de valeurs pour toutes les largeurs. */
.invitation {
  position: relative; isolation: isolate;
  width: min(100%, 620px);
  margin-inline: auto;          /* le point d'arrivée de la page est centré */
  text-align: center;
  padding: clamp(26px, 5vw, 40px) clamp(22px, 4vw, 38px) clamp(24px, 4vw, 36px);
  border-radius: 12px;
  background: linear-gradient(150deg, rgba(242,239,233,0.06), rgba(var(--gold-rgb),0.05) 48%, rgba(8,7,6,0.10)), var(--charcoal);
  box-shadow: 0 22px 52px rgba(0,0,0,0.5), 0 0 0 1px rgba(var(--gold-rgb),0.10);
}

.invitation__frame {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%;
  pointer-events: none; overflow: visible;
}
.invitation__frame rect {
  width: calc(100% - 1px); height: calc(100% - 1px);
  fill: none; vector-effect: non-scaling-stroke;
}
.invitation__frame-base { stroke: rgba(var(--gold-rgb), 0.18); stroke-width: 1; }

/* Le cadre se dessine d'un trait à l'entrée. */
.invitation__frame-draw {
  stroke: rgba(var(--gold-rgb), 0.55); stroke-width: 1;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.4s var(--ease-cut) 0.15s;
}
.js-rythme #contact.is-in .invitation__frame-draw { stroke-dashoffset: 0; }

/* Puis le sceau : 16 % de long qui court le périmètre, sans fin. */
.invitation__frame-seal {
  stroke: var(--gold-light); stroke-width: 1.4;
  stroke-dasharray: 0.16 0.84; stroke-dashoffset: 0;
  opacity: 0;
  filter: drop-shadow(0 0 6px rgba(var(--gold-rgb), 0.7));
}
.js-rythme #contact.is-in .invitation__frame-seal {
  animation: sealFade 0.6s ease 1.5s both,
             sealRun 5.2s linear 1.5s infinite;
}
@keyframes sealFade { to { opacity: 0.9; } }
@keyframes sealRun  { to { stroke-dashoffset: -1; } }

.invitation > *:not(.invitation__frame) { position: relative; z-index: 2; }

.invitation__title {
  font-family: var(--cond);
  font-size: clamp(20px, 4.4vw, 30px);
  font-weight: 600; letter-spacing: 0.22em; line-height: 1.1;
  text-transform: uppercase;
  color: rgba(242,239,233,0.94);
}
.invitation__note {
  margin-top: 12px;
  font-family: var(--serif);
  font-size: clamp(15px, 1.4vw, 18px);
  font-style: italic; font-weight: 300;
  color: var(--grey-light); line-height: 1.6;
}

.invitation__cta {
  display: inline-flex; align-items: center; justify-content: space-between;
  gap: 18px; margin-top: clamp(22px, 3.6vw, 30px);
  min-height: 48px; min-width: min(100%, 240px);
  padding: 12px 16px 12px 22px;
  border-radius: 999px;
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--black);
  background: linear-gradient(135deg, var(--gold-light), var(--gold));
  border: 1px solid rgba(205,175,120,0.42);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 6px 20px rgba(8,7,6,0.3);
  transition: background 0.4s ease, box-shadow 0.4s ease, transform 0.5s var(--ease);
}
.invitation__cta:hover {
  transform: translateY(-2px);
  background: linear-gradient(135deg, #dcc08d, var(--gold-light));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.26), 0 10px 28px rgba(8,7,6,0.36);
}
.invitation__arrow {
  font-family: var(--serif); font-size: 16px; line-height: 1; letter-spacing: 0;
  transition: transform 0.45s var(--ease);
}
.invitation__cta:hover .invitation__arrow { transform: translateX(5px); }

.contact__stats {
  display: flex; flex-wrap: wrap; gap: clamp(22px, 4vw, 52px);
  margin-top: clamp(24px, 4vh, 40px); padding-top: clamp(22px, 3vh, 32px);
  border-top: 1px solid var(--rule);
}
.contact__stat-num {
  font-family: var(--cond); font-weight: 600; line-height: 1;
  font-size: clamp(30px, 3.4vw, 50px); letter-spacing: 0.01em; color: var(--off-white);
}
.contact__stat-label {
  margin-top: 8px; max-width: 15ch;
  font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: clamp(13px, 1.05vw, 16px); line-height: 1.3; color: var(--grey-mid);
}
.contact__details { margin-top: clamp(20px, 3vh, 30px); display: flex; flex-direction: column; gap: 10px; }
.contact__detail {
  font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase; color: #9a9894;
}
.contact__detail a {
  display: inline-flex; align-items: center; min-height: 44px;
  transition: color 0.3s ease;
}
.contact__detail a:hover { color: var(--gold-light); }

/* ═══════════════════════ B13 · FOOTER ═══════════════════════ */
footer {
  background: var(--black);
  color: rgba(242,239,233,0.40);
  padding: 28px var(--px);
  padding-bottom: max(28px, env(safe-area-inset-bottom));
  display: flex; flex-direction: column;
  gap: 18px;
  border-top: 1px solid rgba(242,239,233,0.08);
}
.footer__left {
  font-family: var(--cond);
  font-size: 12px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: rgba(242,239,233,0.56);
}
.footer__items { display: flex; gap: clamp(16px, 4vw, 52px); flex-wrap: wrap; align-items: center; }
.footer__item { font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; color: rgba(242,239,233,0.42); }
.footer__email {
  font-size: 11px; letter-spacing: 0.14em; color: rgba(242,239,233,0.42);
  transition: color 0.3s ease;
}
.footer__email:hover { color: rgba(242,239,233,0.66); }
.footer__instagram {
  display: flex; align-items: center; gap: 8px;
  color: rgba(242,239,233,0.46); transition: color 0.3s ease;
}
.footer__instagram:hover { color: rgba(242,239,233,0.68); }
.footer__instagram svg { width: 15px; height: 15px; flex-shrink: 0; }
.footer__instagram-label { font-size: 10px; letter-spacing: 0.16em; }
.footer__copy { font-size: 11px; letter-spacing: 0.12em; color: rgba(242,239,233,0.34); }

/* ─── Cibles tactiles ──────────────────────────────────────────────────
   Le logo, le CTA de nav et les liens de pied font 9 à 34 px de haut : c'est
   la bonne hauteur visuelle et la mauvaise cible au doigt. On étend la zone
   de touche sans toucher à la mise en page. */
.nav__logo,
.footer__email,
.footer__instagram,
.lang__link { position: relative; }

.nav__logo::after,
.footer__email::after,
.footer__instagram::after,
.lang__link::after {
  content: '';
  position: absolute; left: 0; right: 0; top: 50%;
  height: 44px; transform: translateY(-50%);
}

/* ═══════════════════════ LE RYTHME DES SECTIONS ═══════════════════════
   Quatre sections, quatre entrées différentes. Un rythme n'est pas une
   répétition : si les quatre blocs arrivent de la même façon, il n'y a pas
   de rythme, il y a une boucle. Le contraste entre les gestes fait la
   cadence.

     01 · What we arrange  →  LATÉRAL      deux masses qui se rejoignent
     02 · How it works     →  SÉQUENTIEL   un processus, donc une suite
     03 · Who we are       →  L'ÉCART      la serrure, jouée en composition
     Get in touch          →  CONVERGENCE  tout se resserre sur l'action

   BIDIRECTIONNEL, DEUX SEUILS DISTINCTS
   Entrée quand la section touche la bande centrale de l'écran ; sortie
   seulement quand elle est entièrement hors écran. Voir `site.js` pour
   pourquoi un seuil unique ne peut pas faire les deux.

   L'aller et le retour n'ont pas la même durée : l'entrée prend son temps
   et sa cascade, la sortie est brève et sans décalage. On ne fait pas
   attendre quelqu'un qui s'en va.
   ─────────────────────────────────────────────────────────────────────── */
:root {
  --r-in:  900ms;
  --r-out: 460ms;
  /* Le déplacement des masses. En `vw` seul il tombait à 50 px sur un
     téléphone : un « grand geste » qui se lit comme un défaut de rendu.
     Le plancher en pixels le garde lisible sur 80 % du trafic. */
  --r-x:  clamp(96px, 13vw, 200px);
  --r-x2: clamp(72px, 9vw,  140px);
}

/* ─── Le contenu est visible par DÉFAUT ────────────────────────────────
   Les états « hors focus » ne s'appliquent que sous `.js-rythme`, classe
   que `site.js` pose juste avant d'installer les observateurs. Tant qu'il
   ne l'a pas posée, rien n'est caché.

   La version précédente faisait l'inverse : le CSS cachait, le JS
   révélait. Ça marche tant que tout marche — mais `no-js` est retiré à la
   première ligne de `site.js` alors que la chorégraphie n'est installée
   que cinquante lignes plus bas. Toute erreur entre les deux laissait des
   sections entièrement vides, sans aucun filet. Un contenu ne doit jamais
   dépendre d'un script pour être lisible. */

/* Hors focus : décalé et transparent, sortie brève et sans décalage. */
.js-rythme #domains .domains__head, .js-rythme #domains .domains__grid,
.js-rythme #member .cap, .js-rythme #member .member__headline,
.js-rythme #member .member__intro, .js-rythme #member .member__step,
.js-rythme #about .about__eyebrow, .js-rythme #about .about__headline,
.js-rythme #about .about__media, .js-rythme #about .about__text,
.js-rythme #contact .contact__lead, .js-rythme #contact .contact__aside,
.js-rythme #contact .contact__photo, .js-rythme #contact .invitation {
  opacity: 0;
  transition: transform var(--r-out) var(--ease), opacity var(--r-out) var(--ease);
  transition-delay: 0s;
}
/* En focus : au repos, entrée longue, cascade autorisée.

   Le préfixe `.js-rythme` est obligatoire ici, pas décoratif. Sans lui,
   `#domains.is-in .domains__head` (1 id + 2 classes) est à égalité de
   spécificité avec `.js-rythme #domains .domains__head`, et c'est alors
   l'ordre du fichier qui tranche : la règle de `transform` écrite plus bas
   gagnait, le décalage n'était jamais annulé et le titre restait 73 px hors
   écran, définitivement. Toute nouvelle règle « hors focus » doit rester
   d'un cran en dessous de celle-ci. */
.js-rythme #domains.is-in .domains__head, .js-rythme #domains.is-in .domains__grid,
.js-rythme #member.is-in .cap, .js-rythme #member.is-in .member__headline, .js-rythme #member.is-in .member__intro,
.js-rythme #member.is-in .member__step,
.js-rythme #about.is-in .about__eyebrow, .js-rythme #about.is-in .about__headline,
.js-rythme #about.is-in .about__media, .js-rythme #about.is-in .about__text,
.js-rythme #contact.is-in .contact__lead, .js-rythme #contact.is-in .contact__aside, .js-rythme #contact.is-in .contact__photo, .js-rythme #contact.is-in .invitation {
  opacity: 1; transform: none;
  transition: transform var(--r-in) var(--ease), opacity 620ms var(--ease);
}

/* ─── Les titres se posent en resserrant leur chasse ──────────────────
   Le letter-spacing part large et se referme sur sa valeur propre ;
   l'opacité suit. Remplace le dévoilement par le bas.

   Contrainte : un titre ne déborde jamais du padding. Les gros titres
   (Member 126px, About 118px) reçoivent donc un delta plus petit — la
   chasse ne pousse pas le texte contre le bord. Défini par titre plus bas,
   après le bloc de rythme, pour gagner la cascade à spécificité égale. */

/* 01 · LE DÉVOILEMENT — le titre se découvre, les domaines se posent. */
.js-rythme #domains .domains__head { transform: translateY(22px); }
.js-rythme #domains .domains__grid { transform: translateY(48px); }
.js-rythme #domains.is-in .domains__grid { transition-delay: 110ms; }

/* 02 · SÉQUENTIEL — 01, puis 02, puis 03. Le seul bloc où la suite veut
   dire quelque chose : c'est un processus. Le marqueur « From request /
   to recognition » ne bouge pas : c'est le repère fixe contre lequel la
   suite se lit. */
.js-rythme #member .cap,
.js-rythme #member .member__headline,
.js-rythme #member .member__intro { transform: translateY(46px); }
.js-rythme #member .member__step  { transform: translateY(74px); }
.js-rythme #member.is-in .member__headline { transition-delay: 90ms; }
.js-rythme #member.is-in .member__intro    { transition-delay: 170ms; }
.js-rythme #member.is-in .member__step:nth-of-type(1) { transition-delay: 300ms; }
.js-rythme #member.is-in .member__step:nth-of-type(2) { transition-delay: 490ms; }
.js-rythme #member.is-in .member__step:nth-of-type(3) { transition-delay: 680ms; }

/* 03 · L'ENTRÉE PAR LA GAUCHE — seule la photo se déplace latéralement.
   Elle déborde déjà du cadre : la couper n'est pas un défaut, c'est le
   cadrage. Le texte, lui, monte. */
.js-rythme #about .about__eyebrow,
.js-rythme #about .about__headline { transform: translateY(30px); }
.js-rythme #about .about__media { transform: translateX(calc(-1 * var(--r-x))) scale(1.04); }
.js-rythme #about .about__text  { transform: translateY(40px); }
.js-rythme #about.is-in .about__headline { transition-delay: 100ms; }
.js-rythme #about.is-in .about__media    { transition-delay: 200ms; }
.js-rythme #about.is-in .about__text     { transition-delay: 300ms; }

/* 04 · CONVERGENCE — les colonnes se resserrent, le cadre arrive en
   dernier. La page se referme sur l'unique action. */
.js-rythme #contact .contact__lead  { transform: translateY(38px); }
.js-rythme #contact .contact__aside { transform: translateY(38px); }
.js-rythme #contact .contact__photo { transform: translateY(50px); }
.js-rythme #contact .invitation     { transform: translateY(64px) scale(0.97); }
.js-rythme #contact.is-in .contact__aside { transition-delay: 90ms; }
.js-rythme #contact.is-in .contact__photo { transition-delay: 200ms; }
.js-rythme #contact.is-in .invitation     { transition-delay: 320ms; }

/* ═══ Chasse qui se resserre — l'apparition des titres ════════════════
   Hors focus : chasse = valeur propre + delta, opacité 0. En focus : la
   chasse revient, le titre est net. On annule les montées verticales
   propres aux titres pour que le seul mouvement soit typographique.
   Placé après le rythme : à spécificité égale, l'ordre tranche. */
.js-rythme #domains .domains__headline,
.js-rythme #member  .member__headline,
.js-rythme #contact .contact__headline,
.js-rythme #about   .about__headline-main,
.js-rythme #about   .about__headline-alt {
  opacity: 0;
  transition: letter-spacing 1100ms var(--ease), opacity 720ms var(--ease);
}
.js-rythme #domains .domains__headline    { letter-spacing: calc(0.02em + 0.12em); }
.js-rythme #member  .member__headline     { letter-spacing: calc(0.01em + 0.05em); }
.js-rythme #contact .contact__headline    { letter-spacing: calc(0.02em + 0.10em); }
.js-rythme #about   .about__headline-main { letter-spacing: calc(0.01em + 0.08em); }
.js-rythme #about   .about__headline-alt  { letter-spacing: calc(0em   + 0.10em); }

/* Le seul mouvement est la chasse : on neutralise les translations
   verticales posées directement sur ces titres. */
.js-rythme #member .member__headline,
.js-rythme #about  .about__headline { transform: none; }

.js-rythme #domains.is-in .domains__headline,
.js-rythme #member.is-in  .member__headline,
.js-rythme #contact.is-in .contact__headline,
.js-rythme #about.is-in   .about__headline-main,
.js-rythme #about.is-in   .about__headline-alt {
  opacity: 1;
  transition: letter-spacing 1100ms var(--ease), opacity 720ms var(--ease);
}
.js-rythme #domains.is-in .domains__headline    { letter-spacing: 0.02em; }
.js-rythme #member.is-in  .member__headline     { letter-spacing: 0.01em; }
.js-rythme #contact.is-in .contact__headline    { letter-spacing: 0.02em; }
.js-rythme #about.is-in   .about__headline-main { letter-spacing: 0.01em; }
.js-rythme #about.is-in   .about__headline-alt  { letter-spacing: 0em; }

/* Les titres restent en deux lignes, mais ne sont plus masqués ligne à
   ligne : c'est le bloc entier qui entre désormais. Le balisage `.mask`
   est conservé — il ne coûte rien et garde l'option ouverte. */
.mask__line { display: block; }
.mask__line > i { display: block; font-style: inherit; }

/* ─── L'articulation entre deux sections ───────────────────────────────
   Un filet doré se tire en travers du raccord quand la section entre.
   C'est ce qui manquait : les blocs se succédaient sans jointure. */
main > section[data-theme]::after {
  content: ''; position: absolute; top: 0; left: 0; right: 0;
  height: 1px; z-index: 3; pointer-events: none;
  background: linear-gradient(90deg,
    transparent, rgba(var(--gold-rgb), 0.42) 30%, rgba(var(--gold-rgb), 0.42) 70%, transparent);
  transform: scaleX(0);
  transition: transform 1.6s var(--ease-cut);
}
main > section[data-theme].visible-section::after { transform: scaleX(1); }
#domains, #member, #about, #contact { position: relative; }

/* ─── Profondeur au scroll ─────────────────────────────────────────────
   Là où le navigateur sait lier une animation au défilement, la photo de
   l'About dérive dans son cadre et les grands chiffres fantômes suivent
   avec un temps de retard. Ailleurs, rien ne change : c'est du confort,
   pas de la structure. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .about__media { overflow: clip; }
    .about__media img {
      animation: mediaDrift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes mediaDrift {
      from { transform: scale(1.14) translateY(4.5%); }
      to   { transform: scale(1.14) translateY(-4.5%); }
    }

    .member__marker, .about__headline-alt {
      animation: ghostDrift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes ghostDrift {
      from { translate: 0 14px; }
      to   { translate: 0 -14px; }
    }
  }
}

/* ═══════════════════════ MONTÉE EN CHARGE ═══════════════════════ */

@media (min-width: 561px) {
  .domains__grid { grid-template-columns: repeat(2, 1fr); }
  .domain {
    padding-right: clamp(20px, 3vw, 44px);
    border-right: 1px solid var(--rule);
  }
  .domain:nth-child(even) { border-right: none; padding-right: 0; padding-left: clamp(20px, 3vw, 44px); }
  .domain:nth-child(3), .domain:nth-child(4) { padding-top: 24px; }
  .domain:nth-child(1), .domain:nth-child(2) { padding-bottom: 24px; }
}

@media (min-width: 861px) {
  .domains__head { flex-direction: row; justify-content: space-between; align-items: flex-end; }
  .domains__sub { text-align: right; max-width: 260px; align-self: flex-end; }

  .domains__grid { grid-template-columns: repeat(4, 1fr); }
  .domain,
  .domain:nth-child(even),
  .domain:nth-child(1), .domain:nth-child(2),
  .domain:nth-child(3), .domain:nth-child(4) {
    border-right: 1px solid var(--rule); border-bottom: none;
    padding: 0 clamp(20px, 3vw, 44px) 0 0;
  }
  .domain + .domain { padding-left: clamp(20px, 3vw, 44px); }
  .domain:last-child { border-right: none; padding-right: 0; }

  /* Douze colonnes. Le titre tient la largeur, puis la photo à gauche et
     le texte à droite : on lit l'image avant la phrase, pas l'inverse.

     La photo déborde par la gauche. Le texte est centré sur sa hauteur —
     calé en bas, il laissait un vide au milieu de la section, l'œil
     tombait dans un trou entre le titre et le paragraphe. */
  #about {
    grid-template-columns: repeat(12, 1fr);
    column-gap: clamp(20px, 2.4vw, 40px);
    align-items: start;
    min-height: 88vh;
  }
  .about__eyebrow  { grid-column: 1 / 5;  grid-row: 1; }
  .about__headline { grid-column: 1 / 10; grid-row: 2; }

  /* Pas de remontée négative : la ligne dorée est longue et l'image lui
     passait dessus. Le décalage vient du débord à droite et du texte calé
     en bas, pas d'un chevauchement. */
  .about__media {
    grid-column: 1 / 8; grid-row: 3;
    margin-top: clamp(18px, 2.5vw, 40px);
    margin-left: calc(-1 * var(--px));
    margin-right: 0;
  }
  .about__text {
    grid-column: 8 / 13; grid-row: 3;
    align-self: center;
    margin-top: 0;
    max-width: 34ch;
  }

  #domains { min-height: 70vh; }
  #member  { min-height: 90vh; }

  /* Le titre à gauche, le texte à droite, et le cadre centré en travers
     des deux : il conclut la page, il n'est pas rangé dans une marge. */
  /* Resserré : titre + texte à gauche, photo à droite, et l'invitation
     centrée tout en bas — le point d'arrivée de la page. */
  #contact {
    grid-template-columns: 1fr minmax(300px, 0.7fr);
    grid-template-rows: auto auto auto;
    align-items: start;
    column-gap: clamp(30px, 4.5vw, 64px);
    row-gap: clamp(18px, 2.6vh, 30px);
  }
  .contact__lead  { grid-column: 1; grid-row: 1; }
  .contact__aside { grid-column: 1; grid-row: 2; }
  .contact__photo { grid-column: 2; grid-row: 1 / 3; align-self: stretch; justify-self: end;
    width: min(100%, 420px); display: flex; flex-direction: column; }
  .contact__photo-frame { flex: 1 1 auto; padding-top: 0; }
  .invitation     { grid-column: 1 / -1; grid-row: 3; justify-self: center; margin-top: clamp(28px, 5vh, 64px); }

  .hero__signal { width: clamp(330px, 34vw, 500px); }
  .hero__signal-row { gap: clamp(12px, 1.4vw, 20px); }
  .hero__signal-city { font-size: 11px; letter-spacing: 0.3em; }
  .hero__signal-track { height: 26px; }
  .hero__signal-node { width: 8px; height: 8px; }

  .member__journey { grid-template-columns: minmax(210px, 0.42fr) 1fr; gap: clamp(34px, 6vw, 88px); }
  .member__marker { position: sticky; top: 120px; }
  .member__step { grid-template-columns: minmax(76px, 112px) 1fr; gap: clamp(18px, 3vw, 44px); padding: clamp(24px,4vh,44px) 0 clamp(24px,4vh,44px) clamp(28px,4vw,56px); }

  footer { flex-direction: row; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; }

  .invitation__title { letter-spacing: 0.30em; }
}

/* Téléphone couché : le hero ne doit pas manger l'écran */
@media (max-width: 932px) and (max-height: 520px) and (orientation: landscape) {
  #hero { height: auto; min-height: 100svh; }
  .hero__title { font-size: clamp(40px, 9vw, 72px); }
  .hero__eyebrow { margin-bottom: 14px; }
  .hero__bottom { margin-top: 18px; }
}

/* ═══════════════════════ ACCESSIBILITÉ ═══════════════════════ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.2s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.2s !important;
  }
  .hero__bg { filter: none; transform: none; animation: none; }
  .hero__title .line__inner { opacity: 1; transform: none; letter-spacing: 0; animation: none; }
  .hero__signal, .hero__bottom, .hero__scroll { opacity: 1; animation: none; }
  /* Le rythme des sections : tout est en place, sans exception. */
  #domains .domains__head, #domains .domains__grid,
  #member .cap, #member .member__headline, #member .member__intro, #member .member__step,
  #about .about__eyebrow, #about .about__headline, #about .about__media, #about .about__text,
  #contact .contact__lead, #contact .contact__aside, #contact .contact__photo, #contact .invitation {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
  .hero__signal-line { transform: translateY(-50%) scaleX(1); animation: none; }
  .hero__signal-correspondence, .domains__path-progress, .member__path-progress { display: none; }
}

/* Si le JS ne part pas, le contenu reste visible — et le CTA reste joignable
   plutôt que d'attendre un observer qui ne viendra jamais. Sans JS, personne
   ne pose `is-in` : sans ce filet, les quatre sections resteraient vides. */
/* (Le filet `.no-js` pour le rythme n'a plus lieu d'être : les états
   « hors focus » sont scopés sous `.js-rythme`, que seul le JS pose.) */
/* Sans JS, personne ne pose `is-shown` : on rend le nom visible et on le
   laisse défiler avec la page, sans voile, plutôt que de le voir rester
   fixé sur le texte des sections. */
.no-js #main-nav {
  position: absolute;
  opacity: 1; visibility: visible; transform: none;
}
/* Sans JS, personne ne pose `is-shown` : on montre le nom d'emblée. Posé en
   absolu tout en haut (sur le hero sombre), il défile avec la page en clair,
   puis s'en va — pas de bascule de couleur à assurer. */
.no-js .nav__logo {
  pointer-events: auto;
  opacity: 1; transform: none;
}
.no-js .cta-float {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translate(-50%, 0) scale(1);
}

/* ═══════════════════════ CURSEUR ═══════════════════════
   Le curseur maison : un point, un anneau qui respire au survol, une traîne
   de fantômes, et le halo doré qui suit la main avec du retard — la signature.
   Pur confort desktop. Gaté ici sur un pointeur fin ; injecté par le JS, jamais
   dans le HTML. Sur tactile ou sans JS, le curseur système reste seul maître. */
@media (hover: hover) and (pointer: fine) {
  body { cursor: none; }

  .cursor-dot {
    position: fixed; top: 0; left: 0; width: 5px; height: 5px;
    background: var(--off-white); border-radius: 50%;
    pointer-events: none; z-index: 9999;
    transform: translate(-50%, -50%);
    mix-blend-mode: difference;
    transition: opacity 0.6s ease;
  }
  .cursor-dot.idle { opacity: 0; }

  .cursor-ring {
    position: fixed; top: 0; left: 0; width: 34px; height: 34px;
    border: 0.5px solid rgba(242, 239, 233, 0.35); border-radius: 50%;
    pointer-events: none; z-index: 9998;
    transform: translate(-50%, -50%);
    transition: width 0.5s var(--ease), height 0.5s var(--ease),
                border-color 0.4s ease, opacity 0.3s ease;
  }
  .cursor-ring.is-hovering {
    width: 56px; height: 56px; border-color: rgba(242, 239, 233, 0.6);
  }

  /* La traîne : trois points fantômes en retard sur la main. */
  .cursor-ghost {
    position: fixed; top: 0; left: 0; border-radius: 50%;
    background: var(--off-white);
    pointer-events: none; z-index: 9996;
    transform: translate(-50%, -50%);
    mix-blend-mode: difference;
  }

  /* Le halo doré — dégradé radial blanc→or, en fondu « écran », flouté. */
  .cursor-spotlight {
    position: fixed; top: 0; left: 0;
    width: clamp(275px, 35vw, 525px); height: clamp(275px, 35vw, 525px);
    border-radius: 50%;
    pointer-events: none; z-index: 42;
    transform: translate(-50%, -50%);
    background: radial-gradient(circle,
      rgba(242, 239, 233, 0.156) 0%,
      rgba(var(--gold-rgb), 0.09) 22%,
      rgba(var(--gold-rgb), 0.03) 44%,
      transparent 70%);
    mix-blend-mode: screen;
    opacity: 0.5;
    filter: blur(4px);
    transition: opacity 0.45s ease;
  }
  .cursor-spotlight.idle { opacity: 0; }

  /* Le mot sous le point, seulement sur les cibles marquées `data-cursor`. */
  .cursor-label {
    position: fixed; top: 0; left: 0;
    pointer-events: none; z-index: 9997;
    transform: translate(-50%, -50%);
    font-family: var(--sans);
    font-size: 8px; letter-spacing: 0.28em; text-transform: uppercase;
    color: rgba(var(--gold-rgb), 0.9);
    white-space: nowrap;
    opacity: 0; transition: opacity 0.3s ease;
  }
  .cursor-label.visible { opacity: 1; }
}
