/* Edu, Eduport's study buddy (assets/mascot.js): layers, moods, reactions, idle
   actions, the thought cloud, speech bubbles and particles. Flying lives in
   assets/journey.css.

   Everything is driven by classes, data attributes and CSS custom properties that
   mascot.js writes through CSSOM, so the page's Content-Security-Policy (no style=""
   markup) is respected.

   Layers, outside in:
     .mascot   the element the page places (never transformed)
     .m-clip   the crop: the ledge for a peek, a circle for an avatar
     .m-stage  the entrance (rise)            .m-dip   scrollPeek (duck and pop)
     .m-act    one-shot reactions and idle actions, hover tilt
     .m-mood   the state: breathing, thinking, curious, happy, wave
   Long loops only move these HTML layers, which the compositor animates without
   repainting the felt filter. Parts inside the SVG (eyes, arms, mouth, seedling)
   move only for short events. */

/* --- frame ------------------------------------------------------------------------ */
.mascot {
  --gaze-x: 3px; --gaze-y: 1.6px; --lift: -11px; --tilt: 7deg; --lean: 2deg;
  --think-x: 72%; --think-y: 86%; --td: 4.5px; --tg: 3.5px; --tp: 5px 8px;
  position: relative; display: inline-block; width: 100%; line-height: 0;
  -webkit-tap-highlight-color: transparent; -webkit-user-select: none; user-select: none;
}
.mascot.is-interactive { cursor: pointer; touch-action: manipulation; }
.mascot .m-clip, .mascot .m-stage, .mascot .m-dip, .mascot .m-act, .mascot .m-mood {
  display: block; transform-origin: 50% 100%;
}
.mascot svg { display: block; width: 100%; height: auto; overflow: visible; }
.mascot--peek { --lift: 0px; --tilt: 3.5deg; --lean: 1.4deg; }
.mascot--sit { --think-x: 74%; --think-y: 94%; }
.mascot--head {
  --gaze-x: 2.2px; --gaze-y: 1.2px; --lift: -5px; --tilt: 8deg;
  --think-x: 78%; --think-y: 86%; --td: 3px; --tg: 2px; --tp: 3px 5px;
}
/* A peek hides below its ledge (the bottom edge) but may wave, cheer or pop above it. */
.mascot--peek .m-clip { clip-path: inset(-90% -45% 0 -45%); }
/* An avatar is cropped round; the face moves inside the crop. */
.mascot--head .m-clip { clip-path: circle(50% at 50% 50%); background: var(--surface-2); }
.mascot--head .m-act, .mascot--head .m-mood { transform-origin: 50% 78%; }

/* --- the rig (see art/mascot/README.md) ---------------------------------------------- */
.mascot .m-body, .mascot .m-accessory { transform-box: fill-box; transform-origin: 50% 100%; }
.mascot .m-hand-l, .mascot .m-hand-r, .mascot .m-shadow, .mascot .m-eyes, .mascot .m-lid,
.mascot .m-eye, .mascot .m-mouth, .mascot .m-mouth-o, .mascot .m-prop {
  transform-box: fill-box; transform-origin: 50% 50%;
}
.mascot .m-mouth-open { transform-box: fill-box; transform-origin: 50% 0; }
.mascot .m-mouth-o { transform-origin: 50% 25%; }

.mascot .m-gaze {
  transform: translate(calc(var(--gx, 0) * var(--gaze-x)), calc(var(--gy, 0) * var(--gaze-y)));
  transition: transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.mascot .m-lid { transition: transform 0.12s cubic-bezier(0.3, 0, 0.2, 1), opacity 0.1s ease; }
.mascot.is-blinking .m-lid { transform: scaleY(0.08); transition-duration: 0.06s, 0.1s; }
.mascot .m-eye { transition: transform 0.22s cubic-bezier(0.3, 1.4, 0.5, 1), opacity 0.1s ease; }
.mascot .m-joy, .mascot .m-joy-l, .mascot .m-joy-r, .mascot .m-blush, .mascot .m-mouth-o { opacity: 0; transition: opacity 0.12s ease; }
.mascot .m-joy-l, .mascot .m-joy-r { opacity: 1; }
.mascot .m-mouth { transition: transform 0.25s cubic-bezier(0.3, 1.4, 0.5, 1), opacity 0.08s ease; }
.mascot .m-mouth-o { transition: opacity 0.08s ease, transform 0.45s cubic-bezier(0.3, 1.3, 0.5, 1); }
.mascot .m-accessory { transition: transform 0.5s cubic-bezier(0.3, 1.5, 0.5, 1); }
.mascot .m-act { transition: transform 0.5s cubic-bezier(0.3, 1.3, 0.5, 1); }
.mascot .m-mood { transition: transform 0.45s cubic-bezier(0.3, 1.5, 0.5, 1); }
.mascot .m-glow { transition: opacity 0.6s ease; }
.mascot .m-hand-l, .mascot .m-hand-r { transition: transform 0.45s cubic-bezier(0.3, 1.3, 0.5, 1); }

/* --- expressions (classes set by reactions, idle actions and moods) --------------------- */
/* closed "happy" eyes: the beads hide, two little arcs show */
.mascot.x-joy .m-lid, .mascot[data-state="happy"] .m-lid { opacity: 0; }
.mascot.x-joy .m-joy, .mascot[data-state="happy"] .m-joy { opacity: 1; }
.mascot.x-wink .m-joy { opacity: 1; }
.mascot.x-wink .m-joy-l { opacity: 0; }
.mascot.x-wink .m-eye-r { opacity: 0; }
/* open smile (talking, cheering, laughing) */
.mascot.x-open .m-mouth, .mascot[data-state="happy"] .m-mouth, .mascot.is-talking .m-mouth { opacity: 0; }
.mascot.x-open .m-mouth-open, .mascot[data-state="happy"] .m-mouth-open, .mascot.is-talking .m-mouth-open { display: inline; }
.mascot.x-giggle .m-mouth-open { animation: m-giggle 0.15s ease-in-out infinite alternate; }
.mascot.is-talking .m-mouth-open { animation: m-talk 0.18s ease-in-out infinite alternate; }
@keyframes m-giggle { from { transform: scaleY(0.62); } to { transform: scaleY(1); } }
@keyframes m-talk { from { transform: scale(0.92, 0.5); } to { transform: scale(1, 1); } }
/* a small "o" and a big yawn */
.mascot.x-o .m-mouth, .mascot.x-yawn .m-mouth, .mascot.x-o .m-mouth-open, .mascot.x-yawn .m-mouth-open { opacity: 0; }
.mascot.x-o .m-mouth-o, .mascot.x-yawn .m-mouth-o { opacity: 1; }
.mascot.x-yawn .m-mouth-o { transform: scale(1.45, 2.15); }
.mascot.x-frown .m-mouth { transform: scaleY(-1); }
/* eyes */
.mascot.x-wide .m-eye { transform: scale(1.18); }
.mascot.x-wide-sm .m-eye, .mascot[data-state="curious"] .m-eye { transform: scale(1.08); }
.mascot.x-squint .m-eye { transform: scale(1.06, 0.2); }
.mascot.x-sleepy .m-eye, .mascot[data-state="sleepy"] .m-eye { transform: scaleY(0.36); }
.mascot.x-droop .m-eye { transform: scaleY(0.8); }
.mascot.x-content .m-eye { transform: scaleY(0.7); }
.mascot.x-blush .m-blush { opacity: 0.85; }
/* leaning while it glances around */
.mascot.x-lean-l .m-act { transform: rotate(calc(var(--lean) * -1)); }
.mascot.x-lean-r .m-act { transform: rotate(var(--lean)); }

/* --- moods (data-state) ------------------------------------------------------------- */
/* idle: a slow breath on the outer layer; paws and feet stay planted */
.mascot--peek[data-state="idle"] .m-mood, .mascot--sit[data-state="idle"] .m-mood {
  animation: m-breathe 3.6s ease-in-out infinite alternate;
}
@keyframes m-breathe { from { transform: scale(1.006, 0.994); } to { transform: scale(0.994, 1.012); } }

/* curious: stands a little taller and alert while you type */
.mascot[data-state="curious"] .m-mood { transform: scale(0.985, 1.045); }
.mascot--head[data-state="curious"] .m-mood { transform: translateY(-3%) scale(1.03); }
.mascot[data-state="curious"] .m-accessory { transform: rotate(-4deg) scaleY(1.06); }
.mascot.is-typing .m-accessory { animation: m-type 0.36s ease-in-out infinite alternate; }
@keyframes m-type { from { transform: rotate(-6deg) scaleY(1.04); } to { transform: rotate(5deg) scaleY(1.07); } }

/* thinking: rocks gently, glows warm inside and shows a thought cloud */
.mascot[data-state="thinking"] .m-mood { animation: m-ponder 2.8s ease-in-out infinite; }
.mascot--head[data-state="thinking"] .m-mood { animation-name: m-ponder-head; }
@keyframes m-ponder { 0%, 100% { transform: skewX(2.4deg); } 50% { transform: skewX(-2.4deg) scale(1, 1.012); } }
@keyframes m-ponder-head { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(4deg) translateY(-2%); } }
.mascot[data-state="thinking"] .m-glow { animation: m-glow 1.4s steps(6) infinite alternate; } /* few steps: few repaints of the felt */
@keyframes m-glow { from { opacity: 0.4; } to { opacity: 1; } }
.mascot--sit[data-hands*="r"][data-state="thinking"] .m-hand-r { transform: rotate(-112deg); }
.mascot--sit[data-hands="l"][data-state="thinking"] .m-hand-l { transform: rotate(112deg); }

/* happy: a hop (a stretch when peeking, so it never leaves its ledge) */
.mascot--sit[data-state="happy"] .m-mood, .mascot--head[data-state="happy"] .m-mood { animation: m-hop-act 0.8s both; }
.mascot--sit[data-state="happy"] .m-body, .mascot--head[data-state="happy"] .m-body { animation: m-lift 0.8s both; }
.mascot--sit[data-state="happy"] .m-shadow { animation: m-shadow-1 0.8s both; }
.mascot--peek[data-state="happy"] .m-mood { animation: m-pop-stretch 0.75s both; }
.mascot[data-state="happy"] .m-accessory { animation: m-settle 0.8s 0.1s both; }

/* wave: the free hand says hello (-130deg points it straight up in every pose) */
.mascot[data-wave="r"][data-state="wave"] .m-hand-r, .mascot[data-wave="r"].act-wave .m-hand-r {
  animation: m-wave-r 1.3s cubic-bezier(0.45, 0, 0.35, 1) both;
}
.mascot[data-wave="l"][data-state="wave"] .m-hand-l, .mascot[data-wave="l"].act-wave .m-hand-l {
  animation: m-wave-l 1.3s cubic-bezier(0.45, 0, 0.35, 1) both;
}
.mascot[data-state="wave"] .m-mood { animation: m-wave-lean 1.3s ease-in-out both; }
.mascot[data-wave="l"][data-state="wave"] .m-mood { animation-name: m-wave-lean-l; }
.mascot[data-wave=""][data-state="wave"] .m-mood { animation: m-love 1.3s ease-in-out both; }
.mascot[data-state="wave"] .m-mouth, .mascot.act-wave .m-mouth { opacity: 0; }
.mascot[data-state="wave"] .m-mouth-open, .mascot.act-wave .m-mouth-open { display: inline; }
.mascot[data-state="wave"] .m-accessory { animation: m-settle 1.1s 0.2s both; }
@keyframes m-wave-r {
  0% { transform: rotate(0deg); }
  9% { transform: rotate(9deg); }
  27% { transform: rotate(-138deg); }
  39% { transform: rotate(-118deg); }
  51% { transform: rotate(-140deg); }
  63% { transform: rotate(-119deg); }
  75% { transform: rotate(-133deg); }
  91% { transform: rotate(5deg); }
  100% { transform: rotate(0deg); }
}
@keyframes m-wave-l {
  0% { transform: rotate(0deg); }
  9% { transform: rotate(-9deg); }
  27% { transform: rotate(138deg); }
  39% { transform: rotate(118deg); }
  51% { transform: rotate(140deg); }
  63% { transform: rotate(119deg); }
  75% { transform: rotate(133deg); }
  91% { transform: rotate(-5deg); }
  100% { transform: rotate(0deg); }
}
@keyframes m-wave-lean { 0%, 100% { transform: none; } 22%, 76% { transform: rotate(1.6deg) scale(0.99, 1.02); } }
@keyframes m-wave-lean-l { 0%, 100% { transform: none; } 22%, 76% { transform: rotate(-1.6deg) scale(0.99, 1.02); } }

/* --- shared motion ------------------------------------------------------------------ */
@keyframes m-lift {
  0%, 16% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  48% { transform: translateY(var(--lift)); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  72%, 100% { transform: translateY(0); }
}
@keyframes m-hop-act {
  0% { transform: none; animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1); }
  16% { transform: scale(1.07, 0.92); animation-timing-function: cubic-bezier(0.2, 0.6, 0.4, 1); }
  34% { transform: scale(0.94, 1.08); }
  50% { transform: none; animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  72% { transform: scale(1.06, 0.93); animation-timing-function: cubic-bezier(0.2, 0.6, 0.4, 1); }
  86% { transform: scale(0.985, 1.015); }
  100% { transform: none; }
}
@keyframes m-shadow-1 { 0%, 16%, 72%, 100% { transform: none; opacity: 1; } 48% { transform: scale(0.8); opacity: 0.6; } }
@keyframes m-pop-stretch {
  0% { transform: none; animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1); }
  18% { transform: scale(1.05, 0.94); animation-timing-function: cubic-bezier(0.2, 0.6, 0.4, 1); }
  42% { transform: scale(0.95, 1.08); }
  62% { transform: scale(1.03, 0.97); }
  80% { transform: scale(0.99, 1.01); }
  100% { transform: none; }
}
/* the seedling's springy settle (0 → 10 → -7 → 4 → -1.5 → 0) */
@keyframes m-settle {
  0% { transform: none; }
  14% { transform: rotate(10deg); }
  32% { transform: rotate(-7deg); }
  50% { transform: rotate(4deg); }
  68% { transform: rotate(-1.5deg); }
  84% { transform: rotate(0.5deg); }
  100% { transform: none; }
}
@keyframes m-boing {
  0% { transform: none; }
  10% { transform: scale(1, 0.86); }
  24% { transform: rotate(-12deg) scale(1, 1.14); }
  40% { transform: rotate(9deg); }
  56% { transform: rotate(-6deg); }
  72% { transform: rotate(3deg); }
  86% { transform: rotate(-1deg); }
  100% { transform: none; }
}

/* --- reactions (react) -------------------------------------------------------------- */
/* tap: squash on the press, a rebound stretch and a wobble; a giggle or a wink */
.mascot.act-tap .m-act { animation: m-tap 0.78s both; }
.mascot.act-tap .m-accessory { animation: m-boing 0.95s both; }
/* twirl (react("twirl")): the sprout spins like a little rotor about its stem, twice, then settles */
.mascot.x-twirl .m-accessory { animation: m-twirl 0.68s cubic-bezier(0.35, 0.6, 0.35, 1) both; }
@keyframes m-twirl {
  0% { transform: none; }
  22% { transform: scaleX(-1) scaleY(1.08); }
  44% { transform: scaleX(1) scaleY(1.04); }
  66% { transform: scaleX(-1) scaleY(1.06); }
  86% { transform: scaleX(1) rotate(-6deg); }
  100% { transform: none; }
}
@keyframes m-tap {
  0% { transform: none; animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1); }
  13% { transform: scale(1.15, 0.84); animation-timing-function: cubic-bezier(0.2, 0.6, 0.4, 1); }
  32% { transform: scale(0.93, 1.09); animation-timing-function: ease-in-out; }
  48% { transform: scale(1.04, 0.96) rotate(-2.5deg); }
  64% { transform: scale(0.985, 1.02) rotate(2deg); }
  80% { transform: rotate(-0.8deg); }
  100% { transform: none; }
}

/* love: a happy little sway with blushing cheeks (hearts come from mascot.js) */
.mascot.act-love .m-act { animation: m-love 1.85s ease-in-out both; }
.mascot.act-love .m-accessory { animation: m-settle 1.2s 0.1s both; }
@keyframes m-love {
  0% { transform: none; }
  14% { transform: scale(1.05, 0.95) rotate(-3deg); }
  34% { transform: scale(1.02, 1.01) rotate(3.5deg); }
  54% { transform: rotate(-2.5deg); }
  72% { transform: rotate(1.5deg); }
  88% { transform: rotate(-0.5deg); }
  100% { transform: none; }
}

/* surprise: a quick crouch, then a jump with wide eyes, a little "o" and flared arms */
.mascot.act-surprise .m-act { animation: m-surprise 1.15s both; }
.mascot--sit.act-surprise .m-body, .mascot--head.act-surprise .m-body { animation: m-lift-early 1.15s both; }
.mascot--sit.act-surprise .m-shadow { animation: m-shadow-early 1.15s both; }
.mascot.act-surprise .m-accessory { animation: m-boing 1.15s both; }
.mascot[data-hands*="r"].act-surprise .m-hand-r { animation: m-flare-r 1.15s both; }
.mascot[data-hands*="l"].act-surprise .m-hand-l { animation: m-flare-l 1.15s both; }
@keyframes m-surprise {
  0% { transform: none; animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1); }
  9% { transform: scale(1.07, 0.9); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  24% { transform: scale(0.93, 1.12); animation-timing-function: ease-in-out; }
  40% { transform: scale(1.03, 0.97); }
  56% { transform: scale(0.99, 1.01); }
  100% { transform: none; }
}
@keyframes m-lift-early {
  0%, 9% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  24% { transform: translateY(var(--lift)); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  40%, 100% { transform: translateY(0); }
}
@keyframes m-shadow-early { 0%, 9%, 40%, 100% { transform: none; opacity: 1; } 24% { transform: scale(0.8); opacity: 0.6; } }
@keyframes m-flare-r { 0%, 100% { transform: none; } 9% { transform: rotate(8deg); } 24% { transform: rotate(-44deg); } 62% { transform: rotate(-36deg); } }
@keyframes m-flare-l { 0%, 100% { transform: none; } 9% { transform: rotate(-8deg); } 24% { transform: rotate(44deg); } 62% { transform: rotate(36deg); } }

/* sad: slumps, the seedling droops, a frown and a sweat drop; then shakes it off */
.mascot.act-sad .m-act { animation: m-sag 1.95s ease-in-out both; }
.mascot.act-sad .m-accessory { animation: m-droop 1.95s both; }
.mascot[data-hands*="r"].act-sad .m-hand-r { animation: m-droop-r 1.95s ease-in-out both; }
.mascot[data-hands*="l"].act-sad .m-hand-l { animation: m-droop-l 1.95s ease-in-out both; }
@keyframes m-sag {
  0% { transform: none; }
  28%, 78% { transform: translateY(1%) scale(1.035, 0.935); }
  90% { transform: scale(0.99, 1.015); }
  100% { transform: none; }
}
@keyframes m-droop {
  0% { transform: none; animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1); }
  26% { transform: rotate(30deg); animation-timing-function: ease-in-out; }
  34% { transform: rotate(26deg); }
  76% { transform: rotate(24deg); animation-timing-function: cubic-bezier(0.3, 0, 0.3, 1); }
  88% { transform: rotate(-7deg); }
  96% { transform: rotate(2deg); }
  100% { transform: none; }
}
@keyframes m-droop-r { 0%, 100% { transform: none; } 28%, 78% { transform: rotate(14deg); } }
@keyframes m-droop-l { 0%, 100% { transform: none; } 28%, 78% { transform: rotate(-14deg); } }

/* cheer: both arms up, two happy bounces and confetti */
.mascot.act-cheer .m-act { animation: m-cheer 1.65s both; }
.mascot--sit.act-cheer .m-body, .mascot--head.act-cheer .m-body { animation: m-lift-2 1.65s both; }
.mascot--sit.act-cheer .m-shadow { animation: m-shadow-2 1.65s both; }
.mascot.act-cheer .m-accessory { animation: m-boing 1.3s 0.1s both; }
.mascot[data-hands*="r"].act-cheer .m-hand-r { animation: m-cheer-r 1.65s ease-in-out both; }
.mascot[data-hands*="l"].act-cheer .m-hand-l { animation: m-cheer-l 1.65s ease-in-out both; }
@keyframes m-cheer {
  0% { transform: none; animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1); }
  8% { transform: scale(1.07, 0.92); animation-timing-function: cubic-bezier(0.2, 0.6, 0.4, 1); }
  20% { transform: scale(0.95, 1.07); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  32% { transform: scale(1.05, 0.95); animation-timing-function: cubic-bezier(0.2, 0.6, 0.4, 1); }
  44% { transform: scale(0.97, 1.05); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  56% { transform: scale(1.04, 0.96); animation-timing-function: ease-out; }
  70% { transform: scale(0.99, 1.01); }
  100% { transform: none; }
}
@keyframes m-lift-2 {
  0%, 8% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  20% { transform: translateY(var(--lift)); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  32% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  44% { transform: translateY(calc(var(--lift) * 0.75)); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  56%, 100% { transform: translateY(0); }
}
@keyframes m-shadow-2 {
  0%, 8%, 32%, 56%, 100% { transform: none; opacity: 1; }
  20% { transform: scale(0.8); opacity: 0.6; }
  44% { transform: scale(0.85); opacity: 0.7; }
}
@keyframes m-cheer-r {
  0%, 100% { transform: none; }
  7% { transform: rotate(10deg); }
  19% { transform: rotate(-142deg); }
  31% { transform: rotate(-120deg); }
  43% { transform: rotate(-142deg); }
  55% { transform: rotate(-122deg); }
  69% { transform: rotate(-136deg); }
  83% { transform: rotate(-132deg); }
  94% { transform: rotate(6deg); }
}
@keyframes m-cheer-l {
  0%, 100% { transform: none; }
  7% { transform: rotate(-10deg); }
  19% { transform: rotate(142deg); }
  31% { transform: rotate(120deg); }
  43% { transform: rotate(142deg); }
  55% { transform: rotate(122deg); }
  69% { transform: rotate(136deg); }
  83% { transform: rotate(132deg); }
  94% { transform: rotate(-6deg); }
}

/* nod: "got it", twice */
.mascot.act-nod .m-act { animation: m-nod 0.95s ease-in-out both; }
.mascot.act-nod .m-accessory { animation: m-settle 1s 0.15s both; }
@keyframes m-nod {
  0% { transform: none; }
  22% { transform: scale(1.015, 0.95); }
  42% { transform: none; }
  62% { transform: scale(1.01, 0.96); }
  80% { transform: scale(0.995, 1.01); }
  100% { transform: none; }
}

/* spot: eyes on something (a "Remember this" card), a twinkle, then a knowing nod */
.mascot.act-spot .m-act { animation: m-nod 0.95s 0.38s ease-in-out both; }
.mascot.act-spot .m-accessory { animation: m-settle 1s 0.4s both; }

/* look-up: leans back to look at its seedling (or the sky) */
.mascot.act-look-up .m-act { animation: m-look-up 1.5s ease-in-out both; }
.mascot.act-look-up .m-accessory { animation: m-settle 1.1s 0.1s both; }
@keyframes m-look-up { 0%, 100% { transform: none; } 22%, 78% { transform: scale(0.985, 1.035); } 92% { transform: scale(1.01, 0.99); } }

/* lights-on: squints at the brightness, then opens its eyes with a smile */
.mascot.act-lights-on .m-act { animation: m-lights-on 2.05s both; }
.mascot--sit.act-lights-on .m-body, .mascot--head.act-lights-on .m-body { animation: m-lift-late 2.05s both; }
.mascot.act-lights-on .m-accessory { animation: m-settle 1.1s 0.95s both; }
.mascot[data-hands*="r"].act-lights-on .m-hand-r { animation: m-shield-r 2.05s ease-in-out both; }
.mascot[data-hands*="l"].act-lights-on .m-hand-l { animation: m-shield-l 2.05s ease-in-out both; }
@keyframes m-lights-on {
  0% { transform: none; animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  6% { transform: scale(1.07, 0.91); }
  14%, 38% { transform: scale(1.04, 0.95) rotate(-2deg); animation-timing-function: cubic-bezier(0.3, 0, 0.5, 1); }
  47% { transform: scale(0.95, 1.08); }
  58% { transform: scale(1.03, 0.97); }
  70% { transform: scale(0.99, 1.01); }
  80%, 100% { transform: none; }
}
@keyframes m-lift-late {
  0%, 39% { transform: translateY(0); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
  48% { transform: translateY(calc(var(--lift) * 0.8)); animation-timing-function: cubic-bezier(0.6, 0, 0.8, 0.4); }
  57%, 100% { transform: translateY(0); }
}
@keyframes m-shield-r { 0%, 52%, 100% { transform: none; } 8%, 38% { transform: rotate(-36deg); } }
@keyframes m-shield-l { 0%, 52%, 100% { transform: none; } 8%, 38% { transform: rotate(36deg); } }

/* lights-off: looks around in the dark, then a tiny yawn and a stretch */
.mascot.act-lights-off .m-act { animation: m-lights-off 2.35s ease-in-out both; }
.mascot[data-hands*="r"].act-lights-off .m-hand-r { animation: m-stretch-r 2.35s ease-in-out both; }
.mascot[data-hands*="l"].act-lights-off .m-hand-l { animation: m-stretch-l 2.35s ease-in-out both; }
.mascot.act-lights-off .m-accessory { animation: m-settle 1.1s 1.25s both; }
@keyframes m-lights-off {
  0% { transform: none; }
  10%, 30% { transform: rotate(calc(var(--lean) * -1)); }
  40%, 54% { transform: rotate(var(--lean)); }
  62% { transform: none; }
  72% { transform: scale(0.975, 1.05); }
  84% { transform: scale(0.97, 1.06); }
  92% { transform: scale(1.02, 0.985); }
  100% { transform: none; }
}
@keyframes m-stretch-r { 0%, 60%, 100% { transform: none; } 72% { transform: rotate(-64deg); } 84% { transform: rotate(-72deg); } 94% { transform: rotate(4deg); } }
@keyframes m-stretch-l { 0%, 60%, 100% { transform: none; } 72% { transform: rotate(64deg); } 84% { transform: rotate(72deg); } 94% { transform: rotate(-4deg); } }

/* --- idle actions (autoplay) ---------------------------------------------------------- */
.mascot.act-sprout .m-accessory { animation: m-pluck 1.15s both; }
@keyframes m-pluck {
  0% { transform: none; }
  8% { transform: scale(1, 0.88); }
  20% { transform: rotate(12deg) scale(1, 1.06); }
  36% { transform: rotate(-8deg); }
  52% { transform: rotate(5deg); }
  68% { transform: rotate(-2deg); }
  84% { transform: rotate(0.6deg); }
  100% { transform: none; }
}
.mascot--sit.act-hop .m-act, .mascot--head.act-hop .m-act { animation: m-hop-act 0.9s both; }
.mascot--sit.act-hop .m-body, .mascot--head.act-hop .m-body { animation: m-lift 0.9s both; }
.mascot--sit.act-hop .m-shadow { animation: m-shadow-1 0.9s both; }
.mascot--peek.act-hop .m-act { animation: m-peek-hop 0.9s both; }
.mascot.act-hop .m-accessory { animation: m-settle 1.1s 0.35s both; }
@keyframes m-peek-hop {
  0% { transform: none; animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1); }
  18% { transform: translateY(5%) scale(1.05, 0.95); animation-timing-function: cubic-bezier(0.2, 0.7, 0.3, 1); }
  44% { transform: scale(0.95, 1.08); }
  62% { transform: scale(1.03, 0.97); }
  78% { transform: scale(0.99, 1.01); }
  100% { transform: none; }
}
.mascot.act-tilt .m-act { animation: m-tilt-l 1.9s both; }
.mascot.act-tilt.x-tilt-r .m-act { animation-name: m-tilt-r; }
.mascot.act-tilt .m-accessory { animation: m-settle 1.1s 1.2s both; }
@keyframes m-tilt-l {
  0% { transform: none; animation-timing-function: cubic-bezier(0.4, 0, 0.3, 1); }
  20%, 68% { transform: rotate(calc(var(--tilt) * -1)); animation-timing-function: cubic-bezier(0.5, 0, 0.3, 1); }
  84% { transform: rotate(calc(var(--tilt) * 0.22)); }
  94% { transform: rotate(calc(var(--tilt) * -0.07)); }
  100% { transform: none; }
}
@keyframes m-tilt-r {
  0% { transform: none; animation-timing-function: cubic-bezier(0.4, 0, 0.3, 1); }
  20%, 68% { transform: rotate(var(--tilt)); animation-timing-function: cubic-bezier(0.5, 0, 0.3, 1); }
  84% { transform: rotate(calc(var(--tilt) * -0.22)); }
  94% { transform: rotate(calc(var(--tilt) * 0.07)); }
  100% { transform: none; }
}
.mascot.act-yawn .m-act { animation: m-yawn 2.2s ease-in-out both; }
.mascot[data-hands*="r"].act-yawn .m-hand-r { animation: m-yawn-r 2.2s ease-in-out both; }
.mascot[data-hands*="l"].act-yawn .m-hand-l { animation: m-yawn-l 2.2s ease-in-out both; }
@keyframes m-yawn { 0%, 10%, 100% { transform: none; } 30% { transform: scale(0.975, 1.05); } 66% { transform: scale(0.97, 1.06); } 80% { transform: scale(1.025, 0.975); } 90% { transform: scale(0.995, 1.005); } }
@keyframes m-yawn-r { 0%, 12%, 100% { transform: none; } 32% { transform: rotate(-60deg); } 64% { transform: rotate(-70deg); } 80% { transform: rotate(4deg); } }
@keyframes m-yawn-l { 0%, 12%, 100% { transform: none; } 32% { transform: rotate(60deg); } 64% { transform: rotate(70deg); } 80% { transform: rotate(-4deg); } }
.mascot.act-askbox .m-act { animation: m-ask 1.7s ease-in-out both; }
@keyframes m-ask { 0%, 48%, 74%, 100% { transform: none; } 60% { transform: scale(1.01, 0.965); } }
/* the feature-card poses: reading the book, searching with the glass, eyeing the pencil */
.mascot.act-read .m-act { animation: m-read 2.1s ease-in-out both; }
@keyframes m-read { 0%, 100% { transform: none; } 30% { transform: rotate(-1.5deg) scale(1.01, 0.985); } 64% { transform: rotate(1.5deg) scale(1.01, 0.985); } }
.mascot.act-search .m-hand-r { animation: m-search 1.8s ease-in-out both; }
.mascot.act-search .m-act { animation: m-lean-r 1.8s ease-in-out both; }
@keyframes m-search { 0%, 100% { transform: none; } 18%, 50% { transform: rotate(-6deg); } 34%, 66% { transform: rotate(6deg); } 82% { transform: rotate(-2deg); } }
@keyframes m-lean-r { 0%, 100% { transform: none; } 20%, 80% { transform: rotate(1.6deg); } }
.mascot.act-jot .m-act { animation: m-nod 0.95s 0.85s ease-in-out both; }
.mascot.act-jot .m-accessory { animation: m-settle 1.1s 0.3s both; }
.mascot.act-wave .m-act { animation: m-wave-lean 1.45s ease-in-out both; }
.mascot[data-wave="l"].act-wave .m-act { animation-name: m-wave-lean-l; }
.mascot.act-wave .m-accessory { animation: m-settle 1.1s 0.25s both; }

/* hover (a mouse, never touch): a curious tilt */
.mascot.is-hover .m-act { transform: rotate(calc(var(--tilt) * -0.55)); }
.mascot.is-hover .m-accessory { transform: rotate(-8deg) scaleY(1.05); }
.mascot.is-hover .m-eye { transform: scale(1.06); }

/* --- entrance and scrollPeek (peek) ---------------------------------------------------- */
/* rises from behind its ledge: the seedling pokes up, the eyes peek over and glance
   left and right, then a springy pop */
.mascot--peek.is-entering .m-stage { animation: m-rise 1.5s 1.4s both; }
.mascot--peek.is-entering .m-gaze { animation: m-rise-look 1.5s 1.4s both; }
@keyframes m-rise {
  0% { transform: translateY(104%); animation-timing-function: cubic-bezier(0.2, 0.7, 0.3, 1); }
  12%, 22% { transform: translateY(74%); animation-timing-function: cubic-bezier(0.4, 0, 0.3, 1); }
  32%, 60% { transform: translateY(21%); animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); }
  76% { transform: translateY(0) scale(0.95, 1.07); animation-timing-function: ease-in-out; }
  88% { transform: scale(1.03, 0.97); }
  100% { transform: none; }
}
@keyframes m-rise-look {
  0%, 32% { transform: translate(0, -1px); }
  38%, 45% { transform: translate(-3px, -0.6px); }
  51%, 58% { transform: translate(3px, -0.6px); }
  66%, 100% { transform: none; }
}
.mascot.is-dipped .m-dip { transform: translateY(104%); }
.mascot.is-ducking .m-dip { animation: m-duck 0.42s both; }
.mascot.is-popping .m-dip { animation: m-pop 0.75s both; }
.mascot.is-popping .m-accessory { animation: m-settle 1.1s 0.3s both; }
@keyframes m-duck {
  0% { transform: none; animation-timing-function: cubic-bezier(0.3, 0, 0.5, 1); }
  22% { transform: scale(1.05, 0.94); animation-timing-function: cubic-bezier(0.55, 0, 0.8, 0.3); }
  100% { transform: translateY(104%); }
}
@keyframes m-pop {
  0% { transform: translateY(104%); animation-timing-function: cubic-bezier(0.2, 0.75, 0.35, 1); }
  52% { transform: translateY(0) scale(0.95, 1.08); animation-timing-function: ease-in-out; }
  70% { transform: scale(1.03, 0.96); }
  86% { transform: scale(0.99, 1.01); }
  100% { transform: none; }
}

/* --- thought cloud (state "thinking") ------------------------------------------------- */
.m-think {
  position: absolute; z-index: 1; left: var(--think-x); bottom: var(--think-y); line-height: 0;
  pointer-events: none; transform-origin: 0% 100%;
  animation: m-think-in 0.45s cubic-bezier(0.3, 1.5, 0.5, 1) both;
}
.m-think.is-out { animation: m-think-out 0.2s ease-in both; }
.m-think-cloud {
  position: relative; display: flex; align-items: center; gap: var(--tg); padding: var(--tp); border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line); box-shadow: var(--shadow-1);
}
.m-think-cloud i { display: block; width: var(--td); height: var(--td); border-radius: 50%; background: var(--muted); animation: m-dot 1.2s ease-in-out infinite; }
.m-think-cloud i:nth-child(2) { animation-delay: 0.16s; }
.m-think-cloud i:nth-child(3) { animation-delay: 0.32s; }
.m-think::before, .m-think::after {
  content: ""; position: absolute; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--line);
}
.m-think::before { left: calc(var(--td) * -0.1); bottom: calc(var(--td) * -1.1); width: calc(var(--td) * 1.4); height: calc(var(--td) * 1.4); }
.m-think::after { left: calc(var(--td) * -1); bottom: calc(var(--td) * -2.1); width: calc(var(--td) * 0.9); height: calc(var(--td) * 0.9); }
.mascot--head .m-think::after { display: none; }
@keyframes m-think-in { from { opacity: 0; transform: translate(-30%, 30%) scale(0.3); } to { opacity: 1; transform: none; } }
@keyframes m-think-out { to { opacity: 0; transform: translate(-20%, 20%) scale(0.5); } }
@keyframes m-dot { 0%, 64%, 100% { transform: none; opacity: 0.45; } 30% { transform: translateY(-40%); opacity: 1; } }

/* --- overlay: speech bubbles and particles ---------------------------------------------- */
/* One fixed layer for every mascot, so cards with overflow: hidden never clip them. */
.m-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 60; pointer-events: none; overflow: hidden; contain: strict; }
/* the page-wide layer is there only while a bubble or sparkle is, and never while a class (a YouTube
   player) is on screen: nothing of ours is stacked over the player (classplayer.js .cv-live) */
.m-overlay:empty, .cv-live .m-overlay { display: none; }
.m-anchor { --m-top: 4%; position: absolute; left: 0; top: 0; contain: layout style; }
.m-anchor--sit { --m-top: 6%; }
.m-anchor--head { --m-top: 0%; }
.m-anchor.is-hidden { visibility: hidden; }
.m-anchor.is-hidden * { animation-play-state: paused; }

.m-bubble {
  --tail: 50%;
  position: absolute; left: 0; bottom: calc(100% - var(--m-top) + 12px);
  width: max-content; max-width: min(248px, calc(100vw - 24px));
  padding: 8px 13px 9px; border-radius: 16px;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--heading); box-shadow: var(--shadow-1);
  font: 500 13.5px/1.38 var(--font-sans, system-ui, sans-serif); letter-spacing: -0.003em;
  text-align: left; white-space: normal; overflow-wrap: break-word;
  transform-origin: var(--tail) 100%;
  animation: m-bubble-in 0.48s cubic-bezier(0.3, 1.45, 0.55, 1) both;
}
.m-bubble::after {
  content: ""; position: absolute; left: var(--tail); bottom: -6px; width: 11px; height: 11px; margin-left: -5.5px;
  background: inherit; border: inherit; border-top: 0; border-left: 0; border-radius: 0 0 3px 0; transform: rotate(45deg);
}
.m-bubble.is-below { bottom: auto; top: calc(100% + 12px); transform-origin: var(--tail) 0%; }
.m-bubble.is-below::after { bottom: auto; top: -6px; border: inherit; border-right: 0; border-bottom: 0; border-radius: 3px 0 0 0; }
/* beside the mascot (say(text, { place: "left" | "right" })): mascot.js sets top, and --tail is
   the height of the face, where the tail points */
.m-bubble.is-left, .m-bubble.is-right { bottom: auto; transform-origin: 100% var(--tail); }
.m-bubble.is-right { transform-origin: 0% var(--tail); }
.m-bubble.is-left::after, .m-bubble.is-right::after { left: auto; bottom: auto; top: var(--tail); margin: -5.5px 0 0; border: inherit; }
.m-bubble.is-left::after { right: -6px; border-left: 0; border-bottom: 0; border-radius: 0 3px 0 0; }
.m-bubble.is-right::after { left: -6px; border-top: 0; border-right: 0; border-radius: 0 0 0 3px; }
.m-bubble.is-out { animation: m-bubble-out 0.2s ease-in both; }
@keyframes m-bubble-in { from { opacity: 0; transform: translateY(6px) scale(0.55); } 55% { opacity: 1; } to { opacity: 1; transform: none; } }
@keyframes m-bubble-out { to { opacity: 0; transform: translateY(-4px) scale(0.92); } }

.m-fx {
  position: absolute; left: var(--ox); top: var(--oy); width: var(--size); height: var(--size);
  margin: calc(var(--size) / -2) 0 0 calc(var(--size) / -2); line-height: 0; opacity: 0;
  animation: m-spark var(--t) cubic-bezier(0.15, 0.7, 0.3, 1) var(--d) both;
}
.m-fx svg { display: block; width: 100%; height: 100%; }
.m-c0 { color: var(--brand); }
.m-c1 { color: #f5a524; }
.m-c2 { color: #6faa52; }
.m-c3 { color: #ff7a5e; }
.m-fx-spark, .m-fx-twinkle { background: currentColor; clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%); }
.m-fx-twinkle { animation-name: m-twinkle; }
.m-fx-heart { color: #ff6b7a; animation: m-heart var(--t) cubic-bezier(0.3, 0.5, 0.4, 1) var(--d) both; }
.m-fx-heart.m-c0 { color: var(--brand); }
.m-fx-confetti { height: calc(var(--size) * 0.55); border-radius: 1.5px; background: currentColor; animation: m-confetti var(--t) linear var(--d) both; }
.m-fx-drop { color: #7cc4ff; animation: m-drop var(--t) ease-in var(--d) both; }
.m-fx-bang { color: var(--brand); animation: m-bang var(--t) cubic-bezier(0.3, 1.6, 0.5, 1) var(--d) both; }
@keyframes m-spark {
  0% { opacity: 0; transform: scale(0.2); }
  12% { opacity: 1; }
  38% { opacity: 1; transform: translate(calc(var(--dx) * 0.7), calc(var(--dy) * 0.7)) scale(var(--s)) rotate(calc(var(--r) * 0.5)); }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.1) rotate(var(--r)); }
}
@keyframes m-twinkle {
  0% { opacity: 0; transform: scale(0.1); }
  30% { opacity: 1; transform: translate(calc(var(--dx) * 0.6), calc(var(--dy) * 0.6)) scale(var(--s)); }
  55% { opacity: 0.55; transform: translate(calc(var(--dx) * 0.8), calc(var(--dy) * 0.8)) scale(calc(var(--s) * 0.6)); }
  70% { opacity: 1; transform: translate(calc(var(--dx) * 0.9), calc(var(--dy) * 0.9)) scale(var(--s)) rotate(45deg); }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.2) rotate(90deg); }
}
@keyframes m-heart {
  0% { opacity: 0; transform: scale(0.3); }
  16% { opacity: 1; transform: translate(calc(var(--dx) * 0.15), calc(var(--dy) * 0.18)) scale(var(--s)); }
  45% { transform: translate(calc(var(--dx) * -0.6), calc(var(--dy) * 0.5)) scale(var(--s)) rotate(calc(var(--r) * -1)); }
  72% { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(calc(var(--s) * 0.8)) rotate(var(--r)); }
}
@keyframes m-confetti {
  0% { opacity: 0; transform: none; animation-timing-function: cubic-bezier(0.1, 0.6, 0.3, 1); }
  8% { opacity: 1; }
  34% { transform: translate(var(--dx), var(--dy)) rotate(var(--r)); animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.6); }
  80% { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(var(--dx) * 1.35), calc(var(--dy) + var(--fall))) rotate(calc(var(--r) * 3)); }
}
@keyframes m-drop {
  0% { opacity: 0; transform: translateY(-30%) scale(0.4); }
  18% { opacity: 1; transform: none; }
  70% { opacity: 1; }
  100% { opacity: 0; transform: translateY(var(--dy)) scale(0.85, 1.05); }
}
@keyframes m-bang {
  0% { opacity: 0; transform: translateY(30%) scale(0.2) rotate(-12deg); }
  22% { opacity: 1; transform: none; }
  70% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(-25%) scale(0.9); }
}

/* the light theme: white bubbles and clouds */
:root[data-theme="light"] .m-bubble, :root[data-theme="light"] .m-think-cloud,
:root[data-theme="light"] .m-think::before, :root[data-theme="light"] .m-think::after { background: var(--sunken); }

/* offscreen or hidden mascots rest */
.mascot.is-offscreen *, .mascot.is-offscreen .m-think-cloud i { animation-play-state: paused; }
/* watching a class with the visitor (assets/journey.js chatLife): settled, no idle motion */
.mascot.is-watching *, .mascot.is-watching *::before, .mascot.is-watching *::after { animation-play-state: paused !important; }

/* --- reduced motion: no loops, no particles, no travel; faces still change ------------ */
@media (prefers-reduced-motion: reduce) {
  .mascot *, .mascot *::before, .mascot *::after, .m-overlay * {
    animation: none !important; transition: none !important;
  }
  .mascot.is-dipped .m-dip { transform: none; }
  .m-fx { display: none; }
}

/* point: a paw raised toward what it spots (react("spot")) */
.mascot--sit[data-hands*="r"].x-point .m-hand-r { transform: rotate(-104deg); }
.mascot--sit[data-hands="l"].x-point .m-hand-l { transform: rotate(104deg); }
