/* ============================================================================
   base.css — tokens, reset, paper, typography.

   The whole design sits on one idea: this is a sheet of 1890s newsprint that
   has been sitting in a drawer. That means warm cream stock rather than white,
   ink that is brown-black rather than black, hairline rules doing the work that
   borders and shadows would do in a modern UI, and no pure #000 or #fff
   anywhere on the page.
   ========================================================================= */

:root {
  /* — stock — */
  --paper:        #e9e0ca;
  --paper-lit:    #f2ead7;  /* where the sheet catches light */
  --paper-2:      #ded2b5;
  --paper-3:      #cec0a0;
  --paper-edge:   #b8a988;

  /* — ink — */
  --ink:          #1b1710;
  --ink-2:        #3a3225;
  --ink-3:        #6a5c45;  /* worn impression */
  --ink-4:        #8d7f66;  /* barely there */

  /* — the second colour on the press — */
  --red:          #8c2a1c;
  --red-2:        #a83826;
  --red-wash:     rgba(140, 42, 28, 0.09);

  /* — the third colour, kept for verdicts only —
     A dark bottle green: the one hue that reads unambiguously as "passed"
     while still looking like ink soaked into cheap paper. */
  --green:        #2c5c39;
  --green-wash:   rgba(44, 92, 57, 0.10);

  /* — type — */
  --f-black:   'UnifrakturMaguntia', 'Playfair Display', serif;
  --f-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --f-body:    'EB Garamond', Georgia, 'Times New Roman', serif;
  --f-antique: 'IM Fell English', Georgia, serif;
  --f-type:    'Special Elite', 'Courier New', monospace;

  /* The committed map viewBox is 2000 x 780.6, so the plate is this wide for
     every unit of height. Capping the height and deriving the width from it
     keeps the whole map visible while stopping it eating the viewport. */
  --plate-ratio: 2.562;
  --plate-max-h: min(30vh, 360px);

  /* — measure & rhythm — */
  --measure: 68ch;
  --gap: clamp(0.75rem, 2vw, 1.5rem);
  --pad: clamp(1rem, 3vw, 2.25rem);
  --shell: min(1180px, 94vw);

  /* — rules — */
  --hair: 1px solid var(--ink-3);
  --rule-heavy: 3px double var(--ink-2);

  --radius: 2px; /* paper does not have rounded corners; this is just anti-aliasing */
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100svh;
  background-color: var(--paper);
  /* Two soft washes give the sheet an uneven tone, as if unevenly foxed. */
  background-image:
    radial-gradient(120% 80% at 12% 0%, var(--paper-lit) 0%, transparent 55%),
    radial-gradient(90% 70% at 88% 100%, rgba(176, 158, 122, 0.35) 0%, transparent 60%);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);
  line-height: 1.55;
  font-feature-settings: 'onum' 1, 'kern' 1, 'liga' 1;
  overflow-x: hidden;
}

/* ── the press's imperfections ─────────────────────────────────────────── */

/* Fibrous grain across the whole sheet. Multiply so it darkens rather than fogs. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 9000;
  pointer-events: none;
  opacity: 0.42;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  background-size: 300px 300px;
}

/* Edges of an old sheet are always darker than the middle. */
.vignette {
  position: fixed;
  inset: 0;
  z-index: 8999;
  pointer-events: none;
  background:
    radial-gradient(130% 110% at 50% 45%, transparent 52%, rgba(70, 55, 30, 0.30) 100%);
}

/* ── typography ────────────────────────────────────────────────────────── */

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 700;
  line-height: 1.1;
  text-wrap: balance;
}

p { margin: 0 0 0.9em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

/* Small caps with letterspacing is the workhorse label style of the period. */
.label,
.record__label,
.tally__label,
.hints__title,
.dispatch-head,
.mode-card__kicker {
  font-family: var(--f-antique);
  font-size: 0.78rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Rules: the period's structural device. Doubled for weight, never a box-shadow. */
.rule {
  height: 0;
  border: 0;
  border-top: var(--hair);
  margin: 1rem 0;
}

.rule--thin { border-top: 1px solid var(--ink-4); margin: 0.7rem 0; }

.rule--ornate {
  position: relative;
  border-top: var(--rule-heavy);
  margin: 1.1rem 0 1.4rem;
}

/* A printer's fleuron sitting on the rule, knocked out of the paper. */
.rule--ornate::after {
  content: '❦';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 0 0.55em;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 0.95rem;
  line-height: 1;
}

.orn { color: var(--ink-3); padding: 0 0.5em; }

/* Old-style figures suit running prose but sink numbers that carry meaning —
   a score or a count set in `onum` reads as decoration and half of it drops
   below the baseline. Anything the player has to actually read gets lining,
   tabular figures. */
.num,
.colophon,
.records__age,
.attempts__worth,
.masthead__corner,
.playbar__no,
.playbar__score,
.record__year,
.tally__value,
.mode-card__meta dd,
.scorelist__points,
.archive__date,
.broadside__span,
.award__value {
  font-variant-numeric: lining-nums tabular-nums;
  /* body sets font-feature-settings: 'onum', and that wins over
     font-variant-numeric, so the old-style figures have to be turned off in
     the same channel they were turned on. */
  font-feature-settings: 'kern' 1, 'liga' 1, 'lnum' 1, 'tnum' 1;
}

.mark { font-family: var(--f-display); color: var(--red); }

/* ── focus & selection ─────────────────────────────────────────────────── */

:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}

::selection {
  background: var(--red-wash);
  color: var(--ink);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10000;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--f-antique);
}
.skip-link:focus { left: 0; }

/* ── boot / failure ────────────────────────────────────────────────────── */

body.is-loading .screens { visibility: hidden; }

.boot {
  position: fixed;
  inset: 0;
  z-index: 9500;
  display: grid;
  place-content: center;
  gap: 0.5rem;
  padding: 2rem;
  text-align: center;
  background: var(--paper);
}
.boot[hidden] { display: none; }

.boot__text {
  font-family: var(--f-type);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-size: 0.85rem;
  color: var(--ink-3);
}

.boot--error { background: var(--paper); }
.boot__title { font-family: var(--f-black); font-size: 2rem; color: var(--red); }
.boot__body { font-family: var(--f-body); max-width: 40ch; }
.boot__detail {
  font-family: var(--f-type);
  font-size: 0.75rem;
  color: var(--ink-3);
  max-width: 60ch;
  word-break: break-word;
}

[hidden] { display: none !important; }
