/* =====================================================================
   ✦ SPARK LAYER - custom cursor, spin badge, theme wipe, click sparks.
   Purely additive on top of styles.css. Every effect is gated:
   html[data-cursor], pointer-fine media.
   ===================================================================== */

/* ----------  CUSTOM CURSOR  ---------- */
@media (hover: hover) and (pointer: fine) {
  html[data-cursor="on"], html[data-cursor="on"] *,
  html[data-cursor="on"] *::before, html[data-cursor="on"] *::after { cursor: none !important; }
  /* keep native cursor for text entry + the tweaks panel */
  html[data-cursor="on"] input, html[data-cursor="on"] textarea,
  html[data-cursor="on"] select,
  html[data-cursor="on"] #tweaks-root, html[data-cursor="on"] #tweaks-root * { cursor: auto !important; }
}
.cursor-dot, .cursor-ring {
  position: fixed; top: 0; left: 0; z-index: 500; pointer-events: none;
  opacity: 0; transition: opacity .4s var(--ease);
  will-change: transform;
}
html[data-cursor="on"] .cursor-dot.is-live,
html[data-cursor="on"] .cursor-ring.is-live { opacity: 1; }
.cursor-dot {
  width: 6px; height: 6px; margin: -3px 0 0 -3px; border-radius: 50%;
  background: var(--accent);
}
.cursor-ring {
  width: 26px; height: 26px; margin: -13px 0 0 -13px; border-radius: 50%;
  border: 1.5px solid var(--fg);
  mix-blend-mode: difference; border-color: #fff;
  display: flex; align-items: center; justify-content: center;
  transition: opacity .4s var(--ease), width .35s var(--ease), height .35s var(--ease),
              margin .35s var(--ease), background-color .35s var(--ease), border-color .35s var(--ease);
}
/* hover state: ring swells slightly */
.cursor-ring.is-link { width: 38px; height: 38px; margin: -19px 0 0 -19px; }
/* label state over work rows: ring becomes a solid badge with text */
.cursor-ring__label {
  font-family: var(--font-mono); font-size: .58rem; letter-spacing: .1em;
  text-transform: uppercase; color: #000; opacity: 0; transform: scale(.6);
  transition: opacity .3s var(--ease), transform .35s var(--ease);
  white-space: nowrap;
}
.cursor-ring.is-label {
  width: 58px; height: 58px; margin: -29px 0 0 -29px;
  background: #fff; border-color: #fff;
}
.cursor-ring.is-label .cursor-ring__label { opacity: 1; transform: scale(1); }
/* pressed: dot swells briefly */
.cursor-dot.is-down { transform-origin: center; }
@media (hover: none), (pointer: coarse) { .cursor-dot, .cursor-ring { display: none; } }

/* ----------  CLICK SPARKS - tiny accent shards burst from the click point ---------- */
.spark-bit {
  position: fixed; top: 0; left: 0; z-index: 499; pointer-events: none;
  width: 5px; height: 1.5px; border-radius: 1px; background: var(--accent);
  will-change: transform, opacity;
}

/* ----------  SPIN BADGE - rotating circular text, links to contact ---------- */
.spinbadge {
  position: absolute; right: var(--pad); top: 50%;
  transform: translateY(-72%);
  width: clamp(96px, 9.5vw, 132px); aspect-ratio: 1; z-index: 2;
  display: grid; place-items: center;
  opacity: 0; animation: metaIn 1.1s var(--ease) .85s forwards;
}
.spinbadge__svg { position: absolute; inset: 0; width: 100%; height: 100%;
  animation: spinbadge 22s linear infinite; }
.spinbadge:hover .spinbadge__svg { animation-duration: 7s; }
.spinbadge__svg text {
  font-family: var(--font-mono); font-size: 8.2px; letter-spacing: .28em;
  text-transform: uppercase; fill: var(--fg-dim);
  transition: fill .4s var(--ease);
}
.spinbadge:hover .spinbadge__svg text { fill: var(--fg); }
.spinbadge__core {
  width: 34%; aspect-ratio: 1; border-radius: 50%;
  border: 1px solid var(--line); display: grid; place-items: center;
  font-size: 1rem; color: var(--accent);
  transition: transform .5s var(--ease), background .4s var(--ease),
              color .4s var(--ease), border-color .4s var(--ease);
}
.spinbadge:hover .spinbadge__core {
  background: var(--accent); color: var(--accent-ink);
  border-color: var(--accent); transform: scale(1.08);
}
@keyframes spinbadge { to { transform: rotate(360deg); } }
@media (max-width: 900px) { .spinbadge { display: none; } }

/* the pill is taller than the text links - center-align the nav row,
   and set it off from the text links with a hairline divider */
.nav__links { align-items: center; }
.nav__links .themetoggle { margin-left: clamp(6px, 1vw, 14px); position: relative; }
.nav__links .themetoggle::before {
  content: ""; position: absolute; left: calc(clamp(6px, 1vw, 14px) * -0.5 - 1px);
  top: 50%; height: 16px; width: 1px; transform: translateY(-50%);
  background: var(--line);
}

/* ----------  THEME TOGGLE (nav) - editorial pill switch  ----------
   A slim capsule: a puck slides end-to-end (sun morphs into moon inside it)
   while the mono label rolls vertically between LIGHT and DARK.
   Hover: puck leans toward the other side (a "peek"); active: puck squashes. */
.themetoggle {
  --tt-w: 46px; --tt-h: 24px; --tt-puck: 17px; --tt-inset: 3px;
  --tt-x: 0px; --tt-peek: 0px;
  appearance: none; -webkit-appearance: none; cursor: pointer;
  position: relative; display: inline-block;
  width: var(--tt-w); height: var(--tt-h); padding: 0;
  border: 1px solid var(--line); border-radius: 999px;
  background: color-mix(in oklab, var(--bg-soft) 72%, transparent);
  color: var(--fg); overflow: hidden;
  transition: border-color .45s var(--ease), background .45s var(--ease);
}
.themetoggle:hover { border-color: color-mix(in oklab, var(--fg) 42%, var(--line)); }
.themetoggle:focus-visible { outline: 1px solid var(--accent); outline-offset: 3px; }
:root[data-theme="dark"] .themetoggle { --tt-x: calc(var(--tt-w) - var(--tt-puck) - var(--tt-inset) * 2 - 2px); }
:root[data-theme="light"] .themetoggle:hover { --tt-peek: 3px; }
:root[data-theme="dark"] .themetoggle:hover { --tt-peek: -3px; }

.tt-puck {
  position: absolute; top: var(--tt-inset); left: var(--tt-inset);
  width: var(--tt-puck); height: var(--tt-puck); border-radius: 50%;
  background: var(--fg); color: var(--bg);
  display: grid; place-items: center;
  transform: translateX(calc(var(--tt-x) + var(--tt-peek)));
  transition: transform .6s var(--snap), background .45s var(--ease);
  will-change: transform;
}
.themetoggle:active .tt-puck { transform: translateX(calc(var(--tt-x) + var(--tt-peek))) scale(.88); }
.themetoggle__svg { width: 13px; height: 13px; overflow: visible; display: block; position: relative; }
/* two crossfading icons stacked in the same box */
.tt-ico { transform-box: fill-box; transform-origin: center;
  transition: opacity .4s var(--ease), transform .55s var(--snap); }
.tt-sun { stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.tt-moon { fill: currentColor; stroke: none; }
/* light = sun in, moon out (spun away); dark = the reverse */
:root[data-theme="light"] .tt-sun  { opacity: 1; transform: rotate(0) scale(1); }
:root[data-theme="light"] .tt-moon { opacity: 0; transform: rotate(-70deg) scale(.4); }
:root[data-theme="dark"]  .tt-sun  { opacity: 0; transform: rotate(70deg) scale(.4); }
:root[data-theme="dark"]  .tt-moon { opacity: 1; transform: rotate(0) scale(1); }

/* labels removed - the sun→moon puck carries the meaning on its own */
.tt-label { display: none; }

/* ----------  THEME SWEEP - circular cover from the toggle ---------- */
/* One composited layer, transform/opacity only; --fg of the outgoing theme
   reads as the incoming theme's ground, so the flip underneath is invisible */
.theme-sweep {
  position: fixed; width: 48px; height: 48px; border-radius: 50%;
  z-index: 400; pointer-events: none;
  background: var(--fg);
  transform: scale(0); will-change: transform, opacity;
}
/* while covered, the page must snap to the new theme in a single repaint -
   per-element color transitions would otherwise keep repainting the blurred
   aurora/grain stack for 500ms after the cover lifts */
.theme-flip, .theme-flip *:not(.theme-sweep), .theme-flip *::before, .theme-flip *::after {
  transition: none !important;
}
.theme-flip .aurora::before, .theme-flip .aurora::after, .theme-flip .aurora__b {
  animation-play-state: paused;
}

/* ----------  HERO - cursor-follow drift composes into existing transform ---------- */
.hero__name {
  transform: translate(var(--hero-mx, 0px), calc(var(--hero-ty, 0px) + var(--hero-my, 0px)))
             skewX(var(--hero-sk, 0deg));
}
