/* Taskies Games.
 *
 * The game is the page. It fills the viewport edge to edge, and everything that
 * is not the game lives in the corners: back to Taskies, up and down, and one
 * link to the creator's own site. No titles, no bylines, no tags, no chrome
 * down the side. You scroll, and you play.
 *
 * Detector note: Inter is flagged as an overused face and stays. It is the
 * brand across the desktop app and taskies.tech, and a distinctive face on this
 * one page would make it a different product.
 */

:root {
  --ink:    #0e0f13;
  --josh:   #2fae7a;
  --hope:   #e8893f;
  --accent: #2f6df0;
  --ease:   cubic-bezier(0.22, 1, 0.36, 1);   /* the landing page's rise */
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }

body {
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  background: var(--ink);
  color: #fff;
  overflow: hidden;                /* the feed scrolls, the page never does */
  -webkit-font-smoothing: antialiased;
}

/* The UA's [hidden] rule is the lowest-priority rule there is, so any author
   display: declaration silently beats it. The loader and the banner below are
   both flex, and without this they never hide. */
[hidden] { display: none !important; }

::selection { background: color-mix(in srgb, var(--accent) 30%, white); color: var(--ink); }
:root { caret-color: var(--accent); accent-color: var(--accent); }

svg { width: 1em; height: 1em; fill: none; stroke: currentColor; stroke-width: 1.7;
      stroke-linecap: round; stroke-linejoin: round; }
.play-icon path { fill: currentColor; stroke: none; }

/* ── Feed ────────────────────────────────────────────────────────────────── */
.feed {
  height: 100%; overflow-y: auto;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
}
.feed::-webkit-scrollbar { display: none; }

.card {
  position: relative;
  width: 100%; height: 100vh; height: 100dvh;   /* dvh keeps phone bars honest */
  scroll-snap-align: start; scroll-snap-stop: always;
  perspective: 900px;                            /* the tilt needs somewhere to happen */
}

.stage {
  position: absolute; inset: 0; overflow: hidden;
  background: var(--tint-base, #0e0f13);
  transform-origin: 50% 50%;
  will-change: transform, filter;
  backface-visibility: hidden;
}
/* A running game is never tilted, blurred or dimmed: it is the page, and the
   brief is that it fills the screen. Only cards you are scrolling past move. */
.card.is-live .stage { transform: none !important; filter: none !important; }
.frame-slot { position: absolute; inset: 0; z-index: 1; }
.stage iframe { width: 100%; height: 100%; border: 0; display: block; background: #000; }

/* Before it starts: the game's own colour, lit from the top left, and one
   button. Nothing to read, because there is nothing to choose. */
.poster {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  background:
    radial-gradient(120% 92% at 22% 8%, var(--tint-glow, #2f6df0) 0%, transparent 62%),
    var(--tint-base, #0e0f13);
}

.play {
  width: 88px; height: 88px; border: 0; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center;
  color: var(--ink); background: #fff;
  box-shadow: 0 14px 40px rgba(0,0,0,0.38);
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.play svg { width: 30px; height: 30px; margin-left: 4px; }   /* optical centring */
.play::before {
  content: ""; position: absolute; inset: -14px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.35);
  animation: halo 2.8s var(--ease) infinite;
}
.play:hover { transform: scale(1.07); box-shadow: 0 22px 60px rgba(0,0,0,0.46); }
.play:active { transform: scale(1.0); }
@keyframes halo {
  0%   { transform: scale(0.92); opacity: 0.9; }
  70%  { transform: scale(1.22); opacity: 0; }
  100% { transform: scale(1.22); opacity: 0; }
}

/* ── Loading ─────────────────────────────────────────────────────────────── */
/* Adapted to plain CSS from "Loading Indicator" by uniquesonu on 21st.dev: two
   blocks whose inset walks an eight-step square while the pair counter-rotates,
   so the shape never repeats the same way twice. Character colours. */
.loading { position: absolute; inset: 0; z-index: 3; display: grid; place-items: center; }
.squeeze {
  position: relative; width: 58px; height: 58px;
  animation: squeeze-spin 9s linear infinite;
}
.squeeze i { position: absolute; display: block; }
.squeeze i:nth-child(1) { background: var(--josh); animation: squeeze 2.2s infinite; }
.squeeze i:nth-child(2) { background: var(--hope); border-radius: 50%;
                          animation: squeeze 2.2s infinite; animation-delay: -0.92s; }
@keyframes squeeze {
  0%    { inset: 0 2em 2em 0; }
  12.5% { inset: 0 2em 0 0; }
  25%   { inset: 2em 2em 0 0; }
  37.5% { inset: 2em 0 0 0; }
  50%   { inset: 2em 0 0 2em; }
  62.5% { inset: 0 0 0 2em; }
  75%   { inset: 0 0 2em 2em; }
  87.5% { inset: 0 0 2em 0; }
  100%  { inset: 0 2em 2em 0; }
}
@keyframes squeeze-spin { to { transform: rotate(-360deg); } }

.stuck {
  position: absolute; z-index: 4; left: 50%; bottom: 84px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: center;
  max-width: min(88%, 34rem); text-align: center;
  padding: 11px 20px; border-radius: 999px;
  background: rgba(0,0,0,0.62); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  font-size: 0.84rem; color: #f2f4f8;
}
.stuck-link { color: #9dbcff; text-underline-offset: 3px; }

.empty { position: fixed; inset: 0; display: grid; place-items: center; text-align: center;
         color: rgba(255,255,255,0.7); padding: 24px; }
.empty h2 { font-size: 1.25rem; font-weight: 800; letter-spacing: -0.02em; color: #fff; margin-bottom: 6px; }

/* ── Chrome ──────────────────────────────────────────────────────────────── */
/* Deliberately always visible rather than fading out on idle. Once a game is
   mounted the cursor is inside a cross-origin iframe and the page stops seeing
   mousemove entirely, so anything hidden on a timer could not be brought back
   without scrolling away. It stays quiet instead of disappearing. */
.chrome {
  position: fixed; z-index: 40;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px; border-radius: 999px;
  text-decoration: none; cursor: pointer;
  font-size: 0.82rem; font-weight: 600; letter-spacing: -0.005em;
  color: #fff;
  background: rgba(14,15,19,0.62);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 6px 22px rgba(0,0,0,0.28);
  backdrop-filter: blur(14px) saturate(1.3); -webkit-backdrop-filter: blur(14px) saturate(1.3);
  opacity: 0.82;
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease),
              background 0.3s ease, border-color 0.3s ease;
}
.chrome:hover, .chrome:focus-visible { opacity: 1; background: rgba(14,15,19,0.80); }
.chrome:focus-visible { outline: 2px solid rgba(255,255,255,0.8); outline-offset: 3px; }
.chrome svg { width: 15px; height: 15px; }

.back  { top: 20px; left: 20px; }
.back:hover svg { transform: translateX(-3px); }
.back svg { transition: transform 0.3s var(--ease); }

.visit { bottom: 20px; left: 20px; }
.visit:hover svg { transform: translate(2px, -2px); }
.visit svg { transition: transform 0.3s var(--ease); }

.pager {
  right: 20px; top: 50%; transform: translateY(-50%);
  flex-direction: column; gap: 10px;
  padding: 8px; border-radius: 999px;
}
.pagebtn {
  width: 40px; height: 40px; border: 0; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center;
  color: inherit; background: transparent;
  transition: background 0.25s ease, transform 0.35s var(--ease), opacity 0.25s ease;
}
.pagebtn svg { width: 18px; height: 18px; }
.pagebtn:hover { background: rgba(255,255,255,0.16); transform: scale(1.1); }
.pagebtn:active { transform: scale(1); }
.pagebtn:disabled { opacity: 0.25; cursor: default; transform: none; background: transparent; }

/* The whole feed fades up once, on arrival. */
.feed { animation: wake 0.7s var(--ease) both; }
.chrome { animation: wake 0.8s 0.18s var(--ease) both; }
@keyframes wake { from { opacity: 0; } to { opacity: 1; } }
/* The chrome's resting opacity has to survive its own entrance. */
.chrome { animation-name: wake-chrome; }
@keyframes wake-chrome { from { opacity: 0; } to { opacity: 0.82; } }

/* ── Phones ──────────────────────────────────────────────────────────────── */
@media (max-width: 700px) {
  .chrome { padding: 9px 13px; font-size: 0.76rem; }
  .back  { top: 14px; left: 14px; }
  .visit { bottom: 14px; left: 14px; }
  .pager { right: 12px; padding: 6px; gap: 6px; }
  .pagebtn { width: 36px; height: 36px; }
  .play { width: 74px; height: 74px; }
  .play svg { width: 26px; height: 26px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .chrome { opacity: 0.82; }
}

/* Every visit: the pager starts big and settles into place, with a "Scroll here" note beside
   it, so people find the way to the next game (games.js, showScrollHint). */
.pager.hint {
  animation: wake-chrome 0.8s 0.18s var(--ease) both, pager-hint 2.4s 0.5s cubic-bezier(.22,1,.36,1) both;
  box-shadow: 0 0 0 0 rgba(255,255,255,0.35);
}
@keyframes pager-hint {
  0%   { transform: translateY(-50%) scale(1.9); box-shadow: 0 0 0 0 rgba(255,255,255,0.45); }
  35%  { transform: translateY(-50%) scale(1.9); box-shadow: 0 0 0 18px rgba(255,255,255,0); }
  100% { transform: translateY(-50%) scale(1);   box-shadow: 0 0 0 0 rgba(255,255,255,0); }
}
.scroll-hint {
  position: fixed; z-index: 41; right: 84px; top: 50%;
  display: inline-flex; align-items: center; gap: 10px;
  padding: 10px 16px; border-radius: 999px; pointer-events: none;
  font-size: 0.9rem; font-weight: 700; color: #0e0f13; background: #fff;
  box-shadow: 0 10px 30px rgba(0,0,0,0.35);
  transform: translate(12px, -50%); opacity: 0;
  animation: hint-in 0.7s 1.1s cubic-bezier(.22,1,.36,1) forwards;
}
.scroll-hint svg { width: 16px; height: 16px; animation: nudge 1.1s 1.8s ease-in-out infinite; }
.scroll-hint.out { animation: hint-out 0.5s ease forwards; }
@keyframes hint-in  { to { transform: translate(0, -50%); opacity: 1; } }
@keyframes hint-out { from { transform: translate(0, -50%); opacity: 1; } to { transform: translate(12px, -50%); opacity: 0; } }
@keyframes nudge    { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(5px); } }
@media (max-width: 640px) { .scroll-hint { right: 66px; font-size: 0.82rem; padding: 8px 12px; } }
