/* ── Mote v2 locomotion: ROLL / HOP / JELLY LANDING / HATCH ──────────
 * REFERENCE
 * - ui/overlay/mote-avatar.js (emits .mote-spin / .mote-body-anim /
 *   .mote-shadow / .mote-eye groups with inline transform-origins)
 * - ui/companion/mote-box.js (toggles .pg-mote--rolling/--hop/--landing/
 *   --hatch + sets --roll-turns/--roll-dir/--roll-dur)
 * - ui/mote-animation/mote-anim-vars.css (per-palette personality vars)
 * - docs/MOTE-DESIGN-2026-07.md (JUSSI motion spec + jelly emphasis)
 *
 * Rules here operate on SVG groups from the persistent .pg-mote container
 * so the SVG can be hot-swapped mid-animation. Rotation easing MUST match
 * the container's left/top transition easing or the ball skids.
 */

/* Neutralize the v1 whole-svg breathe (ambient life now lives inside the
   SVG via mote-anim-idle.css — the old rule would make the shadow breathe). */
.pg-mote--idle .pg-mote__avatar svg,
.pg-mote--gather .pg-mote__avatar svg { animation: none; }
/* v1 landing squash on the avatar div is replaced by the jelly landing. */
.pg-mote--landing .pg-mote__avatar { animation: none; }

/* ── Roll: real rotation coupled to travel ─────────────────────────── */
/* JS computes the final angle (whole turns × direction × 360°) into ONE
   typed var — calc(number×number×angle) inside keyframes fails to
   interpolate on unregistered custom props, so the angle is registered
   with @property and pre-multiplied in mote-box.js. */
@property --roll-angle { syntax: '<angle>'; inherits: true; initial-value: 360deg; }
.pg-mote--rolling .mote-spin {
  animation: mh-roll var(--roll-dur, 900ms) cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes mh-roll {
  from { transform: rotate(0deg); }
  to   { transform: rotate(var(--roll-angle, 360deg)); }
}

/* Anticipation crouch just before the travel starts. */
.pg-mote--rolling { transition-delay: 90ms; }
.pg-mote--rolling .mote-body-anim { animation: mh-roll-windup 240ms ease-out; }
@keyframes mh-roll-windup {
  0%   { transform: scaleY(1) scaleX(1); }
  35%  { transform: scaleY(0.88) scaleX(1.10); }
  100% { transform: scaleY(1) scaleX(1); }
}

/* Eyes squeeze shut while rolling — shut eyes sell speed. */
.pg-mote--rolling .mote-eye { animation: none; transform: scaleY(0.15); }

/* Contact patch narrows under a rolling ball. */
.mote-shadow ellipse { transition: transform 150ms ease, opacity 150ms ease; }
.pg-mote--rolling .mote-shadow ellipse { transform: scaleX(0.92); opacity: 0.75; }

/* ── Bounce: playful loop + single hop ─────────────────────────────── */
.pg-mote--play .mote-body-anim { animation: mh-play-bounce 620ms infinite; }
.pg-mote--hop  .mote-body-anim { animation: mh-play-bounce 620ms 1; }
@keyframes mh-play-bounce {
  0%   { transform: translateY(0) scaleY(1) scaleX(1);          animation-timing-function: ease-in; }
  12%  { transform: translateY(0) scaleY(0.82) scaleX(1.14);    animation-timing-function: ease-out; }
  38%  { transform: translateY(calc(var(--bounce-height, 8px) * -2.2)) scaleY(1.12) scaleX(0.90); animation-timing-function: ease-in-out; }
  55%  { transform: translateY(calc(var(--bounce-height, 8px) * -2.35)) scaleY(1.01) scaleX(0.99); animation-timing-function: ease-in; }
  74%  { transform: translateY(0) scaleY(0.80) scaleX(1.16);    animation-timing-function: ease-out; }
  88%  { transform: translateY(-3px) scaleY(1.04) scaleX(0.97); animation-timing-function: ease-in-out; }
  100% { transform: translateY(0) scaleY(1) scaleX(1); }
}
.pg-mote--play .mote-shadow ellipse,
.pg-mote--hop  .mote-shadow ellipse { animation: mh-bounce-shadow 620ms infinite; }
.pg-mote--hop  .mote-shadow ellipse { animation-iteration-count: 1; }
@keyframes mh-bounce-shadow {
  0%, 12%, 74%, 100% { transform: scaleX(1); opacity: 1; }
  38%, 55%           { transform: scaleX(0.6); opacity: 0.45; }
}

/* ── JELLY LANDING — the ball splats wide while squeezing flat, then
      wobbles back through damped cycles like living gel (Ville 2026-07-09:
      "kinda like jelly so ball expands to sides while squeezing"). Every
      scaleY is volume-paired with a compensating scaleX, anchored at the
      ground contact. Per-palette depth via --squash-depth/--stretch-peak. */
.pg-mote--landing .mote-body-anim {
  animation: mh-land 560ms cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes mh-land {
  0%   { transform: scaleY(var(--squash-depth, 0.72)) scaleX(calc(2 - var(--squash-depth, 0.72))); }
  30%  { transform: scaleY(var(--stretch-peak, 1.12)) scaleX(calc(2 - var(--stretch-peak, 1.12))); }
  55%  { transform: scaleY(0.94) scaleX(1.06); }
  78%  { transform: scaleY(1.025) scaleX(0.985); }
  100% { transform: scaleY(1) scaleX(1); }
}
/* Shadow spreads under the splat, then settles. */
.pg-mote--landing .mote-shadow ellipse { animation: mh-shadow-land 560ms ease-out; }
@keyframes mh-shadow-land {
  0%   { transform: scaleX(1.25); opacity: 1; }
  30%  { transform: scaleX(0.9); opacity: 0.7; }
  55%  { transform: scaleX(1.08); }
  100% { transform: scaleX(1); opacity: 1; }
}
/* Follow-through: the hat keeps falling for a beat, then settles. */
.pg-mote--landing .mote-hat {
  animation: mh-hat-settle 450ms cubic-bezier(0.34, 1.56, 0.64, 1);
  transform-box: fill-box; transform-origin: 50% 100%;
}
@keyframes mh-hat-settle {
  0%   { transform: translateY(-3.5px) rotate(2deg); }
  55%  { transform: translateY(1px) rotate(-1deg); }
  100% { transform: translateY(0) rotate(0deg); }
}

/* ── Hands tuck in to roll: floating hands never spin with the ball. ── */
.mote-hands { transition: opacity 150ms ease; }
.pg-mote--rolling .mote-hands { opacity: 0; }

/* ── Hatch crack: the egg rocks with growing urgency before it breaks.
   Pivots at the shell base so it rocks like an egg on grass, not a coin. */
.pg-mote--cracking .pg-mote__avatar {
  animation: mh-egg-crack 900ms ease-in-out both;
  transform-origin: 50% 88%;
}
@keyframes mh-egg-crack {
  0%   { transform: rotate(0deg); }
  12%  { transform: rotate(-4deg); }
  24%  { transform: rotate(3.5deg); }
  36%  { transform: rotate(-6deg); }
  48%  { transform: rotate(5.5deg); }
  60%  { transform: rotate(-9deg) translateY(-1px); }
  72%  { transform: rotate(8deg) translateY(-2px); }
  84%  { transform: rotate(-5deg) scale(1.04, 0.96); }
  100% { transform: rotate(0deg) scale(1.07, 0.93); }
}

/* ── Hatch celebration pop ─────────────────────────────────────────── */
.pg-mote--hatch .mote-body-anim {
  animation: mh-hatch-pop 700ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes mh-hatch-pop {
  0%   { transform: scale(0.2) rotate(-8deg); opacity: 0; }
  45%  { transform: scale(1.22) rotate(4deg); opacity: 1; }
  62%  { transform: scaleX(1.12) scaleY(0.88) rotate(-2deg); }
  78%  { transform: scaleX(0.95) scaleY(1.07) rotate(1deg); }
  100% { transform: scale(1) rotate(0deg); }
}
.pg-mote--hatch .mote-eye { animation: none; transform: scale(1.18); } /* wide-eyed newborn */

/* ── Reduced motion ────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .pg-mote--rolling .mote-spin,
  .pg-mote--rolling .mote-body-anim,
  .pg-mote--play .mote-body-anim,
  .pg-mote--hop .mote-body-anim,
  .pg-mote--landing .mote-body-anim,
  .pg-mote--landing .mote-hat,
  .pg-mote--hatch .mote-body-anim,
  .pg-mote--cracking .pg-mote__avatar,
  .mote-shadow ellipse { animation: none !important; transition: none !important; }
  .pg-mote--rolling { transition-delay: 0ms; }
  .pg-mote--rolling .mote-eye { transform: none; }
}
