/* ═══════════════════════════════════════════════════════════════════════════
   fx-hero — the drawing is alive.

   The hero is no longer one image. It's the master drawing cut into
   registered layers (see docs/fx-contract.md and README "Art pipeline"):

     base   the body with NO brain and NO drool (nano-banana-2 edit of the master)
     brain  brain + stalk + thread, cut from the master using the diff mask
     drool  the drawn drool, cut from the master the same way
     eyes   per eye: a paper-coloured cover that hides the base's pupil, the
            pupil itself as its own image (so it can move), and a closed-lid
            overlay for blinking

   Every offset below is a percentage of the base image box, computed from
   the 4K master coordinates, so the layers reassemble pixel-for-pixel at any
   size. Don't nudge them by eye — regenerate from tools/ if the art changes.
   ═══════════════════════════════════════════════════════════════════════════ */

.hero__stack {
  position: relative;
  width: 100%;
  /* the layers are sized off this box; lock the ratio so nothing reflows
     while the base is still loading */
  aspect-ratio: 1400 / 1491;
}
.hero__stack > * { position: absolute; display: block; }
.hero__base {
  position: relative !important;
  inset: auto;
  width: 100%; height: auto;
  filter: drop-shadow(10px 12px 0 rgb(20 16 16 / .1));
}

/* ── brain ────────────────────────────────────────────────────────────────── */
.hero__brain {
  left: 25.716%; top: 9.302%; width: 39.379%;
  /* the stalk grows out of the cavity wall at the patch's left end — that's
     the hinge. Anything more than a degree swings the far thread visibly. */
  transform-origin: 8% 55%;
}
@media (prefers-reduced-motion: no-preference) {
  html.fx-hero .hero__brain { animation: brain-quiver 5.4s ease-in-out infinite alternate; }
}
@keyframes brain-quiver {
  0%   { transform: translateY(0)      rotate(0deg); }
  38%  { transform: translateY(-1.6%)  rotate(-.55deg); }
  62%  { transform: translateY(-1.2%)  rotate(-.7deg); }
  100% { transform: translateY(.5%)    rotate(.35deg); }
}

/* ── drool ────────────────────────────────────────────────────────────────── */
.hero__drool { left: 39.439%; top: 68.423%; width: 18.496%; }

/* The live drip: a teardrop that grows from the tip of the drawn strand,
   detaches, falls, and starts again. It's the only part that isn't the
   original drawing, so it's SVG in the same three colours. */
.hero__drip {
  left: 41.99%; top: 85.86%;
  width: 2.3%;
  aspect-ratio: 1 / 3.2;
  transform-origin: 50% 0;
  overflow: visible;
  transform: scaleY(0);
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  html.fx-hero .hero__drip { animation: drip 8.6s cubic-bezier(.4, 0, .6, 1) infinite; }
}
/* grow slowly (0–58%), hang (58–66%), drop and fade (66–78%), rest (78–100%).
   scaleY handles the growth; the fall is a translate so the origin stays put. */
@keyframes drip {
  0%   { transform: translateY(0) scaleY(0);   opacity: 1; }
  58%  { transform: translateY(0) scaleY(1);   opacity: 1; }
  66%  { transform: translateY(0) scaleY(1.06); opacity: 1; }
  78%  { transform: translateY(260%) scaleY(.9); opacity: 0; }
  78.01%, 100% { transform: translateY(0) scaleY(0); opacity: 0; }
}

/* ── eyes ─────────────────────────────────────────────────────────────────── */
.eye { pointer-events: none; }
.eye--l { left: 9.308%;  top: 25.553%; width: 11.635%; height: 12.048%; }
.eye--r { left: 60.322%; top: 28.215%; width: 15.961%; height: 11.908%; }
.eye > * { position: absolute; inset: 0; width: 100%; height: 100%; }

/* hides the pupil that's baked into the base. It's the pupil's own silhouette
   used as a mask on a paper-coloured box, grown a hair so no dark fringe
   survives; the edge lands on bare skin, which is the page colour, so there's
   no seam at any background. */
.eye__cover {
  background: var(--bg);
  -webkit-mask: var(--pupil-mask) center / 100% 100% no-repeat;
  mask: var(--pupil-mask) center / 100% 100% no-repeat;
  transform: scale(1.12);
  transform-origin: var(--pupil-cx) var(--pupil-cy);
}
.eye--l { --pupil-mask: url("../assets/hero/pupilL.png"); --pupil-cx: 46.2%; --pupil-cy: 38.5%; }
.eye--r { --pupil-mask: url("../assets/hero/pupilR.png"); --pupil-cx: 59.7%; --pupil-cy: 29.9%; }

/* the pupil can only travel inside the eye opening; clip the wrapper to it. */
.eye__socket { clip-path: inset(9% 9% 11% 8% round 45%); }
.eye--l .eye__socket { clip-path: inset(9% 12% 11% 8% round 45%); }
.eye__pupil {
  --px: 0; --py: 0;
  /* 5% of the eye box is ~2px on desktop. Past that the left pupil hits the
     socket clip and gets sliced into a half-moon. */
  transform: translate(calc(var(--px) * 5%), calc(var(--py) * 2.5%));
  will-change: transform;
}
html:not(.fx-hero) .eye__pupil { will-change: auto; }
.hero__stack.is-paused .eye__pupil { will-change: auto; }
.hero__stack.is-paused .hero__brain,
.hero__stack.is-paused .hero__drip { animation-play-state: paused; }

/* blink: a paper cover over the whole open eye, with the closed lid drawn
   on top. Off by default; JS flips .is-blink for ~110ms. */
.eye__blink { opacity: 0; }
.eye__blink::before {
  content: ''; position: absolute; inset: 3.5%;
  background: var(--bg); border-radius: 42% / 48%;
}
.eye--l .eye__blink::before { inset: 3.5% 8% 3.5% 3.5%; }
.eye__lid { position: absolute; inset: 0; width: 100%; height: 100%; }
.eye.is-blink .eye__blink { opacity: 1; }

/* ── mobile ───────────────────────────────────────────────────────────────── */
/* On a phone the plate is ~330px wide: the eyes are 38px across and a 2px
   pupil shift is below the noise floor. Keep the blink and the drool
   (both read at any size) and freeze the pupils. */
@media (max-width: 720px) {
  .eye__pupil { transform: none !important; will-change: auto; }
}
