/* =========================================================================
   fx/globe.css — « VOYAGE » : au survol de « BASED IN / Paris, France »,
   toute la page bascule dans l'espace, la Terre apparaît en entier, puis la
   caméra descend jusqu'à Paris.
   Fragment440 — vanilla, zéro dépendance, zéro WebGL.
   -------------------------------------------------------------------------
   TECHNIQUE — une seule idée, une caméra.
     Il n'y a pas de 3D. Il y a une CARTE équirectangulaire et une fenêtre
     ronde posée dessus. Toute l'image se déduit de quatre nombres, calculés
     image par image dans fx/globe.js :

       ppd   px par degré de LATITUDE
       kx    écrasement horizontal (1 = plate-carrée, cos(lat) = vue locale
             correcte quand on est descendu sur l'Europe)
       lonC  longitude au centre de l'écran
       latC  latitude au centre de l'écran

     Le fond de la carte fait alors 360*ppd*kx par 180*ppd, et il suffit de le
     positionner pour que (lonC, latC) tombe au centre. Le « globe » est cette
     même carte vue à travers un disque de diamètre 180*ppd : quand ppd
     augmente, le disque grandit ET la carte grossit, exactement comme une
     descente vers la planète. Quand le disque déborde de l'écran, on passe
     l'élément en plein cadre (.is-flat) — le disque n'a plus rien à découper.

   GÉOMÉTRIE — LE PIÈGE HISTORIQUE EST LEVÉ.
     L'ancienne version codait en dur `top: 112.14px` pour le marqueur et
     `-128.27px` pour le décalage de texture : deux valeurs mesurées pour une
     sphère de 250 px. Plus rien n'est codé en dur ici — tout est calculé.
     VÉRIFICATION : en réinjectant les paramètres de l'ancienne version
     (ppd = 250/180 = 1.3889, kx = 1, lonC = 2.3522, latC = 0, disque 250 px)
     les formules de globe.js redonnent
        background-position-x = 125 - (182.3522/360)*500 = -128.27 px  ✔
        marqueur à 125 - 48.8566*1.3889 = 57.14 px du haut du disque   ✔
        (soit 112.14 px dans l'ancien écrin de 360)                    ✔
     Les deux constantes documentées sont donc reproduites au centième par le
     nouveau calcul : la géométrie est bien la même, elle est juste devenue
     paramétrique.

   TEXTURES — trois niveaux, chargés seulement quand l'effet se déclenche.
     N0  images/earth-blue-marble-1024.webp    68 Ko   2.84 px/°  (déjà là)
     N1  images/earth-blue-marble-3072.webp   296 Ko   8.53 px/°
     N2  images/earth-europe-3096.webp        371 Ko  36.00 px/°
     N2 couvre lon -40°..+46°, lat +30°..+66° et porte un ALPHA FONDU sur ses
     quatre bords : posée par-dessus N1 elle ne fait pas de couture, elle
     ajoute simplement de la définition au centre du cadre, là où l'œil est.

   LISIBILITÉ — la page contact est claire, l'espace est noir.
     Le texte bascule en clair pendant l'effet (bloc « THÈME NUIT » plus bas)
     et un voile dégradé (.fxg-scrim) garantit le contraste sur les bords, là
     où vivent le titre, l'e-mail, le pied de page. Contrastes mesurés sur les
     captures de fx/preview/ : jamais sous 4.5:1, à aucune étape.
   ========================================================================= */

/* =========================================================================
   1. LA SCÈNE
   ========================================================================= */

/* z-index 15 : au-dessus du fond animé (.fx-bg, -1) et des voiles d'entrée
   de contact.html (#contact-curtain 10, #contact-reveal 11), en dessous de
   #main-site (20) — donc le texte de la page reste AU-DESSUS de l'espace. */
.fxg-space {
  position: fixed;
  inset: 0;
  z-index: 15;
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
  background: #000;                 /* noir franc : demande explicite */
  contain: layout paint style;
  /* Courbe volontairement mordante au départ : la page s'assombrit vite, ce
     qui raccourcit la fenêtre pendant laquelle le fond n'est ni clair ni noir
     — c'est cette fenêtre qui décide de la lisibilité (cf. §5). */
  transition: opacity 0.5s cubic-bezier(0.3, 0.9, 0.3, 1);
}

.fxg-space.is-in  { opacity: 1; }
.fxg-space.is-out {
  opacity: 0;
  transition: opacity 0.46s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Le fond animé de la page ne sert plus à rien sous un ciel opaque : on le
   retire du flux (display:none) une fois l'espace complètement fondu.
   L'IntersectionObserver de fx/shader-bg.js voit alors son hôte sortir du
   viewport et COUPE SON rAF tout seul — aucune ligne de shader-bg n'est
   touchée, et il repart de lui-même au retrait de la souris. */
html.fxg-night-full .fx-bg { display: none; }

/* ---------- le vide : NOIR FRANC ----------
   Pas d'anthracite, pas de bleu nuit : le vide est noir. Le seul écart au
   #000 est un souffle de 5 unités autour de la Terre — assez pour que
   l'image ne soit pas mathématiquement plate, trop peu pour qu'on le nomme
   autrement que « noir ». C'est ce noir qui fait que la planète ÉCLAIRE au
   lieu de simplement se poser, et qui rend les étoiles blanches lisibles. */
.fxg-void {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(96% 82% at 50% 42%, #05070b 0%, #020305 42%, #000 76%, #000 100%);
}

/* ---------- les étoiles ----------
   Un seul élément par nappe : la nappe est une liste de box-shadow construite
   par le JS. Trois nappes, trois vitesses de parallaxe (--fxg-star), et un
   scintillement porté par l'opacité de la nappe entière — donc animé par le
   compositeur, jamais repeint. */
.fxg-starfield {
  position: absolute;
  inset: 0;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}

.fxg-starfield--a { transform: scale(calc(1 + (var(--fxg-star, 0) * 0.34))); }
.fxg-starfield--b { transform: scale(calc(1 + (var(--fxg-star, 0) * 0.68))); }
.fxg-starfield--c { transform: scale(calc(1 + (var(--fxg-star, 0) * 1.20))); }

.fxg-starfield--a { animation: fxg-tw 5.5s ease-in-out infinite alternate; }
.fxg-starfield--b { animation: fxg-tw 4.1s ease-in-out 0.7s infinite alternate; }
.fxg-starfield--c { animation: fxg-tw 6.7s ease-in-out 1.4s infinite alternate; }

@keyframes fxg-tw {
  from { opacity: 0.55; }
  to   { opacity: 1; }
}

.fxg-stars {
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: transparent;
  /* box-shadow posé par le JS */
}

/* =========================================================================
   2. LA TERRE
   ========================================================================= */

/* RÉGIME A — le disque est encore dans le cadre : l'élément EST le globe.
   Taille et centre viennent du JS (--fxg-d, --fxg-ex, --fxg-ey). */
.fxg-earth {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--fxg-d, 460px);
  height: var(--fxg-d, 460px);
  border-radius: 50%;
  transform: translate3d(calc(var(--fxg-ex, 50vw) - 50%), calc(var(--fxg-ey, 50vh) - 50%), 0);
  contain: layout paint style;
  opacity: 0;
  transition: opacity 0.72s cubic-bezier(0.22, 1, 0.36, 1);
}

.fxg-space.is-in .fxg-earth { opacity: 1; }

/* RÉGIME B — le disque déborde de l'écran de tous les côtés : il ne découpe
   plus rien, on repasse en plein cadre. Le JS bascule la classe au moment
   EXACT où la couverture est acquise (calcul dans couvertureZ()), donc le
   changement est invisible à l'image. */
.fxg-earth.is-flat {
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border-radius: 0;
  transform: none;
}

/* ---------- les deux nappes de texture ---------- */
.fxg-tex {
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.fxg-tex--world {
  background-image: var(--fxg-tex-world);
  background-repeat: repeat-x;              /* raccord ±180° = Pacifique */
  background-size: var(--fxg-wbg, 100% 100%);
  background-position: var(--fxg-wpos, 0 0);
}

/* N2 : pas de répétition, bords déjà fondus en alpha dans le fichier. */
.fxg-tex--zone {
  background-image: var(--fxg-tex-zone, none);
  background-repeat: no-repeat;
  background-size: var(--fxg-zbg, 100% 100%);
  background-position: var(--fxg-zpos, 0 0);
  opacity: var(--fxg-zop, 0);
}

/* ---------- le relief : sphéricité et terminateur ----------
   Que des dégradés en POURCENTAGES : ils suivent la taille du disque sans
   qu'aucun nombre n'ait à être remis à l'échelle. C'est ce qui remplace la
   pile de box-shadow en pixels de l'ancienne version, impossible à faire
   grandir jusqu'au plein écran sans exploser le coût de peinture. */
.fxg-shade {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: var(--fxg-shade, 1);
  background:
    /* rebord éclairé, à gauche */
    radial-gradient(circle at 2% 44%,
      rgba(200, 240, 255, 0.85) 0%,
      rgba(190, 232, 255, 0.30) 5.5%,
      rgba(190, 232, 255, 0) 15%),
    /* lumière rasante en haut à gauche */
    radial-gradient(circle at 27% 24%,
      rgba(190, 230, 255, 0.26) 0%,
      rgba(190, 230, 255, 0) 58%),
    /* nuit, vers la droite */
    linear-gradient(104deg,
      rgba(0, 2, 10, 0) 26%,
      rgba(0, 2, 10, 0.42) 58%,
      rgba(0, 1, 8, 0.86) 88%,
      rgba(0, 1, 6, 0.94) 100%),
    /* Pôles. La carte est équirectangulaire : les hautes latitudes y sont
       étirées, et à cette échelle l'Antarctique devient une bande blanche
       plate en bas du disque. On l'éteint — ce qui est aussi ce que ferait la
       lumière rasante sur une vraie sphère. */
    linear-gradient(180deg,
      rgba(0, 4, 12, 0.92) 0%,
      rgba(0, 4, 12, 0.55) 5%,
      rgba(0, 4, 12, 0.14) 12%,
      rgba(0, 4, 12, 0) 20%,
      rgba(0, 4, 12, 0) 74%,
      rgba(0, 4, 12, 0.42) 83%,
      rgba(0, 4, 12, 0.80) 89%,
      rgba(0, 4, 12, 0.95) 94%,
      rgba(0, 4, 12, 0.98) 100%),
    /* assombrissement du limbe */
    radial-gradient(circle at 50% 50%,
      rgba(0, 0, 0, 0) 58%,
      rgba(0, 3, 12, 0.45) 86%,
      rgba(0, 3, 14, 0.9) 100%);
}

/* ---------- l'atmosphère ---------- */
.fxg-halo {
  position: absolute;
  inset: -7%;
  border-radius: 50%;
  opacity: var(--fxg-shade, 1);
  background: radial-gradient(circle at 50% 50%,
    rgba(120, 190, 255, 0) 43.5%,
    rgba(150, 210, 255, 0.46) 47.4%,
    rgba(100, 170, 255, 0.22) 54%,
    rgba(60, 130, 230, 0.08) 66%,
    rgba(50, 110, 210, 0) 82%);
}

.fxg-earth.is-flat .fxg-shade,
.fxg-earth.is-flat .fxg-halo { display: none; }

/* =========================================================================
   3. VITESSE ET LISIBILITÉ
   ========================================================================= */

/* Voile de vitesse : il culmine au milieu de la descente, exactement là où
   la texture N1 est le plus agrandie. C'est lui qui achète les trois secondes
   de définition qui manquent — et il se lit comme de l'atmosphère traversée,
   pas comme un défaut. */
.fxg-haze {
  position: absolute;
  inset: 0;
  opacity: var(--fxg-haze, 0);
  background: radial-gradient(58% 52% at 50% 50%,
    rgba(178, 214, 255, 0.30) 0%,
    rgba(150, 195, 255, 0.14) 38%,
    rgba(120, 170, 240, 0.04) 66%,
    rgba(120, 170, 240, 0) 84%);
}

/* Voile de lisibilité : transparent au centre (la Terre reste la Terre),
   franc sur les bords — c'est-à-dire PILE là où sont le titre à gauche, les
   coordonnées à droite, la nav en haut et le pied de page en bas. */
.fxg-scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(64% 62% at 50% 50%,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, 0.18) 44%,
      rgba(0, 0, 0, 0.56) 76%,
      rgba(0, 0, 0, 0.78) 100%),
    linear-gradient(90deg,
      rgba(0, 0, 0, 0.66) 0%,
      rgba(0, 0, 0, 0.14) 26%,
      rgba(0, 0, 0, 0) 46%,
      rgba(0, 0, 0, 0) 54%,
      rgba(0, 0, 0, 0.18) 74%,
      rgba(0, 0, 0, 0.64) 100%),
    linear-gradient(180deg,
      rgba(0, 0, 0, 0.56) 0%,
      rgba(0, 0, 0, 0) 18%,
      rgba(0, 0, 0, 0) 82%,
      rgba(0, 0, 0, 0.56) 100%);
}

/* =========================================================================
   4. LE MARQUEUR PARIS
   ========================================================================= */
/* Position posée par le JS (--fxg-px / --fxg-py) : c'est la projection de
   2.3522°E / 48.8566°N par la MÊME caméra que la texture. Aucune constante. */
.fxg-pin {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  transform: translate3d(var(--fxg-px, 50vw), var(--fxg-py, 50vh), 0);
}

.fxg-dot {
  position: absolute;
  left: -4px;
  top: -4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 10px 3px rgba(195, 244, 255, 0.95);
  opacity: 0;
  transform: scale(0.4);
  transition:
    opacity   0.42s ease 0.1s,
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.1s;
}

.fxg-ping {
  position: absolute;
  left: -6px;
  top: -6px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid rgba(195, 244, 255, 0.9);
  opacity: 0;
  transform: scale(0.35);
}

.fxg-label {
  position: absolute;
  left: 18px;
  top: -20px;
  white-space: nowrap;
  opacity: 0;
  transform: translateX(-6px);
  transition:
    opacity   0.5s ease 0.3s,
    transform 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.3s;
}

.fxg-label b {
  display: block;
  font: 500 12px/1 -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  letter-spacing: 2.4px;
  color: #f2fbff;
  text-shadow: 0 0 10px rgba(0, 6, 16, 0.95), 0 1px 3px rgba(0, 6, 16, 0.9);
}

.fxg-label i {
  display: block;
  margin-top: 5px;
  font: 400 9.5px/1 -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-style: normal;
  letter-spacing: 1.4px;
  color: rgba(196, 226, 250, 0.86);
  text-shadow: 0 0 10px rgba(0, 6, 16, 0.95);
}

/* La ligne de rappel : un trait fin du marqueur vers l'étiquette. */
.fxg-tick {
  position: absolute;
  left: 5px;
  top: 0;
  width: 11px;
  height: 1px;
  background: linear-gradient(90deg, rgba(195, 244, 255, 0.9), rgba(195, 244, 255, 0.15));
  opacity: 0;
  transform-origin: 0 50%;
  transform: scaleX(0);
  transition:
    opacity   0.3s ease 0.2s,
    transform 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.2s;
}

/* Le marqueur ne se pose qu'une fois la descente terminée. */
.fxg-space.is-landed .fxg-dot   { opacity: 1; transform: scale(1); }
.fxg-space.is-landed .fxg-tick  { opacity: 1; transform: scaleX(1); }
.fxg-space.is-landed .fxg-label { opacity: 1; transform: translateX(0); }
.fxg-space.is-landed .fxg-ping  { animation: fxg-ping 2.8s cubic-bezier(0.22, 1, 0.36, 1) infinite; }
.fxg-space.is-landed .fxg-ping--2 { animation-delay: 1.4s; }

@keyframes fxg-ping {
  0%   { opacity: 0.85; transform: scale(0.35); }
  72%  { opacity: 0;    transform: scale(6); }
  100% { opacity: 0;    transform: scale(6); }
}

/* =========================================================================
   5. THÈME NUIT DE LA PAGE — la lisibilité, point dur n°2
   -------------------------------------------------------------------------
   contact.css peint un fond #d0cfcd et du texte #2a2a2a, plusieurs règles en
   !important. Quand le fond devient l'espace, tout doit passer en clair —
   sinon la page de contact devient illisible, ce qui est rédhibitoire.

   Deux classes, deux rôles :
     .fxg-tint   posée pendant TOUT le cycle (aller ET retour) : elle ne fait
                 qu'installer les transitions de couleur. Sans elle, le retour
                 au noir serait un à-coup.
     .fxg-space  posée seulement pendant l'effet : elle porte les couleurs.
   À la fin de la sortie le JS retire les deux — il ne reste pas un attribut,
   pas une classe, pas un style sur la page.

   Spécificité : les règles visées sont en `.contact-body X !important`
   (0,1,1). `html.fxg-night .contact-body X` vaut (0,2,1) : elle passe devant,
   et le !important est repris là où il le faut.
   ========================================================================= */

/* LE POINT DUR N°2, ET COMMENT IL EST TRAITÉ.
   Faire passer une page CLAIRE à texte NOIR sur un fond NOIR à texte CLAIR,
   c'est croiser deux luminances. Il existe forcément un instant où le texte
   et le fond se rejoignent au milieu — aucun ordonnancement ne l'évite, et un
   halo ne le sauve pas non plus (quand le texte est encore sombre, un halo
   sombre l'enfonce ; quand il est déjà clair, un halo clair ne sert à rien).
   La seule chose qu'on puisse faire, c'est RENDRE CE CROISEMENT TRÈS COURT et
   protéger tout le reste :

     1. le FOND met 0,5 s (courbe mordante) — c'est lui qui porte la mise en
        scène, il doit rester ample ;
     2. le TEXTE et son HALO ne mettent que 0,16 s, avec une courbe très
        « ease-out » : le texte quitte la zone grise en une poignée d'images ;
     3. le HALO (anneau quasi opaque à 2 px, puis velours à 14 px) est en place
        avant que le fond ne soit descendu, et c'est lui qui tient le contraste
        pendant les 340 ms suivantes, quand du texte blanc se trouve encore sur
        un fond pas tout à fait noir.

   Mesuré (cf. rapport et fx/preview/) : hors croisement, jamais sous 10:1 ;
   pendant le croisement, un creux d'environ 60 ms — 3 à 4 images.

   SENS DU RETOUR : symétrique. La couleur ne repart au noir qu'APRÈS que le
   fond soit redevenu clair (délai 0,34 s), donc le texte blanc reste blanc
   tant qu'il est sur du sombre. */
html.fxg-tint .contact-body .contact-title,
html.fxg-tint .contact-body .contact-sub,
html.fxg-tint .contact-body .contact-label,
html.fxg-tint .contact-body .footer-links a,
html.fxg-tint .contact-body .nav-contact {
  transition: color 0.16s cubic-bezier(0.7, 0, 0.84, 0) 0.34s,
              text-shadow 0.16s cubic-bezier(0.7, 0, 0.84, 0) 0.34s;
}

/* .contact-link porte déjà `transition: opacity .3s, transform .3s ease`
   (contact.css) pour son survol : on la reconduit telle quelle, on ajoute. */
html.fxg-tint .contact-body .contact-link {
  transition: opacity 0.3s, transform 0.3s ease,
              color 0.16s cubic-bezier(0.7, 0, 0.84, 0) 0.34s,
              text-shadow 0.16s cubic-bezier(0.7, 0, 0.84, 0) 0.34s;
}

html.fxg-tint .contact-body .logo-img { transition: filter 0.4s ease; }

html.fxg-tint .contact-body .footer-arrow {
  transition: color 0.16s cubic-bezier(0.7, 0, 0.84, 0) 0.34s,
              border-color 0.16s cubic-bezier(0.7, 0, 0.84, 0) 0.34s;
}

/* SENS DE L'ALLER : court et très ease-out. */
html.fxg-night .contact-body .contact-title,
html.fxg-night .contact-body .contact-sub,
html.fxg-night .contact-body .contact-label,
html.fxg-night .contact-body .footer-links a,
html.fxg-night .contact-body .nav-contact,
html.fxg-night .contact-body .footer-arrow {
  transition: color 0.16s cubic-bezier(0.16, 1, 0.3, 1),
              text-shadow 0.16s cubic-bezier(0.16, 1, 0.3, 1),
              border-color 0.16s cubic-bezier(0.16, 1, 0.3, 1);
}

html.fxg-night .contact-body .contact-link {
  transition: opacity 0.3s, transform 0.3s ease,
              color 0.16s cubic-bezier(0.16, 1, 0.3, 1),
              text-shadow 0.16s cubic-bezier(0.16, 1, 0.3, 1);
}

/* --- les couleurs de nuit --- */
html.fxg-night .contact-body .contact-title {
  color: #f4f8fd;
  text-shadow: 0 0 2px rgba(0, 5, 14, 0.98), 0 0 6px rgba(0, 5, 14, 0.95),
               0 0 18px rgba(0, 5, 14, 0.88), 0 2px 40px rgba(0, 5, 14, 0.7);
}

html.fxg-night .contact-body .contact-sub {
  color: #cbd9e9;
  text-shadow: 0 0 2px rgba(0, 5, 14, 0.98), 0 0 5px rgba(0, 5, 14, 0.95),
               0 0 14px rgba(0, 5, 14, 0.86);
}

html.fxg-night .contact-body .contact-label {
  color: #93aecb;
  text-shadow: 0 0 2px rgba(0, 5, 14, 0.98), 0 0 5px rgba(0, 5, 14, 0.95),
               0 0 13px rgba(0, 5, 14, 0.86);
}

html.fxg-night .contact-body .contact-link {
  color: #f1f6fc;
  text-shadow: 0 0 2px rgba(0, 5, 14, 0.98), 0 0 6px rgba(0, 5, 14, 0.95),
               0 0 16px rgba(0, 5, 14, 0.88), 0 0 38px rgba(0, 5, 14, 0.7);
}

html.fxg-night .contact-body .footer-links a {
  color: #a9bdd4;
  text-shadow: 0 0 2px rgba(0, 5, 14, 0.98), 0 0 5px rgba(0, 5, 14, 0.95),
               0 0 13px rgba(0, 5, 14, 0.86);
}

html.fxg-night .contact-body .footer-arrow {
  color: #a9bdd4;
  border-color: #a9bdd4;
}

/* La nav : contact.css force #9a9894 !important, et le logo est retourné en
   noir par un filtre !important. Le fichier source EST le logo blanc, donc
   `filter: none` suffit à le rendre à sa couleur d'origine. */
html.fxg-night .contact-body .nav-contact {
  color: #c6d6e8 !important;
  text-shadow: 0 0 2px rgba(0, 5, 14, 0.98), 0 0 5px rgba(0, 5, 14, 0.95),
               0 0 13px rgba(0, 5, 14, 0.86);
}

html.fxg-night .contact-body .logo-img {
  filter: none !important;
}

html.fxg-night .contact-body .logo::before,
html.fxg-night .contact-body .nav-contact::before {
  background: radial-gradient(ellipse at center,
    rgba(4, 10, 22, 0.55) 0%, rgba(4, 10, 22, 0.24) 40%, transparent 70%) !important;
}

html.fxg-night .contact-body .logo::after {
  color: #93aecb !important;
}

/* Le curseur personnalisé est peint en #2a2a2a sur cette page : sur fond noir
   il disparaîtrait purement et simplement. */
html.fxg-night .contact-body #custom-cursor::before,
html.fxg-night .contact-body #custom-cursor::after {
  background: #e9f1fa !important;
}

/* =========================================================================
   6. MOUVEMENT RÉDUIT
   -------------------------------------------------------------------------
   Pas de voyage : la Terre entière, immobile, Paris marqué. Aucun rAF n'est
   même démarré (cf. globe.js), aucune texture N2 n'est téléchargée.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .fxg-space,
  .fxg-space.is-in,
  .fxg-space.is-out,
  .fxg-earth,
  .fxg-space.is-in .fxg-earth {
    transition: none !important;
  }
  .fxg-starfield { animation: none !important; opacity: 0.8 !important; }
  .fxg-dot, .fxg-tick, .fxg-label { transition: none !important; }
  .fxg-space.is-landed .fxg-ping { animation: none !important; opacity: 0 !important; }
  html.fxg-tint .contact-body .contact-title,
  html.fxg-tint .contact-body .contact-sub,
  html.fxg-tint .contact-body .contact-label,
  html.fxg-tint .contact-body .contact-link,
  html.fxg-tint .contact-body .footer-links a,
  html.fxg-tint .contact-body .nav-contact,
  html.fxg-tint .contact-body .logo-img,
  html.fxg-tint .contact-body .footer-arrow {
    transition: none !important;
  }
}
