/* ============================================================
   Page transitions.

   • Page-to-page: cross-document View Transitions API — the old
     document fades out + sinks down, the new one fades in from
     below (opted in with @view-transition).
   • On-load entrance (inner pages, <body class="anim">): the
     above-the-fold blocks GLIDE UP + FADE IN with a soft blur/scale
     "focus pull" and a cascading stagger. Pure CSS with
     fill-mode:both, so the hidden start state is applied at first
     paint (no flash) — works with or without JS / the View
     Transitions API.
   • Respects prefers-reduced-motion (plain fade, no movement).
   ============================================================ */

@view-transition {
  navigation: auto;
}

/* ---- Page-level: old sinks + fades, new rises + fades ---- */
::view-transition-old(root) { animation: pt-sink-out 320ms cubic-bezier(0.4, 0, 1, 1) both; }
::view-transition-new(root) { animation: pt-rise-in  460ms cubic-bezier(0.16, 1, 0.3, 1) both; }

@keyframes pt-sink-out { to   { opacity: 0; transform: translateY(28px); } }
@keyframes pt-rise-in  { from { opacity: 0; transform: translateY(28px); } }
@keyframes pt-fade-out { to   { opacity: 0; } }
@keyframes pt-fade-in  { from { opacity: 0; } }

/* Fallback exit (browsers without the API) — driven from chrome.js */
html.pt-exit { animation: 320ms cubic-bezier(0.4, 0, 1, 1) both pt-sink-out; }

/* ============================================================
   Staggered entrance — glide up + fade in + focus pull
   ============================================================ */
/* Uses the individual `translate`/`scale` properties (NOT the `transform`
   shorthand) so the entrance composes with any existing transform-based
   layout — e.g. the portfolio <h1> centered via Tailwind's -translate-x-1/2
   — instead of overwriting it. */
@keyframes rise-fade {
  from {
    opacity: 0;
    translate: 0 56px;
    scale: 0.985;
    filter: blur(10px);
  }
  to {
    opacity: 1;
    translate: 0 0;
    scale: 1;
    filter: blur(0);
  }
}

/* The blocks that animate: top nav, the first few sections, and the
   title + project cards inside <main>. <main> itself stays static so
   its animating children don't inherit a compounding transform.
   Only the first handful of sections animate (the rest sit below the
   fold and stay at rest, so long project pages don't all pop at once). */
body.anim > header,
body.anim > section:nth-of-type(-n+3),
body.anim > main > h1,
body.anim > main > article {
  animation: rise-fade 1s cubic-bezier(0.16, 1, 0.3, 1) both;
  will-change: translate, scale, opacity, filter;
}

/* Inbound cross-document View Transition (html.vt-inbound, flagged by the
   inline pagereveal script in each page's <head>): the VT rise-in is the
   sole entrance. Suppress the per-section rise-fade — running both makes
   the VT hand off to a live DOM that is still mid-animation, snapping the
   page back to a blurred state (the on-load flicker). */
html.vt-inbound body.anim > header,
html.vt-inbound body.anim > section:nth-of-type(-n+3),
html.vt-inbound body.anim > main > h1,
html.vt-inbound body.anim > main > article {
  animation: none;
  will-change: auto;
}

/* Stagger — starts just after the page crossfade, then cascades. */
body.anim > header                         { animation-delay: 0.18s; }
body.anim > main > h1                       { animation-delay: 0.26s; }
body.anim > main > article:nth-of-type(1)   { animation-delay: 0.36s; }
body.anim > main > article:nth-of-type(2)   { animation-delay: 0.47s; }
body.anim > main > article:nth-of-type(3)   { animation-delay: 0.58s; }

body.anim > section:nth-of-type(1)          { animation-delay: 0.26s; }
body.anim > section:nth-of-type(2)          { animation-delay: 0.40s; }
body.anim > section:nth-of-type(3)          { animation-delay: 0.54s; }

/* ---- Mobile: translate + opacity only ----
   Two things make the entrance jitter on phones — both re-raster the
   animating block every frame (main thread), which mobile GPUs can't
   hide:
     • `filter: blur()` — never composited.
     • `scale` — each block holds a large 2x image shown small, so
       animating the scale re-samples that downscaled bitmap at
       fractional sizes → visible shimmer / "static" on the images.
   So phones get ONLY translate + opacity: a pure compositor transform
   that moves the already-rasterized layer without touching pixels →
   smooth. Desktop keeps the full focus-pull (blur + scale); it's fine
   there. */
@media (max-width: 767px) {
  @keyframes rise-fade {
    from { opacity: 0; translate: 0 40px; }
    to   { opacity: 1; translate: 0 0; }
  }
  body.anim > header,
  body.anim > section:nth-of-type(-n+3),
  body.anim > main > h1,
  body.anim > main > article {
    will-change: translate, opacity;
  }
}

/* ---- Reduced motion: gentle fade, no sliding/blur ---- */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root) { animation: pt-fade-out 160ms ease both; }
  ::view-transition-new(root) { animation: pt-fade-in  160ms ease both; }
  html.pt-exit { animation: 140ms ease both pt-fade-out; }
  body.anim > header,
  body.anim > section:nth-of-type(-n+3),
  body.anim > main > h1,
  body.anim > main > article {
    animation: pt-fade-in 0.4s ease both !important;
    translate: none !important;
    scale: none !important;
    filter: none !important;
  }
}
