/* États posés par le JS (is-*, js-motion) et mouvement réduit. */

/* Avant son décodage, une ligne est invisible mais présente pour les lecteurs d'écran. */
.js-motion [data-decode]:not(.is-decoded):not(.c-decode) {
  color: transparent;
}

.js-motion .l-main,
.js-motion .l-dossier {
  animation: fade-in 900ms var(--ease) 300ms both;
}

.js-motion .c-scroll-cue::before {
  animation: cue 2.8s var(--ease) infinite;
}

.js-motion .c-brand__cursor {
  animation: blink 1.1s steps(1, end) infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

.is-menu-open {
  overflow: hidden;
}

.is-menu-open .l-orb,
.is-menu-open .l-dossier__orb {
  visibility: hidden;
}

/* Sortie : le contenu s'efface pendant que l'anneau se contracte, puis blanc (300 ms) et noir (400 ms). */
.is-leaving .l-main,
.is-leaving .l-dossier > :not(.l-dossier__grid),
.is-leaving .l-dossier__texts,
.is-leaving .l-dossier__data,
.is-leaving .l-footer,
.is-leaving .l-header {
  opacity: 0;
  transition: opacity 450ms var(--ease);
}

.is-flash .c-veil {
  opacity: 1;
  transition: opacity 300ms var(--ease);
}

.is-dark .c-veil {
  background: var(--bg);
  transition: background-color 400ms var(--ease);
}

.c-ring-label.is-visible {
  opacity: 1;
}

.is-reading .c-reading-text {
  --veil-open: var(--reading-reveal, 0);
}

.is-reading .c-reading-text,
.is-veiled {
  opacity: calc(0.28 + var(--veil-open, 0) * 0.72);
  filter: blur(calc((1 - var(--veil-open, 0)) * 2.4px));
  mask-image: radial-gradient(ellipse calc(1% + var(--veil-open, 0) * 104%) calc(12% + var(--veil-open, 0) * 200%) at 50% 50%, var(--fg) 65%, transparent 100%);
  text-shadow: 0 0 calc((1 - var(--veil-open, 0)) * 12px) var(--fg);
}

.is-veiled:focus-within,
.is-veiled:focus-visible { opacity: 1; filter: none; mask-image: none; text-shadow: none; }

.is-reading::after {
  content: "";
  position: absolute;
  inset: auto 0 -8px;
  height: 1px;
  background: var(--alert);
  transform: scaleX(var(--reading-reveal, 1));
  transform-origin: left;
}

.is-negative .c-reading,
.is-menu-open .c-reading,
.is-travelling .c-reading,
.is-simulating .c-reading,
.is-leaving .c-reading,
.is-veille .c-reading { visibility: hidden; }

.has-reading-link .c-ring-label { visibility: hidden; }
.has-scene-instruments .c-ring-label { visibility: hidden; }
.is-ring-static.is-ring-unrolled { background-image: none; }
.has-scene-fallback > .is-ring-static { border: 0; }
.has-scene-fallback.is-scene-unrolled > .c-orbital__fallback { visibility: hidden; }

.is-reading-item .c-job__index,
.is-reading-item .c-subject__index { color: var(--alert); }

.c-timeline__year.is-reading-year { color: var(--alert); }
.c-timeline__span.is-reading-period { background: var(--alert); }
.c-timeline__span.is-reading-period::before,
.c-timeline__span.is-reading-period::after { border-color: var(--alert); }

.is-reading-item .c-job__company::after,
.is-reading-item .c-subject__name::after {
  content: "";
  position: absolute;
  inset: auto auto -8px 0;
  width: min(8rem, 100%);
  height: 1px;
  background: var(--alert-line);
}

/* Veille (home.js, watchIdle) : le relevé de l'orbe passe en blanc, précédé d'un témoin rouge qui clignote
   lentement, comme une machine en attente. Jamais de négatif : 40 s sans geste, c'est souvent une lecture. */
.is-veille [data-orb-section] {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  color: var(--fg);
}

.is-veille [data-orb-section]::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  background: var(--alert);
  animation: veille-led 2.4s steps(1, end) infinite;
}

@keyframes veille-led {
  50% {
    opacity: 0.3;
  }
}

/* Écran d'amorçage (boot.js) : les lignes apparaissent l'une après l'autre, puis tout le calque s'efface. */
.c-boot.is-fading {
  opacity: 0;
}

.c-boot__line.is-shown {
  opacity: 1;
}

.c-boot__fill.is-filling {
  width: 100%;
}

.c-boot__sweep {
  animation: boot-sweep 3.2s linear infinite;
}

@keyframes boot-sweep {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(100vh);
  }
}

/* Corruption (commande « hack », js/corruption.js) : bruit et salves de l'anneau (ring.js), aberration
   chromatique statique sur les titres et vacillement du prompt de la console, un raté de machine plutôt qu'un
   mouvement. Couleurs : uniquement --alert et --fg déjà déclarés dans theme.css. */
.is-corrupted .c-subject-name,
.is-corrupted .c-section-title,
.is-corrupted .c-negative__title {
  text-shadow: -1px 0 var(--alert), 1px 0 var(--fg);
}

.is-corrupted .c-console__prompt {
  animation: corrupt-flicker 2.6s steps(1, end) infinite;
}

@keyframes corrupt-flicker {
  0%, 82%, 86%, 100% {
    opacity: 1;
  }
  84% {
    opacity: 0.35;
  }
}

/* Écran de divergence : toute la page passe en négatif (une bascule à l'ouverture, une à la fermeture). */
.is-negative {
  --bg: var(--neg-bg);
  --fg: var(--neg-fg);
  --fg-2: var(--neg-fg-2);
  --fg-3: var(--neg-fg-3);
  --line: var(--neg-line);
  --line-strong: var(--neg-line-strong);
  --alert: var(--neg-alert);
  --alert-line: var(--neg-alert-line);
  --alert-deep: var(--neg-alert-deep);
  color-scheme: light;
}

.js-motion {
  transition-property: --bg, --fg, --fg-2, --fg-3, --line, --line-strong, --alert, --alert-line, --alert-deep;
  transition-duration: 800ms;
  transition-timing-function: var(--ease);
}

.is-negative .c-negative {
  visibility: visible;
  opacity: 1;
  transition: opacity var(--dur-base) var(--ease), visibility 0s;
}

/* Tablette et téléphone : l'orbe quitte la pastille et revient en grand au-dessus du titre. */
@media (max-width: 1023.98px) {
  .is-negative .l-orb {
    transform: none;
  }

  /* Déroulé : l'orbe revenue à l'échelle 1 couvre le haut du texte ; le toucher le traverse (décision 6). */
  .is-unrolled:not(.is-negative) .l-orb > canvas {
    pointer-events: none;
  }

  .js-motion.is-negative .l-orb,
  .js-motion.is-negative-out .l-orb {
    transition: transform 800ms var(--ease);
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

@keyframes cue {
  0% {
    transform: scaleY(0);
    transform-origin: top;
  }
  45% {
    transform: scaleY(1);
    transform-origin: top;
  }
  55% {
    transform: scaleY(1);
    transform-origin: bottom;
  }
  100% {
    transform: scaleY(0);
    transform-origin: bottom;
  }
}

/* Navigation sans le JS (retour, lien ouvert autrement) : même fondu blanc puis noir, entre documents. */
@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: vt-out 700ms var(--ease) both;
}

::view-transition-new(root) {
  animation: fade-in 500ms var(--ease) 700ms both;
}

@keyframes vt-out {
  43% {
    filter: brightness(0) invert(1);
  }
  100% {
    filter: brightness(0);
  }
}

.is-travelling { overflow: hidden; }
.is-simulating { overflow: hidden; }
.is-ring-static { border-radius: 50%; border: 1px solid var(--line-strong); }
.is-model-applied .is-ring-static { border-color: var(--alert); box-shadow: inset 0 0 0 3px var(--alert-line); }
.is-orb-pinned:not(.is-negative) .c-orbital { visibility: hidden; pointer-events: none; }
.is-orb-pinned:not(.is-negative) .c-brand__sys { visibility: hidden; }

@media (prefers-reduced-motion: reduce) {
  .is-reading .c-reading-text,
  .is-veiled { opacity: 1; filter: none; mask-image: none; text-shadow: none; }
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 150ms !important;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }

  /* Bascule en négatif instantanée. */
  html,
  .c-negative,
  .c-simulation,
  .c-simulation *,
  .c-model,
  .c-model * {
    transition: none !important;
  }
}
