/*
 * SPDX-FileCopyrightText: 2025 Juan Manuel Méndez Rey
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * Conquer design system: "Green phosphor over the mountains".
 *
 * A green phosphor monitor from a 1987 computing centre, set under the
 * mountains and pine forests of Middle-earth. This file is the ONLY place colours, fonts and
 * the spacing scale live; pages add layout, never colour.
 *
 * Contents
 *   1. Fonts            4. Typography and links      7. Fields, toggles
 *   2. Tokens           5. Header and nav            8. Cards, tables, notices
 *   3. Base and focus   6. Keycaps, chips, d-pad     9. Terminal, .crt, sheet
 *
 * v3 adds section 12 (the seeing stone, parchment scroll, ledge, compass,
 * plaque) and (v4/v5) web/arch/<race>-*@2x.webp (sculpted frames, baked by tools/arch/bake.py). It stays in this
 * file (about 1000 lines in all); split into artefact.css if it outgrows 1200.
 *
 * Rules: phosphor green is the one accent (interactive, focus, cursor,
 * progress). Gold is only for scores, ranks and "approved/founded"
 * highlights, never on buttons. --ok/--warn/--bad carry meaning only. Every text/background pair
 * used here is at least 4.5:1. Touch targets are at least 44px. Reduced
 * motion removes all transitions.
 */

/* 1. Fonts -------------------------------------------------------------- */
@font-face {
  font-family: "VT323"; font-display: swap;
  src: url(fonts/vt323-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "VT323"; font-display: swap;
  src: url(fonts/vt323-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IM Fell English SC"; font-display: swap;
  src: url(fonts/im-fell-english-sc-latin.woff2) format("woff2");
}

@font-face {
  font-family: "Noto Sans Runic"; font-display: swap;
  src: url(fonts/noto-sans-runic.woff2) format("woff2");   /* Runic block only, OFL */
}

/* 2. Tokens ------------------------------------------------------------- */
:root {
  color-scheme: dark;
  /* surfaces */
  --bg: #0b1210;            /* night over a pine forest */
  --bg-2: #121c18;          /* panels, cards, sheets */
  --screen: #050907;        /* the monitor glass */
  /* text */
  --ink: #e6e2d3;           /* parchment cream: body text */
  --ink-dim: #9aa89c;       /* mist: secondary text, hints */
  /* accent: soft P1-like phosphor green */
  --phos: #8fe3a0;          /* THE accent: fills, borders, cursor, focus */
  --phos-text: #8fe3a0;     /* phosphor used as TEXT; darker in parchment mode */
  --phos-dim: #4e9a63;      /* key undersides, hover borders */
  --phos-glow: rgba(143, 227, 160, .28);
  --on-phos: #0b1210;       /* text on a phosphor fill, in every mode */
  /* stone and gold */
  --stone: #7f8f93;         /* mountain stone at dusk: structure */
  --gold: #d9b35a;          /* scores, ranks, approved/founded: the lantern */
  /* semantic only, never decorative */
  --ok: #8fe3a0;            /* approval is the accent */
  --warn: #d9b35a;
  --bad: #d97a6a;           /* muted brick */
  /* lines */
  --line: rgba(127, 143, 147, .45);  /* bezels */
  --hair: rgba(230, 226, 211, .08);  /* table rows, inner glow */
  --zebra: rgba(230, 226, 211, .03);
  /* legacy names from v1, kept as aliases */
  --amber: var(--phos); --amber-text: var(--phos-text); --amber-dim: var(--phos-dim);
  --amber-glow: var(--phos-glow); --on-amber: var(--on-phos);
  /* type */
  --font-title: "IM Fell English SC", serif;                              /* titles and section names ONLY */
  --font-mono: "VT323", ui-monospace, monospace;                          /* keys, terminal, numbers, badges */
  --font-text: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;  /* prose */
  /* shape */
  --radius: 6px;
  --bezel: 2px;
  --keycap-depth: 3px;
  /* spacing scale: 4 8 12 16 24 32 */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;
  --ease: 120ms ease;
  --mountains: url(mountains.svg);
  --bgmap: url(bg/map-human.webp);
 
  --bevel-hi: #87939a; --bevel-lo: #273031;   /* plain frame bevel */
  --paper: #efe6cf; --paper-ink: #2b2415; --paper-bold: #14100a; --paper-cursor: #7a4a00;
  /* categorical series of the score chart (validated against --bg-2, light on dark) */
  --series-1: #3987e5; --series-2: #d95926; --series-3: #199e70; --series-4: #c98500; --series-5: #d55181;
}

/* Phosphor by race. Human is the default above (no attribute). Set
   data-race="elf|dwarf|orc" on <html>. Only the phosphor and its companions
   (surfaces, stone, gold, glow, mountains) change; structure, type, spacing
   and components never do. Parchment mode below wins over all of them. */
[data-race="elf"] {            /* moonlight on a night-blue glass */
  --bg: #0b1016; --bg-2: #121a22; --screen: #050709;
  --ink-dim: #9db0bb;
  --phos: #a9d3e6; --phos-text: #a9d3e6; --phos-dim: #5a90a8;
  --phos-glow: rgba(169, 211, 230, .28); --on-phos: #0b1016;
  --stone: #93a3ad; --gold: #e0c98a;
  --ok: #a9d3e6; --warn: #e0c98a;
  --line: rgba(147, 163, 173, .45);
  --mountains: url(mountains-elf.svg);
  --bgmap: url(bg/map-elf.webp);
  --paper: #f4f0e1; --paper-ink: #1f2a22; --paper-bold: #0c130e; --paper-cursor: #1f6b35;
 
  --bevel-hi: #8fa0ab; --bevel-lo: #2a353d;
}
[data-race="dwarf"] {          /* the console of Khazad-dum: forge amber on dark rock */
  --bg: #100e0b; --bg-2: #1a1611; --screen: #070605;
  --ink-dim: #aa9f90;
  --phos: #f2a93b; --phos-text: #f2a93b; --phos-dim: #b67a22;
  --phos-glow: rgba(242, 169, 59, .28); --on-phos: #100e0b;
  --stone: #8a7f73; --gold: #e3c56a;
  --ok: #f2a93b; --warn: #e3c56a;
  --line: rgba(138, 127, 115, .45);
  --mountains: url(mountains-dwarf.svg);
  --bgmap: url(bg/map-dwarf.webp);
  --paper: #e3d3a8; --paper-ink: #1d1a14; --paper-bold: #0a0805; --paper-cursor: #8a2a10;
 
  --bevel-hi: #94887a; --bevel-lo: #2b231b;
}
[data-race="orc"] {            /* rust and ember on ash black */
  --bg: #0e0b0b; --bg-2: #171212; --screen: #070404;
  --ink-dim: #a89c9a;
  --phos: #e07a5a; --phos-text: #e07a5a; --phos-dim: #9c4a30;
  --phos-glow: rgba(224, 122, 90, .2); --on-phos: #0e0b0b;   /* .2: keeps text on a pressed key at 4.5:1 */
  --stone: #7d7272; --gold: #c9a24a;
  --ok: #e07a5a; --warn: #c9a24a;
  --bad: #ff9d8a;                /* a paler salmon, so errors stay apart from the rust accent */
  --line: rgba(125, 114, 114, .45);
  --mountains: url(mountains-orc.svg);
  --bgmap: url(bg/map-orc.webp);
  --paper: #4a3424; --paper-ink: #ece3cb; --paper-bold: #ffffff; --paper-cursor: #ffb870;
 
  --bevel-hi: #6a5f5f; --bevel-lo: #1d1616;
}

/* Parchment: long-reading pages (guide, tutorial). Only colours change. */
[data-theme="parchment"] {
  color-scheme: light;
  --bg: #efe9d4;
  --bg-2: #e5ddc2;
  --screen: #050907;
  --ink: #232a22;
  --ink-dim: #4f5a4f;
  --phos-text: #1f6b35;     /* green as text needs to be darker on paper */
  --phos-dim: #2f7a45;
  --phos-glow: rgba(31, 107, 53, .22);
  --stone: #56676b;
  --gold: #7a5a00;
  --line: rgba(60, 78, 74, .5);
  --hair: rgba(35, 42, 34, .12);
  --zebra: rgba(35, 42, 34, .04);
  --ok: #1f6b35;
  --warn: #7a5a00;
  --bad: #a3392b;
}

/* 3. Base and focus ----------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 17px/1.6 var(--font-text);
}
::selection { background: var(--phos); color: var(--on-phos); }

/* Focus: always visible, 2px phosphor ring plus glow. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--phos);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--phos-glow);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}

/* 4. Typography and links ----------------------------------------------- */
h1, h2, h3, .title {
  font-family: var(--font-title); font-weight: 400; letter-spacing: .04em;
  color: var(--ink); line-height: 1.15; margin: 0 0 var(--s3); text-wrap: balance;
}
h1 { font-size: clamp(2rem, 7vw, 3rem); }
h2 { font-size: clamp(1.4rem, 4.5vw, 1.9rem); }
h3 { font-size: 1.25rem; }
/* The site name: phosphor green with a soft glow. */
.site-name {
  font-family: var(--font-title); letter-spacing: .04em; font-size: 1.6rem; line-height: 1;
  color: var(--phos-text); text-shadow: 0 0 8px var(--phos-glow); text-decoration: none;
}
.lede, .dim { color: var(--ink-dim); }
.mono { font-family: var(--font-mono); font-size: 1.3em; letter-spacing: .02em; }
a { color: var(--phos-text); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
code, kbd { font-family: var(--font-mono); font-size: 1.1em; }

/* 5. Header and nav ----------------------------------------------------- */
.site-header {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  padding: var(--s3) var(--s4); background-color: var(--bg-2);
  border-bottom: var(--bezel) solid var(--line);
}
.site-header .spacer { flex: 1; }
.nav { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: center; }
.select {
  font: 600 .9rem var(--font-text); color: var(--ink); background: var(--bg);
  border: var(--bezel) solid var(--line); border-radius: var(--radius);
  min-height: 44px; padding: 0 var(--s3); cursor: pointer; max-width: 100%;
}

/* 6. Keycaps, chips, d-pad ---------------------------------------------- */
/* A key: flat top, thick underside. Use on <button> or <a>. */
.key {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 44px; min-width: 44px; padding: 0 var(--s4);
  font: 600 1rem/1 var(--font-text); color: var(--ink); text-decoration: none; cursor: pointer;
  background: var(--bg-2); border: var(--bezel) solid var(--line);
  border-bottom: var(--keycap-depth) solid var(--stone); border-radius: var(--radius);
  transition: background var(--ease), transform var(--ease), border-color var(--ease);
  -webkit-tap-highlight-color: transparent; user-select: none;
}
.key:hover { background: var(--hair); border-color: var(--phos-dim); border-bottom-color: var(--phos-dim); text-decoration: none; }
.key:active, .key.pressed { transform: translateY(2px); border-bottom-width: 1px; }
.key .hint { font-family: var(--font-mono); font-size: 1.15em; font-weight: 400; margin-left: auto; padding-left: var(--s2); color: var(--ink-dim); }
.key-primary { background: var(--phos); color: var(--on-phos); border-color: var(--phos); border-bottom-color: var(--phos-dim); }
.key-primary:hover { background: var(--phos); filter: brightness(1.08); border-color: var(--phos); border-bottom-color: var(--phos-dim); }
.key-primary .hint { color: var(--on-phos); opacity: .8; }
.key:disabled.key-primary { background: var(--bg-2); color: var(--ink); border-color: var(--line); }
.key-small { padding: 0 var(--s3); font-size: .9rem; }
.key:disabled, .key[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; border-bottom-width: var(--bezel); transform: none; filter: none;
}
.key[aria-pressed="true"], .key.on { color: var(--phos-text); border-color: var(--phos); border-bottom-color: var(--phos-dim); background: var(--phos-glow); }

/* Chip bar: one scrolling row of small keys, snap points, faded edges. */
.chips {
  display: flex; gap: var(--s2); overflow-x: auto; padding: var(--s2) var(--s4);
  scroll-snap-type: x proximity; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--s4), #000 calc(100% - var(--s4)), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 var(--s4), #000 calc(100% - var(--s4)), transparent);
}
.chips::-webkit-scrollbar { display: none; }
.chips .key { flex: none; scroll-snap-align: start; }

/* D-pad: keycaps in a bezel, three columns. */
.dpad {
  display: inline-grid; align-self: flex-start; grid-template-columns: repeat(3, 56px); gap: var(--s2); padding: var(--s3);
  background: var(--bg-2); border: var(--bezel) solid var(--line); border-radius: var(--radius);
  box-shadow: inset 0 0 0 1px var(--hair);
}
.dpad .key { min-width: 56px; min-height: 56px; padding: 0; font: 1.6rem/1 var(--font-mono); }
.dpad .gap { visibility: hidden; }

/* Badge "where am I": mono, a small lit label. */
.badge {
  display: inline-flex; align-items: center; gap: var(--s2); padding: 2px var(--s3);
  font: 1.15rem/1.4 var(--font-mono); letter-spacing: .04em; color: var(--phos-text);
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
}
.badge::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--phos); box-shadow: 0 0 6px var(--phos-glow); }

/* 7. Fields and toggles ------------------------------------------------- */
.form { display: flex; flex-direction: column; gap: var(--s4); }
.field { display: flex; flex-direction: column; gap: var(--s1); }
.field label { font-weight: 600; }
.field .help { color: var(--ink-dim); font-size: .88rem; }
.input {
  font: inherit; color: var(--ink); background: var(--bg); width: 100%; min-height: 44px;
  border: var(--bezel) solid var(--line); border-radius: var(--radius); padding: var(--s2) var(--s3);
  box-shadow: inset 0 0 0 1px var(--hair); transition: border-color var(--ease), box-shadow var(--ease);
}
.input::placeholder { color: var(--ink-dim); opacity: .8; }
.input:focus-visible { border-color: var(--phos); outline: none; box-shadow: 0 0 0 3px var(--phos-glow); }
textarea.input { min-height: 5.5em; resize: vertical; }
.input.code { font-family: var(--font-mono); font-size: 1.4rem; letter-spacing: .14em; text-transform: uppercase; }
.input[aria-invalid="true"] { border-color: var(--bad); }
.error-text { color: var(--bad); font-weight: 600; margin: 0; }
.ok-text { color: var(--ok); font-weight: 600; margin: 0; }
/* Toggle: a key that shows ON/OFF; the state is phosphor when on. */
.toggle { justify-content: space-between; width: 100%; }
.toggle .state { font-family: var(--font-mono); font-size: 1.1em; font-weight: 400; color: var(--ink-dim); }
.toggle[aria-pressed="true"] .state { color: var(--phos-text); }
.toggle[aria-pressed="true"] .state::before { content: "\25CF  "; }

/* 8. Cards, tables, notices, toast, progress ---------------------------- */
.panel, .card {
  background: var(--bg-2); border: var(--bezel) solid var(--line); border-radius: var(--radius);
  box-shadow: inset 0 0 0 1px var(--hair); padding: var(--s4);
}
.apk-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s4); margin: var(--s3) 0; }
.apk-actions .key { text-decoration: none; }
.apk-sha { font-size: .9rem; }
.card { display: flex; flex-direction: column; gap: var(--s2); }
.card .who { font: 1.5rem/1.1 var(--font-mono); color: var(--phos-text); }
.gold { color: var(--gold); }
.card .meta { color: var(--ink-dim); font-size: .9rem; }
.card .actions { display: flex; gap: var(--s2); flex-wrap: wrap; margin-top: var(--s2); }

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; }
.table th, .table td { text-align: left; padding: var(--s2) var(--s3); border-bottom: 1px solid var(--hair); }
.table th { color: var(--ink-dim); border-bottom-color: var(--stone); font-weight: 500; font-size: .75rem; letter-spacing: .08em; text-transform: uppercase; }
.table tbody tr:nth-child(even) { background: var(--zebra); }
.table .num { color: var(--gold); text-align: right; font-family: var(--font-mono); font-size: 1.25rem; font-variant-numeric: tabular-nums; }

.notice {
  padding: var(--s3) var(--s4); background: var(--bg-2);
  border: 1px solid var(--hair); border-left: 4px solid var(--phos); border-radius: var(--radius);
}
.notice p { margin: 0; }
.notice.gold-note { border-left-color: var(--gold); }

/* Hint toast (for example "rotate your phone"). */
.toast {
  display: inline-flex; align-items: center; gap: var(--s3); max-width: 100%;
  padding: var(--s3) var(--s4); color: var(--ink); background: var(--bg-2);
  border: var(--bezel) solid var(--phos); border-radius: var(--radius);
  box-shadow: 0 0 18px var(--phos-glow), inset 0 0 0 1px var(--hair);
}
.toast .mono { color: var(--phos-text); font-size: 1.5rem; line-height: 1; }

.progress { height: 8px; background: var(--hair); border-radius: 4px; overflow: hidden; }
.progress > span { display: block; height: 100%; background: var(--phos); box-shadow: 0 0 8px var(--phos-glow); transition: width var(--ease); }

/* 9. Terminal, .crt, options sheet -------------------------------------- */
.terminal {
  position: relative; background: var(--screen); color: var(--phos);
  border: var(--bezel) solid var(--line); border-radius: var(--radius);
  box-shadow: inset 0 0 0 1px var(--hair), inset 0 0 40px rgba(0, 0, 0, .6);
  padding: var(--s3); overflow: hidden;
}
.terminal pre { margin: 0; font: 1.25rem/1.05 var(--font-mono); white-space: pre; overflow: hidden; }
.terminal .cursor { background: var(--phos); color: var(--screen); animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { background: transparent; color: inherit; } }
/* CRT effect: off by default. Add .crt to <body> (or any ancestor) to switch on. */
.crt .terminal::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, .55) 100%),
    repeating-linear-gradient(0deg, rgba(0, 0, 0, .04) 0 1px, transparent 1px 3px);
}
.crt .terminal pre { text-shadow: 0 0 6px var(--phos-glow); }

/* Options sheet: a bezel panel of toggles that slides up over the keys. */
.sheet {
  background: var(--bg-2); border: var(--bezel) solid var(--line); border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: 0 -8px 24px rgba(0, 0, 0, .45), inset 0 0 0 1px var(--hair);
  padding: var(--s4); display: flex; flex-direction: column; gap: var(--s2);
}
.sheet h3 { margin-bottom: var(--s1); }

/* 10. Mountains ---------------------------------------------------------- */
/* Three low-contrast ridges (bg-2 over bg, far ridge faintest). Colours are
   baked into mountains*.svg (one per race, see section 2), so this is dark mode only. */
.mountains { background: var(--bg) var(--mountains) no-repeat center bottom / cover; }
[data-theme="parchment"] .mountains { background-image: none; }
.site-header.mountains { border-bottom: var(--bezel) solid var(--line); }
.hero { padding: var(--s6) var(--s4) 96px; border-bottom: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0; }
/* Hero and footer show the whole silhouette (6:1), cropped at the sides on phones. */
.hero.mountains, .site-footer.mountains { background-size: max(100%, 720px) auto; }
.site-footer { height: clamp(140px, 17vw, 300px); border-top: 1px solid var(--line); }
/* Three-peak divider between sections. */
.divider { display: flex; align-items: center; gap: var(--s3); color: var(--stone); }
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.divider svg { width: 40px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }

/* 11. World-map texture at the edges ------------------------------------- */
/* The game's world map as terminal glyphs (bg/map-<race>.webp, made by
   tools/hero/build-bg.py), fixed behind everything at a few percent. It only
   shows in the margins: the page column, header, hero, footer, panels and
   terminals all paint their own opaque --bg/--bg-2, so no text ever sits on
   it and no contrast changes. A soft shadow feathers the column's edge. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: var(--bgmap) center / cover no-repeat; opacity: .2;
}
main { background: var(--bg); box-shadow: 0 0 36px 28px var(--bg); }
[data-theme="parchment"] body::before { display: none; }
@media (max-width: 600px) { body::before { display: none; } }   /* phones: never under running text */
@media (prefers-contrast: more) { body::before { display: none; } }


/* 12. The seeing stone, the parchment, the compass (v3) ----------------- */
/* Markup:
     <div class="gamescreen"><div class="gs [has-compass] [has-column]">   container: its width sets the frame width
       <a class="plaque">...</a>
       <div class="stone [parchment] [plain]">
         <span class="roll l"></span><span class="roll r"></span>
         <div class="terminal"><pre>80x24</pre></div>
       </div>
       <div class="ledge [column]"><div class="chips">keys</div></div>
       <div class="compass">...</div>
     </div></div>
   The terminal stays exactly as before; the stone only adds glass and frame. */
.gamescreen { container: gamescreen / inline-size; }
.gs { display: grid; gap: var(--s4); grid-template-columns: minmax(0, 1fr); align-items: start; }
.stone {
  --fw: 14px; --recess: 3px; --C: 6px; --L: 36px; --S: 18px; --K: 0px; --ov: 0px; --ovl: 0px;
  position: relative; isolation: isolate; min-width: 0; margin: var(--ov);
  padding: calc(var(--L) + var(--recess)) calc(var(--C) + var(--recess)) calc(var(--S) + var(--recess));
  filter: drop-shadow(0 8px 14px rgba(0, 0, 0, .55));
  transition: filter 240ms ease;
}
@container gamescreen (min-width: 700px) { .stone { --C: 44px; --L: 56px; --S: 36px; --K: 62px; --ov: 9px; --recess: 4px; } }
@container gamescreen (min-width: 1100px) { .stone { --C: 72px; --L: 88px; --S: 56px; --K: 100px; --ov: 14px; --recess: 5px; } }
/* v5: the frame is architecture, baked. Per race a set of lit raster pieces (web/arch/<race>-*@2x.webp, built by
   tools/arch/bake.py from the SVG shapes in tools/arch/src; the images are set per race in section 12c).
   lintel = centre emblem (616 units) + a tile that repeats in whole copies on each side + two end caps;
   sill   = emblem (560) + tile (112) + end caps; column = capital (64) + shaft tile (72, whole copies) + base (48).
   The right-hand pieces are separate images (mirrored before lighting) so the light stays top-left everywhere.
   Frieze motifs are never cut: the tile bands use background-repeat: round, so only whole tiles are shown. */
.arch { position: absolute; inset: 0; z-index: 2; pointer-events: none; transition: opacity 240ms ease; }
.arch i { position: absolute; display: block; background-repeat: no-repeat; }
.arch .lintel, .arch .sill { left: 0; right: 0; }
.arch .lintel { top: 0; height: var(--L); z-index: 1; background-position: 50% 0; background-size: calc(var(--L) * 616 / 88) 100%; }
.arch .sill { bottom: 0; height: var(--S); z-index: 1; background-position: 50% 0; background-size: calc(var(--S) * 560 / 56) 100%; }
.arch .lintel::before, .arch .lintel::after, .arch .sill::before, .arch .sill::after {
  content: ""; position: absolute; top: 0; bottom: 0; background-repeat: no-repeat, round no-repeat; background-size: auto 100%, auto 100%; }
.arch .lintel::before, .arch .lintel::after { width: calc(50% - var(--L) * 308 / 88 + 1px); }
.arch .sill::before, .arch .sill::after { width: calc(50% - var(--S) * 280 / 56 + 1px); }
.arch .lintel::before, .arch .sill::before { left: 0; background-position: 0 0, 0 0; }
.arch .lintel::after, .arch .sill::after { right: 0; background-position: 100% 0, 0 0; }
.arch .col { top: calc(var(--L) - var(--ovl)); bottom: calc(var(--S) - var(--ovl)); width: var(--C); z-index: 2;
  background-repeat: no-repeat; background-position: 0 0, 0 100%; background-size: 100% calc(var(--C) * 64 / 72), 100% calc(var(--C) * 48 / 72); }
.arch .col::before { content: ""; position: absolute; left: 0; right: 0; top: calc(var(--C) * 64 / 72); bottom: calc(var(--C) * 48 / 72);
  background-repeat: no-repeat round; background-size: 100% auto; background-position: 0 0; }
.arch .col.l { left: 0; } .arch .col.r { right: 0; }
.arch .cor { --kp: calc(var(--K) * .14); width: calc(var(--K) * 1.28); height: calc(var(--K) * 1.28); z-index: 3; background-size: 100% 100%; }
.arch .tl { left: calc(-1 * (var(--ov) + var(--kp))); top: calc(-1 * (var(--ov) + var(--kp))); }
.arch .tr { right: calc(-1 * (var(--ov) + var(--kp))); top: calc(-1 * (var(--ov) + var(--kp))); }
.arch .bl { left: calc(-1 * (var(--ov) + var(--kp))); bottom: calc(-1 * (var(--ov) + var(--kp))); }
.arch .br { right: calc(-1 * (var(--ov) + var(--kp))); bottom: calc(-1 * (var(--ov) + var(--kp))); }
/* Phones: no columns or corners, a thin lintel with the emblem, a thin sill, a plain stone strip at the sides. */
@container gamescreen (max-width: 699.98px) {
  .arch .cor { display: none; }
  .arch .col { background: linear-gradient(90deg, var(--st-d), var(--st-m) 50%, var(--st-d)) !important; }
  .arch .col::before { display: none; }
}
/* The old bezel slot stays for the parchment edges (elf, orc) and the plain frame. */
.stone::before {
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none; opacity: 0;
  border: var(--fw) solid transparent; transition: opacity 240ms ease;
}
/* Plain frame: a thin bevel, no ornament. */
.stone.plain { --fw: 7px; --recess: 3px; --ov: 0px; padding: calc(var(--fw) + var(--recess)); }
.stone.plain .arch { opacity: 0; visibility: hidden; }
.stone.plain::before {
  opacity: 1; border-style: solid; border-radius: 3px;
  border-color: var(--bevel-hi) var(--bevel-lo) var(--bevel-lo) var(--bevel-hi);
}
/* The glass. */
.stone .terminal {
  position: relative; z-index: 1; border: 0; border-radius: 3px; padding: 6px;
  color: var(--term-fg, var(--phos)); background-color: var(--term-bg, var(--screen));
  box-shadow:
    inset 0 0 24px color-mix(in srgb, var(--phos) 17%, transparent),
    0 0 0 1px color-mix(in srgb, var(--phos) 40%, transparent),
    0 0 0 var(--recess) var(--recess-c, rgba(0, 0, 0, .7));
  animation: breathe 8s ease-in-out infinite;
  transition: color 240ms ease, background-color 240ms ease, box-shadow 240ms ease;
}
@container gamescreen (min-width: 700px) { .stone .terminal { padding: 12px; } }
@container gamescreen (min-width: 1100px) { .stone .terminal { padding: 16px; } }
@keyframes breathe {
  0%, 100% { box-shadow: inset 0 0 24px color-mix(in srgb, var(--phos) 17%, transparent), 0 0 0 1px color-mix(in srgb, var(--phos) 40%, transparent), 0 0 0 var(--recess) var(--recess-c, rgba(0, 0, 0, .7)); }
  50%      { box-shadow: inset 0 0 24px color-mix(in srgb, var(--phos) 28%, transparent), 0 0 0 1px color-mix(in srgb, var(--phos) 40%, transparent), 0 0 0 var(--recess) var(--recess-c, rgba(0, 0, 0, .7)); }
}
/* Vignette and specular highlight sit above the text but never change its colour by more than 7%. */
.stone .terminal::before {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; border-radius: inherit;
  background:
    radial-gradient(ellipse 35% 16% at 50% 5%, rgba(255, 255, 255, .07), transparent),
    radial-gradient(ellipse farthest-corner at 50% 50%, transparent 66%, rgba(0, 0, 0, .55));
  transition: opacity 240ms ease;
}
.stone .terminal pre { margin: 0 auto; width: max-content; font-size: var(--fit, 1.15rem); line-height: 1.05; }
.stone .terminal b { color: var(--term-bold, inherit); }
.stone .terminal .cursor { background: var(--term-cursor, var(--phos)); color: var(--term-bg, var(--screen)); }
.stone.parchment .terminal::after { display: none; }

/* The parchment: the same wrapper when the game shows a report. */
.stone .roll { display: none; }
.stone::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: 0;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgba(120, 80, 20, .28) 100%),
    linear-gradient(180deg, #e6d9b6, var(--paper) 12%, var(--paper) 88%, #e2d3ac);
  clip-path: polygon(0.00% 3.0px,2.27% 2.0px,4.55% 1.5px,6.82% 0.0px,9.09% 1.0px,11.36% 1.0px,13.64% 3.0px,15.91% 0.0px,18.18% 4.0px,20.45% 0.0px,22.73% 1.0px,25.00% 1.5px,27.27% 1.5px,29.55% 1.0px,31.82% 4.0px,34.09% 1.0px,36.36% 1.5px,38.64% 0.0px,40.91% 1.0px,43.18% 4.0px,45.45% 0.0px,47.73% 1.5px,50.00% 0.0px,52.27% 4.0px,54.55% 0.0px,56.82% 2.0px,59.09% 5.0px,61.36% 1.5px,63.64% 2.0px,65.91% 1.0px,68.18% 5.0px,70.45% 2.0px,72.73% 1.0px,75.00% 4.0px,77.27% 3.0px,79.55% 1.0px,81.82% 1.0px,84.09% 0.0px,86.36% 4.0px,88.64% 6.0px,90.91% 1.5px,93.18% 3.0px,95.45% 6.0px,97.73% 6.0px,100.00% 3.0px,100.00% calc(100% - 5.0px),97.73% calc(100% - 4.0px),95.45% calc(100% - 0.0px),93.18% calc(100% - 6.0px),90.91% calc(100% - 1.0px),88.64% calc(100% - 2.0px),86.36% calc(100% - 3.0px),84.09% calc(100% - 6.0px),81.82% calc(100% - 0.0px),79.55% calc(100% - 3.0px),77.27% calc(100% - 1.5px),75.00% calc(100% - 5.0px),72.73% calc(100% - 6.0px),70.45% calc(100% - 5.0px),68.18% calc(100% - 0.0px),65.91% calc(100% - 1.0px),63.64% calc(100% - 6.0px),61.36% calc(100% - 5.0px),59.09% calc(100% - 1.0px),56.82% calc(100% - 1.0px),54.55% calc(100% - 6.0px),52.27% calc(100% - 6.0px),50.00% calc(100% - 3.0px),47.73% calc(100% - 3.0px),45.45% calc(100% - 3.0px),43.18% calc(100% - 1.0px),40.91% calc(100% - 0.0px),38.64% calc(100% - 1.5px),36.36% calc(100% - 6.0px),34.09% calc(100% - 2.0px),31.82% calc(100% - 3.0px),29.55% calc(100% - 2.0px),27.27% calc(100% - 1.5px),25.00% calc(100% - 1.0px),22.73% calc(100% - 1.0px),20.45% calc(100% - 5.0px),18.18% calc(100% - 6.0px),15.91% calc(100% - 3.0px),13.64% calc(100% - 6.0px),11.36% calc(100% - 5.0px),9.09% calc(100% - 1.0px),6.82% calc(100% - 4.0px),4.55% calc(100% - 2.0px),2.27% calc(100% - 4.0px),0.00% calc(100% - 5.0px));
  transition: opacity 240ms ease;
}
/* The paper keeps the stone's padding and margin: a different frame would change the terminal's
   size, and the game reads a resize as the "any key" a report waits for (the report closed at once). */
.stone.parchment { filter: drop-shadow(0 8px 12px rgba(0, 0, 0, .5)); }
.stone.parchment .arch { opacity: 0; visibility: hidden; }
.stone.parchment::before { opacity: 0; }
.stone.parchment::after { opacity: 1; }
.stone.parchment .terminal {
  --term-fg: var(--paper-ink); --term-bg: var(--paper); --term-bold: var(--paper-bold); --term-cursor: var(--paper-cursor);
  --phos: var(--paper-ink); animation: none;
  box-shadow: inset 0 0 0 1px rgba(90, 60, 15, .28), inset 0 0 26px rgba(120, 80, 20, .16), 0 0 0 var(--recess) transparent;
}
.stone.parchment .terminal::before { opacity: 0; }
.stone.parchment .terminal .cursor { color: var(--paper); }
@container gamescreen (min-width: 700px) {
  .stone .roll {
    display: block; position: absolute; z-index: 4; top: -8px; bottom: -8px; width: 34px; border-radius: 17px / 9px;
    opacity: 0; pointer-events: none; transition: opacity 240ms ease;
    background:
      linear-gradient(90deg, #6b5120 0, #b79a55 18%, #e9d8a4 38%, #cdb571 62%, #8d6f31 85%, #4d3813 100%);
    box-shadow: 0 0 0 1px rgba(40, 25, 5, .6), 0 6px 10px rgba(0, 0, 0, .4);
  }
  .stone .roll::before, .stone .roll::after {
    content: ""; position: absolute; left: 2px; right: 2px; height: 14px; border-radius: 50%;
    background: radial-gradient(ellipse at center, #3e2c0e 0 18%, #b99a52 20% 38%, #6e5424 40% 56%, #d3bb7c 58% 100%);
    box-shadow: 0 0 0 1px rgba(40, 25, 5, .6);
  }
  .stone .roll::before { top: -7px; } .stone .roll::after { bottom: -7px; }
  .stone .roll.l { left: -6px; } .stone .roll.r { right: -6px; }
  .stone.parchment .roll { opacity: 1; }
}

/* Rune ledge: the chip bar sits on a carved stone shelf. */
.ledge {
  position: relative; padding: var(--s2) 0 var(--s3);
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg-2) 80%, var(--stone)), var(--bg-2) 40%);
  border: 1px solid var(--line); border-radius: 4px;
  box-shadow: inset 0 1px 0 rgba(239, 230, 207, .12), 0 6px 10px -2px rgba(0, 0, 0, .65);
}
.ledge::after { content: ""; position: absolute; left: 6px; right: 6px; bottom: 5px; height: 2px; background: rgba(0, 0, 0, .45); border-radius: 1px; box-shadow: 0 1px 0 rgba(239, 230, 207, .08); pointer-events: none; }
.ledge .chips { padding-block: var(--s1); }
.ledge.column .chips { flex-direction: column; overflow: visible; -webkit-mask-image: none; mask-image: none; padding: var(--s2) var(--s3); }
.ledge.column .key { width: 100%; justify-content: space-between; }
@container gamescreen (min-width: 700px) {
  .gs.has-compass { grid-template-columns: minmax(0, 1fr) auto; }
  .gs.has-compass > .compass { justify-self: end; }
  .gs.has-compass > :where(:not(.ledge):not(.compass)) { grid-column: 1 / -1; }
}
@container gamescreen (min-width: 1100px) {
  .gs.has-column { grid-template-columns: minmax(0, 1fr) 232px; align-items: start; }
  .gs.has-column > .plaque { grid-column: 1 / -1; justify-self: start; }
  .gs.has-column > .stone { grid-column: 1; grid-row: 2 / span 2; }
  .gs.has-column > .ledge { grid-column: 2; grid-row: 2; }
  .gs.has-column > .compass { grid-column: 2; grid-row: 3; justify-self: center; }
}

/* Compass rose: the d-pad as eight points. The centre key is the needle. */
.compass {
  --c: 56px; position: relative; display: grid; grid-template-columns: repeat(3, var(--c)); gap: 14px; padding: 18px; justify-self: center;
  background: radial-gradient(circle at center, var(--bg-2) 0 60%, transparent 61%);
}
.compass > svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.compass .key {
  position: relative; z-index: 1; width: var(--c); height: var(--c); min-width: 44px; min-height: 44px; padding: 0;
  flex-direction: column; gap: 0; font: 1.7rem/.9 var(--font-mono);
}
.compass .key small { font: 1rem/1 var(--font-mono); color: var(--ink-dim); }
.compass .key.needle { border-radius: 50%; border-color: var(--phos); color: var(--phos-text); background: var(--bg); box-shadow: 0 0 12px var(--phos-glow), inset 0 0 0 1px var(--hair); }
.compass .key.diag { opacity: .96; }
.compass .rose-stone { fill: var(--stone); } .compass .rose-line { stroke: var(--stone); fill: none; }
.compass .needle-dot { fill: var(--phos); }

/* Plaque: a small brass plate for "where am I / back". */
.plaque {
  position: relative; display: inline-flex; align-items: center; gap: var(--s2); min-height: 32px; padding: 2px 26px; font: 1.3rem/1.2 var(--font-mono); letter-spacing: .05em;
  color: var(--gold); text-decoration: none; background: linear-gradient(180deg, color-mix(in srgb, var(--gold) 14%, var(--bg-2)), var(--bg-2));
  border: 1px solid var(--gold); border-radius: 3px; box-shadow: inset 0 1px 0 rgba(239, 230, 207, .18), 0 2px 4px rgba(0, 0, 0, .5); justify-self: start;
}
button.plaque, a.plaque { min-height: 44px; cursor: pointer; }
button.plaque:hover, a.plaque:hover { text-decoration: none; filter: brightness(1.15); }
.plaque::before, .plaque::after {
  content: ""; position: absolute; top: 50%; width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fff3c4, var(--gold) 45%, #5a4416); box-shadow: 0 0 0 1px rgba(0, 0, 0, .55);
}
.plaque::before { left: 8px; } .plaque::after { right: 8px; }

/* 12b. One artefact per race (v3.1) ---------------------------------------
   Same wrapper, same classes; [data-race] changes how the stone is dressed.
   human  palantir (above)      elf    Galadriel's mirror, a silver basin
   dwarf  the Doors of Durin    orc    the iron window */
.stone .runes, .stone .slit { display: none; }
.runes {
  font-family: "Noto Sans Runic", serif; letter-spacing: .32em; text-align: center; white-space: nowrap; overflow: hidden;
  color: var(--stone); text-shadow: none; transition: color 700ms ease, text-shadow 700ms ease;
}
.runes.lit, .stone:hover .runes, .stone:focus-within .runes { color: var(--phos); text-shadow: 0 0 6px var(--phos), 0 0 18px var(--phos-glow); }
.runes.flicker { animation: flicker 1.4s steps(1) forwards; }
@keyframes flicker { 0% { color: var(--phos); } 12% { color: var(--stone); } 24% { color: var(--phos); } 36% { color: var(--stone); } 48% { color: var(--phos); } 62% { color: var(--stone); } 100% { color: var(--stone); text-shadow: none; } }

/* Elf: Galadriel's mirror */
[data-race="elf"] .stone { --recess: 6px; --recess-c: #aab8c2; }
[data-race="elf"] .stone .terminal { border-radius: 14px; background-color: var(--term-bg, #060c14); overflow: hidden; }
[data-race="elf"] .stone .terminal::before {
  border-radius: inherit;
  background:
    radial-gradient(ellipse 70% 45% at 14% 0%, rgba(205, 228, 255, .10), transparent),
    radial-gradient(ellipse farthest-corner at 50% 50%, transparent 66%, rgba(0, 0, 0, .5));
}
[data-race="elf"] .stone .terminal::after {
  content: ""; position: absolute; z-index: 3; left: var(--rx, 50%); top: var(--ry, 50%); width: 20px; height: 20px; margin: -10px 0 0 -10px;
  border-radius: 50%; border: 2px solid rgba(205, 228, 255, .7); pointer-events: none; opacity: 0;
}
[data-race="elf"] .stone .terminal.rippling::after { animation: ripple 900ms ease-out; }
@keyframes ripple { from { transform: scale(1); opacity: .8; } to { transform: scale(22); opacity: 0; border-width: .3px; } }
[data-race="elf"] .stone.parchment { --fw: 18px; }
[data-race="elf"] .stone.parchment::before { opacity: 1; inset: 5px; border-width: 18px; border-image: url(paper-elf.svg) 64 / 18px round; }
[data-race="elf"] .stone::after { background: radial-gradient(ellipse at center, transparent 60%, rgba(70, 110, 90, .16)), linear-gradient(180deg, #ece7d6, var(--paper) 14%, var(--paper) 86%, #e9e3cf); }

/* Dwarf: the Doors of Durin */
[data-race="dwarf"] .stone .runes {
  display: block; position: absolute; z-index: 4; top: calc(var(--L) * .70); height: calc(var(--L) * .24);
  left: calc(var(--C) + var(--recess) + 8px); right: calc(var(--C) + var(--recess) + 8px);
  font-size: calc(var(--L) * .17); line-height: calc(var(--L) * .24); letter-spacing: .4em;
  background: linear-gradient(180deg, #0a0807, #17130f); border-radius: 1px; box-shadow: inset 0 2px 5px rgba(0, 0, 0, .9);
}
@container gamescreen (max-width: 699.98px) { [data-race="dwarf"] .stone .runes { display: none; } }
[data-race="dwarf"] .stone .terminal { border-radius: 0; }
[data-race="dwarf"] .stone.parchment { --fw: 22px; background: none; }
[data-race="dwarf"] .stone.parchment .runes { display: none; }
[data-race="dwarf"] .stone::after { background: radial-gradient(ellipse at center, transparent 40%, rgba(90, 40, 8, .5) 78%, rgba(20, 8, 0, .85) 100%), var(--paper); }
[data-race="dwarf"] .stone.parchment .terminal { box-shadow: inset 0 0 0 1px rgba(60, 35, 10, .35); }

/* Orc: the iron window */
[data-race="orc"] .stone .slit {
  display: block; position: absolute; z-index: 2; left: calc(var(--C) + 14%); right: calc(var(--C) + 14%); bottom: calc(var(--S) + 1px); height: 3px; border-radius: 2px; pointer-events: none;
  background: linear-gradient(90deg, transparent, #ff8a4a 25%, #ffb870 50%, #ff8a4a 75%, transparent); box-shadow: 0 0 10px 2px rgba(255, 110, 50, .55), 0 -6px 14px rgba(255, 90, 30, .25); opacity: .85;
  animation: ember 5s ease-in-out infinite;
}
@keyframes ember { 50% { opacity: .5; } }
[data-race="orc"] .stone.parchment .slit { display: none; }
@container gamescreen (min-width: 700px) {
  [data-race="orc"] .stone .terminal {
    padding-inline: 40px;
    background-image:
      linear-gradient(90deg, #2a2323 0 4px, #55484a 4px 5px, transparent 5px), linear-gradient(90deg, #2a2323 0 4px, #55484a 4px 5px, transparent 5px), linear-gradient(90deg, #2a2323 0 4px, #55484a 4px 5px, transparent 5px),
      linear-gradient(90deg, #2a2323 0 4px, #55484a 4px 5px, transparent 5px), linear-gradient(90deg, #2a2323 0 4px, #55484a 4px 5px, transparent 5px);
    background-size: 5px 100%; background-repeat: no-repeat;
    background-position: 8px 0, 20px 0, calc(100% - 8px) 0, calc(100% - 20px) 0, 0 0;
  }
  [data-race="orc"] .stone.parchment .terminal { background-image: none; padding-inline: 12px; }
}
[data-race="orc"] .stone.parchment { --fw: 20px; }
[data-race="orc"] .stone.parchment::before { opacity: 1; inset: 8px; border: 2px dashed #cdb98f; border-image: none; border-radius: 4px; }
[data-race="orc"] .stone::after { background: radial-gradient(ellipse at 30% 20%, rgba(255, 255, 255, .05), transparent 50%), radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, .35)), var(--paper); }

/* Human parchment: a wax seal at the corner */
:root:not([data-race]) .stone::after, [data-race="human"] .stone::after {
  background:
    radial-gradient(circle at calc(100% - 13px) calc(100% - 13px), var(--gold) 0 2px, var(--bad) 3px 6px, rgba(0, 0, 0, .35) 7px, transparent 8px),
    radial-gradient(ellipse at center, transparent 55%, rgba(120, 80, 20, .28) 100%),
    linear-gradient(180deg, #e6d9b6, var(--paper) 12%, var(--paper) 88%, #e2d3ac);
}


/* 12c. Sculpted frames (v4) -------------------------------------------------
   The sprite cuts per race; stone tones feed the phone strip. :root is the human set. */
:root { --st-d: #4f4b44; --st-m: #9a958a; }
[data-race="elf"] { --st-d: #46514c; --st-m: #8c9a94; }
[data-race="dwarf"] { --st-d: #2b2724; --st-m: #5a534b; --ovl: 0px; }
[data-race="orc"] { --st-d: #110f0e; --st-m: #2b2624; }
[data-race="elf"] .stone { --ovl: 8px; }
/* Per-race pieces. The human set also answers when no data-race is set. */
.arch .lintel { background-image: url("arch/human-lintel-emblem@2x.webp"); }
.arch .lintel::before { background-image: url("arch/human-lintel-cap-l@2x.webp"), url("arch/human-lintel-tile@2x.webp"); }
.arch .lintel::after { background-image: url("arch/human-lintel-cap-r@2x.webp"), url("arch/human-lintel-tile@2x.webp"); }
.arch .sill { background-image: url("arch/human-sill-emblem@2x.webp"); }
.arch .sill::before { background-image: url("arch/human-sill-cap-l@2x.webp"), url("arch/human-sill-tile@2x.webp"); }
.arch .sill::after { background-image: url("arch/human-sill-cap-r@2x.webp"), url("arch/human-sill-tile@2x.webp"); }
.arch .col.l { background-image: url("arch/human-col-cap-l@2x.webp"), url("arch/human-col-base-l@2x.webp"); }
.arch .col.l::before { background-image: url("arch/human-col-tile-l@2x.webp"); }
.arch .col.r { background-image: url("arch/human-col-cap-r@2x.webp"), url("arch/human-col-base-r@2x.webp"); }
.arch .col.r::before { background-image: url("arch/human-col-tile-r@2x.webp"); }
.arch .tl { background-image: url("arch/human-cor-l@2x.webp"); } .arch .tr { background-image: url("arch/human-cor-r@2x.webp"); }
.arch .bl { background-image: url("arch/human-cor-l@2x.webp"); } .arch .br { background-image: url("arch/human-cor-r@2x.webp"); }
[data-race="human"] .arch .lintel { background-image: url("arch/human-lintel-emblem@2x.webp"); }
[data-race="human"] .arch .lintel::before { background-image: url("arch/human-lintel-cap-l@2x.webp"), url("arch/human-lintel-tile@2x.webp"); }
[data-race="human"] .arch .lintel::after { background-image: url("arch/human-lintel-cap-r@2x.webp"), url("arch/human-lintel-tile@2x.webp"); }
[data-race="human"] .arch .sill { background-image: url("arch/human-sill-emblem@2x.webp"); }
[data-race="human"] .arch .sill::before { background-image: url("arch/human-sill-cap-l@2x.webp"), url("arch/human-sill-tile@2x.webp"); }
[data-race="human"] .arch .sill::after { background-image: url("arch/human-sill-cap-r@2x.webp"), url("arch/human-sill-tile@2x.webp"); }
[data-race="human"] .arch .col.l { background-image: url("arch/human-col-cap-l@2x.webp"), url("arch/human-col-base-l@2x.webp"); }
[data-race="human"] .arch .col.l::before { background-image: url("arch/human-col-tile-l@2x.webp"); }
[data-race="human"] .arch .col.r { background-image: url("arch/human-col-cap-r@2x.webp"), url("arch/human-col-base-r@2x.webp"); }
[data-race="human"] .arch .col.r::before { background-image: url("arch/human-col-tile-r@2x.webp"); }
[data-race="human"] .arch .tl { background-image: url("arch/human-cor-l@2x.webp"); } [data-race="human"] .arch .tr { background-image: url("arch/human-cor-r@2x.webp"); }
[data-race="human"] .arch .bl { background-image: url("arch/human-cor-l@2x.webp"); } [data-race="human"] .arch .br { background-image: url("arch/human-cor-r@2x.webp"); }
[data-race="elf"] .arch .lintel { background-image: url("arch/elf-lintel-emblem@2x.webp"); }
[data-race="elf"] .arch .lintel::before { background-image: url("arch/elf-lintel-cap-l@2x.webp"), url("arch/elf-lintel-tile@2x.webp"); }
[data-race="elf"] .arch .lintel::after { background-image: url("arch/elf-lintel-cap-r@2x.webp"), url("arch/elf-lintel-tile@2x.webp"); }
[data-race="elf"] .arch .sill { background-image: url("arch/elf-sill-emblem@2x.webp"); }
[data-race="elf"] .arch .sill::before { background-image: url("arch/elf-sill-cap-l@2x.webp"), url("arch/elf-sill-tile@2x.webp"); }
[data-race="elf"] .arch .sill::after { background-image: url("arch/elf-sill-cap-r@2x.webp"), url("arch/elf-sill-tile@2x.webp"); }
[data-race="elf"] .arch .col.l { background-image: url("arch/elf-col-cap-l@2x.webp"), url("arch/elf-col-base-l@2x.webp"); }
[data-race="elf"] .arch .col.l::before { background-image: url("arch/elf-col-tile-l@2x.webp"); }
[data-race="elf"] .arch .col.r { background-image: url("arch/elf-col-cap-r@2x.webp"), url("arch/elf-col-base-r@2x.webp"); }
[data-race="elf"] .arch .col.r::before { background-image: url("arch/elf-col-tile-r@2x.webp"); }
[data-race="elf"] .arch .tl { background-image: url("arch/elf-cor-l@2x.webp"); } [data-race="elf"] .arch .tr { background-image: url("arch/elf-cor-r@2x.webp"); }
[data-race="elf"] .arch .bl { background-image: url("arch/elf-cor-l@2x.webp"); } [data-race="elf"] .arch .br { background-image: url("arch/elf-cor-r@2x.webp"); }
[data-race="dwarf"] .arch .lintel { background-image: url("arch/dwarf-lintel-emblem@2x.webp"); }
[data-race="dwarf"] .arch .lintel::before { background-image: url("arch/dwarf-lintel-cap-l@2x.webp"), url("arch/dwarf-lintel-tile@2x.webp"); }
[data-race="dwarf"] .arch .lintel::after { background-image: url("arch/dwarf-lintel-cap-r@2x.webp"), url("arch/dwarf-lintel-tile@2x.webp"); }
[data-race="dwarf"] .arch .sill { background-image: url("arch/dwarf-sill-emblem@2x.webp"); }
[data-race="dwarf"] .arch .sill::before { background-image: url("arch/dwarf-sill-cap-l@2x.webp"), url("arch/dwarf-sill-tile@2x.webp"); }
[data-race="dwarf"] .arch .sill::after { background-image: url("arch/dwarf-sill-cap-r@2x.webp"), url("arch/dwarf-sill-tile@2x.webp"); }
[data-race="dwarf"] .arch .col.l { background-image: url("arch/dwarf-col-cap-l@2x.webp"), url("arch/dwarf-col-base-l@2x.webp"); }
[data-race="dwarf"] .arch .col.l::before { background-image: url("arch/dwarf-col-tile-l@2x.webp"); }
[data-race="dwarf"] .arch .col.r { background-image: url("arch/dwarf-col-cap-r@2x.webp"), url("arch/dwarf-col-base-r@2x.webp"); }
[data-race="dwarf"] .arch .col.r::before { background-image: url("arch/dwarf-col-tile-r@2x.webp"); }
[data-race="dwarf"] .arch .tl { background-image: url("arch/dwarf-cor-l@2x.webp"); } [data-race="dwarf"] .arch .tr { background-image: url("arch/dwarf-cor-r@2x.webp"); }
[data-race="dwarf"] .arch .bl { background-image: url("arch/dwarf-corb-l@2x.webp"); } [data-race="dwarf"] .arch .br { background-image: url("arch/dwarf-corb-r@2x.webp"); }
[data-race="orc"] .arch .lintel { background-image: url("arch/orc-lintel-emblem@2x.webp"); }
[data-race="orc"] .arch .lintel::before { background-image: url("arch/orc-lintel-cap-l@2x.webp"), url("arch/orc-lintel-tile@2x.webp"); }
[data-race="orc"] .arch .lintel::after { background-image: url("arch/orc-lintel-cap-r@2x.webp"), url("arch/orc-lintel-tile@2x.webp"); }
[data-race="orc"] .arch .sill { background-image: url("arch/orc-sill-emblem@2x.webp"); }
[data-race="orc"] .arch .sill::before { background-image: url("arch/orc-sill-cap-l@2x.webp"), url("arch/orc-sill-tile@2x.webp"); }
[data-race="orc"] .arch .sill::after { background-image: url("arch/orc-sill-cap-r@2x.webp"), url("arch/orc-sill-tile@2x.webp"); }
[data-race="orc"] .arch .col.l { background-image: url("arch/orc-col-cap-l@2x.webp"), url("arch/orc-col-base-l@2x.webp"); }
[data-race="orc"] .arch .col.l::before { background-image: url("arch/orc-col-tile-l@2x.webp"); }
[data-race="orc"] .arch .col.r { background-image: url("arch/orc-col-cap-r@2x.webp"), url("arch/orc-col-base-r@2x.webp"); }
[data-race="orc"] .arch .col.r::before { background-image: url("arch/orc-col-tile-r@2x.webp"); }
[data-race="orc"] .arch .tl { background-image: url("arch/orc-cor-l@2x.webp"); } [data-race="orc"] .arch .tr { background-image: url("arch/orc-cor-r@2x.webp"); }
[data-race="orc"] .arch .bl { background-image: url("arch/orc-cor-l@2x.webp"); } [data-race="orc"] .arch .br { background-image: url("arch/orc-cor-r@2x.webp"); }

/* The gate: the Doors of Durin as the login dialog (race-independent) */
.gate { max-width: 880px; width: 100%; }
.gate-stage { --C: clamp(20px, 7vw, 72px); --L: clamp(40px, 10vw, 88px); --S: clamp(24px, 5vw, 56px); --K: clamp(48px, 9vw, 100px); --ov: 0px; --ovl: 0px;
  position: relative; overflow: hidden; perspective: 1400px; background: #0d0b09; min-height: 440px; isolation: isolate; }
.gate-stage > .runes { display: block; position: absolute; z-index: 5; top: calc(var(--L) * .70); height: calc(var(--L) * .24); left: calc(var(--C) + 12px); right: calc(var(--C) + 12px);
  font-size: calc(var(--L) * .17); line-height: calc(var(--L) * .24); letter-spacing: .4em; background: linear-gradient(180deg, #0a0807, #17130f); box-shadow: inset 0 2px 5px rgba(0, 0, 0, .9); }
.gate .behind { position: relative; z-index: 0; padding: var(--L) var(--C) var(--S); }
.gate .behind .stone { --C: 0px; --L: 0px; --S: 0px; --ov: 0px; --recess: 4px; width: 100%; }
.gate .behind .stone .arch, .gate .behind .stone .runes { display: none; }
.gate .leaf { position: absolute; z-index: 2; top: var(--L); bottom: var(--S); width: calc((100% - 2 * var(--C)) / 2); transition: transform 600ms cubic-bezier(.5, 0, .2, 1); backface-visibility: hidden;
  background:
    repeating-linear-gradient(90deg, rgba(0, 0, 0, .22) 0 2px, transparent 2px 14px),
    linear-gradient(180deg, #6f6558, #51483e 45%, #3d362e);
  box-shadow: inset 0 0 0 4px rgba(0, 0, 0, .35), inset 0 0 0 6px rgba(239, 230, 207, .08), inset 0 0 40px rgba(0, 0, 0, .55); }
.gate .leaf::before { content: ""; position: absolute; inset: 16% 18%; border: 2px solid rgba(239, 230, 207, .12); border-radius: 50% 50% 0 0 / 30% 30% 0 0; box-shadow: inset 0 0 0 6px rgba(0, 0, 0, .12); }
.gate .leaf.l { left: var(--C); transform-origin: 0 50%; border-right: 2px solid #1c1812; }
.gate .leaf.r { right: var(--C); transform-origin: 100% 50%; border-left: 2px solid #1c1812; }
.gate.open .leaf.l { transform: rotateY(-105deg); } .gate.open .leaf.r { transform: rotateY(105deg); }
.gate .login { position: absolute; z-index: 4; left: 50%; top: calc(var(--L) + (100% - var(--L) - var(--S)) / 2); transform: translate(-50%, -50%); width: min(300px, 80%); background: var(--bg-2); border: 2px solid var(--stone); border-radius: 6px; padding: var(--s4); box-shadow: 0 8px 24px rgba(0, 0, 0, .7), inset 0 0 0 1px var(--hair); transition: opacity 300ms ease, visibility 0s linear 300ms; }
.gate .login .form { gap: var(--s3); }
.gate.open .login { opacity: 0; visibility: hidden; }
.gate-actions { margin-top: var(--s3); }
/* A wrong password: the doors shake */
.gate-stage.shake { animation: gate-shake 480ms cubic-bezier(.36, .07, .19, .97) both; }
@keyframes gate-shake { 10%, 90% { transform: translateX(-2px); } 20%, 80% { transform: translateX(4px); } 30%, 50%, 70% { transform: translateX(-7px); } 40%, 60% { transform: translateX(7px); } }
@media (prefers-reduced-motion: reduce) { .gate .leaf, .gate .login { transition: none; } .runes { transition: none; } .gate-stage.shake { animation: none; } }
[data-race="orc"] .stone .roll { display: none !important; }

/* 13. Page chrome shared by every page ------------------------------------
   Layout only (widths, spacing, the footer's content, the reading block);
   no page adds a colour of its own. */
.page { max-width: 880px; margin: 0 auto; padding: var(--s6) var(--s4) 64px; display: flex; flex-direction: column; gap: var(--s5); }
.page.narrow { max-width: 600px; }
.page.wide { max-width: 1180px; }
.page > h1, .page > .lede { margin: 0; }
.page > .lede { max-width: 62ch; }
.crumbs { color: var(--ink-dim); font-size: .9rem; margin: 0; }
.err, .page .error { color: var(--bad); font-weight: 600; margin: 0; }
.site-header .site-name { margin-right: var(--s2); }
.site-header .select { margin-left: 0; }
.site-footer { display: flex; flex-direction: column; align-items: center; gap: var(--s1); padding: var(--s4) var(--s4) 0; text-align: center; font-size: .85rem; color: var(--ink-dim); }
.site-footer p { margin: 0; max-width: 70ch; }
.site-footer .foot-links { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s1) var(--s4); }
/* A long-reading block: set data-theme="parchment" on it. Paper, dark ink. */
.reading { background: var(--bg); color: var(--ink); border: var(--bezel) solid var(--line); border-radius: var(--radius); padding: var(--s5) var(--s4); box-shadow: inset 0 0 0 1px var(--hair); }
.reading kbd { display: inline-block; min-width: 1.8em; text-align: center; padding: 0 .4em; background: var(--bg-2); border: 1px solid var(--line); border-bottom: 3px solid var(--stone); border-radius: 4px; white-space: nowrap; }
.reading pre { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--s3) var(--s4); overflow-x: auto; }
.reading hr { border: 0; border-top: 1px solid var(--line); }
@media (min-width: 700px) { .reading { padding: var(--s6); } }

/* 20. In the Android app (site.js: html.in-app) --------------------------- */
/* The pages lose the site's chrome: header, footer, language, Join, Design,
   links to other sites. On the game pages the header gives way to a compact
   bar (appbar.js, 44 px at most). */
.app-bar, .app-handle { display: none; }
.in-app .site-header, .in-app .site-footer, .in-app [data-lang-menu], .in-app #lang,
.in-app [data-server-link="signup.html"], .in-app a[href$="design.html"],
.in-app a[href^="http"]:not([data-server-link]), .in-app .join, .in-app .story,
.in-app .hero-inner > :not(.pitch) { display: none !important; }
.in-app .hero { padding-bottom: var(--s5); }
.in-app [data-donate], .in-app [data-donate-wrap] { display: none !important; }
.in-app .app-bar {
  display: flex; align-items: center; gap: var(--s2); position: relative; z-index: 25;
  flex: none; height: 44px; padding: 0 var(--s2); box-sizing: border-box;
  background-color: var(--bg-2); border-bottom: var(--bezel) solid var(--line);
}
.app-bar .spacer { flex: 1; }
.app-bar .key { min-height: 36px; white-space: nowrap; padding-inline: var(--s3); }
.app-menu { position: absolute; top: 100%; right: var(--s2); min-width: 190px; display: flex; flex-direction: column; gap: 1px; padding: var(--s1);
  background: var(--bg-2); border: var(--bezel) solid var(--line); border-radius: var(--radius); box-shadow: 0 8px 18px rgba(0, 0, 0, .6); }
.app-menu[hidden] { display: none; }
.app-item { min-height: 44px; padding: 0 var(--s3); text-align: left; font: 600 .95rem var(--font-text); color: var(--ink); background: transparent; border: 0; border-radius: var(--radius); cursor: pointer; }
.app-item:hover, .app-item:active { background: var(--hair); }
