/* ==========================================================================
   GFR GAMES — CHROME
   --------------------------------------------------------------------------
   The building, not the galleries. Everything here is the light gallery wall:
   paper, graphite, one accent, and the type that carries the institution's
   voice. Per-game color lives in themes-games.css and never leaks in here.

   Design: docs/plans/2026-08-03-gfr-games-visual-identity-design.md

   Structure of this file:
     1. Fonts + tokens
     2. Base + reset-ish
     3. Nav
     4. Paper sections (hero, wall text, close)
     5. Rooms — the full-bleed themed bands
     6. Wall labels (placards)
     7. Footer
     8. Forms + buttons
     9. Reduced motion
   ========================================================================== */

/* 1. FONTS + TOKENS ======================================================== */

/* Chrome faces only. Each game's display face is imported by
   themes-games.css so the two layers stay independently removable. */
@import url('https://fonts.googleapis.com/css2?family=Archivo:wght@500;600;700;800;900&family=Spectral:ital,wght@0,400;0,500;0,600;1,400&display=swap');

:root {
    /* Gallery wall. Warm throughout — no neutral grays, nothing pure. */
    --gfr-paper:    #f4f0e6;
    --gfr-panel:    #fbf8f1;
    --gfr-ink:      #1a1714;
    --gfr-ink-dim:  #5c554c;
    --gfr-rule:     rgba(26, 23, 20, 0.14);
    --gfr-rule-firm:rgba(26, 23, 20, 0.28);

    /* Exhibition vermilion, darkened a step from the #a83a24 in the design
       doc. Measured on paper: 6.27:1 here vs 5.60:1 for the original. Both
       clear AA; the extra headroom is for small link and label text, which is
       most of where the accent actually appears. */
    --gfr-accent:      #9c3520;
    --gfr-accent-soft: rgba(156, 53, 32, 0.10);

    --gfr-display: 'Archivo', ui-sans-serif, system-ui, sans-serif;
    --gfr-body:    'Spectral', 'Iowan Old Style', Georgia, serif;

    --gfr-maxw:   1180px;
    --gfr-gutter: clamp(1.25rem, 5vw, 4.5rem);

    /* Rooms are sized in vh but clamped: on a short laptop this gets cramped,
       on a tall monitor it becomes a canyon. Pulled down from 65vh after
       looking at it — content is bottom-anchored, so a taller room just grew
       dead space above the title rather than presence. */
    --gfr-room-h: clamp(26rem, 58vh, 40rem);
}

/* 2. BASE ================================================================== */

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

html { scroll-behavior: smooth; }

body {
    margin: 0;
    background: var(--gfr-paper);
    color: var(--gfr-ink);
    font-family: var(--gfr-body);
    font-size: clamp(1rem, 0.97rem + 0.16vw, 1.09rem);
    line-height: 1.62;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
    font-family: var(--gfr-display);
    font-weight: 800;
    line-height: 1.04;
    letter-spacing: -0.03em;
    margin: 0;
}

a { color: var(--gfr-accent); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { text-decoration-thickness: 2px; }

/* One focus treatment everywhere. Vermilion reads on paper and on every room
   ground, which is why the accent had to survive contrast on both. */
:focus-visible {
    outline: 2px solid var(--gfr-accent);
    outline-offset: 3px;
    border-radius: 2px;
}
.room :focus-visible { outline-color: currentColor; }

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

.gfr-wrap {
    max-width: var(--gfr-maxw);
    margin-inline: auto;
    padding-inline: var(--gfr-gutter);
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--gfr-ink);
    color: var(--gfr-paper);
    padding: 0.7rem 1.1rem;
    z-index: 100;
}
.skip-link:focus { left: 0; }

/* Small wide-tracked Archivo. This is what removes the need for a mono face —
   labels, eyebrows, statuses and nav all share it. */
.gfr-label {
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.68rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gfr-ink-dim);
}

/* 3. NAV =================================================================== */

/* Paper on every page, including over the dark rooms. The building's signage
   is constant; the galleries differ. Also keeps the portfolio's Hard Rule 5
   intact — themes never touch chrome. */
.gfr-nav {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    padding: 0.9rem var(--gfr-gutter);
    background: var(--gfr-paper);
    border-bottom: 1px solid var(--gfr-rule);
}

/* The wordmark is type, not an image. GFR is initials only — never expanded,
   so there is no lockup to draw. */
.gfr-mark {
    display: inline-flex;
    align-items: baseline;
    gap: 0.55rem;
    font-family: var(--gfr-display);
    font-weight: 900;
    color: var(--gfr-ink);
    text-decoration: none;
    letter-spacing: -0.05em;
}
.gfr-mark__initials { font-size: 1.5rem; line-height: 1; }
.gfr-mark__word {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--gfr-ink-dim);
}
.gfr-mark:hover .gfr-mark__initials { color: var(--gfr-accent); }

.gfr-nav__links {
    display: flex;
    gap: 1.75rem;
    list-style: none;
    margin: 0;
    padding: 0;
}
.gfr-nav__links a {
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.78rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gfr-ink-dim);
    text-decoration: none;
    padding-bottom: 2px;
    border-bottom: 2px solid transparent;
}
.gfr-nav__links a:hover { color: var(--gfr-ink); }
.gfr-nav__links a[aria-current="page"] {
    color: var(--gfr-ink);
    border-bottom-color: var(--gfr-accent);
}

/* Three links fit on a phone without a hamburger. The old site shipped a
   toggle plus a slide-out panel plus the JS to drive them, for this. */
@media (max-width: 30rem) {
    .gfr-nav { gap: 0.75rem; padding-inline: 1rem; }
    .gfr-nav__links { gap: 1rem; }
    .gfr-nav__links a { font-size: 0.7rem; letter-spacing: 0.1em; }
    .gfr-mark__word { display: none; }
}

/* 4. PAPER SECTIONS ======================================================== */

.gfr-hero {
    padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(2.5rem, 6vw, 4rem);
}
.gfr-hero__eyebrow { margin: 0 0 1.4rem; }

.gfr-hero__title {
    font-size: clamp(2.9rem, 11vw, 7rem);
    font-weight: 900;
    letter-spacing: -0.055em;
    margin-bottom: 1.2rem;
}

.gfr-hero__lede {
    max-width: 46ch;
    font-size: clamp(1.08rem, 1rem + 0.4vw, 1.3rem);
    color: var(--gfr-ink-dim);
    margin: 0;
}

/* Museum wall text — the panel at the gallery entrance. Wider measure than a
   lede, set at reading size, no container chrome. */
.gfr-walltext {
    padding: clamp(2.5rem, 7vw, 5rem) 0;
}
.gfr-walltext__body { max-width: 62ch; }
.gfr-walltext__body p { margin: 0 0 1.15em; }
.gfr-walltext__body p:last-child { margin-bottom: 0; }

/* Lead paragraph gets optical emphasis without a different face. */
.gfr-walltext__body > p:first-of-type {
    font-size: 1.18em;
    line-height: 1.5;
    color: var(--gfr-ink);
}

.gfr-rule {
    border: 0;
    border-top: 1px solid var(--gfr-rule);
    margin: 0;
}

/* Definition rows — replaces the dossier intake table. No borders, no boxes;
   the label column just recedes. */
.gfr-facts {
    display: grid;
    grid-template-columns: minmax(8rem, 14rem) 1fr;
    gap: 0.55rem 2rem;
    margin: 0;
}
.gfr-facts dt {
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.68rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--gfr-ink-dim);
    padding-top: 0.4em;
}
.gfr-facts dd { margin: 0; }

@media (max-width: 40rem) {
    .gfr-facts { grid-template-columns: 1fr; gap: 0.15rem 0; }
    .gfr-facts dd { margin-bottom: 0.9rem; }
}

/* 5. ROOMS ================================================================= */

/* Full-bleed bands. Each one is flooded by its theme class, which supplies
   --pt-bg / --pt-ink / --pt-accent / --pt-display-font. This file only
   provides the shape; it never names a game color. */
.rooms { display: block; }

.room {
    position: relative;
    display: flex;
    align-items: flex-end;
    min-height: var(--gfr-room-h);
    padding: clamp(2.5rem, 6vw, 4.5rem) 0 clamp(2rem, 4vw, 3rem);
    background: var(--pt-bg, var(--gfr-ink));
    color: var(--pt-ink, var(--gfr-paper));
    /* `clip` rather than `hidden`: both clip the parallax overhang, but
       `hidden` makes this element a scroll container, which becomes the
       nearest scrollport for the motif's view() timeline — pinning its
       progress at 50% and killing the drift entirely. `clip` does not.
       The `hidden` line stays as the fallback for older engines, which get
       a static background anyway. */
    overflow: hidden;
    overflow: clip;
    isolation: isolate;
    text-decoration: none;
}

/* The threshold between rooms. A single paper hairline — the wall showing
   through the gap between galleries. */
.room + .room { border-top: 1px solid rgba(244, 240, 230, 0.14); }

/* Background motifs (star fields, conic sweeps) come from the theme as
   --pt-motif. Held on a pseudo-element so it sits under content and can be
   killed independently for reduced motion. */
.room::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--pt-motif, none);
    opacity: 0.85;
}

/* Vignette toward the lower edge so the placard and title always have a
   settled ground regardless of what the motif is doing. */
.room::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    /* Eased from 0.38 after the grounds were brightened — at the old strength
       the vignette was pulling every room back toward the near-black they had
       just been lifted out of. */
    background: linear-gradient(to bottom, transparent 40%, rgba(0, 0, 0, 0.26) 100%);
    pointer-events: none;
}

.room__inner {
    position: relative;
    width: 100%;
    max-width: var(--gfr-maxw);
    margin-inline: auto;
    padding-inline: var(--gfr-gutter);
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: end;
    gap: 2rem 3rem;
}

/* No max-width here. Capping the body capped the title with it, which forced
   "The World Dungeon" onto three lines and left a dead column down the middle
   of every room. The hook gets the reading measure instead; the title is free
   to run as wide as its grid column. */
.room__body { min-width: 0; }

/* The title carries the game's own display face — this is the whole point of
   the rooms treatment, and the reason the font budget is ~8 families and not
   two. */
.room__title {
    font-family: var(--pt-display-font, var(--gfr-display));
    font-size: clamp(2.4rem, 7.5vw, 5.6rem);
    line-height: 0.95;
    letter-spacing: -0.02em;
    color: var(--pt-ink, var(--gfr-paper));
    margin: 0 0 0.9rem;
    /* Titles are short enough to balance rather than run ragged. */
    text-wrap: balance;
}

/* Deliberately the chrome body face, not the game's. The title is the game
   speaking; everything else in the room is the institution describing it —
   the same voice as the placard. Keeps the font budget at 8 families total
   instead of 12, but the reason is editorial, not performance. */
.room__hook {
    font-family: var(--gfr-body);
    font-size: clamp(1.02rem, 0.98rem + 0.3vw, 1.22rem);
    line-height: 1.5;
    color: var(--pt-ink-dim, rgba(244, 240, 230, 0.78));
    margin: 0;
    max-width: 42ch;
}

/* Entry into the room. Sits on the game's accent so each room's call to
   action is that game's color. */
.room__enter {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    margin-top: 1.6rem;
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.78rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--pt-bg, var(--gfr-ink));
    /* --pt-cta falls back to the accent; themes whose accent can't carry
       label text at AA override it. See themes-games.css. */
    background: var(--pt-cta, var(--pt-accent, var(--gfr-paper)));
    padding: 0.75rem 1.3rem;
    text-decoration: none;
    border: 1px solid transparent;
    transition: transform 160ms ease, filter 160ms ease;
}
.room__enter:hover { transform: translateY(-2px); filter: brightness(1.12); }

.room__enter--ghost {
    background: transparent;
    color: var(--pt-cta, var(--pt-accent, var(--gfr-paper)));
    border-color: currentColor;
}
.room__enter--ghost:hover { filter: none; background: rgba(255, 255, 255, 0.07); }

.room__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* 6. WALL LABELS =========================================================== */

/* The connective device. Paper-colored placard carrying the corridor's
   typography into each dark room — the room is the artwork's world, the
   placard is the institution's voice. Also where honest project status goes:
   "none of these are finished" needs somewhere truthful to sit. */
.placard {
    background: var(--gfr-paper);
    color: var(--gfr-ink);
    padding: 0.95rem 1.15rem;
    max-width: 17rem;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
}

.placard__num {
    font-family: var(--gfr-display);
    font-weight: 800;
    font-size: 0.72rem;
    letter-spacing: 0.16em;
    color: var(--gfr-accent);
    display: block;
    margin-bottom: 0.35rem;
}

.placard__title {
    font-family: var(--gfr-display);
    font-weight: 800;
    font-size: 0.95rem;
    letter-spacing: -0.01em;
    margin: 0 0 0.5rem;
    color: var(--gfr-ink);
}

.placard__meta {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.15rem 0.7rem;
    margin: 0;
    font-size: 0.78rem;
    line-height: 1.4;
}
.placard__meta dt {
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.6rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gfr-ink-dim);
    padding-top: 0.25em;
}
.placard__meta dd { margin: 0; color: var(--gfr-ink); }

@media (max-width: 52rem) {
    /* Placard moves inline beneath the hook rather than floating. */
    .room__inner { grid-template-columns: 1fr; }
    .room { align-items: flex-start; }
    .placard { max-width: none; }
}

/* 6b. GAME PAGES =========================================================== */

/* The room you walked into, held for a whole page instead of 65vh. Same
   threshold gesture as the homepage: paper nav above, the game's world below.
   The theme class goes on this element, never on the nav or footer. */
.gamepage {
    position: relative;
    background: var(--pt-bg, var(--gfr-ink));
    color: var(--pt-ink, var(--gfr-paper));
    padding: clamp(2.5rem, 7vw, 5.5rem) 0 clamp(3.5rem, 8vw, 6rem);
    overflow: hidden;
    overflow: clip;   /* see .room — `hidden` would break the view() timeline */
    isolation: isolate;
}
.gamepage::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--pt-motif, none);
    /* Dimmer than the homepage rooms — this one sits behind body copy, and a
       star field competing with a paragraph is just noise. */
    opacity: 0.6;
}

.gamepage__inner {
    max-width: var(--gfr-maxw);
    margin-inline: auto;
    padding-inline: var(--gfr-gutter);
}

.gamepage__back {
    display: inline-block;
    margin-bottom: clamp(2rem, 5vw, 3.5rem);
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.72rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--pt-ink-dim, rgba(244, 240, 230, 0.7));
    text-decoration: none;
}
.gamepage__back:hover { color: var(--pt-cta, var(--pt-accent)); }

.gamepage__title {
    font-family: var(--pt-display-font, var(--gfr-display));
    font-size: clamp(2.6rem, 8vw, 6rem);
    line-height: 0.95;
    letter-spacing: -0.02em;
    text-wrap: balance;
    margin: 0 0 1.1rem;
}

.gamepage__hook {
    font-family: var(--gfr-body);
    font-size: clamp(1.15rem, 1.05rem + 0.5vw, 1.5rem);
    line-height: 1.45;
    color: var(--pt-ink-dim, rgba(244, 240, 230, 0.78));
    max-width: 44ch;
    margin: 0 0 clamp(2rem, 5vw, 3rem);
}

/* Reading measure. This is the institution's voice, so it stays Spectral —
   the title is the only place the game's own face appears. */
.gamepage__prose {
    max-width: 64ch;
    font-size: 1.04rem;
}
.gamepage__prose p { margin: 0 0 1.15em; }
.gamepage__prose p:last-child { margin-bottom: 0; }

.gamepage__prose h2 {
    font-size: clamp(1.3rem, 1.15rem + 0.6vw, 1.75rem);
    letter-spacing: -0.015em;
    margin: 2.4em 0 0.7em;
}
.gamepage__prose h2:first-child { margin-top: 0; }

.gamepage__prose h3 {
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    margin: 1.9em 0 0.5em;
    color: var(--pt-accent-2, var(--pt-accent));
}

.gamepage__prose em { color: var(--pt-ink, inherit); }
.gamepage__prose a { color: var(--pt-cta, var(--pt-accent)); }

.gamepage__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    /* Margin on both sides: the generated pages put actions last, the World
       Dungeon page puts them above the prose. */
    margin-top: clamp(2.25rem, 5vw, 3rem);
    margin-bottom: clamp(2.25rem, 5vw, 3rem);
}
.gamepage__actions:last-child { margin-bottom: 0; }

/* At desktop the placard moves alongside the copy instead of sitting below
   it — the reading measure only fills the left half, and a single column left
   the right half of every game page dead. Placed explicitly by row/column
   rather than by source order, because the World Dungeon page carries its
   placard higher up the document than the generated pages do. */
@media (min-width: 64rem) {
    .gamepage__inner {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 17rem;
        column-gap: clamp(2.5rem, 5vw, 4.5rem);
        align-items: start;
    }
    .gamepage__back { grid-column: 1 / -1; }
    .gamepage__title,
    .gamepage__hook,
    .gamepage__prose,
    .gamepage__actions { grid-column: 1; }

    .gamepage .placard {
        grid-column: 2;
        grid-row: 2 / span 4;
        margin: 0 !important;   /* beats the inline margin on the page markup */
        position: sticky;
        top: 5rem;
        max-width: none;
    }
}

/* Same single-weight bulking as the homepage titles. */
.theme-drifter .gamepage__title,
.theme-d20craps .gamepage__title {
    -webkit-text-stroke: 1.5px currentColor;
    paint-order: stroke fill;
}

/* 6c. PARALLAX ============================================================= */

/* The motif drifts slower than the page, so each room's back wall sits behind
   the text rather than travelling with it.
 *
 * Done with a scroll-driven animation rather than a scroll listener: no JS, no
 * per-frame work on the main thread, and nothing to throttle. Browsers without
 * `animation-timeline` simply keep the static background, which is what the
 * site shipped with — so this is additive, never a dependency.
 *
 * The layer is inset negatively to give the translation somewhere to go; the
 * room's `overflow: hidden` clips the overhang. Without that, the drift would
 * expose a hard edge at the top or bottom of every room.
 *
 * Nested inside prefers-reduced-motion: no-preference so it is never applied
 * for users who opted out, rather than applied and then overridden. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .room::before,
        .gamepage::before {
            inset: -18% 0;
            animation: gfr-drift linear both;
            animation-timeline: view();
            animation-range: cover;
            will-change: transform;
        }

        @keyframes gfr-drift {
            from { transform: translateY(-9%); }
            to   { transform: translateY(9%); }
        }
    }
}

/* 7. FOOTER ================================================================ */

.gfr-foot {
    padding: clamp(2.5rem, 6vw, 4rem) 0;
    border-top: 1px solid var(--gfr-rule);
    background: var(--gfr-paper);
    color: var(--gfr-ink-dim);
    font-size: 0.88rem;
}
.gfr-foot__row {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.75rem 2rem;
}
.gfr-foot a { color: var(--gfr-ink-dim); }
.gfr-foot a:hover { color: var(--gfr-accent); }

/* 8. FORMS + BUTTONS ======================================================= */

.gfr-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.78rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    background: var(--gfr-ink);
    color: var(--gfr-paper);
    border: 1px solid var(--gfr-ink);
    padding: 0.8rem 1.4rem;
    text-decoration: none;
    cursor: pointer;
    transition: background 160ms ease, color 160ms ease;
}
.gfr-btn:hover { background: var(--gfr-accent); border-color: var(--gfr-accent); }

.gfr-btn--ghost { background: transparent; color: var(--gfr-ink); }
.gfr-btn--ghost:hover { background: var(--gfr-ink); color: var(--gfr-paper); }

.gfr-field { display: block; margin-bottom: 1.4rem; }
.gfr-field > span {
    display: block;
    font-family: var(--gfr-display);
    font-weight: 700;
    font-size: 0.68rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--gfr-ink-dim);
    margin-bottom: 0.45rem;
}
.gfr-field input,
.gfr-field textarea,
.gfr-field select {
    width: 100%;
    font-family: var(--gfr-body);
    font-size: 1rem;
    color: var(--gfr-ink);
    background: var(--gfr-panel);
    border: 1px solid var(--gfr-rule-firm);
    padding: 0.7rem 0.85rem;
}
.gfr-field textarea { min-height: 9rem; resize: vertical; }

.gfr-field input:focus,
.gfr-field textarea:focus { border-color: var(--gfr-accent); }

/* Error state on the form's status line. Vermilion carries it, with a rule
   rather than a filled box — nothing on this site is a filled box. */
[role="status"].is-error {
    color: var(--gfr-accent);
    border-left: 3px solid var(--gfr-accent);
    padding-left: 0.85rem;
}

.gfr-form-success {
    border-left: 3px solid var(--gfr-accent);
    padding: 0.4rem 0 0.4rem 1.1rem;
    max-width: 44ch;
}
.gfr-form-success__head {
    font-family: var(--gfr-display);
    font-weight: 800;
    font-size: 1.4rem;
    letter-spacing: -0.02em;
    margin: 0 0 0.5rem;
}
.gfr-form-success p:last-child { margin: 0; color: var(--gfr-ink-dim); }

/* 9. REDUCED MOTION ======================================================== */

/* Hard Rule 3 — every animation guarded. The motifs are the main casualty:
   flat theme color instead of drifting gradients. */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }

    .room::before { background: none; }
    .room__enter:hover { transform: none; }
}
