/* ============================================================
   FOND SPATIAL + RENFORT SCIENCE-FICTION (Franck, 30/09/2026)
   Gabarit du hub SEUL : tout est rangé sous body.sf (base.html.twig). L'espace client,
   le suivi public et la note secrète chargent aussi app.css : ils n'en héritent pas.
   Les règles passent par :where(.sf) pour garder la spécificité d'origine — une carte
   qui a sa propre couleur (.card.hud, alertes…) la garde.
   ============================================================ */

/* ---------- Le ciel ---------- */
body.sf {
  background-color: #03050b;
  background-image:
    radial-gradient(120% 85% at 50% -5%, #0b1428 0%, #070b18 42%, #03050b 100%),
    repeating-linear-gradient(0deg, rgba(120, 190, 255, .012) 0 1px, transparent 1px 44px),
    repeating-linear-gradient(90deg, rgba(120, 190, 255, .012) 0 1px, transparent 1px 44px);
  background-blend-mode: normal, screen, screen;
  background-attachment: fixed;
}
.espace-fond { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.espace-fond canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Nébuleuses : voiles colorés qui glissent et respirent sur 90 s (couche composée par la
   carte graphique : le processeur ne la redessine pas). */
.espace-nebuleuse {
  position: absolute; inset: -18%;
  background:
    radial-gradient(34% 28% at 80% 16%, var(--neb1, rgba(53, 208, 242, .30)), transparent 70%),
    radial-gradient(30% 26% at 16% 84%, var(--neb2, rgba(124, 108, 246, .32)), transparent 72%),
    radial-gradient(26% 20% at 60% 62%, var(--neb3, rgba(214, 90, 200, .13)), transparent 70%),
    radial-gradient(22% 18% at 30% 28%, rgba(53, 208, 242, .12), transparent 70%),
    radial-gradient(20% 16% at 88% 70%, rgba(124, 108, 246, .14), transparent 70%),
    radial-gradient(50% 14% at 50% 48%, rgba(160, 200, 255, .05), transparent 75%);
  animation: nebuleuse 90s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes nebuleuse {
  from { transform: translate3d(0, 0, 0) scale(1) rotate(0deg); }
  to { transform: translate3d(-3%, 2.5%, 0) scale(1.08) rotate(3deg); }
}
/* NÉBULEUSE PEINTE (Franck, 18/10/2026 : « meilleurs graphismes pour […] les objets stellaires ») : fond-astres.js peint
   la nébuleuse du système (bruit fractal, filaments, poussière sombre) dans #klNebuleuse, en basse définition — elle
   est floue par nature, la carte graphique l'agrandit. Elle apparaît en fondu (neb-gl) par-dessus les voiles. */
.espace-nebuleuse canvas { opacity: 0; transition: opacity 1.4s ease-out; }
.espace-fond.neb-gl .espace-nebuleuse canvas { opacity: .8; }
/* Poussières au premier plan : elles traversent l'écran en diagonale, vite (on avance).
   Transformations seules : la carte graphique les compose, le processeur ne fait rien. */
.espace-poussiere { position: absolute; inset: 0; }
.espace-poussiere i {
  position: absolute; left: 100%; top: 100%; width: 7px; height: 7px; border-radius: 50%;
  background: radial-gradient(circle, rgba(200, 235, 255, .5), rgba(120, 200, 255, 0) 70%);
  animation: poussiere 9s linear infinite; will-change: transform; opacity: .7;
}
.espace-poussiere i:nth-child(1) { top: 70%; animation-duration: 8s; animation-delay: -1s; }
.espace-poussiere i:nth-child(2) { top: 95%; left: 60%; animation-duration: 11s; animation-delay: -6s; width: 10px; height: 10px; }
.espace-poussiere i:nth-child(3) { top: 40%; animation-duration: 7s; animation-delay: -3s; width: 5px; height: 5px; }
.espace-poussiere i:nth-child(4) { top: 105%; left: 30%; animation-duration: 12s; animation-delay: -9s; }
.espace-poussiere i:nth-child(5) { top: 85%; animation-duration: 9.5s; animation-delay: -4.5s; width: 12px; height: 12px; opacity: .45; }
.espace-poussiere i:nth-child(6) { top: 55%; animation-duration: 6.5s; animation-delay: -2s; width: 4px; height: 4px; }
.espace-poussiere i:nth-child(7) { top: 110%; left: 80%; animation-duration: 10s; animation-delay: -7.5s; }
.espace-poussiere i:nth-child(8) { top: 30%; animation-duration: 8.5s; animation-delay: -5.5s; width: 6px; height: 6px; }
.espace-poussiere i:nth-child(9) { top: 100%; left: 45%; animation-duration: 13s; animation-delay: -11s; width: 9px; height: 9px; opacity: .5; }
.espace-poussiere i:nth-child(10) { top: 65%; animation-duration: 7.5s; animation-delay: -0.5s; }
@keyframes poussiere { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-120vw, -44vw, 0); } }
@media (max-width: 767px) { .espace-poussiere i:nth-child(n+6) { display: none; } }
/* Module SAUT : au doigt sur grand écran, une zone plus haute. */
@media (min-width: 900px) and (pointer: coarse) { :where(.sf) .hyper { height: 42px; padding-bottom: 8px; } }
/* ---------- Saut dans l'hyperespace (Franck, 07/10/2026) ----------
   public/js/fond-spatial.js : les étoiles s'étirent en traits (canevas) ; ici, le reste. « Réduire les animations » :
   simple fondu (saut-fondu). Couleurs des nébuleuses : --neb1..3 posées par le lieu.

   SAUT CONTINU (Franck, 14/10/2026 : « L'animation du saut fige toujours 1 seconde lors du chargement, il faut aucun
   arrêt de l'animation, et il faut rendre l'animation plus réaliste ») : depuis le tableau de bord, changer de contexte
   ne recharge plus la page (public/js/navigation-douce.js). Phases, posées en classes sur .espace-fond :
   - saut-depart (0,6 s) : planètes et trafic filent vers l'avant et s'effacent, nébuleuses et poussières s'éteignent,
     la lueur du point de fuite monte ; les étoiles accélèrent (canevas) ;
   - saut-tunnel : le TUNNEL D'HYPERESPACE, tant que la page demandée n'est pas arrivée. Transformations et opacité
     seules, sur des calques à part : la carte graphique l'anime MÊME quand le fil principal travaille (réponse lue,
     contenu remplacé, page qui se charge) ;
   - éclair : le voile .saut-voile (au-dessus de tout) monte au blanc, le contenu change dessous ;
   - saut-arrivee (sans transition) : le nouveau système, encore loin et invisible ; saut-retour : il se rapproche,
     le tunnel s'efface (saut-tunnel-sortie : il tourne encore en s'effaçant) ;
   - saut-entree : page d'ARRIVÉE d'une navigation classique (autres pages, replis), posée avant le premier rendu par
     le script de _espace.html.twig : elle s'ouvre en plein tunnel et n'en sort qu'une fois ses astres prêts. Des
     ANIMATIONS (et non des transitions) pour le tunnel : même sans fond-spatial.js, le filet du script le retire. */
.espace-fond #klPlanetes, .espace-fond #klTrafic { transform-origin: 50% 44%; }
.espace-saut {
  position: absolute; inset: 0; opacity: 0; pointer-events: none; transition: opacity .9s ease-out;
  background:
    radial-gradient(circle at 50% 44%, rgba(235, 248, 255, .95) 0, rgba(150, 210, 255, .55) 7%, rgba(80, 130, 255, .18) 28%, rgba(10, 20, 60, 0) 60%),
    radial-gradient(circle at 50% 44%, transparent 42%, rgba(0, 4, 18, .6) 100%);
}
.espace-fond.saut-depart .espace-saut { opacity: .6; transition: opacity .6s cubic-bezier(.6, 0, .9, .4); }
.espace-fond:is(.saut-tunnel, .saut-entree) .espace-saut { opacity: .42; transition: opacity .3s; }
/* Éclair DERRIÈRE le contenu (arrivée d'une navigation classique, saut sans changement de page) : la lueur monte au
   blanc, puis retombe avec la transition de base (0,9 s). */
.espace-fond.saut-eclair-fond .espace-saut { opacity: 1; transition: opacity .15s cubic-bezier(.6, 0, .9, .4); }
.espace-fond.saut-depart #klPlanetes { transform: scale(1.9); opacity: 0; filter: blur(2px); transition: transform .6s cubic-bezier(.6, 0, .9, .35), opacity .5s ease-in .1s, filter .6s; }
.espace-fond.saut-depart #klTrafic { opacity: 0; transition: opacity .35s; }
.espace-fond.saut-depart .espace-nebuleuse { opacity: 0; transition: opacity .55s ease-in; }
.espace-fond.saut-depart .espace-poussiere { opacity: 0; transition: opacity .4s; }
.espace-fond.saut-arrivee #klPlanetes { transform: scale(.55); opacity: 0; transition: none; }
.espace-fond.saut-arrivee #klTrafic, .espace-fond.saut-arrivee .espace-nebuleuse, .espace-fond.saut-arrivee .espace-poussiere { opacity: 0; transition: none; }
.espace-fond.saut-retour .espace-nebuleuse { transition: opacity 1.8s ease-out; }
.espace-fond.saut-retour #klTrafic, .espace-fond.saut-retour .espace-poussiere { transition: opacity 1.3s ease-out .5s; }
.espace-fond.saut-fondu #klPlanetes, .espace-fond.saut-fondu .espace-nebuleuse { opacity: 0; transition: opacity .3s; }

/* Le TUNNEL : trois couronnes de traînées lumineuses qui grossissent et s'effacent en décalé (on file vers le point de
   fuite), l'ensemble tourne doucement ; au centre, la lueur bleutée qui palpite. Image des traînées tirée au hasard
   par fond-spatial.js (--tunnel) ; à défaut (page qui arrive, avant tout script), trois éventails CSS aux pas
   incommensurables. Bords rouges et bleus : légère aberration chromatique de la verrière. */
.espace-tunnel { position: absolute; inset: 0; opacity: 0; pointer-events: none; overflow: hidden; contain: strict; transition: opacity .45s ease-out; }
.espace-tunnel-rot { position: absolute; inset: 0; transform-origin: 50% 44%; }
.espace-tunnel i, .espace-tunnel b { position: absolute; left: 50%; top: 44%; display: block; border-radius: 50%; opacity: 0; }
.espace-tunnel i {
  width: 84vmax; height: 84vmax; margin: -42vmax 0 0 -42vmax;
  background: var(--tunnel,
    repeating-conic-gradient(from 3deg, rgba(160, 210, 255, 0) 0deg 2.1deg, rgba(255, 140, 170, .22) 2.3deg, rgba(232, 244, 255, .9) 2.45deg, rgba(110, 170, 255, .34) 2.6deg, rgba(160, 210, 255, 0) 2.8deg 7.3deg),
    repeating-conic-gradient(from 1deg, rgba(0, 0, 0, 0) 0deg 4.1deg, rgba(190, 225, 255, .55) 4.25deg, rgba(0, 0, 0, 0) 4.4deg 11.9deg),
    repeating-conic-gradient(from 5deg, rgba(0, 0, 0, 0) 0deg 1.3deg, rgba(140, 195, 255, .38) 1.4deg, rgba(0, 0, 0, 0) 1.5deg 5.3deg));
  background-size: cover;
  -webkit-mask: radial-gradient(closest-side, transparent 9%, #000 34%, #000 70%, transparent 100%);
  mask: radial-gradient(closest-side, transparent 9%, #000 34%, #000 70%, transparent 100%);
  will-change: transform, opacity;
}
.espace-tunnel b {
  width: 46vmax; height: 46vmax; margin: -23vmax 0 0 -23vmax;
  background: radial-gradient(circle, rgba(236, 248, 255, .85) 0, rgba(150, 205, 255, .5) 12%, rgba(80, 120, 255, .16) 38%, rgba(10, 20, 60, 0) 68%);
  will-change: transform, opacity;
}
.espace-fond:is(.saut-tunnel, .saut-entree, .saut-tunnel-sortie) .espace-tunnel-rot { animation: tunnel-rotation 16s linear infinite; }
.espace-fond:is(.saut-tunnel, .saut-entree, .saut-tunnel-sortie) .espace-tunnel i:nth-child(1) { animation: tunnel-fuite-1 1.15s linear infinite; }
.espace-fond:is(.saut-tunnel, .saut-entree, .saut-tunnel-sortie) .espace-tunnel i:nth-child(2) { animation: tunnel-fuite-2 1.15s linear -.38s infinite; }
.espace-fond:is(.saut-tunnel, .saut-entree, .saut-tunnel-sortie) .espace-tunnel i:nth-child(3) { animation: tunnel-fuite-3 1.15s linear -.77s infinite; }
.espace-fond:is(.saut-tunnel, .saut-entree, .saut-tunnel-sortie) .espace-tunnel b { animation: tunnel-coeur .7s ease-in-out infinite alternate; }
.espace-fond:is(.saut-tunnel, .saut-entree) .espace-tunnel { opacity: .92; transition: opacity .3s ease-in; }
@keyframes tunnel-rotation { to { transform: rotate(360deg); } }
@keyframes tunnel-fuite-1 { 0% { transform: scale(.32) rotate(0deg); opacity: 0; } 22% { opacity: 1; } 70% { opacity: .9; } 100% { transform: scale(2.7) rotate(9deg); opacity: 0; } }
@keyframes tunnel-fuite-2 { 0% { transform: scale(.32) rotate(121deg); opacity: 0; } 22% { opacity: 1; } 70% { opacity: .9; } 100% { transform: scale(2.7) rotate(130deg); opacity: 0; } }
@keyframes tunnel-fuite-3 { 0% { transform: scale(.32) rotate(242deg); opacity: 0; } 22% { opacity: 1; } 70% { opacity: .9; } 100% { transform: scale(2.7) rotate(251deg); opacity: 0; } }
@keyframes tunnel-coeur { from { transform: scale(.82); opacity: .6; } to { transform: scale(1.08); opacity: 1; } }
/* Parois du tunnel (18/10/2026) : voiles bleu-violet qui tournent en sens inverse des traînées, la profondeur du tube. */
.espace-tunnel s {
  position: absolute; left: 50%; top: 44%; display: block; width: 110vmax; height: 110vmax; margin: -55vmax 0 0 -55vmax; border-radius: 50%; opacity: 0;
  background: conic-gradient(from 10deg, rgba(80, 120, 255, 0), rgba(120, 90, 255, .2) 40deg, rgba(60, 170, 255, .06) 95deg, rgba(150, 110, 255, .22) 150deg,
    rgba(70, 140, 255, .05) 205deg, rgba(110, 90, 255, .18) 260deg, rgba(60, 190, 255, .1) 310deg, rgba(80, 120, 255, 0) 360deg);
  -webkit-mask: radial-gradient(closest-side, transparent 10%, #000 36%, #000 66%, transparent 100%);
  mask: radial-gradient(closest-side, transparent 10%, #000 36%, #000 66%, transparent 100%);
  transition: opacity .4s;
}
.espace-fond:is(.saut-tunnel, .saut-entree, .saut-tunnel-sortie) .espace-tunnel s { opacity: 1; animation: tunnel-paroi 7s linear infinite; }
@keyframes tunnel-paroi { to { transform: rotate(-360deg); } }
/* SECOUSSE au passage en hyperespace (18/10/2026), avec la détonation du son : le ciel tremble une fois. */
.espace-fond.saut-tunnel #klEspace { animation: saut-secousse .55s cubic-bezier(.2, .7, .3, 1) 1; }
@keyframes saut-secousse {
  0% { transform: translate3d(0, 0, 0); } 10% { transform: translate3d(-6px, 4px, 0); } 24% { transform: translate3d(5px, -3px, 0); }
  40% { transform: translate3d(-3px, 2px, 0); } 58% { transform: translate3d(2px, -1px, 0); } 100% { transform: translate3d(0, 0, 0); }
}
/* ONDES DU SAUT (18/10/2026) : la CHARGE — un anneau se resserre sur le point de fuite pendant le départ (0,6 s, au
   rythme du son qui monte) ; l'ONDE DE CHOC — au passage en hyperespace, un anneau lumineux s'élargit jusqu'aux bords.
   Transformations et opacité seules (carte graphique). */
.espace-onde { position: absolute; inset: 0; pointer-events: none; overflow: hidden; contain: strict; }
/* Sans will-change : au repos, aucun calque réservé ; l'animation les promeut le temps du saut. */
.espace-onde i, .espace-onde b { position: absolute; left: 50%; top: 44%; display: block; border-radius: 50%; opacity: 0; }
.espace-onde i {
  width: 70vmax; height: 70vmax; margin: -35vmax 0 0 -35vmax;
  background: radial-gradient(closest-side, transparent 88%, rgba(150, 205, 255, .5) 94%, rgba(235, 247, 255, .85) 97%, transparent 100%);
}
.espace-fond.saut-depart .espace-onde i { animation: onde-charge .6s cubic-bezier(.55, 0, .85, .45) forwards; }
@keyframes onde-charge { 0% { transform: scale(1.35); opacity: 0; } 35% { opacity: .55; } 92% { opacity: .9; } 100% { transform: scale(.03); opacity: 0; } }
.espace-onde b {
  width: 50vmax; height: 50vmax; margin: -25vmax 0 0 -25vmax;
  background: radial-gradient(closest-side, transparent 55%, rgba(110, 160, 255, .16) 72%, rgba(210, 235, 255, .7) 90%, rgba(255, 255, 255, .9) 94%, transparent 100%);
}
.espace-fond.saut-tunnel .espace-onde b { animation: onde-choc .75s cubic-bezier(.12, .62, .3, 1) forwards; }
@keyframes onde-choc { 0% { transform: scale(.04); opacity: 1; } 70% { opacity: .55; } 100% { transform: scale(3.6); opacity: 0; } }
/* ÉCLAT DE SORTIE (18/10/2026) : à l'arrivée, un trait horizontal (reflet anamorphique de la verrière) et une lueur qui
   s'élargissent et s'éteignent pendant que le nouveau système se rapproche. */
.espace-eclat { position: absolute; left: 0; right: 0; top: 44%; height: 0; pointer-events: none; opacity: 0; }
.espace-eclat i, .espace-eclat b { position: absolute; display: block; }
.espace-eclat i { left: -10vw; right: -10vw; top: -18px; height: 36px; background: radial-gradient(50% 50% at 50% 50%, #fff, rgba(175, 215, 255, .7) 14%, rgba(100, 150, 255, .25) 42%, transparent 70%); }
.espace-eclat b { left: 50%; top: 0; width: 40vmax; height: 40vmax; margin: -20vmax 0 0 -20vmax; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 255, 255, .9), rgba(170, 210, 255, .4) 28%, rgba(90, 130, 255, .1) 55%, transparent 74%); }
.espace-fond.saut-arrivee .espace-eclat { opacity: 1; transition: none; }
.espace-fond.saut-arrivee .espace-eclat i { transform: scaleX(.35); transition: none; }
.espace-fond.saut-arrivee .espace-eclat b { transform: scale(.25); transition: none; }
.espace-fond.saut-retour .espace-eclat { opacity: 0; transition: opacity 1.1s ease-out .05s; }
.espace-fond.saut-retour .espace-eclat i { transform: scaleX(1.7); transition: transform 1.1s cubic-bezier(.1, .7, .3, 1); }
.espace-fond.saut-retour .espace-eclat b { transform: scale(2.4); transition: transform 1s cubic-bezier(.1, .7, .3, 1); }
/* Le nouveau système arrive dans la lumière de la sortie : un éclat qui retombe sur les astres. */
.espace-fond.saut-arrivee #klPlanetes { filter: brightness(2.2); }
.espace-fond.saut-retour #klPlanetes { filter: none; transition: transform 1.5s cubic-bezier(.15, .7, .25, 1), opacity 1.1s ease-out, filter 1.3s ease-out; }
/* Pendant le tunnel, et sur la page qui arrive : planètes, trafic, nébuleuses et poussières restent dehors. */
.espace-fond:is(.saut-tunnel, .saut-entree) #klPlanetes { transform: scale(1.9); opacity: 0; }
.espace-fond:is(.saut-tunnel, .saut-entree) #klTrafic, .espace-fond:is(.saut-tunnel, .saut-entree) .espace-nebuleuse,
.espace-fond:is(.saut-tunnel, .saut-entree) .espace-poussiere { opacity: 0; }

/* ÉCLAIR : voile blanc bleuté au-dessus de TOUT (contenu, en-tête, modales) ; au plus fort, le contenu change dessous.
   Montée 0,15 s, descente 0,3 s ; jamais cliquable. */
.saut-voile {
  position: fixed; inset: 0; z-index: 150; pointer-events: none; opacity: 0; visibility: hidden;
  background: radial-gradient(130% 120% at 50% 44%, #fff 0, #f2f9ff 34%, #d8ecff 70%, #bcd9ff 100%);
  transition: opacity .3s cubic-bezier(.2, .7, .3, 1), visibility 0s linear .3s;
}
.saut-voile.monte { opacity: 1; visibility: visible; transition: opacity .15s cubic-bezier(.6, 0, .9, .4), visibility 0s; }
/* La verrière vibre, discrètement, pendant l'accélération et le tunnel. */
html.kl-hyper .visor { animation: verriere-vibre .11s linear infinite; will-change: transform; }
@keyframes verriere-vibre {
  0% { transform: translate3d(0, 0, 0); } 25% { transform: translate3d(.7px, -.5px, 0); }
  50% { transform: translate3d(-.6px, .6px, 0); } 75% { transform: translate3d(.5px, .5px, 0); } 100% { transform: translate3d(0, 0, 0); }
}
/* Navigation douce : le HUD s'atténue pendant le saut (on regarde dehors) ; le nouveau contenu revient avec l'éclair.
   Opacité posée sur chaque panneau et non sur <main> ni sur la grille : un parent translucide priverait les panneaux
   de leur verre dépoli (backdrop-filter) le temps du saut. kl-saut-retour : le retour à la pleine opacité. */
body.sf.kl-saut-attenue main > :not(.dash), body.sf.kl-saut-attenue main > .dash > * { opacity: .3; transition: opacity .5s ease-in; }
body.sf.kl-saut-retour main > :not(.dash), body.sf.kl-saut-retour main > .dash > * { transition: opacity .3s ease-out; }
/* Après une navigation douce, le focus est rendu au début du nouveau contenu (<main tabindex="-1">) : sans cadre. */
body.sf > main[tabindex="-1"]:focus { outline: none; }
/* « Réduire les animations » : le contenu passe en fondu, rien ne bouge. */
body.sf.kl-saut-fondu main > :not(.dash), body.sf.kl-saut-fondu main > .dash > * { opacity: 0; transition: opacity .15s linear; }
@media (prefers-reduced-motion: reduce) {
  .espace-tunnel, .saut-voile, .espace-onde, .espace-eclat { display: none; }
  html.kl-hyper .visor { animation: none; }
}
@media print { .espace-fond, .saut-voile { display: none; } }

/* ---------- Panneaux : verre fumé et crochets de visée ---------- */
/* TRANSLUCIDES (30/09/2026, 2e passe : à 86 % d'opacité, le ciel ne se voyait nulle part
   sur le tableau de bord, que les panneaux couvrent presque en entier). Pas de flou : il
   serait recalculé à chaque image derrière chaque panneau. Quatre crochets aux coins,
   posés à l'intérieur de l'arrondi. */
:where(.sf) .card {
  --crochet: rgba(53, 208, 242, .42);
  background:
    linear-gradient(var(--crochet), var(--crochet)) left 6px top 6px / 9px 1px no-repeat,
    linear-gradient(var(--crochet), var(--crochet)) left 6px top 6px / 1px 9px no-repeat,
    linear-gradient(var(--crochet), var(--crochet)) right 6px top 6px / 9px 1px no-repeat,
    linear-gradient(var(--crochet), var(--crochet)) right 6px top 6px / 1px 9px no-repeat,
    linear-gradient(var(--crochet), var(--crochet)) left 6px bottom 6px / 9px 1px no-repeat,
    linear-gradient(var(--crochet), var(--crochet)) left 6px bottom 6px / 1px 9px no-repeat,
    linear-gradient(var(--crochet), var(--crochet)) right 6px bottom 6px / 9px 1px no-repeat,
    linear-gradient(var(--crochet), var(--crochet)) right 6px bottom 6px / 1px 9px no-repeat,
    repeating-linear-gradient(0deg, rgba(160, 220, 255, .018) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, rgba(20, 30, 50, .6), rgba(9, 14, 26, .7));
  border-color: rgba(70, 110, 160, .42);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(120, 220, 255, .08), inset 0 0 40px rgba(53, 208, 242, .04);
}

/* VERRE DÉPOLI (30/09/2026, « met un peu de flou ») : ce qui passe derrière un panneau —
   étoiles, planètes, vaisseaux — est flouté ; autour, le ciel reste net. Rend aussi le texte
   plus lisible (plus rien de net ne bouge derrière). Panneaux de la PAGE seulement (la
   modale a déjà son fond), sans les panneaux imbriqués (double flou inutile), et sans celui
   qui porte le voile de dépôt d'un ticket (un flou d'arrière-plan fait d'un panneau le
   repère des éléments fixes : le voile ne couvrirait plus que ce panneau). */
:where(.sf) main .card {
  -webkit-backdrop-filter: blur(7px) saturate(1.25);
  backdrop-filter: blur(7px) saturate(1.25);
}
:where(.sf) main .card .card,
:where(.sf) main .card:has(.pj-voile) { -webkit-backdrop-filter: none; backdrop-filter: none; }
/* Le flou fait de chaque panneau une couche à part : une liste déroulante qui dépasse de son
   bas passerait SOUS le panneau suivant. Le panneau où l'on travaille passe devant. */
:where(.sf) main .card:focus-within,
:where(.sf) main .card:has(.kl-combo-liste:not([hidden])) { z-index: 6; }
/* « Réduire la transparence » (système) : panneaux opaques, sans flou. */
@media (prefers-reduced-transparency: reduce) {
  :where(.sf) main .card {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: linear-gradient(180deg, rgba(20, 30, 50, .96), rgba(9, 14, 26, .97));
  }
}

/* ---------- Titres : lueur d'écran ---------- */
:where(.sf) h1 { text-shadow: 0 0 22px rgba(53, 208, 242, .3), 0 0 2px rgba(53, 208, 242, .25); letter-spacing: .02em; }
:where(.sf) h2 { text-shadow: 0 0 14px rgba(53, 208, 242, .18); }

/* ---------- Bandeau : flux de données qui court sous la ligne ---------- */
:where(.sf) .hud-top::after {
  background:
    linear-gradient(90deg, transparent 0 42%, rgba(200, 245, 255, .95) 50%, transparent 58% 100%),
    linear-gradient(90deg, transparent, rgba(53, 208, 242, .5), rgba(124, 108, 246, .4), transparent);
  background-size: 320% 100%, 100% 100%;
  background-repeat: no-repeat;
  animation: flux-donnees 7s linear infinite;
}
@keyframes flux-donnees { from { background-position: 100% 0, 0 0; } to { background-position: 0% 0, 0 0; } }

/* ---------- Verrière : coins lumineux ---------- */
/* La vignette de la visière assombrissait justement les bords, là où le ciel se voit :
   adoucie. */
:where(.sf) .visor::before { background: radial-gradient(135% 110% at 50% 45%, transparent 64%, rgba(4, 7, 13, .28) 86%, rgba(3, 5, 10, .55) 100%); }
:where(.sf) .visor-corner { border-color: rgba(53, 208, 242, .72); filter: drop-shadow(0 0 4px rgba(53, 208, 242, .55)); }
:where(.sf) .visor-ticks { opacity: .7; }

/* ============================================================
   COCKPIT (30/09/2026, « faire croire qu'on se trouve dans un vaisseau »)
   On regarde l'espace depuis la passerelle : montants rivetés de la verrière sur les
   côtés, renforts aux coins bas, console à voyants en bas, reflets sur la vitre, coque
   texturée sous le bandeau. Tout vit dans .visor (fixe, jamais cliquable) ; le contenu
   est décalé d'autant pour que rien ne passe dessous. Écrans ≥ 900 px seulement : au
   téléphone, les barres basses du HUD occupent déjà les bords.
   ============================================================ */
.cockpit-montant, .cockpit-renfort, .cockpit-console, .cockpit-reflet { display: none; }
.hyper { display: none; }
@media (min-width: 900px) {
  :where(.sf) .cockpit-reflet {
    display: block; position: absolute; inset: 0;
    background:
      linear-gradient(112deg, transparent 0 16%, rgba(180, 230, 255, .045) 20%, rgba(180, 230, 255, .012) 24%, transparent 29% 100%),
      linear-gradient(112deg, transparent 0 61%, rgba(180, 230, 255, .03) 63.5%, transparent 68% 100%);
  }
  :where(.sf) .cockpit-montant {
    display: block; position: absolute; top: 46px; bottom: 0; width: 16px;
    background:
      radial-gradient(circle, rgba(170, 200, 240, .6) 0 1.2px, rgba(0, 0, 0, .7) 1.7px, transparent 2.4px) center 20px / 16px 76px repeat-y,
      linear-gradient(90deg, #03060c, #182235 32%, #28364f 50%, #121b2b 68%, #04070d);
    box-shadow: 0 0 26px rgba(0, 0, 0, .75);
  }
  :where(.sf) .cockpit-montant.g { left: 0; border-right: 1px solid rgba(53, 208, 242, .32); }
  :where(.sf) .cockpit-montant.d { right: 0; border-left: 1px solid rgba(53, 208, 242, .32); }
  /* Filet lumineux côté cabine, qui respire. */
  :where(.sf) .cockpit-montant::after {
    content: ''; position: absolute; top: 0; bottom: 0; width: 2px;
    background: linear-gradient(180deg, transparent 4%, rgba(53, 208, 242, .85) 40%, rgba(124, 108, 246, .7) 70%, transparent 96%);
    animation: montant-lueur 5s ease-in-out infinite;
  }
  :where(.sf) .cockpit-montant.g::after { right: -3px; }
  :where(.sf) .cockpit-montant.d::after { left: -3px; animation-delay: -2.5s; }
  @keyframes montant-lueur { 0%, 100% { opacity: .25; } 50% { opacity: .95; } }

  /* Renforts d'angle, au-dessus de la console. */
  :where(.sf) .cockpit-renfort {
    display: block; position: absolute; bottom: 22px; width: 84px; height: 84px;
    background: linear-gradient(135deg, #223047, #0b111c 70%);
    filter: drop-shadow(0 0 1px rgba(53, 208, 242, .45));
  }
  :where(.sf) .cockpit-renfort.bg { left: 0; clip-path: polygon(0 0, 16px 0, 100% 100%, 0 100%); }
  :where(.sf) .cockpit-renfort.bd { right: 0; clip-path: polygon(calc(100% - 16px) 0, 100% 0, 100% 100%, 0 100%); }

  /* Console : bande basse, voyants qui clignotent à des rythmes différents, jauge. */
  :where(.sf) .cockpit-console {
    display: flex; align-items: center; justify-content: space-between;
    position: absolute; left: 0; right: 0; bottom: 0; height: 22px; padding: 0 110px;
    background: linear-gradient(180deg, #152033, #070b13);
    border-top: 1px solid rgba(53, 208, 242, .34);
    box-shadow: 0 -8px 22px rgba(0, 0, 0, .6), inset 0 1px 0 rgba(140, 210, 255, .1);
  }
  :where(.sf) .cockpit-voyants { display: flex; gap: 12px; }
  :where(.sf) .cockpit-voyants i {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--accent); box-shadow: 0 0 7px var(--accent);
    animation: voyant 2.6s steps(1) infinite;
  }
  :where(.sf) .cockpit-voyants i:nth-child(2) { background: var(--success); box-shadow: 0 0 7px var(--success); animation-duration: 3.7s; animation-delay: -.8s; }
  :where(.sf) .cockpit-voyants i:nth-child(3) { background: var(--warn); box-shadow: 0 0 7px var(--warn); animation-duration: 1.9s; animation-delay: -.3s; }
  :where(.sf) .cockpit-voyants i:nth-child(4) { background: var(--accent-2); box-shadow: 0 0 7px var(--accent-2); animation-duration: 4.4s; animation-delay: -1.9s; }
  :where(.sf) .cockpit-voyants i:nth-child(5) { animation-duration: 3.1s; animation-delay: -1.2s; }
  :where(.sf) .cockpit-voyants + .cockpit-jauge + .cockpit-voyants i { animation-delay: -2.2s; }
  @keyframes voyant { 0%, 64% { opacity: 1; } 65%, 100% { opacity: .18; } }
  :where(.sf) .cockpit-jauge {
    width: min(360px, 30vw); height: 4px; border-radius: 2px; overflow: hidden;
    background: rgba(53, 208, 242, .12); box-shadow: inset 0 0 0 1px rgba(53, 208, 242, .25);
  }
  :where(.sf) .cockpit-jauge b {
    display: block; height: 100%; width: 36%;
    background: linear-gradient(90deg, transparent, var(--accent), var(--accent-2), transparent);
    animation: jauge 6s ease-in-out infinite alternate;
  }
  @keyframes jauge { from { transform: translateX(-60%); } to { transform: translateX(240%); } }

  /* Module SAUT (07/10/2026) : au centre de la console, à la place de la jauge décorative.
     Forme en trapèze dessinée par ::before (clip-path) pour garder la lueur du bouton (filter).
     14/10/2026 : il porte le NOM DU CONTEXTE (un site = un système) et ouvre le choix du contexte ; plus de
     jauge, il n'y a plus de saut automatique. */
  :where(.sf.hud-on) .cockpit-jauge { visibility: hidden; }
  :where(.sf) .hyper {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    position: fixed; z-index: 41; left: 50%; bottom: 0; transform: translateX(-50%);
    min-width: 270px; height: 32px; padding: 0 34px 5px; border: 0; background: none; cursor: pointer;
    color: #bfefff; font: 600 10.5px/1 var(--font-num, 'JetBrains Mono', ui-monospace, monospace);
    letter-spacing: .22em; text-transform: uppercase;
    filter: drop-shadow(0 0 1px rgba(53, 208, 242, .75)) drop-shadow(0 -4px 12px rgba(0, 0, 0, .55));
    transition: filter .2s;
  }
  :where(.sf) .hyper::before {
    content: ''; position: absolute; inset: 0; z-index: -1;
    background:
      linear-gradient(180deg, rgba(140, 210, 255, .16), transparent 30%),
      repeating-linear-gradient(90deg, transparent 0 23px, rgba(120, 180, 255, .07) 23px 24px),
      linear-gradient(180deg, #1e2c45, #0a101b 78%);
    clip-path: polygon(16px 0, calc(100% - 16px) 0, 100% 100%, 0 100%);
  }
  :where(.sf) .hyper:hover, :where(.sf) .hyper:focus-visible {
    color: #fff; filter: drop-shadow(0 0 2px rgba(53, 208, 242, .95)) drop-shadow(0 0 14px rgba(53, 208, 242, .35)) drop-shadow(0 -4px 12px rgba(0, 0, 0, .55));
  }
  :where(.sf) .hyper:focus-visible { outline: none; }
  :where(.sf) .hyper-lib { text-shadow: 0 0 8px rgba(53, 208, 242, .7); }
  :where(.sf) .hyper-lieu { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: rgba(160, 205, 235, .72); font-weight: 500; letter-spacing: .16em; }
  :where(.sf) .hyper-lieu:empty { display: none; }
  :where(.sf) .hyper-lieu::before { content: '·'; margin-right: 10px; color: rgba(53, 208, 242, .6); }
  /* Chevrons de propulsion : ils défilent au survol et pendant le saut. */
  :where(.sf) .hyper-chevrons { display: inline-flex; gap: 1px; }
  :where(.sf) .hyper-chevrons i { width: 6px; height: 8px; background: currentColor; opacity: .35; clip-path: polygon(0 0, 45% 0, 100% 50%, 45% 100%, 0 100%, 55% 50%); }
  :where(.sf) .hyper:hover .hyper-chevrons i, :where(.sf) .hyper.en-saut .hyper-chevrons i { animation: hyper-chevron .9s ease-in-out infinite; }
  :where(.sf) .hyper-chevrons i:nth-child(2) { animation-delay: .15s !important; }
  :where(.sf) .hyper-chevrons i:nth-child(3) { animation-delay: .3s !important; }
  @keyframes hyper-chevron { 0%, 100% { opacity: .3; } 40% { opacity: 1; color: #8ff3ff; } }
  /* Pendant le saut (départ, arrivée) : libellé qui scintille, chevrons qui défilent. */
  :where(.sf) .hyper.en-saut { cursor: progress; color: #e8fbff; }
  :where(.sf) .hyper.en-saut .hyper-lib { animation: hyper-scintille .18s steps(2) infinite; }
  @keyframes hyper-scintille { 50% { opacity: .55; } }

  /* Coque : plaques et joints sous le bandeau. Écart réduit (16 → 10 px) : le bouton des
     sons tient sans rogner la bande de télémétrie ni « Chrono ». */
  :where(.sf) .hud-top { gap: 10px; }
  :where(.sf) .hud-top {
    background:
      repeating-linear-gradient(90deg, transparent 0 119px, rgba(120, 180, 255, .07) 119px 120px),
      linear-gradient(180deg, rgba(20, 28, 44, .97), rgba(9, 13, 22, .9) 70%, rgba(9, 13, 22, .55));
  }

  /* Le contenu ne passe ni sous les montants ni sous la console. */
  body.sf.hud-on > main { padding-left: 34px; padding-right: 34px; padding-bottom: 84px; }
  :where(.sf) .visor-corner.bl, :where(.sf) .visor-corner.br { bottom: 30px; }
  :where(.sf) .visor-corner.bl { left: 24px; }
  :where(.sf) .visor-corner.br { right: 24px; }
  :where(.sf) .visor-corner.tl { left: 24px; }
  :where(.sf) .visor-corner.tr { right: 24px; }
  :where(.sf) .visor-ticks.bottom { bottom: 30px; }
}
