/* Expressions v2 (spec/expressions-v2-plan.md). The art changes only the face; posture lives here, on
   #pl-body, so it moves the whole figure (base + eyelids + swap + pose) together and never the background.
   Every posture change is a transition: a new expression reads as a person shifting, never as a cut.
   portrait-canvas.js mirrors the transform-origin (POSE_ORIGIN_Y) so Marco's smoke stays on the ember. */
.iv-body {
  position: absolute; inset: 0;
  transform-origin: 50% 92%;
  transform: translate(var(--pose-x, 0), var(--pose-y, 0)) rotate(var(--pose-r, 0deg)) scale(var(--pose-s, 1));
  transition: transform var(--pose-ms, 900ms) cubic-bezier(0.3, 0.7, 0.3, 1);
}
/* Momentum faces: small deltas, so adjacent states read apart (posture, not face alone). */
.iv-body[data-pose="Guarded"]   { --pose-y: -0.15%; --pose-s: 1.004; }
.iv-body[data-pose="Pressured"] { --pose-s: 1.008; --pose-ms: 700ms; }
.iv-body[data-pose="Cracking"]  { --pose-y: 0.35%; --pose-ms: 700ms; }
/* Moods: warm lets the shoulders drop; spent slumps, slowly. */
.iv-body[data-pose="Warm"]      { --pose-y: 0.25%; --pose-s: 0.996; --pose-ms: 1200ms; }
.iv-body[data-pose="Spent"]     { --pose-y: 0.8%; --pose-r: 0.35deg; --pose-s: 0.99; --pose-ms: 1500ms; }
/* Reactions: a startle is a fast recoil, anger leans in, scorn tips the head away. */
.iv-body[data-pose="Startled"]  { --pose-y: -0.7%; --pose-s: 0.992; --pose-ms: 160ms; }
.iv-body[data-pose="Indignant"] { --pose-y: -0.25%; --pose-s: 1.014; --pose-ms: 380ms; }
.iv-body[data-pose="Scornful"]  { --pose-x: 0.35%; --pose-r: -0.6deg; --pose-ms: 650ms; }

/* Breathing per expression (the momentum faces' rules live in styles.css next to .iv-figure).
   Same specificity as those, so the .iv-screen.thinking deep breath still wins during the beat. */
.iv-figure[data-state="Warm"]      { animation-duration: 5.4s, 12s; }
.iv-figure[data-state="Spent"]     { animation-name: iv-breathe-sigh, iv-drift; animation-duration: 6.6s, 13s; }
.iv-figure[data-state="Startled"]  { animation-duration: 2.1s, 6s; }
.iv-figure[data-state="Indignant"] {
  animation-name: iv-breathe, iv-shiver; animation-duration: 3s, 0.5s;
  animation-timing-function: ease-in-out, linear;
}
.iv-figure[data-state="Scornful"]  { animation-duration: 5.2s, 11s; }
/* A long slow sigh: in, held, out. */
@keyframes iv-breathe-sigh { 0%, 100% { scale: 1; } 40% { scale: 1.009; } 55% { scale: 1.009; } }
/* Anger held in: half the Cracking tremble, so it reads as tension, not fear. */
@keyframes iv-shiver {
  0%, 100% { translate: 0 0; rotate: 0deg; }
  25% { translate: 0.08% 0.05%; rotate: 0.12deg; }
  50% { translate: -0.07% -0.05%; rotate: -0.1deg; }
  75% { translate: 0.06% 0.07%; rotate: 0.08deg; }
}

/* The overlay a face change hides behind. Its fade length comes from JS through --swap-ms (a 90ms
   closed-eye dissolve, the 240ms fallback, or 0 for an eyelid snap); the transform transition is the
   same as every .iv-figure layer so it tracks the parallax exactly. At rest it is invisible. */
.iv-swap { opacity: 0; transition: opacity var(--swap-ms, 0ms) linear, transform 0.18s ease-out; }

html[data-reduce="1"] .iv-body { transition: none; transform: none; }
