/* Theo, as layered parts. Every layer shares one 400x400 canvas, so they
   stack with inset: 0 and turn about fixed points given in % (so it all
   scales with --theo-size).

   Each arm is one closed piece with its shoulder tucked inside the body.
   It turns about that shoulder for every pose; nothing swaps. Angles are
   for the right arm (positive = clockwise = in towards the body, negative =
   out and up); the left arm mirrors them. Every arm move starts from
   --from, the angle the arm was at when the move began. */

.theo-widget {
  position: relative;
  display: inline-block;
  width: var(--theo-size, 84px);
  height: var(--theo-size, 84px);
}
.theo-widget.theo-clickable { cursor: pointer; outline: none; }
.theo-widget.theo-clickable:focus-visible .theo-body {
  filter: drop-shadow(0 0 2px var(--brand, #4F4DD9));
}

.theo-motion, .theo-lean, .theo-sway, .theo-breathe,
.theo-part, .theo-confetti {
  position: absolute; inset: 0;
}
.theo-part { width: 100%; height: 100%; object-fit: contain; user-select: none; }
.theo-motion, .theo-lean, .theo-sway, .theo-breathe { transform-origin: 50% 92%; }

/* Shoulder pivots, from packaging/theo/build_rig.py. */
.theo-arm-r { transform-origin: 74% 52.5%; }
.theo-arm-l { transform-origin: 25.75% 52.5%; }

/* ---- idle: always running, never pretends to be an emotion ---------- */

.theo-breathe { animation: theo-breathe 3.6s ease-in-out infinite; }
.theo-sway    { animation: theo-sway 6.5s ease-in-out infinite alternate; }
.theo-arm-r   { animation: theo-swing-r 3.6s ease-in-out infinite; }
.theo-arm-l   { animation: theo-swing-l 3.6s ease-in-out infinite; }
@keyframes theo-breathe {
  0%, 100% { transform: scale(1, 1); }
  50%      { transform: scale(0.995, 1.018); }
}
@keyframes theo-sway {
  from { transform: rotate(-1deg); }
  to   { transform: rotate(1deg); }
}
@keyframes theo-swing-r { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(-4deg); } }
@keyframes theo-swing-l { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(4deg); } }

.theo-eyelid {
  position: absolute;
  background: #E4E2FF;
  border-radius: 3px;
  transform: scaleY(0);
  transform-origin: center;
  transition: transform 0.05s linear;
  pointer-events: none;
}
.theo-blinking .theo-eyelid { transform: scaleY(1); }

/* The screen switches face like a display would. */
.theo-face-happy { opacity: 0; transition: opacity 70ms linear; }
.theo-happy .theo-face-happy { opacity: 1; }

/* ---- wave: up, wave the hand twice, back down -------------------------- */

.theo-waving .theo-arm-r { animation: theo-wave-r 2.4s both; }
.theo-waving .theo-arm-l { animation: none; }
.theo-waving .theo-lean  { animation: theo-lean 2.4s ease-in-out both; }

@keyframes theo-wave-r {
  0%   { transform: rotate(var(--from, 0deg)); animation-timing-function: ease-in-out; }
  6%   { transform: rotate(6deg); animation-timing-function: cubic-bezier(.25, .7, .35, 1); }
  25%  { transform: rotate(-133deg); animation-timing-function: ease-in-out; }
  31%  { transform: rotate(-124deg); animation-timing-function: ease-in-out; }
  41%  { transform: rotate(-106deg); animation-timing-function: ease-in-out; }
  51%  { transform: rotate(-130deg); animation-timing-function: ease-in-out; }
  61%  { transform: rotate(-106deg); animation-timing-function: ease-in-out; }
  71%  { transform: rotate(-124deg); animation-timing-function: cubic-bezier(.45, 0, .35, 1); }
  93%  { transform: rotate(4deg); animation-timing-function: ease-in-out; }
  100% { transform: rotate(0); }
}
@keyframes theo-lean {
  0%, 100% { transform: rotate(0); }
  18%, 76% { transform: rotate(1.6deg); }
}

/* ---- cheer: arms follow the hop, then stay up ------------------------
   Down into the crouch, flung up as he springs, a dip as he lands, then
   settled up for as long as the reaction lasts. */

.theo-cheer .theo-arm-r       { animation: theo-cheer-r 0.9s both; }
.theo-cheer .theo-arm-l       { animation: theo-cheer-l 0.9s 30ms both; }
.theo-cheer-twice .theo-arm-r { animation: theo-cheer-twice-r 1.62s both; }
.theo-cheer-twice .theo-arm-l { animation: theo-cheer-twice-l 1.62s 30ms both; }

@keyframes theo-cheer-r {
  0%   { transform: rotate(var(--from, 0deg)); animation-timing-function: ease-in; }
  14%  { transform: rotate(10deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  42%  { transform: rotate(-134deg); animation-timing-function: ease-in-out; }
  56%  { transform: rotate(-124deg); animation-timing-function: ease-in; }
  76%  { transform: rotate(-108deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(-122deg); }
}
@keyframes theo-cheer-l {
  0%   { transform: rotate(var(--from, 0deg)); animation-timing-function: ease-in; }
  14%  { transform: rotate(-10deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  42%  { transform: rotate(134deg); animation-timing-function: ease-in-out; }
  56%  { transform: rotate(124deg); animation-timing-function: ease-in; }
  76%  { transform: rotate(108deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(122deg); }
}
@keyframes theo-cheer-twice-r {
  0%   { transform: rotate(var(--from, 0deg)); animation-timing-function: ease-in; }
  8%   { transform: rotate(10deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  24%  { transform: rotate(-136deg); animation-timing-function: ease-in-out; }
  31%  { transform: rotate(-124deg); animation-timing-function: ease-in; }
  41%  { transform: rotate(-106deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  57%  { transform: rotate(-138deg); animation-timing-function: ease-in; }
  74%  { transform: rotate(-110deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(-122deg); }
}
@keyframes theo-cheer-twice-l {
  0%   { transform: rotate(var(--from, 0deg)); animation-timing-function: ease-in; }
  8%   { transform: rotate(-10deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  24%  { transform: rotate(136deg); animation-timing-function: ease-in-out; }
  31%  { transform: rotate(124deg); animation-timing-function: ease-in; }
  41%  { transform: rotate(106deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  57%  { transform: rotate(138deg); animation-timing-function: ease-in; }
  74%  { transform: rotate(110deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(122deg); }
}

/* An arm that was already up (a tap mid-wave) dips instead of dropping. */
.theo-cheer .theo-arm-r[data-up]       { animation-name: theo-cheer-up-r; }
.theo-cheer .theo-arm-l[data-up]       { animation-name: theo-cheer-up-l; }
.theo-cheer-twice .theo-arm-r[data-up] { animation-name: theo-cheer-twice-up-r; }
.theo-cheer-twice .theo-arm-l[data-up] { animation-name: theo-cheer-twice-up-l; }

@keyframes theo-cheer-up-r {
  0%   { transform: rotate(var(--from, -122deg)); animation-timing-function: ease-in-out; }
  14%  { transform: rotate(-98deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  42%  { transform: rotate(-134deg); animation-timing-function: ease-in-out; }
  56%  { transform: rotate(-124deg); animation-timing-function: ease-in; }
  76%  { transform: rotate(-108deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(-122deg); }
}
@keyframes theo-cheer-up-l {
  0%   { transform: rotate(var(--from, 122deg)); animation-timing-function: ease-in-out; }
  14%  { transform: rotate(98deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  42%  { transform: rotate(134deg); animation-timing-function: ease-in-out; }
  56%  { transform: rotate(124deg); animation-timing-function: ease-in; }
  76%  { transform: rotate(108deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(122deg); }
}
@keyframes theo-cheer-twice-up-r {
  0%   { transform: rotate(var(--from, -122deg)); animation-timing-function: ease-in-out; }
  8%   { transform: rotate(-98deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  24%  { transform: rotate(-136deg); animation-timing-function: ease-in-out; }
  31%  { transform: rotate(-124deg); animation-timing-function: ease-in; }
  41%  { transform: rotate(-106deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  57%  { transform: rotate(-138deg); animation-timing-function: ease-in; }
  74%  { transform: rotate(-110deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(-122deg); }
}
@keyframes theo-cheer-twice-up-l {
  0%   { transform: rotate(var(--from, 122deg)); animation-timing-function: ease-in-out; }
  8%   { transform: rotate(98deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  24%  { transform: rotate(136deg); animation-timing-function: ease-in-out; }
  31%  { transform: rotate(124deg); animation-timing-function: ease-in; }
  41%  { transform: rotate(106deg); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  57%  { transform: rotate(138deg); animation-timing-function: ease-in; }
  74%  { transform: rotate(110deg); animation-timing-function: cubic-bezier(.3, .7, .4, 1); }
  100% { transform: rotate(122deg); }
}

/* ---- arms back down, from wherever they are --------------------------- */

.theo-arms-down .theo-arm-r { animation: theo-lower-r 0.65s both; }
.theo-arms-down .theo-arm-l { animation: theo-lower-l 0.65s 40ms both; }
@keyframes theo-lower-r {
  0%   { transform: rotate(var(--from, -122deg)); animation-timing-function: cubic-bezier(.45, 0, .35, 1); }
  82%  { transform: rotate(5deg); animation-timing-function: ease-in-out; }
  100% { transform: rotate(0); }
}
@keyframes theo-lower-l {
  0%   { transform: rotate(var(--from, 122deg)); animation-timing-function: cubic-bezier(.45, 0, .35, 1); }
  82%  { transform: rotate(-5deg); animation-timing-function: ease-in-out; }
  100% { transform: rotate(0); }
}

/* ---- eyes: follow the pointer, glide rather than jump ----------------- */

.theo-eyes {
  position: absolute; inset: 0;
  transition: transform 0.22s cubic-bezier(.2, .7, .3, 1);
}

/* ---- perk: a little "oh, hi" when you point at him -------------------- */

.theo-perk .theo-motion { animation: theo-perk 0.45s both; }
@keyframes theo-perk {
  0%   { transform: translateY(0) scale(1, 1); animation-timing-function: cubic-bezier(.2, .7, .3, 1); }
  38%  { transform: translateY(calc(var(--theo-size, 84px) * -0.04)) scale(1.02, 1.04); animation-timing-function: ease-in-out; }
  72%  { transform: translateY(0) scale(1.02, .98); animation-timing-function: ease-out; }
  100% { transform: translateY(0) scale(1, 1); }
}

/* ---- speech bubble ---------------------------------------------------- */

.theo-say {
  position: absolute; left: 74%; bottom: 86%; z-index: 2;
  width: max-content; max-width: min(230px, 62vw);
  padding: 7px 12px;
  background: var(--card, #fff);
  color: var(--ink, #17181F);
  border: 2px solid var(--ink, #17181F);
  border-radius: 14px 14px 14px 4px;
  box-shadow: 0 6px 18px rgba(23, 24, 31, .12);
  font-family: inherit; font-size: 13.5px; font-weight: 600; line-height: 1.3;
  text-align: left;
  pointer-events: none;
  opacity: 0;
  transform: translateY(6px) scale(.6);
  transform-origin: 0 100%;
  transition: opacity .16s ease, transform .38s cubic-bezier(.2, 1.35, .4, 1);
}
.theo-saying .theo-say { opacity: 1; transform: none; }
.theo-bubble-left .theo-say {
  left: auto; right: 74%;
  border-radius: 14px 14px 4px 14px;
  transform-origin: 100% 100%;
}

/* When the usual side would run off the screen. */
.theo-widget.theo-bubble-flip .theo-say {
  left: auto; right: 74%;
  border-radius: 14px 14px 4px 14px;
  transform-origin: 100% 100%;
}
.theo-bubble-left.theo-bubble-flip .theo-say {
  right: auto; left: 74%;
  border-radius: 14px 14px 14px 4px;
  transform-origin: 0 100%;
}
.theo-widget.theo-bubble-top .theo-say {
  left: 50%; right: auto; bottom: 104%;
  max-width: min(260px, calc(100vw - 32px));
  width: max-content;
  border-radius: 14px;
  transform: translate(-50%, 6px) scale(.6);
  transform-origin: 50% 100%;
}
.theo-widget.theo-bubble-top.theo-saying .theo-say { transform: translate(-50%, 0); }

/* ---- hop: crouch, spring up, land, settle ---------------------------- */

.theo-hopping .theo-motion       { animation: theo-hop 0.9s both; }
.theo-hopping-twice .theo-motion { animation: theo-hop-twice 1.62s both; }

@keyframes theo-hop {
  0%   { transform: translateY(0) scale(1, 1); animation-timing-function: cubic-bezier(.3, 0, .5, 1); }
  14%  { transform: translateY(0) scale(1.06, .92); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  46%  { transform: translateY(calc(var(--theo-size, 84px) * -0.16)) scale(.98, 1.03); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  74%  { transform: translateY(0) scale(1.05, .93); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  88%  { transform: translateY(0) scale(.99, 1.01); animation-timing-function: ease-in-out; }
  100% { transform: translateY(0) scale(1, 1); }
}
@keyframes theo-hop-twice {
  0%   { transform: translateY(0) scale(1, 1); animation-timing-function: cubic-bezier(.3, 0, .5, 1); }
  8%   { transform: translateY(0) scale(1.06, .92); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  25%  { transform: translateY(calc(var(--theo-size, 84px) * -0.18)) scale(.98, 1.03); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  41%  { transform: translateY(0) scale(1.05, .93); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  58%  { transform: translateY(calc(var(--theo-size, 84px) * -0.11)) scale(.99, 1.02); animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  74%  { transform: translateY(0) scale(1.04, .95); animation-timing-function: cubic-bezier(.2, .7, .4, 1); }
  88%  { transform: translateY(0) scale(.99, 1.01); animation-timing-function: ease-in-out; }
  100% { transform: translateY(0) scale(1, 1); }
}

/* ---- confetti, for a download ----------------------------------------- */

.theo-confetti { pointer-events: none; overflow: visible; }
.theo-confetti i {
  position: absolute; left: 47%; top: 38%;
  width: 7%; height: 3.5%;
  border-radius: 1px;
  opacity: 0;
  background: #4F4DD9;
}
.theo-confetti i[data-hue="1"] { background: #F5B83D; }
.theo-confetti i[data-hue="2"] { background: #EC6A9C; }
.theo-confetti i[data-hue="3"] { background: #3CC4B4; }
.theo-bursting .theo-confetti i { animation: theo-confetti 1.1s both; }
@keyframes theo-confetti {
  0%   { transform: translate(0, 0) rotate(0) scale(.6); opacity: 1;
         animation-timing-function: cubic-bezier(.15, .7, .3, 1); }
  60%  { transform: translate(calc(var(--dx) * var(--theo-size, 84px)), calc(var(--dy) * var(--theo-size, 84px)))
                    rotate(calc(var(--spin) * .7)) scale(1); opacity: 1;
         animation-timing-function: cubic-bezier(.5, 0, .8, .4); }
  100% { transform: translate(calc(var(--dx) * var(--theo-size, 84px)), calc((var(--dy) + .28) * var(--theo-size, 84px)))
                    rotate(var(--spin)) scale(1); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .theo-breathe, .theo-sway, .theo-arm-r, .theo-arm-l,
  .theo-waving .theo-arm-r, .theo-waving .theo-lean,
  .theo-hopping .theo-motion, .theo-hopping-twice .theo-motion,
  .theo-bursting .theo-confetti i,
  .theo-perk .theo-motion { animation: none; }
  .theo-say { transition: opacity .16s ease; transform: none; }
  .theo-cheer .theo-arm-r, .theo-cheer .theo-arm-l,
  .theo-cheer-twice .theo-arm-r, .theo-cheer-twice .theo-arm-l,
  .theo-arms-down .theo-arm-r, .theo-arms-down .theo-arm-l {
    animation-duration: 1ms; animation-delay: 0s;
  }
}
