/* ==========================================================================
   MewPurr — doodle cat loading overlay
   Self-contained: only depends on the asset, not on the rest of the theme.
   All variables are prefixed --ld- so this can be dropped into any site.

   Progressive enhancement, in this order:
     no JS        -> loader is display:none, content is visible. Nothing traps.
     JS, no GSAP  -> loader shows, then a plain CSS/callback path closes it.
     JS + GSAP    -> full wobble and walk-off.
   ========================================================================== */

:root {
  /* Change these two lines to re-skin the whole loader. */
  --ld-bg: #FFFFFF;
  --ld-ink: #221D18;

  --ld-z: 10000;                    /* above the theme's grain (9998) and drawer (1000) */

  /* Cat width per breakpoint. Height stays auto — never stretch the PNG. */
  --ld-cat-w: clamp(140px, 19vw, 300px);

  --ld-text-size: 13px;
  --ld-text-tracking: .18em;
}

/* --------------------------------------------------------------------------
   Structure
   -------------------------------------------------------------------------- */

.site-loader {
  position: fixed;
  inset: 0;                          /* top/left/width/height in one line */
  z-index: var(--ld-z);
  display: none;                     /* no JS: never shown */
  align-items: center;
  justify-content: center;
  background: var(--ld-bg);
  /* opacity is animated by GSAP; visibility is toggled with it */
  will-change: opacity;
}

/* The overlay only exists while it is wanted.
   - no JS                          -> never shown
   - JS, before the loader decides  -> still not shown (the page is on screen and
     readable from first paint; nothing is hidden waiting for a decision)
   - .loader-armed                  -> laid out but invisible. This is the state
     that fetches the frames without the visitor seeing an empty cat stage.
   - .loader-active                 -> visible, and the content underneath hides.

   This used to be `.js .site-loader { display: flex }`, which pulled the six
   pose images on every visit even though the overlay was decorative on most of
   them. The frames are loading="lazy" now, and a display:none box has no
   intersection, so a visit that never shows the loader downloads none of them. */
.js.loader-armed .site-loader,
.js.loader-active .site-loader { display: flex; }
.js.loader-armed .site-loader { visibility: hidden; }

.loader-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

/* The stage is the thing the cat is anchored to. Motion lines are positioned
   against it, so they travel with the cat on wide viewports without needing
   to be animated separately. */
.cat-stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* room for the motion lines, which sit just outside the cat */
  padding: 18px;
}

.loader-cat {
  display: block;
  width: var(--ld-cat-w);
  height: auto;                      /* preserves the doodle's proportions */
  transform-origin: 50% 85%;         /* pivot near the paws, not the centre */
  will-change: transform, opacity;
  /* no filters, no shadows: the illustration carries itself */
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Frame-sequence mode
   --------------------------------------------------------------------------
   loader.js transforms one static PNG. loader-frames.js swaps real illustrated
   poses instead, which needs a stack of images rather than a single one.

   The reel is the transform target for BOTH the wobble and the walk. Images are
   stacked and toggled by class rather than having their src replaced: swapping
   src can show a blank frame while the next one decodes, which on a 13fps pose
   change is very visible.
   -------------------------------------------------------------------------- */

:root {
  /* Reel, not cat: the canvas is 4:3 and the cat occupies ~71% of its width and
     ~58% of its height, so these are larger numbers than --ld-cat-w for the
     same on-screen cat. Tuned to land the cat at ~300px wide on desktop and
     ~160px on a phone, which is the range that was specified. */
  --ld-reel-w: clamp(250px, 30vw, 450px);
}

.cat-reel {
  position: relative;
  width: var(--ld-reel-w);
  aspect-ratio: 1200 / 900;          /* every frame shares this canvas exactly */
  transform-origin: 50% 85%;         /* pivot near the paws, not the centre */
  will-change: transform, opacity;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

.cat-reel .cat-frame {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
}

.cat-reel .cat-frame.is-on { opacity: 1; }

/* The reel is a 4:3 canvas and the cat's paws sit at 85.6% of its height, so
   there is a band of empty canvas below the cat that grows with the viewport.
   Left alone it pushes the label ~85px away from the paws and the cat and the
   text stop reading as one object — the empty band sits between them. Pull the
   label back up by exactly that band (0.1444 of the reel height, i.e. 0.108 of
   the reel width) so the gap is ~28px at every size. */
.cat-stage--frames + .loader-text {
  margin-top: calc(10px - var(--ld-reel-w) * 0.108);
}

/* --------------------------------------------------------------------------
   Doodle motion lines
   Pure CSS: a thin arc made from a bordered, rounded box — same hand-drawn
   feel as the illustration, no extra assets.
   -------------------------------------------------------------------------- */

.motion-line {
  position: absolute;
  width: 26px;
  height: 14px;
  border-top: 2.5px solid var(--ld-ink);
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  opacity: 0;                        /* animated in by GSAP, or by CSS below */
  transform-origin: 50% 100%;
  pointer-events: none;
}

.motion-line-1 { top: 6%;   left: 2%;   transform: rotate(-38deg); }
.motion-line-2 { top: 2%;   right: 4%;  transform: rotate(32deg);  }
.motion-line-3 { bottom: 14%; right: 0; transform: rotate(64deg);  }
.motion-line-4 { bottom: 6%; left: 0;   transform: rotate(-58deg); }

/* --------------------------------------------------------------------------
   Loading text — optional. Delete the markup and nothing else changes.
   -------------------------------------------------------------------------- */

.loader-text {
  margin-top: 20px;
  font-family: var(--ld-font, 'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif);
  font-size: var(--ld-text-size);
  font-weight: 500;
  letter-spacing: var(--ld-text-tracking);
  text-transform: uppercase;
  color: var(--ld-ink);
  opacity: .55;
}

/* --------------------------------------------------------------------------
   Content reveal
   --------------------------------------------------------------------------
   The page is only hidden while html has .loader-active, and that class is
   only ever added by the inline script in <head>. With JS off it is never
   added, so the site renders normally. Nothing here can leave a visitor
   staring at a blank page.

   Both classes land on <html>, so these are COMPOUND selectors. Written as
   descendants (".js .loader-active .site-content") they match nothing at all:
   that would require an element carrying .loader-active to be nested inside
   html.js, which never happens. This went unnoticed because the overlay is
   opaque white, so the content was covered up rather than hidden — the bug only
   becomes visible the moment anyone lightens --ld-bg.
   -------------------------------------------------------------------------- */

.js.loader-active .site-content {
  opacity: 0;
  transform: translateY(8px);
}

/* Two locks, because either class may be absent: 'loading' is added by the
   loader script, 'loader-active' by the pre-paint script in <head>. */
.js.loader-active,
.js body.loading { overflow: hidden; }

/* --------------------------------------------------------------------------
   Reduced motion
   --------------------------------------------------------------------------
   No wobble, no walk. JS skips straight to the fade. These rules are a second
   line of defence in case a stray tween still runs.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .motion-line { opacity: .5 !important; }
  .site-loader { transition: opacity .3s linear; }
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 900px) {
  :root { --ld-cat-w: clamp(170px, 34vw, 240px); --ld-reel-w: clamp(220px, 44vw, 340px); }
}

@media (max-width: 560px) {
  :root { --ld-cat-w: clamp(130px, 42vw, 190px); --ld-reel-w: clamp(190px, 58vw, 265px); --ld-text-size: 12px; }
  .cat-stage { padding: 12px; }
  .motion-line { width: 20px; height: 11px; }
}
