:root {
    --red: #ee0000;
    --red-dark: #8a0000;
    --white: #ffffff;
    --black: #000000;
    --display: 'Archivo Black', 'Arial Black', Impact, sans-serif;
    --title: 'Inter Tight', 'Helvetica Neue', Arial, sans-serif;
    --ui: 'Archivo', system-ui, sans-serif;
    --ease-out: cubic-bezier(.2, .9, .25, 1);
    --ease-inout: cubic-bezier(.75, 0, .2, 1);
    --ease-back: cubic-bezier(.3, 1.6, .5, 1);
}

[hidden] { display: none !important; }

* { box-sizing: border-box; }

html, body {
    margin: 0;
    height: 100%;
    background-color: var(--black);
    color: var(--white);
    overflow: hidden;
    font-family: var(--ui);
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

body.idle { cursor: none; }

/* ============ logo ============ */

.logo {
    font-family: var(--display);
    color: var(--white);
    text-align: center;
    line-height: .95;
    text-transform: uppercase;
    -webkit-text-stroke: .07em var(--red);
    paint-order: stroke fill;
    white-space: nowrap;
}
.logo span { display: block; }
.logo-name { font-size: 1em; letter-spacing: -.01em; }
.logo-tag { font-size: .62em; margin-top: .25em; }

/* black letters, glowing gold outline (teaser + corner logo) */
.logo.gold {
    color: #000;
    -webkit-text-stroke: .05em #ffe08a;
    text-shadow: 0 0 .06em #ffe08a, 0 0 .22em rgba(255, 196, 64, .95), 0 0 .7em rgba(255, 150, 0, .6);
}

/* always on screen, above pages, effects and HUD (only the program panel covers it) */
.logo.brand {
    position: fixed;
    z-index: 35;
    right: max(16px, 3vw);
    top: max(16px, 3.5vh);
    font-size: clamp(1.1rem, 2.4vw, 2.6rem);
    -webkit-text-stroke-width: .07em;
    pointer-events: none;
}

/* ============ teaser ============ */

.teaser {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: grid;
    place-items: center;
    background: var(--black);
    transition: opacity 1.5s ease;
}
.teaser .logo {
    font-size: min(17vw, 26vh);
    animation: teaser 40s ease 0s infinite, gold 2.8s ease-in-out infinite alternate;
}
.teaser.leaving { opacity: 0; }

@keyframes gold {
    from {
        -webkit-text-stroke-color: #e9b949;
        text-shadow: 0 0 .04em #ffcf5a, 0 0 .14em rgba(255, 176, 32, .7), 0 0 .4em rgba(255, 140, 0, .35);
    }
    to {
        -webkit-text-stroke-color: #fff0b8;
        text-shadow: 0 0 .06em #ffe08a, 0 0 .22em rgba(255, 196, 64, .95), 0 0 .7em rgba(255, 150, 0, .6);
    }
}

@keyframes teaser {
    0%   { filter: blur(3rem); opacity: 0; transform: scale(2); }
    50%  { filter: blur(2rem); opacity: 1; transform: scale(1); }
    75%  { filter: blur(0);   opacity: 1; transform: scale(1); }
    90%  { filter: blur(0);   opacity: 1; transform: scale(1); }
    95%  { filter: blur(3rem); opacity: 0; }
    100% { filter: blur(3rem); opacity: 0; }
}

/* ============ stage & slide ============ */

.stage {
    position: fixed;
    inset: 0;
    overflow: hidden;
    perspective: 2200px;
    touch-action: pan-y;
}

.slide {
    --ox: 50%;
    --oy: 50%;
    --h: 0;
    --tilt: 0deg;
    --bd: .45s;
    position: absolute;
    inset: 0;
    z-index: 1;
    isolation: isolate;
    overflow: hidden;
    background:
        radial-gradient(ellipse at 25% 20%, hsl(var(--h) 85% 42%) 0%, transparent 60%),
        radial-gradient(ellipse at 85% 85%, hsl(calc(var(--h) + 70) 90% 30%) 0%, transparent 55%),
        linear-gradient(160deg, hsl(calc(var(--h) + 200) 60% 10%), #050508);
    backface-visibility: hidden;
}

/* film grain, so the generated backgrounds don't look like a PowerPoint */
.slide::before {
    content: '';
    position: absolute;
    inset: -50%;
    z-index: 1;
    pointer-events: none;
    opacity: .14;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    animation: grain 1s steps(6) infinite;
}
.slide.has-img::before { opacity: .06; }

@keyframes grain {
    0%   { transform: translate(0, 0); }
    20%  { transform: translate(-6%, 4%); }
    40%  { transform: translate(5%, -7%); }
    60%  { transform: translate(-3%, 8%); }
    80%  { transform: translate(7%, 2%); }
    100% { transform: translate(0, 0); }
}

.slide .bg {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    opacity: 0;
    transition: opacity .6s ease;
    animation: kenburns 70s ease-in-out infinite alternate;
}
.slide.has-img .bg { opacity: 1; }

@keyframes kenburns {
    from { transform: scale(1) translate(0, 0); }
    to   { transform: scale(1.14) translate(-2%, -1.5%); }
}

/* big outlined word behind everything when there's no photo yet */
.slide .ghost {
    position: absolute;
    left: -5vw;
    top: 50%;
    width: max-content;
    font-family: var(--display);
    font-size: 24vmax;
    line-height: .85;
    color: transparent;
    -webkit-text-stroke: 2px rgba(255, 255, 255, .12);
    transform: translateY(-50%) rotate(-8deg);
    white-space: nowrap;
    animation: ghost 50s linear infinite;
}
.slide.has-img.layout-full .ghost,
.slide.has-img.layout-duotone .ghost { display: none; }

@keyframes ghost {
    from { translate: 0 0; }
    to   { translate: -60% 0; }
}

/* ============ photo layouts ============
   full    – photo fills the screen (default)
   framed  – tilted white-bordered print on top of a blurred copy of itself
   split   – photo fills the left side with a slanted red edge
   duotone – full screen, black & red print with a halftone screen      */

.slide.layout-framed .bg,
.slide.layout-split .bg {
    inset: -10%;
    filter: blur(40px) brightness(.45) saturate(1.5);
}

.slide .photo { position: absolute; z-index: 1; opacity: 0; transition: opacity .6s ease; }
.slide.has-img .photo { opacity: 1; }
.slide .photo-img {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    animation: kenburns 70s ease-in-out infinite alternate;
}

.slide.layout-framed .photo {
    left: 7%;
    top: 19%;
    width: min(54vw, 98vh);
    aspect-ratio: 16 / 10;
    overflow: hidden;
    border: clamp(6px, .8vw, 16px) solid #fff;
    border-bottom-width: clamp(18px, 3vw, 54px);
    box-shadow: 0 2vmin 6vmin rgba(0, 0, 0, .55);
    transform: rotate(-3deg);
    animation: float 9s ease-in-out infinite alternate;
}
@keyframes float {
    from { transform: rotate(-3deg) translateY(0); }
    to   { transform: rotate(-1.5deg) translateY(-1.2vh); }
}

.slide.layout-split .photo {
    left: 0;
    top: 0;
    bottom: 0;
    width: 62%;
    overflow: hidden;
    clip-path: polygon(0 0, 100% 0, 80% 100%, 0 100%);
}
.slide.layout-split .photo::after {
    /* red slanted edge */
    content: '';
    position: absolute;
    inset: 0;
    background: var(--red);
    clip-path: polygon(97.5% 0, 100% 0, 80% 100%, 77.5% 100%);
}

.slide.layout-duotone .bg { filter: grayscale(1) contrast(1.35) brightness(1.05); }
.slide.layout-duotone.has-img::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(circle, rgba(0, 0, 0, .35) 1px, transparent 1.6px) 0 0 / 5px 5px,
        linear-gradient(135deg, #ff1a1a 0%, #b00000 45%, #2a0040 100%);
    mix-blend-mode: multiply;
}

@media (max-width: 640px) {
    .slide.layout-framed .photo { left: 6%; top: 20%; width: 88vw; aspect-ratio: 4 / 3; }
    .slide.layout-split .photo { width: 100%; bottom: 45%; clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%); }
    .slide.layout-split .photo::after { display: none; }
}

/* ============ red boxes ============ */

.box {
    position: absolute;
    z-index: 2;
    background-color: var(--red);
    color: var(--white);
    font-family: var(--title);
    font-weight: 800;
    padding: .2em 1em;
    transform: rotate(var(--tilt));
    box-shadow: 0 .4rem 2.5rem rgba(0, 0, 0, .35);
}

.stamp {
    left: 5%;
    top: 5%;
    font-size: clamp(1.8rem, 4.6vw, 4.2em);
    line-height: 1.1;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    padding: .24em 1.2em;
}
.stamp .day { margin-right: .35em; }

.caption {
    right: 5%;
    bottom: max(7%, calc(max(16px, 2vw) + 64px));
    max-width: 90%;
    text-align: right;
    padding: .7em 1.6em .6em 2.4em;
}
.caption .kind,
.caption .who {
    display: block;
    font-family: var(--title);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .14em;
    font-size: clamp(.8rem, 1.6vw, 1.6rem);
}
.caption .kind {
    display: inline-block;
    background: var(--white);
    color: var(--red);
    padding: .15em .6em;
    margin-bottom: .35em;
}
.caption .who {
    font-weight: 500;
    letter-spacing: .06em;
    margin-top: .4em;
    opacity: .9;
}
.caption .who::before { content: '— '; }
.caption .title {
    display: block;
    white-space: pre-line;
    font-size: clamp(1.7rem, 5.6vw, 6em);
    line-height: 1.04;
    letter-spacing: -.01em;
}

/* ============ preshow ============ */

.slide.preshow .center {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6vh;
    padding: 0 16px;
}
.slide.preshow .caption {
    position: relative;
    inset: auto;
    text-align: center;
    max-width: 100%;
}
.slide.preshow .caption .title { font-size: clamp(1.8rem, 6vw, 6em); }
.slide.preshow .caption .who::before { content: none; }
.slide.preshow.has-img .bg { filter: brightness(.45); }

/* ============ box entrance (after any page turn) ============ */

.slide.in .box {
    animation: boxIn .7s var(--ease-back) both;
}
.slide.in .stamp { animation-delay: var(--bd); }
.slide.in .caption { animation-delay: calc(var(--bd) + .2s); animation-name: boxInRight; }

/* new text waits until the old page is out of the way */
.slide.fx-first   { --bd: .2s; }
.slide.fx-dissolve { --bd: .5s; }
.slide.fx-shrink  { --bd: .65s; }
.slide.fx-pop     { --bd: .55s; }
.slide.fx-flip    { --bd: .75s; }
.slide.fx-zoom    { --bd: .55s; }
.slide.fx-tvoff   { --bd: 1s; }
.slide.fx-slam    { --bd: .6s; }
.slide.fx-vortex  { --bd: .85s; }
.slide.fx-spin    { --bd: .95s; }
.slide.fx-melt    { --bd: .95s; }

/* entrance variants */
.slide.in.ent-zoomin .box  { animation-name: boxZoom; animation-timing-function: var(--ease-out); }
.slide.in.ent-spinin .box  { animation-name: boxSpin; animation-duration: .9s; animation-timing-function: var(--ease-out); }
.slide.in.ent-flipin .box  { animation-name: boxFlip; animation-duration: .8s; transform-origin: center top; }
.slide.in.ent-drop .box    { animation-name: boxDrop; animation-duration: .9s; animation-timing-function: ease-in; }
.slide.in.ent-tornado .box { animation-name: boxTornado; animation-duration: 1.1s; animation-timing-function: var(--ease-out); }

@keyframes boxZoom {
    from { opacity: 0; transform: scale(3.5) rotate(var(--tilt)); filter: blur(12px); }
    to   { opacity: 1; transform: rotate(var(--tilt)); filter: none; }
}
@keyframes boxSpin {
    from { opacity: 0; transform: rotate(-720deg) scale(0); }
    to   { opacity: 1; transform: rotate(var(--tilt)); }
}
@keyframes boxFlip {
    0%   { opacity: 0; transform: perspective(900px) rotateX(-100deg) rotate(var(--tilt)); }
    60%  { opacity: 1; transform: perspective(900px) rotateX(18deg) rotate(var(--tilt)); }
    100% { opacity: 1; transform: perspective(900px) rotateX(0) rotate(var(--tilt)); }
}
@keyframes boxDrop {
    0%   { opacity: 1; transform: translateY(-110vh) rotate(var(--tilt)); }
    55%  { transform: translateY(0) rotate(var(--tilt)); animation-timing-function: ease-out; }
    72%  { transform: translateY(-7vh) rotate(var(--tilt)); animation-timing-function: ease-in; }
    86%  { transform: translateY(0) rotate(var(--tilt)); animation-timing-function: ease-out; }
    93%  { transform: translateY(-1.8vh) rotate(var(--tilt)); animation-timing-function: ease-in; }
    100% { opacity: 1; transform: rotate(var(--tilt)); }
}
@keyframes boxTornado {
    from { opacity: 0; transform: translateY(70vh) rotate(-1080deg) scale(.15); }
    to   { opacity: 1; transform: rotate(var(--tilt)); }
}

@keyframes boxIn {
    from { opacity: 0; transform: translateX(-40vw) skewX(20deg) rotate(var(--tilt)); }
    to   { opacity: 1; transform: rotate(var(--tilt)); }
}
@keyframes boxInRight {
    from { opacity: 0; transform: translateX(40vw) skewX(-20deg) rotate(var(--tilt)); }
    to   { opacity: 1; transform: rotate(var(--tilt)); }
}

.slide.in.fx-glitch .box { animation-name: boxGlitch; animation-duration: .9s; animation-timing-function: steps(1); }
@keyframes boxGlitch {
    0%   { opacity: 0; }
    10%  { opacity: 1; transform: translate(-3vw, 0) rotate(var(--tilt)); text-shadow: .08em 0 cyan, -.08em 0 lime; }
    25%  { transform: translate(2vw, -1vh) skewX(-25deg) rotate(var(--tilt)); }
    40%  { opacity: .3; transform: translate(-1vw, 1vh) rotate(var(--tilt)); text-shadow: -.06em 0 cyan, .06em 0 magenta; }
    55%  { opacity: 1; transform: translate(1vw, 0) skewX(15deg) rotate(var(--tilt)); }
    70%  { transform: translate(0, 0) rotate(var(--tilt)); text-shadow: .03em 0 cyan, -.03em 0 magenta; }
    100% { opacity: 1; transform: rotate(var(--tilt)); text-shadow: none; }
}

/* late night: the boxes can't sit still either */
.slide.wild:not(.in) .caption { animation: wobble 7s ease-in-out infinite; }
.slide.wild:not(.in) .stamp { animation: wobble 9s ease-in-out -3s infinite reverse; }
@keyframes wobble {
    0%, 100% { transform: rotate(var(--tilt)) translate(0, 0); }
    25%      { transform: rotate(calc(var(--tilt) * -1)) translate(-.4vw, .3vh); }
    50%      { transform: rotate(calc(var(--tilt) + 1deg)) translate(.3vw, -.4vh) scale(1.02); }
    75%      { transform: rotate(var(--tilt)) translate(.2vw, .2vh); }
}

/* old text leaves first (unless the transition carries it away) */
.slide.out[class*="exit-"] .box   { animation: .4s ease-in both; }
.slide.out.exit-spinout .box      { animation-name: boxSpinOut; }
.slide.out.exit-shrinkout .box    { animation-name: boxShrinkOut; }
.slide.out.exit-dropout .box      { animation-name: boxDropOut; }
.slide.out.exit-flyout .stamp     { animation-name: boxFlyOutLeft; }
.slide.out.exit-flyout .caption   { animation-name: boxFlyOutRight; }
@keyframes boxSpinOut     { to { opacity: 0; transform: rotate(540deg) scale(0); } }
@keyframes boxShrinkOut   { to { opacity: 0; transform: scale(0); } }
@keyframes boxDropOut     { to { opacity: 0; transform: translateY(80vh) rotate(28deg); } }
@keyframes boxFlyOutLeft  { to { opacity: 0; transform: translateX(-90vw) skewX(30deg); } }
@keyframes boxFlyOutRight { to { opacity: 0; transform: translateX(90vw) skewX(-30deg); } }

/* ============ transitions ============
   .slide.in.fx-X  = incoming page,  .slide.out.fx-X = outgoing page,
   .rev = going backwards                                           */

.slide.out { pointer-events: none; }
.slide.in  { z-index: 2; }

/* first paint */
.slide.in.fx-first { animation: dissolveIn 1.2s ease both; }

/* dissolve */
.slide.in.fx-dissolve  { animation: dissolveIn 1.1s ease both; }
.slide.out.fx-dissolve { animation: dissolveOut 1.1s ease both; }
@keyframes dissolveIn  { from { opacity: 0; transform: scale(1.12); filter: blur(24px); } }
@keyframes dissolveOut { to   { opacity: 0; transform: scale(.94);  filter: blur(10px); } }

/* slide (push) */
.slide.in.fx-slide      { animation: slideIn .85s var(--ease-inout) both; }
.slide.out.fx-slide     { animation: slideOut .85s var(--ease-inout) both; }
.slide.in.fx-slide.rev  { animation-name: slideInRev; }
.slide.out.fx-slide.rev { animation-name: slideOutRev; }
@keyframes slideIn     { from { transform: translateX(100%); } }
@keyframes slideOut    { to   { transform: translateX(-35%); filter: brightness(.3); } }
@keyframes slideInRev  { from { transform: translateX(-100%); } }
@keyframes slideOutRev { to   { transform: translateX(35%); filter: brightness(.3); } }

/* wipe – a red brush stroke drags the new page in */
.slide.in.fx-wipe      { animation: wipeIn .95s var(--ease-inout) both; }
.slide.in.fx-wipe.rev  { animation-name: wipeInRev; }
.slide.out.fx-wipe     { animation: hold .95s both; }
.slide.in.fx-wipe::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: 7vw;
    z-index: 5;
    background: var(--red);
    animation: wipeBar .95s var(--ease-inout) both;
}
.slide.in.fx-wipe.rev::after { animation-name: wipeBarRev; }
@keyframes wipeIn     { from { clip-path: inset(0 0 0 100%); } to { clip-path: inset(0 0 0 0); } }
@keyframes wipeInRev  { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes wipeBar    { 0% { left: 100%; opacity: 1; } 88% { opacity: 1; } 100% { left: 0; opacity: 0; } }
@keyframes wipeBarRev { 0% { left: -7vw; opacity: 1; } 88% { opacity: 1; } 100% { left: calc(100% - 7vw); opacity: 0; } }
@keyframes hold { to { filter: brightness(.6); } }

/* iris */
.slide.in.fx-iris  { animation: irisIn 1s var(--ease-inout) both; }
.slide.out.fx-iris { animation: irisOut 1s ease both; }
@keyframes irisIn  { from { clip-path: circle(0% at var(--ox) var(--oy)); } to { clip-path: circle(150% at var(--ox) var(--oy)); } }
@keyframes irisOut { to { transform: scale(.9); filter: brightness(.3) blur(4px); } }

/* flip – actual page turn, old page on top */
.slide.out.fx-flip      { z-index: 3; transform-origin: left center; animation: flipOut .9s var(--ease-inout) both; }
.slide.out.fx-flip.rev  { transform-origin: right center; animation-name: flipOutRev; }
.slide.in.fx-flip       { animation: flipUnder .9s ease both; }
@keyframes flipOut {
    0%   { transform: rotateY(0); opacity: 1; }
    80%  { transform: rotateY(-90deg); opacity: 1; filter: brightness(.3); }
    81%, 100% { transform: rotateY(-90deg); opacity: 0; }
}
@keyframes flipOutRev {
    0%   { transform: rotateY(0); opacity: 1; }
    80%  { transform: rotateY(90deg); opacity: 1; filter: brightness(.3); }
    81%, 100% { transform: rotateY(90deg); opacity: 0; }
}
@keyframes flipUnder  { from { transform: scale(.94); filter: brightness(.25); } }

/* shrink – old page shrinks into a dot, revealing the new one */
.slide.out.fx-shrink { z-index: 3; animation: shrinkOut .8s cubic-bezier(.6, 0, .8, .4) both; }
.slide.in.fx-shrink  { animation: shrinkUnder .8s ease both; }
@keyframes shrinkOut {
    0%   { transform: scale(1); border-radius: 0; box-shadow: 0 0 0 rgba(0, 0, 0, 0); }
    30%  { transform: scale(.85); border-radius: 3vmin; box-shadow: 0 2vmin 6vmin rgba(0, 0, 0, .7); }
    100% { transform: scale(0); border-radius: 50%; opacity: .6; }
}
@keyframes shrinkUnder { from { transform: scale(1.12); filter: brightness(.35); } }

/* pop – new page grows out of a dot */
.slide.in.fx-pop  { z-index: 3; animation: popIn .8s var(--ease-back) both; }
.slide.out.fx-pop { animation: hold .8s both; }
@keyframes popIn {
    0%   { transform: scale(0); border-radius: 50%; }
    70%  { border-radius: 4vmin; }
    100% { transform: scale(1); border-radius: 0; }
}

/* vortex – old page spirals down the drain */
.slide.out.fx-vortex { z-index: 3; animation: vortexOut 1s cubic-bezier(.55, 0, .9, .45) both; }
.slide.in.fx-vortex  { animation: vortexIn 1.1s .15s var(--ease-out) both; }
@keyframes vortexOut {
    to { transform: rotate(600deg) scale(0); filter: blur(6px) hue-rotate(120deg); border-radius: 50%; }
}
@keyframes vortexIn {
    from { transform: rotate(-120deg) scale(1.8); opacity: 0; filter: blur(16px); }
}

/* zoom – rush through the old page */
.slide.in.fx-zoom  { animation: zoomIn 1s var(--ease-out) both; }
.slide.out.fx-zoom { z-index: 3; animation: zoomOut .7s ease-in both; }
@keyframes zoomIn  { from { transform: scale(.4); opacity: 0; filter: blur(8px); } }
@keyframes zoomOut { to { transform: scale(3.5); opacity: 0; filter: blur(14px); } }

/* tvoff – the old CRT dies, a new one warms up */
.slide.out.fx-tvoff { z-index: 3; animation: tvOff .55s ease-in both; }
.slide.in.fx-tvoff  { animation: tvOn .6s .5s ease-out both; }
@keyframes tvOff {
    0%   { transform: scale(1, 1); filter: brightness(1); }
    60%  { transform: scale(1, .006); filter: brightness(6); }
    100% { transform: scale(0, .006); filter: brightness(10); }
}
@keyframes tvOn {
    0%   { transform: scale(0, .006); filter: brightness(10); }
    40%  { transform: scale(1, .006); filter: brightness(6); }
    100% { transform: scale(1, 1); filter: brightness(1); }
}

/* slam – drops from the ceiling, shakes the room */
.slide.in.fx-slam  { animation: slamIn .7s cubic-bezier(.5, 0, .75, 0) both; }
.slide.out.fx-slam { animation: hold .7s both; }
@keyframes slamIn {
    0%   { transform: translateY(-110%) rotate(-7deg); }
    100% { transform: translateY(0) rotate(0); }
}
.stage.shake { animation: shake .55s .68s linear both; }
@keyframes shake {
    0%, 100% { transform: none; }
    15% { transform: translate(-2.2vw, 1.4vh) rotate(-1.2deg); }
    30% { transform: translate(1.8vw, -1vh) rotate(1deg); }
    45% { transform: translate(-1.2vw, .6vh); }
    60% { transform: translate(.8vw, -.4vh) rotate(.4deg); }
    80% { transform: translate(-.3vw, .2vh); }
}

/* glitch */
.slide.in.fx-glitch  { animation: glitchIn .9s steps(1) both; }
.slide.out.fx-glitch { animation: glitchOut .9s steps(1) both; }
@keyframes glitchIn {
    0%   { opacity: 0; }
    8%   { opacity: 1; clip-path: inset(10% 0 60% 0); transform: translateX(-6%); filter: hue-rotate(90deg) saturate(3); }
    16%  { clip-path: inset(55% 0 20% 0); transform: translateX(8%); }
    24%  { opacity: 0; }
    32%  { opacity: 1; clip-path: inset(0 0 75% 0); transform: translateX(-3%) skewX(12deg); filter: invert(1); }
    44%  { clip-path: inset(30% 0 30% 0); transform: translateX(4%); filter: hue-rotate(-90deg) contrast(2); }
    56%  { clip-path: inset(0 0 0 0); transform: translateX(-1%); filter: none; }
    64%  { clip-path: inset(70% 0 5% 0); transform: translateX(2%); }
    76%  { clip-path: inset(0); transform: none; filter: saturate(4); }
    100% { opacity: 1; clip-path: none; transform: none; filter: none; }
}
@keyframes glitchOut {
    0%   { transform: none; }
    20%  { transform: translateX(3%) skewX(-8deg); filter: hue-rotate(160deg); }
    40%  { transform: translateX(-5%); filter: invert(1); }
    60%  { transform: translateY(2%); filter: contrast(3); }
    80%  { opacity: .3; }
    100% { opacity: 0; }
}

/* spin – why not */
.slide.in.fx-spin  { z-index: 3; animation: spinIn 1.3s var(--ease-back) both; }
.slide.out.fx-spin { animation: spinOut 1.3s ease-in both; }
@keyframes spinIn  { from { transform: rotate(-540deg) scale(0); border-radius: 50%; } 60% { border-radius: 30%; } to { border-radius: 0; } }
@keyframes spinOut { to { transform: rotate(120deg) scale(1.8); filter: blur(12px) brightness(.3); opacity: 0; } }

/* melt – the old page gives up */
.slide.out.fx-melt { z-index: 3; transform-origin: center top; animation: melt 1.4s cubic-bezier(.6, 0, .9, .5) both; }
.slide.in.fx-melt  { animation: dissolveIn 1.4s ease both; }
@keyframes melt {
    0%   { transform: none; filter: none; }
    30%  { transform: scaleY(1.05) skewX(3deg); filter: hue-rotate(40deg) blur(1px); }
    100% { transform: translateY(70%) scaleY(1.9) skewX(-14deg); filter: hue-rotate(200deg) blur(14px); opacity: 0; }
}

/* "NYT!" stamp when the live program moves on */
.nyt {
    position: fixed;
    left: 50%;
    top: 50%;
    z-index: 30;
    pointer-events: none;
    font-family: var(--display);
    font-size: min(28vw, 40vh);
    color: var(--white);
    -webkit-text-stroke: .05em var(--red);
    paint-order: stroke fill;
    animation: nyt 1.5s var(--ease-out) both;
}
@keyframes nyt {
    0%   { opacity: 0; transform: translate(-50%, -50%) rotate(var(--r)) scale(3.2); }
    18%  { opacity: 1; transform: translate(-50%, -50%) rotate(var(--r)) scale(.92); }
    28%  { transform: translate(-50%, -50%) rotate(var(--r)) scale(1.04); }
    70%  { opacity: 1; filter: blur(0); }
    100% { opacity: 0; transform: translate(-50%, -50%) rotate(var(--r)) scale(1.3); filter: blur(12px); }
}

/* ============ effect canvases ============ */

/* the canvases live inside the current page: above the photo, below the red boxes */
#vfx, #demo {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    pointer-events: none;
}
#demo {
    mix-blend-mode: screen;
    opacity: 0;
    transition: opacity .8s ease;
}
#demo.on { opacity: .92; }


/* ============ HUD ============ */

.hud {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 20;
    pointer-events: none;
}

.progress {
    height: 5px;
    background: rgba(255, 255, 255, .08);
}
.progress i {
    display: block;
    height: 100%;
    background: var(--red);
    transform-origin: left;
    transform: scaleX(0);
    transition: transform .25s linear;
}
body.browsing .progress { opacity: 0; }

.controls {
    position: absolute;
    left: max(16px, 2vw);
    bottom: calc(max(16px, 2vw) + env(safe-area-inset-bottom));
    display: flex;
    align-items: center;
    gap: 6px;
    pointer-events: auto;
    transition: opacity .4s ease, transform .4s ease;
}
body.idle .controls > :not(.btn-live),
body.idle:not(.browsing) .btn-live {
    opacity: 0;
    pointer-events: none;
}

.controls button,
.controls .pos {
    font: 700 14px/1 var(--ui);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--white);
    background: rgba(0, 0, 0, .6);
    border: 1px solid rgba(255, 255, 255, .25);
    border-radius: 999px;
    height: 40px;
    min-width: 40px;
    padding: 0 14px;
    cursor: pointer;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    transition: opacity .4s ease, background .2s ease;
}
.controls #btn-prev,
.controls #btn-next { font-size: 24px; padding: 0 0 3px; }
.controls .pos {
    display: inline-flex;
    align-items: center;
    cursor: default;
    background: none;
    border: 0;
    min-width: 64px;
    justify-content: center;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.controls button:hover { background: rgba(238, 0, 0, .8); }
.controls button:focus-visible { outline: 2px solid var(--white); outline-offset: 2px; }

.btn-live {
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.btn-live .dot {
    flex: none;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--red);
    box-shadow: 0 0 0 0 rgba(238, 0, 0, .7);
    animation: pulse 2s infinite;
}
.btn-live .sub {
    font-weight: 500;
    opacity: .7;
    font-variant-numeric: tabular-nums;
}
.btn-live .sub:empty { display: none; }
.btn-live:not(.paused) { cursor: default; }
.btn-live.paused {
    background: var(--red);
    border-color: var(--red);
    height: 48px;
    padding: 0 20px;
    font-size: 16px;
    animation: livePulse 1.6s ease-in-out infinite;
}
.btn-live.paused .dot { background: var(--white); animation: none; }
.btn-live.paused .dot::before { content: ''; }

@keyframes pulse {
    0%   { box-shadow: 0 0 0 0 rgba(238, 0, 0, .7); }
    70%  { box-shadow: 0 0 0 10px rgba(238, 0, 0, 0); }
    100% { box-shadow: 0 0 0 0 rgba(238, 0, 0, 0); }
}
@keyframes livePulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(238, 0, 0, .6); transform: scale(1); }
    50%      { box-shadow: 0 0 0 12px rgba(238, 0, 0, 0); transform: scale(1.04); }
}

/* ============ agenda ============ */

.agenda {
    position: fixed;
    inset: 0 0 0 auto;
    z-index: 40;
    width: min(480px, 100%);
    display: flex;
    flex-direction: column;
    background: rgba(8, 8, 10, .92);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-left: 4px solid var(--red);
    animation: agendaIn .35s var(--ease-out) both;
}
@keyframes agendaIn { from { transform: translateX(100%); } }

.agenda header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 20px 16px 12px 20px;
}
.agenda h2 {
    margin: 0;
    font: 400 22px/1.1 var(--display);
    text-transform: uppercase;
}
.agenda header button {
    font-size: 30px;
    line-height: 1;
    width: 44px;
    height: 44px;
    color: var(--white);
    background: none;
    border: 0;
    cursor: pointer;
}
.agenda ol {
    list-style: none;
    margin: 0;
    padding: 0 0 40px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}
.agenda .day {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 10px 20px;
    background: var(--red);
    font: 400 15px/1 var(--display);
    text-transform: uppercase;
    letter-spacing: .06em;
}
.agenda button[data-i] {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    width: 100%;
    padding: 12px 20px;
    text-align: left;
    color: inherit;
    background: none;
    border: 0;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
    font: 500 16px/1.3 var(--ui);
    cursor: pointer;
}
.agenda button[data-i]:hover { background: rgba(255, 255, 255, .06); }
.agenda time {
    flex: none;
    width: 3.2em;
    font-family: var(--title);
    font-weight: 800;
    color: var(--red);
    font-variant-numeric: tabular-nums;
}
.agenda .txt { flex: 1; }
.agenda .txt small {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    opacity: .6;
}
.agenda .badge {
    display: none;
    flex: none;
    font: 700 11px/1 var(--ui);
    letter-spacing: .1em;
    padding: 5px 7px;
    border-radius: 4px;
    background: var(--red);
}
.agenda .is-past { opacity: .45; }
.agenda .is-live { opacity: 1; }
.agenda .is-live .badge { display: block; }
.agenda .is-current { background: rgba(238, 0, 0, .18); box-shadow: inset 4px 0 0 var(--red); }

.noscript {
    position: fixed;
    inset: 0;
    display: grid;
    place-items: center;
    margin: 0;
    padding: 16px;
    font: 400 24px/1.3 var(--display);
    text-align: center;
}

/* ============ small screens ============ */

@media (max-width: 640px), (max-height: 480px) {
    .stamp { left: 16px; top: 16px; }
    .caption { right: 16px; bottom: 84px; max-width: calc(100% - 32px); padding: .52em 1.2em .45em 1.8em; }
    .stamp { padding: .18em .9em; }
    .logo.brand { right: 16px; top: 20px; }
    .controls { left: 16px; right: 16px; gap: 4px; }
    .controls .pos { min-width: 0; padding: 0 4px; font-size: 12px; }
    body.browsing .controls .pos,
    body.browsing #btn-prev,
    body.browsing #btn-next { display: none; }
    .controls button { padding: 0 11px; }
    .btn-live.paused { padding: 0 14px; font-size: 14px; }
    .btn-live .sub { display: none; }
    body.idle .controls > :not(.btn-live) { opacity: 1; pointer-events: auto; }
}

@media (prefers-reduced-motion: reduce) {
    .slide .bg, .slide .ghost, .slide::before, .teaser .logo,
    .slide.wild .caption, .slide.wild .stamp { animation: none !important; }
}
