/**
 * BeMatrx — UI effects
 *
 * Micro-interactions adapted from React Bits (https://reactbits.dev,
 * MIT + Commons Clause). React Bits ships four variants per component
 * (JS/TS x CSS/Tailwind) and several of its components pull gsap, motion,
 * three or ogl from npm; this theme has no Tailwind and a deliberately
 * empty dependency list, so only the effects that reduce to plain CSS were
 * taken, rewritten against the --bm-* tokens:
 *
 *   SpotlightCard -> .bm-spotlight  (components/ui/SpotlightGroup.tsx)
 *   ShinyText     -> .bm-shiny      (components/ui/ShinyText.tsx)
 *
 * CountUp (components/ui/CountUp.tsx) is the third port; it needs no CSS.
 *
 * Loaded globally from app/layout.tsx (precedence bm-8) — after home.css,
 * before the per-route sheets. Every selector here is new, so cascade
 * position never decides a conflict.
 *
 * @package BeMatrx
 * @since   2026-08-04
 */

/* =====================  Spotlight (cards)  ========================= */

/* A soft radial wash in the card's own accent colour that follows the
   cursor. Applied to the white artifact cards only — .bm-counter,
   .bm-crew-badge, .bm-career-card — never to the dark passes/tickets or
   to the prints, which DESIGN.md §8 keeps static. */
.bm-spotlight {
  /* .bm-counter is not positioned; the crew badge and career card already
     are. Setting it here is harmless for those two (no absolutely
     positioned descendants depend on a different containing block). */
  position: relative;
  /* Keeps the -1 layer inside the card: without a stacking context the
     glow would slide behind the section background and disappear. */
  isolation: isolate;
  --bm-spot-x: 50%;
  --bm-spot-y: 38%;
  --bm-spot-size: 260px;
  /* Channel colour (counters, crew badges) -> career colour (home grid)
     -> brand red. Each card sets whichever token it owns inline. */
  --bm-spot-tint: var(--c, var(--career-accent, var(--bm-primary)));
}

.bm-spotlight::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(
    var(--bm-spot-size) circle at var(--bm-spot-x) var(--bm-spot-y),
    color-mix(in srgb, var(--bm-spot-tint) 15%, transparent),
    transparent 72%
  );
  opacity: 0;
  transition: opacity 0.45s var(--bm-ease-out);
}

/* :focus-within gives keyboard users the same cue — the mono-chip links
   inside counters are focusable. The default 50%/38% origin makes that
   case read as a centred wash rather than a corner smudge. */
.bm-spotlight:hover::after,
.bm-spotlight:focus-within::after {
  opacity: 1;
}

/* The glow radius is a length (radial-gradient takes no percentage for a
   circle), so it has to be sized per card family: the default 260px suits
   the ~380px-wide counters, but on the smaller crew badges and home career
   tiles the same radius floods the whole card and reads as a flat tint
   instead of a pool under the cursor. */
.bm-crew-badge.bm-spotlight {
  --bm-spot-size: 170px;
}
.bm-home-character__grid .bm-spotlight {
  --bm-spot-size: 150px;
}

/* =====================  Shiny text (gold foil)  ==================== */

/* Sweep spends the first ~45% of the cycle crossing the text and then
   holds off-screen, so the label reads as an occasional glint rather than
   a constantly moving element. background-position is a paint-thread
   animation, hence the small, short-lived surface area.
   background-position stays inside 0%..100% ON PURPOSE. The fill is fully
   transparent, so any sliver of the text box the gradient does not cover
   renders as *invisible text*, not as plain gold — and a percentage
   outside that range offsets the image by (boxWidth - imageWidth) * pct,
   which walks the 250%-wide gradient clean off the label. At 0% and 100%
   the image still covers the box end to end while the highlight band sits
   just outside it, so the resting state is solid gold either way. */
.bm-shiny {
  display: inline-block;
  background-image: linear-gradient(
    110deg,
    currentColor 0%,
    currentColor 40%,
    var(--bm-shiny-highlight, #fff7d6) 50%,
    currentColor 60%,
    currentColor 100%
  );
  background-size: 250% 100%;
  /* Tiling (the default) is the second guard: neighbouring tiles are
     2.5x the label away, too far to show a second highlight, but they
     paint any edge the primary tile leaves uncovered. */
  background-position: 100% center;
}

/* Guarded: without background-clip the transparent fill would erase the
   text instead of revealing a gradient through it. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .bm-shiny {
    -webkit-background-clip: text;
    background-clip: text;
    /* text-fill, NOT `color` — `color` has to stay gold for the
       currentColor stops in the gradient above to resolve. */
    -webkit-text-fill-color: transparent;
    animation: bm-shiny-sweep var(--bm-shiny-speed, 6s) linear infinite;
  }
}

@keyframes bm-shiny-sweep {
  0% {
    background-position: 100% center;
  }
  45%,
  100% {
    background-position: 0% center;
  }
}

/* =====================  Reduced motion  =========================== */

@media (prefers-reduced-motion: reduce) {
  /* The spotlight is cursor-driven movement by definition — drop it
     entirely rather than transitioning it faster. */
  .bm-spotlight::after {
    display: none;
  }
  .bm-shiny {
    animation: none;
    background-image: none;
    -webkit-text-fill-color: currentColor;
  }
}
