/* Page transitions, driven by page-transition.js: the blur dissolve for most
   moves, and the ink (a disc of the accent colour with the wordmark) for
   going to your own profile. Loaded after brotein.css, so it can use its
   tokens. */

/* ---- Blur dissolve for every move that isn't home <-> profile ----
   The old page goes out of focus as it fades, the new one sharpens in. Only
   the content layers take part: the background is fixed to the viewport and
   identical on every page, so leaving it alone makes the site read as one
   surface with the content swapping inside it. */
@keyframes pfOut {
    to {
        opacity: 0;
        filter: blur(14px);
    }
}

@keyframes pfIn {
    from {
        opacity: 0;
        filter: blur(14px);
    }
}

html.pf-out header,
html.pf-out main,
html.pf-out footer,
html.pf-out body > .page-shell {
    animation: pfOut 320ms ease-in both;
}

html.pf-in header,
html.pf-in main,
html.pf-in footer,
html.pf-in body > .page-shell {
    animation: pfIn 420ms cubic-bezier(0.2, 0.8, 0.3, 1) both;
}

@media (prefers-reduced-motion: reduce) {
    html.pf-out header,
    html.pf-out main,
    html.pf-out footer,
    html.pf-out body > .page-shell,
    html.pf-in header,
    html.pf-in main,
    html.pf-in footer,
    html.pf-in body > .page-shell {
        animation: none;
    }
}

/* ---- The ink (page-transition.js) ----
   A disc of the accent colour grows from the click with the wordmark in the
   middle; the next page arrives under it and the ink dissolves away. */

/* Painted before the incoming page shows, so there's no flash of content. */
html.pt-covered body {
    visibility: hidden;
}

html.pt-covered::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 9998;
    background: var(--accent, #b7d83a);
}

.pt-overlay {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: grid;
    place-items: center;
    background: var(--accent, #b7d83a);
    pointer-events: none;
    clip-path: circle(0 at var(--pt-x, 50%) var(--pt-y, 50%));
    transition: clip-path 520ms cubic-bezier(0.7, 0, 0.3, 1);
}

.pt-overlay.is-covering {
    clip-path: circle(var(--pt-r, 150vmax) at var(--pt-x, 50%) var(--pt-y, 50%));
}

/* On arrival the ink is already full and simply dissolves. */
.pt-overlay.is-dissolving {
    opacity: 0;
    transition: opacity 420ms ease-out;
}

/* Used for one frame on arrival: cover without animating. */
.pt-overlay.is-instant,
.pt-overlay.is-instant .pt-word {
    transition: none;
}

/* Out of the way once the page is open, so nothing can trap clicks. */
.pt-overlay.is-idle {
    display: none;
}

.pt-word {
    font-family: "Archivo", "Geist", system-ui, sans-serif;
    font-stretch: 118%;
    font-size: clamp(2.2rem, 7vw, 4.6rem);
    font-weight: 800;
    letter-spacing: 0.08em;
    color: var(--accent-ink, #1d2a05);
    opacity: 0;
    transform: scale(0.9);
    transition: opacity 300ms ease, transform 420ms cubic-bezier(0.2, 0.8, 0.3, 1);
}

.pt-overlay.is-covering .pt-word {
    opacity: 1;
    transform: scale(1);
    transition-delay: 180ms;
}

.pt-overlay.is-dissolving .pt-word {
    transform: scale(1.05);
    transition: transform 420ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
    .pt-overlay {
        display: none;
    }
}

/* ---- Phones: the browser's own page transitions ----
   Below 1080px both pages take part at once, like a phone app. page-transition.js
   picks the move and puts vt-<move> on <html> for as long as it plays; the bottom
   bar holds still in all of them. Browsers without these keep the blur above. */
@media (max-width: 1080px) {
    @view-transition { navigation: auto; }
    .tabbar { view-transition-name: vt-tabbar; }
}

::view-transition-group(vt-tabbar) { z-index: 10; }

/* Our moves replace the default crossfade, so the two pages are drawn as they are. */
html[class*="vt-"]::view-transition-old(*),
html[class*="vt-"]::view-transition-new(*) { mix-blend-mode: normal; }

/* Short and transform-only, so they stay smooth on a phone: no filters on the
   full-screen snapshots, and nothing long enough to keep a second tap waiting. */
@keyframes vt-in-from-right { from { transform: translateX(100%); } }
@keyframes vt-out-to-right { to { transform: translateX(100%); } }
@keyframes vt-out-to-left { to { transform: translateX(-30%); } }
@keyframes vt-in-from-left { from { transform: translateX(-30%); } }
@keyframes vt-sink { to { transform: translateX(-25%); } }
@keyframes vt-rise { from { transform: translateX(-25%); } }
@keyframes vt-fade-in { from { opacity: 0; } }
@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-hold { from, to { opacity: 1; } }
@keyframes vt-show-late { 0%, 44% { opacity: 0; } 45%, 100% { opacity: 1; } }
@keyframes vt-flood {
    0% { clip-path: circle(0 at var(--vt-x, 50%) var(--vt-y, 90%)); transform: translateY(0); animation-timing-function: cubic-bezier(0.7, 0, 0.3, 1); }
    44% { clip-path: circle(150vmax at var(--vt-x, 50%) var(--vt-y, 90%)); transform: translateY(0); animation-timing-function: cubic-bezier(0.4, 0, 1, 1); }
    100% { clip-path: circle(150vmax at var(--vt-x, 50%) var(--vt-y, 90%)); transform: translateY(-100%); }
}

/* Another tab: the new page slides in from the side of the tab you tapped. */
html.vt-tab-next::view-transition-old(root) { animation: vt-out-to-left 260ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
html.vt-tab-next::view-transition-new(root) { animation: vt-in-from-right 260ms cubic-bezier(0.2, 0.8, 0.2, 1) both; box-shadow: -6px 0 18px rgba(0, 0, 0, 0.14); }
html.vt-tab-prev::view-transition-old(root) { z-index: 1; animation: vt-out-to-right 260ms cubic-bezier(0.2, 0.8, 0.2, 1) both; box-shadow: -6px 0 18px rgba(0, 0, 0, 0.14); }
html.vt-tab-prev::view-transition-new(root) { animation: vt-in-from-left 260ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }

/* Going deeper slides the new screen over; back slides it away again. */
html.vt-push::view-transition-old(root) { animation: vt-sink 300ms cubic-bezier(0.16, 1, 0.3, 1) both; }
html.vt-push::view-transition-new(root) { animation: vt-in-from-right 300ms cubic-bezier(0.16, 1, 0.3, 1) both; box-shadow: -6px 0 18px rgba(0, 0, 0, 0.16); }
html.vt-pop::view-transition-old(root) { z-index: 1; animation: vt-out-to-right 250ms cubic-bezier(0.2, 0.8, 0.2, 1) both; box-shadow: -6px 0 18px rgba(0, 0, 0, 0.16); }
html.vt-pop::view-transition-new(root) { animation: vt-rise 250ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }

/* Anything else: a short crossfade. */
html.vt-swap::view-transition-old(root) { animation: vt-fade-out 140ms ease both; }
html.vt-swap::view-transition-new(root) { animation: vt-fade-in 180ms ease both; }

/* Start on the Today card: the card grows into the workout page and its title
   travels to the page heading. Back home from that workout reverses it. */
html.vt-morph::view-transition-group(vt-session),
html.vt-morph::view-transition-group(vt-session-title),
html.vt-morph-back::view-transition-group(vt-session),
html.vt-morph-back::view-transition-group(vt-session-title) { animation-duration: 340ms; animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1); }
html.vt-morph::view-transition-group(vt-session-title),
html.vt-morph-back::view-transition-group(vt-session-title) { z-index: 2; }
html.vt-morph::view-transition-old(vt-session),
html.vt-morph::view-transition-new(vt-session),
html.vt-morph-back::view-transition-old(vt-session),
html.vt-morph-back::view-transition-new(vt-session) { height: 100%; object-fit: cover; object-position: 50% 0; }
html.vt-morph::view-transition-old(vt-session) { animation: vt-fade-out 140ms ease both; }
html.vt-morph::view-transition-new(vt-session) { animation: vt-fade-in 200ms 100ms ease both; }
html.vt-morph::view-transition-old(root) { animation: vt-fade-out 340ms ease both; }
html.vt-morph::view-transition-new(root) { animation: vt-fade-in 160ms 180ms ease both; }
html.vt-morph-back::view-transition-old(vt-session) { animation: vt-fade-out 160ms 40ms ease both; }
html.vt-morph-back::view-transition-new(vt-session) { animation: vt-fade-in 200ms 120ms ease both; }
html.vt-morph-back::view-transition-old(root) { animation: vt-fade-out 180ms ease both; }
html.vt-morph-back::view-transition-new(root) { animation: vt-fade-in 340ms ease both; }

/* The raised Today button: the accent floods out from it, the workout page
   appears under the colour, and the colour lifts away. */
.vt-ripple { position: fixed; inset: 0; z-index: 30; display: grid; place-items: center; background: var(--accent); color: var(--accent-ink); font-size: 3.4rem; pointer-events: none; view-transition-name: vt-ripple; }
html.vt-ripple::view-transition-old(root) { animation: vt-hold 520ms both; }
html.vt-ripple::view-transition-new(root) { animation: vt-show-late 520ms both; }
html.vt-ripple::view-transition-new(vt-ripple) { animation: vt-flood 520ms both; }

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) { animation: none !important; }
    .vt-ripple { display: none; }
}
