/* ── The arcade's front door ──────────────────────────────────────────────
 * Its own file, not a <style> block, because `_headers` sets `style-src
 * 'self'` with no 'unsafe-inline' — the strictness that file goes out of its
 * way to protect. An inline block here would be silently dropped by the CSP
 * and the page would render naked, which is a thing you only find out by
 * loading it.
 *
 * ── This page belongs to the site, not to the game ──
 * It used to inherit the game's palette wholesale: near-black with an orange
 * accent. The site it is a door into runs light, over a plants photograph,
 * with a green accent — so the two looked like different companies, and the
 * orange read as a mistake rather than as a choice.
 *
 * So the tokens are overridden here to the site's light theme with the
 * avocado green, and the same background photograph is served from this
 * domain. `arcade.css` keeps the dark palette for the GAME, which is correct:
 * a light chrome around a lit 3D world fights the world.
 *
 * The photograph is a copy rather than a hotlink on purpose. `_headers` sets
 * `img-src 'self'` and names no third-party origin anywhere — the same policy
 * that was silently breaking the favicon until it was served locally.
 */
/* No token block here any more, and that is the fix rather than an omission.
   Hardcoding the light palette forced light on this page whatever the switch
   said — `markScheme()` then read the resolved --bg, found it pale, and
   stamped data-scheme="light" even in dark mode. So the theme button did
   nothing and the photograph could never appear.

   The copied stylesheet already carries both palettes, keyed on
   `[data-mode="light"]`, and the avocado green arrives from `.avocado-on`
   exactly as it does on the main site. The cascade was always going to do
   this correctly; it just had to be allowed to. */

/* The photograph is NOT painted here. The main site builds #page-bg for it and
   its stylesheet then hides that element on any light page:

     :root[data-scheme="light"] #page-bg { display: none !important; }

   A first attempt put the plants behind this page unconditionally, with a wash
   over the top to keep type readable. It was wrong in the way that matters —
   the green a visitor sees on the light site is the AVOCADO FIELD, not the
   photograph, and painting the photograph under a light page drowned the lead
   paragraph and half the nav. arcade-chrome.js builds #page-bg the same way
   app.js does, and the copied stylesheet decides when it is seen.
/* ── The arcade's front door ────────────────────────────────────────
   This address used to BE the driving game: arcade.javiercarnicer.com
   loaded a 3D world directly, so there was nowhere to put a second game
   and no way to describe the first one before somebody was already in it.
   The game now lives at /games/InfinityDrive and this is the room it
   opens off.

   Deliberately plain. The game is the thing worth looking at, and a
   landing page that competes with it is a landing page that delays it. */
/* ── The index scrolls ──
   arcade.css still pins html and body to the window with overflow hidden,
   a rule from when this address was the driving game and nothing scrolled.
   With two games in a column the second one sat below the fold with no way
   to reach it. The index is a page, so it gets a page's scrolling back. */
html:has(body.arcade-home), body.arcade-home {
  height: auto; overflow-y: visible; overscroll-behavior: auto;
}
body.arcade-home {
  margin: 0; min-height: 100svh;
  background: transparent; color: var(--text);
  font-family: var(--sans);
  display: flex; flex-direction: column;
  padding: clamp(28px, 7vw, 92px);
  gap: clamp(28px, 6vh, 64px);
}
/* ── The header has to be lifted above the avocado field ──────────────────
   styles.css parks the field at `position: fixed; z-index: 0` and lifts the
   page's own content back over it with

     .avocado-on main, .avocado-on footer { position: relative; z-index: 1; }

   which names the two elements the MAIN site's content lives in. This page
   puts its title in a <header> that is a sibling of <main>, and a static
   element cannot win against a positioned one no matter where it sits in the
   document — so "Arcade" and the lead paragraph painted underneath the field
   and vanished the moment the avocados faded in. The title was there the
   whole time: visible, opaque, dark on pale, and behind a canvas.

   The game cards never showed the bug because .ah-game is already
   `position: relative`, and the footer is a <footer>, which the rule above
   already names. This header was the one element on the page that was
   neither. */
.ah-head { position: relative; z-index: 1; }

.ah-kicker {
  font-family: var(--mono); font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 14px;
}
.ah-kicker a { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; }
.ah-kicker a:hover { border-bottom-color: currentColor; }
/* A sentence now, not one word, so smaller than the old "Arcade" and held
   to a measure that breaks it into two or three lines rather than one long
   banner. */
.ah-title {
  font-size: clamp(2.2rem, 6.4vw, 4.4rem); line-height: 1;
  letter-spacing: -.03em; font-weight: 600; margin: 0; max-width: 14ch;
  text-wrap: balance;
}

/* ── One game, and the box that made it look like four ──
   This was a hairline mosaic: `auto-fill`, a 2px gap, and the container
   painted with `background: var(--border)` and a border around the lot. With
   one card in it, `auto-fill` still laid out three or four tracks across a
   wide window — and the container's own background and border drew the empty
   ones. So a single game appeared as a card wedged into the left third of a
   large empty rectangle, which is exactly what it looked like.

   A mosaic needs tiles. With one tile it is a card, so it is a card: the
   grid carries no background and no border of its own, and `auto-fit`
   collapses the tracks nothing occupies instead of reserving them. The
   max-width is what stops that one card then stretching to 1900px. */
.ah-games {
  display: grid;
  gap: 18px;
  /* Side by side whenever two fit. A fixed 380px track left half a
     770px window empty and stacked the cards; flexible tracks share the
     width, and the max-width keeps one card from stretching across 1900px. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  max-width: 1240px;
  align-content: start;
}
.ah-game {
  position: relative; text-decoration: none; color: inherit;
  background: var(--bg-2);
  padding: 0;
  display: flex; flex-direction: column; justify-content: flex-end;
  overflow: hidden; isolation: isolate;
  border: 1px solid var(--border); border-radius: 14px;
  transition: background .25s var(--ease), border-color .25s var(--ease),
              transform .25s var(--ease);
}
.ah-game:hover {
  background: #ffffff; border-color: rgba(20,20,16,.28);
  transform: translateY(-2px);
}
.ah-game:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .ah-game { transition: border-color .2s ease; }
  .ah-game:hover { transform: none; }
}
/* ── A card that shows the game ──
   It used to be a wash of two green gradients, which is to say a blank box
   with a title under it: the one thing a games index has to do is show what
   the game looks like, and this showed the brand colour instead.

   The still is a frame of the actual world with the HUD cropped off, set as
   a custom property on the card so the markup stays a list of links. It
   occupies the top of the card and the words sit beneath it, so nothing is
   printed over the picture and nothing needs a scrim to stay readable. */
/* ── Why the still is named by a data attribute and not an inline style ──
   The obvious spelling is `style="--shot:url(...)"` on the card, and it is
   what shipped first. `_headers` sets `style-src 'self'` with no
   'unsafe-inline', and CSP treats a style ATTRIBUTE as inline style — so the
   custom property never landed, `var(--shot)` resolved to nothing, and the
   card went back to being the blank box this was meant to fix. The console
   said so plainly; the deploy did not.

   One rule per game, here, where the stylesheet can carry it. */
.ah-game[data-game="infinitydrive"]::before {
  background-image: url("/images/games/infinitydrive.jpg");
}
/* Cut to 16:10 to match the box it fills, so `cover` has nothing to crop and
   the framing here is the framing on the page. The first version was a
   1.74:1 slice of the whole page; cover took the sides off it and left a band
   of the white "What is Sheen" panel along the bottom of the card. */
.ah-game[data-game="travianz"]::before {
  background-image: url("/images/games/travianz.jpg");
}
.ah-game[data-game="tidewater"]::before {
  background-image: url("/images/games/tidewater.jpg");
}
.ah-game[data-game="redline"]::before { background-image: url("/images/games/redline.jpg"); }
.ah-game[data-game="rally"]::before { background-image: url("/images/games/rally.jpg"); }
.ah-game[data-game="cordwood"]::before { background-image: url("/images/games/cordwood.jpg"); }
/* `hidden` has to beat the display:flex above, or a card waiting on its live
   check (TravianZ, when the machine is off) would show anyway. */
.ah-game[hidden] { display: none; }
.ah-game::before {
  content: ""; position: absolute; inset: 0 0 auto 0; z-index: 0;
  aspect-ratio: 16 / 10;
  background-size: cover; background-position: center 42%;
  transition: transform .45s var(--ease), filter .3s var(--ease);
}
.ah-game:hover::before { transform: scale(1.03); filter: saturate(1.06); }
/* No data-game, no picture: a game added without a still gets the quiet
   surface rather than a broken image or an empty strip. */
.ah-game:not([data-game])::before {
  aspect-ratio: auto; inset: 0;
  background-image:
    radial-gradient(115% 95% at 78% 12%, rgba(85,112,42,.16), transparent 62%),
    radial-gradient(85% 70% at 12% 92%, rgba(85,112,42,.08), transparent 56%);
}
/* The text block, under the picture. `padding-top` is the picture's height —
   16/10 of the card's width — so the two never overlap at any card size. */
.ah-game > * { position: relative; z-index: 1; }
.ah-game .ah-body {
  margin-top: calc(100% * 10 / 16);
  padding: 18px 20px 20px;
  background: var(--bg-2);
}
.ah-game:not([data-game]) .ah-body { margin-top: 0; padding-top: 120px; background: transparent; }
.ah-game h2 { margin: 0; font-size: 1.5rem; letter-spacing: -.02em; font-weight: 600; }
.ah-game p { margin: 8px 0 0; color: var(--muted); font-size: .86rem; line-height: 1.6; max-width: 34em; }
/* .ah-tag is gone along with the markup that used it. It said "WebGL", which
   names the rendering API rather than anything a person came here to play —
   the equivalent of labelling a film "H.264". If a tag comes back it should
   say what the game IS. */
.ah-foot {
  margin-top: auto; padding-top: 18px; border-top: 1px solid var(--border);
  font-family: var(--mono); font-size: 11px; color: var(--dim);
  display: flex; flex-wrap: wrap; gap: 6px 20px;
}
.ah-foot a { color: var(--muted); text-decoration: none; }
.ah-foot a:hover { color: var(--accent); }

/* a game we host but didn't make says so on its card */
.ah-game .ah-credit { margin-top: 10px; font-size: .78rem; color: var(--muted); font-style: italic; }
