/* ==========================================================================
   CUSTOM CURSOR — CLAUDE.md §5. Phase 6.

   At rest: the conch's OUTER SWEEP only — the last stretch of the spine,
   before it winds in. Not the full coil. §3's own note records why: at cursor
   size the tight inner windings collapse into a blob, and the crop that
   solves it is already documented in work.css as "0 450 550 1000". The same
   fraction is used here, so the cursor and the card coils are cropping the
   identical geometry rather than two hand-picked guesses.

   On hover it extends BACK along the path toward the fuller conch line —
   uncoiling, in the sense that more of the curve becomes visible from the
   inner end. The stroke never redraws; only how much of it shows changes.

   POINTER-EVENTS: NONE IS LOAD-BEARING. A full-viewport fixed layer that
   accepts pointer events swallows every click on the page. It would have
   silently re-broken click-to-zoom, the nav, and the video facades. It is
   declared on the host and never overridden.

   DESKTOP ONLY, gated in script on (hover: hover) and (pointer: fine) — the
   element is not created at all on touch, so there is nothing to interfere
   with a tap. The native cursor is only hidden once the custom one exists.
   ========================================================================== */

/* Hiding the native cursor is done by a class the script adds, so a page
   where the script never ran keeps its ordinary pointer rather than losing
   the cursor entirely. */
.has-conch-cursor,
.has-conch-cursor a,
.has-conch-cursor button,
.has-conch-cursor summary,
.has-conch-cursor .is-zoomable,
.has-conch-cursor label { cursor: none; }

.cursor {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: var(--z-cursor);
  pointer-events: none;          /* see the note above — never change this */
  width: var(--cursor-size, 26px);
  aspect-ratio: 666 / 908;
  /* translate3d keeps the follow on the compositor; nothing here triggers
     layout, so the page is not re-flowed once per pointer move. */
  transform: translate3d(-100px, -100px, 0);
  will-change: transform;
  opacity: 0;
  transition: opacity var(--t-quick) var(--ease),
              width var(--t-quick) var(--ease);
}

.cursor.is-visible { opacity: 1; }

.cursor svg { display: block; width: 100%; height: 100%; overflow: visible; }

.cursor__path {
  fill: none;
  stroke: var(--kumkumam);
  stroke-width: 46;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* REST — the outer sweep. dasharray reveals 550 of the 1000-unit path and
     dashoffset slides that window to start at 450, so what shows is the
     outer end of the curve and none of the inner winding. */
  stroke-dasharray: 550 1000;
  stroke-dashoffset: -450;
  transition: stroke-dasharray var(--t-base) var(--ease),
              stroke-dashoffset var(--t-base) var(--ease),
              stroke var(--t-quick) var(--ease);
}

/* HOVER — coils ALL THE WAY IN. The window opens to the whole 1000-unit path
   and its start slides to 0, so every winding including the tightest inner
   one is drawn. Stopping at 850/-150 left the gesture visibly unfinished —
   it read as a nudge rather than as the conch completing. The stroke is
   never redrawn; only how much of it shows changes. */
.cursor.is-over .cursor__path {
  stroke-dasharray: 1000 1000;
  stroke-dashoffset: 0;
}

/* OVER RED AND DARK GROUNDS the mark goes cream. --kumkumam on the About
   field, the inverted footer, a hovered card's wash or the CTA button is
   kumkumam on kumkumam — 1:1, invisible. The case-study blocks are dark for a
   different reason and need the same treatment.

   The transition is on `stroke` alone, so the switch reads as the mark
   changing ink rather than as a second animation competing with the uncoil. */
.cursor.is-inverted .cursor__path { stroke: var(--paper); }

/* QUIETER ON PROJECT PAGES (§5: "shorter, quicker version of the same
   effect"). §1 puts the shell's drama on the homepage and asks these pages to
   get out of the way, so the cursor is smaller and settles faster.

   The COIL ITSELF STILL COMPLETES here — quieter is carried by size and
   speed, not by truncating the gesture. A half-finished coil does not read as
   restraint, it reads as broken. */
.pj-cursor .cursor { --cursor-size: 20px; }

.pj-cursor .cursor__path {
  stroke-width: 54;              /* thinner artwork, so a heavier stroke */
  transition: stroke-dasharray var(--t-quick) var(--ease),
              stroke-dashoffset var(--t-quick) var(--ease);
}

.pj-cursor .cursor.is-over .cursor__path {
  stroke-dasharray: 1000 1000;
  stroke-dashoffset: 0;
}

/* REDUCED MOTION — the mark still tracks the pointer, which is what makes it
   a cursor, but nothing animates: no uncoil, no fade, no size change. The
   rest state is what shows. */
@media (prefers-reduced-motion: reduce) {
  /* The ink switch is not motion — it is what keeps the mark visible — so it
     survives here; only the uncoil and the fades are dropped. */
  .cursor { transition: none; }
  .cursor__path { transition: none; }
  .cursor.is-over .cursor__path,
  .pj-cursor .cursor.is-over .cursor__path {
    stroke-dasharray: 550 1000;
    stroke-dashoffset: -450;
  }
}
