/**
 * mobile-motion.css — motion budget for phones and tablets
 *
 * THE PROBLEM
 * The site runs ~33 infinite CSS animations at once on the homepage. Twelve of
 * them animate transform or opacity, which the compositor handles for free.
 * The other twenty-one animate box-shadow, text-shadow, filter,
 * background-position or `left` — none of which can be composited, so each one
 * forces the browser to repaint its element every single frame, forever.
 *
 * On a desktop that is invisible. On a phone it is not: measured on the
 * homepage at 390px with the CPU throttled 6x, scrolling ran at a median of
 * 50ms per frame with 55 of 93 frames over 50ms. That is the flickering —
 * the page cannot finish painting between frames, so it tears and stutters.
 * With every animation disabled the same scroll ran at 4.2ms median and zero
 * long frames. Animations were the whole cause; shadows, blurs, the animated
 * background and the cursor trail each made no measurable difference.
 *
 * WHY DEFAULT-DENY
 * The obvious fix is a list of the offending selectors. That fails here for two
 * reasons: several of the worst offenders are inline `style="animation: ..."`
 * attributes on the homepage rather than rules in a stylesheet, and any
 * animation added later would silently reintroduce the problem. So this turns
 * everything off and names the ones worth keeping. A new animation is then
 * fast-by-default on mobile, and someone has to make a deliberate decision to
 * exempt it.
 *
 * `animation-name` alone is overridden rather than the whole shorthand, so the
 * original duration, easing and iteration count survive — re-enabling an
 * animation below only needs its name.
 *
 * !important is required, not laziness: it is the only thing that beats the
 * inline animation attributes on the homepage buttons.
 */

@media (max-width: 1024px), (hover: none) and (pointer: coarse) {

  *,
  *::before,
  *::after {
    animation-name: none !important;
  }

  /* ── Allowlist ──────────────────────────────────────────────
     Every one of these animates only transform or opacity, so it runs on the
     compositor and costs nothing to keep. They are the small signs of life
     that stop the site looking frozen. */

  .cyber-terminal-title::after            { animation-name: terminalBlink !important; }   /* the blinking _ */
  .card[role="link"]:hover .card-terminal { animation-name: terminalBlink !important; }
  .live-dot::after                        { animation-name: liveDotPing !important; }     /* "online now" */
  .logo::before                           { animation-name: logoGlitch !important; }
  .nav-links::before                      { animation-name: panelNebula !important; }
  .profile-glow-badge::before             { animation-name: profileGlowSpin !important; }
  .floating-back-to-top                   { animation-name: backToTopFloat !important; }
  .floating-back-to-top::after            { animation-name: backToTopGlowSpin !important; }

  /* Tool pages: these two are status indicators rather than decoration — the
     radar says a scan is running, the beacon says the status check is live. */
  .pcs-console.is-scanning .pcs-radar__sweep { animation-name: pcsSweep !important; }
  .net-beacon::after                         { animation-name: netPulse !important; }
  /* CAT Sweep Timer's radar wedge. Transform-only, and it is the on-screen
     confirmation that a sweep is actually running — freezing it would make a
     live scan look stalled. */
  .dial.scanning .radar                      { animation-name: radarSpin !important; }
  /* The heading badge's shimmer. Transform-only, one element, and it is the
     app's signature — worth the compositor time. */
  .titlePill::after                          { animation-name: pillShine !important; }

  /* The app navigator on /apps drifting its pills past. Transform-only on a
     single element, so it composites like the rest of this list.

     Exempt out of necessity as much as taste: the nine app pills are far wider
     than a phone, and the drift is how the rail shows the ones off-screen. It
     replaced hand-scrolling rather than joining it — .apps-nav--marquee turns
     the track's overflow off, because a lane being animated and dragged at the
     same time fights itself. Frozen here, the rail would show the first three
     apps and offer no way at all to reach the other six. A tap still pauses it
     for a few seconds to aim, and prefers-reduced-motion below still stops it —
     apps.html hands scrolling back in the same breath, for exactly this. */
  .apps-nav--marquee .apps-nav-lane          { animation-name: apNavDrift !important; }

  /* ── Static fallbacks ───────────────────────────────────────
     A couple of elements relied on their animation to look finished rather
     than merely to move. Frozen mid-keyframe they would look wrong, so they
     get a sensible resting state. */

  /* logoShimmer slides a gradient across the wordmark; parked at 0% the
     gradient sits off to one side. Centre it. */
  .logo { background-position: 50% 50% !important; }

  /* The travelling border gradients read as a flat block when stopped, so
     hold them at a position where both colours show. */
  .live-telemetry,
  .loc-stats { background-position: 50% 50% !important; }
}

/* Anyone who has asked for reduced motion gets the same budget at every width,
   including desktop. The site already has a reduced-motion block; this makes
   sure the newer decorative layers are covered by it too. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-name: none !important;
  }
}
