/* Rare Aardvarks — site theme.
   Stardew-Valley-inspired 16-bit chrome (pixel fonts, wood panels, chunky
   outlines) coloured from the app's own palette (Palette.swift / AardvarkType). */

/* Fonts are loaded by a <link> in each page's <head>, NOT by @import here.
   An @import cannot begin until this file has been fetched *and* parsed, so it
   stacks DNS + TLS + a round trip for fonts.googleapis.com behind style.css,
   and then another for the font files themselves — all before the first glyph
   can render. The <link> starts in parallel with this stylesheet, and a
   preconnect warms fonts.gstatic.com while the CSS is still in flight.
   If you add a page, copy that block or the fonts silently fall back. */

:root {
  /* Farm / 16-bit world */
  --sky: #6ec6f0;
  --sky-deep: #4ba7e0;
  --grass: #5fb14e;
  --grass-dark: #3f8c3a;
  --dirt: #e0c07a;
  --wood: #7a4a24;
  --wood-dark: #4f3016;
  --wood-light: #a8703a;
  --parchment: #fbeecb;
  --parchment-2: #f5e2b6;
  --ink: #2b1d12;

  /* App palette (Palette.swift) */
  --neon-pink: #ff4dc7;
  --neon-cyan: #33f2f2;
  --neon-yellow: #fbeb38;
  --neon-orange: #ff7f2e;
  --lav: #9e73f2;

  --pixel: "Press Start 2P", monospace;
  --body: "VT323", monospace;

  /* Shadow scale. One token used to do every job, so a 40px badge and the
     full-width hero cast an identical 4px shadow and read as the same distance
     off the page. Bigger surfaces sit higher, so they throw further — expressed
     as offset rather than blur, because this idiom has no soft edges. */
  --shadow-sm: 3px 3px 0 var(--ink);   /* chips, buttons, nav links */
  --shadow:    4px 4px 0 var(--ink);   /* panels, card tiles */
  --shadow-lg: 7px 7px 0 var(--ink);   /* hero, modal sheet, app badge */
}

* { box-sizing: border-box; }

/* Light only, declared rather than left to chance. This is a daylight farm
   world — a dark theme would fight the art, the palette and the app it mirrors,
   so it is a decision, not an omission. Declaring it stops the UA from rendering
   form fields, scrollbars and the search input's clear button in dark chrome
   against parchment when the OS is set to dark. */
:root { color-scheme: light; }

/* Smooth scrolling is opt-OUT by default in most implementations, which makes it
   a vestibular trigger nobody consented to. Gate it on the preference instead of
   declaring it unconditionally. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  font-family: var(--body);
  font-size: 1.375rem;
  line-height: 1.35;
  color: var(--ink);
  background-color: var(--grass-dark);
  background-image:
    linear-gradient(180deg, var(--sky) 0%, var(--sky) 30%, transparent 30%),
    repeating-linear-gradient(0deg, var(--grass) 0 14px, var(--grass-dark) 14px 28px);
  background-attachment: fixed;
  min-height: 100vh;
}

img { image-rendering: auto; }

h1, h2, h3, .pixel { font-family: var(--pixel); }

/* ----- pixel type scale -----
   Press Start 2P runs from 0.4375rem (chips) to 1.875rem (hero) here — a 4×
   range. A single leading + tracking pair cannot serve both ends, and the old
   blanket `line-height: 1.5` was actually inverted: loosest on the 30px hero,
   tightest on the 10px labels.

   Two rules, both size-dependent:
     leading  — tight as type grows, generous as it shrinks
     tracking — negative as type grows, positive as it shrinks

   Tracking stays small (≤0.05em) on purpose. This is a pixel face, so large
   fractional letter-spacing pushes glyphs off whole-pixel positions and the
   antialiaser smears the edges — which costs more than loose spacing does.
   These values were checked optically at 3× zoom, not just computed. */

/* Display — large enough that default spacing reads loose. */
.hero h1,
.links-header h1                  { line-height: 1.15; letter-spacing: -.03em; }
.stat .n,
.download-hero .download-h1       { line-height: 1.2;  letter-spacing: -.025em; }
.section-title                    { line-height: 1.25; letter-spacing: -.02em; }

/* Mid — headings and controls. Default tracking is already right here; only the
   leading needs pulling in from 1.5. */
.notify-title,
.modal h2,
.card-page .card-page-body h1,
.feature h3,
.empty,
.lb-status                        { line-height: 1.4; letter-spacing: 0; }
.btn,
.nav .links a,
.available-now,
.links-button strong,
.attack .a-name,
.lb-rank,
.footer .pixel                    { line-height: 1.5; letter-spacing: 0; }

/* Small — 0.4375–0.625rem. These are the hardest to read on the site, and they
   are also the ones carrying the data (type, rarity, HP, card names). Opening
   the tracking buys legibility that a size bump can't, because the grid columns
   are already tight. */
.chip, .rarity-dot, .eff-tag,
.attack .a-cost,
.stat .l,
.type-emblem .t,
.fbtn,
.filter-group > .lbl,
.skip-link,
.links-eyebrow,
.links-footer,
.result-count,
.lb-subtitle,
.lb-wins                          { letter-spacing: .05em; }
.chip, .rarity-dot, .eff-tag      { line-height: 1.4; }
/* Card names wrap to two lines; the reserved box follows the leading so a
   longer name never shoves the chips row down a few pixels. */
.card-tile .cname                 { line-height: 1.5; letter-spacing: .04em; min-height: 3em; }

a { color: var(--wood-dark); }

/* Keyboard focus — make it clearly visible everywhere (the heavy custom button
   styling otherwise swallows the UA default outline). Mouse clicks don't trigger
   :focus-visible, so this only shows for keyboard/AT users. */
:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 2px;
  border-radius: 2px;
}

main { display: block; } /* legacy UA fallback for the <main> landmark */

/* ----- chunky shared components ----- */
.panel {
  background: var(--parchment);
  border: 4px solid var(--ink);
  box-shadow: var(--shadow);
  border-radius: 6px;
}

.btn {
  display: inline-block;
  font-family: var(--pixel);
  font-size: 0.75rem;
  text-decoration: none;
  color: var(--ink);
  background: var(--wood-light);
  border: 3px solid var(--ink);
  box-shadow: var(--shadow-sm);
  border-radius: 4px;
  padding: 14px 18px;
  cursor: pointer;
  transition: transform .05s, box-shadow .05s;
}
/* Hover is gated on a real hover-capable pointer. Ungated, a tap on a phone
   leaves the element stuck in its lifted state until you tap elsewhere, which
   reads as "selected" rather than "pressed". :active is NOT gated — it is the
   press feedback, and it must fire on touch. */
@media (hover: hover) {
  .btn:hover { transform: translate(-1px, -1px); box-shadow: 5px 5px 0 var(--ink); }
}
.btn:active { transform: translate(3px, 3px); box-shadow: 0 0 0 var(--ink); }
.btn.primary { background: var(--neon-yellow); }
.btn.cyan { background: var(--neon-cyan); }
.btn.pink { background: var(--neon-pink); color: #fff; }

/* ----- skip link -----
   First focusable element on every page: lets a keyboard or screen-reader user
   jump straight to <main id="main"> instead of tabbing through the whole nav on
   every single page (all 264 of them). Visually hidden until focused — pulled
   off-screen rather than `display:none`, which would drop it out of the focus
   order and defeat the point. z-index clears the sticky nav. */
.skip-link {
  position: absolute; top: -100px; left: 12px; z-index: 100;
  padding: 10px 16px;
  font-family: var(--pixel); font-size: 0.625rem;
  color: var(--ink); background: var(--neon-yellow);
  border: 3px solid var(--ink); border-radius: 4px;
  text-decoration: none;
  transition: top .12s ease-out;
}
.skip-link:focus { top: 12px; }
@media (prefers-reduced-motion: reduce) { .skip-link { transition: none; } }

/* ----- top nav ----- */
/* The toolbar is a raised layer, not a painted strip.
   Two things say so, both in the site's own idiom rather than borrowed glass:
   an inset highlight along the top edge, because light in this world falls from
   above and every other raised surface catches it; and a drop shadow that only
   deepens once content is actually passing underneath (see .nav--scrolled,
   toggled in nav.js). At the top of the page the bar sits flush and the shadow
   is nearly absent — a scroll edge effect instead of a permanent divider. */
.nav {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 18px;
  padding: 12px 20px;
  background: var(--wood);
  border-bottom: 5px solid var(--ink);
  box-shadow: inset 0 3px 0 rgba(255,255,255,.13), 0 2px 0 rgba(0,0,0,.14);
  transition: box-shadow 180ms ease-out;
}
.nav--scrolled { box-shadow: inset 0 3px 0 rgba(255,255,255,.13), 0 6px 0 rgba(0,0,0,.34); }
.nav .brand {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--pixel); font-size: 0.875rem; color: var(--parchment);
  text-decoration: none; text-shadow: 2px 2px 0 var(--ink);
}
.nav .brand img { width: 40px; height: 40px; border: 3px solid var(--ink); border-radius: 6px; }
.nav .links { margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap; }
.nav .links a {
  font-family: var(--pixel); font-size: 0.6875rem; text-decoration: none;
  color: var(--ink); background: var(--parchment-2);
  padding: 10px 12px; border: 3px solid var(--ink); border-radius: 4px;
  box-shadow: var(--shadow-sm);
}
@media (hover: hover) {
  .nav .links a:hover { background: var(--neon-cyan); }
}
/* Press feedback on the nav: same "button sinks into its own shadow" language
   as .btn, so every pressable thing on the site behaves identically. */
.nav .links a:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.nav .links a.active { background: var(--neon-yellow); }
.nav-toggle:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }

/* Hamburger toggle — hidden on desktop, shown on mobile. */
.nav-toggle {
  display: none; margin-left: auto; cursor: pointer;
  width: 44px; height: 42px; align-items: center; justify-content: center;
  font-family: var(--pixel); font-size: 1.5rem; line-height: 1;
  color: var(--ink); background: var(--neon-yellow);
  border: 3px solid var(--ink); border-radius: 4px;
  padding: 0; box-shadow: var(--shadow-sm);
  transition: transform .05s, box-shadow .05s;
}

/* ----- layout ----- */
.wrap { max-width: 1180px; margin: 0 auto; padding: 28px 20px 80px; }
.section-title {
  font-size: 1.25rem; color: var(--parchment);
  text-shadow: 3px 3px 0 var(--ink); margin: 36px 0 18px;
}
/* The referral banner sits on a light parchment panel, so the default light
   section-title washes out — use the dark heading treatment instead. */
#referral-banner .section-title {
  color: var(--wood-dark);
  text-shadow: 2px 2px 0 rgba(255, 255, 255, 0.5);
}

/* ----- footer ----- */
.footer {
  background: var(--wood-dark); color: var(--parchment);
  border-top: 5px solid var(--ink); padding: 26px 20px;
  text-align: center; font-size: 1.25rem;
}
.footer .pixel { font-size: 0.6875rem; }
.footer a { color: var(--neon-cyan); }
.footer .copyright { font-size: 1.125rem; margin-top: 14px; opacity: .9; }

/* ----- HOME ----- */
.hero {
  position: relative; overflow: hidden;
  border: 5px solid var(--ink); border-radius: 10px;
  box-shadow: var(--shadow-lg);
  background: linear-gradient(160deg, var(--sky), var(--grass));
  display: grid; grid-template-columns: 1.1fr .9fr; gap: 10px; align-items: center;
}
.hero .copy { padding: 40px 34px; }
.hero h1 { font-size: 1.875rem; color: #fff; text-shadow: 4px 4px 0 var(--ink); margin: 0 0 18px; }
.hero .tag { font-size: 1.625rem; color: var(--ink); background: rgba(251,238,203,.85);
  display: inline-block; padding: 8px 12px; border: 3px solid var(--ink); border-radius: 6px; margin-bottom: 24px; }
.hero .cta { display: flex; gap: 14px; flex-wrap: wrap; }

/* "Available Now" launch badge — sits between the tagline and the lead copy on
   both the home and download heroes. Pixel font at badge size, so keep the text
   short (it wraps as a block, not inline, on narrow screens). */
.available-now {
  display: inline-block;
  font-family: var(--pixel); font-size: 0.6875rem; line-height: 1.6;
  color: var(--ink); background: var(--neon-cyan);
  border: 3px solid var(--ink); border-radius: 5px;
  box-shadow: var(--shadow-sm);
  padding: 9px 13px;
  margin: 0 0 22px;
}
.hero .art { align-self: stretch; }
.hero .art img { width: 100%; height: 100%; object-fit: cover; display: block; border-left: 5px solid var(--ink); }

.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 26px; }
.stat { text-align: center; padding: 20px 10px; }
.stat .n { font-family: var(--pixel); font-size: 1.5rem; color: var(--neon-pink); text-shadow: 2px 2px 0 var(--ink); }
.stat .l { font-family: var(--pixel); font-size: 0.625rem; margin-top: 10px; }

.types-row { display: grid; grid-template-columns: repeat(8, 1fr); gap: 16px; }
.type-emblem { text-align: center; padding: 14px 6px; color: inherit; text-decoration: none; display: block; transition: transform .08s ease, box-shadow .08s ease; }
@media (hover: hover) {
  a.type-emblem:hover { transform: translateY(-3px); box-shadow: 6px 6px 0 var(--ink); }
}
a.type-emblem:active { transform: translate(3px, 3px); box-shadow: 0 0 0 var(--ink); }
.type-emblem img { width: 64px; height: 64px; border: 3px solid var(--ink); border-radius: 10px; background: #fff; }
.type-emblem .t { font-family: var(--pixel); font-size: 0.625rem; margin-top: 10px; }

.features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.feature { padding: 22px; }
.feature h3 { font-size: 0.8125rem; margin: 0 0 12px; color: var(--wood-dark); }

/* Match the wiki grid so home cards are the same size/shape as the wiki. */
.featured-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; }

/* ----- DOWNLOAD: hero ----- */
/* Solid parchment (matches the site's panels) with a subtle two-tone across
   the divider — no sky/grass gradient. */
.download-hero { grid-template-columns: 0.85fr 1.15fr; gap: 0; background: var(--parchment); }
.download-art {
  display: flex; align-items: center; justify-content: center;
  align-self: stretch;
  background: var(--parchment-2);
  padding: 30px; border-right: 5px solid var(--ink);
}
.download-art .app-badge {
  width: 180px; height: 180px; display: block;
  border: 5px solid var(--ink); border-radius: 28px; box-shadow: var(--shadow-lg);
}
/* Higher specificity so it beats the base `.hero h1` (which is white). */
.download-hero .download-h1 { font-size: 1.5rem; color: var(--wood-dark); text-shadow: 2px 2px 0 rgba(255,255,255,.5); margin: 0 0 18px; }
.download-lead { font-size: 1.5rem; }

/* ----- Centred call-out panel -----
   Named `notify` from its original life as the pre-launch email signup; now the
   download page's "Available Now" panel and thanks.html both use these three
   rules. The form-specific rules were dropped with the signup form itself. */
.notify { padding: 28px 26px; margin: 30px 0; text-align: center; }
.notify-title { font-size: 1.125rem; margin: 0 0 12px; color: var(--wood-dark); }
.notify-sub { font-size: 1.375rem; max-width: 560px; margin: 0 auto 22px; }

/* ----- INSTAGRAM LINK PAGE ----- */
/* A focused, single-column destination for social profile links. It uses the
   site's farm palette and chunky controls, while keeping every primary action
   comfortably sized for a thumb on a narrow phone. */
.links-page {
  display: grid;
  min-height: 100vh;
  place-items: center;
  padding: 24px 16px;
  background-image:
    radial-gradient(circle at 14% 12%, rgba(251,238,56,.5) 0 6px, transparent 7px),
    radial-gradient(circle at 85% 23%, rgba(255,255,255,.55) 0 5px, transparent 6px),
    linear-gradient(180deg, var(--sky) 0%, var(--sky) 56%, transparent 56%),
    repeating-linear-gradient(0deg, var(--grass) 0 14px, var(--grass-dark) 14px 28px);
}
.links-wrap {
  width: min(100%, 480px);
  padding: 18px 0 10px;
}
.links-header { text-align: center; margin-bottom: 24px; }
.links-app-icon {
  display: block;
  width: 94px;
  height: 94px;
  margin: 0 auto 16px;
  border: 4px solid var(--ink);
  border-radius: 19px;
  box-shadow: var(--shadow);
}
.links-eyebrow {
  margin: 0 0 12px;
  font-family: var(--pixel);
  font-size: 0.5625rem;
  color: var(--ink);
}
.links-header h1 {
  margin: 0;
  font-size: clamp(1.5rem, 7vw, 2.125rem);
  line-height: 1.35;
  color: #fff;
  text-shadow: 4px 4px 0 var(--ink);
}
.links-intro {
  max-width: 360px;
  margin: 16px auto 0;
  padding: 9px 13px;
  font-size: 1.4375rem;
  color: var(--ink);
  background: rgba(251,238,203,.88);
  border: 3px solid var(--ink);
  border-radius: 6px;
  box-shadow: var(--shadow-sm);
}
.links-list { display: grid; gap: 16px; }
.links-button {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) 24px;
  align-items: center;
  gap: 12px;
  min-height: 82px;
  padding: 13px 15px;
  color: var(--ink);
  text-decoration: none;
  border: 4px solid var(--ink);
  border-radius: 7px;
  box-shadow: var(--shadow);
  transition: transform .05s, box-shadow .05s;
}
@media (hover: hover) {
  .links-button:hover { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 var(--ink); }
}
.links-button:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--ink); }
.links-download { background: var(--neon-yellow); }
.links-contest { background: var(--neon-pink); color: #fff; }
.links-wiki { background: var(--neon-cyan); }
.links-button-icon {
  display: grid;
  width: 42px;
  height: 42px;
  place-items: center;
  font-family: var(--pixel);
  font-size: 1.25rem;
  line-height: 1;
  color: var(--ink);
  background: rgba(255,255,255,.72);
  border: 3px solid var(--ink);
  border-radius: 5px;
}
.links-button strong,
.links-button small { display: block; }
.links-button strong {
  font-family: var(--pixel);
  font-size: 0.6875rem;
  line-height: 1.5;
}
.links-button small { margin-top: 5px; font-size: 1.25rem; line-height: 1.1; }
.links-arrow {
  font-family: var(--pixel);
  font-size: 1.0625rem;
  text-align: right;
}
.links-footer {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 24px;
  font-family: var(--pixel);
  font-size: 0.5625rem;
  color: var(--parchment);
  text-shadow: 2px 2px 0 var(--ink);
}
.links-footer a { color: var(--parchment); }

/* ----- CARD TILE (shared by home + wiki) ----- */
.card-tile {
  background: var(--parchment); border: 4px solid var(--ink); border-radius: 8px;
  box-shadow: var(--shadow-sm); overflow: hidden; cursor: pointer;
  transition: transform .06s, box-shadow .06s; display: flex; flex-direction: column;
  text-decoration: none; color: inherit;
}
@media (hover: hover) {
  .card-tile:hover { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 var(--ink); }
}
/* The wiki's primary interaction — 258 of these — previously had no press state
   at all, so a tap felt inert until the modal appeared. */
.card-tile:active { transform: translate(3px, 3px); box-shadow: 0 0 0 var(--ink); }
/* Portrait art window so each tile reads as a trading card (taller than wide).
   The art is landscape (1344x768) with a centered subject, so a 1:1 crop keeps
   the full-height aardvark and trims only the side scenery. Combined with the
   meta block below, the whole tile lands near a real card's 5:7 proportion. */
.card-tile .thumb { position: relative; aspect-ratio: 1 / 1; border-bottom: 4px solid var(--ink); overflow: hidden; }
/* Placeholder shown when the card art hasn't been generated yet. Sits behind
   the <img>; an `onerror` hides a broken image and reveals this. */
.thumb::before {
  content: "ART SOON"; position: absolute; inset: 0; z-index: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--pixel); font-size: 0.6875rem; color: var(--wood-dark);
  text-shadow: 1px 1px 0 rgba(255,255,255,.4);
  background:
    repeating-linear-gradient(45deg, rgba(43,29,18,.06) 0 9px, transparent 9px 18px),
    var(--parchment-2);
}
.card-tile .thumb img { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; object-fit: cover; display: block; }
.card-tile .meta { padding: 10px 12px 12px; }
/* Leading, tracking and the two-line reserve live in the pixel type scale. */
.card-tile .cname { font-family: var(--pixel); font-size: 0.625rem; }
.card-tile .row { display: flex; align-items: center; gap: 4px; margin-top: 8px; flex-wrap: wrap; }
/* Compact the tile chips so type + rarity + HP fit on one line even in the
   narrowest grid column (minmax 200px floor). Modal/card-page chips unaffected. */
.card-tile .row .chip,
.card-tile .row .rarity-dot { font-size: 0.4375rem; padding: 4px 4px; border-width: 2px; }
.chip {
  font-family: var(--pixel); font-size: 0.5rem; color: #fff;
  padding: 5px 7px; border: 2px solid var(--ink); border-radius: 3px;
  text-shadow: 1px 1px 0 rgba(0,0,0,.4);
}
.chip.hp { background: var(--wood-dark); }
.rarity-dot { font-family: var(--pixel); font-size: 0.5rem; padding: 5px 7px; border: 2px solid var(--ink); border-radius: 3px; }
.rarity-basic { background: #e8e8e8; }
.rarity-elite { background: #4ce4ff; }
.rarity-legendary { background: var(--neon-yellow); }

/* ----- WIKI controls ----- */
.controls { padding: 20px; margin-bottom: 22px; }
.search-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.search-row input[type="search"] {
  flex: 1; min-width: 220px; font-family: var(--body); font-size: 1.5rem;
  padding: 10px 14px; border: 3px solid var(--ink); border-radius: 5px; background: #fff; color: var(--ink);
}
.filter-group { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; align-items: center; }
.filter-group > .lbl { font-family: var(--pixel); font-size: 0.625rem; margin-right: 4px; }
.fbtn {
  font-family: var(--pixel); font-size: 0.625rem; cursor: pointer;
  background: var(--parchment-2); border: 3px solid var(--ink); border-radius: 4px;
  padding: 8px 10px; box-shadow: var(--shadow-sm); display: inline-flex; align-items: center; gap: 6px;
  transition: transform .05s, box-shadow .05s;
}
.fbtn img { width: 18px; height: 18px; }
@media (hover: hover) {
  .fbtn:hover { transform: translate(-1px,-1px); box-shadow: 4px 4px 0 var(--ink); }
}
.fbtn:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.filters-toggle:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.fbtn.active { background: var(--neon-yellow); }
.fbtn.active.type { color: #000; box-shadow: inset 0 0 0 3px #fff, var(--shadow-sm); }
.result-count { font-family: var(--pixel); font-size: 0.6875rem; color: var(--parchment); text-shadow: 2px 2px 0 var(--ink); margin: 6px 0 16px; }

/* Filters collapse — toggle hidden on desktop, filters always shown. */
.filters-toggle {
  display: none; width: 100%; margin-top: 14px; cursor: pointer;
  font-family: var(--pixel); font-size: 0.6875rem; color: var(--ink);
  background: var(--parchment-2); border: 3px solid var(--ink); border-radius: 5px;
  padding: 12px; box-shadow: var(--shadow-sm); text-align: center;
}

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; }

/* ----- loading skeletons -----
   The leaderboard already had a loading state; the wiki showed an empty page
   until cards.json landed, so two comparable pages made two different promises.
   These reserve the grid's real shape, so nothing reflows when data arrives.
   Reuses the ART SOON hatch rather than inventing a second placeholder idiom —
   with the label suppressed, since nothing is missing here, only late. */
.skel { pointer-events: none; }
.skel .thumb::before { content: ""; }
.skel .cname,
.skel-chip {
  background: var(--parchment-2);
  border: 2px solid rgba(43,29,18,.22);
  border-radius: 3px;
}
.skel .cname { min-height: 0; height: 1.6em; margin-bottom: 8px; }
.skel-chip { display: inline-block; width: 46px; height: 1.35em; }
.skel-chip.w2 { width: 34px; }
/* Breathes so it reads as "loading", not "broken". Slow enough to be calm,
   fast enough not to be one of the ~0.2 Hz oscillations that trigger motion
   sensitivity; the reduced-motion block at the end of this file freezes it. */
@media (prefers-reduced-motion: no-preference) {
  .skel { animation: skel-pulse 1.4s ease-in-out infinite; }
  .skel:nth-child(3n+2) { animation-delay: .15s; }
  .skel:nth-child(3n+3) { animation-delay: .3s; }
}
@keyframes skel-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .62; } }
.empty { font-family: var(--pixel); font-size: 0.8125rem; color: var(--parchment); text-align: center; padding: 60px 0; text-shadow: 2px 2px 0 var(--ink); }

/* ----- MODAL ----- */
/* The card sheet grows out of the tile you tapped and shrinks back into it.
   Previously this was a `display: none` → `flex` hard cut, so all 258 tiles
   produced the same box appearing from nowhere and the link between what you
   touched and what opened was lost.

   Driven entirely by CSS state, not a JS animation loop, for two reasons:
   a half-finished JS close can strand the dialog open, and CSS transitions are
   inherently interruptible — reopening mid-dismiss picks up from wherever the
   panel currently is instead of snapping. JS only supplies the origin via
   --fx/--fy/--fs (set from the trigger's rect in wiki.js).

   visibility, not display, so the panel can animate; visibility:hidden still
   removes it from the accessibility tree and the tab order, which display:none
   was previously doing for us. */
.modal-bg {
  position: fixed; inset: 0; background: rgba(20,12,8,.72); z-index: 100;
  display: flex; align-items: center; justify-content: center; padding: 20px;
  visibility: hidden; opacity: 0;
  /* Delay visibility on the way out so the shrink is visible; kill the delay on
     the way in so the dialog is interactive immediately. */
  transition: opacity 200ms ease-out, visibility 0s linear 340ms;
}
.modal-bg.open {
  visibility: visible; opacity: 1;
  transition: opacity 160ms ease-out, visibility 0s;
}
.modal {
  width: min(680px, 96vw); max-height: 92vh; overflow: auto;
  background: var(--parchment); border: 5px solid var(--ink); border-radius: 10px; box-shadow: var(--shadow-lg);
  /* Resting (closed) state = collapsed onto the trigger. .open animates to
     identity, so open and close share one path in both directions — Apple's
     spatial-consistency rule: it leaves the way it came. */
  transform: translate(var(--fx, 0px), var(--fy, 0px)) scale(var(--fs, .96));
  opacity: 0;
  /* Critically damped — reaches the target and stops, no overshoot. Bounce
     would be wrong here: no gesture momentum preceded this. */
  transition: transform 340ms cubic-bezier(.32,.72,0,1), opacity 200ms ease-out;
}
.modal-bg.open .modal { transform: none; opacity: 1; }
.modal .m-head { position: relative; aspect-ratio: 1344/768; overflow: hidden; border-bottom: 5px solid var(--ink); }
.modal .m-head::before {
  content: "ART SOON"; position: absolute; inset: 0; z-index: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--pixel); font-size: 1rem; color: var(--wood-dark);
  text-shadow: 1px 1px 0 rgba(255,255,255,.4);
  background:
    repeating-linear-gradient(45deg, rgba(43,29,18,.06) 0 12px, transparent 12px 24px),
    var(--parchment-2);
}
.modal .m-head img { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; object-fit: cover; display: block; }
.modal .m-close {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
  font-family: var(--pixel); font-size: 1.375rem; line-height: 1;
  background: var(--neon-pink); color: #fff; border: 3px solid var(--ink); border-radius: 6px;
  cursor: pointer; box-shadow: var(--shadow-sm);
  transition: transform .05s, box-shadow .05s;
}
@media (hover: hover) {
  .modal .m-close:hover { transform: translate(-1px, -1px); box-shadow: 5px 5px 0 var(--ink); }
}
.modal .m-close:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.modal .m-body { padding: 22px 24px 28px; }
.modal h2 { font-size: 1.125rem; margin: 0 0 12px; }
.modal .m-tags { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; align-items: center; }
.modal .m-desc { font-size: 1.375rem; margin: 6px 0 18px; }
.attack {
  border: 3px solid var(--ink); border-radius: 6px; background: var(--parchment-2);
  padding: 12px 14px; margin-bottom: 12px;
}
.attack .a-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.attack .a-name { font-family: var(--pixel); font-size: 0.6875rem; }
.attack .a-cost { font-family: var(--pixel); font-size: 0.5625rem; background: var(--wood-dark); color: #fff; padding: 4px 7px; border: 2px solid var(--ink); border-radius: 3px; }
.attack .a-dmg { font-family: var(--pixel); font-size: 0.75rem; color: var(--neon-orange); text-shadow: 1px 1px 0 var(--ink); margin-left: auto; }
.attack .a-flavor { font-size: 1.3125rem; margin-top: 8px; }
.eff-tag { font-family: var(--pixel); font-size: 0.5rem; padding: 4px 6px; border: 2px solid var(--ink); border-radius: 3px; background: var(--lav); color: #fff; }
.engineer-effect { border: 3px dashed var(--ink); padding: 14px; border-radius: 6px; background: #fff7e0; }

/* ----- standalone card pages (cards/<slug>.html) ----- */
.card-page { padding: 0; overflow: hidden; max-width: 760px; margin: 0 auto; }
.card-page .card-page-art { position: relative; aspect-ratio: 1344 / 768; overflow: hidden; border-bottom: 5px solid var(--ink); }
.card-page .card-page-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-page .card-page-body { padding: 22px 24px 28px; }
.card-page .card-page-body h1 { font-family: var(--pixel); font-size: 1.125rem; line-height: 1.5; margin: 0 0 14px; }
.card-page .m-tags { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; align-items: center; }
.card-page .m-desc { font-size: 1.375rem; margin: 6px 0 18px; }

/* ----- responsive ----- */
@media (max-width: 860px) {
  .hero { grid-template-columns: 1fr; }
  .hero .art { display: none; }
  .stats { grid-template-columns: repeat(2, 1fr); }
  .types-row { grid-template-columns: repeat(4, 1fr); }
  .features { grid-template-columns: 1fr; }
  .nav .brand span { display: none; }

  /* Download hero stacks: badge on top, copy below. */
  .download-hero { grid-template-columns: 1fr; }
  .download-art { padding: 26px; border-right: none; border-bottom: 5px solid var(--ink); }
  .download-art .app-badge { width: 132px; height: 132px; }
  .download-hero .copy { padding: 28px 24px; text-align: center; }
  .download-hero .cta { justify-content: center; }
}

/* Collapse the nav into a hamburger dropdown on phones. */
@media (max-width: 720px) {
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; }
  /* Stays `flex` and is gated by visibility rather than display, so it can
     animate. visibility:hidden keeps it out of the tab order and the a11y tree,
     which is the one thing display:none was doing for us here. The dropdown
     drops FROM the toolbar edge it belongs to — same path in and out. */
  .nav .links {
    display: flex; position: absolute; top: 100%; left: 0; right: 0; margin: 0;
    flex-direction: column; align-items: stretch; gap: 8px;
    background: var(--wood); border-bottom: 5px solid var(--ink);
    padding: 12px 16px; box-shadow: 0 6px 0 rgba(0,0,0,.25);
    visibility: hidden; opacity: 0; transform: translateY(-10px);
    transform-origin: top center;
    transition: opacity 140ms ease-out,
                transform 200ms cubic-bezier(.32,.72,0,1),
                visibility 0s linear 200ms;
  }
  .nav.open .links {
    visibility: visible; opacity: 1; transform: none;
    transition: opacity 120ms ease-out,
                transform 220ms cubic-bezier(.32,.72,0,1),
                visibility 0s;
  }
  .nav .links a { text-align: center; font-size: 0.8125rem; padding: 13px; }

  /* Height collapse via a 0fr→1fr grid track — the only way to transition to
     an intrinsic height without measuring it in JS. */
  .filters-toggle { display: block; }
  .filters {
    display: grid; grid-template-rows: 0fr; opacity: 0;
    transition: grid-template-rows 260ms cubic-bezier(.32,.72,0,1), opacity 140ms ease-out;
  }
  .filters-inner {
    overflow: hidden;
    visibility: hidden;
    transition: visibility 0s linear 260ms;   /* only untabbable once fully closed */
  }
  .controls.filters-open .filters { grid-template-rows: 1fr; opacity: 1; }
  .controls.filters-open .filters-inner { visibility: visible; transition: visibility 0s; }
}

/* ── Leaderboard ─────────────────────────────────────────────────── */
.lb-subtitle {
  font-family: var(--pixel); font-size: 0.6875rem; color: var(--parchment);
  text-shadow: 2px 2px 0 var(--ink); margin: 6px 0 16px;
}
.lb-panel { padding: 10px 12px; }
.lb-list { list-style: none; margin: 0; padding: 0; }
.lb-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 10px;
  border-bottom: 2px dashed rgba(43, 29, 18, 0.25);
}
.lb-row:last-child { border-bottom: none; }
.lb-rank {
  font-family: var(--pixel); font-size: 0.75rem; color: var(--wood-dark);
  flex: 0 0 56px;
}
.lb-name {
  font-family: var(--body); font-size: 1.5rem; color: var(--ink);
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-wins {
  font-family: var(--pixel); font-size: 0.625rem; color: #fff;
  background: var(--grass-dark); border: 2px solid var(--ink);
  border-radius: 3px; padding: 5px 8px; flex: 0 0 auto;
}
.lb-status {
  font-family: var(--pixel); font-size: 0.75rem; color: var(--wood-dark);
  text-align: center; padding: 36px 10px; line-height: 1.6;
}
/* Podium highlights for the top three. */
.lb-rank-1 .lb-rank { color: var(--neon-orange); }
.lb-rank-1 .lb-wins { background: var(--neon-orange); color: var(--ink); }
.lb-rank-2 .lb-rank { color: var(--sky-deep); }
.lb-rank-3 .lb-rank { color: var(--lav); }

/* ----- cookie-consent banner (EEA + UK, injected by js/nav.js) ----- */
.consent-bar {
  position: fixed;
  left: 12px; right: 12px; bottom: 12px;
  z-index: 1000;
  max-width: 880px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 16px 18px;
  background: var(--parchment);
  border: 4px solid var(--ink);
  box-shadow: var(--shadow);
  border-radius: 6px;
}
.consent-bar .consent-text {
  flex: 1 1 280px;
  margin: 0;
  font-family: var(--body);
  font-size: 1.25rem;
  line-height: 1.3;
  color: var(--ink);
}
.consent-bar .consent-text a { color: var(--wood); text-decoration: underline; }
.consent-bar .consent-actions { display: flex; gap: 10px; flex: 0 0 auto; }
.consent-bar .btn { font-size: 0.6875rem; padding: 10px 16px; }
@media (max-width: 520px) {
  .consent-bar { flex-direction: column; align-items: stretch; }
  .consent-bar .consent-actions { justify-content: flex-end; }
}

/* ═══════════════════════════════════════════════════════════════════
   USER PREFERENCES — last in the file so these win the cascade.
   ═══════════════════════════════════════════════════════════════════ */

/* Reduced motion. Not "no feedback" — the press states below still fire, they
   just arrive instantly instead of travelling. Every transform-based hover/press
   in this file is transition-driven, so neutralising durations is enough; the
   states themselves stay, which keeps the interface legible. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  /* Nothing should travel across the viewport, even instantly. The card sheet
     still cross-fades in place — that keeps the open/close event legible
     without the flight across the page. */
  .modal-bg, .modal, .nav .links { transform: none !important; }
}

/* Reduced transparency. Four surfaces on this site let the background through;
   at this setting they become solid. The palette already contains an opaque
   equivalent for each, so nothing changes but the alpha. */
@media (prefers-reduced-transparency: reduce) {
  .hero .tag,
  .links-intro          { background: var(--parchment); }
  .links-button-icon    { background: #fff; }
  .modal-bg             { background: rgb(20,12,8); }
  .nav                  { box-shadow: 0 4px 0 rgba(0,0,0,.4); }
  .footer .copyright    { opacity: 1; }
}

/* Increased contrast. The site is high-contrast by construction — 3–5px ink
   outlines on everything — so the gap here is the low-alpha decoration, not the
   chrome: dashed 25%-opacity dividers, translucent text shadows, and the
   parchment-on-parchment fills that separate nested panels. */
@media (prefers-contrast: more) {
  .lb-row            { border-bottom: 2px solid var(--ink); }
  .attack            { background: #fff; }
  .engineer-effect   { background: #fff; border-style: solid; }
  .download-hero .download-h1,
  .thumb::before,
  .modal .m-head::before { text-shadow: none; }
  .footer .copyright { opacity: 1; }
  :focus-visible     { outline-width: 4px; }
}
