/* ==========================================================================
   Base — reset, fonts, typographic primitives
   ========================================================================== */

/* Both faces are self-hosted and split by script. The latin-ext slice only
   downloads when a Turkish glyph actually appears on the page, so the
   English default pays nothing for it. */
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F,
                 U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin-ext.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Cyrillic. Only downloaded when the page is actually switched to Russian —
   the English default and the Turkish one pay nothing for it.

   Newsreader ships no Cyrillic at all, which is why the display stack falls
   through to Georgia there: an old-style serif with the same colour on the
   page, chosen on purpose rather than whatever the system would pick. */
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-cyrillic.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-cyrillic-ext.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F,
                 U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-latin-ext.woff2") format("woff2");
  font-weight: 200 800;
  font-display: swap;
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* IBM Plex Mono (SIL OFL) for labels, numerals and add-on prices. The system
   stack it replaces fell to Consolas on Windows — dotted zeros, a code-editor
   voice — and to a different face on every other OS. Regular only; Latin,
   Latin-Ext (Turkish İ Ş Ğ) and Cyrillic, ~36 KB in all. */
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibm-plex-mono-latin.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibm-plex-mono-latin-ext.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibm-plex-mono-cyrillic.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

*, *::before, *::after { box-sizing: border-box; }
/* [hidden] means hidden: a component's own display (flex, grid) overrode the
   browser's default and showed an empty "welcome back" line to everyone */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* the curtain and the ticket lock the scroll; without a reserved gutter
     the scrollbar's 15px came and went and the whole page shifted sideways
     (measured on Windows) */
  scrollbar-gutter: stable;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--c-cream);
  color: var(--c-ink);
  font-family: var(--f-body);
  font-size: var(--t-body);
  line-height: var(--lh-normal);
  font-feature-settings: "kern" 1, "liga" 1, "cv11" 1;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Headings are the serif voice. Optical sizing lets the variable face thin
   its own strokes as it grows, which is why a serif headline at 8rem does
   not turn into a slab. */
h1, h2, h3 {
  margin: 0;
  font-family: var(--f-display);
  font-weight: 370;            /* a hair lighter than regular: delicate, still crisp on Windows (12.10) */
  font-optical-sizing: auto;
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-display);
  text-wrap: balance;
}
p { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }

img, svg, canvas { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; transition: color var(--d-fast) var(--e-out); }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--c-accent); color: #fff; }

:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  padding: var(--s-3) var(--s-6);
  background: var(--c-ink); color: var(--c-cream);
  font-size: var(--t-small);
}
.skip-link:focus { left: var(--s-4); top: var(--s-4); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* --- Shared primitives ---------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}

/* The step marker. A rule before the text turns a floating caption into a
   piece of set type, and it is one pseudo-element. */
.label {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--f-mono);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-ink-faint);
}
.label--rule::before {
  content: "";
  width: 26px; height: 1px;
  background: var(--c-accent);
  flex: none;
}

.lead {
  font-size: var(--t-lead);
  line-height: 1.6;
  color: var(--c-ink-dim);
  max-width: var(--w-text);
}

/* Paper grain. Flat digital cream reads as "default background"; a whisper
   of noise reads as stock. Generated, not downloaded — one inline SVG
   turbulence, tiled by the browser. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  /* No blend mode. A fixed, full-viewport layer set to multiply has to be
     re-composited against everything beneath it on every scrolled pixel;
     on a page that also runs a WebGL scene that is the difference between
     a glide and a stutter. On a cream ground a plain grey noise at low
     opacity is all but indistinguishable from the multiplied version. */
  opacity: 0.22;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.22'/%3E%3C/svg%3E");
}
