/* ==========================================================================
   FX — the futuristic layer
   Ambient backdrops, glow, sweeps, spotlights and text effects.
   Token-driven, works in both themes, all killed by prefers-reduced-motion.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Aurora — slow drifting brand mesh behind a section
   -------------------------------------------------------------------------- */

.fxAurora { position: relative; isolation: isolate; }

.fxAurora::before {
  content: "";
  position: absolute;
  inset: -25%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(32% 42% at 20% 28%, rgba(var(--qd-accent-rgb), 0.30), transparent 62%),
    radial-gradient(30% 38% at 78% 22%, rgba(var(--qd-gradB-rgb), 0.26), transparent 62%),
    radial-gradient(34% 40% at 55% 78%, rgba(var(--qd-gradA-rgb), 0.22), transparent 62%);
  filter: blur(44px) saturate(1.15);
  /* Promote to its own layer so the blur rasterises once and the animation is
     a pure compositor transform. Without this the whole blurred area repaints
     every frame and the page feels sluggish on click and scroll. */
  will-change: transform;
  transform: translateZ(0);
  animation: fxAuroraDrift 22s ease-in-out infinite alternate;
}

@keyframes fxAuroraDrift {
  0%   { transform: translate3d(0, 0, 0) scale(1)    rotate(0deg); }
  50%  { transform: translate3d(2%, -3%, 0) scale(1.12) rotate(4deg); }
  100% { transform: translate3d(-3%, 2%, 0) scale(1.05) rotate(-3deg); }
}

/* --------------------------------------------------------------------------
   Grid backdrop with a horizon fade — the "tech floor"
   -------------------------------------------------------------------------- */

.fxGrid { position: relative; isolation: isolate; }

.fxGrid::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(var(--qd-gradA-rgb), 0.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--qd-gradA-rgb), 0.10) 1px, transparent 1px);
  background-size: 54px 54px;
  -webkit-mask: radial-gradient(80% 60% at 50% 0%, #000 10%, transparent 85%);
  mask: radial-gradient(80% 60% at 50% 0%, #000 10%, transparent 85%);
  animation: fxGridPan 28s linear infinite;
}

@keyframes fxGridPan { to { background-position: 54px 54px; } }

/* Scan line sweeping down a panel. */
.fxScan { position: relative; overflow: hidden; }

.fxScan::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -30%;
  height: 30%;
  pointer-events: none;
  background: linear-gradient(180deg,
    transparent,
    rgba(var(--qd-gradA-rgb), 0.13),
    transparent);
  animation: fxScanDown 5.5s ease-in-out infinite;
}

@keyframes fxScanDown { to { top: 110%; } }

/* --------------------------------------------------------------------------
   Cursor spotlight — follows the pointer across a card
   (--fx-x / --fx-y are written by fx.js)
   -------------------------------------------------------------------------- */

.fxSpot { position: relative; isolation: isolate; }

.fxSpot::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
  background: radial-gradient(
    240px circle at var(--fx-x, 50%) var(--fx-y, 50%),
    rgba(var(--qd-gradA-rgb), 0.16),
    transparent 65%
  );
}

.fxSpot:hover::before { opacity: 1; }
.fxSpot > * { position: relative; z-index: 1; }

/* 3D tilt, driven by fx.js */
.fxTilt {
  transform: perspective(900px)
             rotateX(var(--fx-rx, 0deg))
             rotateY(var(--fx-ry, 0deg));
  transform-style: preserve-3d;
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

/* --------------------------------------------------------------------------
   Shine sweep across a button or card on hover
   -------------------------------------------------------------------------- */

.fxShine { position: relative; overflow: hidden; }

.fxShine::after {
  content: "";
  position: absolute;
  top: 0;
  left: -120%;
  width: 60%;
  height: 100%;
  pointer-events: none;
  transform: skewX(-22deg);
  background: linear-gradient(90deg,
    transparent,
    rgba(255, 255, 255, 0.18),
    transparent);
}

.fxShine:hover::after { animation: fxShineSweep 0.85s ease; }

@keyframes fxShineSweep { to { left: 140%; } }

/* --------------------------------------------------------------------------
   Glow
   -------------------------------------------------------------------------- */

.fxGlow {
  box-shadow:
    0 0 0 1px rgba(var(--qd-gradA-rgb), 0.16),
    0 0 26px rgba(var(--qd-gradA-rgb), 0.14),
    0 0 60px rgba(var(--qd-gradB-rgb), 0.10);
}

.fxGlowPulse { animation: fxGlowPulse 3.4s ease-in-out infinite; }

@keyframes fxGlowPulse {
  0%, 100% { box-shadow: 0 0 18px rgba(var(--qd-gradA-rgb), 0.12); }
  50%      { box-shadow: 0 0 38px rgba(var(--qd-gradB-rgb), 0.26); }
}

/* Small live indicator. */
.fxPing {
  position: relative;
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--qd-gradA);
}

.fxPing::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: inherit;
  animation: fxPing 1.9s cubic-bezier(0, 0, 0.2, 1) infinite;
}

@keyframes fxPing {
  0%   { transform: scale(1);   opacity: 0.7; }
  80%, 100% { transform: scale(2.6); opacity: 0; }
}

/* --------------------------------------------------------------------------
   Text effects
   -------------------------------------------------------------------------- */

/* Gradient that slowly travels through a heading. */
.fxTextFlow {
  background: linear-gradient(100deg,
    var(--qd-gradA), var(--qd-gradB), var(--qd-accent), var(--qd-gradA)
  ) 0 0 / 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: fxTextFlow 8s linear infinite;
}

@keyframes fxTextFlow { to { background-position: 300% 0; } }

/* Monospace label with a tracking-in feel. */
.fxMono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--qd-fs-xs);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--qd-muted);
}

/* --------------------------------------------------------------------------
   Marquee
   -------------------------------------------------------------------------- */

.fxMarquee {
  overflow: hidden;
  -webkit-mask: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.fxMarquee__track {
  display: flex;
  gap: 14px;
  width: max-content;
  animation: fxMarquee 34s linear infinite;
}

.fxMarquee:hover .fxMarquee__track { animation-play-state: paused; }

@keyframes fxMarquee { to { transform: translateX(-50%); } }

/* --------------------------------------------------------------------------
   Corner brackets — HUD framing
   -------------------------------------------------------------------------- */

.fxBrackets { position: relative; }

.fxBrackets::before,
.fxBrackets::after {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  pointer-events: none;
  border-color: rgba(var(--qd-gradA-rgb), 0.5);
  border-style: solid;
  transition: inset 0.4s ease;
}

.fxBrackets::before {
  top: 10px;
  left: 10px;
  border-width: 1px 0 0 1px;
  border-top-left-radius: 5px;
}

.fxBrackets::after {
  right: 10px;
  bottom: 10px;
  border-width: 0 1px 1px 0;
  border-bottom-right-radius: 5px;
}

/* --------------------------------------------------------------------------
   Navbar scroll state — dark over the hero, themed once scrolled
   -------------------------------------------------------------------------- */

.qdNav__inner {
  transition: background 0.35s ease, box-shadow 0.35s ease,
              border-color 0.35s ease, transform 0.35s ease;
}

/* Over the hero the bar is lighter-weight; it solidifies once you scroll past.
   Colour still comes from the theme — the hero follows the theme now, so
   forcing white here would break light mode. */
body.hasDarkHero .qdNav:not(.isScrolled) .qdNav__inner {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.qdNav.isScrolled .qdNav__inner {
  box-shadow: var(--qd-nav-shadow), 0 0 30px rgba(var(--qd-gradA-rgb), 0.08);
}

/* --------------------------------------------------------------------------
   Reduced motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="force"]) .fxAurora::before,
  html:not([data-motion="force"]) .fxGrid::before,
  html:not([data-motion="force"]) .fxScan::after,
  html:not([data-motion="force"]) .fxMarquee__track,
  html:not([data-motion="force"]) .fxTextFlow,
  html:not([data-motion="force"]) .fxGlowPulse,
  html:not([data-motion="force"]) .fxPing::after { animation: none !important; }

  html:not([data-motion="force"]) .fxTilt { transform: none !important; }
}
