/* ═══════════════════════════════════════════════════════════════════════
   Tuvia Capital — page d'accueil publique
   ───────────────────────────────────────────────────────────────────────
   Ce fichier est servi depuis notre domaine (/assets/landing.css). La
   politique de sécurité du site (`style-src 'self'`) refuse un CDN.

   RÈGLE DE BASE : la page doit être entièrement lisible SANS JavaScript.
   Tout état « avant animation » vit donc sous `html.js` — la classe que
   `landing.js` pose sur <html> dès qu'il démarre. Sans JS, rien n'est
   caché. Un seul mouvement échappe à cette règle, l'entrée du hero : elle
   est en CSS pur (keyframes), parce qu'elle se joue AU-DESSUS de la ligne
   de flottaison, là où un état initial posé par un script différé
   provoquerait un clignotement.
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── 0. Polices ───────────────────────────────────────────────────── */

/* Servies depuis NOTRE domaine, comme tout le reste de cette page.
   Mesuré : la feuille de style de Google Fonts bloquait l'affichage
   837 ms à elle seule (un aller-retour DNS + TLS vers un second domaine,
   avant même de savoir quels fichiers télécharger), et le plus grand
   élément de la page apparaissait à 2,8 s. Rapatriées ici, les deux
   polices sont découvertes dans la même réponse que le reste.
   Ce sont les versions VARIABLES, sous-ensemble latin (le français y est
   entièrement couvert, accents compris) : un seul fichier par famille
   couvre toutes les graisses employées. Licences OFL dans
   /vendor/fonts/. `swap` : le texte s'affiche tout de suite avec la
   police du système et bascule quand la nôtre arrive. */
@font-face {
  font-family: 'Fraunces';
  src: url('/vendor/fonts/fraunces-latin-wght.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Manrope';
  src: url('/vendor/fonts/manrope-latin-wght.woff2') format('woff2');
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

/* ─── 1. Jetons ────────────────────────────────────────────────────── */

:root {
  /* Marque — charte officielle Tuvia.
     Deux adaptations assumées, parce que la charte est pensée pour un
     fond CLAIR et que cette page est sur marine :
     · `--slate` (#5B6B82) ne donne que 2,8:1 sur le marine : il ne sert
       donc QU'aux filets et séparateurs, jamais à du texte. Le texte
       tertiaire emploie `--slate-lift` (6,0:1).
     · `--emerald` ne donne que 4,3:1 sur une carte : les petits textes
       verts emploient `--emerald-lift` (6,3:1). Les pastilles et les
       icônes, elles, gardent l'emerald de la charte (seuil 3:1). */
  --navy:         #0B2545;  /* fond de la page */
  --navy-deep:    #05080F;  /* hero + salle de projection : fond EXACT des médias */
  --navy-raised:  #0F2E53;  /* cartes */
  --navy-sunk:    #08203C;  /* bandes, pied de page */
  --mist:         #EEF2F7;  /* texte principal       — 13,7:1 sur marine */
  --navy-mist:    #C9D6E8;  /* texte secondaire      — 10,5:1 */
  --slate:        #5B6B82;  /* filets uniquement */
  --slate-lift:   #8FA3BF;  /* texte tertiaire       —  6,0:1 */
  --gold:         #D9B86A;  /* gold-bright, l'accent sur marine — 8,1:1 */
  --emerald:      #10A37F;  /* signal hausse : pastilles, icônes */
  --emerald-lift: #2BC79B;  /* texte vert sur carte */

  --line:         rgba(201, 214, 232, 0.14);  /* navy-mist à 14 % */
  --line-strong:  rgba(201, 214, 232, 0.26);
  --gold-wash:    rgba(217, 184, 106, 0.10);

  /* Typographie fluide — jamais de taille par palier */
  /* Le titre du hero est calibré pour que chacune de ses deux lignes
     tienne VRAIMENT sur une ligne : la plus longue mesure 13,4 fois la
     taille de police, et sa colonne vaut ~0,57 de la largeur de l'écran.
     D'où le 4vw — au-delà, le masque se révélerait par blocs de deux
     lignes au lieu de ligne à ligne. */
  --t-display:  clamp(2.25rem, 4vw, 3.5rem);
  --t-h2:       clamp(1.75rem, 1.1rem + 2.4vw, 2.6rem);
  --t-h3:       clamp(1.125rem, 1rem + 0.4vw, 1.25rem);
  --t-lead:     clamp(1.0625rem, 1rem + 0.35vw, 1.1875rem);
  --t-body:     clamp(0.9375rem, 0.9rem + 0.2vw, 1rem);
  --t-label:    0.75rem;

  /* Espacement */
  --sp-xs:  clamp(8px, 1vw, 12px);
  --sp-sm:  clamp(12px, 1.5vw, 18px);
  --sp-md:  clamp(18px, 2.2vw, 28px);
  --sp-lg:  clamp(28px, 3.4vw, 46px);
  --sp-xl:  clamp(48px, 6vw, 84px);
  --sp-2xl: clamp(72px, 9vw, 132px);

  --wrap: 1180px;
  --gutter: clamp(20px, 4vw, 32px);
  --radius: 18px;

  /* Courbes — aucune n'est rebondissante : c'est une fintech */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);     /* power4.out */
  --ease-mid: cubic-bezier(0.65, 0, 0.35, 1);
}

/* ─── 2. Socle ─────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--navy);
  color: var(--mist);
  font-family: 'Manrope', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: var(--t-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
  font-weight: 500;
  margin: 0;
  /* Indispensable : sans elle, les titres héritent du 1.6 du corps de
     texte et s'étalent sur trois interlignes. Plus le texte est gros,
     plus l'interligne doit être serré. */
  line-height: 1.16;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
h3 { line-height: 1.28; letter-spacing: -0.015em; }

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

/* Accessibilité : le focus clavier doit toujours se voir. */
:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute;
  left: 50%;
  top: 8px;
  transform: translate(-50%, -200%);
  z-index: 100;
  padding: 12px 20px;
  background: var(--navy-raised);
  border: 1px solid var(--gold);
  border-radius: 999px;
  color: var(--gold);
  font-weight: 700;
  transition: transform 0.2s var(--ease-out);
}
.skip:focus { transform: translate(-50%, 0); }

.wrap {
  width: min(var(--wrap), 100% - var(--gutter) * 2);
  margin-inline: auto;
}
/* Le hero respire plus large que le reste de la page : c'est la rupture
   de rythme qui l'installe comme bloc signature, et c'est elle qui donne
   au titre la largeur dont il a besoin. */
.wrap--hero { --wrap: 1320px; }

/* ─── 3. Éléments communs ──────────────────────────────────────────── */

.eyebrow {
  font-size: var(--t-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--slate-lift);
  font-weight: 700;
}

.lead {
  font-size: var(--t-lead);
  line-height: 1.65;
  color: var(--navy-mist);
  max-width: 54ch;
}

.card {
  background: linear-gradient(180deg, var(--navy-raised), rgba(15, 46, 83, 0.55));
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* Boutons — plus aucun aplat d'or : la charte l'interdit. Le bouton
   principal se distingue par un contour or plein et un voile doré au
   survol ; le secondaire par un simple filet clair. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 14px 26px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.9375rem;
  line-height: 1;
  border: 1px solid transparent;
  background: transparent;
  cursor: pointer;
  transition: background-color 0.3s var(--ease-out),
              border-color 0.3s var(--ease-out),
              box-shadow 0.3s var(--ease-out);
}
.btn-primary {
  border-color: var(--gold);
  color: var(--gold);
  box-shadow: inset 0 0 0 0 var(--gold-wash);
}
.btn-ghost {
  border-color: var(--line-strong);
  color: var(--mist);
}
.btn-sm { padding: 10px 20px; font-size: 0.875rem; }

/* Survol réservé à la souris : au doigt, iOS rejoue les événements de
   souris et l'état resterait collé au bouton touché. */
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover {
    background-color: var(--gold-wash);
    box-shadow: 0 0 0 4px rgba(217, 184, 106, 0.08);
  }
  .btn-ghost:hover {
    border-color: var(--mist);
    background-color: rgba(238, 242, 247, 0.06);
  }
  .navlink:hover { color: var(--mist); }
  .navlink:hover::after { transform: scaleX(1); }
}

.media-note {
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--slate-lift);
  letter-spacing: 0.01em;
  text-align: center;
  margin-top: var(--sp-sm);
}

/* Un badge d'état. « Disponible » et « Bientôt » ne se ressemblent pas :
   une fonctionnalité à venir ne doit jamais se lire comme une promesse
   tenue. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.badge::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.badge-live { color: var(--emerald-lift); background: rgba(16, 163, 127, 0.12); }
.badge-soon { color: var(--gold);         background: var(--gold-wash); }

/* ─── 4. Barre de navigation ───────────────────────────────────────── */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background-color 0.4s var(--ease-out),
              border-color 0.4s var(--ease-out),
              backdrop-filter 0.4s var(--ease-out);
}
/* Posée par landing.js au-delà de 24 px de défilement. */
.nav.is-scrolled {
  background: rgba(11, 37, 69, 0.82);
  border-bottom-color: var(--line);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
}

.nav__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: clamp(14px, 1.6vw, 20px);
  transition: padding-block 0.4s var(--ease-out);
}
.nav.is-scrolled .nav__bar { padding-block: 11px; }

.nav__logo { height: 38px; width: auto; transition: height 0.4s var(--ease-out); }
.nav.is-scrolled .nav__logo { height: 32px; }

.nav__links { display: flex; align-items: center; gap: clamp(20px, 2.6vw, 36px); }

.navlink {
  position: relative;
  font-size: 0.875rem;
  color: var(--navy-mist);
  transition: color 0.2s var(--ease-out);
}
.navlink::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -4px;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease-out);
}
.navlink:hover::after { transform-origin: left; }

/* « Se connecter » : un lien, pas un second bouton — deux pastilles
   côte à côte se disputeraient l'attention, et c'est l'inscription
   qu'on veut d'abord. En clair (mist) plutôt qu'en navy-mist, pour le
   distinguer des ancres de section. */
.nav__login { color: var(--mist); margin-left: clamp(4px, 1vw, 12px); }

.nav__mobile { display: none; align-items: center; gap: 14px; }

/* ─── 5. Hero ──────────────────────────────────────────────────────── */

/* Fond EXACTEMENT celui de la vidéo (#05080F) : les bords du média s'y
   fondent sans aucune arête visible. C'est une contrainte du média, pas
   un choix de palette — d'où un marine plus profond qu'ailleurs. */
.hero {
  position: relative;
  background: var(--navy-deep);
  padding-top: clamp(40px, 6vw, 72px);
  padding-bottom: clamp(56px, 7vw, 96px);
  overflow: hidden;
}

.hero__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.28fr 0.72fr;
  gap: clamp(32px, 4vw, 56px);
  align-items: center;
}

/* Le titre se révèle ligne par ligne : chaque ligne est écrite telle
   quelle dans le HTML, dans un masque. Pas de découpage JavaScript —
   deux lignes ne le justifient pas, et le texte reste intact pour les
   lecteurs d'écran et les moteurs de recherche.
   `padding-bottom` + marge négative : sans eux, le masque couperait les
   jambages (le « g » de « Gérer »). */
.hero__title {
  font-size: var(--t-display);
  line-height: 1.05;
  letter-spacing: -0.025em;
  margin-top: var(--sp-md);
}
.line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.line__in { display: block; }

.hero__lead { margin-top: var(--sp-md); max-width: 30em; }

.hero__actions {
  display: flex;
  gap: var(--sp-sm);
  margin-top: var(--sp-lg);
  flex-wrap: wrap;
}

.hero__stats {
  display: flex;
  gap: clamp(18px, 2.4vw, 30px);
  margin-top: var(--sp-xl);
  flex-wrap: wrap;
  align-items: stretch;
}
.hero__stat-v {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.375rem;
  line-height: 1.2;
  color: var(--mist);
}
.hero__stat-k {
  font-size: 0.75rem;
  color: var(--slate-lift);
  margin-top: 3px;
}
.hero__sep { width: 1px; background: var(--slate); opacity: 0.55; }

/* Le téléphone. Le conteneur est la cible du parallaxe souris : c'est lui
   qu'on translate, jamais la vidéo (qui doit garder son rendu natif). */
.hero__phone {
  position: relative;
  width: 100%;
  max-width: 580px;
  margin-inline: auto;
  will-change: transform;
}
/* La vidéo est un CARRÉ où le téléphone n'occupe que le tiers central :
   affichée telle quelle, l'appareil devient une vignette perdue dans du
   noir. On la RECADRE plutôt que de l'agrandir — un cadre plus haut que
   large, et `object-fit: cover` coupe les marges vides à gauche et à
   droite. Agrandir à la place (un `scale`) faisait dépasser la vidéo du
   côté droit de l'écran, où elle se faisait couper.
   `height: auto` n'est pas décoratif : les attributs width/height du
   HTML (ils réservent la place et évitent tout décalage) agissent comme
   une hauteur déclarée et l'emporteraient sur `aspect-ratio`. */
.hero__video {
  width: 100%;
  height: auto;
  aspect-ratio: 5 / 8;
  object-fit: cover;
  background: var(--navy-deep);
  /* Le recadrage coupe le média là où sa lueur autour du téléphone n'est
     pas encore retombée au noir : sur un grand écran, le rectangle de la
     vidéo se devinait. Les bords sont donc fondus par un masque — 12 % de
     chaque côté, 6 % en haut et en bas, loin du téléphone, qui occupe le
     tiers central. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent),
                      linear-gradient(180deg, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent),
              linear-gradient(180deg, transparent, #000 6%, #000 94%, transparent);
  mask-composite: intersect;
}

/* Repère de défilement : un trait qui respire, et un mot. Posé au bas
   du hero sur ordinateur seulement — sur téléphone, le pli est évident
   et chaque pixel compte. Le trait anime `transform`, donc rien ne
   repasse par la mise en page ; « réduire les animations » le fige. */
.hero__cue {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  display: none;
  align-items: center;
  gap: 10px;
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--slate-lift);
  z-index: 1;
}
.hero__cue-line {
  width: 1px;
  height: 36px;
  background: linear-gradient(180deg, transparent, var(--gold));
  transform-origin: top;
}
@media (min-width: 1024px) and (prefers-reduced-motion: no-preference) {
  .hero__cue-line { animation: cue-breathe 2.4s var(--ease-mid) infinite; }
}
@keyframes cue-breathe {
  0%   { transform: scaleY(0.35); opacity: 0.4; }
  55%  { transform: scaleY(1);    opacity: 1; }
  100% { transform: scaleY(0.35); opacity: 0.4; }
}

/* ─── 6. Bande de réassurance ──────────────────────────────────────── */

/* La transition du marine profond du hero vers le marine de la page se
   fait DANS cette bande : pas d'arête entre deux fonds. */
.strip {
  background: linear-gradient(180deg, var(--navy-deep), var(--navy));
  border-bottom: 1px solid var(--line);
}
.strip__row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 3vw, 40px);
  flex-wrap: wrap;
  padding-block: var(--sp-md);
  font-size: 0.8125rem;
  color: var(--slate-lift);
  letter-spacing: 0.02em;
  text-align: center;
}
.strip__dot { color: var(--slate); }

/* ─── 7. Mission ───────────────────────────────────────────────────── */

.mission { padding-top: var(--sp-2xl); }
.mission__card {
  padding: clamp(28px, 4vw, 52px);
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: clamp(24px, 3vw, 44px);
  align-items: center;
}
.mission__badges { display: flex; flex-direction: column; gap: 12px; }
.mission__badge {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 16px;
  border-radius: 12px;
  font-size: 0.875rem;
  line-height: 1.45;
}
.mission__badge-live {
  background: rgba(16, 163, 127, 0.08);
  border: 1px solid rgba(16, 163, 127, 0.3);
}
.mission__badge-soon {
  background: var(--gold-wash);
  border: 1px solid rgba(217, 184, 106, 0.3);
}
.dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dot-live { background: var(--emerald); }
.dot-soon { background: var(--gold); }

/* ─── 8. Le récit produit (salle de projection) ────────────────────── */

/* Fond marine profond, celui des images de la séquence, avec un dégradé
   d'entrée et de sortie pour qu'aucune arête n'apparaisse. */
.story {
  position: relative;
  margin-top: var(--sp-2xl);
  background: linear-gradient(180deg,
    var(--navy) 0,
    var(--navy-deep) 170px,
    var(--navy-deep) calc(100% - 170px),
    var(--navy) 100%);
}
.story__head { padding-top: var(--sp-2xl); text-align: center; }
.story__head .lead { margin-inline: auto; }

.story__stage { padding-block: var(--sp-xl); }

.story__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-lg);
  align-items: center;
}

.story__visual { position: relative; width: 100%; max-width: 480px; margin-inline: auto; }
/* L'image de chaque étape ne sert qu'au téléphone (carrousel ci-dessous) :
   sur ordinateur c'est le canvas qui montre l'écran. `loading="lazy"` et
   `display: none` : le navigateur ne la télécharge jamais ici. */
.step__img { display: none; }
.story__note-phone { display: none; }
.story__canvas,
.story__poster {
  width: 100%;
  height: auto;            /* voir la note sur .hero__video */
  aspect-ratio: 1 / 1;
  border-radius: 12px;
}
/* Par défaut — et donc sans JavaScript, et sur téléphone — on montre
   l'image fixe. Le canvas ne prend le relais que quand landing.js décide
   que la séquence est jouable (≥ 1024 px, mouvement non réduit).
   Les deux se superposent et se croisent en fondu : si le canvas
   apparaissait vide le temps que la première image arrive, on verrait un
   trou. Et comme c'est l'image fixe qui donne sa hauteur à la boîte, le
   passage de l'une à l'autre ne décale rien. */
.story__canvas { display: none; }
.story__poster { transition: opacity 0.3s var(--ease-out); }
.story.is-sequenced .story__canvas {
  display: block;
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.3s var(--ease-out);
}
.story.is-sequenced.is-ready .story__canvas { opacity: 1; }
.story.is-sequenced.is-ready .story__poster { opacity: 0; }

/* Les quatre étapes doivent tenir ENSEMBLE dans un écran : la section est
   épinglée, et une étape qui dépasse serait inatteignable. D'où des
   marges resserrées ici, plus serrées qu'ailleurs sur la page. */
.story__steps { display: grid; gap: 10px; }

.step {
  position: relative;
  padding: 16px 20px 16px 34px;
  border-radius: 14px;
  border: 1px solid transparent;
}
/* Le filet vertical marque l'étape en cours. Sans JS, toutes les étapes
   sont lisibles et aucune n'est « éteinte » : c'est une liste. */
.step::before {
  content: '';
  position: absolute;
  left: 0; top: 10px; bottom: 10px;
  width: 2px;
  border-radius: 2px;
  background: var(--line-strong);
}
.step__n {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  color: var(--gold);
}
.step__head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.step h3 { font-size: var(--t-h3); margin-top: 6px; }
.step p { margin-top: 8px; color: var(--navy-mist); font-size: 0.9375rem; }

/* ─── 9. Fonctionnalités ───────────────────────────────────────────── */

.features { padding-top: var(--sp-2xl); }
/* Quatre cartes : deux colonnes, jamais trois — à trois, la quatrième
   reste seule sur sa rangée et le bloc paraît inachevé. Le minimum de
   420 px impose ce découpage jusqu'à ce que l'écran devienne étroit. */
.features__grid {
  margin-top: var(--sp-lg);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: clamp(14px, 1.6vw, 20px);
}
.feature {
  position: relative;
  padding: clamp(24px, 2.6vw, 32px);
  transition: border-color 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .feature:hover { border-color: rgba(217, 184, 106, 0.38); transform: translateY(-3px); }
}
.feature__icon { color: var(--gold); }
.feature h3 { font-size: 1.1875rem; margin-top: var(--sp-sm); }
.feature p { margin-top: 10px; color: var(--navy-mist); }
.feature .badge { position: absolute; top: 24px; right: 24px; }

/* ─── 10. Approche ─────────────────────────────────────────────────── */

.approach { padding-block: var(--sp-2xl); }
.approach__grid {
  margin-top: var(--sp-lg);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  gap: clamp(24px, 2.6vw, 32px);
}
.approach__n { font-family: 'Fraunces', Georgia, serif; font-size: 2.125rem; color: var(--gold); line-height: 1; }
.approach__step h3 { font-size: 1.125rem; margin-top: 14px; }
.approach__step p { margin-top: 10px; color: var(--navy-mist); }
.approach__head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* ─── 11. Citation ─────────────────────────────────────────────────── */

.quote {
  padding-block: var(--sp-2xl);
  text-align: center;
  max-width: 820px;
  margin-inline: auto;
}
.quote__mark { opacity: 0.55; margin: 0 auto var(--sp-md); display: block; }
.quote blockquote { margin: 0; }
.quote p {
  font-family: 'Fraunces', Georgia, serif;
  font-size: clamp(1.3rem, 1rem + 1.4vw, 1.75rem);
  line-height: 1.5;
  color: var(--mist);
}
.quote figcaption { margin-top: var(--sp-md); font-size: 0.875rem; color: var(--slate-lift); }

/* ─── 12. Sécurité ─────────────────────────────────────────────────── */

.security { padding-bottom: var(--sp-2xl); }
.security__card {
  padding: clamp(28px, 4vw, 52px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4vw, 48px);
  align-items: center;
}
.security__list { margin-top: var(--sp-md); display: flex; flex-direction: column; gap: 12px; }
.security__item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 15px 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  font-size: 0.90625rem;
}
.security__visual {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 260px;
}
.security__halo {
  position: absolute;
  width: 190px; height: 190px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(16, 163, 127, 0.2), transparent 70%);
}
.security__ring {
  position: absolute;
  width: 180px; height: 180px;
  border-radius: 50%;
  border: 1px solid rgba(16, 163, 127, 0.35);
}
.security__lock { position: relative; }

/* Les ondes et le flottement du cadenas sont en CSS, pas en JavaScript :
   ils n'ont rien à voir avec le défilement, et le bloc « mouvement
   réduit » plus bas les neutralise sans qu'aucun code ne s'exécute. Ils
   n'animent que `transform` et `opacity`, donc rien ne repasse par la
   mise en page. */
@media (prefers-reduced-motion: no-preference) {
  .security__ring { animation: ping 3.2s ease-out infinite; }
  .security__ring[data-ring='1'] { animation-delay: 1.07s; }
  .security__ring[data-ring='2'] { animation-delay: 2.14s; }
  .security__lock { animation: lock-float 5.5s ease-in-out infinite; }
}
@keyframes ping {
  from { transform: scale(0.78); opacity: 0.55; }
  to   { transform: scale(1.7);  opacity: 0; }
}
@keyframes lock-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}

/* ─── 13. Appel final ──────────────────────────────────────────────── */

.cta { padding-bottom: var(--sp-2xl); }
.cta__card {
  padding: clamp(44px, 6vw, 72px) clamp(22px, 4vw, 48px);
  text-align: center;
  background: linear-gradient(180deg, var(--gold-wash), rgba(15, 46, 83, 0.4));
}
.cta__card h2 { font-size: var(--t-h2); }
.cta__card .lead { margin: var(--sp-sm) auto 0; max-width: 46ch; }
.cta__actions { display: flex; justify-content: center; margin-top: var(--sp-lg); }
/* Le bouton « magnétique » : landing.js lui donne une translation suivie
   par la souris. `will-change` n'est posé que sur ce bouton-là. */
.cta__actions .btn { will-change: transform; }

/* ─── 14. Pied de page ─────────────────────────────────────────────── */

.foot { border-top: 1px solid var(--line); background: var(--navy-sunk); }
.foot__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-md);
  padding-block: var(--sp-lg);
}
.foot__brand { display: flex; align-items: center; gap: 12px; font-size: 0.875rem; color: var(--slate-lift); }
.foot__mark {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 1.5px solid var(--gold);
  display: grid; place-items: center;
  font-family: 'Fraunces', Georgia, serif;
  font-size: 0.8125rem;
  color: var(--gold);
}
.foot__links { display: flex; gap: clamp(16px, 2vw, 28px); flex-wrap: wrap; }

/* Le groupe « Légal » : une seconde ligne, séparée par un filet, avec
   son intitulé — les deux documents sont ensemble, et nommés en entier. */
.foot__legal { border-top: 1px solid var(--line); }
.foot__legal-nav {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 10px clamp(16px, 2vw, 28px);
  padding-block: 18px;
}
.foot__legal-k {
  font-size: var(--t-label); letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--slate-lift); font-weight: 700; margin-right: 6px;
}

/* ═══ 15. La couche de mouvement ═══════════════════════════════════════
   Tout ce qui suit ne s'applique QUE si landing.js a démarré (html.js).
   Sans JavaScript, aucune de ces règles n'existe et la page est entière.
   ═════════════════════════════════════════════════════════════════════ */

/* Les révélations au défilement. Deux classes seulement, posées par
   landing.js et UNIQUEMENT sur les éléments situés sous la ligne de
   flottaison : un élément déjà à l'écran n'est jamais caché après coup.
   Une règle qui cacherait tout dès le chargement les ferait disparaître
   pour de bon si le script ne partait pas.
   La transition est portée par `.is-in`, pas par l'état de départ :
   sinon l'élément s'effacerait visiblement au moment où on l'arme. */
/* Une ANIMATION, pas une transition — et c'est mesuré, pas théorique :
   une transition qui porte un `transition-delay` (la cascade des
   groupes) est refusée par le compositeur de Chrome, qui la renvoie sur
   le fil principal (« paramètres de minutage non compatibles »). Une
   animation avec `animation-delay`, elle, reste sur le compositeur. Le
   délai passe donc par une variable, jamais par `transition-delay`. */
html.js .rv { opacity: 0; }
html.js .rv.is-in {
  animation: rv-rise 0.8s var(--ease-out) var(--rv-delay, 0s) both;
}
@keyframes rv-rise {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}

/* Les cartes se dévoilent par un `clip-path` : le bloc est là, c'est le
   rideau qui remonte. Plus net qu'un fondu sur une surface bordée. */
html.js .cv { opacity: 0; clip-path: inset(0 0 100% 0); }
html.js .cv.is-in {
  animation: cv-wipe 1s var(--ease-mid) both;
}
@keyframes cv-wipe {
  from { opacity: 0; clip-path: inset(0 0 100% 0); }
  to   { opacity: 1; clip-path: inset(0 0 0 0); }
}

/* Lenis — les trois règles nécessaires, recopiées plutôt qu'importées
   depuis `lenis/dist/lenis.css` (une requête réseau de moins). */
html.lenis, html.lenis body { height: auto; }
html.lenis-smooth { scroll-behavior: auto !important; }
html.lenis-stopped { overflow: hidden; }

/* ─── 16. Entrée du hero — CSS pur ─────────────────────────────────── */

/* Elle ne dépend pas de JavaScript, pour deux raisons : c'est le premier
   écran (un état initial posé par un script différé clignoterait), et
   `prefers-reduced-motion` se traite ici de façon déclarative, sans
   qu'aucun code n'ait à s'exécuter. Durée totale : 1,16 s. */
@media (prefers-reduced-motion: no-preference) {
  .hero__anim > * { animation: rise 0.8s var(--ease-out) backwards; }
  .hero__eyebrow  { animation-delay: 0.05s; }
  .hero__title    { animation: none; }           /* ses lignes s'animent seules */
  .hero__lead     { animation-delay: 0.46s; }
  .hero__actions  { animation-delay: 0.54s; }
  .hero__stats    { animation-delay: 0.62s; }

  .line__in { animation: line-up 0.9s var(--ease-out) backwards; }
  .line:nth-child(1) .line__in { animation-delay: 0.16s; }
  .line:nth-child(2) .line__in { animation-delay: 0.26s; }

  .hero__phone { animation: media-in 1.1s var(--ease-out) 0.3s backwards; }
  .hero .media-note { animation: rise 0.8s var(--ease-out) 0.8s backwards; }
}

@keyframes rise     { from { opacity: 0; transform: translateY(18px); } }
@keyframes line-up  { from { transform: translateY(105%); } }
@keyframes media-in { from { opacity: 0; transform: translateY(22px) scale(0.985); } }

/* ─── 17. Mise en page selon la taille ─────────────────────────────── */

/* La séquence pilotée au scroll est une expérience d'ORDINATEUR : elle
   épingle une section pendant trois hauteurs d'écran, ce qui sur
   téléphone confisque le défilement. En dessous de 1024 px, les quatre
   étapes redeviennent une liste et l'image est fixe. */
@media (min-width: 1024px) {
  /* Le hero occupe exactement un écran : contenu centré, repère de
     défilement calé en bas. Au-delà de 900 px de haut, c'est l'air qui
     grandit, pas le contenu — et le repère reste au pli. Le téléphone
     est ramené à 430 px pour que l'ensemble tienne dans 900 px, la
     hauteur d'écran la plus courante sur un portable. */
  .hero {
    /* 100svh MOINS la barre de navigation (79 px à sa hauteur de repos) :
       elle est dans le flux au-dessus du hero, et sans cette soustraction
       le bas du hero — le repère compris — passait sous le pli. */
    min-height: calc(100svh - 80px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-top: 48px;
    padding-bottom: 64px;
  }
  .hero__phone { max-width: 420px; }
  .hero__cue { display: inline-flex; bottom: 22px; }
  .story.is-sequenced { min-height: 340vh; }
  .story.is-sequenced .story__stage {
    position: sticky;
    top: 0;
    height: 100vh;
    display: grid;
    align-content: center;
    /* La barre de navigation reste collée en haut : sans cette réserve,
       la première étape passerait dessous. */
    padding-block: 76px 24px;
  }
  .story__grid {
    grid-template-columns: 1fr 0.92fr;
    gap: clamp(32px, 4vw, 64px);
  }
  .story__visual { max-width: 540px; margin-inline: 0 auto; }
  /* L'étape en cours se distingue par la COULEUR de son texte, un filet
     doré et un fond à peine posé — pas par l'opacité. Une étape mise à
     32 % d'opacité descend à 3,2:1 de contraste, sous le seuil AA : le
     texte en retrait doit rester lisible, c'est encore du contenu. */
  .story.is-sequenced .step {
    transition: background-color 0.5s var(--ease-out);
  }
  .story.is-sequenced .step h3,
  .story.is-sequenced .step p {
    color: var(--slate-lift);               /* 7,8:1 sur le marine profond */
    transition: color 0.5s var(--ease-out);
  }
  .story.is-sequenced .step::before { transition: background-color 0.5s var(--ease-out); }
  .story.is-sequenced .step.is-active { background: rgba(217, 184, 106, 0.05); }
  .story.is-sequenced .step.is-active h3 { color: var(--mist); }
  .story.is-sequenced .step.is-active p { color: var(--navy-mist); }
  .story.is-sequenced .step.is-active::before { background: var(--gold); }
}

/* Le hero repasse sur une colonne plus tôt que le reste : à deux
   colonnes sous 1100 px, le téléphone devient une vignette et le titre
   se remet à passer à la ligne. */
@media (max-width: 1100px) {
  .hero__grid { grid-template-columns: 1fr; }
  .hero__phone { max-width: 440px; margin-top: var(--sp-lg); }
}

@media (max-width: 1023px) {
  .mission__card, .security__card { grid-template-columns: 1fr; }

  /* ─ Le récit sur téléphone : quatre cartes qu'on fait glisser ─
     Une liste verticale à côté d'une seule image fixe ne montrait qu'un
     écran sur quatre. Ici chaque étape porte le sien. Même balisage que
     sur ordinateur (le <ol> et ses <li>), seule la mise en page change :
     défilement horizontal natif, `scroll-snap` pour que chaque carte se
     cale, voisines qui dépassent pour dire qu'on peut glisser. Aucun
     JavaScript — c'est le geste natif d'iOS, et il marche sans script. */
  .story__visual-col { display: none; }
  .story__note-phone { display: block; }
  .story__grid { display: block; }
  .story__steps {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    margin-inline: calc(-1 * var(--gutter));
    padding: 4px var(--gutter) 14px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .story__steps::-webkit-scrollbar { display: none; }
  .step {
    flex: 0 0 min(76vw, 340px);
    scroll-snap-align: start;
    padding: 0 0 18px;
    border: 1px solid var(--line);
    border-radius: 18px;
    background: linear-gradient(180deg, var(--navy-raised), rgba(15, 46, 83, 0.55));
    overflow: hidden;
  }
  .step::before { display: none; }
  .step__img {
    display: block;
    width: 100%;
    height: auto;             /* voir la note sur .hero__video */
    aspect-ratio: 5 / 6;
    object-fit: cover;
    background: var(--navy-deep);
    /* mêmes bords fondus que la vidéo du hero, même raison */
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent),
                        linear-gradient(180deg, #000 80%, transparent);
    -webkit-mask-composite: source-in;
    mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent),
                linear-gradient(180deg, #000 80%, transparent);
    mask-composite: intersect;
  }
  .step__head { padding: 16px 18px 0; }
  .step h3 { padding-inline: 18px; }
  .step p { padding-inline: 18px; }

  /* Sur téléphone, la page fait plus de 8 000 px : calculer la mise en
     page et peindre la totalité au chargement coûte cher sur un appareil
     modeste. `content-visibility: auto` dit au navigateur de ne faire ce
     travail qu'à l'approche de chaque section.
     `contain-intrinsic-size: auto …` lui donne une hauteur présumée en
     attendant — puis il retient la vraie : sans elle, la barre de
     défilement sauterait à chaque section rendue.
     Réservé au téléphone À DESSEIN : sur ordinateur, ScrollTrigger
     mesure la page pour caler la séquence d'images, et une section dont
     la hauteur est encore présumée lui donnerait une mesure fausse.

     Et SEULEMENT sur les sections sans lien. Dans un sous-arbre dont le
     rendu est sauté, Chrome ne calcule pas les styles, et un outil qui
     les interroge quand même lit les valeurs par défaut du navigateur :
     un contrôle d'accessibilité voyait les liens du pied de page en
     bleu #0000EE sur marine (1,74:1) et signalait un défaut de
     contraste qui n'existe pas à l'écran. L'affichage est juste, la
     mesure ne l'est pas — et une alerte d'accessibilité qui se déclenche
     au hasard est pire qu'un gain de quelques millisecondes. Le pied de
     page et l'appel final restent donc rendus normalement. */
  .features,
  .approach,
  .quote,
  .security {
    content-visibility: auto;
    contain-intrinsic-size: auto 760px;
  }
}

@media (max-width: 760px) {
  .nav__links { display: none; }
  .nav__mobile { display: inline-flex; gap: 12px; }
  .nav__login { margin-left: 0; white-space: nowrap; font-size: 0.8125rem; }
  /* Logo, « Connexion » et « Créer un compte » doivent tenir sur UNE
     ligne jusqu'à 360 px de large : gouttière réduite à 16 px, logo à
     28 px, bouton resserré — mesuré, il reste quelques pixels. */
  .nav__bar { --gutter: 16px; }
  .nav__logo, .nav.is-scrolled .nav__logo { height: 28px; }
  .nav__mobile .btn-sm { padding: 9px 13px; font-size: 0.8125rem; white-space: nowrap; }
  .feature .badge { position: static; display: inline-flex; margin-bottom: 14px; }
  .hero__sep { display: none; }
  .hero__stats { gap: var(--sp-md) var(--sp-lg); }
  .quote p { font-size: 1.25rem; }
}

/* ─── 18. Mouvement réduit ─────────────────────────────────────────── */

/* Ce n'est pas un mode dégradé : la page reste complète, seuls les
   déplacements disparaissent. landing.js fait sa part (pas de Lenis, pas
   de séquence, pas de ScrollTrigger, vidéo en pause sur son image fixe) ;
   ici on neutralise tout ce qui bouge en CSS. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.12s !important;
  }
  .story.is-sequenced { min-height: 0; }
  .story.is-sequenced .story__stage { position: static; height: auto; }
}
