/* ===========================================================
   GARDEN STREET GAMES — shared effects
   Loaded by the home, games and leaderboard pages, after their own sheet.
   Depends on tokens.css. No hardcoded colors below this line.

   Everything here respects reduced motion through the tokens: the scene
   dissolve and drift collapse to 0, the ticker and the pulse stop.
   =========================================================== */

/* ---- Scenes: the games' own scenes dissolving one into the next behind a hero,
   each with a slow push-in (js/hero.js). Layers, back to front: .scenes,
   .scenes-shade, .scenes-grain, .plat-grid. Used by the home, games and
   leaderboard heroes. ---- */
.scenes { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.scenes img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity var(--dur-scene) var(--ease-in-out);
}
.scenes img.is-on { opacity: 0.6; }
.scenes img.is-on,
.scenes img.is-leaving { animation: scene-drift var(--dur-drift) linear forwards; }
@keyframes scene-drift {
  from { transform: scale(1.06) translateX(0); }
  to   { transform: scale(1.18) translateX(-2%); }
}
/* Light mode (js/lite.js): the scenes still dissolve, they just hold still. */
.lite .scenes img.is-on,
.lite .scenes img.is-leaving { animation: none; }
/* Dark where the type sits, opening toward the right; the bottom melts into the page. */
.scenes-shade {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to top, var(--bg) 0%, transparent 38%),
    linear-gradient(90deg,
      color-mix(in srgb, var(--ink) 94%, transparent) 0%,
      color-mix(in srgb, var(--ink) 72%, transparent) 42%,
      color-mix(in srgb, var(--ink) 30%, transparent) 100%);
}
@media (max-width: 700px) {
  .scenes-shade {
    background:
      linear-gradient(to top, var(--bg) 0%, transparent 38%),
      color-mix(in srgb, var(--ink) 74%, transparent);
  }
}
/* Film grain: an inline SVG noise tile, so no extra request. */
.scenes-grain {
  position: absolute; inset: 0; pointer-events: none;
  opacity: 0.09; mix-blend-mode: overlay;
  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='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* Light mode: no grain. A full-width overlay blend repaints everything under it. */
.lite .scenes-grain { display: none; }

/* ---- The faint street grid, rotated like a plat map on a drafting table ---- */
.plat-grid {
  position: absolute; inset: -40% -20%;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--paper) 13%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--paper) 13%, transparent) 1px, transparent 1px);
  background-size: 92px 92px;
  transform: rotate(-14deg);
  /* #000 here is a mask stencil (opaque = keep), not a brand colour - do not tokenise */
  mask-image: radial-gradient(ellipse 78% 70% at 58% 44%, #000 12%, transparent 82%);
  pointer-events: none;
}


/* ================= STRIP / MARQUEE ================= */
.strip {
  position: relative;
  border-block: var(--hairline);
  background: var(--surface);
  overflow: hidden;
  padding: var(--s-4) 0;
}
.strip__track {
  display: flex; gap: var(--s-7); width: max-content;
  animation: slide 38s linear infinite;
}
.strip__track > span {
  font-family: var(--font-display); font-size: 1.15rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-faint); white-space: nowrap;
  display: flex; align-items: center; gap: var(--s-7);
}
.strip__track > span::after {
  content: ""; width: 6px; height: 6px; background: var(--accent);
  transform: rotate(45deg); flex: none;
}
@keyframes slide { to { transform: translateX(-50%); } }

/* Live scores (js/ticker.js): a pinned label, and each score as name, number, game. */
.strip__live {
  display: none;
  position: absolute; left: 0; top: 0; bottom: 0; z-index: 1;
  align-items: center; gap: var(--s-2);
  padding: 0 var(--s-4) 0 var(--gutter);
  background: var(--surface);
  font-family: var(--font-body); font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--accent); white-space: nowrap;
}
.strip__live::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent);
  animation: live-pulse var(--dur-scene) var(--ease-in-out) infinite;
}
@keyframes live-pulse { 50% { opacity: 0.25; } }
.strip__live::after {   /* scores slide out from under a short fade, not a hard edge */
  content: ""; position: absolute; left: 100%; top: 0; bottom: 0;
  width: var(--s-7);
  background: linear-gradient(90deg, var(--surface), transparent);
}
.strip.is-live .strip__live { display: flex; }
/* A page with no static strip to fall back on shows the ticker only once it is live. */
.strip[data-ticker-only]:not(.is-live) { display: none; }
.strip__track > .tick { gap: var(--s-3); }
.tick__name { color: var(--text); }
.tick__score { color: var(--accent); }
.tick__game {
  font-family: var(--font-body); font-size: var(--fs-xs);
  letter-spacing: var(--tracking-label); color: var(--text-faint);
}
@media (prefers-reduced-motion: reduce) { .strip__track, .strip__live::before { animation: none; } }

/* ---- Page hero: the games and leaderboard pages open like the home page ---- */
.page-hero {
  position: relative;
  overflow: hidden;
  padding: clamp(3rem, 12vh, 7rem) 0 clamp(2.5rem, 7vh, 4.5rem);
  border-bottom: var(--hairline);
}
.page-hero__inner { position: relative; }
.page-hero--short { padding: clamp(2.5rem, 8vh, 4.5rem) 0 clamp(2rem, 5vh, 3rem); }
.page-hero__eyebrow {
  display: flex; align-items: center; gap: var(--s-3);
  margin: 0 0 var(--s-5);
  font-family: var(--font-body); font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--text-faint);
}
.page-hero__eyebrow::before {
  content: ""; width: 28px; height: 2px; background: var(--accent); flex: none;
}
.page-hero h1 {
  font-family: var(--font-display);
  font-size: var(--fs-hero);
  font-weight: 400;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
  line-height: 0.9;
  margin: 0 0 var(--s-5);
}
.page-hero h1 .outline {
  color: transparent;
  -webkit-text-stroke: 2px var(--paper);
  paint-order: stroke fill;
}
.page-hero h1 .accent { color: var(--accent); }
.page-hero p {
  color: var(--text-muted);
  font-size: var(--fs-md);
  max-width: var(--maxw-text);
  margin: 0;
}

/* ---- Rise into view (js/fx.js). JS adds .rise, so with no JS nothing is ever
   left hidden; --rise-delay staggers a group. It moves with `translate`, not
   `transform`, so it never fights an element's own transform (the catalog
   cards' tilt lives in `transform`). ---- */
.rise {
  opacity: 0;
  translate: 0 var(--s-5);
  transition: opacity var(--dur-slow) var(--ease-out) var(--rise-delay, 0ms),
              translate var(--dur-slow) var(--ease-out) var(--rise-delay, 0ms),
              border-color var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}
.rise.is-in { opacity: 1; translate: none; }
