/* effects.css - layered animation/effect styles for arjavjain.org
   Progressive enhancement only. Every rule here can be absent and the site
   still works perfectly. All color via site.css vars (warm cream/terracotta).
   Scope: ClickSpark canvas, CurvedLoop band, SpecularButton sheen, ScrollStack.
*/

/* ============================================================
   1. ClickSpark
   One fixed full-viewport canvas, no layout impact, on top of UI but
   transparent to pointer events so it never blocks clicks.
   ============================================================ */
.efx-spark-canvas {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 9999;
  /* spark color is read from --accent in JS; canvas itself is transparent */
}

/* ============================================================
   2. CurvedLoop
   A slim marquee band. The SVG + textPath are built in JS; this just
   sizes/scopes the container. ~120-140px tall, never full viewport.
   ============================================================ */
.curved-loop {
  display: block;
  width: 100%;
  height: clamp(120px, 14vw, 140px);
  overflow: visible;       /* allow the curved tail to breathe */
  margin-block: 0;
  pointer-events: auto;    /* optional drag-to-scrub */
  user-select: none;
  -webkit-user-select: none;
}
.curved-loop__svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.curved-loop__text {
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 3.4vw, 3rem);
  font-weight: 500;
  letter-spacing: -0.01em;
  fill: var(--muted);
}
.curved-loop__text--accent { fill: var(--accent); }

/* When the band sits as its own section spacer, give it room above/below.
   Only applied when the page wraps it in .curved-loop--section. */
.curved-loop--section {
  padding-block: var(--sp-4, 2rem);
}

/* ============================================================
   3. SpecularButton (light CSS cursor-sheen, no WebGL)
   The sheen is a masked radial highlight on a ::before pseudo. The
   JS writes --mx / --my (0..1, relative to the button) and --spec
   (0..1 proximity) on pointermove. Default (no JS) = no sheen, the
   button still works and still uses its existing .btn styling.
   ============================================================ */
[data-specular] {
  position: relative;
  overflow: hidden;
  isolation: isolate;       /* contain the blended layer */
}
[data-specular]::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 0;
  opacity: 0;               /* hidden until cursor enters */
  /* Radial sheen centered at the cursor; accent-tinted, soft. */
  background: radial-gradient(
    120px 120px at calc(var(--mx, 0.5) * 100%) calc(var(--my, 0.5) * 100%),
    oklch(from var(--accent) l c h / 0.55),
    oklch(from var(--accent-2) l c h / 0.18) 45%,
    transparent 72%
  );
  mix-blend-mode: screen;
  transition: opacity var(--dur-fast) var(--ease-soft);
}
/* Specular sheen only shows while the cursor is actually over the button.
   JS toggles .efx-spec-active on enter/leave so the highlight fades cleanly. */
[data-specular].efx-spec-active::before { opacity: calc(0.65 * var(--spec, 0)); }
/* Keep button label/arrow above the sheen layer. */
[data-specular] > * { position: relative; z-index: 1; }
/* Subtle press feedback (active state) without fighting existing .btn transitions. */
[data-specular]:active { transform: scale(0.97); }

/* ============================================================
   4. ScrollStack (light, native scroll)
   Desktop (>=1024px) only. Each .topic-block gets a stacking context;
   earlier lanes scale down slightly as the next slides up over them.
   Implemented via transforms applied by JS to an inner wrapper
   (.efx-stack-inner) so we never fight the existing .reveal transform
   on .topic-block itself. z-index gives the slide-up-and-over effect.
   We do NOT touch position:sticky on .topic-block__side.
   ============================================================ */
@media (min-width: 1024px) {
  /* The wrapper holds the cards column; side aside is untouched. */
  .efx-stack-inner {
    will-change: transform;
    transform-origin: center top;
    /* No transition: we drive per-frame via rAF for smoothness. */
  }
  /* When stacked, raise z-index so the sliding lane covers earlier ones.
     Set by JS adding .efx-stack-active on the section container. */
  .topic-block { transition: none; }
  .efx-stack-ready .topic-block { position: relative; z-index: 1; }
}

/* ============================================================
   Reduced motion - everything snaps to a static, working state.
   No animation, no transforms from effects, no transitions on effects.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .efx-spark-canvas { display: none; }
  .curved-loop { height: auto; min-height: 0; }
  .curved-loop__svg { display: none; }
  /* Render the loop text as a simple static line so content still shows. */
  .curved-loop--static {
    display: block;
    text-align: center;
    font-family: var(--font-display);
    font-size: clamp(1.25rem, 2.4vw, 1.75rem);
    color: var(--muted);
    padding: var(--sp-4, 2rem) 0;
    letter-spacing: -0.01em;
  }
  [data-specular]::before { display: none; }
  [data-specular]:active { transform: none; }
  /* ScrollStack: never apply stacking transforms or dimming. */
  .efx-stack-inner { transform: none !important; opacity: 1 !important; will-change: auto !important; }
}
