/* TeraDeep Solutions — superposition HUD 2D
   V3 « Deep Sapphire » : retour au fond nuit — le verre en transmission
   échantillonne ce qui est derrière lui ; sur bleu nuit il sature, sur
   ardoise claire il se délave (voir src/config.ts, bloc PALETTE).

   Contraintes du brief Module 5 :
     canvas    : position fixed, inset 0, z-index 1, pointer-events none
     sections  : min-height 100vh, z-index 10
     interactifs : pointer-events auto

   ── Règle de contraste appliquée partout ──────────────────────────────────
   Aucun texte en gris sombre sur fond nuit. Les titres passent en #E8EFFA
   (blanc bleuté) et le courant en #B6C4D9 / #8FA1BA (slate 300 / 400).
   Même discipline qu'en V2, inversée : chaque paire encre/fond est vérifiée
   AA (4,5:1) par `scripts/verify.mjs` sur tous les noeuds de texte.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  color-scheme: light;

  /* Fonds — Thème clair médical/naturel harmonisé avec mind-library.html */
  --bg: #f1f6f1;          /* vert d'eau pâle médical — même valeur que PALETTE.base */
  --bg-veil: #e3efe7;     /* voile sauge doux */
  --bg-deep: #e8f0ea;     /* nuance d'encre douce */

  /* Encres — trois niveaux, contraste AA vérifié */
  --ink: #0f2a21;         /* vert forêt très sombre — titres */
  --ink-dim: #2f4a3e;     /* vert sauge profond — texte courant, AA > 7:1 */
  --ink-faint: #587165;   /* vert sauge moyen — secondaire, AA > 4.5:1 */

  /* Accents */
  --accent: #0d6b4f;      /* émeraude — accent principal */
  --accent-ink: #0a5a43;  /* émeraude assombri pour texte */
  --royal: #0d6b4f;       /* focus, actif */
  --royal-ink: #0a3a2d;   /* vert forêt */
  --forest: #0a3a2d;
  --forest-2: #0f5a45;
  --gold: #e8b33d;
  --gold-2: #f6d98a;
  --gold-ink: #3a2a05;
  --ivory: #f3ead2;

  /* Surfaces & Cartes */
  --line: #cfe0d5;
  --line-soft: #e1ece5;
  --panel: rgba(255, 255, 255, 0.90);
  --panel-solid: #ffffff;
  --shadow-panel: 0 16px 36px -10px rgba(10, 58, 45, 0.08);
  --shadow-lift: 0 24px 48px -15px rgba(10, 58, 45, 0.14);

  --font-display: "Bricolage Grotesque", "Space Grotesk", system-ui, -apple-system, sans-serif;
  --font-sans: "Manrope", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

* { box-sizing: border-box; }

html { scroll-behavior: auto; }

/* Pendant l'intro, le défilement est figé : la séquence est une ouverture,
   pas un document à parcourir. */
html.intro-open, html.intro-open body { overflow: hidden; }

body {
  margin: 0;
  background-color: var(--bg);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150' viewBox='0 0 150 150'%3E%3Cg fill='none' stroke='%2388bda4' stroke-width='1' stroke-linecap='round' stroke-opacity='0.45'%3E%3Cpath d='M0 75h42l15-15h32'/%3E%3Cpath d='M150 32h-38l-13 13H64'/%3E%3Cpath d='M75 150v-36l17-17'/%3E%3Cpath d='M20 0v26l12 12'/%3E%3C/g%3E%3Cg fill='%2388bda4' fill-opacity='0.45'%3E%3Ccircle cx='57' cy='60' r='2.8'/%3E%3Ccircle cx='89' cy='60' r='2.8'/%3E%3Ccircle cx='64' cy='45' r='2.8'/%3E%3Ccircle cx='92' cy='97' r='2.8'/%3E%3Ccircle cx='32' cy='38' r='2.8'/%3E%3C/g%3E%3C/svg%3E"),
    radial-gradient(110% 78% at 88% 24%, rgba(13, 107, 79, 0.07) 0%, transparent 58%),
    radial-gradient(105% 72% at 10% 82%, var(--bg-deep) 0%, transparent 55%);
  background-size: 150px 150px, auto, auto;
  background-repeat: repeat, no-repeat, no-repeat;
  color: var(--ink-dim);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Le défilement horizontal est déjà bridé sur `body` ; on le bride aussi sur
   la racine, sinon un élément large (un `nowrap` oublié) rétablit une barre
   de défilement latérale sur mobile. */
html { overflow-x: hidden; }

/* Message affiché uniquement si le JavaScript ne tourne pas. */
.noscript {
  position: relative;
  z-index: 40;
  margin: 0;
  padding: 14px clamp(16px, 5vw, 48px);
  background: rgba(250, 204, 21, 0.14);
  border-bottom: 1px solid rgba(250, 204, 21, 0.4);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.5;
  text-align: center;
}

.mono { font-family: var(--font-mono); font-variant-ligatures: none; }

/* Focus visible et cohérent partout : c'est le bleu royal, l'accent réservé
   aux éléments interactifs. Sur fond nuit, un liseré interne clair en plus
   garantit que le focus reste visible même sur un CTA au fond saturé. */
:focus-visible {
  outline: 2px solid var(--royal);
  outline-offset: 3px;
  border-radius: 6px;
}

/* Canvas : immuable, jamais cliquable */
#gl {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
  display: block;
}

/* ── Sélection de texte ────────────────────────────────────────────────────
   `.stage` et `.foot` étaient en `pointer-events: none` avec seulement 5
   exceptions `.interactive` : le H1, le chapô, les paragraphes et l'adresse
   e-mail n'étaient NI survolables NI sélectionnables à la souris (mesuré :
   `elementFromPoint` sur le H1 renvoyait `body`). C'est inutile : le canvas
   3D est déjà protégé par `#gl { pointer-events: none }` ci-dessus. On
   rétablit donc la sélection partout, et `.interactive` ne sert plus qu'à
   marquer sémantiquement les zones cliquables. */
.stage { position: relative; z-index: 10; }
.interactive { pointer-events: auto; }

/* Le texte reste sélectionnable même sur les blocs à `user-select` hérité. */
h1, h2, h3, p, li, .lede, .body, .foot__legal, .foot__mail, address {
  user-select: text;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

/* Navigation */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  /* `env(safe-area-inset-*)` : encoche / Dynamic Island en haut, barre
     gestuelle en bas. Sans `viewport-fit=cover` (posé dans index.html) ces
     valeurs valent 0, d'où le `max()` qui garde la valeur nominale. */
  padding:
    max(18px, env(safe-area-inset-top))
    max(clamp(20px, 4vw, 56px), env(safe-area-inset-right))
    18px
    max(clamp(20px, 4vw, 56px), env(safe-area-inset-left));
  background: linear-gradient(to bottom, rgba(7, 15, 28, 0.88) 0%, rgba(7, 15, 28, 0) 100%);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

/* Bouton « Sections » : masqué en desktop, visible uniquement quand les liens
   sont masqués (voir le bloc responsive). Il remplace l'ancien
   `display: none` nu qui rendait 4 sections inatteignables sur téléphone. */
.nav__toggle {
  display: none;
  align-items: center;
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.nav__toggle[aria-expanded="true"] { border-color: var(--royal); color: var(--royal-ink); }

.brand { display: flex; align-items: center; gap: 11px; }
/* Le monogramme est un lockup large (ratio 945/678) : on le dimensionne
   par la HAUTEUR, sinon `width` seul l'étirerait. */
.brand__mark { padding: 5px; border-radius: 9px; line-height: 0; }
.brand__mark img { height: 30px; width: auto; }
.brand__name { font-size: 15px; font-weight: 500; color: var(--ink-dim); }
.brand__name b { font-weight: 700; color: var(--ink); }

.nav__links { display: flex; gap: 4px; }
.nav__links a {
  position: relative;
  padding: 7px 13px;
  font-size: 13.5px;
  color: var(--ink-faint);
  border-radius: 8px;
  transition: color 0.2s ease, background 0.2s ease;
}
.nav__links a:hover { color: var(--ink); background: rgba(148, 174, 209, 0.14); }
.nav__links a.is-active { color: var(--royal-ink); font-weight: 500; }
.nav__links a.is-active::after {
  content: "";
  position: absolute;
  left: 13px; right: 13px; bottom: 1px;
  height: 2px;
  border-radius: 2px;
  background: var(--royal);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  transition: transform 0.18s ease, background 0.2s ease, border-color 0.2s ease,
              box-shadow 0.2s ease;
}
.btn:hover { transform: translateY(-1px); }
/* Dégradé royal -> cyan (V3) : le midpoint du dégradé garde un contraste
   mesuré > 5:1 avec le blanc — vérifié par scripts/verify.mjs. */
.btn--solid {
  background: linear-gradient(135deg, var(--accent) 0%, var(--forest) 100%);
  color: #ffffff;
  box-shadow: 0 10px 24px -6px rgba(10, 58, 45, 0.35);
}
.btn--solid:hover {
  box-shadow: 0 14px 28px -4px rgba(10, 58, 45, 0.45);
  transform: translateY(-1px);
}
.btn--lg { padding: 15px 28px; font-size: 15px; }

/* ── État « canal non encore ouvert » ─────────────────────────────────────
   Les liens de contact sans `href` (WhatsApp / e-mail pas encore construits)
   sont marqués `aria-disabled` par `applyContactLinks()`. Ils doivent se lire
   comme « bientôt », pas comme un bouton actif qui ne répond pas. */
.btn[aria-disabled="true"],
.foot__mail[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.72;
  box-shadow: none;
}
.btn[aria-disabled="true"]:hover,
.foot__mail[aria-disabled="true"]:hover { transform: none; }
.foot__contact-state {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--ink-faint);
}
.foot__contact-state[hidden] { display: none; }
/* Sections */
.phase {
  position: relative;
  min-height: 100vh;
  /* `100dvh` corrige le saut de mise en page quand la barre d'adresse
     mobile se replie : `vh` désigne la PLUS GRANDE hauteur possible, donc la
     page est trop haute tant que la barre est visible (iOS Safari surtout).
     Déclaré APRÈS `100vh` : les navigateurs sans `dvh` gardent le repli.
     Les bornes de phase restent justes : elles sont MESURÉES sur le DOM par
     `src/motion/scroll.ts`, jamais déduites de ces valeurs. */
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding: clamp(96px, 12vh, 150px) 0;
}

/* Hauteurs calées pour la direction C (5 phases) : les bornes mesurées
   tombent sur ≈ 0.20 / 0.38 / 0.56 / 0.73 / 1.00.
   Les hauteurs réelles sont celles des règles ci-dessous (100 / 125 / 125 /
   125 / 175 vh + le pied de page) ; toute modification de ces valeurs doit
   être suivie d'un `node scripts/verify.mjs`, qui mesure les bornes réelles
   et échoue si elles s'écartent des cibles.
   (L'ancien commentaire annonçait « 750vh » depuis hud.css et « 730vh »
   depuis index.html : deux totaux contradictoires, aucun n'étant la source.
   La source est ici, et nulle part ailleurs.)

   ⚠ Ces sélecteurs sont indexés par ID : ils doivent suivre tout
   renommage de section (#contenus / #appareils / #recherche / #rapidite).
   Un ID divergent ne casse rien visiblement — la section retombe sur le
   `min-height: 100vh` générique — mais décale les bornes de phase de
   plusieurs pourcents sans lever la moindre erreur. */
.phase--hero { min-height: 100vh; min-height: 100dvh; }
#contenus   { min-height: 125vh; min-height: 125dvh; }
#appareils  { min-height: 125vh; min-height: 125dvh; }
#recherche  { min-height: 125vh; min-height: 125dvh; }
#rapidite   { min-height: 175vh; min-height: 175dvh; }

/* ── Phase 4 : les trois gestes de la recherche (direction C) ──────────
   Même grammaire que .pillars : cartes nuit, filet, encres AA. L'écran 3D
   est la démonstration ; ces cartes racontent le geste, elles ne le
   simulent pas (aucun faux champ de saisie). */
.holo-steps {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  margin: 0 0 30px;
}
.holo-step {
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: var(--shadow-panel);
}
.holo-step__idx {
  display: block;
  margin: 0 0 8px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--accent-ink);
}
.holo-step p { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-faint); }
.holo-step b { color: var(--ink); font-weight: 600; }

/* Légendes de la fenêtre holo : réutilisent .scan-note, mais posées DANS
   le flux de la section (pas épinglées au bord droit comme les
   annotations du scan). La classe is-holo est posée par main.ts quand
   drive.holo traverse sa fenêtre — un changement de classe, pas un
   style par frame. */
.holo-notes {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  opacity: 0.55;
  transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.holo-notes.is-holo { opacity: 1; }
.holo-notes .scan-note {
  border-right: 1px solid rgba(0, 242, 254, 0.28);
  border-radius: 8px;
}
@media (prefers-reduced-motion: reduce) {
  .holo-notes { transition: none; }
}

.wrap {
  width: min(1180px, calc(100% - clamp(32px, 8vw, 112px)));
  margin: 0 auto;
}

/* ── Réservation de la colonne 3D ──────────────────────────────────────────
 *
 * Le livre occupe la colonne DROITE, à partir de 56 % de la largeur. Sans
 * cette réservation, `.wrap` s'étendait sur les 1180 px et ses titres
 * passaient sous le verre — mesuré : le H1 du hero occupe x=38..921 alors que
 * le livre commence à 649, soit 272 px de recouvrement.
 *
 * On réserve donc la moitié gauche DÈS QUE LES DEUX COLONNES coexistent.
 * Le critère est le rapport d'aspect, et non une largeur en pixels : c'est
 * EXACTEMENT la condition que le code 3D utilise pour décaler le livre à
 * droite (`w / h >= 1.25`). Les deux doivent tomber d'accord, sinon le
 * texte est réservé sur un écran où le livre est centré — ou l'inverse, et
 * le recouvrement revient sans qu'on le voie.
 */
@media (min-aspect-ratio: 5 / 4) {
  .wrap {
    /* 52 % de la largeur : le texte s'arrête net avant la colonne du livre. */
    width: min(1180px, 52vw);
    margin-left: clamp(32px, 6vw, 96px);
    margin-right: auto;
  }
}

/* ── Le logo dans le site ──────────────────────────────────────────────
   Quatre emplacements, deux traitements.

   `.plaque` : le fond du logo original n'est PAS une couleur plate — c'est
   un panneau sombre dessiné (grille technique + vignette). `colorkey` ne peut
   pas le supprimer sans ronger la lueur. Résultat sans traitement : sous
   ~200 px, le panneau devient un rectangle sombre à bords durs qui trahit le
   fond clair.

   On pose donc les usages SITE sur une plaque de la couleur EXACTE du fond
   baked (#020412, mesurée dans les coins de `logo/logo.jpg`). Image et
   plaque partagent cette couleur : la couture est impossible. L'intro, en
   revanche, garde sa version ALPHA à 700 px, où le panneau se lit comme une
   trame technique plutôt que comme un rectangle.

   La vraie correction serait un logo version claire dessiné par la marque ;
   elle n'existe pas dans les sources fournies. */
.plaque {
  display: inline-flex;
  background: #020412;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 12px 28px -14px rgba(15, 23, 42, 0.5);
}
.plaque img { display: block; }

.hero__seal {
  margin: 0 0 26px;
  line-height: 0;
}
.hero__seal .plaque { padding: 9px; border-radius: 14px; }
.hero__seal img {
  height: clamp(112px, 15vh, 168px);
  width: auto;
}

.cta__mark {
  display: block;
  margin: 0 0 14px;
  line-height: 0;
}
.cta__mark .plaque { padding: 7px; border-radius: 10px; }
.cta__mark img { height: 40px; width: auto; }

.foot__logo {
  display: block;
  margin: 0 0 22px;
  line-height: 0;
}
.foot__logo .plaque { padding: 9px; border-radius: 14px; }
.foot__logo img { height: clamp(120px, 16vh, 176px); width: auto; }

@media (max-width: 640px) {
  .hero__seal img { height: 104px; }
  .foot__logo img { height: 112px; }
  .cta__mark img { height: 32px; }
}

/* Typographie */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 22px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.eyebrow .num {
  display: inline-grid;
  place-items: center;
  min-width: 30px;
  height: 22px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: rgba(148, 174, 209, 0.12);
  color: var(--royal-ink);
  letter-spacing: 0.06em;
}
.dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px rgba(0, 242, 254, 0.14);
}

.display {
  margin: 0;
  font-size: clamp(2.1rem, 4.9vw, 3.9rem);
  line-height: 1.06;
  font-weight: 700;
  letter-spacing: -0.032em;
  color: var(--ink);
}
.display em {
  font-style: normal;
  background: linear-gradient(100deg, var(--forest), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.headline {
  margin: 0 0 22px;
  max-width: 22ch;
  font-size: clamp(1.8rem, 3.8vw, 2.8rem);
  line-height: 1.14;
  font-weight: 600;
  letter-spacing: -0.022em;
  color: var(--ink);
}

.lede {
  margin: 26px 0 0;
  max-width: 60ch;
  font-size: clamp(1.02rem, 1.6vw, 1.18rem);
  line-height: 1.7;
  color: var(--ink-dim);
}
.body { margin: 0 0 40px; max-width: 62ch; color: var(--ink-dim); }
.body--tight { margin-bottom: 22px; }

/* Piliers (hero) — les libellés sont longs : on passe de pastilles en ligne
   à des cartes, sinon le texte ne tient plus sur une seule ligne. */
.pillars {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  margin: 40px 0 0;
  padding: 0;
  list-style: none;
}
.pillars li {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: var(--shadow-panel);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-faint);
}
.pillars li b { color: var(--ink); font-weight: 600; }
.pillars .idx {
  flex: none;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  color: var(--accent-ink);
  letter-spacing: 0.08em;
}

.scrollcue {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 64px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.scrollcue__line {
  display: block;
  width: 56px;
  height: 1px;
  background: linear-gradient(to right, var(--accent), transparent);
}
/* Cartes — glassmorphism nuit */
.cards {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
}
.card {
  padding: 30px 28px 32px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--panel);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: var(--shadow-panel);
  transition: border-color 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease;
}
.card:hover {
  border-color: rgba(13, 107, 79, 0.4);
  transform: translateY(-3px);
  box-shadow: var(--shadow-lift);
}
.card__kicker {
  margin: 0 0 14px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--royal-ink);
}
.card h3 {
  margin: 0 0 12px;
  font-size: 1.45rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.card p { margin: 0 0 20px; font-size: 14.5px; color: var(--ink-faint); }

.ticks { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.ticks li {
  position: relative;
  padding-left: 22px;
  font-size: 13.5px;
  color: var(--ink-faint);
}
.ticks li::before {
  content: "";
  position: absolute;
  left: 0; top: 8px;
  width: 9px; height: 9px;
  border: 1.5px solid var(--accent);
  border-radius: 3px;
  transform: rotate(45deg);
}

/* Dual-core */
.duo {
  display: grid;
  gap: clamp(28px, 5vw, 56px);
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
}
.duo__rule {
  width: 1px;
  align-self: stretch;
  background: linear-gradient(to bottom, transparent, var(--line) 25%, var(--line) 75%, transparent);
}
.duo__tag {
  margin: 0 0 14px;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
.duo__col h3 {
  margin: 0 0 16px;
  font-size: 1.6rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* Métriques */
.metrics {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin: 0 0 48px;
}
.metric {
  padding: 22px 20px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: var(--shadow-panel);
}
.metric dt {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.metric dd {
  margin: 10px 0 0;
  font-size: clamp(2rem, 3.6vw, 2.9rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.metric dd span {
  background: linear-gradient(140deg, var(--ink), var(--royal));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* CTA — la dalle de verre dépoli sert de toile de fond */
.cta {
  display: grid;
  gap: 34px;
  grid-template-columns: minmax(0, 1.5fr) auto;
  align-items: center;
  padding: clamp(30px, 4vw, 46px);
  border: 1.5px solid rgba(13, 107, 79, 0.22);
  border-radius: 24px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(227, 239, 231, 0.85));
  -webkit-backdrop-filter: blur(22px);
  backdrop-filter: blur(22px);
  box-shadow: var(--shadow-lift);
}
.cta__kicker {
  margin: 0 0 12px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--royal-ink);
}
.cta h3 {
  margin: 0 0 12px;
  font-size: clamp(1.4rem, 2.4vw, 1.9rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.cta p { margin: 0; font-size: 14.5px; color: var(--ink-faint); }
.cta__action { display: grid; gap: 10px; justify-items: center; }
.cta__note { font-size: 10.5px !important; letter-spacing: 0.1em; color: var(--ink-faint) !important; }
/* Pied de page */
.foot {
  position: relative;
  z-index: 10;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding: 110px 0 max(70px, env(safe-area-inset-bottom));
  border-top: 1px solid rgba(243, 234, 210, 0.15);
  background: linear-gradient(180deg, #0a3a2d 0%, #06231b 100%);
  color: var(--ivory);
}
.foot .foot__line { color: #ffffff; }
.foot .foot__line em {
  background: linear-gradient(100deg, var(--gold), var(--gold-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.foot .foot__mark { color: var(--gold); }
.foot .foot__intro { color: #cfe0d5; }
.foot .foot__mail { color: var(--gold-2); }
.foot .foot__label { color: var(--gold-2); }
.foot .foot__grid p:not(.foot__label) { color: #cfe0d5; }
.foot .foot__legal { color: #8da99c; }
.foot .foot__legal-links a { color: var(--ivory); }
.foot__mark {
  margin: 0 0 22px;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
.foot__line {
  margin: 0 0 26px;
  max-width: 30ch;
  font-size: clamp(1.7rem, 3.6vw, 2.7rem);
  line-height: 1.14;
  font-weight: 600;
  letter-spacing: -0.028em;
  color: var(--ink);
}
.foot__line em {
  font-style: normal;
  background: linear-gradient(100deg, var(--forest), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.foot__intro {
  margin: 0 0 30px;
  max-width: 62ch;
  font-size: clamp(1rem, 1.4vw, 1.12rem);
  line-height: 1.7;
  color: var(--ink-dim);
}
.foot__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px 24px;
  margin: 0 0 clamp(40px, 8vh, 80px);
}
/* Cible tactile : le lien e-mail mesurait 195×21 px, sous le minimum
   confortable de 40 px de haut sur mobile. On épaissit la zone cliquable
   sans changer la taille du texte. */
.foot__mail {
  font-size: 13px;
  color: var(--royal-ink);
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 4px 0;
}
.foot__mail:hover { text-decoration: underline; text-underline-offset: 3px; }
.foot__grid {
  display: grid;
  gap: 30px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  padding-top: 34px;
  border-top: 1px solid var(--line);
}
.foot__label {
  margin: 0 0 10px;
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.foot__grid p:not(.foot__label) { margin: 0; font-size: 14px; color: var(--ink-dim); }
.foot__legal {
  margin: 44px 0 0;
  max-width: 68ch;
  font-size: 11px;
  line-height: 1.7;
  color: var(--ink-faint);
}
/* Liens légaux : obligatoires (LCEN art. 6-III-1) et visibles sans être
   criards. Cibles tactiles de 40 px de haut sur mobile. */
.foot__legal-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin: 18px 0 0;
}
.foot__legal-links a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--royal-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(147, 197, 253, 0.4);
}
.foot__legal-links a:hover { text-decoration-color: var(--royal-ink); }
/* ── Annotations du balayage (Module 8) ───────────────────────────────
   Trois filets mono à droite, visibles PENDANT la phase 3 seulement. La
   classe `is-on` est posée par main.ts quand `drive.scan` traverse la
   fenêtre du balayage — aucun timer, aucune boucle : un changement de
   classe sur transition, pas une écriture de style par frame. */
.scan-notes {
  position: fixed;
  right: clamp(20px, 4.5vw, 72px);
  bottom: 24vh;
  z-index: 12;
  display: grid;
  gap: 14px;
  justify-items: end;
  pointer-events: none;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.scan-notes.is-on { opacity: 1; transform: none; }
.scan-note {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px 7px 14px;
  border: 1px solid rgba(13, 107, 79, 0.3);
  border-right: none;
  border-radius: 8px 0 0 8px;
  background: rgba(255, 255, 255, 0.94);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--accent-ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  box-shadow: 0 8px 20px rgba(10, 58, 45, 0.08);
}
.scan-note::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px rgba(13, 107, 79, 0.6);
}
@media (prefers-reduced-motion: reduce) {
  .scan-notes { transition: none; }
}
/* Sous 900px, la colonne du livre est étroite : les annotations passent
   sous la forme d'une barre discrète en bas, jamais par-dessus le texte. */
@media (max-width: 900px) {
  .scan-notes { right: 16px; bottom: 14vh; gap: 10px; }
  .scan-note { font-size: 10px; padding: 6px 10px 6px 12px; }
}

/* Révélation au scroll — amincissement progressif assumé.
   Le contenu est VISIBLE par défaut : c'est le JS qui pose `is-pending`
   avant d'observer. Si le script ne s'exécute pas (CORS, exception,
   WebGL indisponible), la page reste lisible au lieu d'être blanche. */
.reveal { opacity: 1; transform: none; }
.reveal.is-pending {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s cubic-bezier(.22,1,.36,1), transform .7s cubic-bezier(.22,1,.36,1);
}
.reveal.is-pending.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.is-pending { opacity: 1; transform: none; transition: none; }
  .btn:hover { transform: none; }
  /* Transitions décoratives : sans risque de mouvement, mais on les coupe
     pour respecter la préférence jusqu'au bout. */
  .card { transition: none; }
  .card:hover { transform: none; }
  .nav__links a, .btn, .btn--solid { transition: none; }
}

/* Le verre de la nav s'opacifie APRÈS le hero (classe posée par hud.ts) :
   au premier écran on veut voir la 3D au travers, ensuite la lisibilité
   prime. Transition coupée si la préférence motion est « reduce ». */
.nav.is-scrolled {
  background: linear-gradient(to bottom, rgba(7, 15, 28, 0.97) 0%, rgba(7, 15, 28, 0.78) 100%);
  border-bottom: 1px solid var(--line);
}

/* ══ MOBILE / TABLETTE ════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .nav {
    gap: 12px;
    /* La nav passe sur deux rangées si besoin ; le CTA ne doit jamais
       comprimer la marque. */
    flex-wrap: wrap;
    padding-top: max(12px, env(safe-area-inset-top));
    padding-bottom: 12px;
  }
  .nav__toggle { display: inline-flex; }

  /* Les liens sont repliés par défaut et déroulés par le bouton. Sans JS,
     `hud.ts` n'a pas posé `hidden` : la barre reste donc visible et
     utilisable (dégradation correcte). */
  .nav__links {
    order: 3;
    flex-basis: 100%;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: center;
  }
  .nav__links[hidden] { display: none; }
  .nav__links a {
    /* Cible tactile confortable : 7 px de padding donnaient ~36 px de haut. */
    padding: 12px 16px;
    font-size: 13.5px;
  }
  .duo { grid-template-columns: 1fr; }
  .duo__rule { display: none; }
  .cta { grid-template-columns: 1fr; }
  .cta__action { justify-items: start; }
  .holo-steps { grid-template-columns: 1fr; }

  /* ── Composition en BANDES (portrait) — v2 « socle » ───────────────────
     DÉFAUT « perched top center » réglé définitivement : le livre ne vit
     PLUS dans une bande haute. Au hero il est EN GRAND, centré au centre
     optique (38 %, cf. main.ts) ; ensuite il POSE EN BAS d'écran (socle,
     dock=1) — comme un objet sur un rebord. Le texte des sections coule
     AU-DESSUS de lui : padding-bottom réserve la place du socle (~44vh :
     le livre 0,56 + sa marge de pose), le padding-top ne garde que la
     marge sous la nav fixe. */
  .phase {
    padding-top: 96px;
    padding-bottom: max(44vh, 360px);
  }
  /* Le HERO est le showcase : le livre y vit EN GRAND (dock=0) — son
     contenu (logo, eyebrow, titres) commence SOUS le modèle (~52vh). */
  .phase--hero {
    padding-top: max(52vh, 420px);
    align-items: flex-end;
    padding-bottom: 64px;
  }

  /* Les ancres de saut : le contenu atterrit au-dessus du socle. */
  #contenus, #appareils, #recherche, #rapidite {
    scroll-margin-top: 96px;
  }
  /* Le titre du hero ne doit pas dépasser l'écran : à 390 px il tient, mais
     la version 700 px d'un écran pliable non. */
  .display { font-size: clamp(1.75rem, 8.2vw, 2.6rem); }
  .headline { font-size: clamp(1.5rem, 7vw, 2.1rem); }
  .foot__line { font-size: clamp(1.45rem, 6.6vw, 2.1rem); }
}

/* ── TÉLÉPHONE EN PAYSAGE ────────────────────────────────────────────────
   DÉFAUT MESURÉ (844×390) : le hero appliquait `padding-top: max(52vh,420px)`
   — la règle portrait ci-dessus — soit 420 px de padding sur un viewport de
   390 px de haut. Résultat : H1 à y=638, entièrement SOUS le pli, premier
   écran vide.

   La cause est un désaccord, pas un oubli : la 3D bascule en composition à
   DEUX COLONNES dès que `largeur/hauteur >= 1.25` (src/main.ts, partagé
   avec `@media (min-aspect-ratio: 5/4)` qui réserve la moitié gauche). En
   paysage, le livre est donc en COLONNE À DROITE, pas dans un socle bas : les
   bandes portrait n'ont plus de sens.

   On annule donc les bandes sur le MÊME critère que la 3D, et on ne garde
   que la marge sous la nav. */
@media (max-width: 900px) and (min-aspect-ratio: 5 / 4) {
  .phase {
    padding-top: 96px;
    padding-bottom: 96px;
  }
  .phase--hero {
    padding-top: 96px;
    padding-bottom: 96px;
    align-items: center;
  }
  /* Le titre ne doit pas occuper toute la largeur : la colonne du livre
     commence à 56 %. */
  .display { font-size: clamp(1.6rem, 4.4vw, 2.3rem); }
}

/* ── Écrans BAS (peu importe l'orientation) ──────────────────────────────
   Filet de sécurité pour les viewports très courts (paysage de téléphone,
   fenêtre réduite) : aucun padding ne doit dépasser la hauteur visible. */
@media (max-height: 520px) {
  .phase { padding-top: 88px; padding-bottom: 88px; }
  .phase--hero { padding-top: 88px; padding-bottom: 88px; align-items: center; }
}

/* ── TÉLÉPHONE ÉTROIT ──────────────────────────────────────────────────── */
@media (max-width: 560px) {
  /* On garde une hauteur par section : un min-height auto comprimerait le
     défilement et les tranches de phase deviendraient saccadées. Les ratios
     changent mais restent exacts, car ils sont mesurés sur le DOM et pas
     codés en dur. */
  .phase, #contenus, #appareils, #recherche, #rapidite {
    min-height: 100vh;
    min-height: 100dvh;
  }
  /* Le padding-bottom du socle (44vh, bloc 900px) SURVIT : on ne retouche
     que les marges latérales — l'écraser remettrait le texte SUR le livre
     posé (défaut corrigé). */
  .phase { padding-left: 0; padding-right: 0; }
  .foot {
    min-height: 100vh;
    min-height: 100dvh;
    padding: 72px 0 max(48px, env(safe-area-inset-bottom));
  }
  .brand__name { display: none; }

  /* Le CTA du pied de page mesurait 376 px pour un conteneur de 358 px :
     `white-space: nowrap` le faisait toucher le bord droit de l'écran
     (mesuré : `right` = largeur du viewport, marge droite nulle alors que la
     marge gauche vaut 16 px). On autorise le retour à la ligne. */
  .foot__cta .btn,
  .cta .btn {
    white-space: normal;
    text-align: center;
    max-width: 100%;
  }
  .foot__cta { align-items: stretch; }

  /* Le CTA de la nav doit rester lisible une fois la marque réduite. */
  .nav > .btn { padding: 10px 15px; font-size: 12.5px; }

  /* Plancher de lisibilité : 11,5 px sur `.eyebrow` est en dessous du
     confortable sur un écran à forte densité. */
  .eyebrow { font-size: 12px; }
}

/* ── Écran très large et bas ────────────────────────────────────────────── */
@media (min-aspect-ratio: 16 / 10) and (max-width: 900px) {
  /* En paysage large, l'intro garde sa vidéo entière. */
  .scan-notes { bottom: 8vh; }
}


/* ── Hero Actions unifiés ── */
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 30px 0 20px;
}
.hero-btn-main {
  background: linear-gradient(135deg, var(--accent) 0%, var(--forest) 100%) !important;
  color: #ffffff !important;
  box-shadow: 0 10px 25px -5px rgba(10, 58, 45, 0.4) !important;
  font-weight: 800;
  padding: 14px 22px;
  font-size: 14.5px;
  border-radius: 9999px;
  text-decoration: none;
}
.hero-btn-sub {
  background: #ffffff !important;
  border: 1.5px solid var(--line) !important;
  color: var(--ink) !important;
  padding: 14px 22px;
  font-size: 14px;
  font-weight: 700;
  border-radius: 9999px;
  box-shadow: var(--shadow-panel) !important;
  text-decoration: none;
}
.hero-btn-sub:hover {
  border-color: var(--accent) !important;
  color: var(--accent) !important;
}

@media (max-width: 600px) {
  .hero-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .hero-btn-main, .hero-btn-sub {
    width: 100%;
    text-align: center;
    white-space: normal;
  }
}
