/* ============================================================
   Shared site-wide polish: film grain, custom cursor, magnetic
   buttons. Additive only — does not touch any existing selector,
   safe to load on every page alongside its own stylesheet.
   ============================================================ */

/* ---------- film grain overlay ----------
   Sits above everything, blended in, so large flat dark areas
   don't read as plastic-flat on big monitors. Purely decorative:
   aria-hidden, no pointer events, invisible to reduced-motion. */
.grain-overlay {
  position: fixed;
  top: -12%; left: -12%;
  width: 124%; height: 124%;
  z-index: 9998;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 160px 160px;
  animation: grain-shift 1s steps(6) infinite;
}
@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  16%  { transform: translate(-3%, -5%); }
  33%  { transform: translate(-6%, 3%); }
  50%  { transform: translate(4%, -6%); }
  66%  { transform: translate(-2%, 5%); }
  83%  { transform: translate(5%, 2%); }
  100% { transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .grain-overlay { animation: none; }
}

/* ---------- cursor glow (desktop / fine-pointer only) ----------
   The native cursor stays exactly as it is — this just adds a soft
   teal ring + glow that trails it, growing over links/buttons. */
@media (hover: hover) and (pointer: fine) {
  .cursor-ring {
    position: fixed;
    top: 0; left: 0;
    width: 36px; height: 36px;
    margin: -18px 0 0 -18px;
    border-radius: 50%;
    pointer-events: none;
    z-index: 9999;
    will-change: transform;
    /* no border/ring shape — just a soft glow that fades smoothly to
       nothing, no hard circular edge */
    background: radial-gradient(circle, rgba(0, 212, 180, 0.4) 0%, rgba(0, 212, 180, 0.14) 45%, rgba(0, 212, 180, 0) 72%);
    filter: blur(1.5px);
    transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1), height 0.3s cubic-bezier(0.16, 1, 0.3, 1),
      margin 0.3s cubic-bezier(0.16, 1, 0.3, 1), background 0.3s ease, opacity 0.25s ease;
  }
  .cursor-ring.is-hover {
    width: 64px; height: 64px;
    margin: -32px 0 0 -32px;
    background: radial-gradient(circle, rgba(0, 212, 180, 0.55) 0%, rgba(0, 212, 180, 0.2) 45%, rgba(0, 212, 180, 0) 72%);
  }
  body.cursor-idle .cursor-ring,
  body.cursor-over-field .cursor-ring {
    opacity: 0;
  }
}

/* ---------- magnetic buttons ----------
   JS sets an inline transform while the cursor is near; this just
   gives the release (mouseleave) a soft spring back to place. */
.magnetic {
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .magnetic { transition: none; }
}

/* ---------- scroll-type reveal ----------
   Each word is its own span; JS sets its opacity per frame based on
   scroll position while the block is on screen. The dim starting
   opacity lives here so the words never flash at full brightness
   before JS has a chance to wrap and dim them. */
.stw { transition: opacity 0.15s linear; }
.stw-dim { opacity: 0.3; }
@media (prefers-reduced-motion: reduce) {
  .stw, .stw-dim { opacity: 1 !important; transition: none; }
}
