/* halmic motion. Tokens (durations --t1..--t4, --ease) live in base.css :root; every effect here uses them.
   Gates: html.mo is set early by vt.js when scripts run, there is no reduced-motion preference and the URL has no ?motion=0.
   Everything that HIDES something before it is revealed needs html.mo, so no script or a reduced-motion preference always shows the plain page.
   No scroll reveals: content is on the page from the first paint. The only scroll-driven effect is the header backdrop.
   Only transform, opacity (and translate/scale/rotate, which are transforms) are animated. Scrolling itself is never touched. */

/* ?motion=0: the test override. No animation, no transition, nothing hidden. */
html[data-motion="0"] *, html[data-motion="0"] *::before, html[data-motion="0"] *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }

@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop { from { opacity: 0; scale: .5; } to { opacity: 1; scale: 1; } }
@keyframes ring { from { opacity: .75; scale: 1; } to { opacity: 0; scale: 1.7; } }
@keyframes spin { to { rotate: 360deg; } }
@keyframes bob { 0%, 100% { translate: 0 0; } 50% { translate: 0 3px; } }
@keyframes flip { from { scale: .94; } to { scale: 1; } }
@keyframes hdr-in { from { opacity: 0; } to { opacity: 1; } }

/* ===== the loading state of a player: the play disc becomes a spinner until the iframe has loaded, then the iframe fades in ===== */
.vframe { opacity: 0; transition: opacity var(--t3) var(--ease); }
.vframe.ready { opacity: 1; }
.pload { position: absolute; inset: 0; z-index: 1; display: grid; place-items: center; pointer-events: none; transition: opacity var(--t3) var(--ease); }
.pload.done { opacity: 0; }
.pload i { display: grid; place-items: center; width: 60px; height: 60px; border-radius: 50%; background: #0f0e13a8; -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); box-shadow: inset 0 0 0 1.5px #ffffff30; }
.pload i::after { content: ""; width: 26px; height: 26px; border-radius: 50%; border: 2.5px solid #ffffff2e; border-top-color: var(--blue-live); }

@media (prefers-reduced-motion: no-preference) {
  .pload i { animation: pop var(--t3) var(--ease) both; }
  .pload i::after { animation: spin 800ms linear infinite; }
  /* the control row of a playing tile arrives after the player, one button at a time */
  .playing .crow > * { animation: rise-s var(--t3) var(--ease) backwards; }
  .playing .crow > :nth-child(1) { animation-delay: 120ms; } .playing .crow > :nth-child(2) { animation-delay: 180ms; }
  .pclose { scale: .85; transition: background var(--t2) var(--ease), color var(--t2) var(--ease), transform var(--t2) var(--ease), opacity var(--t2) var(--ease), scale var(--t3) var(--ease); }
  .playing :is(.cm, .thumb, .tp):is(:hover, :focus-within) .pclose, .pclose:focus-visible, .playing .tp .pclose { scale: 1; }
  @media (hover: none) { .pclose { scale: 1; } }
  /* a closed player gives the tile back with a fade */
  .tile.back, .card.back { animation: pin var(--t3) var(--ease) both; animation-timeline: auto; }
  .tile.playing { animation: none; }
  .pvbar { animation: fade var(--t2) var(--ease) both; }

  /* Twitch clips arriving from /api/clips: the tile content fades in, staggered; the picture fades in when it has loaded; the platform badge pops */
  .clip-in > * { animation: fade var(--t3) var(--ease) var(--d, 0ms) backwards; }
  .clip-in > .bdg { animation: pop var(--t3) var(--ease) calc(var(--d, 0ms) + 140ms) backwards; }
  .clip-in .tbg img { transition: opacity var(--t3) var(--ease), transform var(--t3) var(--ease); }
  .clip-in .tbg img:not(.ld) { opacity: 0; }

  /* the status pill: a soft settle when the live state flips (app.js adds .flip) */
  .status.flip { animation: flip var(--t4) var(--ease); }
  .btn:hover .ic-down { transform: none; animation: bob var(--t4) var(--ease) infinite; }

  /* ===== tiles: press, focus ring, chip glide, play ring ===== */
  .tile, .card { outline: 3px solid transparent; outline-offset: 0; transition: transform var(--t3) var(--ease), outline-color var(--t2) var(--ease), outline-offset var(--t3) var(--ease); }
  .tile:focus-visible, .card:focus-visible { outline-color: var(--blue-live); outline-offset: 3px; }
  .c-paper:focus-visible { outline-color: var(--blue-paper); }
  .mo a.tile.is-tilt, .mo a.tile.is-press, .mo a.card.is-press { transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--ps, 1)); }
  .mo a.tile.is-tilt { transition: transform var(--t1) var(--ease), outline-color var(--t2) var(--ease), outline-offset var(--t3) var(--ease); }
  .mo a.is-press { --ps: .985; transition: transform var(--t1) var(--ease), outline-color var(--t2) var(--ease), outline-offset var(--t3) var(--ease); }
  .tile .chip { transition: background var(--t2) var(--ease), color var(--t2) var(--ease), translate var(--t3) var(--ease); }
  a.tile:hover .chip { translate: -3px 0; }
  :is(.card, .vid, a.tile):is(:hover, :focus-visible) .play::after { animation: ring var(--t4) var(--ease) both; }
  /* link tiles: the brand colour lifts a few percent */
  .t-link { transition: filter var(--t3) var(--ease), transform var(--t3) var(--ease), outline-color var(--t2) var(--ease), outline-offset var(--t3) var(--ease); }
  a.t-link:is(:hover, :focus-visible) { filter: brightness(1.07); }
  .tl-x:is(:hover, :focus-visible) { filter: none; background: #141414; }
}
.play::after { content: ""; position: absolute; inset: 0; border-radius: 50%; border: 1.5px solid var(--blue); opacity: 0; pointer-events: none; }

/* pointer sheen (motion.js sets --mx / --my on the hovered tile): a soft light under the title and badges, hover-capable pointers only */
@media (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) {
  .mo a.tile::before { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity var(--t3) var(--ease); background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), #ffffff2b, #ffffff00 55%); }
  .mo a.tile.is-tilt::before { opacity: 1; }
  .mo a.tile.t-link.is-tilt::before { background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), #ffffff3a, #ffffff00 60%); }
  .mo a.tile:is(.tpaper, .tl-md, .tl-site, .tl-itch).is-tilt::before { background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), #0f0e1318, #0f0e1300 60%); }
}

/* ===== nav: one marker that slides between items on hover and rests under the current section (motion.js) ===== */
.js .top nav a[aria-current]:not(:hover) { background: none; }
.top nav .mk { position: absolute; left: 0; bottom: 5px; width: 20px; height: 3px; border-radius: 3px; background: var(--blue-live); opacity: 0; translate: var(--mx, 0px) 0; pointer-events: none; transition: opacity var(--t2) var(--ease); }
.top nav .mk.on { opacity: 1; }
@media (prefers-reduced-motion: no-preference) { .top nav .mk.go { transition: opacity var(--t2) var(--ease), translate var(--t3) var(--ease); } }

/* ===== header: a blurred ink backdrop once the hero is behind (the header is fixed with scripts) ===== */
.js .top::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0; background: #0f0e13c4; -webkit-backdrop-filter: blur(14px) saturate(1.3); backdrop-filter: blur(14px) saturate(1.3); box-shadow: 0 1px 0 #ffffff12; transition: opacity var(--t3) var(--ease); }
.js .top.solid::before { opacity: 1; }
.tsent { position: absolute; top: 0; left: 0; width: 1px; height: 56px; pointer-events: none; visibility: hidden; }

/* ===== smooth in-page anchors: the browser's own scrolling, nothing intercepted ===== */
@media (prefers-reduced-motion: no-preference) { html:not([data-motion="0"]) { scroll-behavior: smooth; } }

/* ===== scroll-driven (CSS timelines): only the header backdrop arriving behind the nav. Nothing rises, slides or draws in. ===== */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .mo .tile.back, .mo .card.back { animation: pin var(--t3) var(--ease) both; }
    .mo body.home { timeline-scope: --hero; }
    .mo .hero { view-timeline: --hero block; }
    .mo.js body.home .top::before { transition: none; animation: hdr-in linear both; animation-timeline: --hero; animation-range: exit 45% exit 80%; }
    .mo.js body:not(.home) .top::before { transition: none; animation: hdr-in linear both; animation-timeline: scroll(root); animation-range: 0px 80px; }
  }
}

