/* Bits of Redwood studio site
   Design language: mid-century national-park poster. Flat shapes, limited palette,
   sharp corners, solid offset shadows (print misregistration), letterspaced caps.
   Brand palette is fixed (ink/cream/green/rust); everything else is a derived tint. */

@font-face {
    font-family: 'Jost';
    src: url('../fonts/Jost-Variable.woff2') format('woff2-variations'),
         url('../fonts/Jost-Variable.ttf') format('truetype-variations');
    font-weight: 100 900;
    font-display: swap;
}

@font-face {
    font-family: 'Silkscreen';
    src: url('../fonts/Silkscreen-Regular.woff2') format('woff2'),
         url('../fonts/Silkscreen-Regular.ttf') format('truetype');
    font-weight: 400;
    font-display: swap;
}

:root {
    /* settled brand palette — see branding/PALETTE.md. These four are for fills,
       borders and shadows. Brand green and rust land at 3.4:1–4.3:1 on cream, so
       they are NOT safe as text; use the -text variants below for anything read. */
    --ink: #250E0C;
    --parchment: #FAF4EF;
    --green: #677C3C;
    --rust: #BD704C;
    /* text-safe shades of the same two hues — all clear 4.5:1 on both cream and paper */
    --green-text: #546630;  /* 5.80:1 on parchment, 4.81:1 on paper */
    --rust-text: #8E5338;   /* 5.59:1 on parchment, 4.64:1 on paper */
    --green-deep: #5C6F35;  /* header bar: parchment text on it is 5.09:1 */
    /* derived poster tints */
    --pine: #282D27;   /* reserved: the alternative footer bg (parchment on it is 12.9:1,
                          peach 4.96:1) — see the open footer-accent decision */
    --moss: #A2B65F;   /* reserved: mid-distance trees */
    --sage: #4A4C48;   /* reserved: far ridge */
    --peach: #C19076;  /* footer heading accent */
    --bark: #545849;   /* reserved: dark trunk */
    --paper: #ECDED4;  /* alt panel background */
    --ink-60: rgba(37, 14, 12, 0.66);
    --ink-40: rgba(37, 14, 12, 0.42);
    --ink-25: rgba(37, 14, 12, 0.25);
    --cream-25: rgba(250, 244, 239, 0.3);

    /* Silkscreen size scale. Two things make this font need more size than it looks
       like it should: its capitals are only ~55% of the em (Jost's are ~72%), so 12px
       Silkscreen reads smaller than 12px Jost; and it is drawn on an 8px grid, so
       multiples of 8 land on whole pixels and stay crisp. Hence 16 / 14 / 12 rather
       than the 10-11px it started at. Every Silkscreen rule uses one of these three. */
    --px-lg: 1rem;      /* 16px, 2x the design grid — section kickers */
    --px-md: 0.875rem;  /* 14px — card numbers, dates, fact strip, placeholders */
    --px-sm: 0.75rem;   /* 12px — hero note, signup note, tags, footer tag */
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* keyboard users get to the content without tabbing the whole nav */
.skip {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 10;
    background: var(--parchment);
    color: var(--ink);
    border: 2px solid var(--ink);
    padding: 12px 20px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-size: 0.85rem;
}

.skip:focus { left: 12px; top: 12px; }

body {
    margin: 0;
    background: var(--parchment);
    color: var(--ink);
    font-family: 'Jost', 'Segoe UI', system-ui, sans-serif;
    font-weight: 400;
    font-size: 1.0625rem;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

/* short pages (a game page with no media yet, 404) keep the footer on the floor
   instead of floating it mid-screen with bare parchment underneath */
body {
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
}

main { flex: 1 0 auto; }

a { color: inherit; }

/* One visible focus ring everywhere instead of the UA default, whose color isn't
   guaranteed to clear 3:1 on the green bars. Ink on light surfaces, parchment on green. */
:focus-visible {
    outline: 3px solid var(--ink);
    outline-offset: 3px;
}

.site-head :focus-visible,
.site-foot :focus-visible { outline-color: var(--parchment); }

img { max-width: 100%; height: auto; }

.wrap {
    max-width: 1020px;
    margin: 0 auto;
    padding: 0 24px;
}

.wrap.narrow { max-width: 720px; }

.wrap.center { text-align: center; }

/* ---------- pixel kicker (the "bits") ---------- */

.kicker {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-lg);
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--green-text);
    display: inline-flex;
    align-items: center;
    gap: 12px;
    margin: 0 0 14px;
}

/* Three offset "pixels" — the literal bits in the studio name. One 8px box plus two
   box-shadow copies; the shadows overflow the 8px layout box, so margin-right has to
   match the furthest horizontal offset (26px) or the text collides with the third pixel.
   The third was --ink-25 and read as a smudge next to two solid squares; --ink-40 keeps
   it recessive without disappearing. */
.kicker::before {
    content: "";
    width: 8px;
    height: 8px;
    background: var(--rust);
    box-shadow: 13px -6px 0 var(--green), 26px 3px 0 var(--ink-40);
    margin-right: 26px;
    flex: none;
}

/* ---------- header ---------- */

.site-head {
    border-bottom: 2px solid var(--ink);
    background: var(--green-deep);
}

.site-head .brand,
.site-head nav a {
    color: var(--parchment);
}

.site-head .wrap {
    max-width: 1120px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px 22px;
    flex-wrap: wrap;
    padding-top: 16px;
    padding-bottom: 16px;
}

.brand {
    display: flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
}

.brand img {
    height: 32px;
    width: auto;
    display: block;
}

.brand b {
    font-weight: 650;
    font-size: 1.02rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
}

.site-head nav {
    display: flex;
    gap: 6px 26px;
    flex-wrap: wrap;
}

.site-head nav a {
    text-decoration: none;
    text-transform: uppercase;
    font-weight: 600;
    font-size: 0.82rem;
    letter-spacing: 0.14em;
    padding: 10px 0 7px;        /* ~40px tall tap target */
    border-bottom: 3px solid transparent;
}

/* --cream-25 was 1.78:1 on the bar and read as no hover at all */
.site-head nav a:hover { border-bottom-color: var(--moss); }

.site-head nav a[aria-current="page"] { border-bottom-color: var(--parchment); }

/* ---------- buttons ---------- */

.btn {
    display: inline-block;
    font-family: 'Jost', sans-serif;
    font-weight: 700;
    font-size: 1rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
    text-align: center;
    color: var(--ink);          /* 4.87:1 on rust; parchment on rust was only 3.45:1 */
    background: var(--rust);
    border: 2px solid var(--ink);
    border-radius: 2px;
    padding: 13px 28px;
    box-shadow: 4px 4px 0 var(--ink);
    transition: transform 0.08s ease, box-shadow 0.08s ease;
}

.btn:hover,
.btn:focus-visible {
    transform: translate(2px, 2px);
    box-shadow: 2px 2px 0 var(--ink);
}

.btn:active {
    transform: translate(4px, 4px);
    box-shadow: 0 0 0 var(--ink);
}

.btn.ghost {
    background: var(--parchment);
    color: var(--ink);
}

.btn.pine {
    background: var(--green-deep);
    color: var(--parchment);
}

.btn[aria-disabled="true"] {
    pointer-events: none;
    background: var(--paper);
    color: var(--ink-60);
    border-style: dashed;
    box-shadow: none;
}

.btn-row {
    display: flex;
    gap: 18px;
    justify-content: center;
    flex-wrap: wrap;
}

.btn-row.store-row { margin: 42px 0 10px; }

/* ---------- hero (homepage) ---------- */

.hero {
    text-align: center;
    overflow: hidden;
}

.hero-inner {
    padding: clamp(48px, 8vw, 88px) 24px 8px;
    max-width: 780px;
    margin: 0 auto;
}

/* the wordmark image IS the homepage h1 — its alt text carries the heading */
.hero h1 { margin: 0; }

.hero .wordmark {
    width: min(520px, 86%);
    display: block;
    margin: 6px auto 4px;
}

.hero .tagline {
    font-size: clamp(1.1rem, 2.4vw, 1.3rem);
    font-weight: 500;
    max-width: 44ch;
    margin: 0 auto 30px;
    text-wrap: balance;
}

.hero .btn-row { margin-bottom: 10px; }

.hero-note {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-sm);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--ink-60);
    margin-top: 18px;
}

/* ---------- sections ---------- */

.section { padding: clamp(56px, 9vw, 92px) 0; }

/* the two spacing cases that used to be inline style="" on nearly every page:
   .tight follows a .page-head, .flush stacks straight onto the section above it */
.section.tight { padding-top: 48px; }

.section.flush { padding-top: 0; }

.section.tint {
    background: var(--paper);
    border-top: 2px solid var(--ink);
    border-bottom: 2px solid var(--ink);
}

.section-head { margin-bottom: 36px; }

.section-head h2 {
    font-weight: 700;
    font-size: clamp(1.5rem, 3.4vw, 2rem);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin: 0;
}

.section-head.center { text-align: center; }

.section-head.center .kicker { justify-content: center; }

/* intro line under a left-aligned section head, above its grid */
.pitch-wide {
    max-width: 62ch;
    margin: -14px 0 30px;
    color: var(--ink-60);
}

/* ---------- cards ----------
   One box treatment, three layouts. .card is the box; the grid class decides how many
   sit in a row. Only a.card gets hover motion — seedling cards have no detail page to
   link to, so they must not look clickable. */

.card {
    display: block;
    background: var(--parchment);
    border: 2px solid var(--ink);
    border-radius: 2px;
    box-shadow: 5px 5px 0 var(--ink-25);
    padding: 26px 24px 24px;
}

a.card {
    text-decoration: none;
    transition: transform 0.08s ease, box-shadow 0.08s ease;
}

a.card:hover {
    transform: translate(-2px, -2px);
    box-shadow: 7px 7px 0 var(--ink-25);
}

.card .no {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-md);
    letter-spacing: 0.2em;
    color: var(--rust-text);
    display: block;
    margin-bottom: 12px;
}

.card h3 {
    margin: 0 0 8px;
    font-weight: 700;
    font-size: 1.16rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.card p {
    margin: 0;
    font-size: 0.95rem;
    color: var(--ink-60);
}

.card .go {
    display: inline-block;
    margin-top: 16px;
    font-weight: 700;
    font-size: 0.8rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--green-text);
}

a.card:hover .go { color: var(--rust-text); }

a.card .go { transition: transform 0.12s ease; }

a.card:hover .go { transform: translateX(4px); }

/* card grids */

.trail-grid,
.game-grid,
.seedling-grid {
    display: grid;
    gap: 26px;
}

.trail-grid { grid-template-columns: repeat(3, 1fr); }

/* two in progress, side by side, stacking on narrow screens */
.game-grid { grid-template-columns: repeat(2, 1fr); }

/* one game in the workshop: a centered feature card, not half of an empty row */
.game-grid > :only-child {
    grid-column: 1 / -1;
    justify-self: center;
    width: 100%;
    max-width: 560px;
}

/* auto-fit so this keeps working at 3, 5 or 9 seedlings without a new breakpoint */
.seedling-grid { grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }

.seedling-card .no { color: var(--green-text); }

.game-grid + .grid-note,
.seedling-grid + .grid-note {
    margin: 30px 0 0;
    text-align: center;
}

.grid-note a {
    font-weight: 700;
    font-size: 0.85rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--green-text);
}

/* the "vote on what's next" block under the seedlings */
.vote-box {
    margin-top: 34px;
    padding: 26px 24px;
    border: 2px dashed var(--ink-25);
    border-radius: 2px;
    text-align: center;
}

.vote-box p {
    margin: 0 0 20px;
    color: var(--ink-60);
    max-width: 52ch;
    margin-inline: auto;
}

/* ---------- page banner (subpages) ---------- */

.page-head {
    text-align: center;
    padding: clamp(44px, 7vw, 72px) 24px 0;
}

.page-head h1 {
    font-weight: 700;
    font-size: clamp(2rem, 5vw, 2.9rem);
    letter-spacing: 0.03em;
    text-transform: uppercase;
    margin: 0 0 10px;
}

.page-head .lede {
    max-width: 54ch;
    margin: 0 auto;
    color: var(--ink-60);
    font-size: 1.08rem;
}

.page-head .kicker { justify-content: center; }

/* ---------- media frames (trailer / screenshots) ---------- */

.poster-frame {
    border: 2px solid var(--ink);
    border-radius: 2px;
    background: var(--paper);
    box-shadow: 5px 5px 0 var(--ink-25);
    margin: 0 0 30px;
    overflow: hidden;
}

.poster-frame .placeholder {
    aspect-ratio: 16 / 9;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    color: var(--ink-60);
    text-align: center;
    padding: 24px;
}

.poster-frame .placeholder .px {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-md);
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--green-text);
}

.shot-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 22px;
    margin-bottom: 30px;
}

.shot-grid .poster-frame { margin: 0; }

.shot-grid .placeholder { aspect-ratio: 16 / 10; }

/* ---------- signup ---------- */

.signup-card {
    border: 2px solid var(--ink);
    border-radius: 2px;
    background: var(--parchment);
    box-shadow: 5px 5px 0 var(--ink-25);
    padding: clamp(26px, 4vw, 40px);
}

.signup-card h2 {
    margin: 0 0 8px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-size: 1.35rem;
}

.signup-card > p { margin: 0 0 20px; color: var(--ink-60); }

.signup-groups {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 24px;
    margin: 0 0 22px;
    padding: 0;
    list-style: none;
}

.signup-groups li {
    position: relative;
    padding-left: 22px;
    font-size: 0.98rem;
}

.signup-groups li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.42em;
    width: 9px;
    height: 9px;
    background: var(--green-text);
}

.signup-groups li:nth-child(even)::before { background: var(--rust); }

.signup-groups b { font-weight: 600; }

.signup-note {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-sm);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-60);
    margin-top: 16px;
}

/* ---------- prose / about ---------- */

.prose p { margin: 0 0 1.2em; }

/* section headings inside long-form text (support, privacy) */
.prose h2 {
    font-weight: 700;
    font-size: 1.25rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin: 1.8em 0 0.5em;
}

.prose h2:first-child { margin-top: 0; }

.prose .back-link { margin-top: 2.5em; }

.prose .placeholder-line,
.placeholder-line {
    border: 2px dashed var(--ink-25);
    border-radius: 2px;
    padding: 22px;
    color: var(--ink-60);
    font-size: 0.95rem;
}

.fact-strip {
    display: flex;
    justify-content: center;
    gap: 14px 34px;
    flex-wrap: wrap;
    margin: 30px 0 0;
    padding: 18px 12px;
    border-top: 2px solid var(--ink);
    border-bottom: 2px solid var(--ink);
}

.fact-strip span {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-md);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-60);
}

/* ---------- contact ---------- */

.contact-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
}

.contact-card {
    border: 2px solid var(--ink);
    border-radius: 2px;
    background: var(--parchment);
    box-shadow: 5px 5px 0 var(--ink-25);
    padding: 26px 24px;
}

.contact-card h3 {
    margin: 0 0 6px;
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.contact-card p { margin: 0; color: var(--ink-60); font-size: 0.98rem; }

.contact-card a { color: var(--ink); font-weight: 600; }

.contact-card .kicker { margin-bottom: 10px; }

/* ---------- links page ---------- */

.link-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.link-list a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    text-decoration: none;
    background: var(--parchment);
    border: 2px solid var(--ink);
    border-radius: 2px;
    box-shadow: 4px 4px 0 var(--ink-25);
    color: var(--ink);
    padding: 16px 20px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-size: 0.95rem;
    transition: transform 0.08s ease, box-shadow 0.08s ease;
}

.link-list a::after {
    content: "→";
    font-weight: 400;
    color: var(--rust-text);
}

.link-list a:hover {
    transform: translate(2px, 2px);
    box-shadow: 2px 2px 0 var(--ink-25);
    background: var(--paper);
}

.link-list a[aria-disabled="true"] {
    pointer-events: none;
    border-style: dashed;
    box-shadow: none;
    color: var(--ink-60);
}

.link-list a[aria-disabled="true"]::after { content: "···"; color: var(--ink-60); }

.link-list .tag {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-sm);
    letter-spacing: 0.16em;
    color: var(--green-text);
    margin-left: auto;
}

/* ---------- news ---------- */

.news-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.news-list li { border-bottom: 2px solid var(--ink-25); }

.news-list li:first-child { border-top: 2px solid var(--ink-25); }

.news-list a {
    display: block;
    text-decoration: none;
    padding: 26px 8px;
}

.news-list a:hover { background: var(--paper); }

.news-list time {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-md);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--rust-text);
    display: block;
    margin-bottom: 8px;
}

.news-list h3 {
    margin: 0 0 6px;
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.news-list p { margin: 0; color: var(--ink-60); font-size: 0.98rem; }

/* .news-empty is written by tools/build_feed.py, so its name is fixed. .empty-state is
   the same thing for any other section that has nothing in it yet (e.g. Released). */
.news-empty,
.empty-state {
    border: 2px dashed var(--ink-25);
    border-radius: 2px;
    padding: 56px 24px;
    text-align: center;
    color: var(--ink-60);
}

.empty-state .px,
.news-empty .px {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-md);
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--green-text);
    display: block;
    margin-bottom: 10px;
}

.post-meta {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-md);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--rust-text);
}

/* ---------- footer ---------- */

/* Footer stays green to bookend the green header (developer call, 2026-08-07).
   --green-deep rather than --green so parchment on it reaches 5.09:1, not 4.25:1. */
.site-foot {
    position: relative;
    --treeline-h: clamp(180px, 20vw, 264px);
    margin-top: var(--treeline-h);  /* room for the treeline above */
    background: var(--green-deep);
    color: var(--parchment);
    text-align: center;
    padding: 36px 24px 36px;
}

/* The park-poster horizon: a pixel coast-redwood grove (rust trunks, sword ferns at the
   base) tiling across the top of the footer so the footer reads as the forest floor.
   Two layers of one tile, both generated by tools/build_treeline.py with the palette
   hardcoded (re-run it if --green-deep, --green, --moss, --rust or --peach change):
   ::before is the far row (treeline-back.svg), ::after the groves, ground and ferns
   (treeline-front.svg). Stacked with no offset they are exactly the single image. */
.site-foot::before,
.site-foot::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(100% - 1px);   /* 1px overlap so no seam shows at fractional zoom */
    height: var(--treeline-h);
    background: url('../img/treeline-back.svg') repeat-x left bottom / auto 100%;
    pointer-events: none;
}

.site-foot::after { background-image: url('../img/treeline-front.svg'); }

/* Parallax: while the treeline scrolls up into view, the far row starts a little higher
   and rises more slowly, settling into line as the ground reaches the bottom of the
   screen. The range ends there, not when the whole footer is in view, on purpose: any
   offset while the ground is visible would leave the far trunks floating above it.
   The far row moves its background, not the box, so the box view() measures stays put.
   No support or reduced motion: the static, lined-up treeline. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .site-foot::before {
            animation: treeline-far linear both;
            animation-timeline: view();
            animation-range: entry 0% entry 100%;
        }
    }
}

@keyframes treeline-far {
    from { background-position: left bottom calc(var(--treeline-h) / 5); }
}

.site-foot .foot-mark {
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    margin: 0 0 4px;
}

/* OPEN DECISION (studio/DECISIONS.md, 2026-08-09): this peach "of" is 1.99:1 on the
   green footer. Left exactly as designed — every peach that clears 4.5:1 on green is
   so light it stops reading as peach. Fixing it means moving the footer to --pine. */
.site-foot .foot-mark span { color: var(--peach); }

.site-foot .foot-tag {
    font-family: 'Silkscreen', monospace;
    font-size: var(--px-sm);
    letter-spacing: 0.22em;
    text-transform: uppercase;
    margin: 0 0 26px;
}

.foot-links {
    display: flex;
    gap: 4px 28px;
    justify-content: center;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.foot-links.social {
    margin: 0 auto 26px;
    padding-top: 10px;
    max-width: 560px;
    border-top: 2px solid var(--cream-25);
}

.foot-links a {
    display: inline-block;
    padding: 8px 2px 6px;       /* tap target was ~22px tall */
    text-decoration: none;
    font-weight: 600;
    font-size: 0.85rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    border-bottom: 2px solid transparent;
}

/* parchment, not rust: rust on the green footer is 1.48:1 and the hover state
   was invisible. Matches the header's current-page underline. */
.foot-links a:hover { border-bottom-color: var(--parchment); }

.site-foot .fine {
    font-size: 0.82rem;
    margin: 0;
}

/* ---------- utilities ---------- */

/* top gap for a list, grid or button row that follows body copy.
   Declared last so it beats the component's own margin shorthand. */
.spaced,
.prose .spaced { margin-top: 30px; }   /* .prose p would otherwise win on specificity */

/* ---------- responsive ---------- */

@media (max-width: 860px) {
    .trail-grid { grid-template-columns: 1fr; }
    .contact-grid { grid-template-columns: 1fr; }
    /* the two in-progress games stack top-to-bottom rather than squeezing side by side */
    .game-grid { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
    .site-head .wrap { justify-content: center; text-align: center; }
    .site-head nav { justify-content: center; gap: 6px 20px; }
    .shot-grid { grid-template-columns: 1fr; }
    .signup-groups { grid-template-columns: 1fr; }
    .btn { width: 100%; max-width: 340px; }
    .btn-row { flex-direction: column; align-items: center; }
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    /* the poster "press" effect is motion, not decoration — drop the travel,
       keep the shadow change so hover is still visible */
    .btn:hover,
    .btn:focus-visible,
    .btn:active,
    a.card:hover,
    a.card:hover .go,
    .link-list a:hover {
        transform: none;
    }
}
