/* ============================================================
   PRELOADER, CURSOR, MISC UI
   ============================================================ */

.preloader {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-6);
  transition: opacity 0.7s var(--ease-out), visibility 0.7s var(--ease-out);
}
.preloader.is-done { opacity: 0; visibility: hidden; pointer-events: none; }

.preloader-mark {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 24px 4px rgb(91 108 255);
  animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.6); opacity: 0.6; }
}

.preloader-bar {
  width: 220px;
  height: 2px;
  background: var(--line);
  border-radius: 2px;
  overflow: hidden;
}
.preloader-bar-fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width 0.25s var(--ease-out);
}
.preloader-pct {
  font-family: var(--font-body);
  font-size: var(--fs-small);
  color: var(--ink-faint);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
}

/* Ambient cursor spotlight — a soft light that trails the pointer across
   the entire page (see main.js initCursorGlow). Screen-blended so it only
   ever lightens whatever's beneath it, never fights legibility. */
.cursor-glow {
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0;
  background: radial-gradient(
    120px circle at var(--gx, 50%) var(--gy, 50%),
    rgba(138, 245, 255, 0.14),
    rgba(91, 108, 255, 0.06) 42%,
    transparent 72%
  );
  transition: opacity 0.5s var(--ease-out);
}
.cursor-glow.is-active { opacity: 1; }

@media (prefers-reduced-motion: reduce), (pointer: coarse) {
  .cursor-glow { display: none; }
}

/* Ambient background video loop — replaces a flat section background with
   a slow-moving glow (see assets/video/bg). Screen-blended over the
   section's own dark gradient (kept in place, not removed) so the video's
   near-black footage disappears into it and only the two light streaks
   visibly add glow — contrast/legibility for the content on top is never
   at the mercy of tuning a single opacity value. Lazy-played by
   initBgVideos() in main.js once the section nears the viewport. */
.section-bg-video {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  opacity: 0.3;
  mix-blend-mode: screen;
}
.section-bg-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Keeps the loop reading as "very dark" rather than a visible bright
     streak — the edge vignette below handles the border fade. Contrast
     pushes the shadow/haze around the light streaks further toward
     black, which reads as darker overall without dimming the highlight
     cores as much as an equivalent brightness drop would. hue-rotate alone
     was never reliable here — it only ever nudges the existing hue, and
     the source's shadows carry enough red alongside the blue that some
     framing still read as purple no matter the rotation angle. saturate
     is the actual fix: pushed this low, there's barely any hue left to
     read as purple (or any other color) in the first place. */
  filter: brightness(0.55) contrast(1.35) saturate(0.1) hue-rotate(-13deg);
}

@media (prefers-reduced-motion: reduce) {
  .section-bg-video { display: none; }
}

/* no-js / no-webgl fallback notice (rarely shown) */
.js-fallback-note { display: none; }
.no-js .js-fallback-note { display: block; }
.no-js .journey-media video,
.no-js .site-nav { display: none; }

/* Utility */
.mt-0 { margin-top: 0 !important; }
