/* Page transitions. In browsers that support cross-page view transitions (Chrome, Edge, Safari 18.2 and later) moving between two pages of this
   site animates instead of cutting; other browsers just load the page, as always. Nothing here runs for visitors who ask for reduced motion.

   Which animation plays is chosen by the attribute on <html>: data-vt-style="fade | rise | slide | depth | stagger | fly | sweep | wipe | none".
   The attribute, the direction (data-vt-dir="back" when going back), the click position (--vt-x, --vt-y) and the speed (--vt-slow: 3 is three times
   slower, for studying) are set by the small script in the page head (src/site/transitions-script.ts). The study page, /build/system/page-transitions/,
   plays every option on the real site. The one the site uses by default is DEFAULT_STYLE in that script.

   Three rules that must not be broken:
   1. Never give .nav-pill (or anything holding the frosted glass) a view-transition-name. A named element becomes its own isolated layer and its
      backdrop-filter stops seeing the page, which switches the glass off. The header's bar is named by the script only during a move, never at rest.
   2. The page under a running transition cannot be clicked in Chrome or Safari, whatever the CSS says (pointer-events: none does not help). The script in the page head
      therefore skips the transition on the first press and passes the click on to the link under the pointer, so a click always lands at once.
   3. Old and new are blended normally (not "plus-lighter") over the page colour, so a fade never dips dark. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}

:root::view-transition-group(root) { background-color: var(--bg); }
:root::view-transition-old(root), :root::view-transition-new(root) { mix-blend-mode: normal; }
::view-transition-group(site-bar) { animation-duration: calc(.22s * var(--vt-slow, 1)); }

@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-fade-in { from { opacity: 0; } }

/* ── none: the page changes at once (the header and picture still glide) ── */
html[data-vt-style="none"]::view-transition-old(root), html[data-vt-style="none"]::view-transition-new(root) { animation: none; }

/* ── fade: the plainest. A short cross-dissolve ── */
html[data-vt-style="fade"]::view-transition-old(root) { animation: vt-fade-out calc(.2s * var(--vt-slow, 1)) ease both; }
html[data-vt-style="fade"]::view-transition-new(root) { animation: vt-fade-in calc(.28s * var(--vt-slow, 1)) ease both; }

/* ── rise: the old page leaves quickly, the new one fades in while lifting a few pixels ── */
html[data-vt-style="rise"]::view-transition-old(root) { animation: vt-fade-out calc(.16s * var(--vt-slow, 1)) ease-in both; }
html[data-vt-style="rise"]::view-transition-new(root) { animation: vt-rise-in calc(.4s * var(--vt-slow, 1)) cubic-bezier(.2, .8, .2, 1) calc(.04s * var(--vt-slow, 1)) both; }
@keyframes vt-rise-in { from { opacity: 0; transform: translateY(14px); } }

/* ── slide: a gentle sideways drift that knows the direction: forward comes from the right, back from the left ── */
html[data-vt-style="slide"] { --vt-dx: 1; }
html[data-vt-style="slide"][data-vt-dir="back"] { --vt-dx: -1; }
html[data-vt-style="slide"]::view-transition-old(root) { animation: vt-slide-out calc(.24s * var(--vt-slow, 1)) cubic-bezier(.5, 0, .9, .5) both; }
html[data-vt-style="slide"]::view-transition-new(root) { animation: vt-slide-in calc(.46s * var(--vt-slow, 1)) cubic-bezier(.2, .8, .2, 1) calc(.05s * var(--vt-slow, 1)) both; }
@keyframes vt-slide-out { to { opacity: 0; transform: translateX(calc(var(--vt-dx, 1) * -32px)); } }
@keyframes vt-slide-in { from { opacity: 0; transform: translateX(calc(var(--vt-dx, 1) * 44px)); } }

/* ── depth: the old page recedes a hair, the new one comes forward from slightly larger ── */
html[data-vt-style="depth"]::view-transition-old(root) { animation: vt-depth-out calc(.3s * var(--vt-slow, 1)) ease-in both; transform-origin: 50% 35%; }
html[data-vt-style="depth"]::view-transition-new(root) { animation: vt-depth-in calc(.55s * var(--vt-slow, 1)) cubic-bezier(.2, .8, .2, 1) calc(.06s * var(--vt-slow, 1)) both; transform-origin: 50% 35%; }
@keyframes vt-depth-out { to { opacity: 0; transform: scale(.982); } }
@keyframes vt-depth-in { from { opacity: 0; transform: scale(1.022); } }

/* ── stagger: the old page fades away fast, then the new page's parts float up one after another (the arrival, below, is the animation) ── */
html[data-vt-style="stagger"]::view-transition-old(root) { animation: vt-fade-out calc(.14s * var(--vt-slow, 1)) ease-in both; }
html[data-vt-style="stagger"]::view-transition-new(root) { animation: vt-fade-in calc(.1s * var(--vt-slow, 1)) ease-out both; }

/* ── fly: the old page lifts up and away; on the new one the sections, and the cards inside them, fly in from below and from the sides with a small overshoot ── */
html[data-vt-style="fly"]::view-transition-old(root) { animation: vt-fly-out calc(.26s * var(--vt-slow, 1)) cubic-bezier(.5, 0, .8, .4) both; }
html[data-vt-style="fly"]::view-transition-new(root) { animation: vt-fade-in calc(.12s * var(--vt-slow, 1)) ease-out both; }
@keyframes vt-fly-out { to { opacity: 0; transform: translateY(-26px) scale(.985); } }

/* ── sweep: the new page is revealed by a circle growing from where you clicked, as the theme change spreads from its toggle ── */
html[data-vt-style="sweep"]::view-transition-old(root) { animation: none; }
html[data-vt-style="sweep"]::view-transition-new(root) { animation: vt-sweep calc(.75s * var(--vt-slow, 1)) cubic-bezier(.5, 0, .15, 1) both; }
@keyframes vt-sweep { from { clip-path: circle(0 at var(--vt-x, 50%) var(--vt-y, 30%)); } to { clip-path: circle(150vmax at var(--vt-x, 50%) var(--vt-y, 30%)); } }

/* ── wipe: the loud one, for comparison. The new page is uncovered from left to right in one hard-edged wipe ── */
html[data-vt-style="wipe"]::view-transition-old(root) { animation: none; }
html[data-vt-style="wipe"]::view-transition-new(root) { animation: vt-wipe calc(.65s * var(--vt-slow, 1)) cubic-bezier(.65, 0, .25, 1) both; }
@keyframes vt-wipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }

/* ── The arrival: the page's own parts animate in while the new page is showing (stagger and fly). .vt-arrive is on <html> for a moment after a move ── */
html[data-vt-style="stagger"].vt-arrive main > .sx-wrap { animation: vt-float calc(.62s * var(--vt-slow, 1)) cubic-bezier(.2, .8, .2, 1) both; animation-delay: calc(var(--vt-i, 0) * .07s * var(--vt-slow, 1) + .04s); }
html[data-vt-style="stagger"].vt-arrive main > .sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li) { animation: vt-float calc(.55s * var(--vt-slow, 1)) cubic-bezier(.2, .8, .2, 1) both; animation-delay: calc(.2s * var(--vt-slow, 1) + var(--vt-n, 0) * .06s * var(--vt-slow, 1)); }
@keyframes vt-float { from { opacity: 0; transform: translateY(20px); } }

html[data-vt-style="fly"].vt-arrive main > .sx-wrap { animation: vt-fly-section calc(.8s * var(--vt-slow, 1)) cubic-bezier(.16, 1.12, .3, 1) both; animation-delay: calc(var(--vt-i, 0) * .08s * var(--vt-slow, 1) + .05s); }
html[data-vt-style="fly"].vt-arrive main > .sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li) { --vt-fx: -36px; --vt-fr: -1.4deg; animation: vt-fly-card calc(.85s * var(--vt-slow, 1)) cubic-bezier(.16, 1.12, .3, 1) both; animation-delay: calc(.18s * var(--vt-slow, 1) + var(--vt-n, 0) * .07s * var(--vt-slow, 1)); }
html[data-vt-style="fly"].vt-arrive main > .sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li):nth-child(even) { --vt-fx: 36px; --vt-fr: 1.4deg; }
html[data-vt-style="fly"].vt-arrive main .media img { animation: vt-img-settle calc(1.1s * var(--vt-slow, 1)) cubic-bezier(.2, .8, .2, 1) both; }
@keyframes vt-fly-section { from { opacity: 0; transform: translateY(56px); } }
@keyframes vt-fly-card { from { opacity: 0; transform: translate(var(--vt-fx, 0), 44px) rotate(var(--vt-fr, 0deg)); } }
@keyframes vt-img-settle { from { transform: scale(1.1); } }

/* the position of a part among its brothers (the first eight), for the delays above */
main > .sx-wrap:nth-child(1) { --vt-i: 0; } main > .sx-wrap:nth-child(2) { --vt-i: 1; } main > .sx-wrap:nth-child(3) { --vt-i: 2; } main > .sx-wrap:nth-child(4) { --vt-i: 3; }
main > .sx-wrap:nth-child(5) { --vt-i: 4; } main > .sx-wrap:nth-child(6) { --vt-i: 5; } main > .sx-wrap:nth-child(7) { --vt-i: 6; } main > .sx-wrap:nth-child(n+8) { --vt-i: 7; }
.sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li):nth-child(1) { --vt-n: 0; } .sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li):nth-child(2) { --vt-n: 1; }
.sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li):nth-child(3) { --vt-n: 2; } .sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li):nth-child(4) { --vt-n: 3; }
.sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li):nth-child(5) { --vt-n: 4; } .sx-wrap :is(.project, .post-row, .tool, .steps > li, .timeline > div, .pin-list > li):nth-child(n+6) { --vt-n: 5; }

/* A project's or post's picture: a card becomes the cover (and back). Cropped, never squashed, with the card's rounded corners */
::view-transition-group(cover) { animation-duration: calc(.5s * var(--vt-slow, 1)); animation-timing-function: cubic-bezier(.2, .8, .2, 1); }
::view-transition-image-pair(cover) { border-radius: var(--r-inner, 20px); overflow: hidden; }
::view-transition-old(cover), ::view-transition-new(cover) { height: 100%; width: 100%; object-fit: cover; mix-blend-mode: normal; }

/* The mark builds itself once per visit; on later visits to Home it is simply there (the script in the page head sets .mk-seen) */
html.mk-seen .mk * { animation-duration: 1ms !important; animation-delay: 0s !important; }
