/* ============================================================
   Blue Spirit Aero — Design System & pages
   Palette / typo / composants conformes à BSA_New_Website.md
   ============================================================ */

/* ---------- Tokens ---------- */
:root {
  --color-primary: #1368BF;
  --color-accent-dark: #0B3866;
  --color-night: #05080F;
  /* quasi-noir, haut du dégradé global */
  --color-night-2: #0A1B33;
  --color-ink: #0E1116;
  /* texte sur fonds clairs */
  --color-light: #EDF1F5;
  /* sections partenaires / presse */
  --color-footer: #1B1F24;
  /* gris foncé footer */
  --color-grey: #9AA3AD;
  --text: #FFFFFF;
  --font: "Roboto Condensed", "Arial Narrow", sans-serif;
  --radius-pill: 999px;
  --radius-card: 6px;
  --header-h: 92px;
  /* logo full-name 160px de large ≈ 64px de haut (comme l'ancien site) */
  --pad-x: clamp(20px, 6vw, 96px);
  --section-gap: clamp(64px, 10vh, 140px);

  /* ----- Échelle typographique unique -----
     Proportions et valeurs reprises de l'ancien site (root 10px) :
     body 1.4rem=14, h1 2.8rem=28, h2≈2.4rem, .circle+p 2rem=20, .code 1.2rem=12.
     Une seule source de vérité → toutes les pages restent en harmonie. */
  --fs-body: 14px;
  /* texte courant   (anc. 1.4rem) */
  --fs-lead: 20px;
  /* chapô / intro   (anc. .circle+p 2rem) */
  --fs-h3: 18px;
  /* sous-titres     */
  --fs-h2: 24px;
  /* titres section  (anc. h2 ≈ 2.4rem) */
  --fs-h1: 28px;
  /* titres page     (anc. h1 2.8rem) */
  --fs-btn: 12px;
  /* boutons / liens (anc. .code 1.2rem) */
  --fs-nav: 13px;
  /* navigation      */
  --logo-header-w: 160px;
  /* largeur logo header (anc. 160px) */
  --logo-footer-h: 130px;
  /* hauteur logo footer (anc. 13rem) */
}

/* Très grands écrans : l'ancien site augmentait le root 10→12→14px (×1.2 puis ×1.4).
   On reproduit ce comportement sur toute l'échelle d'un coup. */
@media (min-width: 1600px) {
  :root {
    --fs-body: 17px;
    --fs-lead: 24px;
    --fs-h3: 22px;
    --fs-h2: 29px;
    --fs-h1: 34px;
    --fs-btn: 14px;
    --fs-nav: 15px;
    --header-h: 104px;
    --logo-header-w: 200px;
    --logo-footer-h: 156px;
  }
}

@media (min-width: 1800px) {
  :root {
    --fs-body: 20px;
    --fs-lead: 28px;
    --fs-h3: 25px;
    --fs-h2: 34px;
    --fs-h1: 39px;
    --fs-btn: 16px;
    --fs-nav: 16px;
    --header-h: 116px;
    --logo-header-w: 210px;
    --logo-footer-h: 182px;
  }
}

/* Mobile : espacement vertical des sections resserré et UNIFORME. --section-gap
   pilote le padding haut (= l'air au-dessus de chaque titre) et bas de TOUTES les
   sections → un seul réglage garde tous les « dessus de titre » proportionnés et
   identiques. (Desktop inchangé : 10vh ≈ 84–140px.) */
@media (max-width: 700px) {
  :root {
    --section-gap: clamp(40px, 6vh, 60px);
  }
}

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

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--text);
  background: linear-gradient(180deg, var(--color-night) 0%, var(--color-night-2) 45%, var(--color-accent-dark) 80%, var(--color-primary) 130%);
  background-attachment: fixed;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

p {
  margin: 0 0 1em;
}

h1,
h2,
h3,
h4 {
  margin: 0 0 .6em;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  line-height: 1.1;
  /* anc. h1 line-height:1 */
}

h1 {
  font-size: var(--fs-h1);
}

h2 {
  font-size: var(--fs-h2);
}

h3 {
  font-size: var(--fs-h3);
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.4;
}

/* chapô / intro (anc. .circle+p) */

.muted {
  color: var(--color-grey);
}

.rule {
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, .25);
  margin: 18px 0 22px;
}

.on-light .rule {
  border-top-color: rgba(14, 17, 22, .2);
}

section {
  padding: var(--section-gap) var(--pad-x);
}

/* Titre de section avec grand anneau décoratif derrière (repris de l'ancien site).
   Géométrie fidèle : anc. Ø100px / bordure 8px / décalage -50px,-35px sur un titre 28px
   → exprimée en em pour rester proportionnée à toute l'échelle typographique. */
.ring-title {
  position: relative;
  display: inline-block;
  isolation: isolate;
}

.ring-title::before {
  content: "";
  position: absolute;
  z-index: -1;
  /* l'anneau passe derrière le texte du titre */
  left: -1.8em;
  top: -1.25em;
  width: 3.5em;
  height: 3.5em;
  border: .28em solid rgba(255, 255, 255, .28);
  border-radius: 50%;
  pointer-events: none;
}

.on-light .ring-title::before {
  border-color: rgba(14, 17, 22, .16);
}

/* Breakpoints canoniques du site : 920 (large/tablette), 700 (mobile), 560 (petit mobile). */
/* Anneau plus compact sur mobile — évite tout débordement. */
@media (max-width: 700px) {
  .ring-title::before {
    left: -1.1em;
    top: -.8em;
    width: 2.2em;
    height: 2.2em;
    border-width: .2em;
  }
}

/* Très petits écrans : --pad-x tombe à ~20px ; on borne l'anneau en valeurs
   fixes pour qu'il ne soit jamais rogné par le bord gauche de l'écran. */
@media (max-width: 560px) {
  .ring-title::before {
    left: -14px;
    top: -10px;
    width: 38px;
    height: 38px;
    border-width: 3px;
  }
}

/* ---------- Boutons ---------- */
.btn {
  display: inline-block;
  padding: 13px 34px;
  border-radius: var(--radius-pill);
  font-family: var(--font);
  font-size: var(--fs-btn);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .25s, color .25s, border-color .25s, transform .15s;
}

.btn:active {
  transform: scale(.97);
}

.btn-outline {
  background: transparent;
  border: 1.5px solid #fff;
  color: #fff;
}

.btn-outline:hover {
  background: #fff;
  color: var(--color-night);
}

.btn-outline-dark {
  background: transparent;
  border: 1.5px solid var(--color-ink);
  color: var(--color-ink);
}

.btn-outline-dark:hover {
  background: var(--color-ink);
  color: #fff;
}

.btn-solid {
  background: var(--color-primary);
  border: 1.5px solid var(--color-primary);
  color: #fff;
}

.btn-solid:hover {
  background: var(--color-accent-dark);
  border-color: var(--color-accent-dark);
}

/* ---------- Lueur « spotlight » bleu électrique (CTA + 4S/6S) ----------
   Classe posée par main.js sur a.btn et [data-model]. Un anneau lumineux
   bleu électrique suit le curseur sur la bordure (+ halo diffus externe). */
.glow-btn {
  position: relative;
  isolation: isolate;
  /* contient les z-index négatifs de la lueur */
  --gx: 50%;
  /* position du curseur dans le bouton (px via JS) */
  --gy: 50%;
  --glow: .4;
  /* intensité au repos ; 1 au survol */
}

.glow-btn:hover,
.glow-btn:focus-visible {
  --glow: 1;
}

/* anneau lumineux sur la bordure */
.glow-btn::before {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  padding: 2px;
  /* épaisseur de l'anneau */
  background: radial-gradient(130px 130px at var(--gx) var(--gy),
      #38b6ff 0%, #1b8cff 28%, #2f6bff 48%, transparent 72%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  /* ne garde que la bordure */
  opacity: var(--glow);
  transition: opacity .3s;
  pointer-events: none;
  z-index: -1;
}

/* halo diffus rayonnant autour du bouton */
.glow-btn::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(90px 90px at var(--gx) var(--gy),
      rgba(38, 150, 255, .55), transparent 70%);
  filter: blur(11px);
  opacity: var(--glow);
  transition: opacity .3s;
  pointer-events: none;
  z-index: -2;
}

@media (prefers-reduced-motion: reduce) {

  .glow-btn::before,
  .glow-btn::after {
    transition: none;
  }
}

/* ============================================================
   Header
   ============================================================ */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 600;   /* au-dessus des overlays de contenu (carte : guard 400, panneau 500) →
                     le menu hamburger déroulant passe devant la Range Map en mobile.
                     Reste sous la lightbox (1000), qui doit couvrir tout l'écran. */
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-h);
  padding: 0 var(--pad-x);
  background: transparent;
  transition: background .35s, box-shadow .35s, transform .35s ease;
}

.site-header.scrolled,
body.header-solid .site-header {
  background: rgba(5, 8, 15, .92);
  box-shadow: 0 2px 18px rgba(0, 0, 0, .45);
}

/* Masquage au scroll vers le bas, réapparition au scroll vers le haut.
   Neutralisé quand le menu mobile est ouvert (body.nav-open) pour garder
   l'en-tête visible pendant la navigation. */
.site-header.nav-hidden {
  transform: translateY(-100%);
}

body.nav-open .site-header.nav-hidden {
  transform: none;
}

/* Logo header : pleine-largeur, aligné à gauche, calé sur la largeur de l'ancien site (160px). */
.brand img {
  width: var(--logo-header-w);
  height: auto;
}

@media (max-width: 920px) {
  .brand img {
    width: 132px;
  }
}

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2.2vw, 34px);
}

.site-nav a {
  position: relative;
  font-size: var(--fs-nav);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 6px 0;
  opacity: .85;
}

.site-nav a:hover {
  opacity: 1;
}

.site-nav a.active {
  opacity: 1;
}

.site-nav a.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: #fff;
}

.lang-switch {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  letter-spacing: .1em;
}

.lang-switch a {
  opacity: .55;
  font-weight: 700;
}

.lang-switch a.on,
.lang-switch a:hover {
  opacity: 1;
}

.lang-switch .sep {
  opacity: .4;
}

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: 0;
  padding: 10px;
  cursor: pointer;
}

.nav-toggle span {
  width: 24px;
  height: 2px;
  background: #fff;
  transition: transform .3s, opacity .3s;
}

@media (max-width: 920px) {
  .nav-toggle {
    display: flex;
  }

  .site-nav {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    padding: 18px var(--pad-x) 28px;
    background: rgba(5, 8, 15, .97);
    transform: translateY(-130%);
    transition: transform .35s;
  }

  body.nav-open .site-nav {
    transform: translateY(0);
  }

  body.nav-open .site-header {
    background: rgba(5, 8, 15, .97);
  }

  body.nav-open .nav-toggle span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }

  body.nav-open .nav-toggle span:nth-child(2) {
    opacity: 0;
  }

  body.nav-open .nav-toggle span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }

  /* cibles tactiles confortables (≥44px) dans le menu déplié */
  .site-nav a {
    font-size: 16px;
    padding: 12px 0;
  }

  .lang-switch {
    margin-top: 10px;
  }

  .lang-switch a {
    padding: 10px 4px;
  }
}

/* ============================================================
   Footer
   ============================================================ */
.site-footer {
  background: var(--color-footer);
  padding: 64px var(--pad-x) 28px;
  font-size: 15px;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.7fr 1fr 1.3fr;
  gap: 40px;
  align-items: start;
}

/* Colonne gauche : logo BSA collé à gauche du bloc « Nous contacter »,
   « Nous suivre » empilé dessous. */
.footer-contact {
  display: flex;
  align-items: center;
  gap: 26px;
}

.footer-contact .footer-logo {
  flex: none;
}

/* logo réduit car désormais en ligne avec le texte (spécificité > .site-footer .brand img) */
.site-footer .footer-contact .footer-logo img {
  height: clamp(84px, 8vw, 112px);
}

.footer-contact-body {
  min-width: 0;
}

/* Bouton « Envoyer un message » sous les coordonnées de contact.
   Petite pilule outline cohérente avec le footer sombre ; vire au bleu au survol. */
.footer-msg-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 16px;
  padding: 9px 20px;
  border: 1.5px solid rgba(255, 255, 255, .38);
  border-radius: var(--radius-pill);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background .25s, border-color .25s, color .25s;
}

.footer-msg-btn svg {
  width: 16px;
  height: 16px;
  flex: none;
}

/* Spécificité > « .site-footer a:hover { text-decoration: underline } » */
.site-footer .footer-msg-btn { text-decoration: none; }

.site-footer .footer-msg-btn:hover {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
  text-decoration: none;
}

.site-footer h4 {
  font-size: 14px;
  letter-spacing: .18em;
  margin-bottom: 1em;
  color: var(--color-grey);
}

.site-footer .brand img {
  height: var(--logo-footer-h);
  width: auto;
}

/* pictogramme BSA (logo-mark.svg) — anc. 13rem */
.site-footer address {
  font-style: normal;
  line-height: 1.7;
  opacity: .85;
}

.site-footer address strong {
  display: block;
  letter-spacing: .06em;
}

.site-footer a:hover {
  text-decoration: underline;
}

.social {
  display: flex;
  gap: 14px;
}

.social a {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: 50%;
  transition: background .25s, border-color .25s;
}

.social a:hover {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

.social svg {
  width: 17px;
  height: 17px;
  fill: #fff;
}

.legal-links {
  display: grid;
  gap: 8px;
  opacity: .85;
}

.newsletter {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 6px;
}

.newsletter input {
  flex: 1 1 200px;
  padding: 12px 18px;
  border-radius: var(--radius-pill);
  border: 1px solid rgba(255, 255, 255, .35);
  background: rgba(255, 255, 255, .06);
  color: #fff;
  font-family: var(--font);
  font-size: 15px;
}

/* Tactile : police ≥ 16px → pas de zoom auto iOS au focus du champ ; desktop inchangé. */
@media (hover: none) and (pointer: coarse) {
  .newsletter input {
    font-size: 16px;
  }
}

.newsletter input::placeholder {
  color: rgba(255, 255, 255, .5);
}

.newsletter button {
  white-space: nowrap;
}

.newsletter-msg {
  width: 100%;
  min-height: 1.4em;
  font-size: 14px;
  color: #8FC7FF;
  margin: 4px 0 0;
}

/* Anti-bot : champs leurres (honeypot) — hors écran, invisibles, hors flux.
   .hp-field = wrapper dans le formulaire de CV ; .hp-input = champ injecté par
   main.js dans les formulaires newsletter. Jamais affichés à l'utilisateur. */
.hp-field,
.newsletter .hp-input {
  position: absolute !important;
  left: -9999px !important;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.copyright {
  margin-top: 48px;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, .12);
  font-size: 13px;
  letter-spacing: .1em;
  opacity: .6;
  text-align: center;
}

/* Nom + slogan de marque et intro newsletter : uniquement pour le footer mobile,
   masqués ≥ 701px afin de laisser le footer desktop strictement inchangé. */
.footer-brand,
.news-intro { display: none; }

@media (max-width: 920px) {
  .footer-grid {
    grid-template-columns: 1fr 1fr;
  }
  .footer-contact {
    grid-column: 1 / -1; /* le bloc contact prend toute la largeur, légal + newsletter dessous */
  }
}

/* ---------- Footer mobile (≤700px) ----------
   Marque centrée en haut, puis 2 colonnes Contact | Suivez-nous, la newsletter,
   et enfin une barre du bas © + liens légaux. Le desktop reste inchangé. */
@media (max-width: 700px) {
  .site-footer {
    display: flex;
    flex-direction: column;
    padding-top: 40px;
    border-top: 1px solid rgba(255, 255, 255, .12);
  }
  /* La grille s'aplatit : ses 3 blocs deviennent des items du footer, réordonnables. */
  .footer-grid { display: contents; }
  .footer-contact { order: 1; }
  .footer-grid > div:nth-child(3) { order: 2; }   /* newsletter */
  .copyright { order: 3; }
  .footer-grid > div:nth-child(2) { order: 4; }    /* légal → barre du bas */

  /* Bloc marque : logo + nom + slogan, centrés */
  .footer-contact {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 14px;
  }
  .site-footer .footer-contact .footer-logo img { height: 74px; }
  .footer-brand { display: flex; flex-direction: column; gap: 4px; }
  .fb-name { font-size: 18px; font-weight: 700; letter-spacing: .04em; color: #fff; }
  .fb-tag { font-size: 12.5px; opacity: .68; }

  /* 2 colonnes Contact | Suivez-nous, séparées de la marque par un filet */
  .footer-contact-body {
    width: 100%;
    display: grid;
    grid-template-columns: 1.7fr 1fr;
    column-gap: 16px;
    row-gap: 6px;
    text-align: left;
    margin-top: 20px;
    padding-top: 24px;
    border-top: 1px solid rgba(255, 255, 255, .12);
  }
  .footer-contact-body > h4:nth-of-type(1) { grid-column: 1; grid-row: 1; }
  .footer-contact-body > address           { grid-column: 1; grid-row: 2; font-size: 13.5px; }
  .footer-contact-body > h4:nth-of-type(2) { grid-column: 2; grid-row: 1; margin-top: 0 !important; }
  .footer-contact-body > .social           { grid-column: 2; grid-row: 2; }
  /* Le bouton « message » passe sous les deux colonnes, pleine largeur */
  .footer-contact-body > .footer-msg-btn   { grid-column: 1 / -1; grid-row: 3; justify-self: start; margin-top: 10px; }
  .site-footer address { line-height: 1.6; word-break: break-word; }
  .social { flex-wrap: wrap; gap: 12px; }
  .social a { width: 40px; height: 40px; }

  /* Newsletter pleine largeur */
  .footer-grid > div:nth-child(3) { margin-top: 34px; text-align: left; }
  .news-intro { display: block; margin: 0 0 12px; opacity: .75; }
  .newsletter button { flex: 1 1 100%; }

  /* Barre du bas : © puis liens légaux centrés côte à côte (titre masqué) */
  .copyright { margin-top: 30px; }
  .footer-grid > div:nth-child(2) > h4 { display: none; }
  .footer-grid > div:nth-child(2) .legal-links {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 6px 22px;
    margin-top: 10px;
    font-size: 13px;
    opacity: .7;
  }
}

/* ============================================================
   Médias & placeholders
   ------------------------------------------------------------
   .media-shell : conteneur au bon ratio. Le dégradé + libellé
   restent visibles tant que le vrai fichier n'existe pas ;
   déposer le média au bon chemin suffit (aucun code à changer).
   ============================================================ */
.media-shell {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-card);
  background: linear-gradient(145deg, #0A0F1A 0%, var(--color-accent-dark) 100%);
  aspect-ratio: 16 / 9;
}

.media-shell::after {
  content: attr(data-label);
  position: absolute;
  left: 12px;
  bottom: 10px;
  font-size: 11px;
  letter-spacing: .12em;
  color: rgba(255, 255, 255, .4);
  text-transform: none;
  pointer-events: none;
}

.media-shell>img,
.media-shell>video,
.media-shell>iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.media-shell.loaded::after {
  display: none;
}

/* média livré : plus de libellé */
.media-shell.ratio-square {
  aspect-ratio: 1 / 1;
}

.media-shell.ratio-43 {
  aspect-ratio: 4 / 3;
}

.media-shell.ratio-32 {
  aspect-ratio: 3 / 2;
}

.media-shell.ratio-wide {
  aspect-ratio: 21 / 9;
}

img.is-missing {
  visibility: hidden;
}

/* l'img cassée s'efface, le shell affiche le placeholder */

/* rendus détourés (PNG transparents) : pas de fond une fois le fichier livré,
   zone en pointillés tant qu'il manque (navigateurs avec :has) */
.media-shell.transparent-render {
  background: none;
  border-radius: 0;
}

.media-shell.transparent-render::after {
  color: rgba(255, 255, 255, .35);
}

.on-light .media-shell.transparent-render::after {
  color: rgba(14, 17, 22, .45);
}

.media-shell.transparent-render:has(> img.is-missing) {
  border: 1px dashed rgba(143, 199, 255, .4);
  background: rgba(19, 104, 191, .06);
}

.on-light .media-shell.transparent-render:has(> img.is-missing) {
  border-color: rgba(14, 17, 22, .25);
  background: rgba(14, 17, 22, .04);
}

/* ============================================================
   Protection « grand public » des médias
   Décourage l'enregistrement des images/vidéos : pas de glisser-déposer,
   pas de menu « Enregistrer l'image » à l'appui long iOS, pas de sélection.
   Le blocage du clic droit est posé en JS (main.js), uniquement sur les médias.
   ⚠️ Dissuasion, pas une sécurité : les fichiers restent accessibles via les
   outils de développement ou l'URL directe.
   ============================================================ */
img,
video {
  -webkit-user-drag: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* ============================================================
   Heros & sections génériques
   ============================================================ */
.hero-video {
  position: relative;
  height: 100svh;
  min-height: 560px;
  padding: 0;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}

.hero-video .media-shell {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  border-radius: 0;
  background: transparent;
  /* laisse le dégradé global filer sans rupture vers la section suivante */
}

.hero-video::after {
  /* voile léger pour la lisibilité du slogan, fondu doux (pas de démarcation) */
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 36%;
  background: linear-gradient(180deg, transparent, rgba(5, 8, 15, .35));
  pointer-events: none;
}

.hero-content {
  position: relative;
  z-index: 2;
  padding: 0 var(--pad-x) clamp(48px, 9vh, 110px);
  max-width: 860px;
}

.hero-content h1 {
  margin-bottom: .7em;
}

/* Page d'accueil — titres plus percutants : +75 % par rapport à l'échelle de base.
   Scopé à .page-home (main.css est partagé avec les autres pages) ; le calc() suit
   les variables responsive, et l'anneau des .ring-title (dimensionné en em) se met
   à l'échelle automatiquement avec la taille du titre. */

/* Titre du hero : plafonné et responsive (clamp) plutôt que 1.75× fixe — le titre FR
   est plus long que l'EN et débordait le conteneur (5 lignes) sur grand écran. Ici il
   reste impactant mais retombe sur les 2 lignes prévues par le <br>. */
.page-home .hero-content h1 {
  font-size: clamp(28px, 2.6vw, 40px);
}

/* ---------- Intro animée de la home (titre en fondu) ----------
   Le titre apparaît en grand au centre, ses deux lignes en fondu décalé,
   marque une pause, puis rejoint sa position finale en rétrécissant, où il
   se fond exactement dans le titre de la page (voir assets/js/hero-intro.js). */
.hero-intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 clamp(16px, 5vw, 48px);
  pointer-events: none;
}
.hero-intro-title {
  display: inline-block;
  margin: 0;
  text-align: center;
  color: #fff;
  font-weight: 700;
  font-size: clamp(24px, 5.6vw, 81px);
  line-height: 1.05;
  text-shadow: 0 4px 26px rgba(8, 12, 20, .55), 0 1px 3px rgba(8, 12, 20, .5);
  will-change: transform;
}
.hero-intro-title .hit-line {
  display: block;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .55s ease, transform .55s ease;
}
.hero-intro-title .hit-line.in {
  opacity: 1;
  transform: translateY(0);
}

/* Pendant l'intro : le titre final est masqué (l'overlay le remplace). À la
   fin, le titre est échangé « à sec » (aucun fondu) car l'overlay se pose au
   pixel près dessus ; seul le bouton apparaît en fondu doux. */
.page-home.intro-running .hero-content h1 { opacity: 0; }
.page-home.intro-running .hero-content .btn { opacity: 0; }
.page-home .hero-content .btn { transition: opacity .5s ease; }

@media (prefers-reduced-motion: reduce) {
  .hero-intro-overlay { display: none; }
  .page-home.intro-running .hero-content h1,
  .page-home.intro-running .hero-content .btn { opacity: 1; }
}

.page-home h2 {
  font-size: calc(var(--fs-h2) * 1.75);
}

/* …et le titre des cartes du carrousel Programme (« Alpha 0 », « Digital Twin »…). */
.page-home .pc-textitem h3 {
  font-size: calc(var(--fs-h3) * 1.75);
}

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
}

@media (max-width: 920px) {
  .split {
    grid-template-columns: 1fr;
  }
}

.section-light {
  background: var(--color-light);
  color: var(--color-ink);
}

.section-black {
  background: #000;
}

/* ---------- Fond animé « grille + halos » bleu électrique (Home, sections 2 & 3) ----------
   Le canvas est injecté par grid-glow.js en premier enfant de [data-grid-glow].
   Les sections 2 & 3 sont regroupées dans .glow-band → UN SEUL canvas continu
   derrière les deux (grille alignée, halos qui traversent : pas de délimitation). */
[data-grid-glow] {
  position: relative;
  overflow: hidden;
}

/* PAS d'isolation ici : le pod (mix-blend-mode:screen) doit pouvoir se fondre AVEC
   le fond réel derrière la section (dégradé de la page + grille/halos animés).
   Une isolation enfermerait le blend dans la bande et le noir resterait noir. */

[data-grid-glow]>.grid-glow-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  /* derrière les sections, mais DEVANT le dégradé du body → sert de fond de blend */
  pointer-events: none;
  opacity: .65;
}

/* le contenu (sections) passe au-dessus du fond animé ; sections transparentes */
[data-grid-glow]>*:not(.grid-glow-canvas) {
  position: relative;
  z-index: 1;
}

/* le pod NE doit PAS créer de contexte d'empilement → sa vidéo en `screen` se fond
   avec le canvas + le dégradé derrière (le noir laisse voir la grille et les halos) */
#pod {
  z-index: auto;
}

.glow-band>section {
  background: transparent;
}

/* particules lumineuses bas de section pod */
.particles {
  background-image:
    radial-gradient(2px 2px at 12% 88%, rgba(143, 199, 255, .8), transparent),
    radial-gradient(1.5px 1.5px at 28% 94%, rgba(143, 199, 255, .5), transparent),
    radial-gradient(2px 2px at 47% 90%, rgba(255, 255, 255, .45), transparent),
    radial-gradient(1.5px 1.5px at 63% 96%, rgba(143, 199, 255, .6), transparent),
    radial-gradient(2px 2px at 81% 92%, rgba(255, 255, 255, .5), transparent),
    radial-gradient(1.5px 1.5px at 92% 87%, rgba(143, 199, 255, .5), transparent);
  background-repeat: no-repeat;
}

/* flèches circulaires autour du pod */
.rotation-hint {
  position: relative;
}

.rotation-hint::before {
  content: "";
  position: absolute;
  inset: -14px;
  border: 1.5px dashed rgba(143, 199, 255, .45);
  border-radius: 50% / 30%;
  pointer-events: none;
  animation: rot-hint 14s linear infinite;
}

@keyframes rot-hint {
  to {
    transform: rotate(360deg);
  }
}

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

/* Pod : média à transparence NATIVE (alpha dans le fichier), donc on voit la
   grille/les halos à travers le pod sans aucune astuce.
   - WebM VP9 alpha  → Chrome / Firefox / Edge / Android
   - WebP animé alpha → Safari / iPhone (basculé par main.js)
   Plus de mix-blend-mode : screen (ça ne marchait pas sur WebKit/iOS et créait
   le rectangle noir). Le shell reste transparent, ratio 16:9. */
#pod .media-shell {
  aspect-ratio: 16 / 9;
}

#pod .media-shell.loaded {
  background: transparent;
}

/* ---------- Carrousel (Home / Program) ---------- */
.carousel {
  position: relative;
}

.carousel .slide {
  display: none;
}

.carousel .slide.current {
  display: block;
}

.carousel-dots {
  display: flex;
  gap: 8px;
  margin-top: 14px;
}

.carousel-dots button {
  position: relative;
  overflow: hidden;
  flex: 1;
  height: 4px;
  border: 0;
  border-radius: 2px;
  background: rgba(255, 255, 255, .28);
  /* piste : gris */
  cursor: pointer;
  padding: 0;
}

.on-light .carousel-dots button {
  background: rgba(14, 17, 22, .18);
}

.carousel-dots button.current::after {
  /* barre de progression animée (blanc), synchronisée avec l'intervalle JS (4 s) */
  content: "";
  position: absolute;
  inset: 0;
  background: #fff;
  transform-origin: left;
  animation: dot-fill 4s linear forwards;
}

.on-light .carousel-dots button.current::after {
  background: var(--color-ink);
}

@keyframes dot-fill {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .carousel-dots button.current::after {
    animation: none;
  }
}

/* ---------- Carrousel multi-programmes (Home, section Programme) ---------- */
.program-carousel {
  margin-top: 30px;
}

/* Mobile : section Programme resserrée → on rapproche le titre du projet du titre
   « Program » (moins de marge sous le h2 + moins de marge au-dessus du carrousel). */
@media (max-width: 700px) {
  #program > h2 {
    margin-bottom: .25em;
  }
  .program-carousel {
    margin-top: 8px;
  }
}

.pc-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
}

@media (max-width: 920px) {
  .pc-grid {
    grid-template-columns: 1fr;
  }
}

/* Colonne texte : tous les programmes empilés dans la MÊME cellule de grille
   (l'opacité gère la visibilité) → le conteneur prend TOUJOURS la hauteur du
   programme le plus long, quel que soit l'item affiché. Desktop ET mobile :
   le texte ne déborde plus derrière « Learn more », et la hauteur ne saute plus
   d'un projet à l'autre. */
.pc-textstack {
  position: relative;
  display: grid;
}

.pc-textitem {
  grid-area: 1 / 1;   /* tous empilés dans la même cellule → hauteur = plus grand */
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .5s ease, transform .5s ease;
  pointer-events: none;
}

.pc-textitem.current {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.pc-textitem h3 {
  margin: 0 0 .2em;
}

/* Colonne image : flèches de part et d'autre, ligne de progression en bas */
.pc-figure {
  display: flex;
  align-items: center;
  gap: 12px;
}

.pc-images {
  position: relative;
  flex: 1;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-card);
  overflow: hidden;
}

.pc-images .media-shell {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  opacity: 0;
  transition: opacity .5s ease;
}

.pc-images .media-shell.current {
  opacity: 1;
}

/* ligne fine blanche à l'arête basse de l'image = compte à rebours */
.pc-progress {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: #fff;
  transform-origin: left;
  transform: scaleX(0);
  z-index: 3;
  pointer-events: none;
}

.pc-arrow {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .45);
  background: rgba(5, 8, 15, .35);
  color: #fff;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  transition: background .25s, border-color .25s, transform .15s;
}

.pc-arrow:hover {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

.pc-arrow:active {
  transform: scale(.92);
}

/* 5 points : vide (contour) ou plein (blanc) selon la position */
.pc-dots {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 20px;
}

.pc-dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .5);
  background: transparent;
  cursor: pointer;
  transition: background .25s, border-color .25s, transform .25s;
}

.pc-dot.current {
  background: #fff;
  border-color: #fff;
  transform: scale(1.2);
}

@media (max-width: 560px) {
  .pc-arrow {
    width: 34px;
    height: 34px;
    font-size: 19px;
  }
}

/* ---------- Grilles de logos (partenaires / affiliations) ---------- */
.logo-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}

.logo-grid .logo-cell {
  display: grid;
  place-items: center;
  min-height: 110px;
  background: #fff;
  border-radius: var(--radius-card);
  padding: 18px;
  border: 1px solid rgba(14, 17, 22, .08);
}

.logo-grid img {
  max-height: 60px;
  width: auto;
  object-fit: contain;
}

/* logo manquant : la cellule devient un placeholder « en attente » */
.logo-cell.logo-pending {
  border-style: dashed;
  border-color: rgba(14, 17, 22, .22);
  background: rgba(19, 104, 191, .04);
}

.logo-cell .logo-fallback {
  display: grid;
  gap: 6px;
  text-align: center;
  padding: 4px;
}

.logo-fallback .lf-name {
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  font-size: 13px;
  color: var(--color-accent-dark);
}

.logo-fallback .lf-file {
  font-family: "Courier New", monospace;
  font-size: 10px;
  letter-spacing: .02em;
  color: #8a939d;
  word-break: break-all;
}

@media (max-width: 560px) {
  .logo-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ---------- Section Partenaires (Home) : logos gris foncé sans cases ----------
   Au survol/focus le logo s'efface et laisse place au détail de la collaboration,
   avec une surbrillance bleue. Le rendu de l'avion est agrandi et déborde. */
/* rendu de l'avion en fond plein cadre (déborde à droite), titre + logos par-dessus */
#partners {
  position: relative;
  overflow: hidden;
  min-height: clamp(750px, 95vh, 1100px);
}

#partners>.ring-title,
#partners>.partner-tabs,
#partners>.partner-grid {
  position: relative;
  z-index: 1;
}

/* Onglets de catégorie (Financiers / Techniques) — entre le titre et la grille.
   L'affichage alterne toutes les 7 s (partners.js) : la catégorie active est en
   noir, soulignée d'une BARRE DE PROGRESSION qui se remplit sur la durée avant
   la bascule ; l'autre est grisée sans barre. Centrés sur la largeur des logos.
   Aussi cliquables. */
.partner-tabs {
  display: flex;
  justify-content: center;      /* centré par rapport aux logos (même largeur que la grille) */
  gap: clamp(26px, 4vw, 46px);
  max-width: 560px;
  margin-top: 16px;
}

.partner-tab {
  position: relative;
  appearance: none;
  background: none;
  border: 0;
  padding: 0 2px 10px;          /* padding bas = place pour la barre de progression */
  margin: 0;
  font-family: var(--font);
  font-size: clamp(14px, 1.9vw, 23px);   /* ~×1.8 vs l'ancien 13px sur grand écran */
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  line-height: 1.1;
  color: rgba(14, 17, 22, .34);
  cursor: pointer;
  transition: color .35s ease;
}

.partner-tab:focus-visible {
  outline: 2px solid rgba(19, 104, 191, .5);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Catégorie affichée : texte noir. */
.partner-tab.is-active {
  color: var(--color-ink);
}

/* Piste (fine, grise) sous l'onglet actif : montre la longueur totale de la barre. */
.partner-tab.is-active::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2.5px;
  border-radius: 2px;
  background: rgba(14, 17, 22, .16);
}

/* Barre de progression (noire) : se remplit de 0 à 100 % sur la durée d'affichage
   (--switch-ms, posé par partners.js pour rester synchro avec la bascule). Repart
   de zéro à chaque activation (la classe .is-active est reposée à chaque bascule). */
.partner-tab.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2.5px;
  border-radius: 2px;
  background: var(--color-ink);
  transform: scaleX(0);
  transform-origin: left;
  animation: partner-progress var(--switch-ms, 7000ms) linear forwards;
}

@keyframes partner-progress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* Fondu léger des logos au changement de catégorie. */
#partners .partner-grid {
  transition: opacity .28s ease;
}
#partners .partner-grid.is-switching {
  opacity: 0;
}

.partners-render {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: none;
  z-index: 0;
  pointer-events: none;
}

.partners-render img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: right bottom;
  transform: translateY(5%) scale(1.48);
  transform-origin: right bottom;
}

/* Plein écran : l'image est déjà large en 'contain' → on réduit le zoom pour qu'elle
   prenne la pleine largeur sans déborder excessivement, ancrée à droite. */
@media (min-width: 1400px) {
  .partners-render img {
    object-position: right bottom;
    transform: translateY(5%) scale(1.36);
    transform-origin: right bottom;
  }
}

@media (min-width: 1800px) {
  .partners-render img {
    object-position: right bottom;
    transform: translateY(5%) scale(1.24);
    transform-origin: right bottom;
  }
}

@media (max-width: 920px) {
  .partners-render img {
    object-position: center bottom;
    transform: scale(0.92);
    transform-origin: center bottom;
    opacity: .6;
  }
}

/* Téléphone : le rendu de l'avion est ZOOMÉ (sinon trop petit, ancré en bas).
   Centré horizontalement, ancré en bas ; #partners a overflow:hidden → débordement
   rogné, aucun scroll horizontal. (opacité .6 conservée de la règle ≤920.) */
@media (max-width: 700px) {
  /* Section raccourcie → son bas (le vide sous l'avion) est supprimé et le
     bandeau de logos + « Press » remontent d'autant. (+5 % vs version la plus
     courte pour redescendre l'avion, le bandeau et le bas de section.) */
  #partners {
    min-height: clamp(617px, 85vh, 750px);
  }
  .partners-render img {
    /* plus de translateY : la section plus courte remonte déjà l'avion à la
       même position visuelle (ancré center bottom). */
    transform: scale(1.6);
    transform-origin: center bottom;
    object-position: center bottom;
  }
}

.partner-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* row-gap réduit : la 2e ligne remonte vers la 1re (loin de l'aile en bas) */
  gap: 2px 18px;
  max-width: 560px;
  /* logos cantonnés en haut à gauche, l'avion respire à droite */
  margin-top: 14px;
}

/* Nombre de colonnes selon le nombre de logos de la catégorie active (posé par
   partners.js) : 4 logos → 2×2 ; sinon 3 colonnes. (Le mobile ≤560, plus
   spécifique via #partners, force 2 colonnes quoi qu'il arrive.) */
.partner-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.partner-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }

/* En 2×2 (4 logos), les cellules sont ~2× plus larges qu'en 3 colonnes : sans
   bride, les logos grossissent (surtout France 2030, 114 px de haut) et la grille
   dépasse en hauteur la version « Techniques » (3 colonnes). On réduit les logos
   pour retrouver la même échelle et la même hauteur totale (2 lignes à 116 px). */
.partner-grid.cols-2 .partner-logo { max-height: 68px; max-width: 60%; }
.partner-grid.cols-2 .partner-logo[src*="france-2030"] { max-height: 78px; }

@media (max-width: 560px) {
  /* Téléphone : logos partenaires RÉDUITS et resserrés → l'avion en fond
     (rendu .partners-render) est bien plus visible.
     NB : préfixe #partners obligatoire — les règles de base .partner /
     .partner-logo sont définies PLUS BAS dans le fichier ; à spécificité égale
     elles gagneraient (ordre source). L'ID #partners les surclasse. */
  #partners .partner-grid {
    grid-template-columns: repeat(2, 1fr);
    max-width: none;
    gap: 6px 12px;
    margin-top: 16px;
  }
  #partners .partner {
    min-height: 92px;
    padding: 8px;
  }
  /* Les logos larges (DAHER, soben, BALLARD, Dassault) sont bornés par la LARGEUR
     de cellule ; le circulaire (France 2030) par la HAUTEUR → on remonte les deux. */
  #partners .partner-logo {
    max-height: 60px;
    max-width: 90%;
  }
  /* France 2030 : logo circulaire (beaucoup de vide autour) → zoom dédié, plus
     grand que les autres pour un poids visuel équivalent. */
  #partners .partner-logo[src$="france-2030.svg"] {
    max-height: 86px;
    max-width: 100%;
  }
}

.partner {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 116px;
  padding: 14px;
  border-radius: var(--radius-card);
  cursor: default;
  transition: background .3s, box-shadow .3s;
}

.partner:hover,
.partner:focus-visible {
  outline: none;
  background: rgba(19, 104, 191, .06);
  box-shadow: 0 0 0 1px rgba(19, 104, 191, .18), 0 10px 34px rgba(19, 104, 191, .12);
}

.partner-logo {
  max-height: 75px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  filter: grayscale(1) brightness(0);
  opacity: .72;
  /* gris très sombre sur le fond clair */
  transition: opacity .3s;
}

.partner:hover .partner-logo,
.partner:focus-visible .partner-logo {
  opacity: 0;
}

/* s'efface au profit du texte */
/* repli si le SVG manque : on affiche le nom (garde le même comportement de survol) */
.partner-logo.partner-logo-text {
  display: flex;
  align-items: center;
  text-align: center;
  filter: none;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: .04em;
  color: #3a4350;
}

/* --- Logos éditables via le CMS (Galerie) : case « passer en gris » ----------
   .is-grey  → grayscale(1) : conserve les NUANCES (1 couleur→1 gris,
               plusieurs couleurs→plusieurs gris, photo PNG→noir & blanc).
   .is-color → couleurs d'origine du fichier.
   N.B. les 6 partenaires d'origine gardent leur silhouette sombre
   (.partner-logo de base = grayscale + brightness:0), inchangée. */
.partner-logo.is-grey  { filter: grayscale(1); opacity: .8; }
.partner-logo.is-color { filter: none; opacity: 1; }
.lm-item img.is-grey   { filter: grayscale(1); }

/* Logo additionnel SANS nom : pas d'overlay, ne s'efface pas au survol. */
.partner.partner--plain:hover .partner-logo,
.partner.partner--plain:focus-visible .partner-logo { opacity: 1; }

/* Logo principal mis en avant (ex. France 2030) : plus grand, pleine largeur
   de la grille, sous les 6 partenaires. */
.partner.partner--lead { grid-column: 1 / -1; min-height: 120px; }
.partner.partner--lead .partner-logo { max-height: 101px; }

/* France 2030 : logo carré (viewBox 150×150) → bridé par la max-height des autres,
   il paraissait minuscule. On l'agrandit pour qu'il remplisse bien la case. */
.partner-logo[src*="france-2030"] { max-height: 114px; }

.partner-info {
  position: absolute;
  inset: 8px;
  display: grid;
  align-content: center;
  gap: 6px;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .3s, transform .3s;
  pointer-events: none;
  text-align: left;
}

.partner:hover .partner-info,
.partner:focus-visible .partner-info {
  opacity: 1;
  transform: none;
}

/* Mobile : pas de survol → un tap ouvre la fiche partenaire (classe .is-open
   posée par main.js). Le logo s'efface au profit du détail, comme au survol. */
@media (max-width: 700px) {
  .partner {
    cursor: pointer;
  }
  .partner.is-open {
    background: rgba(19, 104, 191, .06);
    box-shadow: 0 0 0 1px rgba(19, 104, 191, .18), 0 10px 34px rgba(19, 104, 191, .12);
  }
  .partner.is-open .partner-logo {
    opacity: 0;
  }
  .partner.is-open .partner-info {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
}

.partner-info h3 {
  margin: 0;
  font-size: 13px;
  letter-spacing: .04em;
  text-transform: none;
  color: var(--color-primary);
}

.partner-info ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 3px;
}

.partner-info li {
  position: relative;
  padding-left: 12px;
  font-size: 11.5px;
  line-height: 1.3;
  color: var(--color-ink);
}

.partner-info li::before {
  content: "•";
  position: absolute;
  left: 0;
  color: var(--color-primary);
}

/* (Le cadrage de l'avion est défini plus haut, en un seul bloc — voir .partners-render img) */

/* ---------- Cartes article ---------- */
/* ---------- Bandeau de logos défilant (Home, juste avant « Presse ») ----------
   Marquee continu droite → gauche, à la hauteur d'un logo SVG, qui chevauche
   légèrement le rendu de la section au-dessus (#partners). La piste est dupliquée
   par logo-marquee.js : translateX(-50%) = un jeu complet → boucle sans couture.
   Marge horizontale négative = plein cadre (annule le padding de la section). */
.logo-marquee {
  position: relative;
  z-index: 2;
  margin: clamp(-64px, -5vw, -36px) calc(-1 * var(--pad-x)) clamp(28px, 4vh, 44px);
  padding: 16px 0;
  overflow: hidden;
  /* fond transparent : les logos SVG se fondent directement sur l'image/section au-dessus */
  background: transparent;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}

.logo-marquee-track {
  display: flex;
  width: max-content;
  align-items: center;
  will-change: transform;
  animation: logoMarquee 40s linear infinite;
}

/* Pause au survol UNIQUEMENT sur périphérique à vrai pointeur (souris) : sur
   tactile, `:hover` reste collé après un tap et bloquait le bandeau. */
@media (hover: hover) {
  .logo-marquee:hover .logo-marquee-track {
    animation-play-state: paused;
  }
}

@keyframes logoMarquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); } /* la piste contient 2 jeux identiques */
}

.lm-item {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  height: clamp(32px, 3.96vw, 47px); /* = hauteur d'un logo SVG (~10% plus fin que la grille de logos au-dessus) */
  width: clamp(118px, 13vw, 168px);
  /* marge (et non gap) pour que -50% tombe pile sur un jeu → boucle sans saut */
  margin-right: clamp(40px, 6vw, 88px);
}

.lm-item img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  object-fit: contain;
}

/* Placeholder tant que le SVG n'existe pas (img.is-missing posée par main.js) :
   affiche le nom de fichier exact à déposer dans assets/img. */
.lm-item:has(> img.is-missing)::after {
  content: attr(data-file);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 4px;
  font-family: "Courier New", monospace;
  font-size: 10px;
  letter-spacing: .02em;
  color: #8a939d;
  text-align: center;
  word-break: break-all;
  border: 1px dashed rgba(14, 17, 22, .22);
  border-radius: 8px;
  background: rgba(19, 104, 191, .04);
}

/* Téléphone : bandeau de logos défilant RÉDUIT → plus de visibilité sur l'avion en fond. */
@media (max-width: 700px) {
  .lm-item {
    height: clamp(20px, 5.4vw, 28px);
    width: clamp(74px, 23vw, 116px);
    margin-right: clamp(24px, 7vw, 50px);
  }
}

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

.press-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 3vw, 36px);
}

@media (max-width: 920px) {
  .press-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 560px) {
  .press-grid {
    grid-template-columns: 1fr;
  }
}

.article-card {
  display: grid;
  gap: 12px;
  align-content: start;
}

.article-card .meta {
  font-size: 13px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--color-grey);
}

.on-light .article-card .meta {
  color: #5a636d;
}

.article-card h3 {
  font-size: 18px;
  letter-spacing: .04em;
  text-transform: none;
  margin: 0;
}

.article-card h3 a:hover {
  text-decoration: underline;
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: clamp(28px, 4vh, 48px);
}

.section-head h2 {
  margin: 0;
}

/* Accueil : on éloigne le titre « News » du bandeau de logos défilant juste
   au-dessus (sinon il est trop collé). Scopé à #press pour ne pas toucher les
   autres en-têtes de section. */
#press .section-head {
  margin-top: clamp(44px, 8vh, 84px);
}

/* ---------- Onglets génériques (Press, modèles 4S/6S) ---------- */
.tabs {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.tab-btn {
  padding: 11px 30px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--color-primary);
  background: transparent;
  /* non-sélectionné = contour */
  color: #fff;
  font-family: var(--font);
  font-size: var(--fs-btn);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .25s, border-color .25s, color .25s;
}

.tab-btn[aria-selected="true"] {
  background: var(--color-primary);
  /* sélectionné = plein, « allumé » */
  border-color: var(--color-primary);
  color: #fff;
}

.on-light .tab-btn {
  color: var(--color-ink);
}

.on-light .tab-btn[aria-selected="true"] {
  color: #fff;
}

/* ============================================================
   Page DRAGONFLY
   ============================================================ */
.dragonfly-hero {
  background: #D5DAE0;            /* fond clair de section (comme avant) */
  color: var(--color-ink);
  text-align: center;
  padding: 0;                    /* aucune marge : la bande touche les bords, pas de bande claire */
}

/* Bande hero PLEIN-BORD (touche les bords gauche/droite) et +30 % de hauteur. Rendus
   désormais à FOND TRANSPARENT → empilement normal sur fond clair, sans blend ; les
   avions sont recadrés en hauteur (object-fit: cover) pour tenir dans la bande. */
.dragonfly-hero .hero-stage {
  position: relative;
  width: 100%;
  margin: 0;
  padding: 0;
  height: 100svh;          /* le hero prend toute la page */
  overflow: hidden;
  background: transparent;
}

/* Voile CLAIR en bas pour la lisibilité du texte sombre posé PAR-DESSUS les images. */
.dragonfly-hero .hero-stage::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 50%;
  background: linear-gradient(to top, rgba(213, 218, 224, .92) 6%, rgba(213, 218, 224, .45) 34%, transparent 64%);
  z-index: 5;
  pointer-events: none;
}

/* Texte d'intro PAR-DESSUS toutes les images (fond transparent), bas de la bande. */
.dragonfly-hero .hero-copy {
  position: absolute;
  left: 50%;
  bottom: clamp(14px, 4vh, 46px);
  transform: translateX(-50%);
  z-index: 6;
  width: min(960px, 92%);
  text-align: center;
}

/* Les 3 rendus empilés (FOND TRANSPARENT, sans blend). Empilement du DESSOUS au
   DESSUS : M (z1) → titre (z2) → 6S (z3) → 4S (z4). */
.dragonfly-hero .hero-plane {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  pointer-events: none;
  will-change: transform, opacity;
}

/* Ancrage + arrivée par le côté respectif (4S ← gauche, 6S → droite, M ↓ haut). */
.hero-plane--m  { z-index: 1; transform: translateY(-10%); animation: df-from-top   1.25s cubic-bezier(.2, .7, .2, 1) .15s both; }  /* desktop : M monté de 10 % (repos mobile ajusté plus bas) */
.hero-plane--6s { z-index: 3; transform: translateY(0);     animation: df-from-right 1.25s cubic-bezier(.2, .7, .2, 1) .35s both; }  /* desktop : 6S au repos à 0 */
.hero-plane--4s { z-index: 4; transform: translateY(10%);   animation: df-from-left  1.25s cubic-bezier(.2, .7, .2, 1) .25s both; }  /* desktop : 4S descendu de 10 % — dégage l'avion blanc du texte */

/* Titre géant glissé ENTRE le 6S et le M (z-index 2). */
.dragonfly-hero h1 {
  position: absolute;
  left: 50%;
  top: 30%;                /* desktop : titre à 30 % (repos mobile à 35 %) */
  transform: translate(-50%, -50%);
  z-index: 2;
  margin: 0;
  font-size: clamp(52px, 11vw, 184px);
  letter-spacing: .06em;
  white-space: nowrap;
  color: #fff;
  text-shadow: 0 4px 26px rgba(8, 12, 20, .6), 0 1px 3px rgba(8, 12, 20, .55);
  animation: df-rise 1.4s cubic-bezier(.2, .7, .2, 1) .2s both;
}

@keyframes df-from-left  { from { opacity: 0; transform: translate(-55%, 10%); } to { opacity: 1; transform: translate(0, 10%); } }  /* desktop — 4S arrive de gauche, repos 10 % plus bas */
@keyframes df-from-right { from { opacity: 0; transform: translate(55%, 0); }   to { opacity: 1; transform: translate(0, 0); } }     /* desktop — 6S arrive de droite, repos à 0 */
@keyframes df-from-top   { from { opacity: 0; transform: translateY(-110%); } to { opacity: 1; transform: translateY(-10%); } }      /* desktop — M arrive du haut, repos 10 % plus haut */

@keyframes df-rise {
  from { opacity: 0; transform: translate(-50%, -34%) scale(.92); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .dragonfly-hero h1,
  .dragonfly-hero .hero-plane { animation: none; }
}

/* --- Mode téléphone (≤700px) : positions du composite héros ajustées ;
   le DESKTOP garde ses réglages ci-dessus. Sur mobile : 4S remonté (repos 0),
   6S remonté (repos -5 %), M et titre descendus de 5 %. La position de repos
   étant portée par la FIN de l'animation (fill both), on bascule sur des
   keyframes dédiées mobile ; le transform sert de repli en reduced-motion. --- */
@media (max-width: 700px) {
  .hero-plane--m  { transform: translateY(-5%); animation-name: df-from-top-m; }
  .hero-plane--6s { transform: translateY(-5%); animation-name: df-from-right-m; }
  .hero-plane--4s { transform: translateY(-2%); animation-name: df-from-left-m; }  /* 4S remonté de 2 % sur mobile */
  .dragonfly-hero h1 { top: 35%; }
}
@keyframes df-from-left-m  { from { opacity: 0; transform: translate(-55%, -2%); } to { opacity: 1; transform: translate(0, -2%); } }  /* repos 4S : -2 % (remonté) */
@keyframes df-from-right-m { from { opacity: 0; transform: translate(55%, -5%); } to { opacity: 1; transform: translate(0, -5%); } }
@keyframes df-from-top-m   { from { opacity: 0; transform: translateY(-105%); }   to { opacity: 1; transform: translateY(-5%); } }

/* Mobile : titre AGRANDI (« DRAGONFLY » reste sur une ligne, cf. white-space:nowrap). */
@media (max-width: 560px) {
  .dragonfly-hero h1 {
    font-size: clamp(42px, 15vw, 90px);
    letter-spacing: .03em;
  }
}

.hero-tab-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 4vw, 48px);
  flex-wrap: wrap;
  margin: 8px 0 26px;
}

.dragonfly-hero .lede {
  color: var(--color-ink);
  max-width: 780px;
  margin: 0 auto;
  text-shadow: 0 1px 6px rgba(213, 218, 224, .9);
}

.dragonfly-hero .sub {
  color: var(--color-accent-dark);
  background: transparent;
  letter-spacing: .2em;
  font-weight: 700;
  text-transform: uppercase;
  margin: 0 0 .55em;
  text-shadow: 0 1px 6px rgba(213, 218, 224, .9);
}

.dragonfly-hero .tab-btn[aria-selected="true"] {
  color: var(--color-ink);
  border-color: var(--color-primary);
}

/* visuels dépendant du modèle sélectionné (body[data-model]) */
body[data-model="4s"] .model-6s-only {
  display: none;
}

body[data-model="6s"] .model-4s-only {
  display: none;
}

/* Blocs specs infographie */
.spec-stage {
  position: relative;
  text-align: center;
}

.spec-columns {
  /* le rendu de l'avion domine, les specs se positionnent au plus près autour */
  display: grid;
  grid-template-columns: minmax(170px, 1fr) minmax(340px, 2.4fr) minmax(170px, 1fr);
  gap: clamp(12px, 2.2vw, 34px);
  align-items: center;
}

@media (max-width: 920px) {
  .spec-columns {
    grid-template-columns: 1fr;
  }
}

.spec-list {
  display: grid;
  gap: 16px;
  text-align: left;
}

.spec-list .spec-row {
  border-bottom: 1px solid rgba(255, 255, 255, .18);
  padding-bottom: 10px;
}

.spec-row .label {
  display: block;
  font-size: 12px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--color-grey);
}

.spec-row .value {
  font-size: clamp(22px, 2.2vw, 30px);
  font-weight: 700;
  letter-spacing: .04em;
}

/* apparition animée des specs au scroll (activée par JS via body.has-js) */
body.has-js .spec-row {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .6s ease, transform .6s ease;
}

body.has-js .spec-row.in-view {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  body.has-js .spec-row {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Bloc 4 — panneau technical specs */
.techspecs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 520px;
  padding: 0;
}

@media (max-width: 920px) {
  .techspecs {
    grid-template-columns: 1fr;
  }
}

.techspecs .photo {
  position: relative;
}

.techspecs .photo .media-shell {
  /* une image par catégorie (performance, dimensions, masses, propulsion) */
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  border-radius: 0;
  opacity: 0;
  transition: opacity .45s ease;
}

.techspecs .photo .media-shell.current {
  opacity: 1;
}

@media (max-width: 920px) {
  .techspecs .photo {
    min-height: 320px;
  }
}

.techspecs .panel {
  background: #000;
  padding: clamp(32px, 5vw, 64px);
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.model-dots {
  display: flex;
  gap: 10px;
  align-items: center;
}

.model-dots .dot {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .4);
  background: transparent;
  color: #fff;
  font-family: var(--font);
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
}

.model-dots .dot[aria-selected="true"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

.techspecs .spec-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 26px;
  flex: 1;
  align-content: start;
}

.spec-grid .spec-row {
  border-bottom: 1px solid rgba(255, 255, 255, .14);
  padding-bottom: 10px;
}

@media (max-width: 560px) {
  .techspecs .spec-grid {
    grid-template-columns: 1fr;
  }
}

/* Mobile : bloc techspecs COMPRESSÉ en hauteur → on veut voir en même temps la
   photo, les specs et les onglets Performance/Dimensions/Weights/Powertrain.
   Photo plus courte, grille maintenue en 2 colonnes (annule le 1-col ≤560),
   valeurs et paddings réduits, onglets plus compacts. */
@media (max-width: 700px) {
  .techspecs .photo { min-height: 190px; }
  .techspecs .panel {
    padding: 18px clamp(16px, 5vw, 26px) 20px;
    gap: 14px;
  }
  .techspecs .section-head { margin-bottom: 0; }
  .techspecs .section-head h2 { font-size: 20px; }
  .techspecs .spec-grid {
    grid-template-columns: 1fr 1fr;
    gap: 9px 18px;
  }
  .techspecs .spec-grid .spec-row { padding-bottom: 6px; }
  .techspecs .spec-row .label { font-size: 10px; letter-spacing: .1em; }
  .techspecs .spec-row .value { font-size: clamp(15px, 4.4vw, 19px); }
  .cat-tabs { gap: 8px; }
  .cat-tabs .cat { font-size: 12px; letter-spacing: .1em; padding: 4px 2px; }
  .cat-tabs .arrow { width: 30px; height: 30px; font-size: 13px; }
}

.spec-cat {
  display: none;
}

.spec-cat.current {
  display: contents;
}

.cat-tabs {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.cat-tabs .arrow {
  background: none;
  border: 1px solid rgba(255, 255, 255, .4);
  color: #fff;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 15px;
}

.cat-tabs .cat {
  background: none;
  border: 0;
  color: var(--color-grey);
  font-family: var(--font);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 6px 4px;
}

.cat-tabs .cat[aria-selected="true"] {
  color: #fff;
  border-bottom: 2px solid var(--color-primary);
}

/* Bloc 5 — globe interactif du rayon d'action (MapLibre GL, projection globe) */
.range-section {
  padding: 0;
  position: relative;
}

#rangeMap {
  height: clamp(460px, 82vh, 760px);
  background: #05080F;
}

/* Mobile — bande DROITE (10%) au niveau de la Range Map :
   1) dégradé noir (transparent → noir vers le bord DROIT) ;
   2) zone SCROLLABLE : l'overlay capte le toucher (pointer-events auto) pour que
      la carte ne panne PAS dessous, et touch-action:pan-y laisse le doigt faire
      défiler la page verticalement — sinon l'utilisateur reste « collé » à la carte.
   Masquée en desktop (la carte reste pleinement interactive). */
.range-scroll-guard { display: none; }

@media (max-width: 700px) {
  .range-scroll-guard {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    width: 10%;
    height: 100%;
    z-index: 400;                 /* au-dessus du canvas de la carte, SOUS le panneau (z-index 500) */
    background: linear-gradient(to left, #000 0%, rgba(0, 0, 0, 0) 100%);
    touch-action: pan-y;          /* le doigt fait défiler la page, pas panner la carte */
  }
  /* Les contrôles MapLibre (zoom, attribution) sont en bas-DROITE, sous le guard :
     on les remonte AU-DESSUS pour qu'ils restent cliquables. */
  #rangeMap .maplibregl-ctrl-bottom-right { z-index: 401; }
}

#rangeMap canvas {
  outline: none;
}

/* Contrôles MapLibre alignés sur le thème sombre du site */
#rangeMap .maplibregl-ctrl-group {
  background: rgba(5, 8, 15, .88);
  border: 1px solid rgba(255, 255, 255, .15);
  box-shadow: 0 2px 12px rgba(0, 0, 0, .4);
}

#rangeMap .maplibregl-ctrl-group button+button {
  border-top: 1px solid rgba(255, 255, 255, .12);
}

#rangeMap .maplibregl-ctrl-group button .maplibregl-ctrl-icon {
  filter: invert(1);
  opacity: .85;
}

#rangeMap .maplibregl-ctrl-group button:hover {
  background: rgba(19, 104, 191, .35);
}

#rangeMap .maplibregl-ctrl-attrib {
  background: rgba(5, 8, 15, .7);
  color: rgba(255, 255, 255, .6);
}

#rangeMap .maplibregl-ctrl-attrib a {
  color: rgba(143, 199, 255, .85);
}

/* Marqueur de marque : point bleu + halo pulsé */
.bsa-pin {
  position: relative;
  width: 18px;
  height: 18px;
  cursor: grab;
}

.bsa-pin:active {
  cursor: grabbing;
}

.bsa-pin .bsa-pin-dot {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #1368BF;
  border: 2px solid #fff;
  box-shadow: 0 0 10px rgba(143, 199, 255, .9);
}

.bsa-pin .bsa-pin-halo {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(143, 199, 255, .45);
  animation: bsa-pin-pulse 2.4s ease-out infinite;
}

@keyframes bsa-pin-pulse {
  0% {
    transform: scale(1);
    opacity: .7;
  }

  70% {
    transform: scale(2.6);
    opacity: 0;
  }

  100% {
    transform: scale(2.6);
    opacity: 0;
  }
}

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

.range-panel {
  position: absolute;
  z-index: 500;
  top: 18px;
  left: 18px;
  background: rgba(5, 8, 15, .88);
  border: 1px solid rgba(255, 255, 255, .15);
  border-radius: var(--radius-card);
  padding: 18px 22px;
  max-width: 320px;
  font-size: 14px;
}

.range-panel h3 {
  font-size: 16px;
  margin-bottom: .6em;
}

.range-panel .tabs {
  margin-bottom: 10px;
}

.range-panel .tab-btn {
  padding: 7px 18px;
  font-size: 12px;
}

.range-value {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: .06em;
  display: block;
  margin-bottom: 6px;
}

.map-fallback {
  display: grid;
  place-items: center;
  height: 100%;
  color: var(--color-grey);
  padding: 24px;
  text-align: center;
}

/* Bloc 6 — galerie : bandeau d'images à DÉFILEMENT NATIF (auto + glisser).
   Le défilement (auto-scroll, glisser, trackpad) et la boucle infinie sont
   pilotés par gallery.js via scrollLeft — plus de marquee CSS. Fonctionne
   à l'identique sur PC et mobile. */
.gallery-pane {
  display: none;
  overflow: hidden;
}

.gallery-pane.current {
  display: block;
  overflow-x: auto;
  overflow-y: hidden;
  cursor: grab;                    /* affordance : glisser pour défiler (PC) */
  scrollbar-width: none;           /* Firefox */
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  -webkit-user-select: none;
  user-select: none;               /* pas de sélection de texte pendant le glisser */
}
.gallery-pane.current::-webkit-scrollbar { display: none; }   /* WebKit / Chrome */
.gallery-pane.current.dragging { cursor: grabbing; }
.gallery-pane.current.dragging .media-shell { cursor: grabbing; }

.gallery-track {
  display: flex;
  gap: 14px;
  width: max-content;
}

.gallery-track .media-shell {
  flex: 0 0 auto;
  width: clamp(240px, 30vw, 440px);
  cursor: zoom-in;
  transition: transform .25s;
}

.gallery-track .media-shell:hover {
  transform: scale(1.02);
}

/* Mobile : pills de la galerie (« 4 Seater / 6 Seater / Unmanned ») sur UNE seule
   ligne. Labels longs → on compacte (padding, interlettrage, gap) et on interdit
   le retour à la ligne. #gallery surclasse la règle de base .tab-btn. */
@media (max-width: 700px) {
  #gallery .section-head .tabs {
    flex-wrap: nowrap;
    gap: 8px;
  }
  #gallery .section-head .tab-btn {
    padding: 9px 14px;
    font-size: 11px;
    letter-spacing: .05em;
    white-space: nowrap;
  }

  /* La galerie n'affiche pas le curseur « grab » sur tactile. */
  .gallery-pane.current { cursor: default; }
}

/* Lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;   /* plein-écran : au-dessus de tout, header (600) inclus */
  background: rgba(0, 0, 0, .92);
  display: none;
  place-items: center;
  padding: 4vh 4vw;
}

.lightbox.open {
  display: grid;
}

.lightbox .media-shell {
  width: min(1100px, 92vw);
  background: #0A0F1A;
}

.lightbox button {
  position: absolute;
  background: none;
  border: 1px solid rgba(255, 255, 255, .4);
  color: #fff;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  font-size: 18px;
  cursor: pointer;
}

.lightbox .lb-close {
  top: 22px;
  right: 22px;
}

.lightbox .lb-prev {
  left: 18px;
  top: 50%;
  transform: translateY(-50%);
}

.lightbox .lb-next {
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
}

/* ============================================================
   Page CONCEPT — séquence scroll-linked
   ============================================================ */
body.page-concept {
  background: #000;
}

/* Calque de fond DÉGRADÉ fixé au viewport, derrière la séquence. Le canvas fait
   100svh (petit viewport, stable au scroll) : quand la barre d'adresse du
   navigateur mobile se rétracte, le viewport grandit et une bande apparaît SOUS
   l'image. Ce calque `fixed` la remplit toujours — noir pur en haut, #000f3f
   (bleu nuit) en bas. z-index:-1 = derrière le canvas (que .seq-sticky, en
   position:sticky, peint au-dessus) mais devant le fond #000 du body. */
body.page-concept::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to bottom, #000 0%, #000 50%, #000f3f 80%, #000f3f 100%);
  pointer-events: none;
}

/* Titre d'intro = OVERLAY TRANSPARENT posé sur le canvas de la séquence (dans
   .seq-sticky), pas une section séparée à traverser. Les frames (noires au départ)
   restent visibles derrière et défilent dès le 1er scroll — aucun temps mort.
   L'opacité de l'overlay est pilotée par scroll-sequence.js (fondu selon la frame).
   z-index 1 = au-dessus du canvas, sous les .seq-step (z-index 2). */
.seq-loader {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  background: transparent;
  text-align: center;
  padding: 0 var(--pad-x);
  pointer-events: none;
}

/* L'équation entière est sur une ligne : « Blue Spirit Aero = Hydrogen + » suivi,
   INLINE, de la pile D/E/P (alignée par la 1re ligne = baseline). Tout est intégré
   dans un seul bloc — pas de « DEP » écrit en double ni de bloc séparé. */
.seq-loader .equation {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 .32em;
  font-size: clamp(20px, 4.2vw, 56px);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  line-height: 1.12;
}

.seq-loader .eq-lead {
  display: inline-flex;
  align-items: baseline;
  gap: 0 .3em;
  white-space: nowrap;
}

/* Chaque opérande de l'équation est un « jeton » : sur ordinateur ils restent en ligne
   (eq-lead = flex en ligne) ; sur téléphone ils s'empilent (cf. media query plus bas). */
.seq-loader .eq-tok {
  white-space: nowrap;
}

/* H₂ → Hydrogen : crossfade (inline-grid → les deux libellés se superposent dans la
   même cellule, la boîte prend la largeur de « Hydrogen », pas de chevauchement). */
.seq-loader .h2-morph {
  display: inline-grid;
  vertical-align: baseline;
}

.seq-loader .h2-morph>* {
  grid-area: 1 / 1;
  white-space: nowrap;
  justify-self: start;
}

.seq-loader .h2-src {
  transition: opacity .35s ease;
}

.seq-loader .h2-dst {
  opacity: 0;
  transition: opacity .4s ease .08s;
}

.seq-loader.h2-write .h2-src {
  opacity: 0;
}

.seq-loader.h2-write .h2-dst {
  opacity: 1;
}

/* Pile D/E/P : démarre en ligne « DEP » (E et P remontés sur la ligne du D), puis
   E et P GLISSENT VERS LE BAS à leur ligne, et les mots s'écrivent après la lettre. */
.seq-loader .dep-stairs {
  display: inline-grid;
  gap: .18em;
  text-align: left;
}

.seq-loader .dep-line {
  display: inline-flex;
  align-items: baseline;
  line-height: 1.05;
  white-space: nowrap;
  transition: transform .6s cubic-bezier(.2, .7, .2, 1);
  will-change: transform;
}

.seq-loader .dep-line .cap {
  color: #8FC7FF;
}

.seq-loader .dep-line .word {
  display: inline-block;
  overflow: hidden;
  max-width: 0;
  opacity: 0;
  transition: max-width .55s ease, opacity .4s ease;
}

/* état initial : « DEP » en ligne (E et P remontés à droite, sur la ligne du D).
   Les positions initiales ET la déconstruction (retour à 0) sont pilotées par
   scroll-sequence.js en style inline → la transition s'anime de façon fiable,
   sans ambiguïté de cascade entre deux règles concurrentes sur `transform`. */
.seq-loader .dep-line:nth-child(2) {
  transform: translate(.72em, -1.23em);
}

.seq-loader .dep-line:nth-child(3) {
  transform: translate(1.44em, -2.46em);
}

/* écriture des mots (cascade légère) */
.seq-loader.write .dep-line .word {
  max-width: 14ch;
  opacity: 1;
}

.seq-loader.write .dep-line:nth-child(2) .word {
  transition-delay: .1s;
}

.seq-loader.write .dep-line:nth-child(3) .word {
  transition-delay: .2s;
}

/* Indicateur de scroll : SOURIS (ordinateur, molette/flèche qui descend) ou MAIN qui
   SWIPE (tactile). Apparaît à la fin du verrou (.seq-loader.ready) puis se fond avec
   l'overlay au scroll. Bascule selon l'appareil via (hover/pointer). */
.seq-loader .scroll-cue {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 12px;
  margin: clamp(34px, 5vh, 64px) 0 0;
  color: rgba(255, 255, 255, .92);
  opacity: 0;
  transition: opacity .8s;
}

/* Libellé explicite au-dessus de l'icône (souris / main) : l'indice de départ
   « écrit » ce qu'il faut faire, il n'est plus seulement une icône muette. */
.seq-loader .cue-label {
  font-size: clamp(12px, 1.5vw, 15px);
  font-weight: 400;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .82);
}

.seq-loader.ready .scroll-cue {
  opacity: .9;
}

/* TÉLÉPHONE : l'équation s'EMPILE verticalement, centrée — « Blue Spirit Aero / = /
   Hydrogen / + » puis l'escalier D·E·P en dessous (cf. maquette mobile). L'escalier
   lui-même (lignes décalées vers la droite) reste piloté par scroll-sequence.js. */
@media (max-width: 560px) {
  .seq-loader .equation {
    flex-direction: column;
    align-items: center;
    gap: .16em 0;
  }
  .seq-loader .eq-lead {
    flex-direction: column;
    align-items: center;
    gap: .16em 0;
  }
}

/* Par défaut (ordinateur) : souris. Tactile (pas de survol, pointeur grossier) : main. */
.scroll-cue .cue-hand { display: none; }

@media (hover: none) and (pointer: coarse) {
  .scroll-cue .cue-mouse { display: none; }
  .scroll-cue .cue-hand { display: block; }
}

/* Souris : molette STATIQUE, et une flèche juste en dessous qui descend en boucle. */
.cue-chevron { animation: cue-chevron 1.6s ease-in-out infinite; }

@keyframes cue-chevron {
  0%, 100% { opacity: .35; transform: translateY(0); }
  50%      { opacity: 1;   transform: translateY(4px); }
}

/* Main : geste de swipe vers le haut + flèche de direction. */
.cue-hand-g { animation: cue-swipe 1.8s ease-in-out infinite; }
.cue-swipe-arrow { animation: cue-arrow 1.8s ease-in-out infinite; }

@keyframes cue-swipe {
  0%, 100% { transform: translateY(3px); }
  45%      { transform: translateY(-3px); }
}

@keyframes cue-arrow {
  0%, 100% { opacity: .3; transform: translateY(3px); }
  45%      { opacity: 1;  transform: translateY(-2px); }
}

@media (prefers-reduced-motion: reduce) {
  .cue-chevron, .cue-hand-g, .cue-swipe-arrow { animation: none; }
}

/* Relance « Continue to scroll » : rappel discret affiché en bas au centre quand
   l'utilisateur s'immobilise > 2 s EN PLEINE PHASE ANIMÉE (entre deux temps de pose).
   Piloté par scroll-sequence.js (classe .show), masqué dès la reprise du scroll. */
.seq-nudge {
  position: absolute;
  left: 50%;
  bottom: clamp(26px, 6vh, 64px);
  z-index: 3;               /* au-dessus des titres (.seq-step, z-index 2) */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: rgba(255, 255, 255, .95);
  font-size: clamp(12px, 1.5vw, 15px);
  font-weight: 400;
  letter-spacing: .22em;
  text-transform: uppercase;
  text-shadow: 0 2px 16px rgba(0, 0, 0, .65);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate(-50%, 12px);
  transition: opacity .5s ease, transform .5s ease, visibility .5s;
}

.seq-nudge.show {
  opacity: .96;
  visibility: visible;
  transform: translate(-50%, 0);
}

.seq-nudge-chevron {
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, .5));
  animation: seq-nudge-bounce 1.5s ease-in-out infinite;
}

@keyframes seq-nudge-bounce {
  0%, 100% { transform: translateY(0);   opacity: .5; }
  50%      { transform: translateY(6px); opacity: 1; }
}

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

.sequence {
  position: relative;
  height: 1000vh;          /* plus haut = moins de frames franchies par unité de scroll */
  padding: 0;
}

.seq-sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}

#seqCanvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.seq-step {
  position: absolute;
  left: var(--pad-x);
  bottom: clamp(48px, 12vh, 140px);
  max-width: 392px;                          /* -30 % (560 → 392) : texte plus étroit, ne déborde plus sur l'avion */
  z-index: 2;            /* au-dessus de l'overlay d'intro (.seq-loader, z-index 1) */
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s, transform .7s;
  pointer-events: none;
}

.seq-step.visible {
  opacity: 1;
  transform: translateY(0);
}

.seq-step h2 {
  /* relief blanc lumineux */
  color: #fff;
  font-size: calc(var(--fs-h2) * 1.25);   /* +25% (page Concept) */
  text-shadow: 0 0 18px rgba(143, 199, 255, .85), 0 0 50px rgba(19, 104, 191, .6);
}

.seq-step p {
  font-size: 22.5px;                       /* 18px +25% (page Concept) */
  color: rgba(255, 255, 255, .92);
}

/* fallback sans animation (prefers-reduced-motion ou JS off) */
body.seq-static .sequence {
  height: auto;
}

body.seq-static .seq-sticky {
  position: static;
  height: auto;
  overflow: visible;
}

body.seq-static #seqCanvas {
  display: none;
}

body.seq-static .seq-step {
  position: static;
  opacity: 1;
  transform: none;
  max-width: 720px;
  margin: 0 auto;
  padding: var(--section-gap) var(--pad-x);
}

body.seq-static .seq-loader {
  display: none;
}

/* ---------- Séquence Concept sur téléphone ----------
   Titres + descriptions plus compacts et calés LE PLUS BAS possible, avec une
   marge sous la barre de navigation fixe : le bloc s'étend du bas de l'écran
   jusqu'à (header + marge) au maximum → il ne remonte jamais sous l'en-tête.
   Scopé au mode animé (le repli .seq-static garde sa mise en page en flux). */
@media (max-width: 700px) {
  body:not(.seq-static) .seq-step {
    top: calc(var(--header-h) + 12px);   /* marge sous la barre de nav */
    bottom: clamp(14px, 3.5vh, 40px);    /* rabaissé : titre + texte calés plus bas */
    right: var(--pad-x);
    max-width: none;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;           /* titre + texte calés en bas de la zone */
  }
  .seq-step h2 {
    font-size: 26px;                      /* desktop : var(--fs-h2) * 1.25 = 30px */
  }
  .seq-step p {
    font-size: 18px;                      /* desktop : 22.5px */
    line-height: 1.4;
    margin-top: 8px;
  }
}

/* ============================================================
   Transition intégrée Dragonfly : Specs extérieur → Séquence → Specs cabine
   ============================================================ */
.specs-transition {
  position: relative;
  height: 400vh;           /* assez de scroll pour 3 phases */
  padding: 0;
  background: #000;        /* WebP brut sur fond noir pur */
}

.specs-transition .st-sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}

.specs-transition canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Overlays specs (par-dessus le canvas) */
.st-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(32px, 5vw, 80px) var(--pad-x);
  transition: opacity .35s ease;
}

/* Plus de scrim sombre : les frames sont déjà sur fond noir pur */
.st-specs-cabin {
  opacity: 0;               /* masqué au début, piloté par JS */
}

/* Ombre portée subtile pour garder le texte des specs lisible sans scrim */
.specs-transition .st-overlay .spec-row .label,
.specs-transition .st-overlay .spec-row .value {
  text-shadow: 0 1px 8px rgba(0,0,0,.85);
}

/* Sélecteur 4S/6S : épinglé en haut. Affiché AVEC les specs (début/fin) et
   MASQUÉ pendant l'animation des frames (opacité pilotée par frame-scroll.js). */
.specs-transition .st-model-tabs {
  position: absolute;
  top: clamp(80px, 11vh, 130px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: inline-flex;
  gap: clamp(10px, 2vw, 26px);
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(0,0,0,.42);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: opacity .35s ease;
}

.specs-transition .st-model-tabs .tab-btn {
  color: #fff;
}

.specs-transition .st-model-tabs .tab-btn[aria-selected="true"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}

/* UAV (« Unmanned ») — note « In development » sur la zone d'animation.
   Affichée quand l'UAV est sélectionné tant qu'aucune séquence d'images n'est
   fournie ; frame-scroll.js ajoute .uav-ready dès que les frames UAV existent. */
.specs-transition .st-dev-note {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 2;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
body[data-model="uav"] .specs-transition .st-dev-note { display: flex; }
/* frames UAV fournies (.uav-ready) → on masque la note ; sélecteur au moins aussi
   spécifique que la règle « display:flex » ci-dessus pour bien l'emporter. */
body[data-model="uav"] .specs-transition.uav-ready .st-dev-note { display: none; }
.specs-transition .st-dev-note span {
  padding: 12px 26px;
  border: 1.5px dashed rgba(143, 199, 255, .5);
  border-radius: 999px;
  background: rgba(5, 8, 15, .55);
  color: rgba(255, 255, 255, .82);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  font-size: clamp(13px, 1.6vw, 18px);
}

/* Loader léger de la séquence d'images (remplace l'ancien avion filaire).
   Injecté par frame-scroll.js, visible tant qu'aucune frame n'est prête. */
.specs-transition .st-loader {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s ease;
}
.specs-transition .st-loader.show {
  opacity: 1;
}
.specs-transition .st-loader-ring {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 3px solid rgba(143, 199, 255, .22);
  border-top-color: #8FC7FF;
  animation: st-spin .8s linear infinite;
}
@keyframes st-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .specs-transition .st-loader-ring { animation: none; }
}

/* Volet de galerie sans photo (ex. UAV en développement) → note sobre. */
.gallery-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: clamp(180px, 34vw, 340px);
  border: 1.5px dashed rgba(143, 199, 255, .4);
  border-radius: 12px;
  color: rgba(255, 255, 255, .6);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  font-size: clamp(13px, 1.6vw, 18px);
}

/* Specs extérieur : grille 3 colonnes (specs | espace canvas | specs) */
.st-specs-exterior .spec-columns {
  display: grid;
  grid-template-columns: minmax(170px, 1fr) minmax(340px, 2.4fr) minmax(170px, 1fr);
  gap: clamp(12px, 2.2vw, 34px);
  align-items: center;
}

/* Colonne de DROITE alignée à droite : le texte « colle » au fuselage,
   en miroir de la colonne de gauche (uniquement quand les specs flanquent
   l'avion — sous 920px le layout passe en grille 2 colonnes, cf. plus bas). */
@media (min-width: 921px) {
  .st-specs-exterior .spec-columns .spec-list:last-of-type {
    text-align: right;
  }
}

.st-spacer {
  /* espace central transparent : le canvas est visible derrière */
}

/* Specs cabine : centrée à gauche */
.st-cabin-inner {
  max-width: 520px;
}

.st-cabin-inner .spec-list {
  display: grid;
  gap: 16px;
  text-align: left;
}

/* ---- Mobile / tablette : specs sur un BANDEAU DIAGONAL noir translucide ----
   Le rendu avion (canvas) occupe tout l'écran. L'ancienne carte opaque masquait
   l'avion et son sélecteur chevauchait les specs cabine. À la place : les deux
   jeux de specs sont ancrés EN BAS sur un dégradé noir DIAGONAL (transparent en
   haut → noir en bas) qui ne couvre que la moitié basse de l'écran. La photo
   reste visible au-dessus de la diagonale, et le texte des specs est plus petit. */
@media (max-width: 920px) {
  .st-spacer { display: none; }

  /* Bandeau diagonal sombre porté par l'overlay lui-même : le dégradé s'arrête
     avant le haut → l'avion reste visible. L'opacité globale de l'overlay reste
     pilotée par frame-scroll.js (fondu au scroll). */
  .specs-transition .st-specs-exterior,
  .specs-transition .st-specs-cabin {
    justify-content: flex-end;      /* specs ancrées en bas de l'écran */
    align-items: stretch;
    padding: 0 clamp(14px, 5vw, 26px) clamp(26px, 6vh, 48px);
    background: linear-gradient(200deg,
                  rgba(0, 0, 0, 0)   34%,
                  rgba(0, 0, 0, .42) 48%,
                  rgba(0, 0, 0, .74) 66%,
                  rgba(0, 0, 0, .85) 100%);
  }

  /* Plus de carte : simples grilles transparentes posées sur le bandeau. */
  .st-specs-exterior .spec-columns,
  .st-specs-cabin .st-cabin-inner {
    max-width: 520px;
    width: 100%;
    margin: 0 auto;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  /* 8 specs extérieur + 6 specs cabine → grille 2 colonnes compacte */
  .st-specs-exterior .spec-columns,
  .st-specs-cabin .st-cabin-inner .spec-list {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 9px 20px;
    align-items: start;
  }
  .st-specs-exterior .spec-list { display: contents; }

  /* Specs plus petites (labels lisibles, valeurs nettes) + fine séparation. */
  .specs-transition .st-overlay .spec-row .label {
    font-size: 10px;
    letter-spacing: .1em;
  }
  .specs-transition .st-overlay .spec-row .value {
    font-size: clamp(15px, 4.2vw, 19px);
  }
  .specs-transition .st-overlay .spec-list .spec-row {
    padding-bottom: 6px;
    border-bottom: 1px solid rgba(255, 255, 255, .12);
  }
}

@media (prefers-reduced-motion: reduce) {
  .specs-transition {
    height: auto;
  }
  .specs-transition .st-sticky {
    position: relative;
    height: auto;
    min-height: 60vh;
  }
  .st-specs-cabin {
    opacity: 1;
  }
}

/* ============================================================
   Page PROGRAM — frise chronologique accordéon
   ============================================================ */
.program-hero {
  position: relative;
  padding: 0;
  overflow: hidden;
  min-height: min(77vh, 672px);   /* hauteur image +20 % */
}

/* Voile dégradé en haut, DEVANT la photo (sous l'en-tête) → contraste pour la nav. */
.program-hero::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 48%;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(5, 8, 15, .62) 0%, rgba(5, 8, 15, .22) 48%, rgba(5, 8, 15, 0) 100%);
}

.program-hero .media-shell {
  position: absolute;
  inset: 0;
  aspect-ratio: unset;
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
  background: transparent;
  /* pas de boîte sombre : le dégradé de la page reste continu */
}

/* Image : pleine largeur (cover, recadrée), sans surzoom. Le bas se DISSOUT totalement
   via le masque bien avant le bord → l'avion se fond dans le dégradé de la page, sans
   aucune démarcation. (object-fit !important pour battre le style inline du HTML.) */
.program-hero .media-shell>img {
  width: 100%;
  height: 100%;
  object-fit: cover !important;
  object-position: center 48%;             /* avion remonté dans la bande */
  transform: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 38%, rgba(0, 0, 0, 0) 84%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 38%, rgba(0, 0, 0, 0) 84%);
}

.program-hero+section {
  position: relative;
  z-index: 2;
  margin-top: -16vh;
}

.timeline {
  max-width: 1020px;
  margin: 0 auto;
  position: relative;
  padding-left: 62px;
}

.timeline::before {
  /* ligne verticale continue — repli SANS JS uniquement.
     Avec JS, elle laisse place aux segments fragmentés (.tl-seg). */
  content: "";
  position: absolute;
  left: 14px;
  top: 28px;
  bottom: 10px;
  width: 3px;
  background: rgba(255, 255, 255, .4);
}

body.has-js .timeline::before {
  display: none;
}

.timeline .tl-arrow {
  /* la frise se lit du plus ancien (haut) au plus récent (bas) :
     la flèche est en bas et pointe vers l'avenir */
  position: absolute;
  left: 4px;
  bottom: -14px;
  font-size: 26px;
  color: #8FC7FF;
}

.milestone {
  position: relative;
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.milestone::before {
  /* marqueur du jalon : ● atteint / ○ futur */
  content: "";
  position: absolute;
  left: -57px;
  top: 26px;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  border: 3px solid #fff;
  background: #fff;
}

.milestone.future::before {
  background: transparent;
}

.milestone summary,
.milestone .ms-head {
  display: flex;
  align-items: baseline;
  gap: clamp(18px, 2.5vw, 30px);
  padding: clamp(22px, 3.2vw, 40px) 8px;
  cursor: pointer;
  list-style: none;
}

.milestone .ms-head {
  cursor: default;
}

.milestone summary::-webkit-details-marker {
  display: none;
}

.milestone .year {
  font-size: clamp(40px, 5.2vw, 66px);
  line-height: 1;
  font-weight: 700;
  letter-spacing: .04em;
  min-width: clamp(120px, 14vw, 200px);
}

.milestone .label {
  font-size: clamp(24px, 3vw, 40px);
  line-height: 1.05;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  flex: 1;
}

.milestone summary::after {
  content: "›";
  font-size: 34px;
  line-height: 1;
  transform: rotate(0deg);
  transition: transform .3s;
  color: #8FC7FF;
}

.milestone[open] summary::after {
  transform: rotate(90deg);
}

.project-card {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: clamp(22px, 4vw, 48px);
  padding: 10px 8px 34px;
}

@media (max-width: 700px) {
  .project-card {
    grid-template-columns: 1fr;
  }
}

/* Mobile : l'en-tête de jalon (année + titre) doit tenir sans tronquer les
   titres longs. Sur 375px, .label (24px) + .year (min-width 120px) + la
   gouttière de 62px ne laissaient ~110px → « DÉMONSTRATEUR » était coupé.
   On resserre la gouttière, on réduit les tailles et on autorise le wrap. */
@media (max-width: 560px) {
  .timeline {
    padding-left: 42px;
  }
  .timeline::before,
  .tl-seg,
  .tl-peak {
    left: 10px;
  }
  .milestone::before {
    left: -37px;
    top: 22px;
    width: 16px;
    height: 16px;
  }
  .milestone summary,
  .milestone .ms-head {
    gap: 14px;
    padding: 22px 4px;
    align-items: center;
  }
  .milestone .year {
    font-size: clamp(30px, 9vw, 40px);
    min-width: 0;
  }
  .milestone .label {
    font-size: 16px;
    letter-spacing: .04em;
    min-width: 0;
    overflow-wrap: break-word;
    hyphens: auto;
  }
  .milestone summary::after {
    font-size: 26px;
  }
}

.project-card h3 {
  letter-spacing: .14em;
}

.yt-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  text-decoration: underline;
}

.yt-link svg {
  width: 26px;
  height: 18px;
  flex: 0 0 auto;
}

/* ============================================================
   Page PROGRAM — frise vivante au scroll
   Progression à gauche + apparitions des rubriques + indice de scroll.
   Tout est activé par JS (body.has-js / éléments injectés) : sans JS,
   la frise reste entièrement lisible et statique.
   ============================================================ */

/* — Indice de défilement sous le hero : invite à descendre découvrir — */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: clamp(150px, 21vh, 240px);
  transform: translateX(-50%);
  z-index: 3;
  display: grid;
  justify-items: center;
  gap: 12px;
  color: #cfe6ff;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .26em;
  text-transform: uppercase;
  text-decoration: none;
  text-shadow: 0 2px 18px rgba(0, 0, 0, .55);
  transition: opacity .5s ease, transform .5s ease;
}

.scroll-cue:hover { color: #fff; }

.scroll-cue__chevron {
  width: 20px;
  height: 20px;
  border-right: 2px solid #8FC7FF;
  border-bottom: 2px solid #8FC7FF;
  animation: cueBob 1.8s ease-in-out infinite;
}

.scroll-cue.is-hidden {
  opacity: 0;
  transform: translate(-50%, 16px);
  pointer-events: none;
}

@keyframes cueBob {
  0%, 100% { transform: rotate(45deg) translate(0, 0); opacity: .5; }
  50%      { transform: rotate(45deg) translate(3px, 3px); opacity: 1; }
}

/* — Ligne FRAGMENTÉE : un segment par intervalle entre deux jalons (injecté par JS).
     Trait sombre au repos ; un .tl-seg__fill descend = la traînée de la « lueur ».
     Le segment n'apparaît (fondu) qu'une fois sa section / la lueur arrivée. — */
.tl-seg {
  position: absolute;
  left: 14px;
  width: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .2);
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity .6s ease;
}

.tl-seg.is-revealed {
  opacity: 1;
}

.tl-seg__fill {
  position: absolute;
  left: 0;
  top: 0;                    /* la lueur descend : le fill grandit du haut vers le bas */
  width: 100%;
  height: 0;
  border-radius: 2px;
  /* Base blanche (sillage déjà passé) + GRANDE traînée bleue ancrée sur la tête (bas du fill).
     PAS de box-shadow ici : le glow ne doit briller que sur le bleu (porté par .tl-peak),
     pas sur le blanc du sillage. */
  background:
    linear-gradient(180deg,
      rgba(143, 199, 255, 0) 0%,
      rgba(143, 199, 255, .55) 38%,
      rgba(86, 170, 255, .92) 76%,
      #2E9BFF 100%) bottom / 100% 230px no-repeat,
    #ffffff;
  will-change: height;
}

/* Segment entièrement franchi : le sillage vire au BLANC PUR (le bleu s'efface) */
.tl-seg.is-done .tl-seg__fill {
  background: #ffffff;
}

/* — Tête de lueur : une COMÈTE sur la ligne, bornée par deux points (avant + arrière).
     La traînée s'efface vers l'arrière → le glow diminue doucement DERRIÈRE la tête.
     Masquée (fondu) quand la tête est « dans » un checkpoint : c'est le jalon qui s'allume. — */
.tl-peak {
  position: absolute;
  left: 14px;
  width: 3px;                /* largeur du trait → une comète SUR la ligne, pas une pastille */
  height: 88px;              /* longueur de la comète : point avant (bas) → point arrière (haut) */
  border-radius: 2px;
  transform: translateY(-100%);   /* le bas = la position de tête (bord AVANT) */
  /* traînée : la moitié arrière (haut) est TOTALEMENT transparente → la fin ne se voit plus ;
     ne devient lumineuse que près de la tête (bas). */
  background: linear-gradient(180deg,
    rgba(143, 199, 255, 0) 0%,
    rgba(143, 199, 255, 0) 40%,
    rgba(143, 199, 255, .16) 64%,
    rgba(187, 224, 255, .72) 87%,
    #ffffff 100%);
  z-index: 2;
  opacity: 0;
  pointer-events: none;
  transition: opacity .35s ease;   /* apparition / disparition douce */
  will-change: top, opacity;
}

/* POINT AVANT (tête) : éclat vif, glow concentré sur le bleu/blanc de la tête.
   (Pas de point arrière : la traînée s'efface dans le vide.) */
.tl-peak::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -2px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  transform: translateX(-50%);
  background: #ffffff;
  box-shadow: 0 0 12px 4px rgba(143, 199, 255, .95), 0 0 28px 10px rgba(86, 170, 255, .5);
}

/* Orbe GARÉE à 75 % (le prochain jalon n'est pas encore atteint) : au lieu de filer,
   la tête reste en place et PULSE pour signaler « progression en cours ». */
.tl-peak.is-parked::after {
  animation: peakPulse 2.2s ease-in-out infinite;
}

@keyframes peakPulse {
  0%, 100% { transform: translateX(-50%) scale(1);   box-shadow: 0 0 12px 4px rgba(143, 199, 255, .95), 0 0 28px 10px rgba(86, 170, 255, .5); }
  50%      { transform: translateX(-50%) scale(1.5); box-shadow: 0 0 18px 6px rgba(143, 199, 255, 1),   0 0 40px 14px rgba(86, 170, 255, .68); }
}

/* — Voile de fond : même dégradé que <body>, fixé à l'écran, masqué au seul bas (~6 %).
     Tout ce qui émerge en bas se fond dans les couleurs du background. — */
.tl-bottom-fade {
  position: fixed;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background: linear-gradient(180deg, var(--color-night) 0%, var(--color-night-2) 45%, var(--color-accent-dark) 80%, var(--color-primary) 130%);
  -webkit-mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0) 6%);
  mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0) 6%);
}

/* Le voile de bas d'écran (z-index 5, fixe) ne doit pas teinter le footer :
   le footer est opaque et passe AU-DESSUS du voile, qui s'arrête donc net à
   son bord supérieur. Scopé à la page Programme (seule à porter ce voile). */
.page-program .site-footer {
  position: relative;
  z-index: 6;
}

/* — Marqueurs : assourdis par défaut sous JS, ils s'allument au passage du point — */
body.has-js .milestone::before {
  background: rgba(255, 255, 255, .22);
  border-color: rgba(255, 255, 255, .42);
  transition: background .45s ease, border-color .45s ease, box-shadow .45s ease, transform .45s ease;
}

body.has-js .milestone.future::before {
  background: transparent;
}

/* « EN COURS » : anneau bleu + point central, légère pulsation (jalon courant).
   La lueur ne fige PAS ce jalon en blanc — il garde son statut « à venir ». */
body.has-js .milestone.is-current::before {
  background: radial-gradient(circle at center, #8FC7FF 0 34%, transparent 38%);
  border-color: #8FC7FF;
  box-shadow: 0 0 14px 2px rgba(143, 199, 255, .55);
  transform: scale(1.08);
  animation: dotPulse 2.2s ease-in-out infinite;
}

@keyframes dotPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(143, 199, 255, .5), 0 0 12px 2px rgba(143, 199, 255, .5); }
  50%      { box-shadow: 0 0 0 8px rgba(143, 199, 255, 0), 0 0 16px 3px rgba(143, 199, 255, .85); }
}

/* Jalon ATTEINT franchi par la lueur : se fige en BLANC PUR (sillage). */
body.has-js .milestone.is-lit::before {
  background: #fff;
  border-color: #fff;
  box-shadow: 0 0 0 4px rgba(46, 155, 255, .16), 0 0 16px 3px rgba(143, 199, 255, .75);
  transform: scale(1.14);
}

/* IGNITION one-shot : le marqueur s'illumine de l'intérieur vers l'extérieur,
   une seule fois, quand la tête de lueur l'atteint (placé après .is-current
   pour que son animation prenne le pas sur la pulsation). */
body.has-js .milestone.is-igniting::before {
  animation: ignite .62s ease-out;
}

@keyframes ignite {
  0%   { box-shadow: 0 0 0 0 rgba(234, 245, 255, .95), 0 0 0 0 rgba(46, 155, 255, 0);  transform: scale(.88); }
  45%  { box-shadow: 0 0 0 5px rgba(234, 245, 255, .55), 0 0 24px 9px rgba(143, 199, 255, .95); transform: scale(1.32); }
  100% { box-shadow: 0 0 0 13px rgba(143, 199, 255, 0), 0 0 14px 3px rgba(143, 199, 255, .3); transform: scale(1.1); }
}

/* — Apparition des jalons (et fiches projet) au scroll, label en léger décalé — */
body.has-js .milestone {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.22, .61, .36, 1);
}

body.has-js .milestone.in-view {
  opacity: 1;
  transform: none;
}

body.has-js .milestone .year,
body.has-js .milestone .label {
  opacity: 0;
  transform: translateX(-16px);
  transition: opacity .6s ease, transform .6s cubic-bezier(.22, .61, .36, 1);
}

body.has-js .milestone.in-view .year { opacity: 1; transform: none; transition-delay: .1s; }
body.has-js .milestone.in-view .label { opacity: 1; transform: none; transition-delay: .18s; }

body.has-js .project-card {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.22, .61, .36, 1);
}

body.has-js .project-card.in-view {
  opacity: 1;
  transform: none;
}

/* Cascade intra-fiche : le contenu « s'ouvre » progressivement à l'entrée à l'écran */
body.has-js .project-card h3,
body.has-js .project-card .rule,
body.has-js .project-card p,
body.has-js .project-card .yt-link,
body.has-js .project-card .media-shell {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.22, .61, .36, 1);
}

body.has-js .project-card.in-view :is(h3, .rule, p, .yt-link, .media-shell) {
  opacity: 1;
  transform: none;
}

body.has-js .project-card.in-view h3 { transition-delay: .04s; }
body.has-js .project-card.in-view .rule { transition-delay: .10s; }
body.has-js .project-card.in-view .media-shell { transition-delay: .12s; }
body.has-js .project-card.in-view p { transition-delay: .16s; }
body.has-js .project-card.in-view .yt-link { transition-delay: .22s; }

/* — La flèche du futur respire pour appeler à continuer vers le bas — */
body.has-js .timeline .tl-arrow {
  animation: arrowBob 1.9s ease-in-out infinite;
}

@keyframes arrowBob {
  0%, 100% { transform: translateY(0); opacity: .65; }
  50%      { transform: translateY(7px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  body.has-js .milestone,
  body.has-js .milestone .year,
  body.has-js .milestone .label,
  body.has-js .project-card,
  body.has-js .project-card h3,
  body.has-js .project-card .rule,
  body.has-js .project-card p,
  body.has-js .project-card .yt-link,
  body.has-js .project-card .media-shell {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }
  body.has-js .milestone::before { transition: none; }
  .tl-seg { transition: none; }
  .tl-peak { display: none; }
  .scroll-cue__chevron,
  body.has-js .timeline .tl-arrow,
  body.has-js .milestone.is-current::before,
  body.has-js .milestone.is-igniting::before { animation: none; }
}

/* ============================================================
   Page DRAGONFLY — Feuille de route CIRCULAIRE animée
   (frise en cercle ; lueur antihoraire ; rendu repris de la frise Program)
   ============================================================ */
.roadmap {
  position: relative;
  background: linear-gradient(180deg, var(--color-night) 0%, var(--color-night-2) 60%, var(--color-accent-dark) 120%);
  color: #fff;
  padding: clamp(34px, 4vw, 58px) 20px clamp(24px, 3vw, 52px);
  overflow: hidden;
}

/* Boutons 4S/6S CENTRÉS (.tabs/.tab-btn) ; titre descendu et calé à gauche (hors flux) */
.roadmap .section-head {
  position: relative;
  display: flex;
  align-items: center;            /* titre (gauche) + boutons sur la même ligne, en haut */
  min-height: 44px;
  max-width: none;
  margin: 0 0 clamp(6px, 1.5vw, 18px);
  padding: 0 clamp(28px, 5vw, 80px);  /* retrait : le titre n'est plus collé au bord (boutons restent centrés) */
}

.roadmap .ring-title {            /* titre à gauche, en flux, aligné avec les boutons */
  margin: 0;
  color: #fff;
  font-size: clamp(22px, 3vw, 34px);
}

.roadmap .section-head .tabs {   /* boutons centrés, indépendamment du titre */
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

/* Mobile : le titre à gauche + boutons centrés en absolu se chevauchaient (les
   pills tombaient sur « ROADMAP » et sur le haut de la frise). On empile comme
   les autres sections : titre calé À GAUCHE avec son anneau (motif cohérent avec
   Gallery), puis les pills centrées en dessous, le tout dans le flux. */
@media (max-width: 700px) {
  .roadmap .section-head {
    flex-direction: column;
    align-items: flex-start;
    min-height: 0;
    padding: 0;
    gap: 16px;
  }
  .roadmap .section-head .ring-title {
    margin-left: .7em;          /* dégage l'anneau du bord gauche de l'écran */
  }
  .roadmap .section-head .tabs {
    position: static;
    left: auto;
    transform: none;
    align-self: center;         /* pills centrées, indépendamment du titre à gauche */
    justify-content: center;
  }
}

/* Scène : aspect-ratio calé sur le viewBox → les overlays HTML (positionnés en %)
   s'alignent exactement sur la géométrie SVG. */
.roadmap-stage {
  position: relative;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  aspect-ratio: 1200 / 650;
}

.rm-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;     /* les halos de glow ne sont pas rognés */
  z-index: 0;
}

/* — Lignes de l'arc — */
.rm-line {
  fill: none;
  stroke: rgba(255, 255, 255, .22);
  stroke-width: 3;
  stroke-linecap: round;
}

.rm-future {                 /* segments « à venir » : pointillés discrets */
  fill: none;
  stroke: rgba(255, 255, 255, .5);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-dasharray: 1.5 13;
}

.rm-trail {                  /* sillage : blanc pur derrière la lueur */
  fill: none;
  stroke: #fff;
  stroke-width: 3.4;
  stroke-linecap: round;
}

.rm-comet {                  /* comète : dégradé proportionnel (transparent → bleu), porté par JS */
  fill: none;
  stroke-width: 4;
  stroke-linecap: round;
  filter: drop-shadow(0 0 6px rgba(86, 170, 255, .85));
}

/* — Avion central (vue de dessus) — */
.rm-center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 32%;              /* reste à l'intérieur de l'anneau de points (~ comme la référence) */
  max-width: 360px;
  z-index: 1;
  pointer-events: none;
}

.rm-center img {
  width: 100%;
  height: auto;
  display: block;
  object-fit: contain;
  /* Le 6S est quasi noir sur le fond sombre de la roadmap : un halo qui suit la
     silhouette détache l'avion du fond. Quasi invisible sur le 4S blanc, qui ne
     gagne qu'une légère lueur bleue. */
  filter: drop-shadow(0 0 7px rgba(255, 255, 255, .42)) drop-shadow(0 0 22px rgba(143, 199, 255, .22));
}

/* Placeholder « en attente d'une vue de dessus 4S/6S » */
.rm-center--pending {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  width: 34%;
  max-width: 360px;
  aspect-ratio: 16 / 9;
  padding: 10px 18px;
  border: 1.5px dashed rgba(143, 199, 255, .45);
  border-radius: 12px;
  color: rgba(255, 255, 255, .6);
  font-size: clamp(11px, 1.2vw, 15px);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* — Checkpoints (mêmes états visuels que les marqueurs de Program) — */
.rm-dot {
  position: absolute;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;       /* centrage sur (left, top) */
  border-radius: 50%;
  background: rgba(255, 255, 255, .2);
  border: 2px solid rgba(255, 255, 255, .42);
  z-index: 3;
  transition: background .45s ease, border-color .45s ease, box-shadow .45s ease, transform .45s ease;
}

.rm-dot.is-igniting { animation: ignite .62s ease-out; }    /* @keyframes ignite : défini plus haut */

.rm-dot.is-lit {                 /* jalon atteint franchi → blanc pur */
  background: #fff;
  border-color: #fff;
  box-shadow: 0 0 0 4px rgba(46, 155, 255, .16), 0 0 16px 3px rgba(143, 199, 255, .75);
  transform: scale(1.14);
}

.rm-dot--future { background: transparent; border-color: #8FC7FF; }   /* à venir → anneau bleu */

.rm-dot--current {               /* prochain jalon : anneau + point central pulsant */
  background: radial-gradient(circle at center, #8FC7FF 0 34%, transparent 38%);
  border-color: #8FC7FF;
  box-shadow: 0 0 14px 2px rgba(143, 199, 255, .55);
  transform: scale(1.08);
  animation: dotPulse 2.2s ease-in-out infinite;     /* @keyframes dotPulse : défini plus haut */
}

/* — Lueur (tête) : même éclat que la comète de Program — */
.rm-glow {
  position: absolute;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 12px 4px rgba(143, 199, 255, .95), 0 0 30px 12px rgba(86, 170, 255, .55);
  opacity: 0;
  z-index: 5;
  pointer-events: none;
  transition: opacity .3s ease;
}

.rm-glow.is-on { opacity: 1; }

/* Lueur GARÉE à 75 % (prochain jalon pas encore atteint) : reste visible et PULSE. */
.rm-glow.is-parked {
  opacity: 1;
  animation: glowPulse 2.2s ease-in-out infinite;
}

@keyframes glowPulse {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 12px 4px rgba(143, 199, 255, .95), 0 0 30px 12px rgba(86, 170, 255, .55); }
  50%      { transform: scale(1.32); box-shadow: 0 0 18px 6px rgba(143, 199, 255, 1),   0 0 44px 18px rgba(86, 170, 255, .72); }
}

/* point ARRIÈRE de la comète (queue) — plus discret que la tête */
.rm-glow-back {
  position: absolute;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: rgba(143, 199, 255, .9);
  box-shadow: 0 0 8px 2px rgba(86, 170, 255, .5);
  opacity: 0;
  z-index: 4;
  pointer-events: none;
  transition: opacity .3s ease;
}

.rm-glow-back.is-on { opacity: 1; }

/* — Libellés (année + intitulé) positionnés autour du cercle — */
.rm-label {
  position: absolute;
  display: flex;
  flex-direction: column;        /* année et titre sur DEUX lignes séparées (plus lisible, surtout mobile) */
  gap: .2em;
  white-space: nowrap;
  z-index: 2;
  pointer-events: none;
  line-height: 1.1;
}

.rm-label .yr {                /* l'année est SECONDAIRE → plus petite que le libellé */
  font-weight: 700;
  font-size: clamp(15px, 1.6vw, 24px);
  line-height: 1;
  color: rgba(255, 255, 255, .82);
}

.rm-label .lb {                /* le libellé est l'écriture PRINCIPALE → plus grand */
  font-size: clamp(17px, 2.1vw, 31px);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 18px rgba(143, 199, 255, .35);
}

/* côté droit : label ancré à GAUCHE du point → année au-dessus du titre, aligné à gauche */
.rm-label--right { transform: translate(0, -50%); align-items: flex-start; text-align: left; }
/* côté gauche : label ancré à DROITE du point → année au-dessus du titre, aligné à droite */
.rm-label--left { transform: translate(-100%, -50%); align-items: flex-end; text-align: right; }
/* bas / haut : empilé et centré */
.rm-label--bottom { transform: translate(-50%, 0); text-align: center; align-items: center; }
.rm-label--top { transform: translate(-50%, -100%); text-align: center; align-items: center; }

/* — Repli sans JS : simple liste lisible (masquée dès que la frise est construite) — */
.rm-fallback {
  list-style: none;
  margin: 28px auto 0;
  padding: 0;
  max-width: 520px;
  display: grid;
  gap: 8px;
  color: rgba(255, 255, 255, .9);
}

.rm-fallback strong { color: #fff; margin-right: .4em; }

.roadmap.is-ready .rm-fallback { display: none; }

@media (max-width: 720px) {
  /* sur mobile, on réduit mais on garde le libellé plus grand que l'année */
  .rm-label .yr { font-size: clamp(11px, 2.6vw, 15px); }
  .rm-label .lb { font-size: clamp(12px, 3.2vw, 17px); }
}

/* ============================================================
   Frise Dragonfly — VARIANTE MOBILE VERTICALE (≤700px)
   circular-timeline.js construit une frise verticale et pose .is-vertical sur
   .roadmap-stage. La hauteur est FIXE (50% de l'écran) quel que soit le nombre
   de jalons : ils se répartissent dedans (JS lit clientWidth/Height en px).
   Plus d'avion central ; libellé à droite du point : TITRE au-dessus, année en dessous.
   ============================================================ */
@media (max-width: 700px) {
  .roadmap-stage.is-vertical {
    max-width: 460px;
    height: 50vh;          /* arc de taille FIXE = 50% de la hauteur de l'écran */
    aspect-ratio: auto;    /* neutralise l'aspect-ratio du cercle (desktop) */
  }
  /* plus de vue de dessus au centre en mobile */
  .roadmap-stage.is-vertical .rm-center,
  .roadmap-stage.is-vertical .rm-center--pending { display: none; }

  .rm-label--v {
    align-items: flex-start;      /* aligné à gauche, contre le point */
    text-align: left;
    gap: .12em;
    max-width: 66%;               /* borne : les titres longs passent à la ligne */
    white-space: normal;          /* override du nowrap de base → wrap autorisé */
    transform: translateY(-50%);  /* centré verticalement sur le point */
  }
  .rm-label--v .lb {
    font-size: clamp(13px, 3.6vw, 17px);
    line-height: 1.12;
    text-shadow: 0 2px 14px rgba(143, 199, 255, .3);
  }
  .rm-label--v .yr {
    font-size: clamp(11px, 3vw, 14px);
    color: rgba(255, 255, 255, .58);
  }
}

@media (prefers-reduced-motion: reduce) {
  .rm-glow { display: none; }
  .rm-comet { display: none; }
  .rm-dot.is-igniting { animation: none; }
  .rm-dot--current { animation: none; }
}

/* ============================================================
   Page TEAM
   ============================================================ */
.team-panel {
  background: #fff;
  color: var(--color-ink);
  border-radius: 10px;
  padding: clamp(32px, 5vw, 72px);
  max-width: 1180px;
  margin: 0 auto;
}

.team-panel .ring-title {
  color: var(--color-ink);
}

.team-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(22px, 3vw, 40px);
  margin-top: 38px;
}

/* team-grid : 3 col > 920 ; 2 col ≤ 920 (puis flex 2 col ≤ 700 via team-sections.css).
   L'ancienne règle « 1 col ≤ 540 » était morte (display:flex de team-sections gagne). */
@media (max-width: 920px) {
  .team-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.member {
  display: grid;
  gap: 10px;
}

.member .name {
  font-weight: 700;
  font-size: 18px;
  letter-spacing: .04em;
}

.member .role {
  font-family: "Courier New", monospace;
  font-size: 13.5px;
  color: #5a636d;
  letter-spacing: .02em;
}

/* ============================================================
   Page PRESS
   ============================================================ */
.press-hero {
  padding: 0;
}

.press-hero .media-shell {
  border-radius: 0;
  aspect-ratio: 21 / 7;
  min-height: 320px;
}

/* ============================================================
   Divers
   ============================================================ */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: #fff;
  color: var(--color-ink);
  padding: 10px 18px;
}

.skip-link:focus {
  left: 0;
}

:focus-visible {
  outline: 2px solid #8FC7FF;
  outline-offset: 2px;
}

/* ============================================================
   Pages LÉGALES — Mentions légales & Politique de confidentialité
   Long texte lisible sur le dégradé sombre : colonne étroite (mesure
   confortable), carte translucide, interlignage aéré. Réutilise
   .ring-title et .rule du design system.
   ============================================================ */
.legal-wrap {
  max-width: 760px;
  margin: 0 auto;
}

/* Le titre démarre SOUS l'en-tête fixe (--header-h) */
.legal-hero {
  padding-top: calc(var(--header-h) + clamp(28px, 6vh, 64px));
  padding-bottom: 0;
}

.legal-hero h1 {
  margin-bottom: .4em;
}

.legal-updated {
  margin: 0;
  font-size: var(--fs-btn);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--color-grey);
}

.legal-body {
  padding-top: clamp(30px, 5vh, 56px);
}

.legal-card {
  background: rgba(255, 255, 255, .045);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--radius-card);
  padding: clamp(26px, 5vw, 60px);
}

.legal-card h2 {
  font-size: var(--fs-h2);
  margin: 1.9em 0 .7em;
}

.legal-card h2:first-child {
  margin-top: 0;
}

.legal-card h3 {
  font-size: var(--fs-h3);
  color: #8FC7FF;
  margin: 1.5em 0 .5em;
}

.legal-card p,
.legal-card li {
  line-height: 1.75;
  color: rgba(255, 255, 255, .86);
}

.legal-card ul {
  margin: 0 0 1.2em;
  padding-left: 1.25em;
}

.legal-card li {
  margin-bottom: .5em;
}

.legal-card li::marker {
  color: #8FC7FF;
}

.legal-card a {
  color: #8FC7FF;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.legal-card a:hover {
  color: #fff;
}

.legal-card strong {
  color: #fff;
  letter-spacing: .02em;
}

/* Encadré « coordonnées » : éditeur, hébergeur, exercice des droits */
.legal-meta {
  margin: 0 0 1.4em;
  padding: 16px 22px;
  border-left: 3px solid var(--color-primary);
  background: rgba(19, 104, 191, .12);
  border-radius: 0 var(--radius-card) var(--radius-card) 0;
  font-style: normal;
  line-height: 1.85;
  color: rgba(255, 255, 255, .9);
}

.legal-meta strong {
  letter-spacing: .04em;
}

/* ============================================================
   FAQ (page Concept) — cartes translucides dépliables en accordéon.
   La page Concept est en fond NOIR (séquence) : la section FAQ pose
   donc son PROPRE dégradé, raccordé au noir en haut puis coulé vers
   le bleu du site (comme le dégradé global du body). Contenu piloté
   par le CMS → assets/js/faq.js / assets/data/faq.json.
   ============================================================ */
.faq {
  position: relative;
  isolation: isolate;   /* stacking context propre → le canvas « grille + halos »
                           (grid-glow.js, z-index:-1) s'affiche PAR-DESSUS ce dégradé
                           et DERRIÈRE le contenu (sinon le fond opaque le masquerait). */
  padding: clamp(70px, 12vh, 150px) var(--pad-x) clamp(90px, 16vh, 190px);
  background: linear-gradient(180deg,
    #000 0%,
    var(--color-night) 7%,
    var(--color-night-2) 42%,
    var(--color-accent-dark) 80%,
    var(--color-primary) 125%);
}

.faq-inner {
  position: relative;   /* passe au-dessus du fond animé (grille + halos) */
  z-index: 1;
  max-width: none;   /* pleine largeur : les gouttières = le padding de la section */
  margin: 0;         /* titre calé au bord gauche (var(--pad-x)), comme la home */
}

/* Ordinateur : 2 colonnes — questions à gauche, visuel Dragonfly à droite
   (comble le vide, dans l'esprit de la section « Our partners » de l'accueil). */
.faq-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(30px, 5vw, 80px);
  align-items: center;
}

.faq-visual {
  margin: 0;
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .4);
  aspect-ratio: 4 / 3;
  background: rgba(255, 255, 255, .04);
}

.faq-visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Titre : même format que l'accueil (.ring-title = bulle/anneau derrière),
   aligné à GAUCHE comme sur la home, à l'échelle de la page Concept (+25 %). */
.faq .ring-title {
  margin: 0 0 clamp(38px, 6vh, 70px);
  font-size: calc(var(--fs-h2) * 1.25);
}

.faq-list {
  display: flex;
  flex-direction: column;
  gap: clamp(12px, 1.8vh, 18px);
  max-width: 820px;   /* longueur de ligne confortable même dans une colonne large */
}

/* Carte : rectangle à coins arrondis, blanchâtre translucide — le dégradé
   du fond transparaît derrière. */
.faq-item {
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 14px;
  background: rgba(255, 255, 255, .06);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  transition: background .3s ease, border-color .3s ease, box-shadow .3s ease, transform .3s ease;
}

/* Question = bouton pleine largeur (intitulé + chevron). */
.faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: clamp(15px, 2.2vw, 22px) clamp(18px, 2.6vw, 28px);
  background: none;
  border: 0;
  color: #fff;
  font-family: inherit;
  font-size: clamp(20px, 2.5vw, 28px);
  font-weight: 700;
  letter-spacing: .01em;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
}

.faq-q-text {
  flex: 1 1 auto;
}

.faq-chevron {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  color: #8FC7FF;
  background: rgba(143, 199, 255, .12);
  transition: transform .42s cubic-bezier(.4, 0, .2, 1), background .3s ease;
}

.faq-item.open .faq-chevron {
  transform: rotate(180deg);
  background: rgba(143, 199, 255, .22);
}

/* Survol réservé aux POINTEURS FINS (ordinateur) — léger relief + lueur.
   Sur tactile, aucun effet de survol parasite (cf. distinction PC/téléphone). */
@media (hover: hover) and (pointer: fine) {
  .faq-item:hover {
    background: rgba(255, 255, 255, .09);
    border-color: rgba(143, 199, 255, .45);
    box-shadow: 0 10px 34px rgba(19, 104, 191, .22);
    transform: translateY(-2px);
  }

  .faq-item:hover .faq-chevron {
    background: rgba(143, 199, 255, .2);
  }
}

/* Carte ouverte : bordure bleutée + fond légèrement plus dense. */
.faq-item.open {
  background: rgba(255, 255, 255, .085);
  border-color: rgba(143, 199, 255, .5);
  box-shadow: 0 12px 40px rgba(19, 104, 191, .24);
}

.faq-q:focus-visible {
  outline: 2px solid #8FC7FF;
  outline-offset: 3px;
  border-radius: 12px;
}

/* Panneau réponse : hauteur animée en douceur via grid 0fr → 1fr (fluide
   quel que soit le volume de texte, s'adapte au redimensionnement). */
.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .42s cubic-bezier(.4, 0, .2, 1);
}

.faq-item.open .faq-a {
  grid-template-rows: 1fr;
}

.faq-a-inner {
  overflow: hidden;
  min-height: 0;                /* indispensable pour que l'enfant grid se réduise à 0 */
  opacity: 0;
  transition: opacity .3s ease;
}

.faq-item.open .faq-a-inner {
  opacity: 1;
  transition: opacity .35s ease .12s;
}

/* Le padding vit ICI (dans l'élément clippé), PAS sur .faq-a-inner : sinon le
   padding-bottom subsiste une fois le panneau replié (grille 0fr) et décale la
   question vers le haut. Ainsi carte fermée = juste le bouton → question centrée. */
.faq-a-body {
  padding: 0 clamp(18px, 2.6vw, 28px) clamp(18px, 2.6vw, 26px);
}

.faq-a-body > :first-child {
  margin-top: 0;
}

.faq-a p {
  margin: 0 0 .9em;
  font-size: clamp(16px, 1.9vw, 22px);
  line-height: 1.7;
  color: rgba(255, 255, 255, .85);
}

.faq-a p:last-child {
  margin-bottom: 0;
}

/* Liens optionnels en fin de réponse (redirection article). */
.faq-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}

.faq-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border: 1px solid rgba(143, 199, 255, .4);
  border-radius: var(--radius-pill);
  color: #8FC7FF;
  font-size: var(--fs-btn);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  transition: background .25s ease, border-color .25s ease, color .25s ease;
}

.faq-link::after {
  content: "→";
  font-size: 1.1em;
  transition: transform .25s ease;
}

.faq-link:hover {
  background: rgba(143, 199, 255, .14);
  border-color: #8FC7FF;
  color: #fff;
}

.faq-link:hover::after {
  transform: translateX(3px);
}

/* Tablette / petit écran : on repasse en 1 colonne et on masque le visuel
   (la FAQ reste compacte, comme sur mobile). */
@media (max-width: 920px) {
  .faq-layout {
    grid-template-columns: 1fr;
  }

  .faq-visual {
    display: none;
  }

  .faq-list {
    max-width: none;
  }
}

/* Téléphone : pleine largeur, zones de tap généreuses, chevron compact. */
@media (max-width: 700px) {
  .faq-q {
    gap: 12px;
    padding: 15px 16px;
    font-size: 20px;
  }

  .faq-a-body {
    padding-left: 16px;
    padding-right: 16px;
  }

  .faq-chevron {
    width: 26px;
    height: 26px;
  }
}

/* Respect de la préférence « animations réduites ». */
@media (prefers-reduced-motion: reduce) {

  .faq-item,
  .faq-a,
  .faq-a-inner,
  .faq-chevron,
  .faq-link,
  .faq-link::after {
    transition: none;
  }
}