/* =============================================================================
   DESIGN TOKENS + BASE LAYER
   Visual identity: a Soviet chess training manual. Printed, institutional,
   dense. Flat ink on flat paper; separation comes from hairline rules, never
   from depth.

   HARD RULES, enforced by review, not by tooling:
     - border-radius is 0 everywhere. No exceptions.
     - No box-shadow anywhere.
     - No cards, no emoji, no gradients.
   Every colour lives in :root below. Nothing downstream may hard-code a hex
   value, and no colour may be defined only inside a media or [data-theme]
   block -- a colour that exists in one theme only is a bug waiting for the
   other theme.

   The dev server (tools/serve.js) sets COEP: require-corp for the engine's
   SharedArrayBuffer. The Google Fonts endpoints send permissive CORS/CORP, so
   this @import survives isolation; the fallback stacks below are real, not
   decorative, because a blocked font must still land on a condensed grotesque
   and a transitional serif.
   ============================================================================= */

@import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;600;700&family=Spectral:ital,wght@0,400;0,500;0,600;1,400&display=swap');

:root {
  /* --- palette: light (ink on paper) ------------------------------------- */
  --paper: #E2DBC9;
  --paper-2: #D8D0BB;
  --ink: #17130E;
  --ink-soft: #4A4335;
  --pencil: #7C7462;
  --rule: #B8AE96;
  --rule-faint: #CBC2AA;
  --red: #B22417;
  --red-wash: #E6CFC7;
  --sq-light: #EDE7D7;
  --sq-dark: #C6BCA4;

  /*
   * PLATE INK -- deliberately NOT themed, and defined once here.
   *
   * The board squares stay light in both themes (--sq-light/--sq-dark dim in
   * dark mode but remain mid-light), so the diagram reads as a printed plate
   * lying on the page rather than as part of it. Ink that inverted with the
   * page would land cream-on-cream: #E0D8C4 on #B9B09A is 1.7:1, invisible.
   * These four are the ink and the second colour of the press; they hold at
   * 5:1 or better on every square in both themes. Use them for anything drawn
   * ON a square -- glyphs, coordinates, marks, arrows. Everything around the
   * plate uses the themed tokens above.
   */
  --plate-ink: #17130E;
  /* Piece bodies. Deliberately NOT the paper tokens: the pieces must read as
     white and black on both square shades and in both themes, so they do not
     follow the surface they sit on. */
  --piece-white: #FBF9F4;
  --piece-black: #14110C;
  --piece-edge: #14110C;
  --plate-ink-soft: #4A4335;
  --plate-red: #B22417;
  --plate-red-wash: #E6CFC7;

  /* Grain is a print artefact: it darkens the sheet in light mode and lifts
     the emulsion in dark mode, so the blend mode is a themed token too. */
  --grain-blend: multiply;
  --grain-opacity: 0.055;

  color-scheme: light;

  /* --- type -------------------------------------------------------------- */
  --font-display: 'Oswald', 'Haettenschweiler', 'Arial Narrow', 'Roboto Condensed', system-ui, sans-serif;
  --font-body: 'Spectral', 'Iowan Old Style', 'Palatino Linotype', 'Book Antiqua', Georgia, serif;
  --font-mono: ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas, monospace;
  /* Chess glyphs U+2654-265F. Segoe UI Symbol carries them on Windows,
     Apple Symbols on macOS, DejaVu/Noto on Linux. */
  --font-chess: 'Segoe UI Symbol', 'Apple Symbols', 'Noto Sans Symbols 2', 'DejaVu Sans', sans-serif;

  --tracking-plate: 0.16em;
  --tracking-wide: 0.28em;
  --tracking-body: 0.005em;

  --step--2: 0.6875rem;
  --step--1: 0.8125rem;
  --step-0: 0.9375rem;
  --step-1: 1.0625rem;
  --step-2: 1.3125rem;
  --step-3: 1.6875rem;
  --step-4: 2.125rem;
  --step-5: 2.875rem;

  --lh-tight: 1.05;
  --lh-plate: 1.2;
  --lh-body: 1.55;

  /* --- measure + rhythm --------------------------------------------------- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;

  --rule-w: 1px;
  --rule-w-heavy: 2px;
  --measure: 64ch;
  --page-max: 1180px;
}

/* System preference. Guarded so an explicit light choice always wins. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --paper: #141109;
    --paper-2: #1D1911;
    --ink: #E0D8C4;
    --ink-soft: #B6AC94;
    --pencil: #8B8371;
    --rule: #3A3426;
    --rule-faint: #2A2519;
    --red: #D8452F;
    --red-wash: #3A1C15;
    --sq-light: #B9B09A;
    --sq-dark: #8C846F;

    --grain-blend: screen;
    --grain-opacity: 0.07;

    color-scheme: dark;
  }
}

/* Explicit choice. Must repeat the dark palette so the toggle wins in both
   directions, including on a light-preference machine. */
:root[data-theme='dark'] {
  --paper: #141109;
  --paper-2: #1D1911;
  --ink: #E0D8C4;
  --ink-soft: #B6AC94;
  --pencil: #8B8371;
  --rule: #3A3426;
  --rule-faint: #2A2519;
  --red: #D8452F;
  --red-wash: #3A1C15;
  --sq-light: #B9B09A;
  --sq-dark: #8C846F;

  --grain-blend: screen;
  --grain-opacity: 0.07;

  color-scheme: dark;
}

/* =============================================================================
   BASE
   ============================================================================= */

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

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

body {
  margin: 0;
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--lh-body);
  letter-spacing: var(--tracking-body);
  font-variant-numeric: lining-nums;
  -webkit-font-smoothing: antialiased;
}

/* Page grain. Owned by this file -- downstream screens must not claim
   body::after. feTurbulence, rasterised once by the UA and tiled. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: var(--grain-opacity);
  mix-blend-mode: var(--grain-blend);
  background-repeat: repeat;
  background-size: 180px 180px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
}

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-plate);
  line-height: var(--lh-tight);
  color: var(--ink);
}

h1 { font-size: var(--step-4); font-weight: 700; }
h2 { font-size: var(--step-2); }
h3 { font-size: var(--step-1); }
h4, h5, h6 { font-size: var(--step--1); color: var(--ink-soft); }

p { margin: 0 0 var(--sp-4); max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

hr {
  height: 0;
  margin: var(--sp-5) 0;
  border: 0;
  border-top: var(--rule-w) solid var(--rule);
}

a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--red);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

a:hover { color: var(--red); }

strong, b { font-weight: 600; }
em, i { font-style: italic; }

small { font-size: var(--step--1); color: var(--ink-soft); }

code, kbd, samp, pre {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--step--1);
}

th {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step--2);
  text-transform: uppercase;
  letter-spacing: var(--tracking-plate);
  color: var(--ink-soft);
  text-align: left;
}

th, td {
  padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
  border-bottom: var(--rule-w) solid var(--rule-faint);
  vertical-align: baseline;
}

button, input, select, textarea {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  background: transparent;
  border: var(--rule-w) solid var(--rule);
}

button { cursor: pointer; }

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

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

/* =============================================================================
   SHARED PRIMITIVES
   The vocabulary later screens conform to. Deliberately few: a stencilled
   label, a hairline, a flat block, a tabular numeral run.
   ============================================================================= */

.plate {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step--2);
  line-height: var(--lh-plate);
  text-transform: uppercase;
  letter-spacing: var(--tracking-plate);
  color: var(--ink-soft);
}

.plate--red { color: var(--red); }
.plate--ink { color: var(--ink); }
.plate--wide { letter-spacing: var(--tracking-wide); }
.plate--heavy { font-weight: 700; color: var(--ink); }

/* A label with the rule running off its right edge -- the manual's section
   marker. Uses a flat block, not a border, so the rule sits on the baseline. */
.plate-rule {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.plate-rule::after {
  content: '';
  flex: 1;
  height: var(--rule-w);
  background: var(--rule);
}

.hair {
  height: var(--rule-w);
  background: var(--rule);
}

.hair--faint { background: var(--rule-faint); }
.hair--ink { background: var(--ink); }

.slab {
  background: var(--paper-2);
  border: var(--rule-w) solid var(--rule);
  padding: var(--sp-4);
}

.slab--ink { border-color: var(--ink); }

.num {
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0;
}

.measure { max-width: var(--measure); }

.notation {
  font-family: var(--font-body);
  font-variant-numeric: tabular-nums lining-nums;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/*
 * HIDDEN MEANS HIDDEN.
 *
 * `[hidden]` is a user-agent rule of `display: none`, and any component rule
 * that sets its own `display` beats it on specificity. Three boxes on the play
 * screen do exactly that -- .promo, .explain and .callin are all `display:
 * grid` -- so a brand-new learner's first drill ("click e1") showed an empty
 * PROMOTE TO box, the "now write down why that works" textarea, and a red
 * banner saying they were wanted in the office. Every one of them was marked
 * hidden and none of them were.
 *
 * The unit tests could not see it: they assert the ATTRIBUTE, which was set
 * correctly the whole time. Only a computed style shows the fault.
 */
[hidden] { display: none !important; }
