/* ---------- mascots: shared drawing rules ---------- */
:root { --m-line: #1f1a17; --m-accent: var(--accent); }
/* where the theme accent is the outline black (light base, rafael, garra, nação) or a wine that sinks into dark sockets and grounds (Bordô), mascots borrow the theme's other accent so eyes, bolt, bulb and belly still read */
:root:is([data-theme="base"], [data-theme="rafael"], [data-theme="garra"])[data-mode="light"] { --m-accent: #f4f4f5; }
:root[data-theme="nacao"][data-mode="light"] { --m-accent: #fac345; }
:root[data-theme="bordo"] { --m-accent: #d0697b; }
.m-svg { width: 100%; height: 100%; overflow: visible; }
.m-ln { fill: none; stroke: var(--m-line); stroke-linecap: round; stroke-linejoin: round; } /* width comes from the drawing (default 2.6 on .m-body) */
/* optional parts a mascot may tag: .m-head (lags the breath), .m-ear (ear/antenna/crest), .m-brow, .m-mouth (talks), .m-fx (Zz, heart, steam), .m-prop (accessory swing) */
.m-body, .m-arm, .m-eyes, .m-tail, .m-wing, .m-head, .m-ear, .m-brow, .m-mouth, .m-fx, .m-prop { transform-box: fill-box; }
.m-body, .m-head, .m-ear { transform-origin: 50% 100%; }
.m-arm.l { transform-origin: 90% 90%; } .m-arm.r { transform-origin: 10% 90%; --s: -1; }
.m-eyes, .m-brow, .m-fx { transform-origin: 50% 50%; }
.m-mouth, .m-prop { transform-origin: 50% 0%; }
.m-tail { transform-origin: 0% 100%; }
.m-wing.l { transform-origin: 100% 80%; } .m-wing.r { transform-origin: 0% 80%; }
.m-pupil { transform: translate(var(--lx, 0), var(--ly, 0)); transition: transform .15s ease-out, translate .3s ease-out; }
/* every mascot breathes (--br), blinks (--bl) and glances (--sc) on its own clock, so a row of faces never moves in sync */
.m-svg { --br: 3.2s; --bl: 7.3s; --sc: 9.7s; }
[data-m="frango"] { --bl: 6.1s; --sc: 8.9s; } [data-m="frango"] .m-prop { transform-origin: 100% 20%; } [data-m="gato"] { --bl: 8.3s; --sc: 11.3s; }
/* gato: arms and the licking paw turn at the shoulder, the tail tip at its joint (viewBox units) */
[data-m="gato"] :is(.m-arm, .g-tip, .g-lick, .m-ear) { transform-box: view-box; } [data-m="gato"] .m-ear.l { transform-origin: 38px 40px; } [data-m="gato"] .m-ear.r { transform-origin: 82px 40px; }
[data-m="gato"] .m-arm.l { transform-origin: 45px 92px; } [data-m="gato"] .m-arm.r { transform-origin: 75px 92px; } [data-m="gato"] .g-lick { transform-origin: 46px 93px; }
[data-m="gato"] .up .g-tip { transform-origin: 107px 63px; } [data-m="gato"] .low .g-tip { transform-origin: 105px 116px; }
[data-m="gato"] .flat .g-tip { transform-origin: 107px 120px; } [data-m="gato"] .curl .g-tip { transform-origin: 105px 118.5px; }
[data-m="gato"] :is(.g-wh, .g-tongue, .g-yawn) { transform-box: fill-box; } [data-m="gato"] .g-wh.l { transform-origin: 100% 50%; }
[data-m="gato"] .g-wh.r { transform-origin: 0% 50%; --s: -1; } [data-m="gato"] .m-ear.r { --s: -1; }
[data-m="gato"] .g-tongue { transform-origin: 100% 0%; } [data-m="gato"] .g-yawn { transform-origin: 50% 0%; }
[data-m="cachorro"] { --bl: 5.7s; --sc: 7.9s; --wg: 1.2s; } [data-m="robo"] { --bl: 5.3s; --sc: 10.1s; }
/* cachorro: tail wags from its base, ears swing from the root (the right ear is drawn mirrored, so the same angle flops it outward too) */
[data-m="cachorro"] :is(.m-tail, .m-arm, .m-ear) { transform-box: view-box; } [data-m="cachorro"] .m-tail { transform-origin: 80px 108px; }
[data-m="cachorro"] .m-ear { transform-origin: 42px 22px; } [data-m="cachorro"] .m-arm.l { transform-origin: 43px 88px; } [data-m="cachorro"] .m-arm.r { transform-origin: 77px 88px; }
[data-m="cachorro"] :is(.c-foot, .c-tongue, .c-bub, .m-pupil) { transform-box: fill-box; } [data-m="cachorro"] .c-foot { transform-origin: 50% 100%; }
[data-m="cachorro"] .c-tongue { transform-origin: 50% 0%; } [data-m="cachorro"] .c-bub { transform-origin: 15% 70%; } [data-m="cachorro"] .m-pupil { transform-origin: 50% 50%; }
[data-m="cachorro"]:is([data-mood="happy"], [data-mood="proud"], [data-mood="love"]) { --wg: .36s; } [data-m="cachorro"][data-mood="smug"] { --wg: 1.9s; }
/* robo: arms turn at the shoulder, the antenna springs from its socket, the spinner turns round the screen centre */
[data-m="robo"] :is(.m-arm, .m-ear, .r-spin, .r-glow) { transform-box: view-box; } [data-m="robo"] .r-glow { transform-origin: 86.5px 10.5px; } [data-m="robo"] .m-ear { transform-origin: 80px 26px; } [data-m="robo"] .r-spin { transform-origin: 60px 51px; }
[data-m="robo"] .m-arm.l { transform-origin: 36px 88px; } [data-m="robo"] .m-arm.r { transform-origin: 84px 88px; }
[data-m="robo"] :is(.r-heart, .r-spark) { transform-box: fill-box; transform-origin: 50% 50%; }
/* grifo: wings turn at the shoulder (the right one is mirrored, --s), the crest at its root, the lion tail at its base */
[data-m="grifo"] :is(.m-wing, .m-ear, .m-arm, .m-tail) { transform-box: view-box; } [data-m="grifo"] .m-wing.l { transform-origin: 44px 82px; }
[data-m="grifo"] .m-wing.r { transform-origin: 76px 82px; --s: -1; } [data-m="grifo"] .m-ear { transform-origin: 60px 28px; } [data-m="grifo"] .m-tail { transform-origin: 80px 114px; }
[data-m="grifo"] .m-arm.l { transform-origin: 41px 84px; } [data-m="grifo"] .m-arm.r { transform-origin: 79px 84px; }
[data-m="grifo"] :is(.gr-tear, .m-prop) { transform-box: fill-box; transform-origin: 50% 50%; }
[data-m="grifo"] { --bl: 6.7s; --sc: 9.3s; } [data-m="zeus"] { --bl: 7.9s; --sc: 12.7s; }
/* zeus: arms turn at the shoulder, the bolt spins round his grip (z-spin sits at the grip), hair and beard hang from their roots */
[data-m="zeus"] :is(.m-arm, .z-spin) { transform-box: view-box; } [data-m="zeus"] .m-arm.l { transform-origin: 34px 58px; } [data-m="zeus"] .m-arm.r { transform-origin: 86px 58px; }
[data-m="zeus"] .z-spin { transform-origin: 0 0; } [data-m="zeus"] :is(.z-hair, .z-beard, .z-cloud, .z-rain) { transform-box: fill-box; }
[data-m="zeus"] .z-hair { transform-origin: 50% 100%; } [data-m="zeus"] .z-beard { transform-origin: 50% 0%; } [data-m="zeus"] .z-cloud { transform-origin: 50% 50%; }
[data-m="hercules"] { --bl: 8.3s; --sc: 11.3s; } [data-m="hermes"] { --bl: 5.3s; --sc: 4.1s; }
/* hercules: arms turn at the shoulder, the head at the neck, the rock rests on its base */
[data-m="hercules"] :is(.m-arm, .m-head) { transform-box: view-box; } [data-m="hercules"] .m-arm.l { transform-origin: 30px 58px; } [data-m="hercules"] .m-arm.r { transform-origin: 90px 58px; }
[data-m="hercules"] .m-head { transform-origin: 60px 50px; } [data-m="hercules"] .m-x-rock { transform-box: fill-box; transform-origin: 50% 100%; }
/* hermes: arms at the shoulder, head at the neck, wings at their roots, the bag hangs from the strap */
[data-m="hermes"] :is(.m-arm, .m-head, .m-x-footwing, .m-x-helmwing, .m-x-bag) { transform-box: view-box; } [data-m="hermes"] .m-arm.l { transform-origin: 37px 54px; } [data-m="hermes"] .m-arm.r { transform-origin: 84px 58px; }
[data-m="hermes"] .m-head { transform-origin: 60px 46px; } [data-m="hermes"] .m-x-footwing.l { transform-origin: 44px 117px; } [data-m="hermes"] .m-x-footwing.r { transform-origin: 76px 117px; --s: -1; }
[data-m="hermes"] .m-x-helmwing.l { transform-origin: 48px 21px; } [data-m="hermes"] .m-x-helmwing.r { transform-origin: 72px 21px; --s: -1; } [data-m="hermes"] .m-x-bag { transform-origin: 43px 52px; }
[data-m="hermes"] :is(.m-x-letter, .m-x-trail) { transform-box: fill-box; transform-origin: 50% 50%; }
[data-m="poseidon"] { --bl: 9.7s; --sc: 13.9s; } [data-m="ninja"] { --bl: 11.3s; --sc: 6.7s; }
/* poseidon: arms at the shoulder (the trident rides in the right fist), head at the neck, beard hangs from the chin, the splash sits on the floor */
[data-m="poseidon"] :is(.m-arm, .m-head) { transform-box: view-box; } [data-m="poseidon"] .m-arm.l { transform-origin: 33px 57px; } [data-m="poseidon"] .m-arm.r { transform-origin: 85px 56px; }
[data-m="poseidon"] .m-head { transform-origin: 60px 46px; } [data-m="poseidon"] :is(.m-x-beard, .m-x-splash, .m-x-cloud) { transform-box: fill-box; }
[data-m="poseidon"] .m-x-beard { transform-origin: 50% 0%; } [data-m="poseidon"] .m-x-splash { transform-origin: 50% 100%; } [data-m="poseidon"] .m-x-cloud { transform-origin: 50% 50%; }
/* ninja: arms at the shoulder, head at the neck, the sash tails at the knot, the smoke puffs from its middle */
[data-m="ninja"] :is(.m-arm, .m-head, .m-x-sash) { transform-box: view-box; } [data-m="ninja"] .m-arm.l { transform-origin: 36px 55px; } [data-m="ninja"] .m-arm.r { transform-origin: 84px 55px; }
[data-m="ninja"] .m-head { transform-origin: 60px 48px; } [data-m="ninja"] .m-x-sash { transform-origin: 77px 22px; } [data-m="ninja"] .m-x-smoke { transform-box: fill-box; transform-origin: 50% 70%; }
[data-m="alien"] { --bl: 5.9s; --sc: 3.7s; } [data-m="panda"] { --bl: 10.1s; --sc: 15.1s; }
/* alien: stick arms at the shoulder (the tablet rides in the right hand), the big head on the thin neck, antennas at their roots */
[data-m="alien"] :is(.m-arm, .m-head, .m-x-antenna) { transform-box: view-box; } [data-m="alien"] .m-arm.l { transform-origin: 53px 94px; } [data-m="alien"] .m-arm.r { transform-origin: 67px 94px; }
[data-m="alien"] .m-head { transform-origin: 60px 86px; } [data-m="alien"] .m-x-antenna.l { transform-origin: 48px 19px; } [data-m="alien"] .m-x-antenna.r { transform-origin: 72px 19px; --s: -1; }
/* panda: arms at the shoulder, head at the neck, the whole body floats (and rolls) around its middle, the shadow and leaf from their centers */
[data-m="panda"] :is(.m-arm, .m-head, .m-x-float) { transform-box: view-box; } [data-m="panda"] .m-arm.l { transform-origin: 40px 80px; } [data-m="panda"] .m-arm.r { transform-origin: 80px 80px; }
[data-m="panda"] .m-head { transform-origin: 60px 86px; } [data-m="panda"] .m-x-float { transform-origin: 60px 76px; } [data-m="panda"] :is(.m-x-shadow, .m-x-leaf) { transform-box: fill-box; transform-origin: 50% 50%; }
[data-m="unicornio"] { --bl: 4.3s; --sc: 6.7s; } [data-m="fantasma"] { --bl: 6.3s; --sc: 5.3s; }
/* unicornio: arms at the shoulder, the head at the neck, the mane from its root behind the left ear; each sparkle and the horn shine on their own center */
[data-m="unicornio"] :is(.m-arm, .m-head, .m-x-mane) { transform-box: view-box; } [data-m="unicornio"] .m-arm.l { transform-origin: 44px 90px; } [data-m="unicornio"] .m-arm.r { transform-origin: 76px 90px; }
[data-m="unicornio"] .m-head { transform-origin: 60px 82px; } [data-m="unicornio"] .m-x-mane { transform-origin: 38px 30px; } [data-m="unicornio"] :is(.m-x-sparkle path, .m-x-shine) { transform-box: fill-box; transform-origin: 50% 50%; }
/* fantasma: the whole sheet floats (and stretches for the Buuu) from its hem line, arms at the side seams, the hem ripples from its top edge */
[data-m="fantasma"] :is(.m-arm, .m-x-float) { transform-box: view-box; } [data-m="fantasma"] .m-arm.l { transform-origin: 26px 75px; } [data-m="fantasma"] .m-arm.r { transform-origin: 94px 75px; --s: -1; }
[data-m="fantasma"] .m-x-float { transform-origin: 60px 112px; } [data-m="fantasma"] :is(.m-x-hem, .m-x-wisp) { transform-box: fill-box; transform-origin: 50% 0%; }
[data-m="dragao"] { --bl: 7.1s; --sc: 8.3s; } [data-m="monstro"] { --bl: 9.1s; --sc: 10.9s; }
/* dragao: wings and arms turn at the shoulder, the tail at its root, the head at the neck; the idle smoke, cough and smoke rings stay hidden until played */
[data-m="dragao"] :is(.m-wing, .m-arm, .m-tail, .m-head) { transform-box: view-box; } [data-m="dragao"] .m-wing.l { transform-origin: 42px 64px; } [data-m="dragao"] .m-wing.r { transform-origin: 78px 64px; --s: -1; }
[data-m="dragao"] .m-arm.l { transform-origin: 41px 64px; } [data-m="dragao"] .m-arm.r { transform-origin: 79px 64px; } [data-m="dragao"] .m-tail { transform-origin: 70px 108px; } [data-m="dragao"] .m-head { transform-origin: 60px 57px; }
[data-m="dragao"] :is(.d-puff, .d-cough, .d-ring, .d-fire, .d-tear) { transform-box: fill-box; } [data-m="dragao"] .d-puff.l { transform-origin: 100% 100%; --s: -1; } [data-m="dragao"] .d-puff.r { transform-origin: 0% 100%; }
[data-m="dragao"] .d-fire { transform-origin: 50% 100%; } [data-m="dragao"] :is(.d-cough, .d-ring) { transform-origin: 50% 50%; } [data-m="dragao"] :is(.d-puff, .d-cough, .d-ring) { opacity: 0; }
/* monstro: arms turn at the shoulder ball, fingers creep from the palm (0 0 of the hand), ears at their root, the head at the neck; the peeking hands and the third eye stay hidden until played */
[data-m="monstro"] :is(.m-arm, .m-head, .m-ear, .mo-fing, .mo-eye3) { transform-box: view-box; } [data-m="monstro"] .m-arm.l { transform-origin: 39px 51px; } [data-m="monstro"] .m-arm.r { transform-origin: 81px 51px; }
[data-m="monstro"] .m-head { transform-origin: 60px 58px; } [data-m="monstro"] .m-ear.l { transform-origin: 44px 31px; } [data-m="monstro"] .m-ear.r { transform-origin: 76px 31px; --s: -1; }
[data-m="monstro"] .mo-fing { transform-origin: 0 0; } [data-m="monstro"] .mo-eye3 { transform-origin: 60px 20.4px; } [data-m="monstro"] :is(.mo-tear, .mo-glow) { transform-box: fill-box; transform-origin: 50% 50%; }
[data-m="monstro"] :is(.mo-peek, .mo-eye3) { opacity: 0; }
[data-m="monstro"] .mo-peek { display: none; }
/* on dark themes his skin lifts so the silhouette still reads (each theme sets color-scheme; light themes keep the approved charcoal) */
@supports (color: light-dark(#000, #fff)) {
  [data-m="monstro"] { --mo-skin: light-dark(#4d4c54, #7a7983); --mo-knob: light-dark(#5b5a62, #8a8992); --mo-lid: light-dark(#424148, #6b6a72); --mo-rags: light-dark(#1d1b20, #47444f); }
  /* and a thin moonlight rim, because his dark outline is the same dark as the ground (the companion keeps its own shadow); the alien and panda outlines need it too */
  .m-svg:is([data-m="monstro"], [data-m="alien"], [data-m="panda"]) { filter: drop-shadow(0 0 1px light-dark(#0000, #a5a4ad)); }
  .bd-me .m-svg:is([data-m="monstro"], [data-m="alien"], [data-m="panda"]) { filter: drop-shadow(0 0 1px light-dark(#0000, #a5a4ad)) drop-shadow(0 4px 6px rgba(0, 0, 0, .25)); }
  .buddy.drag .bd-me .m-svg:is([data-m="monstro"], [data-m="alien"], [data-m="panda"]) { filter: drop-shadow(0 0 1px light-dark(#0000, #a5a4ad)) drop-shadow(0 12px 14px rgba(0, 0, 0, .3)); }
}
[data-mood="happy"] { --br: 1.8s; } [data-mood="smug"] { --br: 4s; } [data-mood="sad"] { --br: 4.4s; }
[data-mood="sleepy"] { --br: 4.8s; } [data-mood="love"] { --br: 2.4s; }
:is(.rank-list li, .mp-row .mp):nth-child(3n+2) .m-svg, .step.p2 .m-svg { --d: -2.3s; }
:is(.rank-list li, .mp-row .mp):nth-child(3n) .m-svg, .step.p3 .m-svg { --d: -4.1s; }
/* joints (Phase 2 rig, contract in ESTUDO-ANIMACAO.md): a limb is a chain of nested groups, each turning at its own pivot (--px/--py, viewBox units).
   The pose is `rotate` (and `translate`, and `scale` on the torso) from variables set per mood or gesture: it is the drawing, so it also holds under
   reduced motion and in lists, and a change glides (transitions below). Motion is `transform` keyframes on top, in layers (below).
   Angles are offsets from the drawn rest (arms hanging 20-35 deg out, legs straight down, tail in a soft curve) in left-side coordinates: the right
   side is drawn mirrored, so one value poses both. The clamps are the joint limits of a front view: shoulder 75 in .. 150 up (sliding 3 sideways,
   4 up, 1.5 down), elbow 135 and wrist 60 either way, hip 25 in .. 45 out (lifting 6, dropping 2), knee 30 out .. 8 in, ankle 45 heel up .. 25 toe up,
   neck 20, torso 10 (more lifts its edge off the hidden hips) and 3 sideways, 3 up, 4 down, 10 % of squash, each tail joint 25, jaw 30, wing root 60,
   wing fold 0 .. 120, finger rods -10 .. 40, finger joints 20 back .. 70 curled. A mascot whose drawn rest differs moves a limit with --X-min/--X-max
   (--up, --lo, --hd, --th, --sh, --ft, --nk, --sx, --sy, --w1, --fold, --fan; --t-min/--t-max for every tail joint, --f-min/--f-max for fingers).
   A pose outside them is a bug: app/test/rig.test.mjs checks style.css. --on (how much of the idle and mood loops plays), --wa (how much walk),
   --mw (how much of the mood's body motion) and --ta (how big the tail swishes in this mood) are registered numbers set on each element that
   uses them; they do not inherit (a fading variable on a parent restyled every child each frame). --on and --mw fade in 6 steps (a CSS transition
   re-reads the keyframes that use them on every frame it runs); the walk's --wa, its --on and the upper body's --mw come from buddy.js in 3
   steps (--wstep, 0..3, one every 120 ms): 3 style passes instead of a transition that re-read every walk keyframe on every frame (on a 6x slower CPU 3 of 4 frames came
   late in the first 400 ms of a walk; with 6 steps half of them, with 3 a quarter) */
@property --on { syntax: '<number>'; inherits: false; initial-value: 1; }
@property --wa { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --mw { syntax: '<number>'; inherits: false; initial-value: 1; }
@property --ta { syntax: '<number>'; inherits: false; initial-value: 1; }
:is(.j-torso, .j-neck, .j-up, .j-lo, .j-hand, .j-thigh, .j-shin, .j-foot, .j-t1, .j-t2, .j-t3, .j-t4, .j-t5, .j-w1, .j-w2, .j-w3, .j-fan, .j-f1, .j-f2, .j-jaw), :is(.j-neck > .m-head, .j-torso > .m-upper, .j-hand > .m-hand) { transform-box: view-box; transform-origin: var(--px) var(--py); }
.j-torso { rotate: clamp(-10deg, var(--tor, 0deg), 10deg); translate: clamp(-3px, var(--tx, 0px), 3px) clamp(-3px, var(--ty, 0px), 4px); scale: calc(1 + (clamp(.9, var(--tsx, 1), 1.1) - 1) * var(--sq, 1)) calc(1 + (clamp(.9, var(--tsy, 1), 1.1) - 1) * var(--sq, 1)); }
.j-neck { rotate: clamp(var(--nk-min, -20deg), var(--nk, 0deg), var(--nk-max, 20deg)); } .j-jaw { rotate: clamp(-30deg, var(--jw, 0deg), 30deg); }
.j-up { rotate: clamp(var(--up-min, -75deg), var(--up, 0deg), var(--up-max, 150deg)); translate: clamp(var(--sx-min, -3px), var(--sx, 0px), var(--sx-max, 3px)) clamp(var(--sy-min, -4px), var(--sy, 0px), var(--sy-max, 1.5px)); }
.j-lo { rotate: clamp(var(--lo-min, -135deg), var(--lo, 0deg), var(--lo-max, 135deg)); } .j-hand { rotate: clamp(var(--hd-min, -60deg), var(--hd, 0deg), var(--hd-max, 60deg)); }
.j-thigh { rotate: clamp(var(--th-min, -25deg), var(--th, 0deg), var(--th-max, 45deg)); translate: 0 clamp(-6px, var(--hy, 0px), 2px); }
.j-shin { rotate: clamp(var(--sh-min, -30deg), var(--sh, 0deg), var(--sh-max, 8deg)); } .j-foot { rotate: clamp(var(--ft-min, -45deg), var(--ft, 0deg), var(--ft-max, 25deg)); }
.j-t1 { rotate: clamp(var(--t-min, -25deg), var(--t1, 0deg), var(--t-max, 25deg)); } .j-t2 { rotate: clamp(var(--t-min, -25deg), var(--t2, 0deg), var(--t-max, 25deg)); } .j-t3 { rotate: clamp(var(--t-min, -25deg), var(--t3, 0deg), var(--t-max, 25deg)); }
.j-t4 { rotate: clamp(var(--t-min, -25deg), var(--t4, 0deg), var(--t-max, 25deg)); } .j-t5 { rotate: clamp(var(--t-min, -25deg), var(--t5, 0deg), var(--t-max, 25deg)); }
/* a wing folds elbow and wrist together (one --fold, each joint its multiplier --k2/--k3, the wrist the other way: a Z) and a bat wing's finger
   rods fan from one --fan (each rod's --k), so a pose cannot open one bone of a wing without the others */
.j-w1 { rotate: clamp(var(--w1-min, -60deg), var(--w1, 0deg), var(--w1-max, 60deg)); } .m-wing:has(.j-fan) { --fold-min: 0deg; --fold-max: 0deg; } /* a bat wing never folds */
.j-w2 { rotate: calc(clamp(var(--fold-min, 0deg), var(--fold, 0deg), var(--fold-max, 120deg)) * var(--k2, 1)); }
.j-w3 { rotate: calc(clamp(var(--fold-min, 0deg), var(--fold, 0deg), var(--fold-max, 120deg)) * var(--k3, -1)); }
.j-fan { rotate: calc(clamp(var(--fan-min, -10deg), var(--fan, 0deg), var(--fan-max, 40deg)) * var(--k, 1)); }
.j-f1 { rotate: clamp(var(--f-min, -20deg), var(--f1, 0deg), var(--f-max, 70deg)); } .j-f2 { rotate: clamp(var(--f-min, -20deg), var(--f2, 0deg), var(--f-max, 70deg)); }
/* a rigged limb's wrapper never moves (its joints do), so the old whole-arm, tail and wing loops cannot swing it from a wrong pivot; the
   wrapper also carries the class rig, so a browser without :has() (dropped inside the forgiving :is()) still freezes it;
   an opacity swap (a hand that hides, a second arm) goes on a group inside the wrapper, e.g. .m-hand.alt (a fist stacked on an open hand) or
   .m-alt (any other drawing a mood or gesture swaps in: a flexed upper arm, a muscle on the other side) */
:is(.m-arm, .m-tail, .m-wing):is(.rig, :has(.j-up, .j-t1, .j-w1)) { animation: none !important; }
:is(.m-hand.alt, .m-alt) { opacity: 0; }
/* jointed legs stand on the feet line: the whole body only jumps from there; its mood moves the upper body over the legs (.m-upper) and the chest breathes (.j-torso) */
.m-body:has(> .m-leg) { transform-box: view-box; transform-origin: 60px 124px; }
/* one walk per mascot: the cycle, its speed in px/s at 64 px (buddy.js reads it) and the step keys, all made by app/test/walkgen.mjs from the
   mascot's own leg and written in its block: [data-m="x"] { --pace; --wk; --step-th; --step-sh; --step-ft } (the test asks for them). A mood
   changes the upper body of the walk, never its cycle (a new cycle on the global clock would jump). These defaults (the test puppet's)
   weigh nothing, so any mascot block wins */
:where(.m-svg:has(.j-thigh)) { --wk: .56s; --pace: 16.9; }
/* the right limbs are drawn mirrored: --s turns a shared swing (sway, walk, dangle) the same way on screen for both sides */
.m-arm.r, .m-leg.r { --s: -1; }
/* the companion: which way it faces (--fx) and which side the bubble is on (--sd) */
.buddy.left { --fx: -1; } .buddy.say-left { --sd: -1; }

/* ---------- the companion ---------- */
.buddy { position: absolute; left: 0; bottom: 0; z-index: 30; width: 64px; height: 70px; will-change: transform; pointer-events: none; }
.bd-me { position: absolute; inset: 0; padding: 0; border: 0; background: none; pointer-events: auto; touch-action: none; -webkit-tap-highlight-color: transparent; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; cursor: grab; transform-origin: 50% 100%; }
.bd-me .m-svg { display: block; transform-origin: 50% 100%; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .25)); }
.buddy.left .bd-me .m-svg { transform: scaleX(-1); }
.buddy.drag .bd-me { cursor: grabbing; }
.buddy.drag .bd-me .m-svg { transform: scale(1.12) rotate(-6deg); filter: drop-shadow(0 12px 14px rgba(0, 0, 0, .3)); }
.bd-say { position: absolute; bottom: calc(100% + 8px); left: 0; width: max-content; max-width: min(250px, 70vw); padding: 10px 14px; border-radius: 16px 16px 16px 4px; background: var(--ink); color: var(--ground); font-size: 14px; font-weight: 700; line-height: 1.3; opacity: 0; transform: translateY(6px) scale(.9); transform-origin: 0 100%; transition: opacity .2s, transform .25s cubic-bezier(.2, 1.4, .4, 1); pointer-events: none; }
.buddy.say-left .bd-say { left: auto; right: 0; border-radius: 16px 16px 4px 16px; transform-origin: 100% 100%; }
.bd-say.show { opacity: 1; transform: none; }
.buddy.peeking .bd-say { display: none; }
.buddy.big { transition: transform .45s cubic-bezier(.2, 1.3, .4, 1) !important; transform: translate(calc(50vw - 32px), -34vh) !important; z-index: 60; }
.buddy.big .bd-me { transform: scale(2.4); transform-origin: 50% 100%; transition: transform .45s cubic-bezier(.2, 1.3, .4, 1); }
.buddy.big .bd-say, .buddy.big .bd-say.show { left: 50%; right: auto; bottom: calc(100% + 104px); border-radius: 16px; transform: translateX(-50%); transform-origin: 50% 100%; font-size: 16px; }

/* picker: same sideways row as the theme picker */
.mp-row { display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x mandatory; margin: 4px -16px 0; padding: 4px 16px 8px; scrollbar-width: none; }
.mp-row::-webkit-scrollbar { display: none; }
.mp { flex: none; display: grid; justify-items: center; gap: 2px; width: 112px; padding: 12px 8px 12px; border: 2px solid transparent; border-radius: 22px; background: var(--ground-2); color: var(--ink); scroll-snap-align: center; text-align: center; }
.mp .m-svg { width: 76px; height: 82px; }
.mp b { font-size: 15px; font-weight: 800; margin-top: 4px; }
.mp small { color: var(--ink-2); font-size: 11.5px; line-height: 1.25; }
.mp[aria-pressed="true"] { border-color: var(--accent); }
.rest-row { display: flex; justify-content: center; margin-top: 10px; }
.rank-list .rk-m, .step-m { flex: none; display: block; }
.rank-list .rk-m { width: 40px; height: 44px; }
.step-m { width: 56px; height: 62px; }

@media (prefers-reduced-motion: no-preference) {
  /* life everywhere: breath with the head and ears lagging behind (follow-through), blinks, glances */
  :is(.m-body, .m-upper) { animation: m-breathe var(--br) ease-in-out var(--d, 0s) infinite; }
  .m-head { animation: m-head var(--br) ease-in-out var(--d, 0s) infinite; transition: rotate .35s ease-out; }
  .m-ear { animation: m-ear var(--br) ease-in-out var(--d, 0s) infinite, m-flick 6.4s var(--d, 0s) infinite; }
  .m-ear.r { animation-delay: var(--d, 0s), calc(var(--d, 0s) - 3.1s); }
  .m-eyes { animation: m-blink var(--bl) var(--d, 0s) infinite; }
  .m-pupil { animation: m-glance var(--sc) var(--d, 0s) infinite; }
  .m-tail { animation: m-wag 1.4s ease-in-out var(--d, 0s) infinite; }
  .m-wing { animation: m-flap 2.6s ease-in-out var(--d, 0s) infinite; }
  .m-wing.r { animation-delay: calc(var(--d, 0s) + .1s); }
  .m-prop { animation: m-sway 2.8s ease-in-out var(--d, 0s) infinite; }
  .m-fx { animation: m-fx 2.2s ease-in-out infinite; }
  .m-brow { transition: translate .25s ease-out; }
  [data-mood="happy"] .m-tail, [data-mood="love"] .m-tail, [data-mood="proud"] .m-tail { animation-duration: .35s; }
  [data-mood="proud"] .m-arm, [data-mood="happy"] .m-arm { animation: m-flex 1.6s ease-in-out infinite; }
  /* each mood moves the whole body its own way */
  [data-mood="happy"] :is(.m-body, .m-upper) { animation-name: m-bounce; } [data-mood="happy"] .j-torso > .m-upper { animation: j-bounce2 4.7s ease-in-out var(--d, 0s) infinite; }
  [data-mood="proud"] :is(.m-body, .m-upper) { animation-name: m-proud; }
  [data-mood="smug"] :is(.m-body, .m-upper) { animation-name: m-smug; }
  [data-mood="sad"] :is(.m-body, .m-upper) { animation-name: m-droop; }
  [data-mood="sleepy"] :is(.m-body, .m-upper) { animation-name: m-deep; }
  [data-mood="love"] :is(.m-body, .m-upper) { animation-name: m-love; }
  [data-mood="angry"] :is(.m-body, .m-upper) { animation: m-shake 2.4s ease-in-out infinite, m-huff 1.1s ease-in-out infinite; }
  [data-mood="shock"] .m-body { animation: m-jump .5s cubic-bezier(.3, 1.6, .5, 1), m-tremble .1s linear .5s 6; }
  [data-mood="shock"] .m-brow { translate: 0 -2px; }
  .buddy.jump[data-mood="shock"] .m-body { animation: m-tremble .1s linear .6s 6; }
  [data-mood="sleepy"] .m-pupil { animation: none; }
  [data-mood="sleepy"] .m-fx { animation: m-zz 2.6s ease-out infinite; }
  [data-mood="love"] .m-fx { animation: m-pulse 1.2s ease-in-out infinite; }
  [data-mood="angry"] .m-fx { animation: m-puff 1.6s ease-out infinite; }

  /* the companion: crouch before a leap (pre), squash when it lands (land) */
  .bd-me .m-svg { transition: scale .2s cubic-bezier(.3, 1.5, .5, 1); }
  .buddy.swap .bd-me .m-svg { animation: m-swap .24s cubic-bezier(.3, 1.5, .5, 1); }
  .buddy.swap[data-mood="sleepy"] .bd-me .m-svg { animation: m-sink .9s ease-in-out; } /* falling asleep sinks, it does not spring */
  .buddy.pre .bd-me .m-svg { scale: 1.12 .86; transition: scale .14s ease-out; } .buddy.push .bd-me .m-svg { scale: .94 1.08; transition: scale .07s ease-in; }
  .buddy.land .bd-me .m-svg { animation: m-land .42s ease-out; }
  .buddy.walking .bd-me .m-svg { animation: m-step .36s ease-in-out infinite; }
  .buddy.jump .bd-me { animation: m-hop .6s ease-out; }
  .buddy.big.jump .bd-me { animation: none; } /* the hop would replace the big scale(2.4) */
  .buddy.hopping .bd-me { animation: m-leap .52s ease-out; }
  .buddy.hearts::after { content: '❤ ❤'; position: absolute; left: 6px; top: -4px; color: #ff4d6d; font-size: 16px; letter-spacing: 8px; animation: m-hearts 1.1s ease-out forwards; pointer-events: none; }
  /* the picker row scrolls sideways, so it clips anything above its padding: the chosen card gets a short hop from the feet */
  .mp[aria-pressed="true"] .m-svg { transform-origin: 50% 100%; animation: m-pick .6s ease-out; }
  /* a jointed mascot hops like the tap, under the same gravity G: 10 units in .32 s (in .6 s it floated at 0.28 G) */
  .mp[aria-pressed="true"] .m-svg:has(.j-torso) { animation: none; } .mp[aria-pressed="true"] .m-body:has(> .m-leg) { --jh: -10px; animation: j-jump .32s; }
  .mp[aria-pressed="true"] .j-torso { --gl: j-hop-torso .32s both; } .mp[aria-pressed="true"] .m-leg :is(.j-thigh, .j-shin, .j-foot) { --gl: j-hop-leg .32s both; }
  /* talking: looks at its bubble, mouth moves, head leans toward it */
  .buddy.talking .m-pupil { animation: none; translate: calc(var(--sd, 1) * var(--fx, 1) * 2px) -1.4px; }
  .buddy.talking .m-mouth { animation: m-talk .22s ease-in-out 4; }
  .buddy.talking .m-head { rotate: calc(var(--sd, 1) * var(--fx, 1) * 3deg); }
  .buddy.talking .m-brow { translate: 0 -1px; }
  /* idle moments buddy.js picks now and then (data-idle, 2.6 s each); a mascot can restyle any of them */
  .buddy[data-idle="think"] .m-pupil { animation: m-think-eye 2.6s ease-in-out both; }
  .buddy[data-idle="think"] .m-brow { animation: m-think-brow 2.6s ease-in-out both; }
  .buddy[data-idle="think"] .m-head { animation: m-think-head 2.6s ease-in-out both; }
  .buddy[data-idle="think"] .m-arm.r { animation: m-think-arm 2.6s cubic-bezier(.3, 1.3, .5, 1) both; }
  .buddy[data-idle="think"] .bd-me .m-svg { animation: m-think-tilt 2.6s ease-in-out both; }
  .buddy[data-idle="think"]::before, .buddy[data-idle="think"] .bd-me::before, .buddy[data-idle="think"] .bd-me::after { content: ''; position: absolute; border: 2px solid var(--m-line); border-radius: 50%; background: #fff; pointer-events: none; }
  .buddy[data-idle="think"] .bd-me::before { top: 6px; right: 6px; width: 7px; height: 7px; animation: m-dot1 2.6s ease-out both; }
  .buddy[data-idle="think"] .bd-me::after { top: -4px; right: 0; width: 10px; height: 10px; animation: m-dot2 2.6s ease-out both; }
  .buddy[data-idle="think"]::before { top: -19px; right: -6px; width: 15px; height: 15px; animation: m-dot3 2.6s ease-out both; }
  .buddy.left[data-idle="think"] .bd-me::before { right: auto; left: 6px; } .buddy.left[data-idle="think"] .bd-me::after { right: auto; left: 0; } .buddy.left[data-idle="think"]::before { right: auto; left: -6px; }
  .buddy[data-idle="look"] .m-pupil { animation: m-look 2.6s ease-in-out both; }
  .buddy[data-idle="look"] .m-head { animation: m-look-head 2.6s ease-in-out .1s both; }
  .buddy[data-idle="stretch"] .bd-me .m-svg { animation: m-stretch 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] .m-arm { animation: m-stretch-arm 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="frango"] .m-arm { animation: m-stretch-arm 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] :is([data-m="zeus"], [data-m="dragao"], [data-m="monstro"], [data-m="hercules"], [data-m="hermes"], [data-m="poseidon"], [data-m="ninja"]) .m-arm { animation-play-state: paused; }
  .buddy[data-idle="fidget"] .bd-me .m-svg { animation: m-fidget 2.6s ease-in-out both; }

  /* joints: a new pose (mood, gesture, walk pose) glides in with successive breaking, and the thought comes first: the head turns at once, the
     torso .08 s later, the arms and legs .12 s later (the right side .18 s: never twins), the tail .2 s. In each limb the root leads and lands
     soft, the middle joint follows --lag later and overshoots a little, the tip another --lag later and overshoots most. Every delay and curve is
     a variable (--td, --lag, --d1..--d5, --te, --te2, --te3, --tt, --tdt, --tet), so a mascot or a gesture retimes a chain without rewriting a
     transition (rewriting one would also drop the stepped fades of --on and --wa) */
  :is(.j-neck, .j-up, .j-thigh, .j-t1, .j-w1, .j-jaw) { transition: rotate var(--tt, .42s) var(--te, cubic-bezier(.5, -.3, .4, 1.1)) var(--d1, var(--td, 0s)), translate var(--tt, .42s) var(--te, cubic-bezier(.5, -.3, .4, 1.1)) var(--d1, var(--td, 0s)), --on var(--ont, .36s) steps(6), --ta .6s linear; }
  .j-torso { transition: rotate var(--tt, .42s) var(--tet, cubic-bezier(.5, -.3, .4, 1.1)) var(--tdt, .08s), translate var(--tt, .42s) var(--tet, cubic-bezier(.5, -.3, .4, 1.1)) var(--tdt, .08s), scale var(--tt, .42s) cubic-bezier(.3, 1.4, .5, 1) var(--tdt, .08s), --on var(--ont, .36s) steps(6); }
  :is(.j-lo, .j-shin, .j-t2, .j-w2) { transition: rotate var(--tt, .42s) var(--te2, cubic-bezier(.4, 0, .3, 1.3)) var(--d2, calc(var(--td, 0s) + var(--lag, .05s))), --on var(--ont, .36s) steps(6), --ta .6s linear; }
  :is(.j-hand, .j-foot, .j-t3, .j-w3, .j-fan) { transition: rotate var(--tt, .42s) var(--te3, cubic-bezier(.34, 1.56, .64, 1)) var(--d3, calc(var(--td, 0s) + 2 * var(--lag, .05s))), --on var(--ont, .36s) steps(6), --ta .6s linear; }
  :is(.j-t4, .j-f1) { transition: rotate var(--tt, .42s) var(--te3, cubic-bezier(.34, 1.56, .64, 1)) var(--d4, calc(var(--d3, calc(var(--td, 0s) + 2 * var(--lag, .05s))) + var(--lag, .05s))), --on var(--ont, .36s) steps(6), --ta .6s linear; }
  :is(.j-t5, .j-f2) { transition: rotate var(--tt, .42s) var(--te3, cubic-bezier(.34, 1.56, .64, 1)) var(--d5, calc(var(--d3, calc(var(--td, 0s) + 2 * var(--lag, .05s))) + 2 * var(--lag, .05s))), --on var(--ont, .36s) steps(6), --ta .6s linear; }
  .j-torso > .m-upper { transition: --mw var(--ont, .36s) steps(6); }
  :is(.m-arm, .m-leg, .m-wing) { --td: .12s; } :is(.m-arm, .m-leg, .m-wing).r { --td: .18s; } .m-tail { --td: .2s; }
  /* the torso of a lively new mood dips the other way first (anticipation); an arm never does: on a big swing a dip of the same share winds the
     shoulder past its limit and into the head */
  :is([data-mood="happy"], [data-mood="proud"], [data-mood="angry"], [data-mood="shock"]) .j-torso { --tet: cubic-bezier(.6, -.8, .4, 1.1); }
  .buddy:is(.walking, [data-idle]) .j-torso { --tet: cubic-bezier(.5, -.3, .4, 1.1); }
  /* a fright: the knees crouch .13 s while the arms gather in (j-gather); at the crouch bottom the legs push and the arms fling up with the
     push (the elbow opens just before the shoulder, while the arm still hangs: an elbow that flipped with the arm held out made a straight
     stick), up by the top of the jump; they droop a little when the knees take the landing; the right arm .05 s later */
  [data-mood="shock"] .m-arm { --tt: .2s; --d2: .11s; --d1: .13s; --d3: .16s; --te: cubic-bezier(.2, 1.3, .4, 1); --te2: cubic-bezier(.2, 1.3, .4, 1); } [data-mood="shock"] .m-arm:where(.r) { --d2: .16s; --d1: .18s; --d3: .21s; }
  /* a body that crouches, leaps, lands or hangs moves at once: no thinking delay */
  .buddy:is(.pre, .push, .hopping, .land, .drag) :is(.m-arm, .m-leg, .m-tail) { --td: 0s; } .buddy:is(.pre, .push, .hopping, .land, .drag) .j-torso { --tdt: 0s; }
  /* each joint plays three layers that add up; a mood or a gesture sets only its layer's variable, never `animation`, so none cuts another off:
     --ml the idle or mood loop (its swing x --on, which a gesture fades to 0 on the limbs it takes over), --wl the walk (x --wa, which fades in
     and out with .walking), --gl a one-shot gesture. Loops run on the global clock (--d, set by buddy.js), so a redraw does not restart them;
     a mood loop starts after the pose glide (delay >= .5 s) and rests at 0 most of its cycle. What a redraw still cuts (a wave in mid-swing, the
     switch between two moods' body motions) buddy.js carries over: the new drawing starts where the old one was and lets it go in .3 s */
  :where(.j-torso, .j-neck, .j-up, .j-lo, .j-hand, .j-thigh, .j-shin, .j-foot, .j-t1, .j-t2, .j-t3, .j-t4, .j-t5, .j-w1, .j-w2, .j-w3, .j-fan, .j-f1, .j-f2, .j-jaw) { --ml: none; --wl: none; --gl: none; animation: var(--ml), var(--wl), var(--gl); animation-composition: add; }
  /* moving hold: the weight sits over one foot (0-46 % of 11.3 s, drifting a little further), crosses in .9 s and sits over the other; the body leans
     over the support foot and the chest breathes on its own slow clock (never in step with the mood's body motion); the head counters 80 % of the
     lean and the hanging arms counter it a beat later, the right arm later still (delays are negative: a positive one would pop when the loop
     starts). The pelvis is hidden, so this is a lean of the upper body, not a full contrapposto; a mascot with big visible legs may add a free knee */
  .j-torso { --sa: 2.5deg; --sw: 1.4px; --ml: j-sway var(--ws, 11.3s) ease-in-out var(--d, 0s) infinite var(--ps, running), j-breathe var(--brt, 4.3s) ease-in-out calc(var(--d, 0s) - 1.1s) infinite; }
  .j-neck { --sa: -2deg; --sw: 0px; --ml: j-sway var(--ws, 11.3s) ease-in-out calc(var(--d, 0s) - var(--ws, 11.3s) + .15s) infinite var(--ps, running); }
  .m-arm .j-up { --sa: calc(var(--s, 1) * -1.4deg); --sw: 0px; --ml: j-sway var(--ws, 11.3s) ease-in-out calc(var(--d, 0s) - var(--ws, 11.3s) + .25s) infinite var(--ps, running); }
  .m-arm:where(.r) .j-up { --ml: j-sway var(--ws, 11.3s) ease-in-out calc(var(--d, 0s) - var(--ws, 11.3s) + .31s) infinite var(--ps, running); }
  /* a foot seen from the front (7 of the 8) can only roll onto its edge in the picture plane, and its knee bends toward the viewer, which a
     front view cannot show: front legs crouch, tuck and dangle by the hips with a little knee out and the sole flat (--cq .3 / -.6 / .3), never
     a sideways shin or a pointed toe. A foot drawn from the side (class side on .m-leg: the test puppet, Monstro) points and bends the knee out */
  .m-leg .j-thigh { --cq: .3; } .m-leg .j-shin { --cq: -.6; } .m-leg .j-foot { --cq: .3; }
  .m-leg.side .j-thigh { --cq: 1; } .m-leg.side .j-shin { --cq: -2; } .m-leg.side .j-foot { --cq: 1; } .m-leg.side .j-foot { --tp: -16deg; } /* a profile foot points its toes at the top of a jump (pushed off) */
  /* the tail swishes and rests (j-swish; a dog's wag uses j-osc, which never rests), each joint later and wider than the one before; its cycle is
     one per mascot (--tw), a mood changes only its size (--ta, faded on the tail joints themselves) */
  .m-tail .j-t1 { --a: 5deg; --ml: j-swish var(--tw, 3.7s) ease-in-out var(--d, 0s) infinite; }
  .m-tail .j-t2 { --a: 7deg; --ml: j-swish var(--tw, 3.7s) ease-in-out calc(var(--d, 0s) - var(--tw, 3.7s) + .12s) infinite; }
  .m-tail .j-t3 { --a: 10deg; --ml: j-swish var(--tw, 3.7s) ease-in-out calc(var(--d, 0s) - var(--tw, 3.7s) + .24s) infinite; }
  .m-tail .j-t4 { --a: 12deg; --ml: j-swish var(--tw, 3.7s) ease-in-out calc(var(--d, 0s) - var(--tw, 3.7s) + .34s) infinite; }
  .m-tail .j-t5 { --a: 14deg; --ml: j-swish var(--tw, 3.7s) ease-in-out calc(var(--d, 0s) - var(--tw, 3.7s) + .42s) infinite; }
  /* walk: a side-step for a front-facing body on the global clock, faded in and out by --wa in the 3 steps buddy.js sets (--wstep), while it speeds
     the travel up and slows it down in the same steps and swaps .walking for .walk-end when the slow-down starts, so the planted foot stays planted at the start, at the stop and in
     between (standing, the walk loops do not run at all). Cycle --wk: the left foot is planted 0-56 % and slides back under the body exactly as
     fast as the body travels (buddy.js moves --pace px/s), flat on the floor; the right foot half a cycle later (--s flips its sweep); the free
     foot lifts with the knee out, toe down then up, and lands flat. The body leans into the travel (--lean) and over the support foot (--wr, --wx)
     and bobs twice a cycle (--bob); the head counters the lean; the hanging arms swing as pendulums a beat behind the body, the forearm and the
     hand later and wider (--as). Meanwhile the mood's body motion and the idle loops fade out and pause (a paused loop costs nothing per frame:
     on a 6x slower CPU the walk fell from 7-12 % slow frames to under 2 %): every idle or mood loop that --on fades ends its --ml entry with
     var(--ps, running), and walking sets --ps to paused (the breath and the tail, which keep going, leave it out) */
  .buddy:is(.walking, .walk-end) :is(.j-torso, .j-neck, .j-thigh, .j-shin, .j-foot, .m-arm .j-up, .m-arm .j-lo, .m-arm .j-hand) { --wa: calc(var(--wstep, 3) / 3); }
  .buddy.walking .j-torso { --tor: var(--lean, 2deg); }
  .buddy:is(.walking, .walk-end) .j-torso { --wr: -3deg; --wx: -.8px; --wl: j-waddle var(--wk, .56s) var(--d, 0s) infinite, j-bob calc(var(--wk, .56s) / 2) var(--d, 0s) infinite; }
  .buddy:is(.walking, .walk-end) .j-neck { --wr: 1.6deg; --wx: 0px; --wl: j-waddle var(--wk, .56s) calc(var(--d, 0s) - var(--wk, .56s) + .06s) infinite; }
  .buddy:is(.walking, .walk-end) .m-leg .j-thigh { --wl: var(--step-th, j-step-th) var(--wk, .56s) linear var(--d, 0s) infinite; } .buddy:is(.walking, .walk-end) .m-leg.r .j-thigh { --wl: var(--step-th, j-step-th) var(--wk, .56s) linear calc(var(--d, 0s) - var(--wk, .56s) / 2) infinite; }
  .buddy:is(.walking, .walk-end) .m-leg .j-shin { --wl: var(--step-sh, j-step-sh) var(--wk, .56s) linear var(--d, 0s) infinite; } .buddy:is(.walking, .walk-end) .m-leg.r .j-shin { --wl: var(--step-sh, j-step-sh) var(--wk, .56s) linear calc(var(--d, 0s) - var(--wk, .56s) / 2) infinite; }
  .buddy:is(.walking, .walk-end) .m-leg .j-foot { --wl: var(--step-ft, j-step-ft) var(--wk, .56s) linear var(--d, 0s) infinite; } .buddy:is(.walking, .walk-end) .m-leg.r .j-foot { --wl: var(--step-ft, j-step-ft) var(--wk, .56s) linear calc(var(--d, 0s) - var(--wk, .56s) / 2) infinite; }
  .buddy:is(.walking, .walk-end) .m-arm .j-up { --wr: calc(var(--s, 1) * var(--as, 4deg)); --wx: 0px; --wl: j-waddle var(--wk, .56s) calc(var(--d, 0s) - var(--wk, .56s) + .06s) infinite; }
  .buddy:is(.walking, .walk-end) .m-arm .j-lo { --wr: calc(var(--s, 1) * var(--as, 4deg) * .8); --wx: 0px; --wl: j-waddle var(--wk, .56s) calc(var(--d, 0s) - var(--wk, .56s) + .11s) infinite; }
  .buddy:is(.walking, .walk-end) .m-arm .j-hand { --wr: calc(var(--s, 1) * var(--as, 4deg) * 1.2); --wx: 0px; --wl: j-waddle var(--wk, .56s) calc(var(--d, 0s) - var(--wk, .56s) + .17s) infinite; }
  .buddy:is(.walking, .walk-end) :is(.j-torso, .j-neck, .m-arm .j-up, .m-arm .j-lo, .m-arm .j-hand, .m-arm .j-f1, .m-arm .j-f2) { --on: calc(1 - var(--wstep, 3) / 3); } .buddy:is(.walking, .walk-end) { --ont: 0s; }
  .buddy.walking .bd-me .m-svg:has(.j-thigh) { animation: none; }
  .buddy:is(.walking, .walk-end) { --ps: paused; } .buddy:is(.walking, .walk-end) .j-torso > .m-upper { animation-play-state: paused; --mw: calc(1 - var(--wstep, 3) / 3); }
  .buddy:is([data-idle="think"], [data-idle="stretch"]) .j-torso > .m-upper { --mw: 0; }
  /* gestures take over the limbs they use: their loops fade out and come back after (--on) */
  .buddy:is([data-idle="think"], [data-idle="stretch"]) .m-arm :is(.j-up, .j-lo, .j-hand, .j-f1, .j-f2) { --on: 0; }
  /* think (jointed): the eyes dart first and a blink covers the turn, the head follows .12 s later, the body leans .2 s later (the whole-svg tilt
     would lift a planted foot); then the hand goes to the chin: from a hanging arm the elbow leads (the hand rises beside the belly instead of
     sweeping across it), then the shoulder and the wrist, and the knuckles knock under the chin. Each mascot sets its own chin angles, and the
     order for a raised arm (its block). They are poses, not keyframes: a tap in the middle glides it all back */
  .buddy[data-idle="think"] .m-svg:has(.j-neck) .m-pupil { animation: j-think-eye 2.6s ease-out both; }
  .buddy[data-idle="think"] .m-svg:has(.j-neck) .m-eyes { animation: j-think-blink 2.6s linear both; }
  .buddy[data-idle="think"] .j-neck > .m-head { rotate: -5deg; transition: rotate .45s cubic-bezier(.3, 1.3, .5, 1) .12s; animation: m-head var(--br) ease-in-out var(--d, 0s) infinite; }
  .buddy[data-idle="think"] .bd-me .m-svg:has(.j-torso) { animation: none; } .buddy[data-idle="think"] .j-torso { --tor: -3deg; --tdt: .2s; }
  .buddy[data-idle="think"] .m-arm.r { --d2: .2s; --d1: .35s; --d3: .45s; --te2: cubic-bezier(.5, -.3, .4, 1.1); --te: cubic-bezier(.4, 0, .3, 1.3); --tt: .42s; }
  .buddy[data-idle="think"] .m-arm.r .m-hand { animation: j-knock 2.6s ease-in-out both; }
  .m-hand { transition: opacity 0s .4s; } .buddy[data-idle="think"] .m-arm.r .m-hand.alt { opacity: 1; } .buddy[data-idle="think"] .m-arm.r .m-hand:has(~ .alt) { opacity: 0; }
  /* stretch (jointed): the arms reach out and up with the elbows bent and the forearms up, uneven (straight arms passed a T on the way and held
     an airplane; raised higher, a big head would hide the elbows); the elbows open first, while the arms still hang, so no frame is a straight
     stick; the shoulders rise, the body grows tall from the hips and goes up on tiptoe (the heels rise, the hips lift as much), the eyes squeeze
     shut and the mouth yawns, the reach trembles once at its peak, and it all glides back. A mascot moves the reach to clear its ears, horns
     and badge and sets the tiptoe to its feet */
  .buddy[data-idle="stretch"] .bd-me .m-svg:has(.j-torso) { animation: none; }
  .buddy[data-idle="stretch"] .j-torso { --tsx: .97; --tsy: 1.05; --ty: -2px; --tt: .6s; }
  .buddy[data-idle="stretch"] .m-svg .m-arm { --up: 80deg; --lo: 56deg; --hd: -6deg; --sy: -3px; --tt: .55s; --d2: var(--td, 0s); --d1: calc(var(--td, 0s) + .1s); --d3: calc(var(--td, 0s) + .14s); } .buddy[data-idle="stretch"] .m-svg .m-arm.r { --up: 74deg; --lo: 58deg; }
  .buddy[data-idle="stretch"] .m-leg { --tt: .5s; } .buddy[data-idle="stretch"] .m-leg.side { --ft: -12deg; --hy: -2px; }
  .buddy[data-idle="stretch"] .m-arm .j-up { --gl: j-strain 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] .m-svg:has(.j-torso) .m-eyes { animation: j-squeeze 2.6s ease-in-out both; } .buddy[data-idle="stretch"] .m-svg:has(.j-torso) .m-mouth { animation: j-yawn 2.6s ease-in-out both; }
  /* jointed bodies crouch, land and take a fright in the knees and the soft upper body (the whole-svg squash would squash the legs too): crouch
     before a leap with the arms swinging down, leap with the legs tucked (the hips lift) and the arms flung up, dangle the legs when held, land
     into the knees while the head and the arms carry on down a beat later (follow-through); the fright crouches, jumps and lands the same way */
  .buddy:is(.pre, .push) .bd-me .m-svg:has(.j-torso) { scale: 1; }
  /* the push before a leap (.push, 70 ms): the legs straighten fast with the feet still down, the torso rises out of the crouch and stretches,
     a profile foot pushes off its toes, the arms swing into the balance pose (below) and fling */
  .buddy.push :is(.j-torso, .m-leg) { --tt: .07s; } .buddy.push .j-torso { --tsx: .97; --tsy: 1.05; --ty: -1px; } .buddy.push .m-leg { --d2: 0s; --d3: 0s; } .buddy.push .m-leg.side { --ft: -16deg; }
  .buddy.pre :is(.j-torso, .m-leg) { --tt: .14s; } .buddy.pre .j-torso { --ty: 3px; --tsx: 1.05; --tsy: .95; } .buddy.pre .m-leg { --th: 3deg; --sh: -6deg; --ft: 3deg; } .buddy.pre .m-leg.side { --th: 9deg; --sh: -18deg; --ft: 9deg; }
  .buddy.pre .m-arm .j-up { --gl: j-arms-pre .14s ease-out both; }
  .buddy.hopping .bd-me:has(.j-torso) { animation: none; }
  .buddy.hopping .j-torso { --tt: .18s; --tsx: .97; --tsy: 1.04; } .buddy.hopping .m-leg { --tt: .12s; --d2: 0s; --d3: 0s; }
  .buddy.tuck .m-leg { --th: 3deg; --sh: -6deg; --ft: 3deg; --hy: -4px; } .buddy.tuck .m-leg.side { --th: 6deg; --sh: -22deg; --ft: -14deg; }
  /* in the push and the air the arms leave the mood for a balance pose, each with its own job: the left out and low, bent in (the shoulder
     first and the elbow .2 s later, so a raised arm comes down before its bend flips), the right up and out, bent out (its elbow opens right
     after the shoulder, as into any raised pose); the swing into it is the take-off's arm swing (a fling keyframe on top of a raised mood arm
     went into the head) */
  .buddy:is(.push, .hopping) .m-arm { --up: 26deg; --lo: -12deg; --hd: 4deg; --d1: 0s; --d2: .2s; --d3: .26s; } .buddy:is(.push, .hopping) .m-arm.r { --up: 50deg; --lo: 34deg; --hd: -8deg; --d1: .06s; --d2: .1s; --d3: .16s; }
  .buddy:is(.push, .hopping) .m-arm :is(.j-up, .j-lo, .j-hand, .j-f1, .j-f2) { --on: 0; }
  .buddy.drag .m-leg { --sh: -3deg; --tt: .3s; } .buddy.drag .m-leg.side { --sh: -8deg; --ft: -20deg; } .buddy.drag .m-leg.l { --th: 10deg; } .buddy.drag .m-leg.r { --th: -2deg; }
  .buddy.drag .m-leg .j-thigh { --gl: j-dangle 1.6s ease-out; } .buddy.drag .m-leg.side .j-shin { --gl: j-dangle 1.6s ease-out .08s; }
  .buddy.drag .m-leg.r .j-thigh { --gl: j-dangle 1.6s ease-out .06s; } .buddy.drag .m-leg.side.r .j-shin { --gl: j-dangle 1.6s ease-out .14s; }
  /* held up, the arms let go of the mood and hang plumb (the svg leans -6), swinging a beat behind the legs; the tail droops to a small swish */
  .buddy.drag .m-arm { --up: 6deg; --lo: 0deg; --hd: 0deg; --d1: 0s; --d2: .16s; --d3: .22s; } .buddy.drag .m-arm.r { --up: -6deg; --d1: .03s; --d2: .19s; --d3: .25s; } .buddy.drag .m-arm :is(.j-up, .j-lo, .j-hand, .j-f1, .j-f2) { --on: 0; }
  .buddy.drag .m-arm .j-up { --gl: j-dangle 1.6s ease-out .05s; } .buddy.drag .m-arm .j-lo { --gl: j-dangle 1.6s ease-out .1s; }
  .buddy.drag .m-svg .m-tail :is(.j-t1, .j-t2, .j-t3, .j-t4, .j-t5) { --ta: .3; }
  .buddy.land .bd-me .m-svg:has(.j-torso) { animation: none; }
  .buddy.land .j-torso { --gl: j-land-torso .5s ease-out; } .buddy.land .m-leg :is(.j-thigh, .j-shin, .j-foot) { --gl: j-land-leg .5s ease-out; }
  .buddy.land .j-neck { --gl: j-nod .5s ease-out .06s; } .buddy.land .m-arm .j-up { --gl: j-flop .5s ease-out .04s; } .buddy.land .m-arm .j-lo { --gl: j-flop .5s ease-out .09s; }
  .buddy.land .m-wing .j-w1 { --gl: j-flop .5s ease-out .06s; } .buddy.land .m-wing .j-w2 { --gl: j-flop .5s ease-out .1s; } .buddy.land .m-wing .j-w3 { --gl: j-flop .5s ease-out .14s; }
  .buddy.land.swap:not(.jump) .j-torso { --gl: j-land-torso .5s ease-out; } .buddy.land .m-wing:has(.j-fan) :is(.j-w2, .j-w3) { --gl: none; } /* skin cannot stretch: a bat wing droops at the shoulder only */
  /* a new face lands on a quick squash of the upper body (as on every mascot); falling asleep sinks. --sq scales every squash and stretch of
     the torso, its pose scales and the upper body's mood motion (a robot sets 0, a bony mascot about .3) */
  .buddy.swap .bd-me .m-svg:has(.j-torso) { animation: none; }
  .buddy.swap .j-torso { --gl: j-swap .3s ease-in-out; } .buddy.swap[data-mood="sleepy"] .j-torso { --gl: j-sink .9s ease-in-out; }
  /* tap and fright: the button hops (or the body jumps), the knees crouch and land and the head and arms follow through on landing; tied to the
     shock face, which is drawn once, so a redraw back to the mood never replays it */
  .buddy.jump:not(.big) .bd-me:has(.j-torso) { --jh: -20px; animation: j-jump .6s; }
  .m-svg[data-mood="shock"] .j-torso { --gl: j-hop-torso .6s both; } .m-svg[data-mood="shock"] .m-leg :is(.j-thigh, .j-shin, .j-foot) { --gl: j-hop-leg .6s both; }
  .m-svg[data-mood="shock"] .j-neck { --gl: j-nod .5s ease-out .46s both; } .m-svg[data-mood="shock"] .m-arm .j-up { --gl: j-gather .6s both; }
  [data-mood] .m-body:has(> .m-leg) { animation: none; } [data-mood="shock"] .m-body:has(> .m-leg) { --jh: -12px; animation: j-jump .6s; }
  .buddy.jump .m-body:has(> .m-leg) { animation: none; } [data-mood="shock"] .m-upper { animation: m-tremble .1s linear .6s 6; }
  /* fidget (jointed): the default fidget rocks the upper body on the hips (the whole-svg rock would lift a planted foot); each mascot has its own */
  .buddy[data-idle="fidget"] .bd-me .m-svg:has(.j-torso) { animation: none; } .buddy[data-idle="fidget"] .j-torso { --gl: j-fidget 2.6s ease-in-out both; }

  /* Frangão: flaps when happy, pumps both biceps when proud, nods off when sleepy, puffs up in shock */
  [data-m="frango"][data-mood="happy"] .m-arm { animation: f-flap 4.7s ease-in-out infinite; }
  [data-m="frango"][data-mood="proud"] .m-arm { animation: f-pump 1.2s ease-in-out infinite; }
  [data-m="frango"][data-mood="sleepy"] .m-head { animation: f-nod 4.8s ease-in-out infinite; }
  [data-m="frango"][data-mood="shock"] .m-arm { animation: f-flare .6s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="frango"][data-mood="shock"] .m-ear { animation: f-comb-up .7s cubic-bezier(.3, 1.5, .5, 1), m-ear var(--br) ease-in-out .7s infinite; }
  /* he waddles with a head bob, wobbles when he lands and his comb jiggles after every hop */
  .buddy.walking [data-m="frango"] .m-head { animation: f-bob .36s ease-in-out infinite; }
  .buddy.land .bd-me .m-svg[data-m="frango"] { animation: m-land .42s ease-out, f-trip .7s ease-out; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="frango"] .m-ear { animation: f-comb .7s ease-out .15s; }
  .buddy[data-idle="think"] [data-m="frango"]:is([data-mood="happy"], [data-mood="proud"]) .m-arm.l { animation-play-state: paused; }
  /* fidget: flexes and kisses his own bicep */
  .buddy[data-idle="fidget"] [data-m="frango"] .m-arm.r { animation: f-kiss-arm 2.6s cubic-bezier(.3, 1.3, .5, 1) both; }
  .buddy[data-idle="fidget"] [data-m="frango"] .m-head { animation: f-kiss-head 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="frango"] .m-eyes { animation: f-kiss-eyes 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="frango"] .m-mouth { animation: f-kiss-beak 2.6s ease-in-out both; }

  /* Gato: the tail talks. Slow sway, a tip that flicks now and then, whiskers that twitch. No dog wag. */
  [data-m="gato"] .m-tail { animation: g-sway 5.2s ease-in-out var(--d, 0s) infinite; }
  [data-m="gato"] .g-tip { animation: g-flick 3.7s ease-in-out var(--d, 0s) infinite; }
  [data-m="gato"] .g-wh { animation: g-whisk 5.9s ease-out var(--d, 0s) infinite; }
  [data-m="gato"] .g-wh.r { animation-delay: calc(var(--d, 0s) - .08s); }
  [data-m="gato"][data-mood] .m-arm { animation: none; }
  /* happy: lazy sway, tip flicks more; angry: fur puffs once, then shakes and the tail lashes; shock: tail pops up */
  [data-m="gato"][data-mood="happy"] { --br: 3.6s; } [data-m="gato"][data-mood="happy"] .m-body { animation-name: g-content; }
  [data-m="gato"][data-mood="happy"] .g-tip { animation-duration: 2.3s; }
  [data-m="gato"][data-mood="angry"] .m-body { animation: m-shake 2.4s ease-in-out .35s infinite, g-puff .35s cubic-bezier(.3, 1.6, .5, 1) both; }
  [data-m="gato"][data-mood="angry"] .m-tail { animation: g-lash 1.2s ease-in-out infinite; }
  [data-m="gato"][data-mood="angry"] .m-fx { animation: m-pulse 1.2s ease-in-out infinite; }
  [data-m="gato"][data-mood="shock"] .m-tail { animation: g-bristle .5s cubic-bezier(.3, 1.6, .5, 1) both; }
  [data-m="gato"]:is([data-mood="sad"], [data-mood="sleepy"]) .m-tail { animation: none; }
  [data-m="gato"][data-mood="sad"] .m-ear { animation: m-ear var(--br) ease-in-out var(--d, 0s) infinite; }
  [data-m="gato"]:is([data-mood="sad"], [data-mood="sleepy"]) .g-tip { animation-duration: 7.4s; }
  /* love: the slow blink ("cat kiss") and kneading paws */
  [data-m="gato"][data-mood="love"] .m-eyes { animation: g-slowblink 4.2s ease-in-out var(--d, 0s) infinite; }
  [data-m="gato"][data-mood="love"] .m-arm { animation: g-knead .9s ease-in-out infinite; }
  [data-m="gato"][data-mood="love"] .m-arm.r { animation-delay: -.45s; }
  /* walks with a level head and the tail up, lands neat with both ears flicking */
  .buddy.walking [data-m="gato"] .m-head { animation: g-level .36s ease-in-out infinite; }
  .buddy.walking [data-m="gato"] .m-tail { animation: g-walk-tail .72s ease-in-out infinite; }
  .buddy.land .bd-me .m-svg[data-m="gato"] { animation: g-land .42s ease-out; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="gato"] .m-ear { animation: g-ears .5s ease-out .1s; }
  /* fidget: licks a paw (the hanging arm swings up and hands over to the paw by the mouth) */
  .buddy[data-idle="fidget"] [data-m="gato"] .m-arm.l { animation: g-lick-arm 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="gato"] .g-lick { animation: g-lick 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="gato"] .g-tongue { animation: g-tongue 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="gato"] .m-head { animation: g-lick-head 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="gato"] .m-eyes { animation: f-kiss-eyes 2.6s ease-in-out both; }
  /* stretch: long and low with a big yawn */
  .buddy[data-idle="stretch"] .bd-me .m-svg[data-m="gato"] { animation: g-stretch 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="gato"] .m-arm { animation: g-reach 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="gato"] .m-tail { animation: g-stretch-tail 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="gato"] .m-eyes { animation: g-yawn-eyes 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="gato"] .m-mouth { animation: g-hide 2.6s both; }
  .buddy[data-idle="stretch"] [data-m="gato"] .g-yawn { animation: g-yawn 2.6s ease-in-out both; }
  /* think: no paw to the chin, the tail tip taps like drumming fingers */
  .buddy[data-idle="think"] [data-m="gato"] .m-arm.r { animation: none; }
  .buddy[data-idle="think"] [data-m="gato"] .g-tip { animation: g-tap 2.6s ease-in-out both; }

  /* Cachorrão: the tail never stops. Fast wag and panting when happy, tippy-tap paws, ears that flop after every hop */
  [data-m="cachorro"] .m-tail { animation: c-wag var(--wg) ease-in-out var(--d, 0s) infinite; }
  [data-m="cachorro"][data-mood] .m-arm { animation: none; }
  [data-m="cachorro"]:is([data-mood="happy"], [data-mood="proud"], [data-mood="love"]) .c-tongue { animation: c-pant .42s ease-in-out infinite; }
  [data-m="cachorro"][data-mood="happy"] .c-foot { animation: c-tap .52s ease-in-out infinite; }
  [data-m="cachorro"][data-mood="happy"] .c-foot.r { animation-delay: -.26s; }
  [data-m="cachorro"][data-mood="love"] .m-pupil { animation: m-pulse 1.2s ease-in-out infinite; }
  /* angry: a cute growl (the lip trembles), stiff tail quivers, heat rises; sad: tail thumps once, weakly */
  [data-m="cachorro"][data-mood="angry"] .m-mouth { animation: c-growl 2.4s linear infinite; }
  [data-m="cachorro"][data-mood="angry"] .m-tail { animation: c-quiver 2.4s linear infinite; }
  [data-m="cachorro"][data-mood="angry"] .m-fx { animation: c-steam 1.6s ease-out infinite; }
  [data-m="cachorro"][data-mood="sad"] .m-tail { animation: c-thump 4.4s ease-in-out var(--d, 0s) infinite; }
  [data-m="cachorro"][data-mood="sleepy"] .m-tail { animation: none; }
  /* sleepy: nods off, the nose bubble swells and shrinks with each breath; shock: ears fly up, tail pops */
  [data-m="cachorro"][data-mood="sleepy"] .m-head { animation: f-nod 4.8s ease-in-out infinite; }
  [data-m="cachorro"][data-mood="sleepy"] .c-bub { animation: c-bubble var(--br) ease-in-out var(--d, 0s) infinite; }
  [data-m="cachorro"][data-mood="shock"] .m-ear { animation: c-ears-up .6s cubic-bezier(.3, 1.6, .5, 1) both; }
  [data-m="cachorro"][data-mood="shock"] .m-tail { animation: g-bristle .5s cubic-bezier(.3, 1.6, .5, 1) both; }
  /* trots with a head bob and bouncing ears; every landing flops the ears */
  .buddy.walking [data-m="cachorro"] .m-head { animation: f-bob .36s ease-in-out infinite; }
  .buddy.walking [data-m="cachorro"] .m-ear { animation: c-trot-ear .36s ease-in-out infinite; }
  .buddy.walking [data-m="cachorro"]:is([data-mood="happy"], [data-mood="proud"], [data-mood="love"], [data-mood="smug"]) .m-tail { animation-duration: .36s; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="cachorro"] .m-ear { animation: c-flop .7s ease-out .1s; }
  /* fidget: chases his own tail (looks back, two quick turns, a dizzy wobble) */
  .buddy[data-idle="fidget"] .bd-me .m-svg[data-m="cachorro"] { animation: c-chase 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="cachorro"] .m-pupil { animation: c-chase-eye 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="cachorro"] .m-tail { animation: c-wag .26s ease-in-out infinite; }
  .buddy[data-idle="fidget"] [data-m="cachorro"] .m-ear { animation: c-chase-ear 2.6s ease-in-out both; }
  /* think: the big dog head tilt ("huh?"), one ear perks; no paw to the chin */
  .buddy[data-idle="think"] [data-m="cachorro"] .m-head { animation: c-tilt 2.6s cubic-bezier(.3, 1.4, .5, 1) both; }
  .buddy[data-idle="think"] [data-m="cachorro"] .m-ear.l { animation: c-perk 2.6s cubic-bezier(.3, 1.4, .5, 1) both; }
  .buddy[data-idle="think"] [data-m="cachorro"] .m-arm.r { animation: none; }
  /* stretch: play bow (front down, paws out, tail wagging), then the wet-dog shake */
  .buddy[data-idle="stretch"] .bd-me .m-svg[data-m="cachorro"] { animation: c-bow 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="cachorro"] .m-head { animation: c-bow-head 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="cachorro"] .m-arm { animation: c-bow-arm 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="cachorro"] .m-ear { animation: c-shake-ear 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="cachorro"] .m-tail { animation: c-wag .3s ease-in-out infinite; }

  /* Robô: the antenna springs now and then, chest lights blink on their own clocks, a scan line sweeps the screen */
  [data-m="robo"] .m-ear { animation: m-ear var(--br) ease-in-out var(--d, 0s) infinite, r-boing 7.3s var(--d, 0s) infinite; }
  [data-m="robo"] .r-led { animation: r-led 2.3s var(--d, 0s) infinite; }
  [data-m="robo"] .r-led.r1 { animation-duration: 3.7s; animation-delay: calc(var(--d, 0s) - 1.1s); }
  [data-m="robo"] .r-led.r2 { animation-duration: 1.9s; animation-delay: calc(var(--d, 0s) - .6s); }
  [data-m="robo"] .r-scan { animation: r-scan 4.3s linear var(--d, 0s) infinite; }
  [data-m="robo"] .r-glow { animation: r-glow 1.8s ease-in-out infinite; }
  [data-m="robo"][data-mood] .m-arm { animation: none; }
  /* happy: waves hello, the lights run in a chase */
  [data-m="robo"][data-mood="happy"] .m-arm.r { animation: r-wave 5.3s ease-in-out infinite; }
  [data-m="robo"][data-mood="happy"] .r-led { animation: r-chase 1.2s infinite; }
  [data-m="robo"][data-mood="happy"] .r-led.r1 { animation-delay: -.8s; } [data-m="robo"][data-mood="happy"] .r-led.r2 { animation-delay: -.4s; }
  [data-m="robo"][data-mood="proud"] .r-led { animation: none; }
  /* angry: fists pump, the alarm lights flash, sparks crackle off the antenna, the screen flickers */
  [data-m="robo"][data-mood="angry"] .m-arm { animation: r-fist .5s ease-in-out infinite; }
  [data-m="robo"][data-mood="angry"] .r-led { animation: r-alarm .5s infinite; }
  [data-m="robo"][data-mood="angry"] .r-spark { animation: r-spark 1.3s infinite; }
  [data-m="robo"][data-mood="angry"] .r-face { animation: r-flicker 2.4s infinite; }
  /* sad: one blue light fades in and out, a pixel tear rolls down the screen */
  [data-m="robo"][data-mood="sad"] .r-led { animation: r-fade 3.4s ease-in-out infinite; }
  [data-m="robo"][data-mood="sad"] .r-tear { animation: r-tear 2.8s ease-in var(--d, 0s) infinite; }
  /* sleepy: nods off, the low battery blinks */
  [data-m="robo"][data-mood="sleepy"] .m-head { animation: f-nod 4.8s ease-in-out infinite; }
  [data-m="robo"][data-mood="sleepy"] .r-bat { animation: r-bat 2s infinite; }
  /* shock: the antenna springs up, the screen glitches once */
  [data-m="robo"][data-mood="shock"] .m-ear { animation: r-sproing .9s ease-out both; }
  [data-m="robo"][data-mood="shock"] .r-glitch { animation: r-glitch-once .5s steps(1) both; }
  /* love: the heart eyes and the hidden heart on the chest beat */
  [data-m="robo"][data-mood="love"] .r-heart { animation: m-pulse 1.2s ease-in-out infinite; }
  /* walks like a machine: head ticks in two frames, arms swing, the antenna lags behind */
  .buddy.walking [data-m="robo"] .m-head { animation: r-tick .36s steps(1) infinite; }
  .buddy.walking [data-m="robo"] .m-arm { animation: r-swing .72s ease-in-out infinite; }
  .buddy.walking [data-m="robo"] .m-arm.r { animation-delay: -.36s; }
  .buddy.walking [data-m="robo"] .m-ear { animation: r-wobble .36s ease-in-out infinite; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="robo"] .m-ear { animation: r-sproing .9s ease-out .05s; }
  /* fidget: the screen glitches twice, then he checks if anyone saw */
  .buddy[data-idle="fidget"] .bd-me .m-svg[data-m="robo"] { animation: r-zap 2.6s steps(1) both; }
  .buddy[data-idle="fidget"] [data-m="robo"] .r-face { animation: r-jitter 2.6s steps(1) both; }
  .buddy[data-idle="fidget"] [data-m="robo"] .r-glitch { animation: r-glitch 2.6s steps(1) both; }
  .buddy[data-idle="fidget"] [data-m="robo"] .m-pupil { animation: r-sneak 2.6s ease-in-out both; }
  /* think: the face goes away and a loading spinner turns on the screen ("processando") */
  .buddy[data-idle="think"] [data-m="robo"] .r-face { animation: r-think-face 2.6s ease-in-out both; }
  .buddy[data-idle="think"] [data-m="robo"] .r-load { animation: r-think-load 2.6s ease-in-out both; }
  .buddy[data-idle="think"] [data-m="robo"] .r-spin { animation: r-spin .8s steps(8) infinite; }
  .buddy[data-idle="think"] [data-m="robo"] .m-arm.r { animation-play-state: paused; }
  /* look: the eyes slide across the screen */
  .buddy[data-idle="look"] [data-m="robo"] .m-eyes { animation: m-blink var(--bl) var(--d, 0s) infinite, r-slide 2.6s ease-in-out both; }
  /* stretch: the accordion neck pops the head up, arms reach out */
  .buddy[data-idle="stretch"] [data-m="robo"] .m-head { animation: r-extend 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="robo"] .m-arm { animation: r-reach 2.6s ease-in-out both; }

  /* Grifo: the wings breathe with the chest, the crest twitches, the lion tail swishes slowly; the shield never swings */
  [data-m="grifo"] .m-wing { animation: gr-wing var(--br) ease-in-out var(--d, 0s) infinite; }
  [data-m="grifo"] .m-wing.r { animation-delay: calc(var(--d, 0s) - .12s); }
  [data-m="grifo"] .m-tail { animation: gr-swish 3.4s ease-in-out var(--d, 0s) infinite; }
  [data-m="grifo"] .m-prop, [data-m="grifo"][data-mood] .m-arm { animation: none; }
  /* happy: small wing beats; proud: slow majestic beats and the shield gleams; love: the wings flutter */
  [data-m="grifo"][data-mood="happy"] .m-wing { animation-name: gr-beat; }
  [data-m="grifo"][data-mood="proud"] .m-wing { animation: gr-glory 2.4s ease-in-out infinite; }
  [data-m="grifo"][data-mood="proud"] .m-prop { animation: m-pulse 2.4s ease-in-out infinite; }
  [data-m="grifo"][data-mood="love"] .m-wing { animation: gr-flutter .5s ease-in-out infinite; }
  /* angry: on every shake the wings mantle wide and the crest shivers; the tail lashes */
  [data-m="grifo"][data-mood="angry"] .m-wing { animation: gr-mantle 2.4s ease-in-out .06s infinite; }
  [data-m="grifo"][data-mood="angry"] .m-ear { animation: gr-shiver 2.4s linear .12s infinite; }
  [data-m="grifo"][data-mood="angry"] .m-tail { animation: g-lash 1.2s ease-in-out infinite; }
  /* sad: wings hang still, a tear rolls; sleepy: nods off */
  [data-m="grifo"]:is([data-mood="sad"], [data-mood="sleepy"]) .m-tail, [data-m="grifo"][data-mood="sad"] .m-wing { animation: none; }
  [data-m="grifo"][data-mood="sad"] .gr-tear { animation: r-tear 2.8s ease-in var(--d, 0s) infinite; }
  [data-m="grifo"][data-mood="sleepy"] .m-head { animation: f-nod 4.8s ease-in-out infinite; }
  /* shock: the wings flare open on a spring, the crest shoots up */
  [data-m="grifo"][data-mood="shock"] .m-wing { animation: gr-flare .7s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="grifo"][data-mood="shock"] .m-ear { animation: gr-pop .7s cubic-bezier(.3, 1.6, .5, 1) both, m-ear var(--br) ease-in-out .7s infinite; }
  /* marches: head high and level, wings tucked, crest bouncing; lands with the wings flung out for balance */
  .buddy.walking [data-m="grifo"] .m-head { animation: g-level .36s ease-in-out infinite; }
  .buddy.walking [data-m="grifo"] .m-wing { animation: gr-tuck .36s ease-in-out infinite; }
  .buddy.walking [data-m="grifo"] .m-ear { animation: gr-bounce .36s ease-in-out infinite; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="grifo"] .m-wing { animation: gr-balance .7s ease-out; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="grifo"] .m-ear { animation: f-comb .7s ease-out .12s; }
  /* fidget: a knight salute (the right wing snaps up to the brow, chin up, eyes shut), then a flourish */
  .buddy[data-idle="fidget"] .bd-me .m-svg[data-m="grifo"] { animation: gr-attention 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="grifo"] .m-wing.r { animation: gr-salute 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="grifo"] .m-head { animation: gr-chin 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="grifo"] .m-eyes { animation: f-kiss-eyes 2.6s ease-in-out both; }
  /* stretch: wings spread wide, then fold in tight */
  .buddy[data-idle="stretch"] [data-m="grifo"] .m-wing { animation: gr-spread 2.6s ease-in-out both; }
  .buddy[data-idle="stretch"] [data-m="grifo"] .m-arm { animation: none; }
  /* think: no claw to the chin, the crest tilts while he plans the battle */
  .buddy[data-idle="think"] [data-m="grifo"] .m-arm.r { animation: none; }
  .buddy[data-idle="think"] [data-m="grifo"] .m-ear { animation: gr-ponder 2.6s cubic-bezier(.3, 1.4, .5, 1) both; }

  /* Zeus: the bolt crackles, the beard sways, the cloud of hair breathes a beat after the chest; the bolt never swings like a prop */
  [data-m="zeus"] .z-glow { animation: z-crackle 3.7s linear var(--d, 0s) infinite; }
  [data-m="zeus"] .z-beard { animation: z-beard 4.6s ease-in-out var(--d, 0s) infinite; }
  [data-m="zeus"] .z-hair { animation: z-hair var(--br) ease-in-out calc(var(--d, 0s) - .3s) infinite; }
  [data-m="zeus"] .m-prop, [data-m="zeus"][data-mood] .m-arm { animation: none; }
  /* happy: two biceps pumps, then he holds the flex; proud: fists on the hips, the bolt planted beside him, the stars twinkle (no pump: it would slide the fists off the hips) */
  [data-m="zeus"][data-mood="happy"] .m-arm { animation: z-pump 4.3s ease-in-out infinite; }
  [data-m="zeus"][data-mood="proud"] .m-fx { animation: z-twinkle 2.4s ease-in-out infinite; }
  /* smug: taps the bolt on his shoulder and lifts one brow now and then */
  [data-m="zeus"][data-mood="smug"] .m-arm:where(.r) { animation: z-tap 4s ease-in-out infinite; }
  [data-m="zeus"][data-mood="smug"] .m-brow { animation: z-brow 4s ease-in-out infinite; }
  /* angry: the raised bolt shakes with the body, the glow flashes twice, the hair rumbles, sparks blink */
  [data-m="zeus"][data-mood="angry"] .m-arm:where(.r) { animation: z-threat 2.4s ease-in-out infinite; }
  [data-m="zeus"][data-mood="angry"] .z-glow { animation: z-strobe 2.4s linear infinite; }
  [data-m="zeus"][data-mood="angry"] .z-hair { animation: z-rumble 2.4s linear .1s infinite; }
  [data-m="zeus"][data-mood="angry"] .m-fx { animation: z-zap 1.2s steps(1) -.58s infinite; } /* on from .62 to 1.22 s and 1.82 to 2.42 s: the sparks flash with the outburst */
  /* sad: his own little cloud rains on him */
  [data-m="zeus"][data-mood="sad"] .z-cloud { animation: z-cloud 3.2s ease-in-out infinite; }
  [data-m="zeus"][data-mood="sad"] .z-rain { animation: z-rain .9s linear infinite; }
  [data-m="zeus"][data-mood="sad"] .z-glow { animation: none; }
  /* sleepy: nods off on his bolt; shock: the hair stands up and the arms fly open; love: pats his heart */
  [data-m="zeus"][data-mood="sleepy"] .m-head { animation: f-nod 4.8s ease-in-out infinite; }
  [data-m="zeus"][data-mood="shock"] .z-hair { animation: z-frizz .7s cubic-bezier(.3, 1.6, .5, 1) both; }
  [data-m="zeus"][data-mood="shock"] .m-arm { animation: z-flare .7s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="zeus"][data-mood="love"] .m-arm:where(.l) { animation: z-pat 1.2s ease-in-out infinite; }
  /* he strides like he owns the place: head level, the bolt arm swings; the hair cloud squashes when he lands */
  .buddy.walking [data-m="zeus"] .m-head { animation: g-level .36s ease-in-out infinite; }
  .buddy.walking [data-m="zeus"] .m-arm { animation: z-march .72s ease-in-out infinite; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="zeus"] :is(.z-hair, .z-beard) { animation: z-land .7s ease-out; }
  /* fidget: twirls the bolt like a baton (a small wind-up, two turns, a cocky stop) with a raised brow */
  .buddy[data-idle="fidget"] [data-m="zeus"] .z-spin { animation: z-twirl 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="zeus"][data-mood="proud"] .z-spin { animation: none; } /* in proud the bolt stands beside him, not in his hand */
  .buddy[data-idle="fidget"] [data-m="zeus"] .m-brow { animation: z-brow 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="zeus"] .m-head { animation: z-admire 2.6s ease-in-out both; }
  /* think: consults the oracle (himself): strokes the beard, the bolt dims while he thinks and flares at the answer */
  .buddy[data-idle="think"] [data-m="zeus"] .m-arm.r { animation: none; }
  .buddy[data-idle="think"] [data-m="zeus"][data-mood="happy"] .m-arm { animation: z-pump 4.3s ease-in-out infinite paused; }
  .buddy[data-idle="think"] [data-m="zeus"] .z-beard { animation: z-stroke 2.6s ease-in-out both; }
  .buddy[data-idle="think"] [data-m="zeus"] .z-glow { animation: z-oracle 2.6s ease-in-out both; }

  /* Hércules: a gentle giant, slow and heavy; he lifts the rock like a feather and puts it down with care */
  [data-m="hercules"][data-mood] .m-arm { animation: none; }
  /* happy: two shy pumps of both arms; proud: double biceps, the rock floats over his fist a second */
  [data-m="hercules"][data-mood="happy"] .m-arm { animation: z-pump 4.9s ease-in-out infinite; }
  [data-m="hercules"][data-mood="proud"] .m-arm { animation: m-flex 2.3s ease-in-out infinite; }
  [data-m="hercules"][data-mood="proud"] .m-x-rock { animation: hc-float 3.1s ease-in-out infinite; }
  /* smug: a shy shrug with a tilted head; angry: the fists tremble; sad: the head sinks with a sigh */
  [data-m="hercules"][data-mood="smug"] .m-arm { animation: hc-shrug 4.1s ease-in-out infinite; }
  [data-m="hercules"][data-mood="smug"] .m-head { animation: z-admire 4.1s ease-in-out .2s infinite; }
  [data-m="hercules"][data-mood="angry"] .m-arm { animation: dr-shake 2.9s ease-in-out infinite; }
  [data-m="hercules"][data-mood="sad"] .m-head { animation: hc-sigh 5.3s ease-in-out infinite; }
  /* sleepy: nods off slowly; shock: the arms fly open (heavy, so a bit slower than Zeus); love: pats his heart */
  [data-m="hercules"][data-mood="sleepy"] .m-head { animation: f-nod 5.3s ease-in-out infinite; }
  [data-m="hercules"][data-mood="shock"] .m-arm { animation: z-flare .9s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="hercules"][data-mood="love"] .m-arm.l { animation: z-pat 1.4s ease-in-out infinite; }
  .buddy.walking [data-m="hercules"] .m-head { animation: g-level .36s ease-in-out infinite; }
  .buddy.walking [data-m="hercules"] .m-arm { animation: z-march .72s ease-in-out infinite; }
  /* fidget: reaches down, lifts the rock with one hand, holds it, sets it down gently */
  .buddy[data-idle="fidget"] [data-m="hercules"]:not([data-mood="proud"]) .m-x-rock { animation: hc-lift 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="hercules"]:not([data-mood="proud"]) .m-arm.r { animation: hc-reach 2.6s ease-in-out both; }
  .buddy[data-idle="think"] [data-m="hercules"] .m-arm.r { animation: none; }

  /* Hermes: never still. The foot wings beat nonstop, the helmet wings flutter, the wind trail gusts, the bag swings */
  [data-m="hermes"] .m-x-footwing { animation: hm-flap .26s ease-in-out var(--d, 0s) infinite; }
  [data-m="hermes"] .m-x-footwing.r { animation-duration: .29s; }
  [data-m="hermes"] .m-x-helmwing { animation: hm-flap 1.9s ease-in-out var(--d, 0s) infinite; }
  [data-m="hermes"] .m-x-helmwing.r { animation-duration: 2.3s; }
  [data-m="hermes"] .m-x-trail { animation: hm-gust 1.7s ease-in-out var(--d, 0s) infinite; }
  [data-m="hermes"] .m-x-bag { animation: hm-bag 2.9s ease-in-out var(--d, 0s) infinite; }
  [data-m="hermes"][data-mood] .m-arm { animation: none; }
  /* happy: a quick wave; proud: flexes the raised arm; smug: the letter (gossip) peeks out of the bag */
  [data-m="hermes"][data-mood="happy"] .m-arm.r { animation: dr-wave 3.1s ease-in-out infinite; }
  [data-m="hermes"][data-mood="proud"] .m-arm.r { animation: z-pump 3.7s ease-in-out infinite; }
  [data-m="hermes"][data-mood="smug"] .m-x-letter { animation: hm-peek 3.4s ease-in-out infinite; }
  [data-m="hermes"][data-mood="smug"] .m-head { animation: z-admire 3.4s ease-in-out .15s infinite; }
  /* angry: shakes the fist, the foot wings buzz; sad: every wing droops and stops */
  [data-m="hermes"][data-mood="angry"] .m-arm.r { animation: dr-shake 2.4s ease-in-out infinite; }
  [data-m="hermes"][data-mood="angry"] .m-x-footwing { animation-duration: .17s; }
  [data-m="hermes"][data-mood="sad"] :is(.m-x-footwing, .m-x-helmwing) { animation: none; rotate: calc(var(--s, 1) * -12deg); }
  /* sleepy: nods, the wings slow down; shock: arms fly open, the helmet wings flap wildly; love: pats his heart */
  [data-m="hermes"][data-mood="sleepy"] .m-head { animation: f-nod 3.7s ease-in-out infinite; }
  [data-m="hermes"][data-mood="sleepy"] .m-x-footwing { animation-duration: 1.3s; }
  [data-m="hermes"][data-mood="shock"] .m-arm { animation: z-flare .7s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="hermes"][data-mood="shock"] .m-x-helmwing { animation: hm-flap .12s ease-in-out 6; }
  [data-m="hermes"][data-mood="love"] .m-arm.l { animation: z-pat 1.1s ease-in-out infinite; }
  /* he walks like he is late: quick swings, the trail streams behind */
  .buddy.walking [data-m="hermes"] .m-head { animation: g-level .24s ease-in-out infinite; }
  .buddy.walking [data-m="hermes"] .m-arm { animation: z-march .48s ease-in-out infinite; }
  .buddy.walking [data-m="hermes"] .m-x-trail { animation: hm-gust .5s ease-in-out infinite; }
  /* talking: the bag swings with every word */
  .buddy.talking [data-m="hermes"] .m-x-bag { animation: hm-bag .44s ease-in-out 2; }
  /* fidget: zips out of the frame in a gust and pops back in from the other side */
  .buddy[data-idle="fidget"] .bd-me .m-svg[data-m="hermes"] { animation: hm-zip 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="hermes"] .m-x-trail { animation: hm-whoosh 2.6s ease-out both; }

  /* Poseidon: the beard rolls like a slow swell all the time; everything he does is heavy and a little sulky */
  [data-m="poseidon"] .m-x-beard { animation: z-beard 5.3s ease-in-out var(--d, 0s) infinite; }
  [data-m="poseidon"][data-mood] .m-arm { animation: none; }
  /* happy: the trident pumps; proud: he lifts it and thumps the floor, a little wave splashes up */
  [data-m="poseidon"][data-mood="happy"] .m-arm.r { animation: z-pump 4.7s ease-in-out infinite; }
  [data-m="poseidon"][data-mood="proud"] .m-arm.r { animation: px-thump 3.7s ease-in-out infinite; }
  [data-m="poseidon"][data-mood="proud"] .m-x-splash { animation: px-splash 3.7s ease-out infinite; }
  /* smug: one brow up, head turned away (Zeus who?) */
  [data-m="poseidon"][data-mood="smug"] .m-brow { animation: z-brow 4.3s ease-in-out infinite; }
  [data-m="poseidon"][data-mood="smug"] .m-head { animation: z-admire 4.3s ease-in-out .2s infinite; }
  /* angry: the storm cloud drifts, the trident shakes, the beard churns */
  [data-m="poseidon"][data-mood="angry"] .m-x-cloud { animation: z-cloud 2.3s ease-in-out infinite; }
  [data-m="poseidon"][data-mood="angry"] .m-arm.r { animation: dr-shake 2.3s ease-in-out infinite; }
  [data-m="poseidon"][data-mood="angry"] .m-x-beard { animation: z-rumble 2.3s linear .1s infinite; }
  /* sad: a long low sigh; sleepy: nods off at low tide */
  [data-m="poseidon"][data-mood="sad"] .m-head { animation: hc-sigh 5.9s ease-in-out infinite; }
  [data-m="poseidon"][data-mood="sleepy"] .m-head { animation: f-nod 5.9s ease-in-out infinite; }
  [data-m="poseidon"][data-mood="shock"] .m-arm { animation: z-flare .8s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="poseidon"][data-mood="love"] .m-arm.l { animation: z-pat 1.3s ease-in-out infinite; }
  /* walks like a heavy king: slow level head, slow arm swing; the beard bounces when he lands */
  .buddy.walking [data-m="poseidon"] .m-head { animation: g-level .42s ease-in-out infinite; }
  .buddy.walking [data-m="poseidon"] .m-arm { animation: z-march .84s ease-in-out infinite; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="poseidon"] .m-x-beard { animation: z-land .7s ease-out; }
  /* fidget: the trident thump with its little wave; think: strokes the beard */
  .buddy[data-idle="fidget"] [data-m="poseidon"] .m-arm.r { animation: px-thump 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="poseidon"] .m-x-splash { animation: px-splash 2.6s ease-out both; }
  .buddy[data-idle="think"] [data-m="poseidon"] .m-arm.r { animation: none; }
  .buddy[data-idle="think"] [data-m="poseidon"] .m-x-beard { animation: z-stroke 2.6s ease-in-out both; }

  /* Ninja: almost still. Only the sash tails move in the wind; every other move is one fast snap and a freeze */
  [data-m="ninja"] .m-x-sash { animation: nj-sash 1.9s ease-in-out var(--d, 0s) infinite; }
  [data-m="ninja"][data-mood] .m-arm { animation: none; }
  /* happy: a quick fist snap, then a hold; proud: a slow chin lift */
  [data-m="ninja"][data-mood="happy"] .m-arm.r { animation: nj-snap 4.1s ease-out infinite; }
  [data-m="ninja"][data-mood="proud"] .m-head { animation: z-admire 5.9s ease-in-out infinite; }
  [data-m="ninja"][data-mood="smug"] .m-brow { animation: z-brow 4.7s ease-in-out infinite; }
  /* angry: the fist snaps hard, the sash whips fast */
  [data-m="ninja"][data-mood="angry"] .m-arm.r { animation: dr-shake 2.9s ease-in-out infinite; }
  [data-m="ninja"][data-mood="angry"] .m-x-sash { animation-duration: .7s; }
  /* sad: the wind stops, the sash hangs; sleepy: nods off, the sash barely moves */
  [data-m="ninja"][data-mood="sad"] .m-x-sash { animation: none; rotate: 14deg; }
  [data-m="ninja"][data-mood="sad"] .m-head { animation: hc-sigh 6.1s ease-in-out infinite; }
  [data-m="ninja"][data-mood="sleepy"] .m-head { animation: f-nod 5.3s ease-in-out infinite; }
  [data-m="ninja"][data-mood="sleepy"] .m-x-sash { animation-duration: 4.3s; }
  [data-m="ninja"][data-mood="shock"] .m-arm { animation: z-flare .45s cubic-bezier(.3, 1.6, .5, 1) both; }
  [data-m="ninja"][data-mood="love"] .m-arm.l { animation: z-pat 1.7s ease-in-out infinite; }
  /* sneaks: the head stays level and quiet, small arm swing, the sash streams behind */
  .buddy.walking [data-m="ninja"] .m-arm { animation: z-march .9s ease-in-out infinite; }
  .buddy.walking [data-m="ninja"] .m-x-sash { animation-duration: .6s; }
  /* fidget: vanishes in a puff of smoke, pops up a step to the side, holds, then darts back in one move */
  .buddy[data-idle="fidget"] .bd-me .m-svg[data-m="ninja"] { animation: nj-shift 2.6s linear both; }
  .buddy[data-idle="fidget"] [data-m="ninja"] .m-body > :not(.m-x-smoke) { animation: nj-gone 2.6s linear both; }
  .buddy[data-idle="fidget"] [data-m="ninja"] .m-x-smoke { animation: nj-puff 2.6s ease-out both; }

  /* angry: the roar winds up (snout back and up), thrusts forward and shakes; the arms tremble with it */

  /* angry: the jaw opens wider (anticipation) then snaps; fins shake, tail lashes */
  /* Alien: the antennas react first to everything (they twitch before the head or arms move); the big head lags on the thin neck */
  [data-m="alien"] .m-x-antenna { animation: al-ant 2.9s ease-in-out var(--d, 0s) infinite; }
  [data-m="alien"] .m-x-antenna.r { animation-duration: 3.7s; }
  [data-m="alien"][data-mood] .m-arm { animation: none; }
  /* happy: antennas bounce, a friendly wave; proud: antennas stand tall, chin up */
  [data-m="alien"][data-mood="happy"] .m-x-antenna { animation-duration: 1.3s; }
  [data-m="alien"][data-mood="happy"] .m-arm.l { animation: dr-wave 3.1s ease-in-out .15s infinite; }
  [data-m="alien"][data-mood="proud"] .m-x-antenna { animation: none; rotate: calc(var(--s, 1) * 16deg); }
  [data-m="alien"][data-mood="proud"] .m-head { animation: z-admire 4.7s ease-in-out infinite; }
  [data-m="alien"][data-mood="smug"] .m-brow { animation: z-brow 4.3s ease-in-out infinite; }
  [data-m="alien"][data-mood="smug"] .m-head { animation: z-admire 5.3s ease-in-out .2s infinite; }
  /* angry: antennas buzz, the tablet shakes (formal complaint filed) */
  [data-m="alien"][data-mood="angry"] .m-x-antenna { animation: al-buzz .19s linear infinite; }
  [data-m="alien"][data-mood="angry"] .m-arm.r { animation: dr-shake 2.3s ease-in-out .1s infinite; }
  /* sad and sleepy: antennas droop, the heavy head sinks */
  [data-m="alien"]:is([data-mood="sad"], [data-mood="sleepy"]) .m-x-antenna { animation: none; rotate: calc(var(--s, 1) * -22deg); }
  [data-m="alien"][data-mood="sad"] .m-head { animation: hc-sigh 6.1s ease-in-out infinite; }
  [data-m="alien"][data-mood="sleepy"] .m-head { animation: f-nod 5.3s ease-in-out infinite; }
  [data-m="alien"][data-mood="shock"] .m-x-antenna { animation: al-zing .6s cubic-bezier(.3, 1.6, .5, 1) both; }
  [data-m="alien"][data-mood="shock"] .m-arm { animation: z-flare .7s cubic-bezier(.3, 1.5, .5, 1) .08s both; }
  [data-m="alien"][data-mood="love"] .m-x-antenna { animation-duration: 1.1s; }
  [data-m="alien"][data-mood="love"] .m-arm.l { animation: z-pat 1.3s ease-in-out infinite; }
  /* walks: arms swing, the big head lags a beat behind the steps, antennas bob */
  .buddy.walking [data-m="alien"] .m-head { animation: g-level .5s ease-in-out .1s infinite; }
  .buddy.walking [data-m="alien"] .m-arm { animation: z-march .5s ease-in-out infinite; }
  .buddy.walking [data-m="alien"] .m-x-antenna { animation-duration: .5s; }
  .buddy.talking [data-m="alien"] .m-x-antenna { animation: al-ant .44s ease-in-out 2; }
  /* fidget: antennas perk, he lifts the tablet and scans (the light sweeps up and down), eyes follow */
  .buddy[data-idle="fidget"] [data-m="alien"] .m-x-antenna { animation: al-zing .6s cubic-bezier(.3, 1.6, .5, 1) both; }
  .buddy[data-idle="fidget"] [data-m="alien"] .m-arm.r { animation: al-raise 2.6s ease-in-out .1s both; }
  .buddy[data-idle="fidget"] [data-m="alien"] .m-x-scan { animation: al-scan 2.6s ease-in-out .1s both; }
  .buddy[data-idle="fidget"] [data-m="alien"] .m-pupil { animation: dr-follow 2.6s ease-in-out both; }
  .buddy[data-idle="think"] [data-m="alien"] .m-x-antenna.r { animation: al-zing .8s cubic-bezier(.3, 1.6, .5, 1) both; }

  /* Panda: very slow. Floats in meditation all the time, his shadow breathes with it; rolls instead of walking */
  [data-m="panda"] .m-x-float { animation: pd-float 4.7s ease-in-out var(--d, 0s) infinite; }
  [data-m="panda"] .m-x-shadow { animation: pd-shadow 4.7s ease-in-out var(--d, 0s) infinite; }
  [data-m="panda"] .m-x-leaf { animation: pd-drift 6.1s ease-in-out var(--d, 0s) infinite; }
  [data-m="panda"][data-mood] .m-arm { animation: none; }
  [data-m="panda"][data-mood="happy"] .m-head { animation: g-level 5.3s ease-in-out infinite; }
  [data-m="panda"][data-mood="proud"] .m-head { animation: z-admire 6.1s ease-in-out infinite; }
  [data-m="panda"][data-mood="smug"] .m-head { animation: z-admire 7.3s ease-in-out .3s infinite; }
  /* angry: he lands (the float stops) and one eye opens; one small sharp head jolt, nothing louder */
  [data-m="panda"][data-mood="angry"] :is(.m-x-float, .m-x-shadow) { animation: none; }
  [data-m="panda"][data-mood="angry"] .m-head { animation: dr-shake 3.7s ease-in-out infinite; }
  [data-m="panda"][data-mood="sad"] .m-head { animation: hc-sigh 7.1s ease-in-out infinite; }
  [data-m="panda"][data-mood="sleepy"] .m-head { animation: f-nod 6.7s ease-in-out infinite; }
  [data-m="panda"][data-mood="sad"] :is(.m-x-float, .m-x-shadow) { animation-duration: 7.9s; }
  [data-m="panda"][data-mood="sleepy"] :is(.m-x-float, .m-x-shadow) { animation-duration: 8.3s; }
  [data-m="panda"][data-mood="shock"] .m-x-float { animation: pd-jolt .7s cubic-bezier(.3, 1.4, .5, 1) both; }
  [data-m="panda"][data-mood="shock"] .m-arm { animation: z-flare .9s cubic-bezier(.3, 1.5, .5, 1) .1s both; }
  [data-m="panda"][data-mood="love"] .m-arm { animation: z-pat 1.9s ease-in-out infinite; }
  [data-m="panda"][data-mood="love"] .m-head { animation: g-level 4.1s ease-in-out infinite; }
  .buddy.walking [data-m="panda"] .m-x-float { animation: pd-roll 1.3s linear infinite; }
  /* fidget: a deeper breath in, he floats higher, holds, and settles back down soft */
  .buddy[data-idle="fidget"] [data-m="panda"] .m-x-float { animation: pd-rise 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="panda"] .m-x-shadow { animation: pd-rise-shadow 2.6s ease-in-out both; }
  /* think: he closes his eyes and the bamboo leaf falls slowly past him */
  .buddy[data-idle="think"] [data-m="panda"] .m-eyes { animation: f-kiss-eyes 2.6s ease-in-out both; }
  .buddy[data-idle="think"] [data-m="panda"] .m-x-leaf { animation: pd-fall 2.6s ease-in-out both; }

  /* Unicórnio: a diva. The mane sways on its own clock and gets flipped for the camera; the horn glints now and then, sparkles twinkle when she shines */
  [data-m="unicornio"] .m-x-mane { animation: un-sway 3.7s ease-in-out var(--d, 0s) infinite; }
  [data-m="unicornio"] .m-x-shine { animation: un-glint 4.3s ease-in-out var(--d, 0s) infinite; }
  [data-m="unicornio"] .m-x-sparkle path { animation: un-twinkle 1.9s ease-in-out infinite; }
  [data-m="unicornio"] .m-x-sparkle path:nth-child(2) { animation-duration: 2.3s; animation-delay: -.7s; } [data-m="unicornio"] .m-x-sparkle path:nth-child(3) { animation-duration: 1.7s; animation-delay: -1.3s; }
  [data-m="unicornio"][data-mood] .m-arm, .buddy[data-idle="fidget"] .bd-me .m-svg:is([data-m="unicornio"], [data-m="fantasma"]) { animation: none; }
  /* happy: a little hoof wave and a mane flip; proud: chin up for the camera, flip after flip; smug: one brow up, a slow admiring tilt */
  [data-m="unicornio"][data-mood="happy"] .m-arm.l { animation: dr-wave 3.1s ease-in-out .15s infinite; }
  [data-m="unicornio"][data-mood="happy"] .m-x-mane { animation: un-flip 3.1s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="proud"] .m-head { animation: z-admire 4.3s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="proud"] .m-x-mane { animation: un-flip 4.3s ease-in-out .25s infinite; }
  [data-m="unicornio"][data-mood="smug"] .m-brow { animation: z-brow 4.7s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="smug"] .m-head { animation: z-admire 5.9s ease-in-out .2s infinite; }
  /* angry: stamps a hoof, the head snaps, the mane bristles out */
  [data-m="unicornio"][data-mood="angry"] .m-arm.r { animation: un-stamp 1.3s ease-in infinite; }
  [data-m="unicornio"][data-mood="angry"] .m-head { animation: dr-shake 2.3s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="angry"] .m-x-mane { animation: none; rotate: 9deg; }
  /* sad and sleepy: the mane hangs and the horn shine goes out (her glow fades) */
  [data-m="unicornio"]:is([data-mood="sad"], [data-mood="sleepy"]) .m-x-mane { animation: none; rotate: -4deg; }
  [data-m="unicornio"]:is([data-mood="sad"], [data-mood="sleepy"]) .m-x-shine { animation: none; opacity: .15; }
  [data-m="unicornio"][data-mood="sad"] .m-head { animation: hc-sigh 6.7s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="sleepy"] .m-head { animation: f-nod 5.9s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="shock"] :is(.m-arm, .m-x-mane) { animation: z-flare .7s cubic-bezier(.3, 1.5, .5, 1) .08s both; }
  [data-m="unicornio"][data-mood="love"] .m-arm.l { animation: z-pat 1.7s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="love"] .m-head { animation: g-level 4.1s ease-in-out infinite; }
  [data-m="unicornio"][data-mood="love"] .m-x-shine { animation-duration: 1.3s; }
  /* walk: a prance; hooves high, the head bobs, the mane trails a beat behind */
  .buddy.walking [data-m="unicornio"] .m-arm { animation: un-prance .36s ease-in-out infinite; }
  .buddy.walking [data-m="unicornio"] .m-arm.r { animation-delay: -.18s; }
  .buddy.walking [data-m="unicornio"] .m-head { animation: f-bob .36s ease-in-out .06s infinite; }
  .buddy.walking [data-m="unicornio"] .m-x-mane { animation: un-sway .36s ease-in-out .12s infinite; }
  /* fidget: she glances away, the chin lifts, and the mane gets tossed back with a flourish while the horn flashes */
  .buddy[data-idle="fidget"] [data-m="unicornio"] .m-head { animation: un-toss-head 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="unicornio"] .m-x-mane { animation: un-toss 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="unicornio"] .m-x-shine { animation: un-glint .9s ease-in-out .9s 2; }
  .buddy[data-idle="fidget"] [data-m="unicornio"] .m-pupil { animation: m-look 2.6s ease-in-out both; }

  /* Fantasma: always floating on a slow sine, the hem ripples, a puff trails off; he fades when he is happy ("quase sumi") and is solid when you let him down.
     The face, arms and scarf ride the float, so the shared mood moves on the sheet alone stay off (they would slide the sheet under the face) */
  [data-m="fantasma"] .m-x-float { animation: fa-float 3.7s ease-in-out var(--d, 0s) infinite; }
  [data-m="fantasma"][data-mood] .m-body { animation: m-breathe var(--br) ease-in-out var(--d, 0s) infinite; }
  [data-m="fantasma"] .m-x-hem { animation: fa-hem 1.9s ease-in-out var(--d, 0s) infinite; }
  [data-m="fantasma"] .m-x-wisp { animation: fa-wisp 3.7s ease-out var(--d, 0s) infinite; }
  [data-m="fantasma"] .m-arm { animation: fa-arm 2.9s ease-in-out var(--d, 0s) infinite; }
  [data-m="fantasma"] .m-arm.r { animation-delay: calc(var(--d, 0s) - 1.1s); }
  [data-m="fantasma"]:is([data-mood="happy"], [data-mood="proud"], [data-mood="love"]) .m-x-float { animation: fa-float 3.7s ease-in-out var(--d, 0s) infinite, fa-fade 4.3s ease-in-out infinite; }
  [data-m="fantasma"][data-mood="happy"] .m-arm.l { animation: dr-wave 3.1s ease-in-out .15s infinite; }
  [data-m="fantasma"][data-mood="proud"] .m-arm { animation: fa-cheer 2.3s ease-in-out infinite; }
  [data-m="fantasma"][data-mood="proud"] .m-arm.r { animation-delay: -.2s; }
  [data-m="fantasma"][data-mood="smug"] .m-brow { animation: z-brow 4.3s ease-in-out infinite; }
  [data-m="fantasma"][data-mood="smug"] .m-x-float { animation-duration: 5.3s; }
  /* angry: the Buuu. He winds down, stretches tall with the arms up, holds, then shrinks back a little embarrassed */
  [data-m="fantasma"][data-mood="angry"] .m-x-float { animation: fa-boo 3.1s ease-in-out infinite; }
  [data-m="fantasma"][data-mood="angry"] .m-arm { animation: fa-boo-arm 3.1s ease-in-out infinite; }
  /* sad: sinks low and slow, arms hang; sleepy: drifts very slow, the hem barely moves */
  [data-m="fantasma"][data-mood="sad"] .m-x-float { animation: fa-sink 6.1s ease-in-out infinite; }
  [data-m="fantasma"]:is([data-mood="sad"], [data-mood="sleepy"]) .m-arm { animation: none; rotate: calc(var(--s, 1) * -8deg); }
  [data-m="fantasma"][data-mood="sleepy"] .m-x-float { animation-duration: 7.3s; }
  [data-m="fantasma"]:is([data-mood="sad"], [data-mood="sleepy"]) .m-x-hem { animation-duration: 4.7s; }
  /* shock: he jolts up and flickers nearly invisible for a blink (a ghost scared of you) */
  [data-m="fantasma"][data-mood="shock"] .m-x-float { animation: pd-jolt .7s cubic-bezier(.3, 1.4, .5, 1) both, fa-flicker .7s linear both; }
  [data-m="fantasma"][data-mood="shock"] .m-arm { animation: z-flare .7s cubic-bezier(.3, 1.5, .5, 1) .08s both; }
  [data-m="fantasma"][data-mood="love"] .m-arm { animation: z-pat 1.9s ease-in-out infinite; }
  /* walk: no feet, so no step; he glides, the hem ripples faster, arms tucked */
  .buddy.walking .bd-me .m-svg[data-m="fantasma"] { animation: none; }
  .buddy.walking [data-m="fantasma"] .m-x-float { animation: fa-float 1.1s ease-in-out infinite; }
  .buddy.walking [data-m="fantasma"] .m-x-hem { animation-duration: .6s; }
  .buddy.walking [data-m="fantasma"] .m-arm { animation: none; rotate: calc(var(--s, 1) * -14deg); }
  /* fidget: one Buuu out of nowhere, then the shy shrink */
  .buddy[data-idle="fidget"] [data-m="fantasma"] .m-x-float { animation: fa-boo 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="fantasma"] .m-arm { animation: fa-boo-arm 2.6s ease-in-out both; }

  /* Dragão: the wings breathe with the chest, the tail swishes slowly, and now and then he snorts smoke from both nostrils */
  [data-m="dragao"] .m-wing { animation: gr-wing var(--br) ease-in-out var(--d, 0s) infinite; }
  [data-m="dragao"] .m-wing.r { animation-delay: calc(var(--d, 0s) - .12s); }
  [data-m="dragao"] .m-tail { animation: gr-swish 4.2s ease-in-out var(--d, 0s) infinite; }
  [data-m="dragao"] .d-puff { animation: dr-snort 6.2s ease-out var(--d, 0s) infinite; }
  [data-m="dragao"] .m-prop, [data-m="dragao"][data-mood] .m-arm { animation: none; }
  /* happy: waves from the shoulder, the tail swishes quicker; proud: slow wing beats and a huff of smoke on each one */
  [data-m="dragao"][data-mood="happy"] .m-arm:where(.r) { animation: dr-wave 6.2s ease-in-out infinite; }
  [data-m="dragao"][data-mood="happy"] .m-tail { animation-duration: 1.8s; }
  [data-m="dragao"][data-mood="proud"] .m-wing { animation: gr-glory 2.4s ease-in-out infinite; }
  [data-m="dragao"][data-mood="proud"] .m-fx { animation: dr-huff 2.4s ease-out infinite; }
  /* smug: turns his claw to admire the talons, one brow lifts */
  [data-m="dragao"][data-mood="smug"] .m-arm:where(.r) { animation: dr-admire 4s ease-in-out infinite; }
  [data-m="dragao"][data-mood="smug"] .m-brow { animation: z-brow 4s ease-in-out infinite; }
  /* angry: fire licks at the mouth, the smoke fumes, and on every shake the fists jerk and the wings mantle; the tail lashes */
  [data-m="dragao"][data-mood="angry"] .m-fx .d-fire { animation: dr-flicker .45s ease-in-out infinite alternate; }
  [data-m="dragao"][data-mood="angry"] .m-fx { animation: dr-fume 1.6s ease-in-out infinite; }
  [data-m="dragao"][data-mood="angry"] .m-arm { animation: dr-shake 2.4s ease-in-out infinite; }
  [data-m="dragao"][data-mood="angry"] .m-wing { animation: gr-mantle 2.4s ease-in-out .06s infinite; }
  [data-m="dragao"][data-mood="angry"] .m-tail { animation: g-lash 1.2s ease-in-out infinite; }
  /* sad: wings and tail hang still, a tear rolls, the fizzled smoke sinks; sleepy: nods off, smoke and Zz rise with the slow breath */
  [data-m="dragao"]:is([data-mood="sad"], [data-mood="sleepy"]) :is(.m-wing, .m-tail, .d-puff) { animation: none; }
  [data-m="dragao"][data-mood="sad"] .d-tear { animation: r-tear 2.8s ease-in var(--d, 0s) infinite; }
  [data-m="dragao"][data-mood="sad"] .m-fx { animation: dr-fizzle 3.4s ease-in-out infinite; }
  [data-m="dragao"][data-mood="sleepy"] .m-head { animation: f-nod 4.8s ease-in-out infinite; }
  /* shock: the wings flare open on a spring and the hands fly up; love: the wings flutter and the smoke heart floats up */
  [data-m="dragao"][data-mood="shock"] .m-wing { animation: gr-flare .7s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="dragao"][data-mood="shock"] .m-arm { animation: z-flare .7s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="dragao"][data-mood="love"] .m-wing { animation: gr-flutter .5s ease-in-out infinite; }
  [data-m="dragao"][data-mood="love"] .m-fx { animation: dr-heart 2.4s ease-out infinite; }
  /* stomps: head level, wings tucked, arms swing; lands with the wings flung out and the tail flopping */
  .buddy.walking [data-m="dragao"] .m-head { animation: g-level .36s ease-in-out infinite; }
  .buddy.walking [data-m="dragao"] .m-wing { animation: gr-tuck .36s ease-in-out infinite; }
  .buddy.walking [data-m="dragao"] .m-arm { animation: z-march .72s ease-in-out infinite; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="dragao"] .m-wing { animation: gr-balance .7s ease-out; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="dragao"] .m-tail { animation: c-flop .7s ease-out .1s; }
  /* fidget: a fire cough. The cheeks puff up, a little burst of fire and smoke pops out, then he glances around: did anyone see? */
  .buddy[data-idle="fidget"] [data-m="dragao"] .m-head { animation: dr-cough-head 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="dragao"] .d-cough { animation: dr-cough 2.6s ease-out both; }
  .buddy[data-idle="fidget"] [data-m="dragao"] .m-pupil { animation: r-sneak 2.6s ease-in-out both; }
  /* think: blows smoke rings while he plots, and his eyes follow them up; stretch: the wings spread wide, then fold in */
  .buddy[data-idle="think"] [data-m="dragao"] .m-arm.r { animation: none; }
  .buddy[data-idle="think"] [data-m="dragao"][data-mood="happy"] .m-arm.r { animation: dr-wave 6.2s ease-in-out infinite paused; }
  .buddy[data-idle="think"] [data-m="dragao"] .d-ring { animation: dr-ring 2s ease-out both; }
  .buddy[data-idle="think"] [data-m="dragao"] .d-ring.d1 { animation-delay: .3s; }
  .buddy[data-idle="think"] [data-m="dragao"] .d-ring.d2 { animation-delay: .6s; }
  .buddy[data-idle="think"] [data-m="dragao"] .m-pupil { animation: dr-follow 2.6s ease-in-out both; }
  .buddy[data-m="dragao"][data-idle="think"]::before, .buddy[data-m="dragao"][data-idle="think"] .bd-me::before, .buddy[data-m="dragao"][data-idle="think"] .bd-me::after { display: none; }
  .buddy[data-idle="stretch"] [data-m="dragao"] .m-wing { animation: gr-spread 2.6s ease-in-out both; }

  /* Monstro: the glow in his sockets pulses, the long fingers never stop creeping (each hand on its own clock), the ears flick */
  [data-m="monstro"] .mo-glow { animation: mo-glow 3.1s ease-in-out var(--d, 0s) infinite; }
  [data-m="monstro"] :where(.m-arm.l) .mo-fing { animation: mo-creep 2.9s ease-in-out var(--d, 0s) infinite; }
  [data-m="monstro"] :where(.m-arm.r) .mo-fing { animation: mo-creep 3.7s ease-in-out calc(var(--d, 0s) - 1.3s) infinite; }
  [data-m="monstro"] .m-prop, [data-m="monstro"][data-mood] .m-arm { animation: none; }
  /* happy: a slow creepy wave from the shoulder, the fingers ripple a beat behind; proud: the eyes burn brighter */
  [data-m="monstro"][data-mood="happy"] .m-arm:where(.r) { animation: dr-wave 7.1s ease-in-out infinite; }
  [data-m="monstro"][data-mood="happy"] :where(.m-arm.r) .mo-fing { animation: mo-ripple 1.6s ease-in-out -.2s infinite; }
  [data-m="monstro"][data-mood="proud"] .mo-glow { animation-duration: 1.6s; }
  /* smug: the steepled fingertips tap together (excelente...), one brow lifts */
  [data-m="monstro"][data-mood="smug"] .mo-fing { animation: mo-tap 1.1s ease-in-out infinite; }
  [data-m="monstro"][data-mood="smug"] .m-brow { animation: z-brow 4s ease-in-out infinite; }
  /* angry: the claws loom and jerk on every shake, flex fast, and the glow flares twice */
  [data-m="monstro"][data-mood="angry"] .m-arm { animation: dr-shake 2.4s ease-in-out infinite; }
  [data-m="monstro"][data-mood="angry"] .mo-fing { animation: mo-creep 1.2s ease-in-out infinite; }
  [data-m="monstro"][data-mood="angry"] .mo-glow { animation: mo-flare 2.4s ease-in-out infinite; }
  /* sad: hugs himself tighter now and then, a tear rolls; sleepy: nods off while one hand rubs the eye */
  [data-m="monstro"][data-mood="sad"] .m-arm { animation: mo-squeeze 4.4s ease-in-out infinite; }
  [data-m="monstro"][data-mood="sad"] .mo-tear { animation: r-tear 2.8s ease-in var(--d, 0s) infinite; }
  [data-m="monstro"][data-mood="sleepy"] .m-head { animation: f-nod 4.8s ease-in-out infinite; }
  [data-m="monstro"][data-mood="sleepy"] .m-arm:where(.r) { animation: mo-rub 1.4s ease-in-out infinite; }
  /* shock: the ears spring up, the hands slap onto the cheeks; love: the clasped hands squeeze in time with the heart */
  [data-m="monstro"][data-mood="shock"] .m-ear { animation: mo-ears-up .8s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="monstro"][data-mood="shock"] .m-arm { animation: mo-slap .6s cubic-bezier(.3, 1.5, .5, 1) both; }
  [data-m="monstro"][data-mood="love"] .m-arm { animation: mo-squeeze 1.2s ease-in-out infinite; }
  [data-m="monstro"][data-mood="love"] .mo-glow { animation-duration: 1.2s; }
  /* he sneaks: head level, arms swing low, the fingers drag along; the long ears flop when he lands */
  .buddy.walking [data-m="monstro"] .m-head { animation: g-level .36s ease-in-out infinite; }
  .buddy.walking [data-m="monstro"] .m-arm { animation: z-march .72s ease-in-out infinite; }
  .buddy.walking [data-m="monstro"] .mo-fing { animation: mo-creep .72s ease-in-out infinite; }
  :is(.buddy.land, .buddy.hopping):not([data-mood="shock"]) [data-m="monstro"] .m-ear { animation: mo-flop .7s ease-out .06s; }
  /* fidget: shy peek. The hands come up over the face, one hand slides open, a glowing eye peeks at you, then he hides again */
  .buddy[data-idle="fidget"] [data-m="monstro"] .m-body > .m-arm { animation: mo-arms-off 2.6s linear both; }
  .buddy[data-idle="fidget"] [data-m="monstro"] .mo-peek { display: inline; animation: mo-peek-in 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="monstro"] .mo-peek .m-arm.r { animation: mo-peek-open 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="monstro"] .m-head { animation: mo-hide 2.6s ease-in-out both; }
  .buddy[data-idle="fidget"] [data-m="monstro"] .m-pupil { animation: mo-peek-eye 2.6s ease-in-out both; }
  /* think: his third eye opens on the brow and looks around while the other two roll up */
  .buddy[data-idle="think"] [data-m="monstro"] .m-arm.r { animation: none; }
  .buddy[data-idle="think"] [data-m="monstro"][data-mood="happy"] .m-arm.r { animation: dr-wave 7.1s ease-in-out infinite paused; }
  .buddy[data-idle="think"] [data-m="monstro"] .mo-eye3 { animation: mo-eye3 2.6s ease-in-out both; }
  .buddy[data-idle="think"] [data-m="monstro"] .mo-p3 { animation: mo-p3 2.6s ease-in-out both; }

  /* rows of many faces (ranking, podium, picker cards not chosen) only breathe and blink: the breath moves the whole <svg> box (composited, nothing inside repaints) and !important keeps any mascot class from moving inside */
  :is(.rk-m, .step-m, .mp[aria-pressed="false"]) .m-svg { transform-origin: 50% 100%; animation: m-breathe 3.2s ease-in-out var(--d, 0s) infinite; }
  :is(.rk-m, .step-m, .mp[aria-pressed="false"]) :is(.m-body, .m-body :not(.m-eyes)) { animation: none !important; }
}
@keyframes m-breathe { 50% { transform: scale(1.02, .98); } }
@keyframes m-head { 0%, 100% { translate: 0 0; } 35% { translate: 0 -.8px; } 70% { translate: 0 1.1px; } }
@keyframes m-ear { 0%, 100% { rotate: 0deg; } 45% { rotate: -3deg; } 80% { rotate: 2deg; } }
@keyframes m-flick { 0%, 90%, 100% { transform: none; } 92% { transform: rotate(-14deg); } 95% { transform: rotate(6deg); } 97% { transform: rotate(-3deg); } }
@keyframes m-blink { 0%, 29%, 33%, 76%, 80%, 84%, 100% { transform: scaleY(1); } 31%, 78%, 82% { transform: scaleY(.1); } }
@keyframes m-glance { 0%, 17%, 38%, 52%, 70%, 100% { translate: 0 0; } 19%, 36% { translate: -1px .3px; } 54%, 68% { translate: 1.1px -.7px; } }
@keyframes m-flex { 50% { transform: rotate(calc(var(--s, 1) * -8deg)); } }
@keyframes m-wag { 0%, 100% { transform: rotate(0); } 40% { transform: rotate(16deg); } 55% { transform: rotate(12deg); } 85% { transform: rotate(-2deg); } }
@keyframes m-flap { 50% { transform: rotate(-10deg); } }
@keyframes m-sway { 0%, 100% { rotate: 0deg; } 30% { rotate: 5deg; } 70% { rotate: -4deg; } }
@keyframes m-fx { 50% { translate: 0 -2px; opacity: .75; } }
@keyframes m-zz { 0% { translate: 0 2px; opacity: 0; } 25% { opacity: 1; } 100% { translate: 2px -8px; opacity: 0; } }
@keyframes m-pulse { 0%, 30%, 100% { scale: 1; } 15% { scale: 1.18; } 45% { scale: 1.1; } }
@keyframes m-puff { 0% { scale: .6; opacity: 0; } 30% { opacity: 1; } 100% { scale: 1.3; translate: 0 -4px; opacity: 0; } }
@keyframes j-bounce2 { 0% { transform: none; animation-timing-function: cubic-bezier(.2, .7, .3, 1); } 7% { transform: translateY(calc(-2px * var(--mw, 1))) scale(calc(1 - .01 * var(--mw, 1) * var(--sq, 1)), calc(1 + .02 * var(--mw, 1) * var(--sq, 1))); animation-timing-function: cubic-bezier(.55, 0, 1, .45); }
  13% { transform: scale(calc(1 + .03 * var(--mw, 1) * var(--sq, 1)), calc(1 - .03 * var(--mw, 1) * var(--sq, 1))); animation-timing-function: cubic-bezier(.2, .7, .3, 1); } 20% { transform: translateY(calc(-1.4px * var(--mw, 1))); animation-timing-function: cubic-bezier(.55, 0, 1, .45); }
  27% { transform: scale(calc(1 + .02 * var(--mw, 1) * var(--sq, 1)), calc(1 - .02 * var(--mw, 1) * var(--sq, 1))); } 35%, 100% { transform: none; } }
@keyframes m-bounce { 0%, 100% { transform: none; } 30% { transform: translateY(calc(-2px * var(--mw, 1))) scale(calc(1 - .01 * var(--mw, 1) * var(--sq, 1)), calc(1 + .02 * var(--mw, 1) * var(--sq, 1))); } 55% { transform: scale(calc(1 + .03 * var(--mw, 1) * var(--sq, 1)), calc(1 - .03 * var(--mw, 1) * var(--sq, 1))); } 70% { transform: none; } }
@keyframes m-proud { 50% { transform: scale(calc(1 + .03 * var(--mw, 1) * var(--sq, 1))) rotate(calc(-1.5deg * var(--mw, 1))); } }
@keyframes m-smug { 50% { transform: rotate(calc(2.5deg * var(--mw, 1))); } }
@keyframes m-droop { 0%, 100% { transform: translateY(calc(1px * var(--mw, 1))) scale(1, calc(1 - .01 * var(--mw, 1) * var(--sq, 1))); } 50% { transform: translateY(calc(2px * var(--mw, 1))) scale(calc(1 + .01 * var(--mw, 1) * var(--sq, 1)), calc(1 - .03 * var(--mw, 1) * var(--sq, 1))); } }
@keyframes m-deep { 50% { transform: scale(calc(1 + .035 * var(--mw, 1) * var(--sq, 1)), calc(1 - .035 * var(--mw, 1) * var(--sq, 1))); } }
@keyframes m-love { 0%, 100% { transform: rotate(calc(-2.5deg * var(--mw, 1))); } 50% { transform: rotate(calc(2.5deg * var(--mw, 1))); } }
@keyframes m-jump { 40% { transform: translateY(-12px) scale(.96, 1.05); } 70% { transform: translateY(0) scale(1.05, .95); } }
@keyframes m-huff { 50% { scale: calc(1 + .025 * var(--mw, 1) * var(--sq, 1)) calc(1 - .025 * var(--mw, 1) * var(--sq, 1)); } }
@keyframes m-tremble { 25% { translate: -.8px 0; } 75% { translate: .8px 0; } }
@keyframes m-shake { 0%, 80%, 100% { transform: none; } 84% { transform: rotate(calc(-3deg * var(--mw, 1))); } 88% { transform: rotate(calc(3deg * var(--mw, 1))); } 92% { transform: rotate(calc(-2deg * var(--mw, 1))); } }
@keyframes m-step { 0%, 100% { translate: 0 0; rotate: 0deg; } 25% { translate: 0 -3px; rotate: -4deg; } 75% { translate: 0 -3px; rotate: 4deg; } }
@keyframes m-swap { from { scale: 1.05 .93; } }
@keyframes m-sink { from { scale: 1 1.03; translate: 0 -1px; } }
@keyframes m-land { 0% { scale: calc(1 + .16 * var(--li, 1)) calc(1 - .16 * var(--li, 1)); } 35% { scale: .95 1.06; } 65% { scale: 1.02 .98; } 100% { scale: 1; } }
/* tap: crouch, jump, squash on landing, settle */
@keyframes m-hop { 0%, 100% { transform: none; } 14% { transform: scale(1.1, .88); } 45% { transform: translateY(-20px) scale(.94, 1.07); } 72% { transform: scale(1.12, .88); } 86% { transform: scale(.97, 1.03); } }
@keyframes m-pick { 0%, 100% { transform: none; } 14% { transform: scale(1.08, .9); } 45% { transform: translateY(-10px) scale(.96, 1.05); } 72% { transform: scale(1.08, .92); } 86% { transform: scale(.98, 1.02); } }
@keyframes m-leap { 0% { transform: scale(.9, 1.1); } 30% { transform: none; } }
@keyframes m-hearts { from { opacity: 1; transform: translateY(0) scale(.6); } to { opacity: 0; transform: translateY(-34px) scale(1.2); } }
@keyframes m-talk { 50% { scale: 1 .55; } }
@keyframes m-think-eye { 0%, 100% { translate: 0 0; } 15%, 85% { translate: 1.6px -2.2px; } }
@keyframes m-think-brow { 0%, 100% { translate: 0 0; } 15%, 85% { translate: 0 -2px; } }
@keyframes m-think-head { 0%, 100% { rotate: 0deg; } 18%, 85% { rotate: -4deg; } }
@keyframes m-think-arm { 0%, 100% { rotate: 0deg; } 18%, 82% { rotate: -22deg; } }
@keyframes m-think-tilt { 0%, 100% { rotate: 0deg; } 18%, 85% { rotate: calc(var(--fx, 1) * -4deg); } }
@keyframes m-dot1 { 0%, 6% { scale: 0; opacity: 0; } 13% { scale: 1.25; opacity: 1; } 18%, 86% { scale: 1; opacity: 1; } 100% { scale: .6; opacity: 0; } }
@keyframes m-dot2 { 0%, 16% { scale: 0; opacity: 0; } 23% { scale: 1.25; opacity: 1; } 28%, 86% { scale: 1; opacity: 1; } 100% { scale: .6; opacity: 0; } }
@keyframes m-dot3 { 0%, 26% { scale: 0; opacity: 0; } 33% { scale: 1.25; opacity: 1; } 38%, 86% { scale: 1; translate: 0 0; opacity: 1; } 100% { scale: .7; translate: 0 -4px; opacity: 0; } }
@keyframes m-look { 0%, 100% { translate: 0 0; } 12%, 40% { translate: -2px 0; } 52%, 82% { translate: 2px -.3px; } }
@keyframes m-look-head { 0%, 100% { rotate: 0deg; } 12%, 40% { rotate: -4deg; } 52%, 82% { rotate: 4deg; } }
@keyframes m-stretch { 0%, 100% { scale: 1; } 30%, 58% { scale: .96 1.08; } 70% { scale: 1.05 .95; } 82% { scale: .99 1.01; } }
@keyframes m-stretch-arm { 0%, 100% { rotate: 0deg; } 30%, 58% { rotate: calc(var(--s, 1) * -16deg); } }
@keyframes f-flap { 0%, 30%, 100% { rotate: 0deg; } 5%, 15%, 25% { rotate: calc(var(--s, 1) * -7deg); } 10%, 20% { rotate: calc(var(--s, 1) * -1deg); } }
@keyframes f-pump { 0%, 100% { rotate: 0deg; } 45% { rotate: calc(var(--s, 1) * 8deg); } 60% { rotate: calc(var(--s, 1) * 6deg); } }
@keyframes f-nod { 0%, 100% { translate: 0 0; rotate: 0deg; } 55% { translate: 0 1.2px; rotate: 1deg; } 78% { translate: 0 2.6px; rotate: 3deg; } 82% { translate: 0 -.6px; rotate: -1.5deg; } 90% { translate: 0 0; rotate: 0deg; } }
@keyframes f-flare { 35% { rotate: calc(var(--s, 1) * -20deg); } 100% { rotate: calc(var(--s, 1) * -7deg); } }
@keyframes f-comb-up { 0% { translate: 0 0; } 30% { translate: 0 -5px; rotate: -8deg; } 60% { translate: 0 1px; rotate: 5deg; } 100% { translate: 0 0; rotate: 0deg; } }
@keyframes f-comb { 0%, 100% { rotate: 0deg; } 20% { rotate: -12deg; } 45% { rotate: 8deg; } 70% { rotate: -4deg; } }
@keyframes f-bob { 0%, 50%, 100% { translate: 0 .6px; } 30%, 80% { translate: 0 -1.2px; } }
@keyframes f-trip { 0%, 100% { rotate: 0deg; } 20% { rotate: calc(var(--fx, 1) * -7deg); } 42% { rotate: calc(var(--fx, 1) * 5deg); } 66% { rotate: calc(var(--fx, 1) * -2deg); } 85% { rotate: calc(var(--fx, 1) * .5deg); } }
@keyframes f-kiss-arm { 0%, 100% { rotate: 0deg; } 18%, 80% { rotate: 16deg; } 40% { rotate: 20deg; } 58% { rotate: 14deg; } }
@keyframes f-kiss-head { 0%, 14%, 100% { rotate: 0deg; translate: 0 0; } 30%, 50% { rotate: 7deg; translate: 1.4px 0; } 40% { rotate: 5deg; } 60% { rotate: 8deg; translate: 1.8px 0; } 78% { rotate: 0deg; translate: 0 0; } }
@keyframes f-kiss-eyes { 0%, 22%, 72%, 100% { transform: scaleY(1); } 28%, 66% { transform: scaleY(.12); } }
@keyframes f-kiss-beak { 0%, 22%, 72%, 100% { scale: 1; } 28%, 66% { scale: .8 1.08; } 40%, 58% { scale: .72 1.12; } }
@keyframes g-sway { 50% { rotate: -2.5deg; } }
@keyframes g-flick { 0%, 58%, 100% { rotate: 0deg; } 66% { rotate: 16deg; } 72% { rotate: -5deg; } 78% { rotate: 3deg; } 84% { rotate: 0deg; } }
@keyframes g-whisk { 0%, 86%, 100% { rotate: 0deg; } 89% { rotate: calc(var(--s, 1) * -7deg); } 93% { rotate: calc(var(--s, 1) * 3deg); } 96% { rotate: 0deg; } }
@keyframes g-content { 50% { transform: rotate(1.6deg) scale(1.01, .99); } }
@keyframes g-puff { from { scale: 1; } to { scale: 1.045 1.03; } }
@keyframes g-lash { 0%, 100% { rotate: 0deg; } 25% { rotate: -6deg; } 75% { rotate: 4deg; } }
@keyframes g-bristle { 0% { scale: .7; } 60% { scale: 1.08; } 100% { scale: 1; } }
@keyframes g-slowblink { 0%, 40%, 100% { transform: scaleY(1); } 55%, 68% { transform: scaleY(.1); } }
@keyframes g-knead { 50% { translate: 0 -2px; } }
@keyframes g-level { 0%, 100% { rotate: 0deg; } 25% { rotate: 3deg; } 75% { rotate: -3deg; } }
@keyframes g-walk-tail { 50% { rotate: -4deg; } }
@keyframes g-land { 0% { scale: 1.08 .92; } 45% { scale: .98 1.02; } 100% { scale: 1; } }
@keyframes g-ears { 0%, 100% { rotate: 0deg; } 30% { rotate: calc(var(--s, 1) * -10deg); } 60% { rotate: calc(var(--s, 1) * 4deg); } }
/* the hanging arm and the licking paw swap in one frame at the same angle, so it reads as one arm swinging up */
@keyframes g-lick-arm { 0%, 100% { rotate: 0deg; opacity: 1; } 15.9% { rotate: -80deg; opacity: 1; } 16%, 83.9% { rotate: -80deg; opacity: 0; } 84% { rotate: -80deg; opacity: 1; } }
@keyframes g-lick { 0%, 15.9%, 84%, 100% { rotate: 80deg; opacity: 0; } 16% { rotate: 80deg; opacity: 1; } 26%, 76% { rotate: 0deg; } 36%, 56% { rotate: -6deg; } 46%, 66% { rotate: 2deg; } 83.9% { rotate: 80deg; opacity: 1; } }
@keyframes g-tongue { 0%, 24%, 74%, 100% { opacity: 0; scale: .3; } 28%, 44%, 60%, 70% { opacity: 1; scale: 1; } 36%, 52% { opacity: 1; scale: .6; } }
@keyframes g-lick-head { 0%, 12%, 84%, 100% { rotate: 0deg; } 24%, 48%, 72% { rotate: -5deg; } 36%, 60% { rotate: -7deg; } }
@keyframes g-stretch { 0%, 100% { scale: 1; } 25%, 60% { scale: 1.1 .9; } 72% { scale: .97 1.04; } 85% { scale: 1.01 .99; } }
@keyframes g-reach { 0%, 100% { rotate: 0deg; } 25%, 60% { rotate: calc(var(--s, 1) * 28deg); } }
@keyframes g-stretch-tail { 0%, 100% { rotate: 0deg; } 30%, 58% { rotate: -8deg; } 66% { rotate: -3deg; } 72% { rotate: -6deg; } }
@keyframes g-yawn-eyes { 0%, 18%, 74%, 100% { transform: scaleY(1); } 26%, 66% { transform: scaleY(.1); } }
@keyframes g-hide { 0%, 20%, 68%, 100% { opacity: 1; } 24%, 64% { opacity: 0; } }
@keyframes g-yawn { 0%, 18%, 68%, 100% { opacity: 0; scale: .4 .2; } 26% { opacity: 1; scale: .9 .8; } 34%, 56% { opacity: 1; scale: 1; } 64% { opacity: 1; scale: .6 .4; } }
@keyframes g-tap { 0%, 30%, 55%, 80%, 100% { rotate: 0deg; } 20%, 45%, 70% { rotate: 14deg; } }
@keyframes c-wag { 0%, 100% { rotate: -9deg; } 50% { rotate: 13deg; } }
@keyframes c-pant { 50% { scale: 1 1.16; } }
@keyframes c-tap { 0%, 45%, 100% { translate: 0 0; } 22% { translate: 0 -2.4px; } }
@keyframes c-growl { 0%, 34%, 100% { translate: 0 0; } 4%, 12%, 20%, 28% { translate: .45px 0; } 8%, 16%, 24%, 32% { translate: -.45px 0; } }
@keyframes c-quiver { 0%, 78%, 100% { rotate: 0deg; } 82%, 90% { rotate: 3deg; } 86%, 94% { rotate: -2deg; } }
@keyframes c-steam { 0% { translate: 0 2px; opacity: 0; } 30% { opacity: 1; } 100% { translate: 0 -6px; opacity: 0; } }
@keyframes c-thump { 0%, 70%, 100% { rotate: 0deg; } 78% { rotate: -6deg; } 86% { rotate: 0deg; } }
@keyframes c-bubble { 0%, 100% { scale: .55; } 50% { scale: 1.12; } }
@keyframes c-ears-up { 0% { rotate: -22deg; } 55% { rotate: 6deg; } 100% { rotate: 0deg; } }
@keyframes c-trot-ear { 0%, 50%, 100% { rotate: 0deg; } 25%, 75% { rotate: 7deg; } }
@keyframes c-flop { 0%, 100% { rotate: 0deg; } 20% { rotate: 16deg; } 45% { rotate: -8deg; } 70% { rotate: 4deg; } }
/* two quick turns: scaleX flips its sign at 40% width (never through zero, or he vanishes), a hop on each turn, then a dizzy wobble */
@keyframes c-chase { 0%, 100% { scale: 1; rotate: 0deg; translate: 0 0; } 10% { rotate: 7deg; } 18% { scale: 1.06 .94; rotate: 5deg; translate: 0 0; }
  22.9% { scale: .4 1; } 23% { scale: -.4 1; } 28% { scale: -1 1; rotate: 0deg; translate: 0 -5px; } 32.9% { scale: -.4 1; } 33% { scale: .4 1; } 38% { scale: 1 1; translate: 0 0; }
  42.9% { scale: .4 1; } 43% { scale: -.4 1; } 48% { scale: -1 1; translate: 0 -5px; } 52.9% { scale: -.4 1; } 53% { scale: .4 1; } 58% { scale: 1 1; translate: 0 0; }
  66% { rotate: -6deg; } 74% { rotate: 5deg; } 82% { rotate: -3deg; } 90% { rotate: 1deg; } }
@keyframes c-chase-eye { 0%, 100% { translate: 0 0; } 8%, 18% { translate: 2.2px .8px; } 62%, 66% { translate: -1.6px -.6px; } 74% { translate: 1.6px .6px; } 82% { translate: -.8px 0; } }
@keyframes c-chase-ear { 0%, 22%, 100% { rotate: 0deg; } 30%, 50% { rotate: 18deg; } 40%, 60% { rotate: -6deg; } 70% { rotate: 6deg; } 80% { rotate: -2deg; } }
@keyframes c-tilt { 0%, 100% { rotate: 0deg; } 16%, 82% { rotate: 13deg; } }
@keyframes c-perk { 0%, 100% { rotate: 0deg; } 16%, 82% { rotate: 18deg; } }
@keyframes c-bow { 0%, 100% { scale: 1; rotate: 0deg; } 12% { scale: 1.03 .97; } 22%, 46% { scale: 1.1 .88; } 54% { scale: 1; rotate: 0deg; }
  58% { rotate: 7deg; } 62% { rotate: -7deg; } 66% { rotate: 6deg; } 70% { rotate: -6deg; } 74% { rotate: 4deg; } 78% { rotate: -3deg; } 84% { rotate: 1deg; } 90% { rotate: 0deg; } }
@keyframes c-bow-head { 0%, 54%, 100% { translate: 0 0; } 22%, 46% { translate: 0 3px; } }
@keyframes c-bow-arm { 0%, 54%, 100% { rotate: 0deg; } 22%, 46% { rotate: calc(var(--s, 1) * 38deg); } }
@keyframes c-shake-ear { 0%, 56%, 92%, 100% { rotate: 0deg; } 60%, 68%, 76% { rotate: 20deg; } 64%, 72%, 80% { rotate: -10deg; } 86% { rotate: 4deg; } }
@keyframes r-boing { 0%, 88%, 100% { transform: none; } 90% { transform: rotate(-12deg); } 92.5% { transform: rotate(8deg); } 95% { transform: rotate(-4.5deg); } 97.5% { transform: rotate(2deg); } }
@keyframes r-sproing { 0% { transform: none; } 15% { transform: rotate(-18deg); } 35% { transform: rotate(12deg); } 55% { transform: rotate(-7deg); } 75% { transform: rotate(3deg); } 100% { transform: none; } }
@keyframes r-led { 0%, 70%, 78%, 100% { opacity: 1; } 72%, 76% { opacity: .3; } }
@keyframes r-chase { 0%, 33% { opacity: 1; } 34%, 100% { opacity: .3; } }
@keyframes r-alarm { 0%, 49% { opacity: 1; } 50%, 100% { opacity: .35; } }
@keyframes r-fade { 50% { opacity: .3; } }
@keyframes r-scan { 0% { translate: 0 0; opacity: 0; } 12% { opacity: .08; } 68% { translate: 0 24px; opacity: .08; } 76%, 100% { translate: 0 26px; opacity: 0; } }
@keyframes r-glow { 0%, 100% { scale: .9; opacity: .55; } 50% { scale: 1.1; opacity: 1; } }
@keyframes r-wave { 0%, 46%, 100% { rotate: -4deg; } 9%, 27% { rotate: 12deg; } 18%, 36% { rotate: 2deg; } }
@keyframes r-fist { 50% { rotate: calc(var(--s, 1) * 6deg); } }
@keyframes r-spark { 0%, 40%, 56%, 70%, 81%, 100% { opacity: 1; scale: 1; } 41%, 55%, 71%, 80% { opacity: 0; scale: .7; } }
@keyframes r-flicker { 0%, 88%, 92%, 96%, 100% { opacity: 1; } 90% { opacity: .5; } 94% { opacity: .75; } }
@keyframes r-tear { 0% { translate: 0 -1px; opacity: 0; } 15% { opacity: 1; } 75% { translate: 0 5px; opacity: 1; } 100% { translate: 0 6px; opacity: 0; } }
@keyframes r-bat { 0%, 49% { opacity: 1; } 50%, 100% { opacity: .15; } }
@keyframes r-glitch-once { 0% { opacity: 1; translate: 3px 0; } 20% { opacity: 0; } 40% { opacity: 1; translate: -3px 0; } 60%, 100% { opacity: 0; translate: 0 0; } }
/* glitch: steps(1) holds each frame, so the face jumps like a broken signal instead of sliding */
@keyframes r-jitter { 0%, 18% { translate: 0 0; } 20% { translate: 2.5px 0; } 22% { translate: -2px .6px; } 24% { translate: 1.5px -.4px; } 26% { translate: -1px 0; } 28%, 62% { translate: 0 0; } 63% { translate: 1.5px 0; } 65% { translate: -1px 0; } 67%, 100% { translate: 0 0; } }
@keyframes r-glitch { 0%, 19% { opacity: 0; } 20% { opacity: 1; translate: 3px 0; } 23% { opacity: 0; } 24% { opacity: 1; translate: -3px 0; } 28%, 62% { opacity: 0; translate: 0 0; } 63% { opacity: 1; translate: 2px 0; } 66%, 100% { opacity: 0; translate: 0 0; } }
@keyframes r-zap { 0%, 19% { translate: 0 0; } 20% { translate: 1px 0; } 22% { translate: -1px 0; } 26%, 100% { translate: 0 0; } }
@keyframes r-sneak { 0%, 30%, 80%, 100% { translate: 0 0; } 36%, 52% { translate: -1.8px .3px; } 58%, 72% { translate: 1.8px .3px; } }
@keyframes r-think-face { 0%, 100% { opacity: 1; } 10%, 84% { opacity: 0; } }
@keyframes r-think-load { 0%, 8%, 90%, 100% { opacity: 0; } 16%, 82% { opacity: 1; } }
@keyframes r-spin { to { rotate: 360deg; } }
@keyframes r-slide { 0%, 100% { translate: 0 0; } 12%, 40% { translate: -4.5px 0; } 52%, 82% { translate: 4.5px -.5px; } }
@keyframes r-extend { 0%, 100% { translate: 0 0; } 22% { translate: 0 -10px; } 30% { translate: 0 -8.4px; } 36%, 58% { translate: 0 -9px; } 70% { translate: 0 1.2px; } 78% { translate: 0 -.4px; } 86% { translate: 0 0; } }
@keyframes r-reach { 0%, 100% { rotate: 0deg; } 24%, 58% { rotate: calc(var(--s, 1) * 20deg); } 70% { rotate: calc(var(--s, 1) * -3deg); } 80% { rotate: 0deg; } }
@keyframes r-tick { 0%, 100% { translate: 0 0; } 50% { translate: 0 -1.2px; } }
@keyframes r-wobble { 0%, 100% { rotate: -5deg; } 50% { rotate: 6deg; } }
@keyframes r-swing { 0%, 100% { rotate: -9deg; } 50% { rotate: 9deg; } }
/* grifo: + folds a wing in, - spreads it out (the right wing flips the sign with --s) */
@keyframes gr-wing { 0%, 100% { rotate: 0deg; } 50% { rotate: calc(var(--s, 1) * -2.5deg); } }
@keyframes gr-beat { 0%, 75%, 100% { rotate: 0deg; } 30% { rotate: calc(var(--s, 1) * -9deg); } 55% { rotate: calc(var(--s, 1) * 2deg); } }
@keyframes gr-glory { 0%, 100% { rotate: 0deg; } 45% { rotate: calc(var(--s, 1) * -12deg); } 60% { rotate: calc(var(--s, 1) * -11deg); } }
@keyframes gr-flutter { 50% { rotate: calc(var(--s, 1) * -4deg); } }
@keyframes gr-mantle { 0%, 78%, 100% { rotate: 0deg; } 82% { rotate: calc(var(--s, 1) * -9deg); } 86% { rotate: calc(var(--s, 1) * -5deg); } 90% { rotate: calc(var(--s, 1) * -8deg); } }
@keyframes gr-shiver { 0%, 80%, 100% { rotate: 0deg; } 83% { rotate: -7deg; } 86% { rotate: 6deg; } 89% { rotate: -4deg; } 92% { rotate: 2deg; } }
@keyframes gr-swish { 0%, 100% { rotate: 0deg; } 40% { rotate: 7deg; } 55% { rotate: 6deg; } 80% { rotate: -3deg; } }
@keyframes gr-flare { 0% { rotate: calc(var(--s, 1) * 16deg); } 40% { rotate: calc(var(--s, 1) * -8deg); } 100% { rotate: 0deg; } }
@keyframes gr-pop { 0% { scale: 1 .5; } 45% { scale: 1 1.15; } 100% { scale: 1; } }
@keyframes gr-tuck { 0%, 100% { rotate: calc(var(--s, 1) * 9deg); } 50% { rotate: calc(var(--s, 1) * 6deg); } }
@keyframes gr-bounce { 0%, 100% { rotate: -3deg; } 50% { rotate: 4deg; } }
@keyframes gr-balance { 0% { rotate: calc(var(--s, 1) * -18deg); } 35% { rotate: calc(var(--s, 1) * 5deg); } 65% { rotate: calc(var(--s, 1) * -3deg); } 100% { rotate: 0deg; } }
@keyframes gr-attention { 0%, 100% { scale: 1; } 20%, 70% { scale: .98 1.03; } }
/* salute: a small dip (anticipation), a snap up past the brow, hold, then a flourish back down */
@keyframes gr-salute { 0%, 100% { rotate: 0deg; } 10% { rotate: calc(var(--s, 1) * -7deg); } 22% { rotate: calc(var(--s, 1) * 24deg); } 27%, 68% { rotate: calc(var(--s, 1) * 19deg); } 80% { rotate: calc(var(--s, 1) * -9deg); } 90% { rotate: calc(var(--s, 1) * 2deg); } }
@keyframes gr-chin { 0%, 18%, 100% { translate: 0 0; rotate: 0deg; } 28%, 68% { translate: 0 -1.5px; rotate: -3deg; } }
@keyframes gr-spread { 0%, 100% { rotate: 0deg; } 30%, 52% { rotate: calc(var(--s, 1) * -22deg); } 68%, 80% { rotate: calc(var(--s, 1) * 12deg); } }
@keyframes gr-ponder { 0%, 100% { rotate: 0deg; } 18%, 85% { rotate: 12deg; } }
/* zeus: the glow is a wrapper, so these opacities scale the strength each mood gives the glow */
@keyframes z-crackle { 0%, 62%, 70%, 100% { opacity: 1; } 64% { opacity: .35; } 66% { opacity: 1; } 68% { opacity: .5; } 84% { opacity: .75; } }
@keyframes z-strobe { 0%, 76%, 84%, 92%, 100% { opacity: 1; } 80%, 88% { opacity: .25; } }
@keyframes z-beard { 0%, 100% { rotate: 0deg; } 35% { rotate: 1.6deg; } 75% { rotate: -1.2deg; } }
@keyframes z-hair { 50% { scale: 1.015 1.02; } }
/* two pumps, then he holds the flex and lets everyone look */
@keyframes z-pump { 0%, 44%, 100% { rotate: 0deg; } 10%, 30% { rotate: calc(var(--s, 1) * 7deg); } 18%, 38% { rotate: calc(var(--s, 1) * 2deg); } }
@keyframes z-twinkle { 0%, 100% { scale: 1; opacity: 1; } 40% { scale: .7; opacity: .55; } 55% { scale: 1.15; opacity: 1; } }
@keyframes z-tap { 0%, 60%, 100% { rotate: 0deg; } 68% { rotate: -4deg; } 74% { rotate: 1deg; } 80% { rotate: -3deg; } 86% { rotate: 0deg; } }
@keyframes z-brow { 0%, 20%, 72%, 100% { translate: 0 0; } 28%, 64% { translate: 0 -1.6px; } }
@keyframes z-threat { 0%, 78%, 100% { rotate: 0deg; } 82% { rotate: -6deg; } 86% { rotate: 4deg; } 90% { rotate: -3deg; } 94% { rotate: 1deg; } }
@keyframes z-rumble { 0%, 80%, 100% { translate: 0 0; } 83% { translate: -.8px 0; } 86% { translate: .8px -.4px; } 89% { translate: -.5px 0; } }
@keyframes z-zap { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
@keyframes z-cloud { 0%, 100% { translate: 0 0; } 50% { translate: 1.4px .8px; } }
@keyframes z-rain { 0% { translate: 0 -2px; opacity: 0; } 25% { opacity: 1; } 100% { translate: 0 5px; opacity: 0; } }
@keyframes z-frizz { 0% { scale: .92 .8; } 45% { scale: 1.04 1.12; } 100% { scale: 1; } }
@keyframes z-flare { 0% { rotate: calc(var(--s, 1) * 14deg); } 40% { rotate: calc(var(--s, 1) * -6deg); } 100% { rotate: 0deg; } }
@keyframes z-pat { 0%, 100% { rotate: 0deg; } 20% { rotate: -2.5deg; } 40% { rotate: 0deg; } 55% { rotate: -1.5deg; } 70% { rotate: 0deg; } }
@keyframes z-march { 0%, 100% { rotate: calc(var(--s, 1) * 2deg); } 50% { rotate: calc(var(--s, 1) * -3deg); } }
@keyframes z-land { 0% { scale: 1.06 .86; } 40% { scale: .98 1.05; } 70% { scale: 1.01 .99; } 100% { scale: 1; } }
/* twirl: a small wind-up back, two fast turns that ease out, a cocky stop */
@keyframes z-twirl { 0%, 8% { rotate: 0deg; } 18% { rotate: -25deg; } 62% { rotate: 735deg; } 72% { rotate: 716deg; } 80%, 100% { rotate: 720deg; } }
@keyframes z-admire { 0%, 100% { rotate: 0deg; translate: 0 0; } 20%, 80% { rotate: 4deg; translate: 0 -.8px; } }
@keyframes z-stroke { 0%, 100% { rotate: 0deg; } 20% { rotate: 3deg; } 35% { rotate: -2deg; } 50% { rotate: 3deg; } 65% { rotate: -2deg; } 80% { rotate: 1deg; } }
@keyframes z-oracle { 0%, 100% { opacity: 1; } 20%, 60% { opacity: .2; } 72% { opacity: 1; } }
@keyframes hc-float { 0%, 100% { translate: 0 0; } 45%, 62% { translate: 0 -4px; } }
@keyframes hc-shrug { 0%, 58%, 100% { translate: 0 0; } 68%, 84% { translate: 0 -2px; } }
@keyframes hc-sigh { 0%, 100% { rotate: 0deg; translate: 0 0; } 40%, 72% { rotate: -2deg; translate: 0 1.4px; } }
@keyframes hc-lift { 0%, 12% { translate: 0 0; } 18% { translate: 0 1px; } 40% { translate: -2px -21px; } 62% { translate: -2px -22px; } 86% { translate: 0 -1px; } 92% { translate: 0 .4px; } 100% { translate: 0 0; } }
@keyframes hc-reach { 0%, 8% { rotate: 0deg; } 16% { rotate: 2deg; } 40%, 62% { rotate: -18deg; } 88% { rotate: -1deg; } 100% { rotate: 0deg; } }
@keyframes hm-flap { 0%, 100% { rotate: 0deg; } 50% { rotate: calc(var(--s, 1) * 16deg); } }
@keyframes hm-gust { 0%, 100% { opacity: .45; translate: 0 0; } 50% { opacity: .15; translate: -3px 0; } }
@keyframes hm-bag { 0%, 100% { rotate: 0deg; } 30% { rotate: 2deg; } 70% { rotate: -1.5deg; } }
@keyframes hm-peek { 0%, 30%, 100% { translate: 0 0; } 40%, 80% { translate: 0 -4px; } }
@keyframes hm-zip { 0%, 6% { translate: 0 0; scale: 1; opacity: 1; } 12% { translate: 3px 0; scale: .92 1.06; } 22%, 48% { translate: -60px 0; scale: 1.4 .8; opacity: 0; } 49% { translate: 60px 0; scale: 1.4 .8; opacity: 0; } 66% { translate: -4px 0; scale: 1.15 .88; opacity: 1; } 76% { translate: 2px 0; scale: .97 1.03; } 86%, 100% { translate: 0 0; scale: 1; opacity: 1; } }
@keyframes hm-whoosh { 0%, 8% { opacity: .45; translate: 0 0; } 18% { opacity: 1; translate: 6px 0; } 40%, 100% { opacity: .45; translate: 0 0; } }
@keyframes px-thump { 0%, 14% { translate: 0 0; } 30% { translate: 0 -6px; } 38% { translate: 0 1.2px; } 44% { translate: 0 -.4px; } 52%, 100% { translate: 0 0; } }
@keyframes px-splash { 0%, 36% { scale: 1; opacity: 1; } 44% { scale: 1.8 1.6; opacity: 1; } 60% { scale: 1.2; opacity: .5; } 72%, 100% { scale: 1; opacity: 1; } }
@keyframes nj-sash { 0%, 100% { rotate: 0deg; scale: 1; } 30% { rotate: -5deg; scale: 1 .92; } 55% { rotate: 3deg; scale: 1.03 1; } 80% { rotate: -2deg; } }
@keyframes nj-snap { 0%, 70% { rotate: 0deg; } 73% { rotate: -11deg; } 76%, 94% { rotate: -8deg; } 100% { rotate: 0deg; } }
@keyframes nj-shift { 0%, 46% { translate: 0 0; } 47%, 80% { translate: 16px 0; } 84% { translate: -1.5px 0; } 87%, 100% { translate: 0 0; } }
@keyframes nj-gone { 0%, 18% { opacity: 1; } 22%, 50% { opacity: 0; } 56%, 100% { opacity: 1; } }
@keyframes nj-puff { 0%, 14% { opacity: 0; scale: .4; } 22% { opacity: 1; scale: 1.1; } 40%, 48% { opacity: 0; scale: 1.4; } 49% { opacity: 0; scale: .4; } 54% { opacity: 1; scale: 1.1; } 70%, 100% { opacity: 0; scale: 1.4; } }
/* alien: antenna sway, buzz and the shock "zing" up (outward is --s); the tablet lift and its scan light */
@keyframes al-ant { 0%, 100% { rotate: 0deg; } 30% { rotate: calc(var(--s, 1) * 7deg); } 65% { rotate: calc(var(--s, 1) * -5deg); } }
@keyframes al-buzz { 0%, 100% { rotate: calc(var(--s, 1) * -3deg); } 50% { rotate: calc(var(--s, 1) * 3deg); } }
@keyframes al-zing { 0% { rotate: 0deg; } 35% { rotate: calc(var(--s, 1) * 26deg); } 65% { rotate: calc(var(--s, 1) * 13deg); } 100% { rotate: calc(var(--s, 1) * 17deg); } }
@keyframes al-raise { 0%, 6% { rotate: 0deg; } 14% { rotate: 3deg; } 32%, 76% { rotate: -16deg; } 92%, 100% { rotate: 0deg; } }
@keyframes al-scan { 0%, 30% { translate: 0 0; } 42% { translate: 0 -10px; } 54% { translate: 0 0; } 66% { translate: 0 -10px; } 78%, 100% { translate: 0 0; } }
/* panda: slow float, its shadow, the drifting leaf, the roll, the rise and the falling leaf */
@keyframes pd-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -3px; } }
@keyframes pd-shadow { 0%, 100% { scale: 1; } 50% { scale: .86 1; } }
@keyframes pd-drift { 0%, 100% { rotate: 0deg; translate: 0 0; } 50% { rotate: 10deg; translate: 1px 2px; } }
@keyframes pd-roll { to { rotate: 360deg; } }
@keyframes pd-jolt { 0% { translate: 0 0; } 25% { translate: 0 -7px; } 55% { translate: 0 1px; } 100% { translate: 0 0; } }
@keyframes pd-rise { 0%, 8% { translate: 0 0; } 16% { translate: 0 1.5px; } 46%, 70% { translate: 0 -11px; } 90% { translate: 0 .8px; } 100% { translate: 0 0; } }
@keyframes pd-rise-shadow { 0%, 8%, 100% { scale: 1; } 46%, 70% { scale: .6 1; } }
@keyframes pd-fall { 0%, 10% { translate: 0 0; rotate: 0deg; opacity: 1; } 34% { translate: 7px 26px; rotate: 24deg; } 58% { translate: -2px 52px; rotate: -14deg; } 82% { translate: 6px 78px; rotate: 18deg; opacity: 1; } 100% { translate: 3px 92px; rotate: 0deg; opacity: 0; } }
@keyframes un-sway { 0%, 100% { rotate: 0deg; } 40% { rotate: 3deg; } 75% { rotate: -2deg; } }
@keyframes un-flip { 0%, 55%, 100% { rotate: 0deg; } 60% { rotate: -3deg; } 68% { rotate: 20deg; } 78% { rotate: -6deg; } 88% { rotate: 2deg; } }
@keyframes un-toss { 0%, 20% { rotate: 0deg; } 30% { rotate: -4deg; } 42% { rotate: 24deg; } 56% { rotate: -8deg; } 68% { rotate: 3deg; } 80%, 100% { rotate: 0deg; } }
@keyframes un-toss-head { 0%, 100% { rotate: 0deg; translate: 0 0; } 15% { rotate: 3deg; translate: 0 .6px; } 38%, 70% { rotate: -6deg; translate: 0 -1.4px; } }
@keyframes un-glint { 0%, 70%, 100% { opacity: .85; scale: 1; } 80% { opacity: 1; scale: 1 1.25; } 85% { opacity: .2; } }
@keyframes un-twinkle { 0%, 100% { scale: 1; opacity: 1; } 50% { scale: .45; opacity: .5; } }
@keyframes un-stamp { 0%, 100% { rotate: 0deg; translate: 0 0; } 35% { rotate: -10deg; translate: 0 -3px; } 50% { rotate: 0deg; translate: 0 .8px; } 60% { translate: 0 0; } }
@keyframes un-prance { 0%, 100% { rotate: 0deg; translate: 0 0; } 50% { rotate: -14deg; translate: 0 -3px; } }
@keyframes fa-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -4px; } }
@keyframes fa-hem { 0%, 100% { transform: skewX(0deg) scaleY(1); } 25% { transform: skewX(5deg) scaleY(1.04); } 75% { transform: skewX(-5deg) scaleY(.97); } }
@keyframes fa-wisp { 0% { translate: 0 0; opacity: 0; } 25% { opacity: .55; } 100% { translate: 4px -12px; opacity: 0; } }
@keyframes fa-arm { 0%, 100% { rotate: 0deg; } 50% { rotate: calc(var(--s, 1) * 7deg); } }
@keyframes fa-fade { 0%, 100% { opacity: .9; } 50% { opacity: .64; } }
@keyframes fa-cheer { 0%, 100% { rotate: calc(var(--s, 1) * 20deg); } 50% { rotate: calc(var(--s, 1) * 34deg); } }
@keyframes fa-boo { 0%, 100% { scale: 1; translate: 0 0; } 15% { scale: 1.05 .93; translate: 0 1px; } 32%, 52% { scale: .94 1.14; translate: 0 -5px; } 64% { scale: 1.04 .94; translate: 0 1px; } 78% { scale: .98; translate: 0 1.5px; } }
@keyframes fa-boo-arm { 0%, 100% { rotate: 0deg; } 15% { rotate: calc(var(--s, 1) * -8deg); } 32%, 52% { rotate: calc(var(--s, 1) * 40deg); } 66% { rotate: calc(var(--s, 1) * -10deg); } 80% { rotate: calc(var(--s, 1) * -6deg); } }
@keyframes fa-sink { 0%, 100% { translate: 0 2px; } 50% { translate: 0 4px; } }
@keyframes fa-flicker { 0%, 100% { opacity: 1; } 20% { opacity: .2; } 30% { opacity: .9; } 40% { opacity: .3; } 60% { opacity: 1; } }
/* dragao: a snort is a quick pop and a slow fade, outward (--s) and up */
@keyframes dr-snort { 0%, 84%, 100% { opacity: 0; scale: .4; translate: 0 0; } 86% { opacity: 1; scale: .9; } 94% { opacity: .7; scale: 1.15; translate: calc(var(--s, 1) * 1.4px) -1.6px; } 99% { opacity: 0; scale: 1.25; translate: calc(var(--s, 1) * 2px) -2.6px; } }
@keyframes dr-wave { 0%, 40%, 100% { rotate: 0deg; } 8%, 24% { rotate: 11deg; } 16%, 32% { rotate: 3deg; } }
@keyframes dr-huff { 0% { scale: .75; opacity: 0; } 14% { scale: 1; opacity: 1; } 65% { opacity: 1; } 100% { scale: 1.12; translate: 0 -2px; opacity: 0; } }
@keyframes dr-admire { 0%, 55%, 100% { rotate: 0deg; } 64% { rotate: -5deg; } 74% { rotate: 1.5deg; } 82% { rotate: -1deg; } 88% { rotate: 0deg; } }
@keyframes dr-flicker { from { scale: 1; } to { scale: .86 1.16; } }
@keyframes dr-fume { 50% { scale: 1.05; } }
@keyframes dr-shake { 0%, 78%, 100% { rotate: 0deg; } 82% { rotate: calc(var(--s, 1) * -6deg); } 86% { rotate: calc(var(--s, 1) * 4deg); } 90% { rotate: calc(var(--s, 1) * -3deg); } 94% { rotate: calc(var(--s, 1) * 1deg); } }
@keyframes dr-fizzle { 0%, 100% { opacity: 1; translate: 0 0; } 50% { opacity: .5; translate: .6px 1.2px; } }
@keyframes dr-heart { 0% { scale: .8; translate: 0 2px; opacity: 0; } 18% { scale: 1; opacity: 1; } 70% { opacity: 1; } 100% { scale: 1.06; translate: 0 -5px; opacity: 0; } }
/* cough: the cheeks swell (anticipation), a jolt as it pops, then a guilty look left and right */
@keyframes dr-cough-head { 0%, 100% { scale: 1; translate: 0 0; rotate: 0deg; } 16% { scale: 1.05 .96; translate: 0 0; } 22% { scale: .97 1.04; translate: 0 -1.6px; } 30% { scale: 1; translate: 0 0; rotate: 0deg; } 44% { rotate: -3deg; } 66% { rotate: 3deg; } 84% { rotate: 0deg; } }
@keyframes dr-cough { 0%, 18% { opacity: 0; scale: .3; translate: 0 0; } 24% { opacity: 1; scale: 1.12; } 34% { opacity: 1; scale: 1; translate: 0 1px; } 62% { opacity: 0; scale: 1.3; translate: 0 -4px; } 100% { opacity: 0; scale: 1.3; } }
@keyframes dr-ring { 0% { opacity: 0; scale: .5; translate: 0 0; } 15% { opacity: 1; scale: 1; } 70% { opacity: .9; } 100% { opacity: 0; scale: 1.25; translate: -2px -4px; } }
@keyframes dr-follow { 0%, 100% { translate: 0 0; } 15%, 85% { translate: -1.6px -2px; } }
/* monstro: the glow breathes; fingers creep from the palm (inside the mirrored right hand the same angle already mirrors) */
@keyframes mo-glow { 0%, 100% { opacity: .65; scale: .9; } 50% { opacity: 1; scale: 1.12; } }
@keyframes mo-creep { 0%, 100% { rotate: 0deg; scale: 1; } 30% { rotate: -4deg; scale: 1 .9; } 55% { rotate: 3deg; scale: 1 1.03; } 78% { rotate: -1deg; scale: 1; } }
@keyframes mo-ripple { 0%, 100% { rotate: -6deg; } 50% { rotate: 6deg; } }
@keyframes mo-tap { 0%, 100% { rotate: 0deg; } 40% { rotate: -7deg; } 55% { rotate: 1deg; } }
@keyframes mo-flare { 0%, 68%, 100% { opacity: .8; scale: 1; } 76% { opacity: 1; scale: 1.35; } 84% { opacity: .7; scale: 1.05; } 91% { opacity: 1; scale: 1.25; } }
@keyframes mo-squeeze { 0%, 100% { rotate: 0deg; } 45% { rotate: calc(var(--s, 1) * -3deg); } 60% { rotate: calc(var(--s, 1) * -2deg); } }
@keyframes mo-rub { 0%, 100% { rotate: 0deg; } 25% { rotate: calc(var(--s, 1) * 5deg); } 50% { rotate: calc(var(--s, 1) * -2deg); } 75% { rotate: calc(var(--s, 1) * 4deg); } }
@keyframes mo-ears-up { 0% { rotate: calc(var(--s, 1) * -22deg); } 45% { rotate: calc(var(--s, 1) * 8deg); } 72% { rotate: calc(var(--s, 1) * -3deg); } 100% { rotate: 0deg; } }
@keyframes mo-slap { 0% { rotate: calc(var(--s, 1) * 12deg); } 50% { rotate: calc(var(--s, 1) * -3deg); } 100% { rotate: 0deg; } }
@keyframes mo-flop { 0%, 100% { rotate: 0deg; } 20% { rotate: calc(var(--s, 1) * -18deg); } 45% { rotate: calc(var(--s, 1) * 9deg); } 70% { rotate: calc(var(--s, 1) * -4deg); } }
/* peek: the mood arms swap out while the hands rise over the face (a quick cross-fade hidden by the rise) */
@keyframes mo-arms-off { 0%, 13% { opacity: 1; } 15.5%, 86% { opacity: 0; } 88.5%, 100% { opacity: 1; } }
@keyframes mo-peek-in { 0%, 12.5% { opacity: 0; translate: 0 12px; } 15.5% { opacity: 1; translate: 0 4px; } 24% { translate: 0 -1px; } 29%, 78% { opacity: 1; translate: 0 0; } 86% { opacity: 1; translate: 0 6px; } 88.5%, 100% { opacity: 0; translate: 0 12px; } }
@keyframes mo-peek-open { 0%, 34% { rotate: 0deg; } 44% { rotate: calc(var(--s, 1) * -24deg); } 48%, 62% { rotate: calc(var(--s, 1) * -21deg); } 70%, 100% { rotate: 0deg; } }
@keyframes mo-hide { 0%, 100% { translate: 0 0; scale: 1; } 20%, 80% { translate: 0 1.5px; scale: .97; } }
@keyframes mo-peek-eye { 0%, 40% { translate: 0 0; } 46%, 60% { translate: -1.2px .6px; } 68%, 100% { translate: 0 0; } }
/* think: the third eye opens with a little overshoot, looks left, right, and shuts */
@keyframes mo-eye3 { 0%, 10% { opacity: 0; scale: 1 0; } 14% { opacity: 1; } 22% { scale: 1 1.18; } 28%, 78% { opacity: 1; scale: 1 1; } 88% { opacity: 1; scale: 1 .05; } 92%, 100% { opacity: 0; scale: 1 0; } }
@keyframes mo-p3 { 0%, 30% { translate: 0 0; } 38%, 50% { translate: -1.3px 0; } 58%, 70% { translate: 1.3px -.2px; } 78%, 100% { translate: 0 0; } }
@keyframes m-fidget { 0%, 80%, 100% { rotate: 0deg; } 20% { rotate: calc(var(--fx, 1) * -3deg); } 45% { rotate: calc(var(--fx, 1) * 2.5deg); } 65% { rotate: calc(var(--fx, 1) * -1deg); } }
/* joints: keyframes of the layers. Idle and mood loops scale their swing by --on (a gesture fades them out), walk keys by --wa (the walk fades in and out) */
@keyframes j-osc { 0%, 100% { transform: rotate(calc(var(--a, 6deg) * var(--on, 1) * var(--ta, 1) * -1)); } 50% { transform: rotate(calc(var(--a, 6deg) * var(--on, 1) * var(--ta, 1))); } }
/* a tail swish: out, back past the middle, a small settle, then rest (a tail that never rests reads as a thing wiggling) */
@keyframes j-swish { 0%, 48%, 100% { transform: none; } 12% { transform: rotate(calc(var(--a, 6deg) * var(--on, 1) * var(--ta, 1))); } 28% { transform: rotate(calc(var(--a, 6deg) * -.7 * var(--on, 1) * var(--ta, 1))); }
  40% { transform: rotate(calc(var(--a, 6deg) * .25 * var(--on, 1) * var(--ta, 1))); } }
/* pumps and shakes come in bursts, never like a metronome: two swings in the first 40 % of the cycle, then the pose rests */
@keyframes j-burst { 0%, 40%, 100% { transform: none; } 7% { transform: rotate(calc(var(--a, 10deg) * var(--on, 1))); } 15% { transform: rotate(calc(var(--a, 10deg) * -.7 * var(--on, 1))); }
  24% { transform: rotate(calc(var(--a, 10deg) * var(--on, 1))); } 32% { transform: rotate(calc(var(--a, 10deg) * -.5 * var(--on, 1))); } }
/* two bursts at uneven places of one (prime) cycle: an angry shake, a nervous tap */
@keyframes j-burst2 { 0%, 14%, 52%, 63%, 100% { transform: none; } 3.5% { transform: rotate(calc(var(--a, 10deg) * var(--on, 1))); } 7% { transform: rotate(calc(var(--a, 10deg) * -1 * var(--on, 1))); }
  10.5% { transform: rotate(calc(var(--a, 10deg) * .6 * var(--on, 1))); } 55.5% { transform: rotate(calc(var(--a, 10deg) * var(--on, 1))); } 59% { transform: rotate(calc(var(--a, 10deg) * -.7 * var(--on, 1))); } }
/* a wave: three quick swings (.25 s each in a 5.3 s cycle) and a settle, then rest; +a should swing away from the face */
@keyframes j-wave { 0%, 28%, 100% { transform: none; } 4.7% { transform: rotate(calc(var(--a, 20deg) * var(--on, 1))); } 9.4% { transform: rotate(calc(var(--a, 20deg) * -.8 * var(--on, 1))); }
  14.1% { transform: rotate(calc(var(--a, 20deg) * var(--on, 1))); } 18.8% { transform: rotate(calc(var(--a, 20deg) * -.6 * var(--on, 1))); } 23.5% { transform: rotate(calc(var(--a, 20deg) * .25 * var(--on, 1))); } }
/* moving hold (11.3 s): the weight over one foot 0-46 % (drifting a little further), crossing in 8 %, over the other foot 54-92 %, crossing back.
   The hips shift (--sw) and the body leans (--sa) toward the foot that carries the weight */
@keyframes j-sway { 0%, 100% { transform: translate(calc(var(--sw, 1px) * var(--on, 1)), 0) rotate(calc(var(--sa, 2deg) * var(--on, 1))); }
  23% { transform: translate(calc(var(--sw, 1px) * 1.2 * var(--on, 1)), 0) rotate(calc(var(--sa, 2deg) * 1.2 * var(--on, 1))); } 46% { transform: translate(calc(var(--sw, 1px) * 1.1 * var(--on, 1)), 0) rotate(calc(var(--sa, 2deg) * 1.1 * var(--on, 1))); }
  54% { transform: translate(calc(var(--sw, 1px) * -1 * var(--on, 1)), 0) rotate(calc(var(--sa, 2deg) * -1 * var(--on, 1))); } 73% { transform: translate(calc(var(--sw, 1px) * -1.2 * var(--on, 1)), 0) rotate(calc(var(--sa, 2deg) * -1.2 * var(--on, 1))); }
  92% { transform: translate(calc(var(--sw, 1px) * -1.1 * var(--on, 1)), 0) rotate(calc(var(--sa, 2deg) * -1.1 * var(--on, 1))); } }
/* the chest breathes in: taller and a little wider from the hips (--sq 0 keeps a robot's plates rigid) */
@keyframes j-breathe { 50% { transform: scale(calc(1 + .012 * var(--sq, 1)), calc(1 + .02 * var(--sq, 1))); } }
/* walk: lean and shift over the support foot (left at 25 %, right at 75 %; sine-like: fast through 0, slow at the ends), and a bob twice a cycle
   (down just after each contact, up at mid-stance); the arms use the same lean, a beat later, as hanging pendulums */
@keyframes j-waddle { 0%, 50%, 100% { transform: none; animation-timing-function: ease-out; }
  25% { transform: translate(calc(var(--wx, 0px) * var(--wa)), 0) rotate(calc(var(--wr, 0deg) * var(--wa))); animation-timing-function: ease-in; }
  75% { transform: translate(calc(var(--wx, 0px) * -1 * var(--wa)), 0) rotate(calc(var(--wr, 0deg) * -1 * var(--wa))); animation-timing-function: ease-in; } }
@keyframes j-bob { 0%, 100% { transform: translate(0, calc(1px * var(--wa) * var(--bob, 1))); animation-timing-function: ease-out; } 12% { transform: translate(0, calc(1.5px * var(--wa) * var(--bob, 1))); animation-timing-function: ease-in-out; }
  56% { transform: translate(0, calc(-1px * var(--wa) * var(--bob, 1))); animation-timing-function: ease-in; } }
/* walk, left leg (keys made by app/test/walkgen.mjs from the puppet's leg; the right leg runs half a cycle later with --s: -1). Planted 0-56 %:
   the straight leg sweeps so the ankle slides at constant speed, the hip drops just enough to keep it at floor height and the foot turns back so
   its sole stays flat. Free 56-100 %: the hip hikes, the knee turns out and bends, toe down then up, and the foot lands flat. A mascot with other
   legs makes its own keys with the generator and names them in --step-th, --step-sh and --step-ft (a foot seen from the front always does: these
   keys bend the knee sideways); --lift (per mood, .45 .. 1) scales only the swing, so a sad walk shuffles low */
@keyframes j-step-th { 0% { transform: translate(0, calc((0.87 + -0.93 * var(--s, 1)) * var(--wa) * 1px)) rotate(calc((5 + -14.2 * var(--s, 1)) * var(--wa) * 1deg)); } 14% { transform: translate(0, calc((0.39 + -0.45 * var(--s, 1)) * var(--wa) * 1px)) rotate(calc((4.75 + -7.04 * var(--s, 1)) * var(--wa) * 1deg)); } 28% { transform: translate(0, calc(0.23 * var(--wa) * 1px)) rotate(calc(4.67 * var(--wa) * 1deg)); } 42% { transform: translate(0, calc((0.39 + 0.45 * var(--s, 1)) * var(--wa) * 1px)) rotate(calc((4.75 + 7.04 * var(--s, 1)) * var(--wa) * 1deg)); } 56% { transform: translate(0, calc((0.87 + 0.93 * var(--s, 1)) * var(--wa) * 1px)) rotate(calc((5 + 14.2 * var(--s, 1)) * var(--wa) * 1deg)); } 63% { transform: translate(0, calc(-3 * var(--lift, 1) * var(--wa) * 1px)) rotate(calc((5 + 12.76 * var(--s, 1) + 4 * var(--lift, 1)) * var(--wa) * 1deg)); } 70% { transform: translate(0, calc(-5.5 * var(--lift, 1) * var(--wa) * 1px)) rotate(calc((5 + 8.45 * var(--s, 1) + 8 * var(--lift, 1)) * var(--wa) * 1deg)); } 78% { transform: translate(0, calc(-6.5 * var(--lift, 1) * var(--wa) * 1px)) rotate(calc((5 + 9 * var(--lift, 1)) * var(--wa) * 1deg)); } 85% { transform: translate(0, calc(-5.5 * var(--lift, 1) * var(--wa) * 1px)) rotate(calc((5 + -7.6 * var(--s, 1) + 7 * var(--lift, 1)) * var(--wa) * 1deg)); } 92% { transform: translate(0, calc(-2.5 * var(--lift, 1) * var(--wa) * 1px)) rotate(calc((5 + -12.32 * var(--s, 1) + 3 * var(--lift, 1)) * var(--wa) * 1deg)); } 100% { transform: translate(0, calc((0.87 + -0.93 * var(--s, 1)) * var(--wa) * 1px)) rotate(calc((5 + -14.2 * var(--s, 1)) * var(--wa) * 1deg)); } }
@keyframes j-step-sh { 0% { transform: none; } 56% { transform: none; } 63% { transform: rotate(calc(-12 * var(--lift, 1) * var(--wa) * 1deg)); } 70% { transform: rotate(calc(-20 * var(--lift, 1) * var(--wa) * 1deg)); } 78% { transform: rotate(calc(-22 * var(--lift, 1) * var(--wa) * 1deg)); } 85% { transform: rotate(calc(-17 * var(--lift, 1) * var(--wa) * 1deg)); } 92% { transform: rotate(calc(-8 * var(--lift, 1) * var(--wa) * 1deg)); } 100% { transform: none; } }
@keyframes j-step-ft { 0% { transform: rotate(calc((-5 + 14.2 * var(--s, 1)) * var(--wa) * 1deg)); } 14% { transform: rotate(calc((-4.75 + 7.04 * var(--s, 1)) * var(--wa) * 1deg)); } 28% { transform: rotate(calc(-4.67 * var(--wa) * 1deg)); } 42% { transform: rotate(calc((-4.75 + -7.04 * var(--s, 1)) * var(--wa) * 1deg)); } 56% { transform: rotate(calc((-5 + -14.2 * var(--s, 1)) * var(--wa) * 1deg)); } 63% { transform: rotate(calc((-5 + -12.76 * var(--s, 1) + -2 * var(--lift, 1)) * var(--wa) * 1deg)); } 70% { transform: rotate(calc((-5 + -8.45 * var(--s, 1) + -2 * var(--lift, 1)) * var(--wa) * 1deg)); } 78% { transform: rotate(calc((-5 + 5 * var(--lift, 1)) * var(--wa) * 1deg)); } 85% { transform: rotate(calc((-5 + 7.6 * var(--s, 1) + 12 * var(--lift, 1)) * var(--wa) * 1deg)); } 92% { transform: rotate(calc((-5 + 12.32 * var(--s, 1) + 11 * var(--lift, 1)) * var(--wa) * 1deg)); } 100% { transform: rotate(calc((-5 + 14.2 * var(--s, 1)) * var(--wa) * 1deg)); } }
/* think: the eyes dart up in .1 s and hold; a blink covers the head turn; the knuckles knock under the chin three times */
@keyframes j-think-eye { 0%, 100% { translate: 0 0; } 4%, 85% { translate: 1.6px -2.2px; } }
@keyframes j-think-blink { 0%, 6%, 13%, 100% { transform: scaleY(1); } 9% { transform: scaleY(.1); } }
@keyframes j-knock { 0%, 36%, 72%, 100% { transform: none; } 40%, 52%, 64% { transform: translate(0, 1.6px); } 46%, 58% { transform: translate(0, -.4px); } }
/* stretch: the reach trembles once at its peak; the eyes squeeze shut and the mouth stretches open while the body is tall */
@keyframes j-strain { 0%, 34%, 52%, 100% { transform: none; } 38% { transform: rotate(1.6deg); } 42% { transform: rotate(-1.2deg); } 46% { transform: rotate(1deg); } 49% { transform: rotate(-.4deg); } }
@keyframes j-squeeze { 0%, 16%, 74%, 100% { transform: none; } 24%, 64% { transform: scaleY(.12); } }
@keyframes j-yawn { 0%, 18%, 72%, 100% { transform: none; } 30%, 58% { transform: scale(.85, 1.6); } }
/* crouch, landing, jump (--cq: hip 1, knee -2, ankle 1 keeps a planted foot in place while the knee goes out): the upper body drops and widens,
   the knees take the weight; a jump crouches (0-22 %), pushes (22-32 %: the legs straighten, the torso rises, a profile foot toes off), flies a
   parabola under gravity (off the floor at 32 %, --jh high at 53 %, down at 75 %) and takes the landing after the contact (knees and torso deepest at 83 %).
   Every squash of the torso is scaled by --sq (a robot sets 0) */
@keyframes j-land-torso { 0%, 100% { transform: none; } 18% { transform: translate(0, calc(3px * var(--li, 1))) scale(calc(1 + .06 * var(--sq, 1) * var(--li, 1)), calc(1 - .06 * var(--sq, 1) * var(--li, 1))); } 50% { transform: translate(0, -.6px) scale(calc(1 - .02 * var(--sq, 1)), calc(1 + .02 * var(--sq, 1))); } 74% { transform: translate(0, .3px); } }
@keyframes j-land-leg { 0%, 100% { transform: none; } 18% { transform: rotate(calc(var(--cq, 1) * 12deg)); } 50% { transform: rotate(calc(var(--cq, 1) * -1deg)); } }
/* off the floor at 32 %, the top at 53 %, down at 75 %: the two halves of a parabola (exact quadratics), so it falls like the buddy's own falls */
@keyframes j-jump { 0%, 32% { transform: none; animation-timing-function: cubic-bezier(.33, .67, .67, 1); } 53% { transform: translate(0, var(--jh, -12px)); animation-timing-function: cubic-bezier(.33, 0, .67, .33); } 75%, 100% { transform: none; } }
@keyframes j-hop-torso { 0%, 75%, 100% { transform: none; } 22% { transform: translate(0, 3px) scale(calc(1 + .06 * var(--sq, 1)), calc(1 - .06 * var(--sq, 1))); animation-timing-function: cubic-bezier(.6, 0, .85, .5); } 32% { transform: translate(0, -1px) scale(calc(1 - .03 * var(--sq, 1)), calc(1 + .05 * var(--sq, 1))); } 53% { transform: scale(calc(1 - .02 * var(--sq, 1)), calc(1 + .03 * var(--sq, 1))); } 83% { transform: translate(0, 2.6px) scale(calc(1 + .06 * var(--sq, 1)), calc(1 - .06 * var(--sq, 1))); } 93% { transform: translate(0, -.4px) scale(calc(1 - .01 * var(--sq, 1)), calc(1 + .01 * var(--sq, 1))); } }
/* the knees take the crouch and, after the contact, the landing (none while walking: the step already bends them); a profile foot toes off at
   the push (--tp) and points in the air; the legs are straight from the push to the contact */
@keyframes j-hop-leg { 0%, 70%, 75%, 95%, 100% { transform: none; } 22% { transform: rotate(calc(var(--cq, 1) * 11deg * (1 - var(--wa, 0)))); animation-timing-function: cubic-bezier(.6, 0, .85, .5); } 83% { transform: rotate(calc(var(--cq, 1) * 11deg * (1 - var(--wa, 0)))); } 32% { transform: rotate(calc(var(--tp, 0deg) * (1 - var(--wa, 0)))); } 53% { transform: rotate(calc(var(--tp, 0deg) * .5 * (1 - var(--wa, 0)))); } }
/* the arms gather in while the knees crouch, before the fling, and droop a little when the knees take the landing */
@keyframes j-gather { 0%, 22%, 75%, 100% { transform: none; } 10% { transform: rotate(-6deg); } 85% { transform: rotate(-5deg); } 94% { transform: rotate(2deg); } }
/* follow-through on impact: the head drops into the shoulders and back, the arms and the wings droop and come back a beat after the hips stop
   (-: down and in, for a left-drawn limb); before a leap the arms gather in */
@keyframes j-nod { 0%, 100% { transform: none; } 25% { transform: translate(0, 1.5px); } 55% { transform: translate(0, -.4px); } }
@keyframes j-flop { 0%, 100% { transform: none; } 30% { transform: rotate(-6deg); } 60% { transform: rotate(2deg); } }
@keyframes j-arms-pre { to { transform: rotate(-6deg); } }
/* held up: the legs swing like pendulums a few times and hang still (--s: both swing the same way on screen) */
@keyframes j-dangle { 0%, 100% { transform: none; } 12% { transform: rotate(calc(var(--s, 1) * 7deg)); } 30% { transform: rotate(calc(var(--s, 1) * -5deg)); } 50% { transform: rotate(calc(var(--s, 1) * 3deg)); } 70% { transform: rotate(calc(var(--s, 1) * -1.5deg)); } 86% { transform: rotate(calc(var(--s, 1) * .5deg)); } }
/* a new face: the torso squashes quickly and springs back (it grows from none: buddy.js carries the old drawing's motion over, so nothing
   needs hiding); falling asleep takes a breath in and sinks */
@keyframes j-swap { 0%, 100% { transform: none; } 30% { transform: scale(calc(1 + .05 * var(--sq, 1)), calc(1 - .07 * var(--sq, 1))); } 65% { transform: scale(calc(1 - .015 * var(--sq, 1)), calc(1 + .02 * var(--sq, 1))); } }
@keyframes j-sink { 0%, 100% { transform: none; } 30% { transform: translate(0, -1px) scale(1, calc(1 + .03 * var(--sq, 1))); } }
/* the default fidget of a jointed mascot: a shrug-and-rock of the upper body on the hips */
@keyframes j-fidget { 0%, 80%, 100% { transform: none; } 20% { transform: rotate(calc(var(--fx, 1) * -3deg)); } 45% { transform: rotate(calc(var(--fx, 1) * 2.5deg)); } 65% { transform: rotate(calc(var(--fx, 1) * -1deg)); } }
/* Google sign-in: white button with the G, the same in every theme */
.btn.google { gap: 10px; background: #fff; color: #1f1f1f; border: 1px solid #dadce0; text-decoration: none; }
.or { display: flex; align-items: center; gap: 12px; color: var(--ink-2); font-size: 14px; margin: -8px 0; }
.or::before, .or::after { content: ''; flex: 1; height: 1px; background: currentColor; opacity: .3; }

