/* ══════════════════════════════════════════════════════════════════════════
   THE HEALA PET — palette and ten states
   ──────────────────────────────────────────────────────────────────────────
   Every colour is a custom property on `.hp`, so a pet can be recoloured per
   surface without touching the drawing:

     .pet-on-accent { --hp-1: #fff; --hp-2: #E9E4FF; … }

   And every state is a class. The geometry is identical in all ten — the
   moment a state needs its own shapes the character has started to drift.
   ══════════════════════════════════════════════════════════════════════════ */
.hp {
  /* Indigo. Four body stops, light to deep. */
  --hp-1: #C3CCFF;
  --hp-2: #818CF8;
  --hp-3: #4F46E5;
  --hp-4: #312E81;
  --hp-face:   #FBFCFF;
  --hp-face-2: #DCE2FA;
  --hp-ink:    #161235;
  --hp-blush:  #FF9BB4;
  --hp-tongue: #FF8FA8;

  display: inline-block; line-height: 0;
  /* ⚠️ THROUGH A CUSTOM PROPERTY, NOT A PLAIN VALUE. `.hp` and a host's own
     `.some-slot` are both one class, so at equal specificity the later
     stylesheet wins — and this file loads last. A host that set a width got
     96px anyway and had to escalate its selector to fight a default. Setting
     --hp-size wins from anywhere, at any specificity, in any order. */
  width: var(--hp-size, 96px); height: var(--hp-size, 96px);
}
.hp svg { width: 100%; height: 100%; overflow: visible; display: block }

.hp .hp-s0 { stop-color: var(--hp-1) }
.hp .hp-s1 { stop-color: var(--hp-2) }
.hp .hp-s2 { stop-color: var(--hp-3) }
.hp .hp-s3 { stop-color: var(--hp-4) }
.hp .hp-f0 { stop-color: var(--hp-face) }
.hp .hp-f1 { stop-color: var(--hp-face-2) }
.hp .hp-under  { fill: var(--hp-4) }
.hp .hp-foot   { fill: var(--hp-3) }
.hp .hp-arm ellipse { fill: var(--hp-3) }
/* The carry arms are a STROKE, not a filled shape: one path per limb with a
   round cap gives a tapering-free arm that stays the same weight however it
   curves, and the cap IS the wrist. */
.hp .hp-limbs path { fill: none; stroke: var(--hp-3); stroke-width: 16.5; stroke-linecap: round }
.hp .hp-limbs ellipse { fill: var(--hp-3) }
.hp .hp-rim    { fill: var(--hp-1); opacity: .38 }
.hp .hp-floor  { fill: var(--hp-4); opacity: .34 }
.hp .hp-eye    { fill: var(--hp-ink) }
.hp .hp-tongue { fill: var(--hp-tongue) }
.hp .hp-blush  { fill: var(--hp-blush); opacity: .6 }
.hp .hp-shadow { fill: var(--hp-4); opacity: .3 }
.hp .hp-tdot   { fill: var(--hp-2) }
.hp .hp-z      { fill: var(--hp-2); font-family: system-ui, sans-serif }
.hp .hp-ring   { fill: none; stroke: var(--hp-2); stroke-width: 2.4 }

/* ⚠️ fill-box RE-DEFINES WHAT transform-origin COORDINATES MEAN. Under it,
   `60px 136px` is measured from that ONE element's bounding box, not from the
   200x200 drawing — so the arm's shoulder resolved to (89, 238), a pivot
   125px away, and a 24deg wave threw the paw right off the body. Anything
   here may only use keywords. A part that needs a real coordinate must say
   view-box first, as the arm does below. */
.hp .hp-whole, .hp .hp-body, .hp .hp-eyes, .hp .hp-pupils,
.hp .hp-tufts, .hp .hp-shadow, .hp .hp-conf,
.hp .hp-z, .hp .hp-ring, .hp .hp-tdot, .hp .hp-blush {
  transform-box: fill-box; transform-origin: center;
}
/* Horns hinge at their base, not their middle — a horn rotating about its
   own centre swings its root out of the head. */
.hp .hp-horns { transform-box: fill-box; transform-origin: bottom center }
/* Shoulder, in the drawing's own coordinates. */
.hp .hp-arm   { transform-box: view-box; transform-origin: 64px 134px }

/* Decoration is off unless a state asks for it. */
.hp .hp-conf, .hp .hp-z, .hp .hp-tdot, .hp .hp-ring { opacity: 0 }

/* ── The vocabulary ─────────────────────────────────────────────────────── */
@keyframes hp-breathe { 0%,100%{transform:translateY(0) scale(1,1)} 50%{transform:translateY(-7px) scale(1.02,.985)} }
@keyframes hp-slow    { 0%,100%{transform:translateY(0) scale(1,1)} 50%{transform:translateY(-4px) scale(1.035,.965)} }
@keyframes hp-blink   { 0%,92%,100%{transform:scaleY(1)} 95.5%{transform:scaleY(.08)} }
@keyframes hp-fast    { 0%,74%,100%{transform:scaleY(1)} 82%{transform:scaleY(.1)} 90%{transform:scaleY(1)} }
@keyframes hp-shut    { 0%,100%{transform:scaleY(.06)} }
@keyframes hp-sway    { 0%,100%{transform:rotate(-7deg)} 50%{transform:rotate(7deg)} }
@keyframes hp-jiggle  { 0%,100%{transform:rotate(0)} 30%{transform:rotate(2.4deg)} 65%{transform:rotate(-1.8deg)} }
@keyframes hp-look    { 0%,40%{transform:translate(0,0)} 52%,72%{transform:translate(3.2px,-1px)} 84%,100%{transform:translate(-2.4px,.6px)} }
@keyframes hp-ground  { 0%,100%{transform:scaleX(1);opacity:.3} 50%{transform:scaleX(.88);opacity:.2} }

/* Anticipation is the whole difference between a thing that decides to jump
   and a thing that is moved: it dips BEFORE it goes, and squashes on landing. */
@keyframes hp-hop { 0%,52%{transform:translateY(0) scale(1,1)}
                    60%{transform:translateY(5px) scale(1.1,.9)}
                    72%{transform:translateY(-30px) scale(.93,1.1)}
                    84%{transform:translateY(0) scale(1.07,.94)}
                    92%,100%{transform:translateY(0) scale(1,1)} }
@keyframes hp-cheer { 0%,40%{transform:translateY(0) scale(1,1)}
                      50%{transform:translateY(6px) scale(1.12,.88)}
                      64%{transform:translateY(-40px) scale(.9,1.13)}
                      78%{transform:translateY(0) scale(1.09,.92)}
                      88%,100%{transform:translateY(0) scale(1,1)} }
@keyframes hp-shade { 0%,52%{transform:scaleX(1);opacity:.3}
                      72%{transform:scaleX(.62);opacity:.12}
                      84%,100%{transform:scaleX(1.06);opacity:.32} }
@keyframes hp-flap { 0%,50%{transform:rotate(0)} 62%{transform:rotate(-16deg)} 78%{transform:rotate(11deg)} 90%,100%{transform:rotate(0)} }
@keyframes hp-conf { 0%,46%{opacity:0; transform:translate(0,14px) scale(.4) rotate(0)}
                     62%{opacity:1; transform:translate(0,-6px) scale(1.1) rotate(60deg)}
                     100%{opacity:0; transform:translate(0,-24px) scale(.7) rotate(140deg)} }
/* Raise, then rock twice, then drop. Positive is up: the shoulder sits above
   and inboard of the paw, so a negative angle drives the paw down and away
   from the body instead of waving with it. */
@keyframes hp-waveArm  { 0%,12%   { transform: rotate(3deg) }
                         28%      { transform: rotate(26deg) }
                         42%      { transform: rotate(14deg) }
                         56%      { transform: rotate(26deg) }
                         70%      { transform: rotate(14deg) }
                         86%,100% { transform: rotate(3deg) } }
@keyframes hp-waveBody { 0%,22%{transform:rotate(0)} 40%{transform:rotate(-4deg)} 66%{transform:rotate(2deg)} 84%,100%{transform:rotate(0)} }
@keyframes hp-zz    { 0%{opacity:0; transform:translate(0,6px) scale(.7)} 30%{opacity:.85}
                      100%{opacity:0; transform:translate(9px,-22px) scale(1.1)} }
@keyframes hp-tilt  { 0%,100%{transform:rotate(-6deg)} 50%{transform:rotate(-2deg)} }
@keyframes hp-up    { 0%,100%{transform:translate(2px,-3.4px)} 50%{transform:translate(-2px,-3.4px)} }
/* Rise, hold, fade — a thought leaving the head. Each dot runs the same
   timeline on a delay, so the sequence reads even with one dot off-screen. */
@keyframes hp-tdot { 0%       { opacity:0; transform:translateY(5px) scale(.4) }
                     16%      { opacity:.95; transform:translateY(0) scale(1) }
                     52%      { opacity:.95; transform:translateY(0) scale(1) }
                     74%,100% { opacity:0; transform:translateY(-4px) scale(.65) } }
/* Amplitude, not speed, is what separates "excited" from "broken". */
@keyframes hp-buzz  { 0%,100%{transform:translate(0,0) rotate(0)}
                      20%{transform:translate(-1.6px,-1px) rotate(-1.2deg)}
                      45%{transform:translate(1.8px,1px) rotate(1.4deg)}
                      70%{transform:translate(-1.2px,1.4px) rotate(-.8deg)} }
@keyframes hp-drift { 0%,100%{transform:translate(0,0) rotate(-3deg)} 50%{transform:translate(6px,-14px) rotate(3deg)} }
@keyframes hp-ring  { 0%{transform:scale(.82);opacity:.6} 70%,100%{transform:scale(1.35);opacity:0} }
@keyframes hp-thump { 0%,100%{transform:scale(1)} 12%{transform:scale(1.045)} 24%{transform:scale(1)}
                      36%{transform:scale(1.03)} 48%{transform:scale(1)} }
@keyframes hp-shrink{ 0%,100%{transform:translateY(0) scale(1)} 50%{transform:translateY(4px) scale(.94)} }
@keyframes hp-away  { 0%,100%{transform:translate(-4px,1.5px)} 50%{transform:translate(-5.5px,2px)} }
@keyframes hp-hot   { 0%,100%{opacity:.6} 50%{opacity:1} }
/* A squash, not a lift — the weight is above it. */
@keyframes hp-settle{ 0%,100%{transform:translateY(0) scale(1,1)} 50%{transform:translateY(2px) scale(1.018,.985)} }

/* ── The ten ───────────────────────────────────────────────────────────────
   ⚠️ NO TWO PARTS ON THE SAME PERIOD. A body, a blink and a sway sharing a
   clock read as one machine moving; the same three on 4.2s, 6.4s and 5.1s
   read as a creature. Where a state genuinely needs parts in step — hop,
   cheer — they are offset within ONE timeline instead of given three. */
.hp-idle .hp-body{animation:hp-breathe 4.2s ease-in-out infinite}
.hp-idle .hp-eyes{animation:hp-blink 6.4s infinite}
.hp-idle .hp-horns{animation:hp-sway 5.1s ease-in-out infinite}
.hp-idle .hp-tufts{animation:hp-jiggle 4.2s ease-in-out infinite}
.hp-idle .hp-pupils{animation:hp-look 9s ease-in-out infinite}
.hp-idle .hp-shadow{animation:hp-ground 4.2s ease-in-out infinite}

.hp-wave .hp-whole{animation:hp-waveBody 2.6s ease-in-out infinite}
.hp-wave .hp-arm{animation:hp-waveArm 2.6s ease-in-out infinite}
.hp-wave .hp-eyes{animation:hp-blink 5.2s infinite}
.hp-wave .hp-body{animation:hp-breathe 4.4s ease-in-out infinite}
.hp-wave .hp-shadow{animation:hp-ground 4.4s ease-in-out infinite}

.hp-hop .hp-body{animation:hp-hop 2.4s cubic-bezier(.34,1.4,.5,1) infinite}
.hp-hop .hp-horns{animation:hp-flap 2.4s ease-in-out infinite}
.hp-hop .hp-eyes{animation:hp-blink 5.6s infinite}
.hp-hop .hp-shadow{animation:hp-shade 2.4s cubic-bezier(.34,1.4,.5,1) infinite}

.hp-cheer .hp-body{animation:hp-cheer 2.8s cubic-bezier(.34,1.45,.5,1) infinite}
.hp-cheer .hp-horns{animation:hp-flap 2.8s ease-in-out infinite}
.hp-cheer .hp-shadow{animation:hp-shade 2.8s cubic-bezier(.34,1.45,.5,1) infinite}
.hp-cheer .hp-conf{opacity:1; animation:hp-conf 2.8s ease-out infinite}
.hp-cheer .hp-c1{animation-delay:.08s} .hp-cheer .hp-c2{animation-delay:.16s}
.hp-cheer .hp-c3{animation-delay:.05s} .hp-cheer .hp-c4{animation-delay:.2s}

.hp-heartbeat .hp-body{animation:hp-thump 1.7s ease-in-out infinite}
.hp-heartbeat .hp-eyes{animation:hp-blink 6.4s infinite}
.hp-heartbeat .hp-ring{opacity:1; animation:hp-ring 1.7s ease-out infinite}
.hp-heartbeat .hp-r1{animation-delay:.28s} .hp-heartbeat .hp-r2{animation-delay:.56s}
.hp-heartbeat .hp-shadow{animation:hp-ground 4.2s ease-in-out infinite}

.hp-think .hp-whole{animation:hp-tilt 5s ease-in-out infinite}
.hp-think .hp-body{animation:hp-breathe 5.2s ease-in-out infinite}
.hp-think .hp-pupils{animation:hp-up 5s ease-in-out infinite}
.hp-think .hp-eyes{animation:hp-blink 7.2s infinite}
.hp-think .hp-tdot{opacity:1; animation:hp-tdot 2.7s ease-in-out infinite}
.hp-think .hp-t1{animation-delay:.24s} .hp-think .hp-t2{animation-delay:.48s}

.hp-excited .hp-whole{animation:hp-buzz .38s linear infinite}
.hp-excited .hp-body{animation:hp-breathe 1.6s ease-in-out infinite}
.hp-excited .hp-eyes{animation:hp-fast 2.4s infinite}
.hp-excited .hp-horns{animation:hp-sway 1.1s ease-in-out infinite}

.hp-sleep .hp-body{animation:hp-slow 6.4s ease-in-out infinite}
.hp-sleep .hp-eyes{animation:hp-shut 1s infinite}
.hp-sleep .hp-z{opacity:1; animation:hp-zz 3.4s ease-out infinite}
.hp-sleep .hp-z2{animation-delay:1.1s}
.hp-sleep .hp-shadow{opacity:.24}

/* A shadow under something that is not standing on anything is a mistake,
   so float removes it rather than fading it. */
.hp-float .hp-whole{animation:hp-drift 5.6s ease-in-out infinite}
.hp-float .hp-body{animation:hp-breathe 4.8s ease-in-out infinite}
.hp-float .hp-eyes{animation:hp-blink 6.8s infinite}
.hp-float .hp-horns{animation:hp-sway 6.2s ease-in-out infinite}
.hp-float .hp-shadow{opacity:0}

.hp-shy .hp-body{animation:hp-shrink 3.6s ease-in-out infinite}
.hp-shy .hp-pupils{animation:hp-away 3.6s ease-in-out infinite}
.hp-shy .hp-eyes{animation:hp-blink 4.4s infinite}
.hp-shy .hp-blush{animation:hp-hot 3.6s ease-in-out infinite}
.hp-shy .hp-shadow{animation:hp-ground 3.6s ease-in-out infinite}

/* ⚠️ NOTHING VERTICAL, AND NOTHING ON .hp-limbs. It is holding something that
   does not move, so the moment the grip drifts the illusion is gone. The
   body settles and breathes UNDER a fixed grip — which is what carrying
   something actually looks like. */
.hp-carry .hp-body{animation:hp-settle 5.2s ease-in-out infinite}
.hp-carry .hp-eyes{animation:hp-blink 5.8s infinite}
.hp-carry .hp-horns{animation:hp-sway 6.6s ease-in-out infinite}
.hp-carry .hp-shadow{animation:hp-ground 5.2s ease-in-out infinite}

@media (prefers-reduced-motion: reduce) {
  /* ⚠️ THE DECORATION STAYS VISIBLE. Stopping the motion must not delete the
     state: without this, cheer becomes idle, sleep becomes idle and think
     becomes idle for anyone who asked for less movement — three different
     things collapsing into one. */
  .hp * { animation: none !important }
  .hp-cheer .hp-conf, .hp-sleep .hp-z, .hp-think .hp-tdot, .hp-heartbeat .hp-ring { opacity: 1 }
  .hp-sleep .hp-eyes { transform: scaleY(.06); transform-origin: center }
}
