/* The cat, wherever it appears: the hero on Home, the perch on Start on the song page, the
   heads peeking from behind every song card, and the Maine Coon napping on Home's app card (at
   the end).
   Shared by every public page, like the rigs it styles (cats.js) and the 3D cat drawn from Mochi's
   (cat3d.js).

/* The parts. `.cat` is every cat; `.hero-cat` is the ones that MOVE (the hero and the perch). */
.cat .tail-fur { fill: none; stroke: var(--cat); stroke-linecap: round; }
.cat .eye { fill: var(--cat-eye); }
.cat .nose { fill: #ff7fb0; }
.cat .bean { fill: var(--pink); }
.cat .ink-line { fill: none; stroke: var(--cat-line); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.cat[data-eyes="happy"] .eyes-open, .cat[data-eyes="open"] .eyes-happy { display: none; }

/* Clipped at its bottom edge — on the keybed — so the entrance reads as the cat climbing up
   from behind what it sits on — the keybed on Home, the Start button on a song page. The padding is headroom for the hop and room for the tail's swish. */
/* Standing side-on to walk, the 3D cat is wider than the rig's box — its canvas reaches 40% past
   each side — so the stage's sides are a percentage of the box, and 60% clears it at any size.
   That overhang is an invisible box over its neighbours, and on Home it sat on top of the sound
   pill and took its clicks — so the stage lets the pointer through and only the cat's own button
   catches it. (`button`: the song page's perch is a span inside Start, pointer-events off.) */
.cat-stage { overflow: hidden; padding: 28px 60% 0; margin: -28px -60% 0; pointer-events: none; }
button.cat-btn { pointer-events: auto; }
.cat-btn {
  position: relative; display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent; border-radius: 40% 40% 12px 12px;
  animation: cat-in 800ms cubic-bezier(.3,1.45,.5,1) 350ms both;
}
.cat-btn svg { display: block; width: 100%; height: auto; overflow: visible; }

@keyframes cat-in { from { transform: translateY(var(--cat-from, 105%)); } to { transform: none; } }

/* What moves. The tail's pivot is inline (cats.js); these are the shared loops. */
.hero-cat .tail { animation: swish 2.6s ease-in-out infinite; }
.hero-cat .body { transform-origin: 70px 150px; animation: breathe 3.2s ease-in-out infinite; }
.hero-cat .head { transform-origin: 70px 96px; }
.hero-cat .paw { transform-box: fill-box; transform-origin: 50% 100%; }
.hero-cat .eyes-open { transform-box: fill-box; transform-origin: center; transition: transform 90ms ease; }
.hero-cat .eyes-open.blink { transform: scaleY(.08); }
.hero-cat .looks { transition: transform 120ms ease-out; }
@keyframes swish { 0%, 100% { transform: rotate(-7deg); } 50% { transform: rotate(13deg); } }
@keyframes breathe { 50% { transform: scale(1.02, 1.035); } }

/* What floats up off the cat during a move — a note, a "z" (cat-moves.js places each one). */
.cat-emotes { position: absolute; inset: 0; z-index: 7; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .cat-btn, .hero-cat .tail, .hero-cat .body { animation: none; }
  .hero-cat .looks { transition: none; }
}

/* ---- the Maine Coon napping on Home's app card (cats.js COON_NAP, ui.js napper) ---------------
   On the card's top edge, near its right end, a layer above the card's surface (home.css): its belly
   sags a little over the edge, its paws rest on it, and its tail hangs over the card's corner, the
   way the reference's hangs over its banner (docs/cat-sleeping.png). The card's right edge is at
   x 207 of the drawing's 150-wide box (38% of it past the box), just past the tail. Everything below is
   sized off --w through --u (1 at the 156px it was drawn at), so the cat can be any size: the zzz,
   the "!" and the hearts shrink with it. The clip-path is only a ceiling — nothing paints more than
   116 units' worth above the card, the room home.css keeps (the band's padding and margin; the
   rows' gap where the cards stack) — and nothing below it is clipped.
   It napped on the AD first; an AdSense slot now carries no cat (ui.js adSlot). */
.coon-perch {
  --w: 130px; --u: calc(var(--w) / 156);
  position: absolute; z-index: 2; bottom: 100%; right: calc(var(--w) * .38); width: var(--w);
  margin: 0 -1px 1px 0;   /* offsets start inside the card's 1px border; this measures from its outside */
  clip-path: inset(calc(100% - 116 * var(--u)) -100% -300% -100%);
}
@media (max-width: 960px) { .coon-perch { --w: 120px; } }
.coon-nap { display: block; width: 100%; height: auto; overflow: visible; --cat: #f6bd4f; }

/* The drawing (viewBox 0 0 150 90: y 90 the card's top edge, x 207 its right edge). Golden fur,
   tapered tabby bands a shade darker, cream paws with toe lines: the footer's Maine Coon
   (base.css, .coon-cat), whole. */
.coon-nap .cream { fill: #ffe3a3; }
.coon-nap .band { fill: #df9333; }
.coon-nap .thigh { fill: none; stroke: #df9333; stroke-width: 1.6; stroke-linecap: round; }
.coon-nap .toe { fill: none; stroke: #e2b86a; stroke-width: 1; stroke-linecap: round; }
.coon-nap .shut { fill: none; stroke: var(--cat-eye); stroke-width: 1.3; stroke-linecap: round; }
.coon-nap .yawn { fill: #6a1b3c; transform-box: fill-box; transform-origin: 50% 0; transform: scale(0); }
.coon-nap .yawn .tongue { fill: #ff7fb0; }
/* It swells out of the nose: the origin is the nose's tip (20, 26.2 in the head's 40x38) within the
   bubble's own box (18.5-29.5 x 24.5-39.6). It used to grow from 20% 20%, which left it under the
   chin, nowhere near the nose. */
.coon-nap .bubble { transform-box: fill-box; transform-origin: 14% 11%; transform: scale(0); }
.coon-nap .bubble circle:not(.shine) { fill: rgba(160, 210, 255, .72); stroke: rgba(255, 255, 255, .9); stroke-width: .5; }
.coon-nap .bubble .shine { fill: #fff; }
.coon-nap .burst { fill: none; stroke: rgba(200, 230, 255, .95); stroke-width: .8; stroke-linecap: round; opacity: 0;
                  transform-box: fill-box; transform-origin: center; }

/* The rig. The body's outline morphs itself (cats.js); the head and the front paws are transforms
   on top, laid out SITTING and moved down and apart to lie — the chin on the paws, one under each
   cheek, the bubble hanging between them. Sitting, the chest comes back over the haunch, which
   stays on the card's corner with the tail, so the head and paws move right as it sits. */
.coon-nap .body { transform-box: view-box; transform-origin: 80px 90px; }
.coon-nap :is(.mitt-l, .mitt-r) { transform-box: view-box; }
/* The tail turns at its root and SWAYS a beat behind (a skew from the root, so the lower it is the
   further it goes): follow-through, the tip trailing the root, where one stiff turn of a plume this
   long read as a plank. It puffs about its own middle, fatter not longer — puffed from the root it
   stretched, and jumped. The tail IS the reference's (docs/cat-sleeping.png): its outline traced
   off the picture's pixels, the pixel staircase smoothed away, and redrawn in long curves with only
   its flicks' tips kept sharp — the first trace, curved through every pixel point, kept the
   picture's noise and read lumpy. Four drawings by eye before it read jagged, lumpy, a sausage, and
   short. Its root runs deep
   into the body, under it in both poses: traced to the lying hip alone, it came away from the body
   as the cat sat up (the haunch tucks in) and as it swung. */
.coon-nap :is(.tail, .tail-sway) { transform-box: view-box; transform-origin: 152px 81px; }   /* the hip */
.coon-nap .tail-puff { transform-box: view-box; transform-origin: 171px 97px; }
.coon-nap .tail-band { fill: none; stroke: #df9333; stroke-width: 4.2; stroke-linecap: round; }
.coon-nap .tilt { transform-box: view-box; transform-origin: 33px 54px; }   /* the neck, in sitting coordinates */
/* The body's own curve (cats.js, the SMIL sit), so the head rides the neck: an overshoot here
   (it was .3,1.4,.5,1) floated the head off a body whose outline cannot overshoot. */
.coon-nap .head { transition: transform 420ms cubic-bezier(.3, .9, .4, 1); }

/* Asleep (and settling): lying down, eyes shut, breathing, the bubble swelling on each breath. */
.coon-nap .head { transform: translate(0, 34px); }
.coon-nap .mitt-l { transform: translateX(-8.5px); }
.coon-nap .mitt-r { transform: translateX(13.5px); }
.coon-nap .eye { display: none; }
.coon-perch[data-state="sleep"] .body { animation: nap-breathe 3.2s ease-in-out infinite; }
.coon-perch[data-state="sleep"] .head-bob { animation: nap-bob 3.2s ease-in-out infinite; }
.coon-perch[data-state="sleep"] .bubble { animation: nap-bubble 3.2s ease-in-out infinite; }
.coon-perch[data-state="sleep"] .tail { animation: nap-tail 6.4s ease-in-out infinite; }
.coon-perch[data-state="sleep"] .tail-sway { animation: nap-sway-slow 6.4s ease-in-out .8s infinite; }

/* Awake: the bubble POPS (it is what woke the cat), a "!", a hop that squashes on landing, the tail
   puffs, the eyes snap open — then sat up, the tilt and hearts loop while the pointer stays (.over),
   the client's brief. Picked from four wake reactions drawn in the mockup (the others: eyes
   following the pointer, a lucky-cat wave, a happy purr). The tail swishes lazily: a cat its own bubble just
   woke is a bit sleepy. Its eyes stay ROUND while you are there — sleepy eyes there were tried and
   dropped, the round eyes are cuter — and only go sleepy once you leave (below). */
.coon-perch[data-state="awake"] .head, .coon-perch[data-state="yawn"] .head { transform: translate(20px, 0); }
.coon-perch:is([data-state="awake"], [data-state="yawn"]) :is(.mitt-l, .mitt-r) { transform: translateX(20px); }
/* The paws STEP to where they go, each lifted off the edge in a small arc and set down, the right a
   beat after the left; they slid there flat before, and a paw sliding along a ledge skates. The
   yawn keeps the same animation, so it does not step again. */
.coon-perch:is([data-state="awake"], [data-state="yawn"]) .mitt-l { animation: mitt-l-up 460ms cubic-bezier(.3, .7, .4, 1) both; }
.coon-perch:is([data-state="awake"], [data-state="yawn"]) .mitt-r { animation: mitt-r-up 460ms 80ms cubic-bezier(.3, .7, .4, 1) both; }
.coon-perch[data-state="settle"] .mitt-l { animation: mitt-l-down 760ms cubic-bezier(.45, 0, .3, 1) both; }
.coon-perch[data-state="settle"] .mitt-r { animation: mitt-r-down 760ms 100ms cubic-bezier(.45, 0, .3, 1) both; }
@keyframes mitt-l-up { 0% { transform: translate(-8.5px, 0); } 45% { transform: translate(7px, -7px); } 100% { transform: translate(20px, 0); } }
@keyframes mitt-r-up { 0% { transform: translate(13.5px, 0); } 45% { transform: translate(17px, -4px); } 100% { transform: translate(20px, 0); } }
@keyframes mitt-l-down { 0% { transform: translate(20px, 0); } 50% { transform: translate(5px, -6px); } 100% { transform: translate(-8.5px, 0); } }
@keyframes mitt-r-down { 0% { transform: translate(20px, 0); } 50% { transform: translate(17px, -3px); } 100% { transform: translate(13.5px, 0); } }
.coon-perch[data-state="awake"] .eye { display: inline; transform-box: fill-box; transform-origin: center; animation: nap-startle 420ms ease-out; }
.coon-perch[data-state="awake"] .shut { opacity: 0; }
.coon-perch[data-state="awake"] .bubble { animation: nap-pop 260ms ease-out both; }
.coon-perch[data-state="awake"] .burst { animation: nap-burst 420ms 160ms ease-out both; }
.coon-perch[data-state="awake"] .bang { animation: nap-bang 900ms 120ms ease-out both; }
.coon-perch[data-state="awake"] .coon-nap { transform-origin: 50% 100%; animation: nap-hop 520ms 100ms cubic-bezier(.3, .7, .4, 1); }
.coon-perch[data-state="awake"] .tail { animation: nap-swish 2.8s ease-in-out infinite; }
.coon-perch[data-state="awake"] .tail-sway { animation: nap-sway 2.8s ease-in-out .35s infinite; }
.coon-perch[data-state="awake"] .tail-puff { animation: nap-puff 1.1s 100ms ease-in-out; }
.coon-perch[data-state="awake"].over .tilt { animation: nap-tilt 1.8s ease-in-out infinite; }

/* Dozing back off. Once the pointer leaves (awake without .over: ui.js's 3 s before the yawn, the
   same 3s as these), the round eyes MELT into soft half-shut ovals, then close once — the sleeping
   ‿ — while the head droops and catches itself, and open to ovals again; a pointer that comes back
   puts .over back and the eyes are round again at once. The yawn squeezes them shut; lying down
   (settle) the ovals come back and close into ‿ as it lands — asleep.
   Picked in review (docs/mockups/round6-sleepy-eyes.html): A's melting dots, with B's closing.
   The first try, flat-topped half-disc lids, read grumpy, not sleepy. */
.coon-perch[data-state="awake"]:not(.over) .eye { animation: nap-eyes-melt 3s ease-in-out forwards; }
.coon-perch[data-state="awake"]:not(.over) .shut { animation: nap-eyes-blink 3s ease-in-out forwards; }
.coon-perch[data-state="awake"]:not(.over) .tilt { animation: nap-nod 3s forwards; }
.coon-perch[data-state="settle"] .eye {
  display: inline; transform-box: fill-box; transform-origin: center; transform: translateY(.5px) scale(1.15, .45);
  animation: nap-eyes-close 800ms ease-in forwards;
}
.coon-perch[data-state="settle"] .shut { animation: nap-eyes-shutting 800ms ease-in forwards; }
@keyframes nap-eyes-melt {
  0%, 18% { transform: none; opacity: 1; }
  34%, 55% { transform: translateY(.5px) scale(1.15, .45); opacity: 1; }
  60%, 72% { transform: translateY(.5px) scale(1.15, .45); opacity: 0; }
  78%, 100% { transform: translateY(.5px) scale(1.15, .45); opacity: 1; }
}
@keyframes nap-eyes-blink { 0%, 55% { opacity: 0; } 60%, 72% { opacity: 1; } 78%, 100% { opacity: 0; } }
@keyframes nap-nod {
  0%, 50% { transform: none; animation-timing-function: ease-in; }
  68% { transform: rotate(7deg) translateY(4px); animation-timing-function: cubic-bezier(.2, 1.6, .4, 1); }
  76% { transform: rotate(-3deg) translateY(-1px); }
  84%, 100% { transform: none; }
}
@keyframes nap-eyes-close { 0%, 55% { opacity: 1; } 100% { opacity: 0; } }
@keyframes nap-eyes-shutting { 0%, 55% { opacity: 0; } 100% { opacity: 1; } }

/* The yawn: still sitting, head thrown back a little, mouth wide, eyes squeezed. Then settle lies
   down, slower than it sat up, and sleep starts breathing again. */
.coon-perch[data-state="yawn"] .tilt { animation: nap-yawn-head 1.5s ease-in-out both; }
.coon-perch[data-state="yawn"] .yawn { animation: nap-yawn 1.5s ease-in-out both; }
.coon-perch[data-state="settle"] .head {
  transition-duration: 800ms; transition-timing-function: cubic-bezier(.45, 0, .3, 1);
}

@keyframes nap-breathe { 50% { transform: scaleY(1.05); } }
@keyframes nap-bob { 50% { transform: translateY(-1.6px); } }
@keyframes nap-bubble { 0%, 100% { transform: scale(.25); } 55% { transform: scale(1); } 85% { transform: scale(.55); } }
@keyframes nap-tail { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(-3deg); } }
@keyframes nap-swish { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(-7deg); } }
@keyframes nap-sway { 0%, 100% { transform: skewX(0deg); } 50% { transform: skewX(8deg); } }
@keyframes nap-sway-slow { 0%, 100% { transform: skewX(0deg); } 50% { transform: skewX(3deg); } }
@keyframes nap-startle { 0% { transform: scale(.2, .1); } 45% { transform: scale(1.45); } 100% { transform: scale(1); } }
@keyframes nap-pop { 0% { transform: scale(1); opacity: 1; } 70% { transform: scale(1.4); opacity: .9; } 100% { transform: scale(1.6); opacity: 0; } }
@keyframes nap-burst { 0% { transform: scale(.5); opacity: 0; } 30% { opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } }
@keyframes nap-bang { 0% { transform: scale(.3) rotate(-12deg); opacity: 0; } 25% { transform: scale(1.25) rotate(6deg); opacity: 1; }
                      45% { transform: scale(1) rotate(0deg); } 80% { opacity: 1; } 100% { transform: translateY(-6px); opacity: 0; } }
@keyframes nap-hop { 0%, 100% { transform: none; } 35% { transform: translateY(-9px) scale(.96, 1.05); } 65% { transform: scale(1.05, .95); } 85% { transform: scale(.99, 1.01); } }
@keyframes nap-puff { 0%, 100% { transform: none; } 25%, 55% { transform: scale(1.16, 1.03); } }
@keyframes nap-tilt { 0%, 100% { transform: rotate(0deg); } 30%, 60% { transform: rotate(-13deg); } }
@keyframes nap-yawn-head { 0%, 100% { transform: rotate(0deg); } 35%, 70% { transform: rotate(7deg) translateY(-2px); } }
@keyframes nap-yawn { 0%, 100% { transform: scale(0); } 35%, 70% { transform: scale(1); } }

/* What floats up — zzz asleep, the "!" and the hearts awake — in units of --u off the cat's box, all
   under the clip's 116: lying, the head's crown is ~50 up; sitting, ~94, so the hearts rise beside
   it, one left of the head and two over the back. */
.nap-fx { position: absolute; inset: auto 0 0 0; height: calc(116 * var(--u)); pointer-events: none; }
.nap-fx i { position: absolute; font-style: normal; font-weight: 800; line-height: 1; letter-spacing: 0; color: var(--accent); opacity: 0; }
.nap-fx .bang { left: 31%; bottom: calc(88 * var(--u)); font-size: calc(22 * var(--u)); color: var(--pink); }
.nap-z i { left: 12%; bottom: calc(54 * var(--u)); font-size: calc(13 * var(--u)); color: #c9a0dc; }   /* the reference's lilac */
.nap-z i:nth-child(2) { font-size: calc(16 * var(--u)); animation-delay: -1.1s !important; }
.nap-z i:nth-child(3) { font-size: calc(19 * var(--u)); animation-delay: -2.2s !important; }
/* The zzz and the hearts never stop mid-air: they loop on regardless, and it is their row that
   fades in and out with the state, so a z or a heart caught in flight drifts away instead of
   vanishing. */
.nap-z, .nap-hearts { transition: opacity 400ms ease; }
.nap-z i { animation: nap-z 3.3s linear infinite; }
.coon-perch:not([data-state="sleep"]) .nap-z { opacity: 0; }
.nap-hearts { opacity: 0; }
.coon-perch[data-state="awake"].over .nap-hearts { opacity: 1; }
.nap-hearts i { width: calc(16 * var(--u)); height: calc(16 * var(--u)); }
.nap-hearts i svg { display: block; width: 100%; height: 100%; fill: var(--pink); }
.nap-hearts i:nth-child(1) { left: 4%; bottom: calc(58 * var(--u)); --dx: -10; }
.nap-hearts i:nth-child(2) { left: 62%; bottom: calc(70 * var(--u)); --dx: 2; animation-delay: .3s !important; }
.nap-hearts i:nth-child(3) { left: 74%; bottom: calc(50 * var(--u)); --dx: 12; animation-delay: .6s !important; }
.coon-perch[data-state="awake"] .nap-hearts i { animation: nap-heart 1.8s cubic-bezier(.2, .7, .3, 1) infinite; }
@keyframes nap-z {
  0% { transform: translate(0, 0) scale(.6); opacity: 0; }
  15% { opacity: 1; }
  80% { opacity: .9; }
  100% { transform: translate(calc(-22 * var(--u)), calc(-50 * var(--u))) scale(1); opacity: 0; }
}
@keyframes nap-heart {
  0% { transform: translate(0, 0) scale(.3); opacity: 0; }
  20% { opacity: 1; }
  70%, 100% { transform: translate(calc(var(--dx) * var(--u)), calc(-30 * var(--u))) scale(1); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  /* Still and asleep; waking swaps the pose without moving (ui.js also makes the morph instant).
     One z, one heart: states, not motion. */
  .coon-perch * { animation: none !important; transition: none !important; }
  .coon-perch[data-state="sleep"] .nap-z i:nth-child(2) { opacity: 1; transform: translate(calc(-8 * var(--u)), calc(-26 * var(--u))); }
  .coon-perch[data-state="sleep"] .bubble { transform: scale(.8); }
  .coon-perch[data-state="awake"].over .nap-hearts i:nth-child(2) { opacity: 1; transform: translateY(calc(-10 * var(--u))); }
  .coon-perch[data-state="yawn"] .yawn { transform: scale(1); }
  .coon-perch[data-state="settle"] .eye { display: none; }
}
