/* ============================================================
   Tokens
   ============================================================ */
@property --beam {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

:root {
  --bg: #05060a;
  --ink: #f2f4f8;
  --ink-dim: #8b93a3;
  --ink-faint: #4d5462;
  --edge: rgba(255,255,255,.07);
  --focus: #8ed8ff;

  --pad: clamp(20px, 4.5vw, 60px);
  --maxw: 1240px;
  --ease: cubic-bezier(.2,.7,.25,1);

  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --display: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;

  /* Reused as a fine film over flat gradients so nothing looks plastic. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* ---- Ambient aurora. Fixed, blurred, slowly adrift. ---- */
.aura {
  position: fixed;
  inset: -20%;
  z-index: -2;
  pointer-events: none;
  filter: blur(90px);
  opacity: .75;
}
.aura i {
  position: absolute;
  display: block;
  border-radius: 50%;
  mix-blend-mode: screen;
}
.aura i:nth-child(1) {
  width: 52vw;
  height: 52vw;
  left: -8%;
  top: -12%;
  background: radial-gradient(circle,#a11226,transparent 66%);
  animation: drift1 34s var(--ease) infinite alternate;
}
.aura i:nth-child(2) {
  width: 44vw;
  height: 44vw;
  right: -6%;
  top: 2%;
  background: radial-gradient(circle,#0e6a7d,transparent 66%);
  animation: drift2 41s var(--ease) infinite alternate;
}
.aura i:nth-child(3) {
  width: 56vw;
  height: 56vw;
  left: 22%;
  bottom: -24%;
  background: radial-gradient(circle,#3b2a7a,transparent 66%);
  animation: drift3 47s var(--ease) infinite alternate;
}

@keyframes drift1 {
  to {
    transform: translate3d(14vw,8vh,0) scale(1.18);
  }
}
@keyframes drift2 {
  to {
    transform: translate3d(-12vw,12vh,0) scale(1.1);
  }
}
@keyframes drift3 {
  to {
    transform: translate3d(8vw,-10vh,0) scale(1.22);
  }
}

/* Deep vignette pinning the aurora behind the content. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(135% 105% at 50% -5%, transparent 32%,
    rgba(5,6,10,.86) 84%);
}

/* Grain rides on top at a whisper. It must be its own low-opacity overlay —
   layered into a `background` list it renders opaque wherever the gradient
   above it is transparent, which greys out the whole page. */
.grain {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--grain);
  background-size: 200px 200px;
  opacity: .055;
  mix-blend-mode: overlay;
}

svg {
  display: block;
}
a {
  color: inherit;
  text-decoration: none;
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
  border-radius: 6px;
}

.skip {
  position: absolute;
  left: 14px;
  top: -80px;
  z-index: 9;
  padding: 10px 16px;
  font-size: 14px;
  background: #12151c;
  border: 1px solid var(--edge);
  border-radius: 8px;
  transition: top .18s var(--ease);
}
.skip:focus {
  top: 14px;
}

/* ============================================================
   Chrome
   ============================================================ */
.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding: clamp(20px,3.5vw,34px) var(--pad);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.bar b {
  color: var(--ink);
  font-weight: 600;
  letter-spacing: .34em;
}
.bar span {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}
.bar span::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #4ade80;
  box-shadow: 0 0 0 3px rgba(74,222,128,.15);
}

/* ============================================================
   Stage
   ============================================================ */
main {
  flex: 1;
  display: flex;
  align-items: center;
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding: clamp(8px,2vw,24px) var(--pad) clamp(36px,7vw,72px);
}

/* One card per row: each game gets the full width of the page. */
.rack {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(16px,2vw,26px);
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The tile is one big link, so a game's second action (its guide) has to be a
   sibling rather than a nested anchor. The cell is what stacks the two. */
.cell {
  display: flex;
}

/* ============================================================
   Tile
   ============================================================ */
.tile {
  --accent: #a11226;
  --accent-2: #46c8b2;
  --mx: 50%;
  --my: 35%;
  /* Full width, so the card reads as a banner rather than a poster. */
  --ratio: 21/9;

  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  flex: 1;
  aspect-ratio: var(--ratio);
  min-height: 300px;
  max-height: 64svh;
  padding: clamp(22px,3.4vw,40px);
  overflow: hidden;
  isolation: isolate;
  border-radius: 20px;
  background: #080a0e;
  transform-style: preserve-3d;
  transition: transform .45s var(--ease), box-shadow .45s var(--ease);
  box-shadow: 0 30px 60px -34px #000, inset 0 0 0 1px var(--edge);
}
/* The card is not focusable itself — the links inside it are. */
.tile:hover,
.tile:has(a:focus-visible) {
  box-shadow:
    0 44px 90px -40px #000,
    0 0 90px -30px var(--accent),
    inset 0 0 0 1px color-mix(in srgb, var(--accent) 34%, var(--edge));
}
.tile:has(.tile__link:active) {
  transform: scale(.994);
}

/* ---- Banner: the game's own artwork, under everything else ---- */
.tile__banner {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .7s var(--ease);
}
.tile--banner:hover .tile__banner {
  transform: scale(1.045);
}

/* ---- Art: pure gradient scenery, keyed off the game's palette ---- */
.tile__art {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(128% 84% at 50% 120%, color-mix(in srgb, var(--accent) 96%,
    #000), transparent 62%),
    radial-gradient(68% 52% at 86% 4%, color-mix(in srgb, var(--accent-2) 48%,
    transparent), transparent 66%),
    radial-gradient(96% 68% at 8% -2%, color-mix(in srgb, var(--accent) 46%,
    transparent), transparent 64%),
    linear-gradient(#0c0e15, #05060a);
  transition: transform .7s var(--ease);
}
.tile:hover .tile__art {
  transform: scale(1.045);
}

/* A far-off horizon ring: reads as depth without any illustration. */
.tile__art::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -52%;
  width: min(86%,620px);
  aspect-ratio: 1;
  transform: translateX(-50%);
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--accent) 85%, #fff 12%);
  background: radial-gradient(circle at 50% 26%, color-mix(in srgb,
    var(--accent) 62%, transparent), transparent 60%);
  filter: blur(1px);
  opacity: .9;
  transition: opacity .6s var(--ease), transform .7s var(--ease);
}
.tile:hover .tile__art::before {
  opacity: 1;
  transform: translateX(-50%) scale(1.06);
}

/* Cursor-tracked bloom (JS feeds --mx/--my; harmless if it never runs). */
.tile__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(38% 46% at var(--mx) var(--my),
    rgba(255,255,255,.16), transparent 70%);
  opacity: 0;
  transition: opacity .5s var(--ease);
}
.tile:hover .tile__art::after {
  opacity: 1;
}

/* With a banner behind it the art stops being the scenery and becomes a tint
   over the photo: no opaque base, no horizon ring, accent wash pulled back. */
.tile--banner .tile__art {
  background:
    radial-gradient(120% 78% at 50% 122%, color-mix(in srgb, var(--accent) 72%,
    #000), transparent 58%),
    radial-gradient(64% 46% at 88% 0%, color-mix(in srgb, var(--accent-2) 26%,
    transparent), transparent 62%);
}
.tile--banner .tile__art::before {
  display: none;
}

/* ---- Legibility veil + grain, above art, below copy ---- */
.tile__veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(transparent 38%, rgba(4,3,7,.58) 74%,
    rgba(3,2,5,.9));
}
/* Artwork needs more help behind the copy than a flat gradient does. */
.tile--banner .tile__veil {
  background: linear-gradient(transparent 14%, rgba(4,3,7,.72) 58%,
    rgba(3,2,5,.95));
}
.tile__veil::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--grain);
  background-size: 200px 200px;
  opacity: .07;
  mix-blend-mode: overlay;
}

/* ---- Rotating border beam ---- */
.tile__beam {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(from var(--beam),
    transparent 0 42%,
    color-mix(in srgb, var(--accent) 85%, #fff) 52%,
    var(--accent-2) 58%,
    transparent 66% 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0
    0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: .4;
  animation: spin 9s linear infinite;
  transition: opacity .45s var(--ease);
}
.tile:hover .tile__beam,
.tile:has(a:focus-visible) .tile__beam {
  opacity: 1;
}
@keyframes spin {
  to {
    --beam: 360deg;
  }
}

/* ---- Copy ---- */
.tile__kind {
  margin: 0 0 auto;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 30%, #fff);
  opacity: .85;
}
/* Labels are separate elements so the divider stays out of the content. */
.tile__kind span + span::before {
  content: "·";
  margin: 0 .7em 0 .5em;
  opacity: .55;
}

/* The title link is stretched over the whole card, so anywhere that is not the
   guide button opens the game — and the link's name is the game's name. */
.tile__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
}

.tile__title {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(38px,7.6vw,86px);
  line-height: .94;
  letter-spacing: -.025em;
  text-shadow: 0 0 60px color-mix(in srgb, var(--accent) 60%, transparent), 0
    3px 18px rgba(0,0,0,.7);
}

/* A two-tone logo: the marked run takes the game's accent, brightened so it
   carries at title size over artwork. */
.tile__title-mark {
  /* Fallback where relative colour syntax is unsupported. */
  color: color-mix(in srgb, var(--accent) 62%, #fff);
  /* Lift lightness but keep chroma and hue: mixing towards white washes a
     deep accent out to pink, which is not what a logo highlight looks like. */
  color: oklch(from var(--accent) calc(l * 1.34) c h);
}

.tile__tag {
  margin: 12px 0 0;
  max-width: 34ch;
  font-size: clamp(13.5px,1.5vw,16px);
  color: var(--ink-dim);
  text-wrap: balance;
}

/* Play and guide sit side by side. */
.tile__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  align-self: flex-start;
  margin-top: clamp(18px,2.4vw,26px);
}

.tile__play {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 11px 20px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  border-radius: 999px;
  color: var(--ink);
  background: rgba(255,255,255,.06);
  border: 1px solid var(--edge);
  backdrop-filter: blur(8px);
  transition: background .4s var(--ease), border-color .4s var(--ease), gap .4s
    var(--ease);
}
.tile:hover .tile__play,
.tile:has(.tile__link:focus-visible) .tile__play {
  gap: 14px;
  background: color-mix(in srgb, var(--accent) 60%, transparent);
  border-color: color-mix(in srgb, var(--accent) 70%, transparent);
}

/* ============================================================
   Guide: button on the tile, overlay over the page
   ============================================================ */
/* Raised above the stretched title link so it takes its own clicks; the play
   pill deliberately stays underneath it and opens the game. */
.guidebtn {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 11px 16px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-dim);
  border-radius: 999px;
  background: rgba(6,8,12,.5);
  border: 1px solid var(--edge);
  backdrop-filter: blur(10px);
  transition: color .35s var(--ease), background .35s var(--ease), border-color
    .35s var(--ease);
}
.guidebtn:hover,
.guidebtn:focus-visible {
  color: var(--ink);
  background: rgba(6,8,12,.82);
  border-color: color-mix(in srgb, var(--ink) 26%, transparent);
}

/* Fills the viewport rather than sitting in a box: the guide is a whole page. */
.guide {
  width: 100vw;
  max-width: 100vw;
  height: 100svh;
  max-height: 100svh;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  color: var(--ink);
  background: var(--bg);
}
.guide[open] {
  display: flex;
  flex-direction: column;
}
.guide::backdrop {
  background: rgba(2,3,6,.8);
  backdrop-filter: blur(4px);
}

.guide__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex: none;
  padding: 12px clamp(14px,3vw,22px);
  border-bottom: 1px solid var(--edge);
  background: #0a0c12;
}
.guide__title {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.guide__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  cursor: pointer;
  color: var(--ink-dim);
  border-radius: 999px;
  background: rgba(255,255,255,.05);
  border: 1px solid var(--edge);
  transition: color .3s var(--ease), background .3s var(--ease);
}
.guide__close:hover,
.guide__close:focus-visible {
  color: var(--ink);
  background: rgba(255,255,255,.12);
}

.guide__frame {
  flex: 1;
  width: 100%;
  min-height: 0;
  border: 0;
  background: var(--bg);
}

/* ============================================================
   Empty state
   ============================================================ */
.empty {
  margin: 0;
  padding: 16vh 0;
  width: 100%;
  text-align: center;
  font-size: 13px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
main:has(.tile) .empty {
  display: none;
}

/* ============================================================
   Preferences
   ============================================================ */
/* Narrow screens read better as a portrait poster than a letterbox. */
@media (max-width:44rem) {
  .tile {
    --ratio: 4/5;
    max-height: none;
    border-radius: 16px;
  }
  .tile__art::before {
    bottom: -40%;
    width: min(112%,520px);
  }
}

@media (prefers-reduced-motion:reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .tile__beam {
    opacity: .6;
  }
  .tile {
    transform: none !important;
  }
}

@media (prefers-contrast:more) {
  :root {
    --ink-dim: #cfd5df;
    --ink-faint: #9aa1ad;
    --edge: rgba(255,255,255,.24);
  }
  .tile__veil {
    background: linear-gradient(transparent 20%, rgba(0,0,0,.85) 70%);
  }
}
