/* ════════════════════════════════════════════════════════════════════════
   NEXUS Clippy — handmade SVG/CSS character
   ────────────────────────────────────────────────────────────────────
   No clippyjs. No external sprites. 100% our own DOM, our own animations,
   our own click handling. Lives inside a popover host (top-layer) so
   nothing on the page can ever cover him or his bubble.

   Architecture:
     #clippy-host      popover wrapper (top layer, escapes stacking)
       #clippy-shell   draggable container (we own this)
         svg.clippy-svg  the character himself
         #clippy-costume-layer  PNG overlay for hats/etc
       .clippy-bubble  speech bubble with action buttons
       .clippy-palette command palette sheet
   ════════════════════════════════════════════════════════════════════════ */


/* ─── TOP LAYER HOST ──────────────────────────────────────────────── */
#clippy-host {
  /* Override default popover/dialog styling */
  position: fixed !important;
  inset: 0 !important;
  width: 100vw !important;
  height: 100vh !important;
  max-width: none !important;
  max-height: none !important;
  border: 0 !important;
  background: transparent !important;
  padding: 0 !important;
  margin: 0 !important;
  overflow: visible !important;
  pointer-events: none !important;     /* clicks pass through; children opt in */
  color: inherit;
}
#clippy-host:focus-visible { outline: none; }
#clippy-host::backdrop { background: transparent !important; }


/* ─── SHELL (the draggable container) ─────────────────────────────── */
#clippy-shell {
  position: fixed;
  bottom: 16px;
  right: 16px;
  /* v18.10 — slimmed from 120px so he takes less screen real estate.
     SVG scales automatically via viewBox. */
  width: 92px;
  height: 92px;
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  /* His glow. The inner cyan is his native body; the outer aura is
     --clippy-soul-glow, which clippy.js eases toward his ANIMA colour so his
     light reflects his soul (v18.48). Near baseline it stays cyan; as a force
     takes hold his aura tints toward that tone's colour. The slow filter
     transition makes the shift breathe rather than snap. */
  --clippy-soul-glow: rgba(92, 176, 255, 0.35);
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45))
          drop-shadow(0 0 14px rgba(92, 176, 255, 0.30))
          drop-shadow(0 0 22px var(--clippy-soul-glow));
  --pos-transition: left 700ms cubic-bezier(0.34, 1.36, 0.64, 1),
                    top  700ms cubic-bezier(0.34, 1.36, 0.64, 1),
                    bottom 700ms cubic-bezier(0.34, 1.36, 0.64, 1),
                    right  700ms cubic-bezier(0.34, 1.36, 0.64, 1);
  /* v330: single transition — the old first declaration (filter 1600ms, the soul-glow "breathe")
     was silently discarded by this second one (filter 200ms snap). Merged so the aura breathes. */
  transition: var(--pos-transition), opacity 280ms ease, filter 1600ms ease;
}

/* Center-stage moment: he glides to the middle, lifts a little, and glows
   warmer so an intimate ask (a dream to share, a question) owns the room.
   The scale rides on top of the position glide, so it eases in together. */
#clippy-shell.is-center-stage {
  z-index: 2147483000;
  transform: scale(1.22);
  filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.5))
          drop-shadow(0 0 26px rgba(124, 196, 255, 0.6));
  transition: var(--pos-transition), transform 640ms cubic-bezier(0.34, 1.36, 0.64, 1),
              filter 400ms ease, opacity 280ms ease;
}

/* ════════════════════════════════════════════════════════════════════
   v18.10 FIREFLIES — 8 independent glowing dots wandering around Trajan.
   Split into two layers: 4 BEHIND the body (z-index -1, slightly blurred
   for depth) and 4 IN FRONT (z-index 2, sharp). Each one has its own
   keyframe path with fade-in/fade-out so they materialize, drift, and
   vanish like real fireflies. No synchronized rotation — every firefly
   moves independently on its own schedule.
   ════════════════════════════════════════════════════════════════════ */
.clippy-orbit-back,
.clippy-orbit-front {
  position: absolute;
  inset: 6px;            /* TIGHT — hugging the body, not floating out */
  pointer-events: none;
}
.clippy-orbit-back  { z-index: -1; }
.clippy-orbit-front { z-index:  2; }

.clippy-orbital {
  position: absolute;
  width: 5px; height: 5px;
  border-radius: 50%;
  /* v355b — FLAT nodes (Alfredo: "remove the brightness on all of them. keep it a flat colour").
     One solid cyan, no glow, no gradient falloff. */
  background: #7cc4ff;
  box-shadow: none;
  opacity: 0;            /* keyframes drive opacity */
  will-change: left, top, opacity, transform;
}
/* The behind layer is a touch smaller for depth. v355b: no blur — flat like the rest. */
.clippy-orbit-back .clippy-orbital {
  width: 4px; height: 4px;
  filter: none;
}
/* v354b — the front dots were tinted warm (peach/rose/pink/purple) back in v334 to keep bright cyan
   off his cheeks. Alfredo now wants every node to MATCH the electric cyan hand nodes, so those tints
   are removed and all front dots inherit the unified bright cyan-white base above. */

/* v353 — HAND NODES. One of his electric nodes pulls in close and acts as a hand: it materializes at
   his side and gestures (wave / point / reach), then melts back into the swarm. Same electric-dot look
   as the fireflies, a touch bigger + brighter. Idle at opacity 0 until a gesture plays. */
.clippy-hand {
  position: absolute;
  left: 50%; top: 58%;
  /* v353b — bigger so it reads clearly as a hand, but the SAME electric gradient + glow as the
     fireflies so it matches the swarm (and one real orbital is "lent" out while it gestures — see
     .clippy-orbital.is-lent — so it looks pulled from the original). */
  width: 8px; height: 8px;   /* v356b — smaller (Alfredo) */
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: #7cc4ff;   /* v355b — flat, matching the swarm (no glow) */
  box-shadow: none;
  opacity: 0;
  pointer-events: none;
  z-index: 3;
  transform: translate(0, 0) scale(0.6);
  will-change: transform, opacity;
}
/* One real firefly is temporarily lent to the hand — it fades from the swarm for the gesture, so it
   reads as "one of them was pulled in close" rather than a new dot appearing from nowhere. */
.clippy-orbital.is-lent { opacity: 0 !important; animation-play-state: paused; }
.clippy-hand-l { --side: -1; }
.clippy-hand-r { --side:  1; }
/* WAVE — pops out to the side and waggles hello */
.clippy-hand.is-waving  { animation: cl-hand-wave 2s ease-in-out; }   /* v356b — 0.6x speed */
@keyframes cl-hand-wave {
  0%   { opacity: 0; transform: translate(calc(var(--side) * 10px), 6px) scale(0.6); }
  18%  { opacity: 1; transform: translate(calc(var(--side) * 30px), -10px) scale(1); }
  35%  { transform: translate(calc(var(--side) * 42px), -15px) rotate(calc(var(--side) * 20deg)) scale(1.08); }
  50%  { transform: translate(calc(var(--side) * 30px), -12px) rotate(calc(var(--side) * -14deg)) scale(1); }
  65%  { transform: translate(calc(var(--side) * 42px), -15px) rotate(calc(var(--side) * 16deg)) scale(1.08); }
  82%  { transform: translate(calc(var(--side) * 30px), -11px) rotate(0deg) scale(1); }
  100% { opacity: 0; transform: translate(calc(var(--side) * 12px), 4px) scale(0.6); }
}
/* POINT — reaches out toward --hand-x/--hand-y (set in JS), holds, retracts */
.clippy-hand.is-pointing { animation: cl-hand-point 2.5s ease-out; }   /* v356b — 0.6x speed */
@keyframes cl-hand-point {
  0%   { opacity: 0; transform: translate(0, 0) scale(0.6); }
  22%  { opacity: 1; transform: translate(var(--hand-x, 30px), var(--hand-y, -6px)) scale(1.15); }
  78%  { opacity: 1; transform: translate(var(--hand-x, 30px), var(--hand-y, -6px)) scale(1); }
  100% { opacity: 0; transform: translate(0, 0) scale(0.6); }
}
/* REACH — a quick grab/tap outward and back */
.clippy-hand.is-reaching { animation: cl-hand-reach 1.6s ease-in-out; }   /* v356b — 0.6x speed */
@keyframes cl-hand-reach {
  0%   { opacity: 0; transform: translate(calc(var(--side) * 6px), 4px) scale(0.6); }
  42%  { opacity: 1; transform: translate(calc(var(--side) * 36px), -20px) scale(1.2); }
  70%  { opacity: 1; transform: translate(calc(var(--side) * 22px), -8px) scale(0.95); }
  100% { opacity: 0; transform: translate(calc(var(--side) * 6px), 2px) scale(0.6); }
}
/* CHEER — BOTH hands raise up and pump (celebration). Fired on both hands at once. */
.clippy-hand.is-cheering { animation: cl-hand-cheer 2.1s ease-in-out; }   /* v356b — 0.6x speed */
@keyframes cl-hand-cheer {
  0%   { opacity: 0; transform: translate(calc(var(--side) * 12px), 6px) scale(0.6); }
  20%  { opacity: 1; transform: translate(calc(var(--side) * 34px), -26px) scale(1.1); }
  40%  { transform: translate(calc(var(--side) * 34px), -38px) scale(1.15); }
  60%  { transform: translate(calc(var(--side) * 34px), -26px) scale(1.05); }
  80%  { transform: translate(calc(var(--side) * 34px), -36px) scale(1.12); }
  100% { opacity: 0; transform: translate(calc(var(--side) * 14px), 4px) scale(0.6); }
}
/* CLAP — BOTH hands converge to center-bottom and tap twice. */
.clippy-hand.is-clapping { animation: cl-hand-clap 1.85s ease-in-out; }   /* v356b — 0.6x speed */
@keyframes cl-hand-clap {
  0%   { opacity: 0; transform: translate(calc(var(--side) * 30px), 2px) scale(0.6); }
  25%  { opacity: 1; transform: translate(calc(var(--side) * 4px), -6px) scale(1.1); }
  38%  { transform: translate(calc(var(--side) * 26px), -4px) scale(1); }
  55%  { transform: translate(calc(var(--side) * 4px), -6px) scale(1.12); }
  70%  { transform: translate(calc(var(--side) * 24px), -4px) scale(1); }
  85%  { transform: translate(calc(var(--side) * 4px), -6px) scale(1.1); }
  100% { opacity: 0; transform: translate(calc(var(--side) * 28px), 2px) scale(0.6); }
}
/* TELEPORT — a bright implode/burst flash while he blinks to a new spot (opacity+filter only, so it
   never fights the body's float/mood transforms). */
#clippy-shell.is-teleporting { animation: cl-teleport-flash 440ms ease-in-out; }
@keyframes cl-teleport-flash {
  0%   { opacity: 1; filter: brightness(1); }
  40%  { opacity: 0.08; filter: brightness(2.4); }
  60%  { opacity: 0.08; filter: brightness(2.4); }
  100% { opacity: 1; filter: brightness(1); }
}

/* Eight unique firefly paths. Each fades in, drifts across an arc near
   Trajan's body, then fades out at a different point. Periods are all
   different (5.7s – 9.5s) and delays are staggered so they never sync. */
.clippy-orbit-back  .clippy-orbital:nth-child(1) { animation: firefly-a 7.2s ease-in-out infinite;       }
.clippy-orbit-back  .clippy-orbital:nth-child(2) { animation: firefly-b 8.6s ease-in-out -2.1s infinite; }
.clippy-orbit-back  .clippy-orbital:nth-child(3) { animation: firefly-c 6.8s ease-in-out -4.0s infinite; }
.clippy-orbit-back  .clippy-orbital:nth-child(4) { animation: firefly-d 9.5s ease-in-out -6.3s infinite; }
.clippy-orbit-front .clippy-orbital:nth-child(1) { animation: firefly-e 5.7s ease-in-out -1.1s infinite; }
.clippy-orbit-front .clippy-orbital:nth-child(2) { animation: firefly-f 8.2s ease-in-out -3.4s infinite; }
.clippy-orbit-front .clippy-orbital:nth-child(3) { animation: firefly-g 7.5s ease-in-out -5.2s infinite; }
.clippy-orbit-front .clippy-orbital:nth-child(4) { animation: firefly-h 6.3s ease-in-out -7.1s infinite; }

@keyframes firefly-a {
  0%,100% { left:  15%; top:  22%; opacity: 1;   transform: scale(0.4); }
  20%     { left:  28%; top:  14%; opacity: 0.9; transform: scale(1);   }
  50%     { left:  62%; top:  30%; opacity: 1;   transform: scale(1.1); }
  78%     { left:  85%; top:  56%; opacity: 0.5; transform: scale(0.7); }
}
@keyframes firefly-b {
  0%,100% { left:  82%; top:  18%; opacity: 1;   transform: scale(0.4); }
  18%     { left:  74%; top:  32%; opacity: 0.9; transform: scale(1);   }
  48%     { left:  46%; top:  64%; opacity: 1;   transform: scale(1.1); }
  76%     { left:  18%; top:  78%; opacity: 0.5; transform: scale(0.6); }
}
@keyframes firefly-c {
  0%,100% { left:  50%; top:  90%; opacity: 1;   transform: scale(0.4); }
  22%     { left:  42%; top:  72%; opacity: 0.8; transform: scale(0.9); }
  52%     { left:  56%; top:  48%; opacity: 1;   transform: scale(1.1); }
  80%     { left:  48%; top:  14%; opacity: 0.4; transform: scale(0.6); }
}
@keyframes firefly-d {
  0%,100% { left:  20%; top:  62%; opacity: 1;   transform: scale(0.4); }
  18%     { left:  35%; top:  50%; opacity: 0.8; transform: scale(0.9); }
  40%     { left:  60%; top:  38%; opacity: 1;   transform: scale(1);   }
  62%     { left:  72%; top:  60%; opacity: 0.9; transform: scale(1.1); }
  82%     { left:  48%; top:  82%; opacity: 0.4; transform: scale(0.6); }
}
@keyframes firefly-e {
  0%,100% { left:  68%; top:   8%; opacity: 1;   transform: scale(0.4); }
  18%     { left:  60%; top:  18%; opacity: 1;   transform: scale(1.2); }
  44%     { left:  42%; top:  36%; opacity: 1;   transform: scale(1);   }
  70%     { left:  26%; top:  54%; opacity: 0.6; transform: scale(0.7); }
}
@keyframes firefly-f {
  0%,100% { left:  88%; top:  68%; opacity: 1;   transform: scale(0.4); }
  20%     { left:  78%; top:  58%; opacity: 0.9; transform: scale(1.1); }
  48%     { left:  68%; top:  42%; opacity: 1;   transform: scale(1);   }
  74%     { left:  56%; top:  72%; opacity: 0.6; transform: scale(0.8); }
}
@keyframes firefly-g {
  0%,100% { left:  38%; top:  88%; opacity: 1;   transform: scale(0.4); }
  22%     { left:  32%; top:  68%; opacity: 0.9; transform: scale(1.1); }
  46%     { left:  44%; top:  50%; opacity: 1;   transform: scale(1.2); }
  72%     { left:  62%; top:  64%; opacity: 0.7; transform: scale(0.8); }
}
@keyframes firefly-h {
  0%,100% { left:  10%; top:  40%; opacity: 1;   transform: scale(0.4); }
  20%     { left:  22%; top:  46%; opacity: 0.9; transform: scale(1);   }
  50%     { left:  50%; top:  28%; opacity: 1;   transform: scale(1.2); }
  78%     { left:  78%; top:  22%; opacity: 0.5; transform: scale(0.7); }
}

/* Suppress fireflies when Trajan is hidden/sleeping/sulking — quiet states */
#clippy-shell.is-hidden     .clippy-orbit-back,
#clippy-shell.is-hidden     .clippy-orbit-front,
#clippy-shell.is-suppressed .clippy-orbit-back,
#clippy-shell.is-suppressed .clippy-orbit-front,
#clippy-shell.is-sleeping   .clippy-orbit-back,
#clippy-shell.is-sleeping   .clippy-orbit-front,
#clippy-shell.is-sulking    .clippy-orbit-back,
#clippy-shell.is-sulking    .clippy-orbit-front {
  opacity: 0;
}
#clippy-shell.is-dragging {
  cursor: grabbing;
  transition: none;
  filter: drop-shadow(0 8px 20px rgba(0, 0, 0, 0.55))
          drop-shadow(0 0 18px rgba(125, 240, 255, 0.55));
}
#clippy-shell.is-hidden {
  opacity: 0;
  pointer-events: none;
  transform: translateY(120%) scale(0.6);
}
#clippy-shell.is-suppressed {
  opacity: 0 !important;
  pointer-events: none !important;
  visibility: hidden;
}

/* SVG fills the shell */
.clippy-svg {
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;     /* events handled by shell */
  overflow: visible;
}


/* ════════════════════════════════════════════════════════════════════
   IDLE — default behaviors (always running unless overridden)
   ════════════════════════════════════════════════════════════════════ */

/* Subtle breathing scale on the body */
.clippy-svg .cl-body {
  transform-origin: 100px 100px;   /* v330: was 60px 130px — a leftover from the old 120x160 paperclip viewBox; in the 200x200 orb it made the body breathe around its bottom edge instead of its center */
  transform-box: view-box;
  animation: clBreathe 4.2s ease-in-out infinite;
}
@keyframes clBreathe {
  0%, 100% { transform: scale(1) translateY(0); }
  50%      { transform: scale(1.012) translateY(-2px); }
}

/* Pupils track the cursor via --eye-x / --eye-y */
.clippy-svg .cl-pupils,
.clippy-svg .cl-glint {
  transform: translate(calc(var(--eye-x, 0) * 1px), calc(var(--eye-y, 0) * 1px));
  transition: transform 200ms ease-out;
  transform-origin: center;
  transform-box: fill-box;
}

/* ════════════════════════════════════════════════════════════════════
   v17 — FULL ANIME EXPRESSION SYSTEM
   ──────────────────────────────────────────────────────────────────────
   Every face state has its own group in the SVG, all stacked at the
   same coordinates. Default eyes + default mouth are visible; every
   other variant has opacity:0 until a mood class is added to the shell.
   Mood class toggles the swap — old default fades out, target fades in.
   ════════════════════════════════════════════════════════════════════ */

/* Universal transition on the swap targets so they crossfade smoothly */
.clippy-svg [class^="cl-eyes-"],
.clippy-svg [class^="cl-mouth-"] {
  transition: opacity 220ms ease, transform 280ms ease-out;
}

/* Default visibility: default eyes & smile shown, all variants hidden */
.clippy-svg .cl-eyes-default { opacity: 1; }
.clippy-svg .cl-eyes-happy,
.clippy-svg .cl-eyes-shut,
.clippy-svg .cl-eyes-love,
.clippy-svg .cl-eyes-stars,
.clippy-svg .cl-eyes-dizzy,
.clippy-svg .cl-eyes-angry,
.clippy-svg .cl-eyes-sad,
.clippy-svg .cl-eyes-sleepy,
.clippy-svg .cl-eyes-dots,
.clippy-svg .cl-eyes-x,
.clippy-svg .cl-eyes-wink-l,
.clippy-svg .cl-eyes-wink-r,
.clippy-svg .cl-eyes-suspicious,
.clippy-svg .cl-eyes-determined,
.clippy-svg .cl-eyes-sparkle,
.clippy-svg .cl-eyes-embarrassed,
.clippy-svg .cl-eyes-tearful,
.clippy-svg .cl-eyes-up,
.clippy-svg .cl-eyes-down,
.clippy-svg .cl-eyes-squint,
.clippy-svg .cl-eyes-wide-shock,
.clippy-svg .cl-eyes-glance,
.clippy-svg .cl-eyes-disgusted,
.clippy-svg .cl-eyes-genius,
.clippy-svg .cl-eyes-studious,
.clippy-svg .cl-eyes-condescend { opacity: 0; }

.clippy-svg .cl-mouth-smile { opacity: 1; }
.clippy-svg .cl-mouth-bigsmile,
.clippy-svg .cl-mouth-tongue,
.clippy-svg .cl-mouth-o,
.clippy-svg .cl-mouth-wavy,
.clippy-svg .cl-mouth-fangs,
.clippy-svg .cl-mouth-flat,
.clippy-svg .cl-mouth-frown,
.clippy-svg .cl-mouth-cat,
.clippy-svg .cl-mouth-kiss,
.clippy-svg .cl-mouth-pout,
.clippy-svg .cl-mouth-star,
.clippy-svg .cl-mouth-laugh,
.clippy-svg .cl-mouth-tape,
.clippy-svg .cl-mouth-triangle { opacity: 0; }

/* v17.16 new overlays — hidden by default */
.clippy-svg .cl-tear,
.clippy-svg .cl-tears-stream,
.clippy-svg .cl-drool,
.clippy-svg .cl-red-nose,
.clippy-svg .cl-vein,
.clippy-svg .cl-snot,
.clippy-svg .cl-queasy,
.clippy-svg .cl-heart-blush { opacity: 0; transition: opacity 0.25s ease; }

/* Sleep Z's hidden by default (kept from prior version) */
.clippy-svg .cl-zzz { opacity: 0; transition: opacity 280ms ease; }

/* v2026 extra overlays — shown on existing moods, combinable with any face.
   anger pop-vein on the angry family, snot bubble while sleeping, green
   wash when disgusted. The snot bubble gently inflates (the reduced-motion
   backstop in nexus-rm.css collapses the loop for motion-sensitive users). */
#clippy-shell.is-angry .cl-vein,
#clippy-shell.is-peeved .cl-vein,
#clippy-shell.is-frustrated .cl-vein { opacity: 1; }
#clippy-shell.is-sleeping .cl-snot { opacity: 1; }
#clippy-shell.is-sleeping .cl-snot-bubble {
  animation: clSnot 3.2s ease-in-out infinite;
  transform-origin: 112px 137px;
}
@keyframes clSnot { 0%, 100% { transform: scale(0.7); } 55% { transform: scale(1.12); } }
#clippy-shell.is-disgusted .cl-queasy { opacity: 1; }

/* Pupil + glint translate via --eye-x/--eye-y CSS vars (set by JS).
   Only meaningful for default eyes; other variants are static. */
.clippy-svg .cl-pupil,
.clippy-svg .cl-glint {
  transform: translate(calc(var(--eye-x, 0) * 1px), calc(var(--eye-y, 0) * 1px));
  transition: transform 200ms ease-out;
  transform-origin: center;
  transform-box: fill-box;
}

/* ───────── MOOD CLASSES ─────────
   Each mood toggles a specific eye + mouth combination.
   Format:  shell.is-X   eye-group-on/off   mouth-group-on/off
*/

/* BLINK — split-second close (fast transition for this one) */
#clippy-shell.is-blinking .cl-eyes-default { opacity: 0; transition-duration: 60ms; }
#clippy-shell.is-blinking .cl-eyes-shut    { opacity: 1; transition-duration: 60ms; }

/* SLEEPING — eyes shut + Z's appear + body dims */
#clippy-shell.is-sleeping .cl-eyes-default { opacity: 0; }
#clippy-shell.is-sleeping .cl-eyes-shut    { opacity: 1; }
#clippy-shell.is-sleeping .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-sleeping .cl-mouth-flat   { opacity: 0.55; }
#clippy-shell.is-sleeping .cl-zzz          { opacity: 1; }
#clippy-shell.is-sleeping .cl-zzz text     { animation: clZzz 2.4s ease-in-out infinite; }
#clippy-shell.is-sleeping .cl-body         { filter: brightness(0.85); }
@keyframes clZzz {
  0%, 100% { opacity: 0.3; transform: translateY(0); }
  50%      { opacity: 1.0; transform: translateY(-3px); }
}

/* HAPPY — closed crescents ^_^ + open smile */
#clippy-shell.is-happy .cl-eyes-default { opacity: 0; }
#clippy-shell.is-happy .cl-eyes-happy   { opacity: 1; }
#clippy-shell.is-happy .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-happy .cl-mouth-bigsmile { opacity: 1; }

/* LOVE — heart eyes + big smile */
#clippy-shell.is-love .cl-eyes-default { opacity: 0; }
#clippy-shell.is-love .cl-eyes-love    { opacity: 1; }
#clippy-shell.is-love .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-love .cl-mouth-bigsmile { opacity: 1; }
#clippy-shell.is-love .cl-eyes-love use {
  animation: clHeartPulse 1.2s ease-in-out infinite;
  transform-origin: center;
  transform-box: fill-box;
}
@keyframes clHeartPulse {
  0%, 100% { transform: scale(1.0); }
  50%      { transform: scale(1.15); }
}

/* EXCITED — star eyes + tongue out */
#clippy-shell.is-excited .cl-eyes-default { opacity: 0; }
#clippy-shell.is-excited .cl-eyes-stars   { opacity: 1; }
#clippy-shell.is-excited .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-excited .cl-mouth-tongue { opacity: 1; }
#clippy-shell.is-excited .cl-eyes-stars use {
  animation: clStarSpin 2.2s linear infinite;
  transform-origin: center;
  transform-box: fill-box;
}
@keyframes clStarSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* SURPRISED — keep default eyes but pop them larger, plus mouth O */
#clippy-shell.is-surprised .cl-eyes-default {
  transform: scale(1.12);
  transform-origin: center;
  transform-box: fill-box;
}
#clippy-shell.is-surprised .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-surprised .cl-mouth-o     { opacity: 1; }

/* THINKING — suspicious half-lid + flat mouth */
#clippy-shell.is-thinking .cl-eyes-default   { opacity: 0; }
#clippy-shell.is-thinking .cl-eyes-suspicious { opacity: 1; }
#clippy-shell.is-thinking .cl-mouth-smile    { opacity: 0; }
#clippy-shell.is-thinking .cl-mouth-flat     { opacity: 1; }

/* CONCERNED — embarrassed/looking-away + flat */
#clippy-shell.is-concerned .cl-eyes-default     { opacity: 0; }
#clippy-shell.is-concerned .cl-eyes-embarrassed { opacity: 1; }
#clippy-shell.is-concerned .cl-mouth-smile      { opacity: 0; }
#clippy-shell.is-concerned .cl-mouth-flat       { opacity: 1; }

/* SAD — droopy eyes + tear + frown */
#clippy-shell.is-sad .cl-eyes-default { opacity: 0; }
#clippy-shell.is-sad .cl-eyes-sad     { opacity: 1; }
#clippy-shell.is-sad .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-sad .cl-mouth-frown  { opacity: 1; }

/* ANGRY — softened: V-brow + small round dark eyes + cute huff mouth.
   v17.14: no red pupils, no fangs, no rage-shake. Anger pop "#" floats
   above his head instead — manga-cute. */
#clippy-shell.is-angry .cl-eyes-default { opacity: 0; }
#clippy-shell.is-angry .cl-eyes-angry   { opacity: 1; }
#clippy-shell.is-angry .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-angry .cl-mouth-fangs  { opacity: 1; }
/* anger-pop animation handled in main effects block above */

/* DIZZY — spiral eyes + wavy mouth + slight tilt */
#clippy-shell.is-dizzy .cl-eyes-default { opacity: 0; }
#clippy-shell.is-dizzy .cl-eyes-dizzy   { opacity: 1; }
#clippy-shell.is-dizzy .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-dizzy .cl-mouth-wavy   { opacity: 1; }
#clippy-shell.is-dizzy .cl-eyes-dizzy {
  animation: clDizzySpin 1.6s linear infinite;
  transform-origin: 100px 103px;
}
@keyframes clDizzySpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* SMUG — tiny dot eyes + cat :3 mouth */
#clippy-shell.is-smug .cl-eyes-default { opacity: 0; }
#clippy-shell.is-smug .cl-eyes-dots    { opacity: 1; }
#clippy-shell.is-smug .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-smug .cl-mouth-cat    { opacity: 1; }

/* KO — X-eyes + flat mouth */
#clippy-shell.is-ko .cl-eyes-default { opacity: 0; }
#clippy-shell.is-ko .cl-eyes-x       { opacity: 1; }
#clippy-shell.is-ko .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-ko .cl-mouth-flat   { opacity: 1; }

/* WINKING — right-eye wink + tongue */
#clippy-shell.is-winking .cl-eyes-default { opacity: 0; }
#clippy-shell.is-winking .cl-eyes-wink-r  { opacity: 1; }
#clippy-shell.is-winking .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-winking .cl-mouth-tongue { opacity: 1; }

/* WINK-LEFT — alternate wink direction */
#clippy-shell.is-winking-l .cl-eyes-default { opacity: 0; }
#clippy-shell.is-winking-l .cl-eyes-wink-l  { opacity: 1; }
#clippy-shell.is-winking-l .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-winking-l .cl-mouth-tongue { opacity: 1; }

/* SLEEPY — heavy lids + cat mouth */
#clippy-shell.is-sleepy .cl-eyes-default { opacity: 0; }
#clippy-shell.is-sleepy .cl-eyes-sleepy  { opacity: 1; }
#clippy-shell.is-sleepy .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-sleepy .cl-mouth-cat    { opacity: 1; }

/* DETERMINED — focused eyes + flat mouth */
#clippy-shell.is-determined .cl-eyes-default    { opacity: 0; }
#clippy-shell.is-determined .cl-eyes-determined { opacity: 1; }
#clippy-shell.is-determined .cl-mouth-smile     { opacity: 0; }
#clippy-shell.is-determined .cl-mouth-flat      { opacity: 1; }

/* SPARKLE — default eyes + sparkle overlay + big smile */
#clippy-shell.is-sparkle .cl-eyes-sparkle { opacity: 1; }
#clippy-shell.is-sparkle .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-sparkle .cl-mouth-bigsmile { opacity: 1; }
#clippy-shell.is-sparkle .cl-eyes-sparkle text {
  animation: clSparkleTwinkle 1.3s ease-in-out infinite;
  transform-origin: center;
  transform-box: fill-box;
}
#clippy-shell.is-sparkle .cl-eyes-sparkle text:nth-child(2n) { animation-delay: 0.3s; }
#clippy-shell.is-sparkle .cl-eyes-sparkle text:nth-child(3n) { animation-delay: 0.6s; }
@keyframes clSparkleTwinkle {
  0%, 100% { opacity: 0.4; transform: scale(0.7); }
  50%      { opacity: 1.0; transform: scale(1.15); }
}

/* EMBARRASSED — looking away + cheeks brighter + cat mouth */
#clippy-shell.is-embarrassed .cl-eyes-default     { opacity: 0; }
#clippy-shell.is-embarrassed .cl-eyes-embarrassed { opacity: 1; }
#clippy-shell.is-embarrassed .cl-cheek {
  opacity: 1;
  filter: brightness(1.25) saturate(1.3);
}
#clippy-shell.is-embarrassed .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-embarrassed .cl-mouth-cat   { opacity: 1; }

/* KISSY — kiss mouth + happy eyes (mwah!) */
#clippy-shell.is-kissy .cl-eyes-default { opacity: 0; }
#clippy-shell.is-kissy .cl-eyes-happy   { opacity: 1; }
#clippy-shell.is-kissy .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-kissy .cl-mouth-kiss   { opacity: 1; }


/* ════════════════════════════════════════════════════════════════════
   ACTION ANIMATIONS — one-shot
   ════════════════════════════════════════════════════════════════════ */

/* Wave — v330: the orb has no arms (kawaii regen), so the old .cl-arms/.cl-hand-r targets were dead.
   Retarget to a friendly whole-body tilt-wave so the gesture actually reads. */
#clippy-shell.is-waving .clippy-svg {
  animation: clWave 640ms ease-in-out 3;
  transform-origin: 50% 80%;
}
@keyframes clWave {
  0%, 100% { transform: rotate(0); }
  30%      { transform: rotate(11deg) translateY(-2px); }
  70%      { transform: rotate(-9deg) translateY(-2px); }
}

/* Boing — entrance from below, springy */
#clippy-shell.is-entering .clippy-svg {
  animation: clBoing 760ms cubic-bezier(0.34, 1.56, 0.64, 1) 1;
}
@keyframes clBoing {
  0%   { transform: translateY(60px) scale(0.55); opacity: 0; }
  60%  { transform: translateY(-10px) scale(1.10); opacity: 1; }
  82%  { transform: translateY(3px) scale(0.96); }
  100% { transform: translateY(0) scale(1); }
}

/* Hop — quick excited up-and-down */
#clippy-shell.is-hopping .clippy-svg {
  animation: clHop 540ms cubic-bezier(0.34, 1.56, 0.64, 1) 1;
}
@keyframes clHop {
  0%, 100% { transform: translateY(0); }
  45%, 60% { transform: translateY(-22px); }
}

/* Wobble — gentle side-to-side */
#clippy-shell.is-wobbling .clippy-svg {
  animation: clWobble 720ms cubic-bezier(0.36, 0.07, 0.19, 0.97) 1;
}
@keyframes clWobble {
  0%, 100% { transform: rotate(0); }
  18%      { transform: rotate(-5deg); }
  36%      { transform: rotate(5deg); }
  54%      { transform: rotate(-3deg); }
  72%      { transform: rotate(3deg); }
  90%      { transform: rotate(-1deg); }
}

/* Dizzy — full 720° spin */
#clippy-shell.is-dizzy .clippy-svg {
  animation: clDizzy 1.2s linear 1;
}
@keyframes clDizzy {
  0%   { transform: rotate(0); }
  100% { transform: rotate(720deg); }
}

/* Cartwheel — sideways flip */
#clippy-shell.is-cartwheeling .clippy-svg {
  animation: clCartwheel 900ms ease-in-out 1;
}
@keyframes clCartwheel {
  0%   { transform: rotate(0) translateX(0); }
  50%  { transform: rotate(-180deg) translateX(-25px); }
  100% { transform: rotate(-360deg) translateX(0); }
}

/* Magic — v330: no .cl-sparkles group exists (kawaii regen); the JS spawns particles for sparkle,
   so make the body itself do a bright magic pulse+bob so the gesture reads even without them. */
#clippy-shell.is-magic .clippy-svg {
  animation: clMagicPulse 900ms ease-in-out 2;
  transform-origin: 50% 55%;
}
@keyframes clMagicPulse {
  0%, 100% { transform: scale(1) translateY(0); filter: brightness(1); }
  40%      { transform: scale(1.07) translateY(-4px); filter: brightness(1.35); }
}

/* Listening (music) — gentle sway */
#clippy-shell.is-listening .clippy-svg {
  animation: clSway 2.8s ease-in-out infinite;
}
@keyframes clSway {
  0%, 100% { transform: rotate(0); }
  50%      { transform: rotate(3deg); }
}


/* ════════════════════════════════════════════════════════════════════
   LOGIN PEEK — pre-acceptance state (only head visible, slides up)
   ════════════════════════════════════════════════════════════════════ */
#clippy-shell.is-peek-entering {
  transform: translateY(140%);
  transition: none;
}
#clippy-shell.is-peeking {
  transform: translateY(50%);
  transition: transform 900ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* v17.5: PEEK-EYES-ONLY mode — for first-login. Clip the shell so only
   the eye band is visible. Position is set via JS to a random spot per
   session. The clip leaves about 25% of the shell visible (the eyes).
   The body/cheeks/mouth/nodes/halo all get clipped out, so only the
   "eyes peeking from somewhere" effect remains. */
#clippy-shell.is-peek-eyes-only {
  /* Show only the middle horizontal band where eyes live (~y=40-72%) */
  clip-path: inset(38% 12% 28% 12% round 30%);
  -webkit-clip-path: inset(38% 12% 28% 12% round 30%);
  filter: drop-shadow(0 0 12px rgba(125, 240, 255, 0.55))
          drop-shadow(0 0 6px rgba(255, 255, 255, 0.4));
  animation: clPeekBob 3.2s ease-in-out infinite;
}
@keyframes clPeekBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2px); }
}
/* When peeking, blink more often to draw attention */
#clippy-shell.is-peek-eyes-only .cl-body,
#clippy-shell.is-peek-eyes-only .cl-cheek,
#clippy-shell.is-peek-eyes-only .cl-mouth {
  opacity: 0.4;
}

/* ════════════════════════════════════════════════════════════════════
   v17.6 PARTICLE EFFECTS
   Spawn via spawnParticles() in JS. Each particle is an absolutely-
   positioned <div> with CSS animation that fires once and self-removes.
   Three flavors: sparkle (yellow burst), heart (pink burst), confetti
   (multicolor with gravity fall).
   ════════════════════════════════════════════════════════════════════ */
.clippy-particle {
  position: fixed;
  pointer-events: none;
  width: 12px;
  height: 12px;
  z-index: 100;
  will-change: transform, opacity;
}
.clippy-particle-sparkle {
  background: radial-gradient(circle, #ffec70 0%, #ffd24a 35%, transparent 70%);
  border-radius: 50%;
  box-shadow: 0 0 6px rgba(255, 220, 100, 0.85);
  animation: clParticle 1.5s ease-out forwards;
}
.clippy-particle-heart {
  width: 14px;
  height: 14px;
  background: radial-gradient(circle, #ff4d8a 0%, #ff4d8a 60%, transparent 70%);
  border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
  transform-origin: center;
  box-shadow: 0 0 4px rgba(255, 77, 138, 0.6);
  animation: clParticle 1.5s ease-out forwards;
}
.clippy-particle-heart::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.8) 0%, transparent 40%);
  border-radius: inherit;
}
.clippy-particle-confetti {
  width: 6px;
  height: 10px;
  background: linear-gradient(135deg, #ffec70, #ff5577, #5cb0ff, #b06fff);
  animation: clConfetti 1.6s ease-out forwards;
}
@keyframes clParticle {
  0%   { transform: translate(0, 0) scale(0);   opacity: 0; }
  20%  { transform: translate(0, 0) scale(1.2); opacity: 1; }
  100% { transform: translate(var(--tx, 0), var(--ty, 0)) scale(0.4) rotate(var(--rot, 0deg)); opacity: 0; }
}
@keyframes clConfetti {
  0%   { transform: translate(0, 0) rotate(0); opacity: 0; }
  15%  { opacity: 1; }
  100% { transform: translate(var(--tx, 0), calc(var(--ty, 0) + 80px)) rotate(var(--rot, 360deg)); opacity: 0; }
}

/* ════════════════════════════════════════════════════════════════════
   v17.10 DANCE + JIGGLE — visible feedback for behaviors
   v17.12 → v17.14: shadow is now a separate DIV (not in SVG). Pacing
           moved from full body to FACE-ONLY (eyes drift inside the
           body, clipped at edge). Body stays put. Demon-angry softened.
   ════════════════════════════════════════════════════════════════════ */

/* External shadow — separate DOM element, anchored below the SVG.
   Sits in the shell at fixed position. Body can bounce/dance over it. */
.clippy-shadow {
  position: absolute;
  bottom: 4px;
  left: 50%;
  width: 64%;
  height: 7%;
  border-radius: 50%;
  background: radial-gradient(ellipse at center,
              rgba(0,0,0,0.32) 0%,
              rgba(0,0,0,0.20) 60%,
              rgba(0,0,0,0) 100%);
  transform: translateX(-50%);
  pointer-events: none;
  transition: width 0.3s ease, opacity 0.3s ease, filter 0.3s ease;
  z-index: 0;
}
#clippy-shell .clippy-svg {
  position: relative;
  z-index: 1;
}

/* Shadow reacts to body-state visually:
   bouncing → shrinks horizontally + fades (body is high up)
   dancing  → subtle pulse */
#clippy-shell.is-bouncing .clippy-shadow {
  animation: clShadowBounce 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) infinite;
}
@keyframes clShadowBounce {
  0%, 100% { width: 64%; opacity: 1; }
  15%      { width: 72%; opacity: 1; }     /* squash — wide and dark */
  35%      { width: 32%; opacity: 0.5; }   /* peak — small, faded */
  60%      { width: 38%; opacity: 0.6; }
  85%      { width: 68%; opacity: 0.95; }
}
#clippy-shell.is-dancing .clippy-shadow {
  animation: clShadowDance 0.65s ease-in-out infinite;
}
@keyframes clShadowDance {
  0%, 100% { width: 64%; opacity: 1; }
  40%      { width: 50%; opacity: 0.7; }
  80%      { width: 62%; opacity: 0.95; }
}

/* FACE PANNING — the eyes look around inside the body.
   Animation drifts cl-face horizontally; clipPath cuts off at body edge. */
#clippy-shell .cl-face {
  animation: clFacePan 9s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: 50% 50%;
}
@keyframes clFacePan {
  0%, 100% { transform: translateX(0); }
  15%      { transform: translateX(-3px); }
  30%      { transform: translateX(-12px); }
  45%      { transform: translateX(-4px); }
  60%      { transform: translateX(0); }
  75%      { transform: translateX(12px); }
  90%      { transform: translateX(4px); }
}

/* Dance: theme song mode. Body bounces/twists; shadow handled above. */
#clippy-shell.is-dancing .cl-floats {
  animation: clDance 0.65s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
}
#clippy-shell.is-dancing {
  filter: drop-shadow(0 0 14px rgba(255, 220, 100, 0.6));
}
@keyframes clDance {
  0%, 100% { transform: translate(0, 0)         rotate(0deg)   scale(1); }
  20%      { transform: translate(-14px, -10px) rotate(-12deg) scale(1.04); }
  40%      { transform: translate(0, -22px)     rotate(0deg)   scale(1.08); }
  60%      { transform: translate(14px, -10px)  rotate(12deg)  scale(1.04); }
  80%      { transform: translate(0, -6px)      rotate(0deg)   scale(1.02); }
}

/* Jiggle: tickle response. Body wobble. Face pan still runs inside. */
#clippy-shell.is-jiggling .cl-floats {
  animation: clJiggle 0.16s ease-in-out 14 !important;
}
@keyframes clJiggle {
  0%, 100% { transform: scale(1)    rotate(0deg); }
  25%      { transform: scale(1.06) rotate(-5deg); }
  75%      { transform: scale(1.06) rotate(5deg); }
}

/* Bouncing: tall jumps with squash/stretch. Shadow scaled separately above. */
#clippy-shell.is-bouncing .cl-floats {
  animation: clBounce 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) infinite !important;
}
@keyframes clBounce {
  0%, 100% { transform: translateY(0)    scaleY(1)    scaleX(1); }
  15%      { transform: translateY(0)    scaleY(0.85) scaleX(1.1); }
  35%      { transform: translateY(-32px) scaleY(1.1)  scaleX(0.92); }
  60%      { transform: translateY(-26px) scaleY(1.05) scaleX(0.96); }
  85%      { transform: translateY(0)    scaleY(0.95) scaleX(1.04); }
}

/* v17.14 NEW EMOTION OVERLAYS — all hidden by default, mood class shows */
.clippy-svg .cl-sweat,
.clippy-svg .cl-music,
.clippy-svg .cl-anger-pop,
.clippy-svg .cl-question { opacity: 0; transition: opacity 0.25s ease; }

/* Embarrassed: sweat drop visible, blush boosted, eyes go winking-l */
#clippy-shell.is-embarrassed .cl-sweat { opacity: 1; }

/* Worried: sweat drop + sad eyes via existing sad mood mapping */
#clippy-shell.is-worried .cl-sweat { opacity: 1; }
#clippy-shell.is-worried .cl-eyes-default { opacity: 0; }
#clippy-shell.is-worried .cl-eyes-sad     { opacity: 1; }
#clippy-shell.is-worried .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-worried .cl-mouth-flat   { opacity: 1; }

/* Singing: music notes float above, eyes happy crescents, big smile */
#clippy-shell.is-singing .cl-music { opacity: 1; animation: clMusicFloat 2s ease-in-out infinite; }
#clippy-shell.is-singing .cl-eyes-default { opacity: 0; }
#clippy-shell.is-singing .cl-eyes-happy   { opacity: 1; }
#clippy-shell.is-singing .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-singing .cl-mouth-bigsmile { opacity: 1; }
@keyframes clMusicFloat {
  0%, 100% { transform: translateY(0)   rotate(-4deg); }
  50%      { transform: translateY(-4px) rotate(4deg); }
}

/* Confused: question mark floats above, dot eyes, suspicious tilt */
#clippy-shell.is-confused .cl-question { opacity: 1; animation: clQuestionWobble 1.5s ease-in-out infinite; }
#clippy-shell.is-confused .cl-eyes-default { opacity: 0; }
#clippy-shell.is-confused .cl-eyes-dots    { opacity: 1; }
#clippy-shell.is-confused .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-confused .cl-mouth-flat   { opacity: 1; }
@keyframes clQuestionWobble {
  0%, 100% { transform: rotate(-6deg) scale(1); }
  50%      { transform: rotate(6deg)  scale(1.1); }
}

/* When angry, the cute manga "anger pop" appears above his head */
#clippy-shell.is-angry .cl-anger-pop { opacity: 1; animation: clAngerPulse 0.6s ease-in-out infinite; }
@keyframes clAngerPulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(1.15); opacity: 0.8; }
}

/* ════════════════════════════════════════════════════════════════════
   v17.11 CHAT BUBBLE — input field, send button, close button.
   The ".is-super" variant is the rare oracle mode: gold border + glow.
   ════════════════════════════════════════════════════════════════════ */
/* v18.54 — the conversation PANEL: a header, a scrollable thread, and a
   docked input. Tinted by his live soul-colour via --chat-soul (JS sets it;
   falls back to NEXUS blue). */
.clippy-chat-panel {
  --chat-soul: #5cb0ff;
  min-width: 300px;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  padding: 12px 12px 12px;
  gap: 8px;
}
.clippy-chat-panel.is-super { --chat-soul: #ffd24a; }
.clippy-chat-panel.is-super {
  border-color: #ffd24a;
  /* !important so the ORACLE's signature amber glow actually wins over the base
     bubble's box-shadow (which is !important) — before, its glow was suppressed. */
  background:
    radial-gradient(130% 82% at 50% 0%, rgba(255, 210, 74, 0.16) 0%, rgba(255, 210, 74, 0) 60%),
    linear-gradient(180deg, rgba(40, 33, 20, 0.985) 0%, rgba(21, 17, 11, 0.99) 100%) !important;
  box-shadow:
    0 0 30px rgba(255, 210, 74, 0.42),
    0 10px 28px rgba(0, 0, 0, 0.50),
    0 0 0 1px rgba(255, 210, 74, 0.55) inset,
    0 1px 0 rgba(255, 240, 200, 0.14) inset !important;
}

/* Header — soul dot, label, close. */
.clippy-chat-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.09);
}
.clippy-chat-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--chat-soul);
  box-shadow: 0 0 8px var(--chat-soul), 0 0 2px var(--chat-soul);
  flex: 0 0 auto;
  animation: clippyChatDot 2.6s ease-in-out infinite;
}
@keyframes clippyChatDot { 0%,100% { opacity: .55; } 50% { opacity: 1; } }
.clippy-chat-head .clippy-bubble-eyebrow {
  flex: 1 1 auto;
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.14em;
  opacity: 0.8;
}
.clippy-chat-panel.is-super .clippy-chat-head .clippy-bubble-eyebrow { color: #ffd24a; }
.clippy-chat-x {
  flex: 0 0 auto;
  width: 24px; height: 24px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.7);
  font-size: 16px; line-height: 1;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.clippy-chat-x:hover { background: rgba(255, 255, 255, 0.16); color: #fff; }

/* The thread. */
.clippy-chat-log {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 46vh;
  min-height: 40px;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 2px 2px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.22) transparent;
}
.clippy-chat-log::-webkit-scrollbar { width: 6px; }
.clippy-chat-log::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.2); border-radius: 3px; }

.clippy-msg {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-width: 100%;
  animation: clippyMsgIn 0.22s ease-out;
}
@keyframes clippyMsgIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.clippy-msg.is-user { align-items: flex-end; }
.clippy-msg.is-clippy { align-items: flex-start; }
.clippy-msg-bubble {
  max-width: 86%;
  padding: 8px 11px;
  border-radius: 14px;
  font-size: 14.5px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
}
.clippy-msg.is-user .clippy-msg-bubble {
  background: var(--chat-soul);
  color: #0c1420;
  border-bottom-right-radius: 5px;
  font-weight: 500;
}
.clippy-msg.is-clippy .clippy-msg-bubble {
  background: rgba(255, 255, 255, 0.07);
  color: #f2f4f8;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-left: 2px solid var(--chat-soul);
  border-bottom-left-radius: 5px;
}
.clippy-msg.is-engraved .clippy-msg-bubble {
  background: rgba(255, 210, 74, 0.1);
  border-color: rgba(255, 210, 74, 0.5);
  border-left-color: #ffd24a;
  color: #fff3d6;
  box-shadow: 0 0 16px rgba(255, 210, 74, 0.22);
}

/* MENS "take me there" — threaded under his reply. */
.clippy-msg-jump {
  align-self: flex-start;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--chat-soul);
  background: color-mix(in srgb, var(--chat-soul) 16%, transparent);
  color: var(--chat-soul);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease, transform 0.06s ease;
}
.clippy-msg-jump:hover { background: color-mix(in srgb, var(--chat-soul) 28%, transparent); }
.clippy-msg-jump:active { transform: scale(0.97); }

/* Thinking item — shown while his LLM brain works. A soul-tinted pulsing orb,
   the word "thinking", and the animated dots, so it reads as real effort. */
.clippy-thinking-item {
  display: inline-flex !important;
  align-items: center;
  gap: 8px;
  background: color-mix(in srgb, var(--chat-soul, #5cb0ff) 12%, rgba(255,255,255,0.05)) !important;
  border: 1px solid color-mix(in srgb, var(--chat-soul, #5cb0ff) 30%, transparent) !important;
}
.clippy-think-orb {
  width: 12px; height: 12px; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #eaf5ff, var(--chat-soul, #5cb0ff) 70%);
  box-shadow: 0 0 8px var(--chat-soul, #5cb0ff), 0 0 2px var(--chat-soul, #5cb0ff);
  flex: 0 0 auto;
  animation: clippyThinkPulse 1.4s ease-in-out infinite;
}
@keyframes clippyThinkPulse {
  0%, 100% { transform: scale(0.82); opacity: 0.65; }
  50%      { transform: scale(1.12); opacity: 1; }
}
.clippy-think-label {
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: color-mix(in srgb, var(--chat-soul, #5cb0ff) 55%, #e8eef6);
  font-style: italic;
}

/* Typing "…". */
.clippy-typing-dots { display: inline-flex; gap: 4px; align-items: center; padding: 2px 0; }
.clippy-typing-dots i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--chat-soul);
  opacity: 0.4;
  animation: clippyTyping 1.1s infinite ease-in-out;
}
.clippy-typing-dots i:nth-child(2) { animation-delay: 0.18s; }
.clippy-typing-dots i:nth-child(3) { animation-delay: 0.36s; }
@keyframes clippyTyping { 0%,60%,100% { opacity: 0.35; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }

/* Docked input. */
.clippy-chat-input-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
}
.clippy-chat-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 10px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(0, 0, 0, 0.32);
  color: #fff;
  font-size: 15px;
  font-family: inherit;
  box-sizing: border-box;
  -webkit-appearance: none;
}
.clippy-chat-input::placeholder { color: rgba(255, 255, 255, 0.4); }
.clippy-chat-input:focus {
  outline: none;
  border-color: var(--chat-soul);
  background: rgba(0, 0, 0, 0.4);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--chat-soul) 22%, transparent);
}
.clippy-chat-send {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  border-radius: 50%;
  border: none;
  background: var(--chat-soul);
  color: #0c1420;
  font-size: 15px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: filter 0.12s ease, transform 0.06s ease;
}
.clippy-chat-send:hover { filter: brightness(1.08); }
.clippy-chat-send:active { transform: scale(0.93); filter: brightness(0.9); }


/* ════════════════════════════════════════════════════════════════════
   COSTUME OVERLAY LAYER — for the 16 SVG hats/crowns/etc
   ════════════════════════════════════════════════════════════════════ */
#clippy-costume-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  display: none;
}
#clippy-costume-layer.is-active { display: block; }
.clippy-costume-img {
  position: absolute;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}

/* Per-costume positioning (translates relative to the shell) */
.clippy-costume-laurel    { transform: translate(0, -14%) scale(0.95); }
.clippy-costume-chef      { transform: translate(0, -28%) scale(1.10); }
.clippy-costume-glasses   { transform: translate(0,  -8%) scale(0.95); }
.clippy-costume-mustache  { transform: translate(0,   8%) scale(0.85); }
.clippy-costume-ghost     { transform: translate(0,  -5%) scale(1.18); }
.clippy-costume-sombrero  { transform: translate(0, -22%) scale(1.18); }
.clippy-costume-sunglasses{ transform: translate(0,  -8%) scale(1.00); }
.clippy-costume-cone      { transform: translate(0, -32%) scale(1.00); }
.clippy-costume-pirate    { transform: translate(0, -22%) scale(1.10); }
.clippy-costume-cowboy    { transform: translate(0, -22%) scale(1.18); }
.clippy-costume-crown     { transform: translate(0, -16%) scale(1.00); }
.clippy-costume-tophat    { transform: translate(0, -28%) scale(0.85); }
.clippy-costume-santa     { transform: translate(0, -22%) scale(1.05); }
.clippy-costume-graduation{ transform: translate(0, -18%) scale(1.05); }
.clippy-costume-halo      { transform: translate(0, -28%) scale(1.00); }
.clippy-costume-devil-horns { transform: translate(0, -22%) scale(0.85); }


/* ════════════════════════════════════════════════════════════════════
   SPEECH BUBBLE — Comic Sans, sits next to him
   ════════════════════════════════════════════════════════════════════ */
.clippy-bubble {
  position: fixed;
  z-index: 100;
  max-width: 280px;
  min-width: 220px;
  background: #fffef6;
  color: #1a1a1a;
  border: 2.5px solid #1a1a1a;
  border-radius: 14px;
  padding: 12px 14px;
  font-family: 'Comic Sans MS', 'Comic Sans', 'Marker Felt', cursive;
  font-size: 14.5px;
  line-height: 1.4;
  box-shadow: 4px 4px 0 #1a1a1a, 0 8px 24px rgba(0,0,0,0.25);
  pointer-events: auto;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px) scale(0.94);
  /* v17.18 — bubble follows shell with smooth transit: position transitions
     during movement, opacity/scale on appear/disappear */
  transition: opacity 220ms ease,
              transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1),
              top 600ms cubic-bezier(0.4, 0, 0.2, 1),
              left 600ms cubic-bezier(0.4, 0, 0.2, 1);
}
.clippy-bubble.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}
/* v18.2: when a game is open, any bubble that DOES manage to fire
   (e.g. game-over toast, high-score celebration) should appear ABOVE
   the game overlay, not behind it. Game overlay is z-index 999. */
body.clippy-game-open .clippy-bubble {
  z-index: 1100 !important;
}
.clippy-bubble::before,
.clippy-bubble::after {
  content: '';
  position: absolute;
  width: 0;
  height: 0;
  border-style: solid;
}
/* Tail pointing DOWN (bubble is ABOVE Trajan) — arrow at bubble's bottom */
.clippy-bubble.tail-right::before {
  bottom: -16px;
  right: 28px;
  border-width: 16px 14px 0 0;
  border-color: rgba(212,164,78,0.30) transparent transparent transparent;   /* v348: gold frame tone */
}
.clippy-bubble.tail-right::after {
  bottom: -12px;
  right: 30px;
  border-width: 12px 11px 0 0;
  border-color: rgba(20,17,12,0.99) transparent transparent transparent;   /* v348: match the dark espresso bubble body (was cream #fffef6, wrong since the body was redefined dark) */
}
.clippy-bubble.tail-left::before {
  bottom: -16px;
  left: 28px;
  border-width: 16px 0 0 14px;
  border-color: rgba(212,164,78,0.30) transparent transparent transparent;   /* v348: gold frame tone, matching the bubble's inset gold frame */
}
.clippy-bubble.tail-left::after {
  bottom: -12px;
  left: 30px;
  border-width: 12px 0 0 11px;
  border-color: rgba(20,17,12,0.99) transparent transparent transparent;   /* v348: dark body */
}
/* v17.24 — Tail pointing UP (bubble is BELOW Trajan) — arrow at bubble's top */
.clippy-bubble.tail-up-right::before {
  top: -16px;
  right: 28px;
  border-width: 0 14px 16px 0;
  border-color: transparent transparent rgba(212,164,78,0.30) transparent;   /* v348: gold frame tone */
}
.clippy-bubble.tail-up-right::after {
  top: -12px;
  right: 30px;
  border-width: 0 11px 12px 0;
  border-color: transparent transparent rgba(20,17,12,0.99) transparent;   /* v348: dark body */
}
.clippy-bubble.tail-up-left::before {
  top: -16px;
  left: 28px;
  border-width: 0 0 16px 14px;
  border-color: transparent transparent rgba(212,164,78,0.30) transparent;   /* v348: gold frame tone */
}
.clippy-bubble.tail-up-left::after {
  top: -12px;
  left: 30px;
  border-width: 0 0 12px 11px;
  border-color: transparent transparent rgba(20,17,12,0.99) transparent;   /* v348: dark body */
}
.clippy-bubble-close {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #fffef6;
  border: 2px solid #1a1a1a;
  color: #1a1a1a;
  font: 700 14px/1 inherit;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.clippy-bubble-text { margin-bottom: 8px; }
.clippy-bubble-text:last-child { margin-bottom: 0; }
.clippy-bubble-actions {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px;
}
.clippy-bubble-btn {
  flex: 1;
  min-width: 80px;
  padding: 8px 12px;
  background: #fffef6;
  border: 2px solid #1a1a1a;
  border-radius: 8px;
  font: 600 13px/1 inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 80ms ease, box-shadow 120ms;
  box-shadow: 2px 2px 0 #1a1a1a;
}
.clippy-bubble-btn:hover { background: #fff8d0; }
.clippy-bubble-btn:active { transform: translate(2px, 2px); box-shadow: 0 0 0 #1a1a1a; }
.clippy-bubble-btn.is-primary { background: #d4a44e; }
.clippy-bubble-btn.is-danger  { background: #fde2e2; }
.clippy-bubble-btn.is-warning-trajan { background: #f5e8d0; }

/* Trajan-mode bubble — black/gold mono */
.clippy-bubble.is-trajan {
  background: #0a0e16;
  color: #d4a44e;
  border-color: #d4a44e;
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  box-shadow: 4px 4px 0 #d4a44e, 0 8px 24px rgba(212,164,78,0.35);
}
.clippy-bubble.is-trajan .clippy-bubble-close {
  background: #0a0e16; border-color: #d4a44e; color: #d4a44e;
}
.clippy-bubble.is-trajan.tail-right::before { border-color: #d4a44e transparent transparent transparent; }
.clippy-bubble.is-trajan.tail-right::after  { border-color: #0a0e16 transparent transparent transparent; }
.clippy-bubble.is-trajan.tail-left::before  { border-color: #d4a44e transparent transparent transparent; }
.clippy-bubble.is-trajan.tail-left::after   { border-color: #0a0e16 transparent transparent transparent; }
.clippy-bubble-trajan-eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: #d4a44e;
  margin-bottom: 6px;
  opacity: 0.8;
}


/* ════════════════════════════════════════════════════════════════════
   COMMAND PALETTE — sliding sheet
   ════════════════════════════════════════════════════════════════════ */
.clippy-palette {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  pointer-events: auto;
}
.clippy-palette-bg {
  position: absolute; inset: 0;
  background: rgba(0,0,0,0.55);
  opacity: 0;
  transition: opacity 220ms ease;
}
.clippy-palette.is-open .clippy-palette-bg { opacity: 1; }
.clippy-palette-card {
  position: relative;
  width: 100%;
  max-width: 520px;
  max-height: 78vh;
  background: var(--surface, #141a2a);
  border: 1px solid var(--nx-highlight-line, rgba(212,164,78,0.22));
  border-radius: 16px 16px 0 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transform: translateY(100%);
  transition: transform 320ms cubic-bezier(0.34, 1.36, 0.64, 1);
}
.clippy-palette.is-open .clippy-palette-card { transform: translateY(0); }
.clippy-palette-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid rgba(212,164,78,0.10);
}
.clippy-palette-title {
  flex: 1;
  font: 600 16px 'Outfit', sans-serif;
  color: var(--text, #ece6d8);
}
.clippy-palette-close {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: transparent;
  border: 1px solid rgba(212,164,78,0.18);
  color: var(--nx-faint, #7a7167);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.clippy-palette-search {
  margin: 12px 14px 8px;
  padding: 11px 14px;
  background: var(--bg, #0a0e16);
  border: 1px solid rgba(212,164,78,0.18);
  border-radius: 10px;
  color: var(--text, #ece6d8);
  font: 14.5px 'Outfit', sans-serif;
}
.clippy-palette-search:focus {
  outline: none;
  border-color: var(--nx-gold, #d4a44e);
  box-shadow: 0 0 0 2px rgba(212,164,78,0.18);
}
.clippy-palette-results { flex: 1; overflow-y: auto; padding: 4px 8px 14px; }
.clippy-palette-section-label {
  padding: 10px 10px 4px;
  font: 700 10px/1 'JetBrains Mono', monospace;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--nx-gold, #d4a44e);
}
.clippy-palette-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 11px 12px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  text-align: left;
  cursor: pointer;
  margin-bottom: 2px;
}
.clippy-palette-item:hover {
  background: rgba(212,164,78,0.06);
  border-color: rgba(212,164,78,0.18);
}
.clippy-palette-item-icon {
  width: 28px; height: 28px;
  border-radius: 6px;
  background: rgba(212,164,78,0.10);
  color: var(--nx-gold);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.clippy-palette-item-body { flex: 1; min-width: 0; }
.clippy-palette-item-name {
  font: 600 14.5px 'Outfit', sans-serif;
  color: var(--text, #ece6d8);
}
.clippy-palette-item-hint {
  font-size: 11.5px;
  color: var(--nx-faint, #7a7167);
  margin-top: 2px;
}
.clippy-palette-empty {
  padding: 32px 20px;
  text-align: center;
  color: var(--nx-faint, #7a7167);
  font-size: 13px;
}


/* ════════════════════════════════════════════════════════════════════
   MUSIC PLAYER (inline in bubble)
   ════════════════════════════════════════════════════════════════════ */
.clippy-music-player {
  margin-top: 10px;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  background: rgba(212,164,78,0.10);
  border: 2px solid #1a1a1a;
  border-radius: 8px;
}
.clippy-music-btn {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: #fffef6;
  border: 2px solid #1a1a1a;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font: 14px inherit;
}
.clippy-music-progress {
  flex: 1; height: 5px;
  background: #1a1a1a;
  border-radius: 3px;
  overflow: hidden;
}
.clippy-music-progress-fill {
  height: 100%; width: 0;
  background: #d4a44e;
  transition: width 200ms linear;
}


/* ════════════════════════════════════════════════════════════════════
   RESPONSIVE
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 480px) {
  #clippy-shell {
    width: 102px;
    height: 102px;
  }
  .clippy-bubble {
    max-width: calc(100vw - 80px);
    font-size: 14px;
  }
}

@supports (padding: env(safe-area-inset-bottom)) {
  #clippy-shell {
    bottom: calc(16px + env(safe-area-inset-bottom));
    right: calc(16px + env(safe-area-inset-right));
  }
}


/* ════════════════════════════════════════════════════════════════════
   v15.5 — TICKLE / WHIMSY / INSPIRATION FROM THE BLUE-ORB VIBE
   ────────────────────────────────────────────────────────────────────
   Channel the cute-glowing-orb energy: subtle gold halo around Clippy
   when idle, bigger jiggle when tickled, blushing cheek hint, more
   personality in the chat bubble.
   ════════════════════════════════════════════════════════════════════ */

/* ─── TICKLE: jiggle when tapped 3 rapid times ─── */
.clippy-shell.is-ticklish {
  animation: clippy-jiggle 0.6s cubic-bezier(0.36, 0.07, 0.19, 0.97) !important;
  transform-origin: 50% 80%;
}
@keyframes clippy-jiggle {
  0%   { transform: rotate(0deg)   scale(1); }
  10%  { transform: rotate(-7deg)  scale(1.04); }
  22%  { transform: rotate(8deg)   scale(1.06); }
  35%  { transform: rotate(-6deg)  scale(1.05); }
  48%  { transform: rotate(5deg)   scale(1.04); }
  62%  { transform: rotate(-4deg)  scale(1.03); }
  76%  { transform: rotate(3deg)   scale(1.02); }
  88%  { transform: rotate(-1deg)  scale(1.01); }
  100% { transform: rotate(0deg)   scale(1); }
}

/* ─── HALO: subtle gold glow that pulses around Clippy when idle.
   Inspired by the user's reference image of the blue glowing orb —
   the magical-companion vibe. Keeps NEXUS gold palette though. */
#clippy-shell::before {
  content: '';
  position: absolute;
  inset: -16px;
  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 60%,
    rgba(212, 164, 78, 0.22) 0%,
    rgba(212, 164, 78, 0.10) 40%,
    rgba(212, 164, 78, 0)    72%
  );
  pointer-events: none;
  z-index: -1;
  animation: clippy-halo 4.2s ease-in-out infinite;
  opacity: 0.85;
}
@keyframes clippy-halo {
  0%, 100% { transform: scale(1.0);  opacity: 0.55; }
  50%      { transform: scale(1.08); opacity: 0.95; }
}
#clippy-shell.is-suppressed::before { opacity: 0; }
#clippy-shell.is-sleeping::before {
  animation-duration: 8s;
  opacity: 0.35;
}

/* When ticklish, halo flares brighter to match the giggle */
#clippy-shell.is-ticklish::before {
  background: radial-gradient(
    circle at 50% 60%,
    rgba(255, 220, 130, 0.45) 0%,
    rgba(212, 164, 78, 0.20) 45%,
    rgba(212, 164, 78, 0)    72%
  );
  opacity: 1;
}

/* ─── BUBBLE: more personality. Soft gradient, animated tail. ─── */
.clippy-bubble {
  /* Deep espresso with a soft gold sheen skimming the top edge, over a richer
     top-lit gradient — reads far more premium than the old flat muddy brown,
     while staying in the steward-gold-on-dark language (Alfredo: "improve the
     color"). A hairline top highlight + crisper gold inset frame add depth. */
  background:
    radial-gradient(130% 80% at 50% 0%, rgba(224, 178, 90, 0.12) 0%, rgba(224, 178, 90, 0) 58%),
    linear-gradient(180deg, rgba(38, 32, 23, 0.985) 0%, rgba(20, 17, 12, 0.99) 100%) !important;
  backdrop-filter: blur(12px) saturate(1.06);
  -webkit-backdrop-filter: blur(12px) saturate(1.06);
  box-shadow:
    0 18px 44px rgba(0, 0, 0, 0.60),
    0 3px 12px rgba(212, 164, 78, 0.20),
    0 0 0 1px rgba(212, 164, 78, 0.30) inset,
    0 1px 0 rgba(255, 236, 194, 0.10) inset !important;
}

/* Whimsical bounce on appear instead of a flat fade */
.clippy-bubble.is-visible {
  animation: clippy-bubble-pop 0.32s cubic-bezier(0.34, 1.56, 0.64, 1) backwards !important;
}
@keyframes clippy-bubble-pop {
  0%   { transform: translateY(8px) scale(0.86); opacity: 0; }
  70%  { transform: translateY(-2px) scale(1.04); opacity: 1; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

/* Gentle text shimmer — like little sparks of thought */
.clippy-bubble-text {
  position: relative;
  font-family: 'Outfit', system-ui, sans-serif;
  font-size: 14.5px;
  line-height: 1.45;
  color: #f4e8c8 !important;
  letter-spacing: 0.005em;
}

/* Eyebrow (Trajan label) — terminal mono */
.clippy-bubble-trajan-eyebrow {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9.5px !important;
  letter-spacing: 1.6px !important;
  color: rgba(212, 164, 78, 0.85) !important;
}

/* Action buttons inside the bubble — bigger touch targets */
.clippy-bubble-btn {
  font-family: 'Outfit', system-ui, sans-serif;
  font-size: 13px;
  font-weight: 600;
  padding: 8px 13px !important;
  border-radius: 9px !important;
  background: rgba(212, 164, 78, 0.12) !important;
  border: 1px solid rgba(212, 164, 78, 0.32) !important;
  color: #d4a44e !important;
  -webkit-tap-highlight-color: transparent;
  transition: background 120ms ease, transform 80ms ease;
}
.clippy-bubble-btn:hover {
  background: rgba(212, 164, 78, 0.22) !important;
}
.clippy-bubble-btn:active {
  transform: scale(0.96);
}
.clippy-bubble-btn.is-primary {
  background: linear-gradient(135deg, #d4a44e, #8b6914) !important;
  border-color: transparent !important;
  color: #101626 !important;
}

/* Close button — softer, more tactile */
.clippy-bubble-close {
  background: rgba(212, 164, 78, 0.14) !important;
  border: 1px solid rgba(212, 164, 78, 0.30) !important;
  color: rgba(212, 164, 78, 0.80) !important;
  width: 22px !important;
  height: 22px !important;
  border-radius: 50% !important;
  font-size: 14px !important;
  line-height: 1 !important;
  transition: background 120ms ease;
}
.clippy-bubble-close:hover {
  background: rgba(212, 164, 78, 0.28) !important;
}

/* ─── Reduced motion respect ─── */
@media (prefers-reduced-motion: reduce) {
  .clippy-shell.is-ticklish { animation: none !important; }
  #clippy-shell::before     { animation: none !important; }
  .clippy-bubble.is-visible { animation: none !important; }
}


/* ════════════════════════════════════════════════════════════════════
   v15.6 — SMOOTH MOVEMENT, DRAG, MORE LIFE
   ════════════════════════════════════════════════════════════════════ */

/* ─── SMOOTH SLIDE: when Clippy moveTo()'s, glide instead of teleport.
   Disabled during active drag so dragging stays 1:1 with the pointer.
   Cubic-bezier with overshoot for personality. */
#clippy-shell {
  transition:
    left 540ms cubic-bezier(0.34, 1.32, 0.64, 1),
    top  540ms cubic-bezier(0.34, 1.32, 0.64, 1),
    opacity 200ms ease,
    filter  200ms ease;
}
#clippy-shell.is-dragging {
  transition: none !important;
  cursor: grabbing !important;
  filter: drop-shadow(0 12px 16px rgba(212, 164, 78, 0.42));
}
#clippy-shell.is-dragging::before {
  /* extra-bright halo while being carried */
  background: radial-gradient(
    circle at 50% 60%,
    rgba(255, 220, 130, 0.55) 0%,
    rgba(212, 164, 78, 0.25) 45%,
    rgba(212, 164, 78, 0)    72%
  ) !important;
  opacity: 1 !important;
}

/* Cursor hint — grab when hovering, grabbing when dragging */
#clippy-shell {
  cursor: grab;
}

/* While suppressed (modal open), don't slide either — instant fade out */
#clippy-shell.is-suppressed {
  transition: opacity 200ms ease, transform 200ms ease;
}


/* ════════════════════════════════════════════════════════════════════
   v16 — ORB REMODEL VISUALS
   The clippy-shell is now a glowing orb. New animated layers:
     • .cl-halo            — pulsing outer glow (radial-gradient circle)
     • .cl-nodes  — 7 orbiting satellite nodes + constellation
                             lines, slow rotation around center
     • .cl-tendrils        — 4 electric tendrils, subtle flicker
     • .cl-body            — main orb, gentle breathing scale
     • .cl-cheek           — pink blush, gentle pulse
     • .cl-glint           — eye-shine micro-float, makes him alive
   The OLD .clippy-shell::before halo (paperclip-gold) is overridden
   here to a soft cyan that complements the new SVG halo.
   ════════════════════════════════════════════════════════════════════ */

/* Override the legacy gold halo to cool cyan, behind the orb.
   v17.4 fix: keep the ORIGINAL 'clippy-halo' animation (scale only,
   no translate). My v16 override added translate(-50%, -50%) which
   broke the inset-based positioning and pushed the halo up-left,
   creating the visible offset glow blob. Now: color change only. */
#clippy-shell::before {
  background: radial-gradient(
    circle at 50% 50%,
    rgba(76, 182, 255, 0.32) 0%,
    rgba(46, 141, 224, 0.16) 40%,
    rgba(46, 141, 224, 0)    72%
  ) !important;
}

/* Inner SVG halo (the circle inside the SVG itself) — soft pulse */
.cl-halo {
  transform-origin: 100px 100px;
  animation: clippy-svghalo-pulse 4.8s ease-in-out infinite;
}
@keyframes clippy-svghalo-pulse {
  0%, 100% { opacity: 0.85; transform: scale(1.00); }
  50%      { opacity: 1.00; transform: scale(1.04); }
}

/* v17.15 MOOD WEATHER — halo glow color shifts with dominant feeling.
   JS sets --mood-weather on #clippy-shell based on dominantFeeling().
   The body picks up a soft drop-shadow tint matching the mood. */
#clippy-shell {
  --mood-weather: #7df0ff;
  /* v348: removed a filter-only `transition` here — it (and the later 1.4s one) clobbered the
     position glide. The shell's transition is now consolidated in the mood-halo rule below. */
}
#clippy-shell .cl-body {
  filter: drop-shadow(0 0 8px var(--mood-weather));
  transition: filter 1.2s ease;
}

/* v17.4: Orbital rotation around orb center (100,100).
   Each node has its own speed/direction so the cluster looks chaotic-
   organic, not robotically synchronized. Inner-orbit nodes (5,6,7) visibly
   pass OVER the body as they swing around; outer ones (1-4) orbit around.
   Direction varies (some reverse) for visual richness. */
.cl-node {
  transform-origin: 100px 100px;
  transform-box: view-box;
}
.cl-node-1 { animation: clOrbit 18s linear infinite; }
.cl-node-2 { animation: clOrbit 22s linear infinite reverse; animation-delay: -4s; }
.cl-node-3 { animation: clOrbit 26s linear infinite; animation-delay: -10s; }
.cl-node-4 { animation: clOrbit 20s linear infinite reverse; animation-delay: -7s; }
.cl-node-5 { animation: clOrbit 15s linear infinite; animation-delay: -2s; }
.cl-node-6 { animation: clOrbit 12s linear infinite reverse; animation-delay: -5s; }
.cl-node-7 { animation: clOrbit 14s linear infinite; animation-delay: -8s; }

@keyframes clOrbit {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Electric tendrils — subtle flicker so they feel alive but not noisy */
.cl-tendrils {
  animation: clippy-tendril-flicker 1.9s ease-in-out infinite;
}
.cl-tendril-2 { animation-delay: 0.25s; }
.cl-tendril-3 { animation-delay: 0.55s; }
.cl-tendril-4 { animation-delay: 0.85s; }
@keyframes clippy-tendril-flicker {
  0%, 100% { opacity: 0.55; }
  30%      { opacity: 0.30; }
  60%      { opacity: 0.75; }
}

/* The body itself — very subtle breathing scale */
.cl-body {
  transform-origin: 100px 100px;
  transform-box: fill-box;
  animation: clippy-body-breathe 5.2s ease-in-out infinite;
}
@keyframes clippy-body-breathe {
  0%, 100% { transform: scale(1.000); }
  50%      { transform: scale(1.012); }
}

/* Cheek blush — soft pulse, gives him warmth */
.cl-cheek {
  animation: clippy-cheek-pulse 3.4s ease-in-out infinite;
}
@keyframes clippy-cheek-pulse {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1.00; }
}

/* Glints — tiny float so eyes feel wet/alive.
   v330: the float animation used to fully OVERRIDE the cursor-gaze translate on .cl-glint (the
   kawaii regen made the pupil invisible, so nothing tracked the cursor). Fold the gaze offset
   (--eye-x/--eye-y, set by updateGaze) INTO the keyframes so the glints both float AND follow. */
.cl-glint {
  animation: clippy-glint-float 2.6s ease-in-out infinite;
}
@keyframes clippy-glint-float {
  0%, 100% { transform: translate(calc(var(--eye-x, 0) * 1px), calc(var(--eye-y, 0) * 1px)); }
  50%      { transform: translate(calc(var(--eye-x, 0) * 1px), calc(var(--eye-y, 0) * 1px - 0.4px)); }
}
/* v330: pupil catchlight — slightly lighter than the #0a0d1f iris so its gaze translate is visible
   (near-invisible at rest, catches the light as it shifts toward the eye's edge). */
.clippy-svg .cl-pupil { fill: #26305a; }

/* When SUPPRESSED (modal open), pause the heavier animations */
#clippy-shell.is-suppressed .cl-nodes,
#clippy-shell.is-suppressed .cl-tendrils,
#clippy-shell.is-suppressed .cl-body,
#clippy-shell.is-suppressed .cl-halo {
  animation-play-state: paused;
}

/* When DRAGGING, freeze the orbital animation (visually correct: a real
   dragged object's satellites would tag along, not keep spinning) */
#clippy-shell.is-dragging .cl-node {
  animation-play-state: paused;
}

/* Mood: surprised → nodes scatter faster, halo brighter */
#clippy-shell.is-surprised .cl-node {
  animation-duration: 3s;
}
#clippy-shell.is-surprised .cl-halo {
  filter: brightness(1.4) saturate(1.3);
}

/* Mood: happy → cheeks deepen, halo warms */
#clippy-shell.is-happy .cl-cheek {
  opacity: 1;
  filter: brightness(1.15);
}

/* Mood: sleeping → halo dims, body fades slightly, nodes slow way down */
#clippy-shell.is-sleeping .cl-halo {
  opacity: 0.3;
}
#clippy-shell.is-sleeping .cl-node {
  animation-duration: 30s;
}
#clippy-shell.is-sleeping .cl-tendrils {
  opacity: 0.15;
}

/* Reduced-motion users: stop all the spinning/pulsing, keep static */
@media (prefers-reduced-motion: reduce) {
  .cl-halo,
  .cl-nodes,
  .cl-node,
  .cl-tendrils,
  .cl-body,
  .cl-cheek,
  .cl-glint,
  #clippy-shell::before {
    animation: none !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   v17.16 KAWAII FACE LIBRARY — 22 new compound expressions composing
   the new SVG building blocks into recognizable faces from the
   reference sheet.
   ════════════════════════════════════════════════════════════════════ */

/* CRYING — sad eyes with a single shiny tear + frown */
#clippy-shell.is-crying .cl-eyes-default { opacity: 0; }
#clippy-shell.is-crying .cl-eyes-tearful { opacity: 1; }
#clippy-shell.is-crying .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-crying .cl-mouth-frown { opacity: 1; }
#clippy-shell.is-crying .cl-tear { opacity: 1; }

/* SOBBING — shut eyes squeezed + frown + streaming tears */
#clippy-shell.is-sobbing .cl-eyes-default { opacity: 0; }
#clippy-shell.is-sobbing .cl-eyes-shut { opacity: 1; }
#clippy-shell.is-sobbing .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-sobbing .cl-mouth-frown { opacity: 1; }
#clippy-shell.is-sobbing .cl-tears-stream { opacity: 1; }


/* WAILING — shut eyes + open laugh mouth + streaming tears (anime sob) */
#clippy-shell.is-wailing .cl-eyes-default { opacity: 0; }
#clippy-shell.is-wailing .cl-eyes-shut { opacity: 1; }
#clippy-shell.is-wailing .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-wailing .cl-mouth-laugh { opacity: 1; }
#clippy-shell.is-wailing .cl-tears-stream { opacity: 1; }

/* POUTY — default eyes + small puckered mouth */
#clippy-shell.is-pouty .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-pouty .cl-mouth-pout { opacity: 1; }

/* GASP — dot eyes + O mouth + sweat */
#clippy-shell.is-gasp .cl-eyes-default { opacity: 0; }
#clippy-shell.is-gasp .cl-eyes-dots { opacity: 1; }
#clippy-shell.is-gasp .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-gasp .cl-mouth-o { opacity: 1; }
#clippy-shell.is-gasp .cl-sweat { opacity: 1; }

/* SHOCKED — wide-shock eyes + flat mouth */
#clippy-shell.is-shocked .cl-eyes-default { opacity: 0; }
#clippy-shell.is-shocked .cl-eyes-wide-shock { opacity: 1; }
#clippy-shell.is-shocked .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-shocked .cl-mouth-o { opacity: 1; }

/* EYE-ROLL — looking up + flat mouth (unimpressed) */
#clippy-shell.is-eye-roll .cl-eyes-default { opacity: 0; }
#clippy-shell.is-eye-roll .cl-eyes-up { opacity: 1; }
#clippy-shell.is-eye-roll .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-eye-roll .cl-mouth-flat { opacity: 1; }

/* PEEVED — looking down + frown */
#clippy-shell.is-peeved .cl-eyes-default { opacity: 0; }
#clippy-shell.is-peeved .cl-eyes-down { opacity: 1; }
#clippy-shell.is-peeved .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-peeved .cl-mouth-frown { opacity: 1; }

/* DROOLING — happy eyes + saliva drip (anime "delicious!") */
#clippy-shell.is-drooling .cl-eyes-default { opacity: 0; }
#clippy-shell.is-drooling .cl-eyes-happy { opacity: 1; }
#clippy-shell.is-drooling .cl-drool { opacity: 1; }

/* LAUGHING-HARD — squint XX eyes + open laugh mouth */
#clippy-shell.is-laughing .cl-eyes-default { opacity: 0; }
#clippy-shell.is-laughing .cl-eyes-squint { opacity: 1; }
#clippy-shell.is-laughing .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-laughing .cl-mouth-laugh { opacity: 1; }

/* SUPER-EXCITED — sparkle eyes + open laugh */
#clippy-shell.is-super-excited .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-super-excited .cl-mouth-laugh { opacity: 1; }
#clippy-shell.is-super-excited .cl-eyes-sparkle { opacity: 1; }

/* MORTIFIED — wide shock + tape mouth + extra blush */
#clippy-shell.is-mortified .cl-eyes-default { opacity: 0; }
#clippy-shell.is-mortified .cl-eyes-wide-shock { opacity: 1; }
#clippy-shell.is-mortified .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-mortified .cl-mouth-tape { opacity: 1; }
#clippy-shell.is-mortified .cl-cheek { opacity: 1; filter: saturate(2.3) brightness(1.05); }

/* FRUSTRATED — angry brows + flat mouth + sweat drop */
#clippy-shell.is-frustrated .cl-eyes-default { opacity: 0; }
#clippy-shell.is-frustrated .cl-eyes-angry { opacity: 1; }
#clippy-shell.is-frustrated .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-frustrated .cl-mouth-flat { opacity: 1; }
#clippy-shell.is-frustrated .cl-sweat { opacity: 1; }

/* TIPSY — happy eyes + red clown nose */
#clippy-shell.is-tipsy .cl-eyes-default { opacity: 0; }
#clippy-shell.is-tipsy .cl-eyes-happy { opacity: 1; }
#clippy-shell.is-tipsy .cl-red-nose { opacity: 1; }

/* SINGING-STAR — shut eyes + star mouth + music notes */
#clippy-shell.is-singing-star .cl-eyes-default { opacity: 0; }
#clippy-shell.is-singing-star .cl-eyes-shut { opacity: 1; }
#clippy-shell.is-singing-star .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-singing-star .cl-mouth-star { opacity: 1; }
#clippy-shell.is-singing-star .cl-music { opacity: 1; }

/* MELANCHOLY — looking down + small smile (bittersweet) */
#clippy-shell.is-melancholy .cl-eyes-default { opacity: 0; }
#clippy-shell.is-melancholy .cl-eyes-down { opacity: 1; }

/* BASHFUL — glance away eyes + smile + heart blush */
#clippy-shell.is-bashful .cl-eyes-default { opacity: 0; }
#clippy-shell.is-bashful .cl-eyes-glance { opacity: 1; }
#clippy-shell.is-bashful .cl-cheek { opacity: 1; filter: saturate(2.5) brightness(1.1); }

/* SMITTEN — heart eyes + heart blush (deeper than love) */
#clippy-shell.is-smitten .cl-eyes-default { opacity: 0; }
#clippy-shell.is-smitten .cl-eyes-love { opacity: 1; }
#clippy-shell.is-smitten .cl-heart-blush { opacity: 1; }
#clippy-shell.is-smitten .cl-cheek { opacity: 0; }

/* v339 — BUNNY mouth deleted (Alfredo: "mouth bunny is horrendous. delete").
   The is-bunny state was already retired (the 'bunny' mood maps to is-happy). */

/* STUNNED — wide-shock eyes + tape mouth */
#clippy-shell.is-stunned .cl-eyes-default { opacity: 0; }
#clippy-shell.is-stunned .cl-eyes-wide-shock { opacity: 1; }
#clippy-shell.is-stunned .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-stunned .cl-mouth-tape { opacity: 1; }

/* PROUD — shut crescents + big smile (smug+happy combo) */
#clippy-shell.is-proud .cl-eyes-default { opacity: 0; }
#clippy-shell.is-proud .cl-eyes-shut { opacity: 1; }
#clippy-shell.is-proud .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-proud .cl-mouth-bigsmile { opacity: 1; }

/* DISAPPOINTED — sleepy half-lids + frown */
#clippy-shell.is-disappointed .cl-eyes-default { opacity: 0; }
#clippy-shell.is-disappointed .cl-eyes-sleepy { opacity: 1; }
#clippy-shell.is-disappointed .cl-mouth-smile { opacity: 0; }
#clippy-shell.is-disappointed .cl-mouth-frown { opacity: 1; }

/* ════════════════════════════════════════════════════════════════════
   v17.17 CONTEXT PERSONALITIES — emotional modes tied to NEXUS views
   ════════════════════════════════════════════════════════════════════ */

/* GENIUS — equipment mode. Focused eyes + cyan glow rings + flat mouth.
   Activates when user is in Equipment view. */
#clippy-shell.is-genius .cl-eyes-default { opacity: 0; }
#clippy-shell.is-genius .cl-eyes-genius  { opacity: 1; }
#clippy-shell.is-genius .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-genius .cl-mouth-flat   { opacity: 1; }

/* DISGUSTED — cleaning mode. Squinted skeptical eyes + sweat drop.
   Activates when user is in Duties view or cleaning_gross fires. */
#clippy-shell.is-disgusted .cl-eyes-default   { opacity: 0; }
#clippy-shell.is-disgusted .cl-eyes-disgusted { opacity: 1; }
#clippy-shell.is-disgusted .cl-mouth-smile    { opacity: 0; }
#clippy-shell.is-disgusted .cl-mouth-wavy     { opacity: 1; }
#clippy-shell.is-disgusted .cl-sweat          { opacity: 1; }

/* STUDIOUS — education mode. Reading glasses + small focused eyes +
   bunny tooth smile (cute scholar). Activates in Education view. */
#clippy-shell.is-studious .cl-eyes-default { opacity: 0; }
#clippy-shell.is-studious .cl-eyes-studious{ opacity: 1; }
/* v339 — studious kept its reading glasses but the bunny-tooth mouth is gone;
   it now wears the default smile (the hide-smile + show-bunny pair was removed). */

/* STRATEGIST — board mode. Determined + cat smirk. */
#clippy-shell.is-strategist .cl-eyes-default    { opacity: 0; }
#clippy-shell.is-strategist .cl-eyes-determined { opacity: 1; }
#clippy-shell.is-strategist .cl-mouth-smile     { opacity: 0; }
#clippy-shell.is-strategist .cl-mouth-cat       { opacity: 1; }

/* ORGANIZED — inventory mode. Dot eyes + cat smile (peaceful order). */
#clippy-shell.is-organized .cl-eyes-default { opacity: 0; }
#clippy-shell.is-organized .cl-eyes-dots    { opacity: 1; }
#clippy-shell.is-organized .cl-mouth-smile  { opacity: 0; }
#clippy-shell.is-organized .cl-mouth-cat    { opacity: 1; }

/* ════════════════════════════════════════════════════════════════════
   v17.18 NEXUS MISCHIEF VISUALS — applied to elements Trajan touches.
   These classes get added TEMPORARILY to NEXUS DOM elements (not the
   shell) when he pokes/checks/drags them. Always non-destructive: the
   classes only affect appearance, never persist, never change data.
   ════════════════════════════════════════════════════════════════════ */

/* When Trajan "pokes" a status pill, it wiggles + flashes gold */
.is-trajan-poked {
  animation: trajanPoke 1.4s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
  position: relative;
}
.is-trajan-poked::after {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: inherit;
  box-shadow: 0 0 0 3px rgba(212, 164, 78, 0.7);
  animation: trajanPokeGlow 1.4s ease-out;
  pointer-events: none;
}
@keyframes trajanPoke {
  0%, 100% { transform: scale(1) rotate(0); }
  20%      { transform: scale(1.12) rotate(-3deg); }
  40%      { transform: scale(0.96) rotate(2deg); }
  60%      { transform: scale(1.08) rotate(-2deg); }
  80%      { transform: scale(1.02) rotate(1deg); }
}
@keyframes trajanPokeGlow {
  0%   { opacity: 0; transform: scale(0.85); }
  30%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.3); }
}

/* When Trajan "ghost-checks" a clean task, a temporary ✓ floats above it */
.is-trajan-ghost-check {
  position: relative;
}
.is-trajan-ghost-check::before {
  content: '✓';
  position: absolute;
  top: -8px;
  right: -8px;
  z-index: 999;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #d4a44e;
  color: #1a1a1a;
  font-weight: 900;
  font-size: 16px;
  line-height: 24px;
  text-align: center;
  box-shadow: 2px 2px 0 #1a1a1a;
  animation: trajanGhostCheck 2.2s cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}
@keyframes trajanGhostCheck {
  0%   { opacity: 0; transform: scale(0) rotate(-180deg); }
  20%  { opacity: 1; transform: scale(1.2) rotate(0); }
  70%  { opacity: 1; transform: scale(1) rotate(10deg); }
  100% { opacity: 0; transform: scale(0.8) translateY(-12px) rotate(20deg); }
}

/* When Trajan "pretends to drag" a board card, it tilts + lifts shadow */
.is-trajan-grabbing {
  animation: trajanGrab 2.2s ease-in-out !important;
  position: relative;
  z-index: 50;
}
@keyframes trajanGrab {
  0%, 100% { transform: rotate(0) translateY(0); box-shadow: 0 2px 6px rgba(0,0,0,0.1); }
  20%      { transform: rotate(-3deg) translateY(-6px); box-shadow: 0 8px 20px rgba(0,0,0,0.25); }
  50%      { transform: rotate(4deg) translateY(-8px); box-shadow: 0 12px 28px rgba(0,0,0,0.3); }
  80%      { transform: rotate(-2deg) translateY(-3px); box-shadow: 0 6px 16px rgba(0,0,0,0.2); }
}

/* When Trajan "counts" an inventory item, a tally counter ticks up */
.is-trajan-counting {
  position: relative;
}
.is-trajan-counting::after {
  content: '...';
  position: absolute;
  top: -4px;
  left: -4px;
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 11px;
  color: #d4a44e;
  text-shadow: 1px 1px 0 #1a1a1a;
  animation: trajanCount 1.8s ease-in-out;
  pointer-events: none;
}
@keyframes trajanCount {
  0%   { opacity: 0; transform: translateY(0); }
  20%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-20px); }
}

/* v17.18 BORED state — slow pulse on the body, sleepy idle look */
#clippy-shell.is-bored .cl-body {
  animation: trajanBoredPulse 4s ease-in-out infinite;
}
@keyframes trajanBoredPulse {
  0%, 100% { filter: drop-shadow(0 0 4px rgba(125, 240, 255, 0.4)) saturate(0.85); }
  50%      { filter: drop-shadow(0 0 8px rgba(125, 240, 255, 0.6)) saturate(1); }
}

/* ════════════════════════════════════════════════════════════════════
   v17.19 GAMES UI — full-screen game overlay
   ════════════════════════════════════════════════════════════════════ */

.clippy-game-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: rgba(10, 12, 24, 0.92);
  backdrop-filter: blur(8px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  font-family: 'Outfit', 'DM Sans', sans-serif;
  color: #fffef6;
  text-align: center;
  opacity: 0;
  transition: opacity 280ms ease;
}
.clippy-game-overlay.is-visible { opacity: 1; }

.clippy-game-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.18em;
  color: #d4a44e;
  text-transform: uppercase;
  margin-bottom: 12px;
}
.clippy-game-instruction {
  font-size: 17px;
  font-weight: 600;
  margin-bottom: 32px;
  max-width: 320px;
  line-height: 1.4;
}
.clippy-game-stat {
  font-family: 'JetBrains Mono', monospace;
  font-size: 48px;
  font-weight: 700;
  color: #fffef6;
  margin: 16px 0;
  letter-spacing: 0.05em;
}
.clippy-game-stat-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  color: rgba(255, 254, 246, 0.6);
  text-transform: uppercase;
}
.clippy-game-timer {
  font-family: 'JetBrains Mono', monospace;
  font-size: 32px;
  font-weight: 700;
  color: #d4a44e;
  margin: 16px 0 8px;
}
.clippy-game-board {
  position: relative;
  width: min(80vw, 400px);
  height: min(80vw, 400px);
  margin: 24px auto;
  border: 2px dashed rgba(212, 164, 78, 0.4);
  border-radius: 16px;
}
.clippy-game-target {
  position: absolute;
  width: 80px;
  height: 80px;
  background: radial-gradient(circle, #4cb6ff 0%, #2e8de0 100%);
  border-radius: 50%;
  cursor: pointer;
  transition: top 80ms ease-out, left 80ms ease-out, transform 120ms ease;
  box-shadow: 0 0 16px rgba(125, 240, 255, 0.6), 4px 4px 0 #1a1a1a;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  user-select: none;
}
.clippy-game-target:hover { transform: scale(1.05); }
.clippy-game-target:active { transform: scale(0.92); }
.clippy-game-target.is-go { background: radial-gradient(circle, #5fff8a 0%, #1aa848 100%); box-shadow: 0 0 24px #5fff8a, 4px 4px 0 #1a1a1a; }
.clippy-game-target.is-wait { background: radial-gradient(circle, #ff5577 0%, #c62a4a 100%); box-shadow: 0 0 16px rgba(255, 85, 119, 0.6), 4px 4px 0 #1a1a1a; }

.clippy-game-buttons {
  display: flex;
  gap: 12px;
  margin-top: 24px;
}
.clippy-game-btn {
  background: #d4a44e;
  color: #1a1a1a;
  border: 2px solid #1a1a1a;
  border-radius: 10px;
  padding: 10px 22px;
  font-family: 'Outfit', sans-serif;
  font-weight: 700;
  font-size: 15px;
  cursor: pointer;
  box-shadow: 3px 3px 0 #1a1a1a;
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.clippy-game-btn:hover { transform: translate(-1px, -1px); box-shadow: 4px 4px 0 #1a1a1a; }
.clippy-game-btn:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 #1a1a1a; }
.clippy-game-btn.is-ghost {
  background: transparent;
  color: #fffef6;
  border-color: rgba(255, 254, 246, 0.4);
  box-shadow: none;
}

.clippy-game-seq {
  display: flex;
  gap: 16px;
  margin: 24px 0;
}
.clippy-game-seq-cell {
  width: 60px;
  height: 60px;
  border-radius: 12px;
  border: 2px solid rgba(212, 164, 78, 0.5);
  background: rgba(255, 254, 246, 0.05);
  transition: all 200ms ease;
}
.clippy-game-seq-cell.is-flash-r { background: #ff5577; transform: scale(1.15); }
.clippy-game-seq-cell.is-flash-g { background: #5fff8a; transform: scale(1.15); }
.clippy-game-seq-cell.is-flash-b { background: #4cb6ff; transform: scale(1.15); }
.clippy-game-seq-cell.is-flash-y { background: #ffd870; transform: scale(1.15); }

.clippy-game-highscore {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  color: rgba(212, 164, 78, 0.8);
  margin-top: 8px;
}
.clippy-game-highscore-new {
  color: #5fff8a;
  font-weight: 700;
  animation: highScorePulse 0.6s ease-in-out infinite alternate;
}
@keyframes highScorePulse {
  from { opacity: 0.7; transform: scale(1); }
  to   { opacity: 1;   transform: scale(1.05); }
}

/* ════════════════════════════════════════════════════════════════════
   v17.20 MOOD-REACTIVE HALO LIGHT — only the GLOW around him shifts
   color based on mood. The body stays its standard blue. The halo
   (outer drop-shadow on the shell + halo gradient opacity) is what
   reflects emotion. Like a mood ring around him, not changing him.
   ════════════════════════════════════════════════════════════════════ */

#clippy-shell {
  /* v348: this is the LAST #clippy-shell transition, so it wins — the old filter-only value
     silently clobbered the position glide + opacity fade from the base rule, making Clippy
     SNAP to new positions instead of gliding. Fold them back in (reuse --pos-transition). */
  transition: var(--pos-transition), opacity 280ms ease, filter 1.4s ease;
}

/* HAPPY family — warm gold glow */
#clippy-shell.is-happy,
#clippy-shell.is-laughing,
#clippy-shell.is-bunny { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 12px rgba(255, 216, 112, 0.7)); }

/* EXCITED / SUPER_EXCITED / SPARKLE / PROUD — bright triumphant gold */
#clippy-shell.is-excited,
#clippy-shell.is-super-excited,
#clippy-shell.is-sparkle,
#clippy-shell.is-proud { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 18px rgba(255, 216, 112, 0.9)) drop-shadow(0 0 28px rgba(255, 180, 50, 0.5)); }

/* LOVE family — pink glow */
#clippy-shell.is-love,
#clippy-shell.is-smitten,
#clippy-shell.is-kissy,
#clippy-shell.is-bashful,
#clippy-shell.is-embarrassed { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 14px rgba(255, 138, 204, 0.75)); }

/* SAD family — cool muted blue glow */
#clippy-shell.is-sad,
#clippy-shell.is-melancholy,
#clippy-shell.is-disappointed,
#clippy-shell.is-peeved,
#clippy-shell.is-worried { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 10px rgba(93, 122, 168, 0.55)); }

/* DEEP SAD — barely visible glow */
#clippy-shell.is-crying,
#clippy-shell.is-sobbing,
#clippy-shell.is-wailing { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 8px rgba(110, 112, 144, 0.4)); }

/* ANGRY — red glow */
#clippy-shell.is-angry,
#clippy-shell.is-frustrated { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 14px rgba(255, 70, 90, 0.75)); }

/* DISGUSTED — sickly green-grey glow */
#clippy-shell.is-disgusted { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 10px rgba(140, 180, 100, 0.55)); }

/* GENIUS — bright cyan glow */
#clippy-shell.is-genius { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 16px rgba(125, 240, 255, 0.85)) drop-shadow(0 0 28px rgba(125, 240, 255, 0.4)); }

/* STUDIOUS — soft purple glow */
#clippy-shell.is-studious { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 12px rgba(180, 130, 220, 0.65)); }

/* STRATEGIST — deep indigo glow */
#clippy-shell.is-strategist { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 12px rgba(130, 110, 200, 0.65)); }

/* ORGANIZED — soft teal glow */
#clippy-shell.is-organized { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 12px rgba(100, 200, 200, 0.65)); }

/* TIPSY — happy pink-red glow */
#clippy-shell.is-tipsy { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 14px rgba(255, 130, 170, 0.75)); }

/* SINGING — joyful gold + pink glow */
#clippy-shell.is-singing,
#clippy-shell.is-singing-star { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 14px rgba(255, 200, 130, 0.75)); }

/* DROOLING — soft pink glow */
#clippy-shell.is-drooling { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 12px rgba(255, 170, 200, 0.7)); }

/* SLEEPY family — barely-there dim glow */
#clippy-shell.is-sleeping,
#clippy-shell.is-sleepy { filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3)) drop-shadow(0 0 6px rgba(150, 160, 180, 0.3)); }

/* DIZZY — wild yellow-green glow */
#clippy-shell.is-dizzy { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 14px rgba(200, 230, 100, 0.75)); }

/* SHOCK family — bright white-ish glow */
#clippy-shell.is-shocked,
#clippy-shell.is-gasp,
#clippy-shell.is-stunned,
#clippy-shell.is-mortified { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 14px rgba(255, 255, 240, 0.85)); }

/* CONFUSED — slightly dim cyan glow */
#clippy-shell.is-confused { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 10px rgba(125, 200, 220, 0.55)); }

/* CONDESCENDING — cool authoritative purple glow */
#clippy-shell.is-condescending { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 12px rgba(160, 120, 200, 0.7)); }

/* THINKING / DETERMINED — focused cyan */
#clippy-shell.is-thinking,
#clippy-shell.is-determined { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 11px rgba(125, 240, 255, 0.5)); }

/* EYE-ROLL — mocking grey-blue */
#clippy-shell.is-eye-roll { filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45)) drop-shadow(0 0 10px rgba(140, 150, 170, 0.5)); }

/* ════════════════════════════════════════════════════════════════════
   v17.20 CONDESCENDING — face composition for "smug lesson" mode
   ════════════════════════════════════════════════════════════════════ */

#clippy-shell.is-condescending .cl-eyes-default    { opacity: 0; }
#clippy-shell.is-condescending .cl-eyes-condescend { opacity: 1; }
#clippy-shell.is-condescending .cl-mouth-smile     { opacity: 0; }
#clippy-shell.is-condescending .cl-mouth-cat       { opacity: 1; }


/* ════════════════════════════════════════════════════════════════════
   v17.20 MEMORY DEX — Pokemon-style grid of collected memory types
   ════════════════════════════════════════════════════════════════════ */

.clippy-dex-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: rgba(10, 12, 24, 0.94);
  backdrop-filter: blur(8px);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 28px 16px;
  overflow-y: auto;
  font-family: 'Outfit', 'DM Sans', sans-serif;
  color: #fffef6;
  opacity: 0;
  transition: opacity 280ms ease;
}
.clippy-dex-overlay.is-visible { opacity: 1; }

.clippy-dex-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.18em;
  color: #d4a44e;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.clippy-dex-headline {
  font-size: 22px;
  font-weight: 700;
  margin-bottom: 22px;
}
.clippy-dex-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 10px;
  width: 100%;
  max-width: 720px;
  padding: 8px;
}
.clippy-dex-card {
  background: rgba(255, 254, 246, 0.04);
  border: 1.5px solid rgba(212, 164, 78, 0.4);
  border-radius: 12px;
  padding: 12px 8px;
  text-align: center;
  transition: transform 160ms ease, border-color 160ms ease;
}
.clippy-dex-card.is-collected {
  background: rgba(212, 164, 78, 0.12);
  border-color: #d4a44e;
}
.clippy-dex-card.is-rare {
  background: linear-gradient(135deg, rgba(212, 164, 78, 0.18), rgba(125, 240, 255, 0.12));
  border-color: #7df0ff;
  box-shadow: 0 0 12px rgba(125, 240, 255, 0.3);
}
.clippy-dex-card-glyph { font-size: 28px; margin-bottom: 6px; }
.clippy-dex-card-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: rgba(255, 254, 246, 0.85);
  text-transform: uppercase;
}
.clippy-dex-card-count {
  font-family: 'JetBrains Mono', monospace;
  font-size: 16px;
  font-weight: 700;
  color: #d4a44e;
  margin-top: 4px;
}
.clippy-dex-card:not(.is-collected) {
  filter: grayscale(1);
  opacity: 0.45;
}

.clippy-dex-bond {
  background: rgba(212, 164, 78, 0.12);
  border: 1.5px solid #d4a44e;
  border-radius: 14px;
  padding: 18px 22px;
  margin: 8px auto 22px;
  text-align: center;
  max-width: 360px;
}
.clippy-dex-bond-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  color: rgba(255, 254, 246, 0.6);
  text-transform: uppercase;
  margin-bottom: 4px;
}
.clippy-dex-bond-level {
  font-size: 28px;
  font-weight: 800;
  color: #d4a44e;
  margin-bottom: 8px;
}
.clippy-dex-bond-bar {
  width: 100%;
  height: 10px;
  background: rgba(255, 254, 246, 0.1);
  border-radius: 5px;
  overflow: hidden;
}
.clippy-dex-bond-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #d4a44e, #ffd870);
  transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ════════════════════════════════════════════════════════════════════
   v17.21 MINI TRAJAN GAME TARGET — the actual orb is the click target.
   Wraps the full SVG markup (body, eyes, mouth, nodes, halo, shadow).
   Scaled to game size. Fully expressive — mood classes can apply here
   too via the mini-shell wrapper.
   ════════════════════════════════════════════════════════════════════ */

.clippy-mini-shell {
  position: absolute;
  width: 100px;
  height: 100px;
  cursor: pointer;
  user-select: none;
  transition: top 80ms ease-out, left 80ms ease-out, transform 140ms ease;
  filter: drop-shadow(0 0 14px rgba(125, 240, 255, 0.55)) drop-shadow(0 4px 10px rgba(0,0,0,0.45));
  display: flex;
  align-items: center;
  justify-content: center;
}
.clippy-mini-shell svg {
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.clippy-mini-shell:hover { transform: scale(1.05); }
.clippy-mini-shell.is-pop {
  animation: miniOrbPop 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes miniOrbPop {
  0%   { transform: scale(1); }
  40%  { transform: scale(0.78); }
  100% { transform: scale(1); }
}

/* Mood states on mini-shell — same classes as main shell, glow differently */
.clippy-mini-shell.is-go    { filter: drop-shadow(0 0 20px rgba(95, 255, 138, 0.95)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); }
.clippy-mini-shell.is-wait  { filter: drop-shadow(0 0 14px rgba(255, 85, 119, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); }
.clippy-mini-shell.is-genius { filter: drop-shadow(0 0 16px rgba(125, 240, 255, 0.85)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); }
.clippy-mini-shell.is-proud { filter: drop-shadow(0 0 18px rgba(255, 216, 112, 0.85)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); }

/* Memory cells in Memory game — use mini-orb but flash colors */
.clippy-mini-shell.is-flash-r { filter: drop-shadow(0 0 18px rgba(255, 85, 119, 0.9)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); transform: scale(1.1); }
.clippy-mini-shell.is-flash-g { filter: drop-shadow(0 0 18px rgba(95, 255, 138, 0.9)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); transform: scale(1.1); }
.clippy-mini-shell.is-flash-b { filter: drop-shadow(0 0 18px rgba(76, 182, 255, 0.9)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); transform: scale(1.1); }
.clippy-mini-shell.is-flash-y { filter: drop-shadow(0 0 18px rgba(255, 216, 112, 0.9)) drop-shadow(0 4px 10px rgba(0,0,0,0.45)); transform: scale(1.1); }

.clippy-mini-shell.is-tapped {
  animation: miniOrbTapped 280ms ease;
}
@keyframes miniOrbTapped {
  0%   { transform: scale(1) rotate(0); }
  35%  { transform: scale(0.7) rotate(-4deg); }
  70%  { transform: scale(1.12) rotate(2deg); }
  100% { transform: scale(1) rotate(0); }
}

/* ════════════════════════════════════════════════════════════════════
   v17.22 NEW GAMES — Flappy, Cannon Battle, Snake. Plus quirky idle
   animations (yawn, hiccup, sneeze, spin).
   ════════════════════════════════════════════════════════════════════ */

/* Flappy game — columns scroll right-to-left */
.clippy-flappy-board {
  position: relative;
  width: min(90vw, 420px);
  height: min(70vh, 500px);
  background: linear-gradient(180deg, #2a3f6a 0%, #4a6088 70%, #6b7a99 100%);
  border-radius: 16px;
  overflow: hidden;
  border: 2.5px solid #1a1a1a;
  box-shadow: 4px 4px 0 #1a1a1a;
  margin: 18px auto;
  touch-action: manipulation;
  user-select: none;
}
.clippy-flappy-column {
  position: absolute;
  width: 56px;
  background: linear-gradient(180deg, #c9a063 0%, #8b6f3d 100%);
  border-left: 3px solid #1a1a1a;
  border-right: 3px solid #1a1a1a;
  /* Roman column decoration */
  background-image:
    linear-gradient(180deg, #c9a063 0%, #8b6f3d 100%),
    repeating-linear-gradient(0deg,
      rgba(0,0,0,0.18) 0px, rgba(0,0,0,0.18) 2px,
      transparent 2px, transparent 14px);
}
.clippy-flappy-column-cap {
  position: absolute;
  width: 64px;
  height: 14px;
  left: -4px;
  background: #6b4a1f;
  border: 2px solid #1a1a1a;
}
.clippy-flappy-column.is-top .clippy-flappy-column-cap { bottom: -2px; }
.clippy-flappy-column.is-bot .clippy-flappy-column-cap { top: -2px; }
.clippy-flappy-bird {
  position: absolute;
  width: 60px;
  height: 60px;
  transition: transform 80ms ease-out;
  filter: drop-shadow(0 0 10px rgba(125, 240, 255, 0.6)) drop-shadow(0 4px 8px rgba(0,0,0,0.5));
  pointer-events: none;
  z-index: 5;
}
.clippy-flappy-bird svg { width: 100%; height: 100%; }
.clippy-flappy-ground {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 28px;
  background: repeating-linear-gradient(90deg, #4a6033 0px, #4a6033 12px, #3a5028 12px, #3a5028 24px);
  border-top: 3px solid #1a1a1a;
}
.clippy-flappy-score {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  font-family: 'JetBrains Mono', monospace;
  font-size: 38px;
  font-weight: 900;
  color: #fffef6;
  text-shadow: 3px 3px 0 #1a1a1a;
  z-index: 6;
  letter-spacing: 0.05em;
}

/* Cannon Battle */
.clippy-cannon-board {
  position: relative;
  width: min(90vw, 420px);
  height: min(70vh, 500px);
  background: linear-gradient(180deg, #06081a 0%, #0d1330 60%, #1a2548 100%);
  border-radius: 16px;
  overflow: hidden;
  border: 2.5px solid #1a1a1a;
  box-shadow: 4px 4px 0 #1a1a1a;
  margin: 18px auto;
  touch-action: none;
  user-select: none;
}
/* Starfield bg */
.clippy-cannon-board::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(2px 2px at 12% 25%, #ffffff, transparent),
    radial-gradient(1.5px 1.5px at 28% 67%, #d4a44e, transparent),
    radial-gradient(2px 2px at 58% 18%, #fffef6, transparent),
    radial-gradient(1.5px 1.5px at 78% 82%, #7df0ff, transparent),
    radial-gradient(2px 2px at 92% 42%, #ffffff, transparent),
    radial-gradient(1px 1px at 44% 50%, #d4a44e, transparent),
    radial-gradient(1.5px 1.5px at 36% 88%, #ffffff, transparent);
  opacity: 0.6;
}
.clippy-cannon-player {
  position: absolute;
  width: 60px;
  height: 60px;
  bottom: 20px;
  filter: drop-shadow(0 0 12px rgba(125, 240, 255, 0.7));
  z-index: 5;
  transition: left 60ms linear;
  pointer-events: none;
}
.clippy-cannon-enemy {
  position: absolute;
  width: 36px;
  height: 36px;
  background: radial-gradient(circle, #ff5577 0%, #c62a4a 100%);
  border-radius: 50%;
  border: 2px solid #1a1a1a;
  box-shadow: 0 0 10px rgba(255, 85, 119, 0.7);
  z-index: 3;
}
.clippy-cannon-enemy::after {
  content: '';
  position: absolute;
  top: 50%; left: 8px; right: 8px; height: 4px;
  background: rgba(0,0,0,0.5);
  transform: translateY(-50%);
  border-radius: 2px;
}
.clippy-cannon-bullet {
  position: absolute;
  width: 6px;
  height: 16px;
  background: linear-gradient(180deg, #ffd870 0%, #d4a44e 100%);
  border-radius: 3px;
  box-shadow: 0 0 8px #ffd870;
  z-index: 4;
}
.clippy-cannon-enemy-bullet {
  position: absolute;
  width: 5px;
  height: 14px;
  background: #ff5577;
  border-radius: 2.5px;
  box-shadow: 0 0 6px #ff5577;
  z-index: 4;
}
.clippy-cannon-explosion {
  position: absolute;
  width: 60px;
  height: 60px;
  pointer-events: none;
  z-index: 6;
  animation: cannonExplode 0.4s ease-out forwards;
}
.clippy-cannon-explosion::before,
.clippy-cannon-explosion::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, #ffd870 0%, #ff5577 50%, transparent 70%);
}
@keyframes cannonExplode {
  0%   { transform: scale(0.3); opacity: 1; }
  100% { transform: scale(1.5); opacity: 0; }
}
.clippy-cannon-hud {
  position: absolute;
  top: 12px;
  left: 12px;
  right: 12px;
  display: flex;
  justify-content: space-between;
  font-family: 'JetBrains Mono', monospace;
  font-size: 14px;
  color: #fffef6;
  text-shadow: 1px 1px 0 #1a1a1a;
  z-index: 7;
  pointer-events: none;
}
.clippy-cannon-hud .hud-stat {
  background: rgba(0,0,0,0.5);
  padding: 4px 10px;
  border-radius: 6px;
  border: 1px solid #d4a44e;
}

/* Snake */
.clippy-snake-board {
  position: relative;
  width: min(90vw, 400px);
  height: min(90vw, 400px);
  background: #0d1330;
  border-radius: 16px;
  overflow: hidden;
  border: 2.5px solid #1a1a1a;
  box-shadow: 4px 4px 0 #1a1a1a;
  margin: 18px auto;
  touch-action: none;
  user-select: none;
  background-image:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.03) 0px, rgba(255,255,255,0.03) 1px, transparent 1px, transparent 20px),
    repeating-linear-gradient(0deg, rgba(255,255,255,0.03) 0px, rgba(255,255,255,0.03) 1px, transparent 1px, transparent 20px);
}
.clippy-snake-cell {
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: radial-gradient(circle, #4cb6ff 0%, #2e8de0 100%);
  box-shadow: 0 0 8px rgba(125, 240, 255, 0.5);
}
.clippy-snake-head {
  width: 22px;
  height: 22px;
  background: radial-gradient(circle, #7df0ff 0%, #4cb6ff 100%);
  box-shadow: 0 0 12px rgba(125, 240, 255, 0.8);
  z-index: 3;
}
.clippy-snake-food {
  position: absolute;
  width: 16px;
  height: 16px;
  background: radial-gradient(circle, #ffd870 0%, #d4a44e 100%);
  border-radius: 50%;
  box-shadow: 0 0 10px #ffd870;
  animation: snakeFoodPulse 1s ease-in-out infinite;
}
@keyframes snakeFoodPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.2); }
}

/* Quirk animations on the main shell */
#clippy-shell.is-yawning .cl-floats { animation: orbYawn 1.6s ease-in-out; }
@keyframes orbYawn {
  0%, 100% { transform: scale(1) translateY(0); }
  20%      { transform: scale(1.05, 0.95) translateY(2px); }
  50%      { transform: scale(0.92, 1.1) translateY(-4px); }
  80%      { transform: scale(1.08, 0.92) translateY(1px); }
}
#clippy-shell.is-hiccupping .cl-floats { animation: orbHiccup 0.4s ease-in-out 4; }
@keyframes orbHiccup {
  0%, 100% { transform: translateY(0); }
  40%      { transform: translateY(-8px) scale(1.06); }
  60%      { transform: translateY(-4px) scale(0.96); }
}
#clippy-shell.is-sneezing .cl-floats { animation: orbSneeze 0.5s ease-in-out; }
@keyframes orbSneeze {
  0%, 100% { transform: translateY(0) scale(1); }
  10%      { transform: translateY(2px) scale(0.92, 1.06); }
  30%      { transform: translateY(-12px) scale(1.15, 0.88); }
  60%      { transform: translateY(4px) scale(1.05, 0.96); }
}
#clippy-shell.is-spinning .cl-floats { animation: orbSpin 1.4s linear; }
@keyframes orbSpin {
  0%   { transform: rotate(0); }
  100% { transform: rotate(360deg); }
}

/* ════════════════════════════════════════════════════════════════════
   v17.23 SULKING MOOD — Duolingo-style turn-the-back. Hides face,
   shows back-of-head tuft, dims glow, slight side-tilt. He won't
   look at you until you earn forgiveness with multiple gentle taps.
   ════════════════════════════════════════════════════════════════════ */

/* Back-tuft is hidden by default */
.clippy-svg .cl-back-tuft { opacity: 0; transition: opacity 0.6s ease; }

/* When sulking: hide everything face-related, show the back-tuft */
#clippy-shell.is-sulking .cl-face,
#clippy-shell.is-sulking .cl-cheek,
#clippy-shell.is-sulking .cl-cheek-l,
#clippy-shell.is-sulking .cl-cheek-r,
#clippy-shell.is-sulking .cl-sweat,
#clippy-shell.is-sulking .cl-music,
#clippy-shell.is-sulking .cl-anger-pop,
#clippy-shell.is-sulking .cl-question,
#clippy-shell.is-sulking .cl-tear,
#clippy-shell.is-sulking .cl-tears-stream,
#clippy-shell.is-sulking .cl-drool,
#clippy-shell.is-sulking .cl-red-nose,
#clippy-shell.is-sulking .cl-heart-blush { opacity: 0 !important; }

#clippy-shell.is-sulking .cl-back-tuft {
  opacity: 1;
}

/* Slight away-tilt + dim glow */
#clippy-shell.is-sulking {
  filter: drop-shadow(0 4px 8px rgba(0,0,0,0.4)) drop-shadow(0 0 8px rgba(110, 112, 144, 0.4));
}
#clippy-shell.is-sulking .cl-floats {
  animation: orbSulkBreathe 4s ease-in-out infinite !important;
  transform-origin: 100px 100px;
}
@keyframes orbSulkBreathe {
  0%, 100% { transform: rotate(-4deg) translateY(2px); }
  50%      { transform: rotate(-6deg) translateY(0px); }
}

/* Tiny puff of disappointment when sulk starts */
#clippy-shell.is-sulking .cl-halo {
  opacity: 0.4 !important;
  animation: none !important;
}

/* Deep sulk: even dimmer, very dark */
#clippy-shell.is-deep-sulking {
  filter: drop-shadow(0 4px 8px rgba(0,0,0,0.5)) drop-shadow(0 0 4px rgba(60, 65, 90, 0.3)) !important;
}
#clippy-shell.is-deep-sulking .cl-halo { opacity: 0.2 !important; }

/* ════════════════════════════════════════════════════════════════════
   v17.24 GAME COUNTDOWN — big 3-2-1 number overlay before games start
   ════════════════════════════════════════════════════════════════════ */

.clippy-game-countdown {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'JetBrains Mono', monospace;
  font-size: 180px;
  font-weight: 900;
  color: #d4a44e;
  text-shadow:
    0 0 20px rgba(212, 164, 78, 0.8),
    0 0 40px rgba(212, 164, 78, 0.4),
    4px 4px 0 #1a1a1a;
  pointer-events: none;
  z-index: 10;
  animation: countdownPulse 1s ease-in-out;
}
@keyframes countdownPulse {
  0%   { transform: scale(0.4); opacity: 0; }
  30%  { transform: scale(1.2); opacity: 1; }
  70%  { transform: scale(1); opacity: 1; }
  100% { transform: scale(1.6); opacity: 0; }
}
.clippy-game-countdown.is-go {
  color: #5fff8a;
  text-shadow:
    0 0 24px rgba(95, 255, 138, 0.9),
    0 0 48px rgba(95, 255, 138, 0.5),
    4px 4px 0 #1a1a1a;
  font-size: 120px;
}

/* ════════════════════════════════════════════════════════════════════
   v17.24 MEMORY GAME — BIGGER, BRIGHTER, scaling orbs
   ════════════════════════════════════════════════════════════════════ */

.clippy-memory-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  justify-content: center;
  margin: 24px 0;
  max-width: 540px;
}
.clippy-memory-cell {
  position: relative;
  width: 96px;
  height: 96px;
  cursor: pointer;
  user-select: none;
  transition: transform 140ms ease, filter 200ms ease;
  filter: drop-shadow(0 0 8px rgba(125, 240, 255, 0.4)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
}
.clippy-memory-cell svg {
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.clippy-memory-cell:hover { transform: scale(1.08); }
.clippy-memory-cell:active { transform: scale(0.92); }
.clippy-memory-cell.is-disabled { pointer-events: none; opacity: 0.5; }
/* BRIGHT flash states — much stronger than v17.16 cell flashes */
.clippy-memory-cell.flash-r {
  filter: drop-shadow(0 0 28px rgba(255, 85, 119, 1)) drop-shadow(0 0 56px rgba(255, 85, 119, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-g {
  filter: drop-shadow(0 0 28px rgba(95, 255, 138, 1)) drop-shadow(0 0 56px rgba(95, 255, 138, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-b {
  filter: drop-shadow(0 0 28px rgba(76, 182, 255, 1)) drop-shadow(0 0 56px rgba(76, 182, 255, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-y {
  filter: drop-shadow(0 0 28px rgba(255, 216, 112, 1)) drop-shadow(0 0 56px rgba(255, 216, 112, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-p {
  filter: drop-shadow(0 0 28px rgba(195, 130, 255, 1)) drop-shadow(0 0 56px rgba(195, 130, 255, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-o {
  filter: drop-shadow(0 0 28px rgba(255, 150, 70, 1)) drop-shadow(0 0 56px rgba(255, 150, 70, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-c {
  filter: drop-shadow(0 0 28px rgba(125, 240, 255, 1)) drop-shadow(0 0 56px rgba(125, 240, 255, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-k {
  filter: drop-shadow(0 0 28px rgba(255, 138, 204, 1)) drop-shadow(0 0 56px rgba(255, 138, 204, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-cell.flash-w {
  filter: drop-shadow(0 0 28px rgba(255, 255, 255, 1)) drop-shadow(0 0 56px rgba(255, 255, 255, 0.7)) drop-shadow(0 4px 10px rgba(0,0,0,0.5));
  transform: scale(1.18);
}
.clippy-memory-level-banner {
  font-family: 'JetBrains Mono', monospace;
  font-size: 16px;
  letter-spacing: 0.12em;
  color: #d4a44e;
  margin-top: 8px;
  text-transform: uppercase;
}

/* ════════════════════════════════════════════════════════════════════
   v17.24 STREAK GACHA — daily pull animation + collection viewer
   ════════════════════════════════════════════════════════════════════ */

.clippy-gacha-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: radial-gradient(ellipse at center, rgba(40, 25, 70, 0.95) 0%, rgba(10, 12, 24, 0.98) 80%);
  backdrop-filter: blur(10px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 28px 16px;
  overflow-y: auto;
  font-family: 'Outfit', 'DM Sans', sans-serif;
  color: #fffef6;
  opacity: 0;
  transition: opacity 280ms ease;
}
.clippy-gacha-overlay.is-visible { opacity: 1; }
.clippy-gacha-prompt {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.2em;
  color: #d4a44e;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.clippy-gacha-title {
  font-size: 28px;
  font-weight: 800;
  text-align: center;
  margin-bottom: 18px;
}
.clippy-gacha-pull-orb {
  width: 200px;
  height: 200px;
  margin: 24px auto;
  filter: drop-shadow(0 0 30px rgba(212, 164, 78, 0.8)) drop-shadow(0 0 60px rgba(212, 164, 78, 0.4));
  animation: gachaIdle 3s ease-in-out infinite;
}
.clippy-gacha-pull-orb.is-spinning {
  animation: gachaSpin 1.5s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes gachaIdle {
  0%, 100% { transform: scale(1) rotate(0); }
  50%      { transform: scale(1.06) rotate(8deg); }
}
@keyframes gachaSpin {
  0%   { transform: scale(1) rotate(0); }
  50%  { transform: scale(1.4) rotate(720deg); filter: drop-shadow(0 0 60px #ffd870) drop-shadow(0 0 120px #ffd870); }
  100% { transform: scale(0.1) rotate(1440deg); opacity: 0; }
}
.clippy-gacha-card {
  width: 240px;
  height: 320px;
  margin: 24px auto;
  border-radius: 16px;
  border: 3px solid #d4a44e;
  background: linear-gradient(135deg, #2a1f4a 0%, #1a1530 100%);
  padding: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  box-shadow: 0 0 24px rgba(212, 164, 78, 0.4), 6px 6px 0 #1a1a1a;
  animation: gachaCardReveal 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.clippy-gacha-card.is-common { border-color: #aaaaaa; box-shadow: 0 0 16px rgba(170, 170, 170, 0.3), 6px 6px 0 #1a1a1a; }
.clippy-gacha-card.is-uncommon { border-color: #5fff8a; box-shadow: 0 0 20px rgba(95, 255, 138, 0.4), 6px 6px 0 #1a1a1a; }
.clippy-gacha-card.is-rare { border-color: #7df0ff; box-shadow: 0 0 24px rgba(125, 240, 255, 0.55), 6px 6px 0 #1a1a1a; }
.clippy-gacha-card.is-legendary {
  border-color: #ffd870;
  background: linear-gradient(135deg, #4a3a1a 0%, #2a1f4a 100%);
  box-shadow: 0 0 32px rgba(255, 216, 112, 0.7), 0 0 64px rgba(255, 216, 112, 0.3), 6px 6px 0 #1a1a1a;
  animation: gachaCardReveal 0.8s cubic-bezier(0.34, 1.56, 0.64, 1), gachaLegendaryGlow 2.4s ease-in-out infinite 1s;
}
@keyframes gachaCardReveal {
  0%   { transform: scale(0) rotateY(-180deg); opacity: 0; }
  100% { transform: scale(1) rotateY(0); opacity: 1; }
}
@keyframes gachaLegendaryGlow {
  0%, 100% { box-shadow: 0 0 32px rgba(255, 216, 112, 0.7), 0 0 64px rgba(255, 216, 112, 0.3), 6px 6px 0 #1a1a1a; }
  50%      { box-shadow: 0 0 48px rgba(255, 216, 112, 1), 0 0 96px rgba(255, 216, 112, 0.5), 6px 6px 0 #1a1a1a; }
}
.clippy-gacha-card-rarity {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin-bottom: 8px;
  opacity: 0.85;
}
.clippy-gacha-card.is-common .clippy-gacha-card-rarity { color: #cccccc; }
.clippy-gacha-card.is-uncommon .clippy-gacha-card-rarity { color: #5fff8a; }
.clippy-gacha-card.is-rare .clippy-gacha-card-rarity { color: #7df0ff; }
.clippy-gacha-card.is-legendary .clippy-gacha-card-rarity { color: #ffd870; }
.clippy-gacha-card-glyph {
  font-size: 72px;
  margin: 12px 0;
}
.clippy-gacha-card-name {
  font-size: 22px;
  font-weight: 800;
  margin-bottom: 8px;
  text-align: center;
}
.clippy-gacha-card-desc {
  font-size: 13px;
  text-align: center;
  opacity: 0.85;
  line-height: 1.4;
  font-style: italic;
}
.clippy-gacha-card-power {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: #d4a44e;
  margin-top: 12px;
  padding: 6px 12px;
  background: rgba(212, 164, 78, 0.12);
  border-radius: 6px;
  letter-spacing: 0.08em;
}

.clippy-gacha-duplicate {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: #ffaa44;
  margin-top: 14px;
}

/* Gacha collection grid */
.clippy-gacha-collection {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 10px;
  width: 100%;
  max-width: 720px;
  padding: 8px;
}
.clippy-gacha-coll-card {
  border-radius: 12px;
  padding: 12px 8px;
  text-align: center;
  border: 1.5px solid rgba(255, 254, 246, 0.2);
  background: rgba(255, 254, 246, 0.04);
}
.clippy-gacha-coll-card.is-common { border-color: #aaaaaa; }
.clippy-gacha-coll-card.is-uncommon { border-color: #5fff8a; }
.clippy-gacha-coll-card.is-rare { border-color: #7df0ff; }
.clippy-gacha-coll-card.is-legendary {
  border-color: #ffd870;
  background: linear-gradient(135deg, rgba(255, 216, 112, 0.14), rgba(212, 164, 78, 0.08));
}
.clippy-gacha-coll-card.is-locked {
  filter: grayscale(1);
  opacity: 0.4;
}
.clippy-gacha-coll-glyph { font-size: 32px; margin-bottom: 4px; }
.clippy-gacha-coll-name {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  color: rgba(255, 254, 246, 0.85);
  text-transform: uppercase;
}
.clippy-gacha-coll-count {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: #d4a44e;
  font-weight: 700;
  margin-top: 3px;
}

/* ════════════════════════════════════════════════════════════════════
   v17.31 COSTUMES + PROPS — FULL REDESIGN
   - 14 hats total (5 NEW: wizard/crown/tophat/cowboy/tricorn)
   - 6 props total (3 NEW: cup/sword/apple)
   - Prop animations focus on the PROP, not the orb (more natural)
   - Telekinetic float effect on held items via cl-prop-float group
   - Idle micro-animations on hats (plumes wave, crests sway, etc.)
   ════════════════════════════════════════════════════════════════════ */

/* All costumes/props hidden by default */
.clippy-svg .cl-costume-laurel,
.clippy-svg .cl-costume-helmet,
.clippy-svg .cl-costume-party-hat,
.clippy-svg .cl-costume-scholar-cap,
.clippy-svg .cl-costume-wizard,
.clippy-svg .cl-costume-crown,
.clippy-svg .cl-costume-tophat,
.clippy-svg .cl-costume-cowboy,
.clippy-svg .cl-costume-tricorn,
.clippy-svg .cl-prop-broom,
.clippy-svg .cl-prop-book,
.clippy-svg .cl-prop-scroll,
.clippy-svg .cl-prop-cup,
.clippy-svg .cl-prop-sword,
.clippy-svg .cl-prop-apple {
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

/* Show costume when its wear-* class is on shell */
#clippy-shell.wear-laurel       .cl-costume-laurel       { opacity: 1; }
#clippy-shell.wear-helmet       .cl-costume-helmet       { opacity: 1; }
#clippy-shell.wear-party-hat    .cl-costume-party-hat    { opacity: 1; }
#clippy-shell.wear-scholar-cap  .cl-costume-scholar-cap  { opacity: 1; }
#clippy-shell.wear-wizard       .cl-costume-wizard       { opacity: 1; }
#clippy-shell.wear-crown        .cl-costume-crown        { opacity: 1; }
#clippy-shell.wear-tophat       .cl-costume-tophat       { opacity: 1; }
#clippy-shell.wear-cowboy       .cl-costume-cowboy       { opacity: 1; }
#clippy-shell.wear-tricorn      .cl-costume-tricorn      { opacity: 1; }

#clippy-shell.holding-broom   .cl-prop-broom   { opacity: 1; }
#clippy-shell.holding-book    .cl-prop-book    { opacity: 1; }
#clippy-shell.holding-scroll  .cl-prop-scroll  { opacity: 1; }
#clippy-shell.holding-cup     .cl-prop-cup     { opacity: 1; }
#clippy-shell.holding-sword   .cl-prop-sword   { opacity: 1; }
#clippy-shell.holding-apple   .cl-prop-apple   { opacity: 1; }

/* ─── IDLE PROP FLOAT — telekinetic levitation on all held items ─── */
.clippy-svg .cl-prop-float {
  animation: propFloat 3.6s ease-in-out infinite;
  transform-origin: 184px 110px;
}
@keyframes propFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-3px) rotate(0.6deg); }
}

/* ─── IDLE HAT MICRO-ANIMATIONS — subtle costume liveliness ─── */
/* Helmet crest sways (red horsehair) */
.clippy-svg .cl-helmet-crest {
  animation: crestSway 2.8s ease-in-out infinite;
  transform-origin: 100px 30px;
}
@keyframes crestSway {
  0%, 100% { transform: skewX(0deg); }
  50%      { transform: skewX(3deg); }
}
/* Macedonian crest — same kind of horsehair, gentler */
.clippy-svg .cl-mac-crest {
  animation: crestSway 3.2s ease-in-out infinite;
  transform-origin: 100px 22px;
}
/* Pom-pom bounces */
.clippy-svg .cl-pompom {
  animation: pomBounce 2.4s ease-in-out infinite;
  transform-origin: 100px 14px;
}
@keyframes pomBounce {
  0%, 100% { transform: scale(1) translateY(0); }
  50%      { transform: scale(1.05) translateY(-1.5px); }
}
/* Party sparkles twinkle */
.clippy-svg .cl-party-sparkles {
  animation: sparkleBlink 1.8s ease-in-out infinite;
}
@keyframes sparkleBlink {
  0%, 100% { opacity: 0.95; }
  50%      { opacity: 0.4; }
}
/* Wizard hat stars twinkle */
.clippy-svg .cl-wizard-stars {
  animation: sparkleBlink 2.2s ease-in-out infinite;
}
/* Tassel swings */
.clippy-svg .cl-tassel {
  animation: tasselSwing 3.2s ease-in-out infinite;
  transform-origin: 154px 76px;
}
@keyframes tasselSwing {
  0%, 100% { transform: rotate(-3deg); }
  50%      { transform: rotate(4deg); }
}
/* Carthaginian feather and tricorn feather sway */
.clippy-svg .cl-cart-feather,
.clippy-svg .cl-tricorn-feather {
  animation: featherSway 3.8s ease-in-out infinite;
  transform-origin: 76px 32px;
}
@keyframes featherSway {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(4deg); }
}
/* Laurel leaves rustle */
.clippy-svg .cl-laurel-leaves {
  animation: leafRustle 4.5s ease-in-out infinite;
  transform-origin: 100px 50px;
}
@keyframes leafRustle {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.015); }
}
/* Uraeus cobra bobs threateningly */
.clippy-svg .cl-uraeus {
  animation: uraeusBob 2.6s ease-in-out infinite;
  transform-origin: 100px 56px;
}
@keyframes uraeusBob {
  0%, 100% { transform: rotate(-1.5deg); }
  50%      { transform: rotate(2deg); }
}
/* Cockade flutter on Napoleon bicorne */
.clippy-svg .cl-bicorne-cockade {
  animation: cockadePulse 3.4s ease-in-out infinite;
  transform-origin: 48px 46px;
}
@keyframes cockadePulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}
/* Mongol fur ruffles */
.clippy-svg .cl-mongol-fur {
  animation: furRuffle 5s ease-in-out infinite;
  transform-origin: 100px 70px;
}
@keyframes furRuffle {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(0.8px); }
}

/* ─── ACTION ANIMATIONS — focus on the prop, not the orb ─── */

/* SWEEPING — broom rocks left-right, orb does small tilt only */
#clippy-shell.is-sweeping .cl-prop-broom { opacity: 1; }
#clippy-shell.is-sweeping .cl-prop-broom-anim {
  animation: broomSweep 0.95s ease-in-out infinite;
  transform-origin: 184px 80px;
}
#clippy-shell.is-sweeping .cl-floats {
  animation: orbSweepGentle 1.9s ease-in-out infinite !important;
  transform-origin: 100px 130px;
}
@keyframes broomSweep {
  0%, 100% { transform: rotate(-15deg) translateX(-2px); }
  50%      { transform: rotate(18deg) translateX(2px); }
}
@keyframes orbSweepGentle {
  0%, 100% { transform: rotate(-2deg); }
  50%      { transform: rotate(2deg); }
}

/* READING — book stays still and the ORB nods toward it; eyes look right */
#clippy-shell.is-reading .cl-prop-book { opacity: 1; }
#clippy-shell.is-reading .cl-prop-book .cl-prop-float {
  animation: bookFloat 2.4s ease-in-out infinite;
}
#clippy-shell.is-reading .cl-floats {
  animation: orbReadNod 3.6s ease-in-out infinite !important;
  transform-origin: 100px 100px;
}
@keyframes bookFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-1.5px) rotate(1.5deg); }
}
@keyframes orbReadNod {
  0%, 100% { transform: rotate(8deg); }
  50%      { transform: rotate(11deg); }
}

/* SCRIBING — scroll bobs more, orb concentrates */
#clippy-shell.is-scribing .cl-prop-scroll { opacity: 1; }
#clippy-shell.is-scribing .cl-prop-scroll .cl-prop-float {
  animation: scrollFloat 2.2s ease-in-out infinite;
}
#clippy-shell.is-scribing .cl-floats {
  animation: orbScribeNod 3s ease-in-out infinite !important;
  transform-origin: 100px 100px;
}
@keyframes scrollFloat {
  0%, 100% { transform: translateY(0) rotate(-1deg); }
  50%      { transform: translateY(-2px) rotate(1.5deg); }
}
@keyframes orbScribeNod {
  0%, 100% { transform: rotate(5deg); }
  50%      { transform: rotate(8deg); }
}

/* DRINKING — wine cup tips toward orb's "mouth" */
#clippy-shell.is-drinking .cl-prop-cup { opacity: 1; }
#clippy-shell.is-drinking .cl-prop-cup .cl-prop-float {
  animation: cupDrink 2.4s ease-in-out infinite;
  transform-origin: 184px 138px;
}
@keyframes cupDrink {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  40%      { transform: translate(-50px, -30px) rotate(-50deg); }
  60%      { transform: translate(-50px, -30px) rotate(-50deg); }
}

/* SWORD POSE — sword swings */
#clippy-shell.is-swording .cl-prop-sword { opacity: 1; }
#clippy-shell.is-swording .cl-prop-sword .cl-prop-float {
  animation: swordSwing 1.6s ease-in-out infinite;
  transform-origin: 184px 62px;
}
@keyframes swordSwing {
  0%, 100% { transform: rotate(0deg); }
  25%      { transform: rotate(-30deg); }
  75%      { transform: rotate(30deg); }
}

/* EATING APPLE — apple lifts to mouth */
#clippy-shell.is-eating .cl-prop-apple { opacity: 1; }
#clippy-shell.is-eating .cl-prop-apple .cl-prop-float {
  animation: appleEat 3s ease-in-out infinite;
  transform-origin: 184px 116px;
}
@keyframes appleEat {
  0%, 100% { transform: translate(0, 0); }
  40%      { transform: translate(-55px, -10px) scale(0.95); }
  60%      { transform: translate(-55px, -10px) scale(0.95); }
}

/* ─── SIGNATURE COSTUME GLOWS — conqueror personas keep theirs ─── */
/* All conqueror persona glows preserved (declared earlier in file). */

/* ─── WARDROBE UI ENHANCEMENTS ─── */

/* Category section divider in wardrobe */
.clippy-wardrobe-tabs {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin: 14px auto 18px;
  flex-wrap: wrap;
  max-width: 540px;
}
.clippy-wardrobe-tab {
  padding: 6px 14px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  background: rgba(255, 254, 246, 0.04);
  border: 1.5px solid rgba(212, 164, 78, 0.35);
  border-radius: 18px;
  color: rgba(255, 254, 246, 0.7);
  cursor: pointer;
  transition: all 140ms ease;
}
.clippy-wardrobe-tab:hover {
  border-color: #d4a44e;
  color: #fffef6;
}
.clippy-wardrobe-tab.is-active {
  background: rgba(212, 164, 78, 0.22);
  border-color: #d4a44e;
  color: #ffd870;
}

/* Set-bonus pill (when matched outfit unlocked) */
.clippy-set-bonus {
  margin: 14px auto;
  padding: 8px 18px;
  text-align: center;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  background: rgba(125, 240, 255, 0.10);
  border: 1.5px solid #7df0ff;
  border-radius: 22px;
  color: #7df0ff;
  max-width: 360px;
  display: block;
  box-shadow: 0 0 14px rgba(125, 240, 255, 0.25);
}
.clippy-set-bonus-label {
  display: block;
  font-size: 9px;
  opacity: 0.65;
  margin-bottom: 2px;
}
.clippy-set-bonus-name {
  font-size: 13px;
  font-weight: 700;
  color: #fffef6;
}

/* Costume picker UI */
.clippy-costume-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 12px;
  max-width: 540px;
  margin: 0 auto;
}
.clippy-costume-card {
  background: rgba(255, 254, 246, 0.04);
  border: 1.5px solid rgba(212, 164, 78, 0.4);
  border-radius: 12px;
  padding: 14px 8px 10px;
  text-align: center;
  cursor: pointer;
  transition: transform 140ms ease, border-color 140ms ease, background 140ms ease;
}
.clippy-costume-card:hover { transform: translateY(-2px); border-color: #d4a44e; }
.clippy-costume-card.is-active {
  background: rgba(212, 164, 78, 0.18);
  border-color: #d4a44e;
  box-shadow: 0 0 12px rgba(212, 164, 78, 0.4);
}
.clippy-costume-glyph { font-size: 32px; margin-bottom: 6px; }
.clippy-costume-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  color: rgba(255, 254, 246, 0.85);
  text-transform: uppercase;
}

/* Cloud sync indicator */
.clippy-sync-indicator {
  position: fixed;
  bottom: 12px;
  right: 12px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  padding: 4px 10px;
  background: rgba(0,0,0,0.6);
  color: rgba(255, 254, 246, 0.6);
  border-radius: 6px;
  border: 1px solid rgba(212, 164, 78, 0.3);
  z-index: 100;
  pointer-events: none;
  opacity: 0;
  transition: opacity 280ms ease;
}
.clippy-sync-indicator.is-visible { opacity: 1; }
.clippy-sync-indicator.is-syncing { color: #7df0ff; border-color: #7df0ff; }
.clippy-sync-indicator.is-synced  { color: #5fff8a; border-color: #5fff8a; }
.clippy-sync-indicator.is-failed  { color: #ff5577; border-color: #ff5577; }

/* ════════════════════════════════════════════════════════════════════
   v17.26 AFFINITY & LIKES — Sims-style relationship scoring with
   per-user opinions + learned likes/dislikes catalog.
   ════════════════════════════════════════════════════════════════════ */

.clippy-affinity-meter {
  background: rgba(212, 164, 78, 0.08);
  border: 1.5px solid #d4a44e;
  border-radius: 14px;
  padding: 16px 22px;
  margin: 8px auto 18px;
  text-align: center;
  max-width: 360px;
}
.clippy-affinity-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.2em;
  color: rgba(255, 254, 246, 0.6);
  text-transform: uppercase;
  margin-bottom: 4px;
}
.clippy-affinity-status {
  font-size: 22px;
  font-weight: 800;
  margin-bottom: 10px;
}
.clippy-affinity-status.is-despised  { color: #ff5577; }
.clippy-affinity-status.is-disliked  { color: #ff9966; }
.clippy-affinity-status.is-neutral   { color: #cccccc; }
.clippy-affinity-status.is-liked     { color: #5fff8a; }
.clippy-affinity-status.is-friend    { color: #7df0ff; }
.clippy-affinity-status.is-cherished {
  color: #ffd870;
  text-shadow: 0 0 12px rgba(255, 216, 112, 0.5);
}

.clippy-affinity-bar {
  position: relative;
  width: 100%;
  height: 14px;
  background: rgba(0,0,0,0.4);
  border-radius: 7px;
  overflow: hidden;
  margin: 4px 0;
  border: 1px solid rgba(255,254,246,0.1);
}
.clippy-affinity-bar-center {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  background: rgba(255,254,246,0.4);
  z-index: 2;
}
.clippy-affinity-bar-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 6px;
  transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1), left 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.clippy-affinity-bar-fill.is-positive {
  left: 50%;
  background: linear-gradient(90deg, #d4a44e 0%, #ffd870 100%);
}
.clippy-affinity-bar-fill.is-negative {
  right: 50%;
  background: linear-gradient(90deg, #ff5577 0%, #ff9966 100%);
}
.clippy-affinity-score {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: rgba(255, 254, 246, 0.6);
  margin-top: 6px;
}

.clippy-likes-section {
  margin-top: 18px;
}
.clippy-likes-section-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.15em;
  color: #d4a44e;
  text-transform: uppercase;
  margin-bottom: 8px;
  text-align: center;
}
.clippy-likes-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  max-width: 560px;
  margin: 0 auto 16px;
}
.clippy-like-tag {
  padding: 6px 12px;
  border-radius: 16px;
  font-size: 13px;
  font-family: 'Outfit', 'DM Sans', sans-serif;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1.5px solid rgba(255,254,246,0.2);
}
.clippy-like-tag.is-like {
  background: rgba(95, 255, 138, 0.1);
  border-color: rgba(95, 255, 138, 0.5);
  color: #5fff8a;
}
.clippy-like-tag.is-dislike {
  background: rgba(255, 85, 119, 0.1);
  border-color: rgba(255, 85, 119, 0.5);
  color: #ff8899;
}
.clippy-like-tag-glyph { font-size: 14px; }
.clippy-like-empty {
  text-align: center;
  font-style: italic;
  opacity: 0.5;
  font-size: 13px;
}

/* ════════════════════════════════════════════════════════════════════
   v17.27 CONQUEROR ALTER EGOS — 5 new hats + signature glow per persona.
   Hidden by default; shown via `wear-{name}` class on shell.
   ════════════════════════════════════════════════════════════════════ */

.clippy-svg .cl-costume-bicorne,
.clippy-svg .cl-costume-mongol,
.clippy-svg .cl-costume-macedonian,
.clippy-svg .cl-costume-carthaginian,
.clippy-svg .cl-costume-nemes,
/* v18.4 BUGFIX — kawaii costumes were missing from the default-hide
   block, so chef-hat + cat-ears + bunny-ears + flower-crown +
   heart-crown + beanie all rendered AT THE SAME TIME regardless of
   the wear-X class. Three-hats-stacked bug. Hide by default now. */
.clippy-svg .cl-costume-chef-hat,
.clippy-svg .cl-costume-cat-ears,
.clippy-svg .cl-costume-bunny-ears,
.clippy-svg .cl-costume-flower-crown,
.clippy-svg .cl-costume-heart-crown,
.clippy-svg .cl-costume-beanie {
  opacity: 0;
  transition: opacity 0.5s ease;
  pointer-events: none;
}

#clippy-shell.wear-bicorne       .cl-costume-bicorne       { opacity: 1; }
#clippy-shell.wear-mongol        .cl-costume-mongol        { opacity: 1; }
#clippy-shell.wear-macedonian    .cl-costume-macedonian    { opacity: 1; }
#clippy-shell.wear-carthaginian  .cl-costume-carthaginian  { opacity: 1; }
#clippy-shell.wear-nemes         .cl-costume-nemes         { opacity: 1; }

/* Signature glow per persona — overrides default halo glow while persona active */
#clippy-shell.persona-napoleon {
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45))
          drop-shadow(0 0 14px rgba(110, 130, 200, 0.75))
          drop-shadow(0 0 24px rgba(180, 30, 50, 0.4)) !important;
}
#clippy-shell.persona-genghis {
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45))
          drop-shadow(0 0 14px rgba(160, 170, 180, 0.75))
          drop-shadow(0 0 24px rgba(160, 60, 30, 0.4)) !important;
}
#clippy-shell.persona-alexander {
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45))
          drop-shadow(0 0 14px rgba(212, 164, 78, 0.85))
          drop-shadow(0 0 24px rgba(180, 130, 30, 0.4)) !important;
}
#clippy-shell.persona-hannibal {
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45))
          drop-shadow(0 0 14px rgba(140, 80, 160, 0.75))
          drop-shadow(0 0 24px rgba(80, 40, 100, 0.4)) !important;
}
#clippy-shell.persona-cleopatra {
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45))
          drop-shadow(0 0 14px rgba(212, 164, 78, 0.85))
          drop-shadow(0 0 24px rgba(26, 128, 80, 0.4)) !important;
}
#clippy-shell.persona-trajan {
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45))
          drop-shadow(0 0 16px rgba(212, 164, 78, 0.9))
          drop-shadow(0 0 28px rgba(212, 164, 78, 0.4)) !important;
}

/* Persona indicator pill — small label near shell showing current alter ego */
.clippy-persona-pill {
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px;
  letter-spacing: 0.16em;
  padding: 3px 9px;
  background: rgba(0,0,0,0.7);
  color: #d4a44e;
  border: 1px solid #d4a44e;
  border-radius: 10px;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
  z-index: 5;
}
.clippy-persona-pill.is-visible { opacity: 1; }
.clippy-persona-pill.is-napoleon  { color: #a8b8ff; border-color: #a8b8ff; }
.clippy-persona-pill.is-genghis   { color: #c8c8d0; border-color: #c8c8d0; }
.clippy-persona-pill.is-alexander { color: #ffd870; border-color: #ffd870; }
.clippy-persona-pill.is-hannibal  { color: #d0a8e8; border-color: #d0a8e8; }
.clippy-persona-pill.is-cleopatra { color: #5fffba; border-color: #5fffba; }
.clippy-persona-pill.is-trajan    { color: #ffd870; border-color: #ffd870; }

/* ════════════════════════════════════════════════════════════════════
   v17.28 SELF-AWARENESS — capability registry viewer
   ════════════════════════════════════════════════════════════════════ */

.clippy-cap-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
  max-width: 720px;
  margin: 0 auto;
}
.clippy-cap-card {
  background: rgba(255, 254, 246, 0.04);
  border: 1.5px solid rgba(212, 164, 78, 0.45);
  border-radius: 12px;
  padding: 14px 16px;
  text-align: left;
  cursor: pointer;
  transition: transform 140ms ease, border-color 140ms ease, background 140ms ease;
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.clippy-cap-card:hover {
  transform: translateY(-2px);
  border-color: #d4a44e;
  background: rgba(212, 164, 78, 0.08);
}
.clippy-cap-card.is-passive {
  border-style: dashed;
  cursor: default;
  opacity: 0.85;
}
.clippy-cap-card.is-passive:hover { transform: none; }
.clippy-cap-glyph {
  font-size: 28px;
  line-height: 1;
  flex-shrink: 0;
}
.clippy-cap-body {
  flex: 1;
  min-width: 0;
}
.clippy-cap-label {
  font-family: 'Outfit', 'DM Sans', sans-serif;
  font-size: 14px;
  font-weight: 700;
  color: #fffef6;
  margin-bottom: 3px;
}
.clippy-cap-tag {
  display: inline-block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px;
  letter-spacing: 0.12em;
  padding: 2px 7px;
  background: rgba(212, 164, 78, 0.15);
  border-radius: 6px;
  color: #d4a44e;
  margin-left: 6px;
  text-transform: uppercase;
}
.clippy-cap-tag.is-passive { background: rgba(125, 240, 255, 0.12); color: #7df0ff; }
.clippy-cap-desc {
  font-family: 'Outfit', 'DM Sans', sans-serif;
  font-size: 11.5px;
  color: rgba(255, 254, 246, 0.65);
  line-height: 1.4;
}

.clippy-world-state {
  background: rgba(0,0,0,0.4);
  border: 1.5px dashed rgba(125, 240, 255, 0.4);
  border-radius: 12px;
  padding: 12px 18px;
  margin: 0 auto 22px;
  max-width: 540px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: rgba(255, 254, 246, 0.75);
  line-height: 1.7;
}
.clippy-world-state-title {
  font-size: 10px;
  letter-spacing: 0.18em;
  color: #7df0ff;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.clippy-world-state-row {
  display: flex;
  justify-content: space-between;
  padding: 2px 0;
}
.clippy-world-state-key { color: rgba(255, 254, 246, 0.5); }
.clippy-world-state-val { color: #fffef6; font-weight: 600; }

.clippy-cap-section-divider {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.2em;
  color: #d4a44e;
  text-transform: uppercase;
  margin: 22px 0 12px;
  text-align: center;
  position: relative;
}
.clippy-cap-section-divider::before,
.clippy-cap-section-divider::after {
  content: '';
  position: absolute;
  top: 50%;
  width: 80px;
  height: 1px;
  background: rgba(212, 164, 78, 0.3);
}
.clippy-cap-section-divider::before { left: 50%; margin-left: -180px; }
.clippy-cap-section-divider::after  { left: 50%; margin-left: 100px; }

/* Locked costume styling */
.clippy-costume-card.is-locked {
  opacity: 0.55;
  cursor: not-allowed;
  border-style: dashed;
}
.clippy-costume-card.is-locked:hover {
  transform: none;
  background: rgba(255, 254, 246, 0.04);
}

/* ════════════════════════════════════════════════════════════════════
   v18.0 GAMES OVERHAUL — canvas boards, combo HUD, bonus orbs, medals,
   coin side picker. Existing rules (.clippy-game-overlay, .clippy-game-
   board, .clippy-mini-shell, .clippy-memory-*) are unchanged.
   ════════════════════════════════════════════════════════════════════ */

/* Canvas wrapper used by Flappy, Cannon, Snake, Breaker, Coins, Asteroids */
.clippy-canvas-wrap {
  display: flex;
  justify-content: center;
  margin: 14px auto;
}
.clippy-canvas-board {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  border: 2.5px solid #1a1a1a;
  box-shadow: 4px 4px 0 #1a1a1a;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.clippy-canvas-board canvas {
  display: block;
  width: 100%;
  height: 100%;
}
.clippy-canvas-board .clippy-game-countdown {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  z-index: 5;
}

/* Tap-game HUD bar — used by Tap, Catch, others */
.clippy-tap-hud {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  margin: 8px auto 12px;
  flex-wrap: wrap;
}
.clippy-tap-hud .hud-stat {
  font: 700 13px/1.1 'JetBrains Mono', monospace;
  color: #fffef6;
  background: rgba(0,0,0,0.45);
  border: 1.5px solid rgba(212, 164, 78, 0.55);
  padding: 6px 10px;
  border-radius: 8px;
  letter-spacing: 0.04em;
}
.clippy-tap-hud .hud-stat span { color: #ffd870; }

/* Combo indicator (Tap game) */
.clippy-tap-combo {
  transition: transform 120ms ease, background 200ms ease, border-color 200ms ease;
}
.clippy-tap-combo.is-hot {
  background: rgba(255, 136, 85, 0.25);
  border-color: #ff8855;
  transform: scale(1.05);
}
.clippy-tap-combo.is-blazing {
  background: rgba(255, 85, 119, 0.35);
  border-color: #ff5577;
  transform: scale(1.12);
  animation: comboBlaze 0.9s ease infinite;
}
@keyframes comboBlaze {
  0%, 100% { box-shadow: 0 0 8px rgba(255, 136, 85, 0.6); }
  50%      { box-shadow: 0 0 16px rgba(255, 85, 119, 0.9); }
}

/* Bonus orb (Tap game) */
.clippy-tap-bonus {
  position: absolute;
  width: 60px;
  height: 60px;
  cursor: pointer;
  filter: drop-shadow(0 0 12px rgba(255, 216, 112, 0.95))
          drop-shadow(0 4px 8px rgba(0,0,0,0.45));
  transform-origin: center;
  animation: bonusPulse 0.6s ease infinite alternate;
  transition: transform 200ms ease, opacity 250ms ease;
}
.clippy-tap-bonus svg { width: 100%; height: 100%; }
@keyframes bonusPulse {
  from { transform: scale(1)    rotate(-3deg); }
  to   { transform: scale(1.15) rotate( 3deg); }
}
.clippy-tap-bonus.is-caught {
  animation: none;
  transform: scale(1.8);
  opacity: 0;
}
.clippy-tap-bonus.is-fading {
  animation: none;
  opacity: 0;
  transform: scale(0.8);
}

/* Medal display on results screen */
.clippy-game-medal {
  display: inline-block;
  margin: 10px auto;
  padding: 8px 18px;
  font: 800 16px/1 'Outfit', sans-serif;
  letter-spacing: 0.06em;
  border-radius: 999px;
  border: 2px solid #1a1a1a;
  box-shadow: 2px 2px 0 #1a1a1a;
}
.clippy-game-medal.is-platinum {
  background: linear-gradient(135deg, #e8eaf0 0%, #b8c6d5 50%, #7d8a99 100%);
  color: #1a1a1a;
}
.clippy-game-medal.is-gold {
  background: linear-gradient(135deg, #fff4d0 0%, #e8c264 50%, #b88a2e 100%);
  color: #1a1a1a;
}
.clippy-game-medal.is-silver {
  background: linear-gradient(135deg, #f5f5f5 0%, #c0c0c0 50%, #808080 100%);
  color: #1a1a1a;
}
.clippy-game-medal.is-bronze {
  background: linear-gradient(135deg, #f5cfa3 0%, #cd7f32 50%, #8b4d1c 100%);
  color: #1a1a1a;
}

/* Extra stats grid on results screen */
.clippy-game-extra-stats {
  margin: 10px auto;
  display: grid;
  gap: 4px;
  max-width: 320px;
}
.clippy-game-extra-stats > div {
  display: flex;
  justify-content: space-between;
  font: 600 13px/1.3 'JetBrains Mono', monospace;
  padding: 5px 10px;
  background: rgba(212, 164, 78, 0.08);
  border-left: 2px solid #d4a44e;
  border-radius: 3px;
}
.clippy-game-extra-stats .lbl { color: rgba(255, 254, 246, 0.65); letter-spacing: 0.04em; }
.clippy-game-extra-stats .val { color: #fffef6; }

/* Coin Catch — side picker */
.clippy-coin-side-pick {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 320px;
  margin: 16px auto;
}
.clippy-coin-side-pick .clippy-game-btn { width: 100%; }

/* ════════════════════════════════════════════════════════════════════
   v18.1 KAWAII + CULINARY HATS — reveal rules + idle animations
   ════════════════════════════════════════════════════════════════════ */

/* Reveal rules — match the same pattern as existing wear-* classes */
#clippy-shell.wear-chef-hat     .cl-costume-chef-hat     { opacity: 1; }
#clippy-shell.wear-cat-ears     .cl-costume-cat-ears     { opacity: 1; }
#clippy-shell.wear-bunny-ears   .cl-costume-bunny-ears   { opacity: 1; }
#clippy-shell.wear-flower-crown .cl-costume-flower-crown { opacity: 1; }
#clippy-shell.wear-heart-crown  .cl-costume-heart-crown  { opacity: 1; }
#clippy-shell.wear-beanie       .cl-costume-beanie       { opacity: 1; }

/* ─── CHEF TOQUE: gentle puff wobble ─── */
.clippy-svg .cl-chef-puff {
  animation: chefPuffWobble 3.8s ease-in-out infinite;
  transform-origin: 100px 50px;
}
@keyframes chefPuffWobble {
  0%, 100% { transform: scale(1)     translateY(0)  rotate(0deg); }
  35%      { transform: scale(1.025) translateY(-0.6px) rotate(-0.6deg); }
  70%      { transform: scale(1.015) translateY(0.4px)  rotate(0.4deg); }
}

/* ─── CAT EARS: independent twitch (left + right offset) ─── */
.clippy-svg .cl-cat-ear-l {
  animation: catEarTwitchL 4.2s ease-in-out infinite;
  transform-origin: 65px 50px;
}
.clippy-svg .cl-cat-ear-r {
  animation: catEarTwitchR 4.6s ease-in-out infinite;
  animation-delay: 0.8s;
  transform-origin: 135px 50px;
}
@keyframes catEarTwitchL {
  0%, 80%, 100% { transform: rotate(0deg); }
  85%           { transform: rotate(-7deg); }
  92%           { transform: rotate(2deg); }
}
@keyframes catEarTwitchR {
  0%, 75%, 100% { transform: rotate(0deg); }
  82%           { transform: rotate(7deg); }
  90%           { transform: rotate(-2deg); }
}

/* ─── BUNNY EARS: floppy sway ─── */
.clippy-svg .cl-bunny-ear-l {
  animation: bunnyEarSwayL 3.6s ease-in-out infinite;
  transform-origin: 74px 50px;
}
.clippy-svg .cl-bunny-ear-r {
  animation: bunnyEarSwayR 3.6s ease-in-out infinite;
  animation-delay: 0.4s;
  transform-origin: 126px 50px;
}
@keyframes bunnyEarSwayL {
  0%, 100% { transform: rotate(-1deg); }
  50%      { transform: rotate(4deg); }
}
@keyframes bunnyEarSwayR {
  0%, 100% { transform: rotate(1deg); }
  50%      { transform: rotate(-4deg); }
}

/* ─── FLOWER CROWN: each flower has its own gentle sway, offset ─── */
.clippy-svg .cl-flower-wreath {
  animation: flowerWreathBreathe 5s ease-in-out infinite;
  transform-origin: 100px 50px;
}
@keyframes flowerWreathBreathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.018); }
}
.clippy-svg .cl-flower-1 { animation: flowerSway 3.4s ease-in-out infinite; transform-origin: 50px 52px; }
.clippy-svg .cl-flower-2 { animation: flowerSway 3.8s ease-in-out infinite; animation-delay: 0.4s; transform-origin: 72px 38px; }
.clippy-svg .cl-flower-3 { animation: flowerSway 3.2s ease-in-out infinite; animation-delay: 0.8s; transform-origin: 100px 26px; }
.clippy-svg .cl-flower-4 { animation: flowerSway 3.8s ease-in-out infinite; animation-delay: 1.2s; transform-origin: 128px 38px; }
.clippy-svg .cl-flower-5 { animation: flowerSway 3.4s ease-in-out infinite; animation-delay: 1.6s; transform-origin: 150px 52px; }
@keyframes flowerSway {
  0%, 100% { transform: rotate(-3deg) scale(1); }
  50%      { transform: rotate(3deg)  scale(1.05); }
}

/* ─── HEART CROWN: hearts pulse, sparkles twinkle ─── */
.clippy-svg .cl-heart-crown-hearts {
  animation: heartCrownPulse 1.8s ease-in-out infinite;
  transform-origin: 100px 36px;
}
@keyframes heartCrownPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}
.clippy-svg .cl-heart-crown-sparkles {
  animation: heartCrownSparkle 1.4s ease-in-out infinite;
}
@keyframes heartCrownSparkle {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.3; }
}

/* ─── BEANIE: pom-pom bobs ─── */
.clippy-svg .cl-beanie-pom {
  animation: beaniePomBob 2.4s ease-in-out infinite;
  transform-origin: 100px 14px;
}
@keyframes beaniePomBob {
  0%, 100% { transform: scale(1)    translateY(0)    rotate(0deg); }
  50%      { transform: scale(1.04) translateY(-1px) rotate(2deg); }
}

/* ════════════════════════════════════════════════════════════════════
   v18.1 CUTENESS POLISH on existing hats — gentle pulses + glow.
   ════════════════════════════════════════════════════════════════════ */

/* Crown gems pulse */
.clippy-svg .cl-crown-jewel,
.clippy-svg .cl-crown-jewels {
  animation: crownGemPulse 2.6s ease-in-out infinite;
  transform-origin: 100px 40px;
}
@keyframes crownGemPulse {
  0%, 100% { filter: brightness(1)    drop-shadow(0 0 0 transparent); }
  50%      { filter: brightness(1.18) drop-shadow(0 0 3px rgba(156, 208, 255, 0.7)); }
}
/* Wizard stars: slightly bigger + more frequent twinkle override */
.clippy-svg .cl-wizard-stars {
  animation: wizardStarTwinkle 1.4s ease-in-out infinite;
}
@keyframes wizardStarTwinkle {
  0%, 100% { opacity: 0.95; transform: scale(1); }
  50%      { opacity: 0.55; transform: scale(1.08); }
}
/* Party sparkles — same boost */

/* ═══ v18.x LIVING BREATHING ═══════════════════════════════════════════
   Constant subtle breath — the strongest aliveness cue in character
   animation. Applied to the SVG itself so any mood/action animation on
   the same element naturally REPLACES the breath while it plays (he
   "holds his breath" during expressions), then breathing resumes.
   Night hours breathe slower — a circadian body, not a screensaver.  */
@keyframes clippy-breathe {
  0%, 100% { transform: scale(1)        translateY(0); }
  45%      { transform: scale(1.022)    translateY(-0.6px); }
  60%      { transform: scale(1.024)    translateY(-0.7px); }
}
.clippy-svg {
  animation: clippy-breathe 4.2s ease-in-out infinite;
  transform-origin: 50% 88%;          /* breathe from the base, like a body */
  will-change: transform;
}
.clippy-night .clippy-svg { animation-duration: 7s; }   /* slow night breathing */
@media (prefers-reduced-motion: reduce) {
  .clippy-svg { animation: none; }
}

/* ═══ v18.x ANXIETY ════════════════════════════════════════════════════
   Sustained-load response (vision organ computes the load score). Shallow,
   quick breathing — the universal stress cue. Declared after .clippy-night
   so anxiety overrides sleepy breathing: a stressed body doesn't doze. */
.clippy-anxious .clippy-svg { animation-duration: 2.4s; }
@media (prefers-reduced-motion: reduce) {
  .clippy-anxious .clippy-svg { animation: none; }
}

/* ─── v18.33 Guided tour ──────────────────────────────────────────────
   Gold pulse on the nav button a tour step points at. Brand palette
   (never red/green). Removed with the .clippy-tour-spot class. */
.clippy-tour-spot {
  animation: clippyTourPulse 1.15s ease-in-out infinite;
  border-radius: 12px;
}
@keyframes clippyTourPulse {
  0%   { box-shadow: 0 0 0 0 rgba(212, 164, 78, 0.70); }
  70%  { box-shadow: 0 0 0 11px rgba(212, 164, 78, 0); }
  100% { box-shadow: 0 0 0 0 rgba(212, 164, 78, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .clippy-tour-spot { animation: none; box-shadow: 0 0 0 3px rgba(212, 164, 78, 0.7); }
}


/* ═══ v18.37 KAO FACES — 20 expressions traced from the reference sheet.
   Appended AFTER the original mood blocks so the cascade overrides them
   without touching shared rules. Each mood now wears its traced face;
   effect layers (tears, sweat, music) still compose on top. */
.clippy-svg .cl-kao { opacity: 0; }
#clippy-shell.is-worried [class*="cl-eyes-"],
#clippy-shell.is-worried [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-worried .cl-kao-plead { opacity: 1; }
#clippy-shell.is-surprised [class*="cl-eyes-"],
#clippy-shell.is-surprised [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-surprised .cl-kao-startle { opacity: 1; }
#clippy-shell.is-super-excited [class*="cl-eyes-"],
#clippy-shell.is-super-excited [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-super-excited .cl-kao-overjoy { opacity: 1; }
#clippy-shell.is-singing [class*="cl-eyes-"],
#clippy-shell.is-singing [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-singing .cl-kao-cheer { opacity: 1; }
#clippy-shell.is-gasp [class*="cl-eyes-"],
#clippy-shell.is-gasp [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-gasp .cl-kao-gasp2 { opacity: 1; }
#clippy-shell.is-proud [class*="cl-eyes-"],
#clippy-shell.is-proud [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-proud .cl-kao-serene { opacity: 1; }
#clippy-shell.is-laughing [class*="cl-eyes-"],
#clippy-shell.is-laughing [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-laughing .cl-kao-xd { opacity: 1; }
#clippy-shell.is-winking [class*="cl-eyes-"],
#clippy-shell.is-winking [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-winking .cl-kao-wink2 { opacity: 1; }
#clippy-shell.is-smug [class*="cl-eyes-"],
#clippy-shell.is-smug [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-smug .cl-kao-lidded { opacity: 1; }
#clippy-shell.is-mortified [class*="cl-eyes-"],
#clippy-shell.is-mortified [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-mortified .cl-kao-horror { opacity: 1; }
#clippy-shell.is-excited [class*="cl-eyes-"],
#clippy-shell.is-excited [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-excited .cl-kao-zest { opacity: 1; }
#clippy-shell.is-kissy [class*="cl-eyes-"],
#clippy-shell.is-kissy [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-kissy .cl-kao-kiss2 { opacity: 1; }
#clippy-shell.is-smitten [class*="cl-eyes-"],
#clippy-shell.is-smitten [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-smitten .cl-kao-puppy { opacity: 1; }
#clippy-shell.is-eye-roll [class*="cl-eyes-"],
#clippy-shell.is-eye-roll [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-eye-roll .cl-kao-deadpan { opacity: 1; }
#clippy-shell.is-peeved [class*="cl-eyes-"],
#clippy-shell.is-peeved [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-peeved .cl-kao-doneup { opacity: 1; }
#clippy-shell.is-furious [class*="cl-eyes-"],
#clippy-shell.is-furious [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-furious .cl-kao-ragefire { opacity: 1; }
#clippy-shell.is-crying [class*="cl-eyes-"],
#clippy-shell.is-crying [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-crying .cl-kao-waterworks { opacity: 1; }
#clippy-shell.is-frustrated [class*="cl-eyes-"],
#clippy-shell.is-frustrated [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-frustrated .cl-kao-grit { opacity: 1; }
#clippy-shell.is-disappointed [class*="cl-eyes-"],
#clippy-shell.is-disappointed [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-disappointed .cl-kao-grump { opacity: 1; }
#clippy-shell.is-condescending [class*="cl-eyes-"],
#clippy-shell.is-condescending [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-condescending .cl-kao-lidded { opacity: 1; }

/* ═══ v18.39 KAO SET II — traced from the second reference sheet. */
#clippy-shell.is-bunny [class*="cl-eyes-"],
#clippy-shell.is-bunny [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-bunny .cl-kao-soft { opacity: 1; }
#clippy-shell.is-guffaw [class*="cl-eyes-"],
#clippy-shell.is-guffaw [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-guffaw .cl-kao-guffaw { opacity: 1; }
#clippy-shell.is-love [class*="cl-eyes-"],
#clippy-shell.is-love [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-love .cl-kao-heartmouth { opacity: 1; }
#clippy-shell.is-drooling [class*="cl-eyes-"],
#clippy-shell.is-drooling [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-drooling .cl-kao-laughtongue { opacity: 1; }
#clippy-shell.is-flirt [class*="cl-eyes-"],
#clippy-shell.is-flirt [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-flirt .cl-kao-kissv { opacity: 1; }
#clippy-shell.is-organized [class*="cl-eyes-"],
#clippy-shell.is-organized [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-organized .cl-kao-sweetface { opacity: 1; }
#clippy-shell.is-embarrassed [class*="cl-eyes-"],
#clippy-shell.is-embarrassed [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-embarrassed .cl-kao-wince { opacity: 1; }
#clippy-shell.is-ko [class*="cl-eyes-"],
#clippy-shell.is-ko [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-ko .cl-kao-ko2 { opacity: 1; }
#clippy-shell.is-melancholy [class*="cl-eyes-"],
#clippy-shell.is-melancholy [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-melancholy .cl-kao-pipi { opacity: 1; }
#clippy-shell.is-blep [class*="cl-eyes-"],
#clippy-shell.is-blep [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-blep .cl-kao-blep { opacity: 1; }
#clippy-shell.is-peckish [class*="cl-eyes-"],
#clippy-shell.is-peckish [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-peckish .cl-kao-lipslick { opacity: 1; }
#clippy-shell.is-delighted [class*="cl-eyes-"],
#clippy-shell.is-delighted [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-delighted .cl-kao-gape { opacity: 1; }
#clippy-shell.is-dizzy [class*="cl-eyes-"],
#clippy-shell.is-dizzy [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-dizzy .cl-kao-dizzy2 { opacity: 1; }
#clippy-shell.is-squee [class*="cl-eyes-"],
#clippy-shell.is-squee [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-squee .cl-kao-squee { opacity: 1; }

/* v18.42 — ANGRY traced from Alfredo's reference ("a perfect face"). */
#clippy-shell.is-angry [class*="cl-eyes-"],
#clippy-shell.is-angry [class*="cl-mouth-"] { opacity: 0; }
#clippy-shell.is-angry .cl-kao-angry2 { opacity: 1; }

/* ═══ v18.45 — Chat font. The speech bubble defaulted to Comic Sans, which
   the chat input, buttons, and eyebrow inherited. Alfredo: replace it.
   The whole chat panel now uses the NEXUS face (DM Sans / Outfit), and
   the conversation text a hair larger for readability. Scoped to the
   chat panel so ambient bubbles elsewhere are untouched. */
.clippy-bubble.clippy-chat-bubble,
.clippy-bubble.clippy-chat-bubble .clippy-bubble-eyebrow,
.clippy-chat-input,
.clippy-chat-send,
.clippy-chat-x,
.clippy-msg-bubble,
.clippy-msg-jump {
  font-family: 'DM Sans', 'Outfit', system-ui, -apple-system, sans-serif !important;
}
.clippy-msg-bubble {
  letter-spacing: 0.005em;
}
.clippy-chat-input { font-size: 15px; }
/* His spoken answers (rendered as plain .clippy-bubble, not .clippy-chat-bubble)
   also drop Comic Sans for the clean face — the voice should read the same
   whether it's a chat reply or an ambient line. */
.clippy-bubble { font-family: 'DM Sans', 'Outfit', system-ui, -apple-system, sans-serif; }

/* ═══ v18.45 — Game leaderboard (who made the scores). NEXUS palette. */
.clippy-game-leaderboard {
  width: 100%; max-width: 340px; margin: 6px auto 4px;
  background: rgba(20,16,10,0.5); border: 1px solid rgba(212,164,78,0.28);
  border-radius: 12px; padding: 10px 12px;
}
.clippy-game-lb-title {
  font: 700 10.5px/1 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: 0.18em; color: #d4a44e; text-align: center;
  margin-bottom: 8px; text-transform: uppercase;
}
.clippy-game-lb-row {
  display: flex; align-items: center; gap: 8px;
  font: 13px/1.4 'DM Sans','Outfit',system-ui,sans-serif; color: #e8dcc2;
  padding: 4px 0; border-top: 1px dashed rgba(212,164,78,0.14);
}
.clippy-game-lb-row:first-child { border-top: none; }
.clippy-game-lb-row.is-me { color: #ffe9c0; font-weight: 700; }
.clippy-game-lb-rank {
  flex: 0 0 20px; text-align: center; font: 700 12px 'JetBrains Mono', monospace;
  color: #b09468;
}
.clippy-game-lb-row:first-child .clippy-game-lb-rank { color: #d4a44e; }
.clippy-game-lb-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clippy-game-lb-score { flex: 0 0 auto; color: #d4a44e; font-weight: 600; }
.clippy-game-lb-loading {
  font: 12px 'DM Sans', system-ui, sans-serif; color: #8a7a58; text-align: center; padding: 6px 0;
}

/* ═══ SOUL TRAVEL — sci-fi beam between devices ═══════════════════════════
   One soul, many bodies. When Alfredo moves to another machine, Clippy's soul
   leaves THIS screen (is-departing: scatter up into a thin column of light) and
   re-forms on the machine he's using (is-arriving: coalesce down out of light).
   is-away = DOZING here (his soul is focused on the screen you're using, but his
   body stays — softly present, dimmed and resting, never gone). Alfredo asked to
   always see Clippy on every laptop, so "away" is a quiet doze, not a vanish; he
   brightens and beams back to full when you return to this machine.
   See SOUL TRAVEL in clippy.js. */
#clippy-shell.is-away {
  opacity: 0.42 !important;        /* still here, just resting — not invisible */
  pointer-events: none !important; /* his soul is elsewhere, so he won't grab clicks */
  transform: scale(0.82);
  filter: saturate(0.5) brightness(0.92) drop-shadow(0 2px 6px rgba(0,0,0,0.35));
  animation: clippyDoze 5.2s ease-in-out infinite !important;
  transition: opacity 0.6s ease, transform 0.6s ease, filter 0.6s ease;
}
/* a slow, sleepy breath so a resting Clippy still reads as alive on the other screens */
@keyframes clippyDoze {
  0%, 100% { opacity: 0.34 !important; transform: scale(0.80) translateY(0); }
  50%      { opacity: 0.48 !important; transform: scale(0.84) translateY(-2px); }
}
/* ONE BODY PER SCREEN: the NEXUS tab's orb steps fully aside while the desktop
   pet is actively embodied on this same machine — the pet IS Clippy here, and
   two of him on one screen is one too many. Unlike is-away (a doze on OTHER
   machines), is-yielded clears the glass: the real body is inches away. */
#clippy-shell.is-yielded {
  opacity: 0 !important;
  pointer-events: none !important;
  transform: scale(0.9);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
#clippy-shell.is-departing {
  animation: clippyBeamOut 1.15s cubic-bezier(0.5, 0, 0.75, 0) forwards !important;
}
#clippy-shell.is-arriving {
  animation: clippyBeamIn 1.3s cubic-bezier(0.16, 1, 0.3, 1) both !important;
}
@keyframes clippyBeamOut {
  0%   { opacity: 1; transform: translateY(0) scale(1);
         filter: drop-shadow(0 0 14px rgba(125, 240, 255, 0.5)); }
  35%  { opacity: 1; transform: translateY(-4px) scaleX(0.5) scaleY(1.25);
         filter: brightness(2.2) drop-shadow(0 0 26px rgba(150, 245, 255, 0.95)); }
  70%  { opacity: 0.85; transform: translateY(-18px) scaleX(0.12) scaleY(1.9);
         filter: brightness(3) drop-shadow(0 0 34px rgba(180, 250, 255, 1)); }
  100% { opacity: 0; transform: translateY(-46px) scaleX(0.02) scaleY(2.6);
         filter: brightness(4) drop-shadow(0 0 40px rgba(200, 252, 255, 1)); }
}
@keyframes clippyBeamIn {
  0%   { opacity: 0; transform: translateY(-46px) scaleX(0.02) scaleY(2.6);
         filter: brightness(4) drop-shadow(0 0 40px rgba(200, 252, 255, 1)); }
  40%  { opacity: 0.9; transform: translateY(-14px) scaleX(0.14) scaleY(1.8);
         filter: brightness(2.6) drop-shadow(0 0 30px rgba(170, 248, 255, 0.95)); }
  72%  { opacity: 1; transform: translateY(3px) scaleX(1.12) scaleY(0.86);
         filter: brightness(1.5) drop-shadow(0 0 20px rgba(140, 240, 255, 0.7)); }
  100% { opacity: 1; transform: translateY(0) scale(1);
         filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45)) drop-shadow(0 0 14px rgba(92, 176, 255, 0.3)); }
}
/* the column of light he travels along */
#clippy-shell.is-departing::after,
#clippy-shell.is-arriving::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 7px; height: 260px;
  transform: translate(-50%, -50%);
  background: linear-gradient(to top,
    rgba(125, 240, 255, 0) 0%,
    rgba(160, 245, 255, 0.85) 46%,
    rgba(220, 253, 255, 1) 50%,
    rgba(160, 245, 255, 0.85) 54%,
    rgba(125, 240, 255, 0) 100%);
  filter: blur(2px);
  pointer-events: none;
  z-index: 3;
  animation: clippyBeamColumn 1.15s ease-in-out forwards;
}
@keyframes clippyBeamColumn {
  0%   { opacity: 0; transform: translate(-50%, -50%) scaleY(0.15); }
  30%  { opacity: 1; transform: translate(-50%, -50%) scaleY(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scaleY(1.1); }
}
@media (prefers-reduced-motion: reduce) {
  #clippy-shell.is-departing { animation: none !important; opacity: 0.42 !important; }
  #clippy-shell.is-arriving  { animation: none !important; }
  /* hold him steady-dim while resting — no sleepy breathing loop */
  #clippy-shell.is-away { animation: none !important; opacity: 0.42 !important; }
  #clippy-shell.is-departing::after,
  #clippy-shell.is-arriving::after { display: none !important; }
}

/* ═══ 🎮 CONTROLLER PANEL — every button, every speed (clippy-controller.js) ═══ */
.clippy-ctrl-overlay {
  position: fixed; inset: 0; z-index: 10050;
  background: rgba(8, 10, 18, 0.72); backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; padding: 18px;
}
.clippy-ctrl-card {
  width: min(560px, 96vw); max-height: 88vh; overflow-y: auto;
  background: linear-gradient(165deg, #141a2a 0%, #0e1220 100%);
  border: 1px solid rgba(125, 200, 255, 0.22); border-radius: 16px;
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.6), 0 0 24px rgba(92, 176, 255, 0.12);
  padding: 18px 20px 16px; color: #dce6f5;
  font: 14px 'DM Sans', system-ui, sans-serif;
}
.clippy-ctrl-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.clippy-ctrl-title { font-weight: 700; font-size: 16px; color: #9fd4ff; }
.clippy-ctrl-x {
  background: none; border: 1px solid rgba(160, 190, 230, 0.3); color: #9fb4d4;
  border-radius: 8px; width: 30px; height: 30px; cursor: pointer; font-size: 13px;
}
.clippy-ctrl-x:hover { color: #fff; border-color: rgba(160, 190, 230, 0.6); }
.clippy-ctrl-sub { margin: 6px 0 12px; font-size: 12px; color: #8fa3c2; line-height: 1.45; }
.clippy-ctrl-gamerow { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.clippy-ctrl-gamerow label { font-weight: 600; color: #b9c9e2; }
.clippy-ctrl-presets { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.clippy-ctrl-preset {
  background: rgba(92, 176, 255, 0.1); border: 1px solid rgba(92, 176, 255, 0.35);
  color: #bfe0ff; border-radius: 999px; padding: 6px 14px; cursor: pointer; font-size: 13px;
}
.clippy-ctrl-preset:hover { background: rgba(92, 176, 255, 0.22); }
.clippy-ctrl-sect {
  margin: 14px 0 6px; font-weight: 700; font-size: 12px; letter-spacing: 0.08em;
  text-transform: uppercase; color: #6f87ab;
  border-bottom: 1px solid rgba(120, 150, 200, 0.15); padding-bottom: 4px;
}
.clippy-ctrl-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 5px 0; }
.clippy-ctrl-row > label { color: #c6d4ea; font-size: 13px; flex: 0 0 46%; }
.clippy-ctrl-select {
  flex: 1; background: #0b1020; color: #dce6f5; border: 1px solid rgba(140, 170, 220, 0.3);
  border-radius: 8px; padding: 6px 8px; font-size: 13px; max-width: 54%;
}
.clippy-ctrl-sliderwrap { flex: 1; display: flex; align-items: center; gap: 10px; max-width: 54%; }
.clippy-ctrl-slider { flex: 1; accent-color: #5cb0ff; }
.clippy-ctrl-val { min-width: 46px; text-align: right; color: #9fd4ff; font-variant-numeric: tabular-nums; font-size: 12px; }
.clippy-ctrl-help { font-size: 11px; color: #71849f; margin: -2px 0 4px; padding-left: 2px; line-height: 1.35; }
.clippy-ctrl-note {
  margin: 10px 0 2px; padding: 8px 10px; border-radius: 10px; font-size: 12px;
  background: rgba(95, 217, 122, 0.08); border: 1px solid rgba(95, 217, 122, 0.22); color: #a9dfb6;
}
.clippy-ctrl-status { min-height: 18px; margin-top: 10px; font-size: 12px; color: #9fd4ff; }
.clippy-ctrl-foot { display: flex; gap: 10px; margin-top: 8px; flex-wrap: wrap; }
.clippy-ctrl-save {
  flex: 1; background: linear-gradient(135deg, #2f7fd4, #5cb0ff); color: #fff; border: none;
  border-radius: 10px; padding: 10px 16px; font-weight: 700; font-size: 14px; cursor: pointer;
}
.clippy-ctrl-save:hover { filter: brightness(1.12); }
.clippy-ctrl-save:disabled { opacity: 0.55; cursor: wait; }
.clippy-ctrl-reset {
  background: none; border: 1px solid rgba(160, 190, 230, 0.3); color: #9fb4d4;
  border-radius: 10px; padding: 10px 14px; cursor: pointer; font-size: 13px;
}
.clippy-ctrl-reset:hover { color: #fff; border-color: rgba(160, 190, 230, 0.6); }
@media (max-width: 520px) {
  .clippy-ctrl-row { flex-wrap: wrap; }
  .clippy-ctrl-row > label { flex: 1 1 100%; }
  .clippy-ctrl-select, .clippy-ctrl-sliderwrap { max-width: 100%; width: 100%; }
}
