/* ==========================================================================
   catfx.css — the download-finale mascot (js/catfx.js, window.AtlasCatFX).
   A bespoke SVG cat that plays OVER the video-loop seam and walks through six
   emotional states, one per completed loop, so the loop reads as intentional.

   Mirrors endfx.css discipline:
   - lives INSIDE #end-pin, z-index:2 (above #end-video/#end-mask/#end-glow,
     below #end-reveal buttons z3 and #end-sound z4).
   - PERF LAW: no backdrop-filter / filter anywhere in #app. The bubble is
     faux-glass (layered translucent gradients + hairline border only).
   - VISIBILITY is CSS-gated on #end.is-revealed.er-settled (so it is testable
     by toggling those classes); the LOOPING idle keyframes are additionally
     gated on .catfx-active (JS/IO) so they rest when the finale is off-screen.
   - reduced-motion / html[data-anim="off"] (tier2) / html[data-perf="3"] all
     drop tweens + idle to static; catfx.js also freezes progression there.
   ========================================================================== */

/* ------------------------------------------------------------ root + entrance */
.catfx-root{
  position:absolute;left:clamp(14px,3vw,32px);bottom:clamp(12px,3vh,28px);
  width:clamp(120px,12vw,150px);z-index:2;pointer-events:none;
  opacity:0;transform:translate(-16px,26px) scale(.86);
  transition:opacity .42s var(--ease),transform .52s cubic-bezier(.34,1.56,.64,1)}
/* the finale reveals -> the cat slides in from the corner with an overshoot bounce */
#end.end--video.is-revealed.er-settled .catfx-root{opacity:1;transform:none}
.catfx-svg{display:block;width:100%;height:auto;overflow:visible;
  /* palette (site charcoal body, cream muzzle, amber eyes, blue rim-light) */
  --cb:#2a3042;--cb2:#333b50;--cc:#f2e6cf;--ci:#ffcf6b;--cp:#141a2a;--cn:#e59aa6;--cr:#5b7cfa}

/* ------------------------------------------------------------ static fills */
.cat-shadow{fill:rgba(0,0,0,.32)}
.cat-body,.cat-tail,.cat-ear,.cat-face{fill:var(--cb)}
.cat-paw{fill:var(--cb2)}
.cat-ear-in{fill:var(--cc)}
.cat-muzzle{fill:var(--cc)}
.eye-ball{fill:var(--ci)}
.eye-pupil{fill:var(--cp)}
.eye-shine{fill:#fff}
.eye-lid{fill:var(--cb)}
.eye-line{fill:none;stroke:var(--cp);stroke-width:2.4;stroke-linecap:round}
.cat-nose{fill:var(--cn)}
.mouth{fill:none;stroke:var(--cp);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.m-angry-fill{fill:var(--cp);stroke:none}
.brow{fill:none;stroke:var(--cp);stroke-width:2.4;stroke-linecap:round}
.cat-whisker{fill:none;stroke:rgba(240,244,255,.5);stroke-width:1.3;stroke-linecap:round}
.cat-tear{fill:#a9d4ff}
.cat-steam{fill:none;stroke:rgba(200,210,235,.72);stroke-width:2;stroke-linecap:round}
.cat-rim{fill:none;stroke:var(--cr);stroke-width:2.6;stroke-linecap:round;opacity:.5}

/* ------------------------------------------------------------ transform rigs
   transform-box:view-box lets these use the SVG's own 0..180 coordinate space
   for their pivots; the eyes/lids pivot about their own box (fill-box). */
.cat,.cat-body,.cat-head,.cat-tail,.cat-ear--l,.cat-ear--r,.cat-paw--l,.cat-paw--r,.cat-whiskers{
  transform-box:view-box}
.cat{transform-origin:90px 160px}
.cat-body{transform-origin:90px 160px}
.cat-head{transform-origin:90px 98px;transition:transform .26s var(--ease)}
.cat-tail{transform-origin:114px 150px;transition:transform .3s var(--ease)}
.cat-ear--l{transform-origin:76px 64px;transition:transform .24s var(--ease)}
.cat-ear--r{transform-origin:104px 64px;transition:transform .24s var(--ease)}
.cat-paw--l,.cat-paw--r{transition:transform .26s var(--ease)}
.cat-whiskers{transform-origin:90px 90px;transition:transform .26s var(--ease)}
.eye-lid,.cat-eye{transform-box:fill-box;transform-origin:center}
.eye-lid{transform:translateY(-20px);transition:transform .22s var(--ease)}
.cat-eye{transition:transform .22s var(--ease)}
.eye-open{transition:opacity .2s var(--ease)}
.eye-line,.brow,.cat-tear,.cat-steam{opacity:0;transition:opacity .2s var(--ease)}
.cat-mouth>*{opacity:0;transition:opacity .2s var(--ease)}
.eye-pupil{transition:transform .24s var(--ease)}

/* ============================================================ STATE: happy
   winky: left eye winks (arc), right open + bright/wide; ears up; big smile;
   tail up + gentle wag. (entrance overshoot handled on .catfx-root above.) */
.catfx--happy .cat-eye--l .eye-open{opacity:0}
.catfx--happy .cat-eye--l .eye-line{opacity:1}
.catfx--happy .cat-eye--r .eye-lid{transform:translateY(-22px)}
.catfx--happy .m-happy{opacity:1}

/* ============================================================ STATE: neutral
   both eyes open, slight smile, ears/gaze toward the CTA (head tilt + pupils
   right + a little pointing paw). Pairs with the glowing buttons (#end.dlx-cue2). */
.catfx--neutral .m-neutral{opacity:1}
.catfx--neutral .cat-head{transform:rotate(4deg)}
.catfx--neutral .eye-pupil{transform:translateX(2px)}
.catfx--neutral .cat-paw--r{transform:translate(3px,-4px)}

/* ============================================================ STATE: worried
   eyes a bit wider, raised brows, ears splay out, faint frown, head tilt. */
.catfx--worried .cat-eye{transform:scale(1.07)}
.catfx--worried .eye-lid{transform:translateY(-23px)}
.catfx--worried .brow-worry{opacity:1}
.catfx--worried .m-worry{opacity:1}
.catfx--worried .cat-head{transform:rotate(-4deg)}
.catfx--worried .cat-ear--l{transform:rotate(-11deg)}
.catfx--worried .cat-ear--r{transform:rotate(11deg)}

/* ============================================================ STATE: sad
   droopy half-closed eyes, ears back/down, downturned mouth, a tear, slump. */
.catfx--sad .eye-lid{transform:translateY(-10px)}
.catfx--sad .m-sad{opacity:1}
.catfx--sad .cat-tear{opacity:1}
.catfx--sad .cat-head{transform:rotate(3deg) translateY(2px)}
.catfx--sad .cat-ear--l{transform:rotate(-26deg) translateY(3px)}
.catfx--sad .cat-ear--r{transform:rotate(26deg) translateY(3px)}
.catfx--sad .cat-whiskers{transform:rotate(4deg) translateY(2px)}
.catfx--sad .cat-body{transform:scaleY(.97)}

/* ============================================================ STATE: grumpy
   half-lidded eyes, ears flat, flat pursed mouth, sharp tail flick. */
.catfx--grumpy .eye-lid{transform:translateY(-9px)}
.catfx--grumpy .m-flat{opacity:1}
.catfx--grumpy .cat-ear--l{transform:rotate(-34deg) translateY(3px)}
.catfx--grumpy .cat-ear--r{transform:rotate(34deg) translateY(3px)}

/* ============================================================ STATE: angry
   narrowed eyes + angry-V brows, ears pinned, tight snarl, steam puffs,
   SITS + runs a forever angry idle (tail lash + body shake). Text stops. */
.catfx--angry .cat-eye--l .eye-lid{transform:translateY(-8px) rotate(13deg)}
.catfx--angry .cat-eye--r .eye-lid{transform:translateY(-8px) rotate(-13deg)}
.catfx--angry .brow-angry{opacity:1}
.catfx--angry .m-angry{opacity:1}
.catfx--angry .cat-steam{opacity:1}
.catfx--angry .cat-ear--l{transform:rotate(-44deg) translateY(4px)}
.catfx--angry .cat-ear--r{transform:rotate(44deg) translateY(4px)}
.catfx--angry .cat-body{transform:translateY(2px)}

/* ============================================================ IDLE keyframes
   Only while active (in view, tab visible) AND motion allowed. State transforms
   above are held even when not active — only these LOOPS pause off-screen. */
.catfx-active .cat-body{animation:cat-breathe 3.4s ease-in-out infinite}
.catfx-active.catfx--angry .cat-body{animation:none}          /* angry shakes instead */
.catfx-active.catfx--happy .cat-tail{animation:cat-tail-wag 2.4s ease-in-out infinite}
.catfx-active.catfx--neutral .cat-tail{animation:cat-tail-sway 3.4s ease-in-out infinite}
.catfx-active.catfx--sad .cat-tail{animation:cat-tail-sway 5s ease-in-out infinite}
.catfx-active.catfx--grumpy .cat-tail{animation:cat-tail-flick 1.7s ease-in-out infinite}
.catfx-active.catfx--angry .cat-tail{animation:cat-tail-lash .5s ease-in-out infinite}
.catfx-active.catfx--angry .cat{animation:cat-shake .17s linear infinite}
.catfx-active.catfx--angry .cat-steam{animation:cat-steam-rise 1.5s ease-out infinite}
/* blink on the open, unwinked eyes (happy blinks the right eye only) */
.catfx-active.catfx--neutral .eye-lid,
.catfx-active.catfx--happy .cat-eye--r .eye-lid{animation:cat-blink 4.6s ease-in-out infinite}
/* an occasional ear twitch keeps happy alive */
.catfx-active.catfx--happy .cat-ear--l{animation:cat-ear-twitch 5.2s ease-in-out infinite}

@keyframes cat-breathe{0%,100%{transform:scaleY(1)}50%{transform:scaleY(1.025) translateY(-1px)}}
@keyframes cat-tail-wag{0%,100%{transform:rotate(-7deg)}50%{transform:rotate(9deg)}}
@keyframes cat-tail-sway{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(5deg)}}
@keyframes cat-tail-flick{0%,58%,100%{transform:rotate(2deg)}70%{transform:rotate(-15deg)}82%{transform:rotate(7deg)}}
@keyframes cat-tail-lash{0%,100%{transform:rotate(-17deg)}50%{transform:rotate(19deg)}}
@keyframes cat-shake{0%,100%{transform:translate(0,1px)}25%{transform:translate(-1.3px,1px)}75%{transform:translate(1.3px,1px)}}
@keyframes cat-blink{0%,90%,100%{transform:translateY(-20px)}95%{transform:translateY(0)}}
/* happy right-eye blink parks a touch wider (matches its -22 open pose) */
.catfx-active.catfx--happy .cat-eye--r .eye-lid{animation-name:cat-blink-wide}
@keyframes cat-blink-wide{0%,90%,100%{transform:translateY(-22px)}95%{transform:translateY(0)}}
@keyframes cat-ear-twitch{0%,86%,100%{transform:rotate(0)}90%{transform:rotate(-9deg)}94%{transform:rotate(2deg)}}
@keyframes cat-steam-rise{0%{opacity:0;transform:translateY(2px)}30%{opacity:1}100%{opacity:0;transform:translateY(-6px)}}

/* ============================================================ speech bubble
   faux-glass: layered translucent dark gradient + hairline border, no blur.
   Sits above the cat with a small pointer aimed down at it. */
.catfx-bubble{position:absolute;left:22px;bottom:calc(100% - 22px);
  padding:8px 13px;border-radius:14px;
  background:linear-gradient(165deg,rgba(44,50,68,.9),rgba(16,18,26,.94));
  border:1px solid rgba(160,175,255,.24);
  box-shadow:0 10px 30px rgba(0,0,0,.42),inset 0 1px 0 rgba(255,255,255,.09);
  color:#eef1fb;font-family:var(--font);font-weight:500;font-size:13px;line-height:1.2;
  white-space:nowrap;
  opacity:0;transform:scale(.82);transform-origin:24px bottom;
  transition:opacity .4s var(--ease),transform .5s cubic-bezier(.34,1.56,.64,1)}
#end.end--video.is-revealed.er-settled .catfx-bubble{opacity:1;transform:none;transition-delay:.14s}
.catfx-bubble-tail{position:absolute;left:24px;top:100%;width:0;height:0;
  border-left:7px solid transparent;border-right:7px solid transparent;
  border-top:8px solid rgba(16,18,26,.94)}
.catfx-bubble-txt{display:inline-block;
  transition:opacity .16s var(--ease),transform .16s var(--ease)}
.catfx-bubble--swap .catfx-bubble-txt{opacity:0;transform:translateY(-3px)}

/* ============================================================ perf + a11y
   tier2 (data-anim=off): mood still swaps but INSTANTLY (kill tweens + idle).
   tier3 / static / reduced-motion / JS-freeze: fully static happy cat. */
html[data-anim="off"] .catfx-root,
html[data-anim="off"] .catfx-root *,
html[data-perf="3"] .catfx-root,
html[data-perf="3"] .catfx-root *,
.catfx-frozen,.catfx-frozen *{animation:none!important;transition:none!important}

@media (prefers-reduced-motion:reduce){
  .catfx-root,.catfx-root *{animation:none!important;transition:none!important}
  .catfx-root{opacity:1;transform:none}
  .catfx-bubble{opacity:1;transform:none}
}

/* never crowd the CTA: on narrow / short finales the reveal takes the stage */
@media (max-width:760px),(max-height:560px){.catfx-root{display:none}}
