/* ── the design language ─────────────────────────────────────────────────
   Palette, type and motion for the whole site. `surface.css` and
   `gold.css` are the two MATERIALS; this file is everything that isn't a
   material — the colours text is set in, the two typefaces, the scale
   they step through, and the timings everything moves on.

   The rule that keeps this file worth having: **a page's own <style> is
   layout only.** Grids, widths, what sits where. The moment a page writes
   a colour, a font stack or a duration of its own, the next page written
   from it inherits a near-miss of this one, and two pages that nearly
   agree look worse than two that differ on purpose.

   Tokens, not values. `var(--fs-body)` and not `15px`, because the scale
   steps up on a phone and only a page that composed from the token gets
   that for free.
   ──────────────────────────────────────────────────────────────────── */

/* ── the two voices ──────────────────────────────────────────────────────
   Two typefaces, one job each, and no third.

   TAGESSCHRIFT is the display voice, and the face the site is recognised
   by: the name of the thing, and anything you are meant to act on. Blunt
   slab-ish letters with uneven weight and a hand-cut edge to every stroke
   — a face that looks *printed*, and printed by something with ink on it,
   which is the register nine balls of wool are in. A clean grotesque
   "JOIN" on this page is a form control; this is a label somebody pressed.

   It is ONE WEIGHT, 400, and there is no other. Never ask for 600 or
   `bold` — nothing bolder exists in the file and the browser answers with
   a synthetic smear, which on a face this irregular is instantly visible.
   Emphasis here is size, tracking and colour. It is also strictly a
   display face: it has no small-size design and long text set in it is
   unreadable, so it stops at the wordmark and the buttons.

   THE TEXT VOICE IS THE SYSTEM'S, and deliberately. There used to be a
   webfont here for it, which was 32kB spent on the `<noscript>` line and
   the screen-reader labels — every word a sighted visitor sees is set in
   the display face. A text face gets chosen when there is text to set,
   against the real thing rather than in anticipation of it.

   The display face is subset to latin and served from this origin.
   `swap` on purpose: the fallbacks below are metrically nothing like it,
   so a reflow is certain either way, and text nobody can read is worse
   than text that moves once. Its filename carries a hash of its own
   bytes, which is what lets it be served with a year-long immutable cache
   while the rest of the site revalidates — so replacing it means a new
   filename in three places: the file, the `@font-face`, and the
   `<link rel="preload">` in the page. */
@font-face {
  font-family: "Tagesschrift";
  src: url("/fonts/tagesschrift-display.e75750b4.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ── colour ───────────────────────────────────────────────────────────
     Gold is the only colour on this page. Everything else is ink, and
     there are exactly two of them because there are exactly two grounds
     to write on.

     There is no token for the black on purpose: `--surf-deep` is the
     material's own base and the only one, because two near-blacks that
     nearly agree is how a seam appears where the page scrolls past the
     ground.

     `--ink` is for the dark ground. Not white — a light grey carrying a
     trace of the material's own violet, which is what stops it reading
     as a hole punched in the page. Warmth is the wrong move here even
     though the page is warm-lit: a cream ink is a second, weaker gold,
     and it competes with the one thing on the screen that is allowed to
     be warm. Cool ink, warm metal, and the button stays the only warm
     object.

     `--ink-on-gold` is for the gold ground, and it is the night the page
     sits in rather than a brown. Brown on gold is the same hue twice and
     goes muddy at small sizes; the blue is the page's own colour, so a
     label on the button reads as the ground showing through the metal.

     GOLD CARRIES THE NAME AND THE ACTION, and nothing else. It used to be
     the action alone; the name earns it because a wordmark is not
     decoration — it is the other thing on this page that is *the point*.
     Everything past those two is decoration, and spending gold there is
     what stops the button being the brightest thing on the screen, which
     is the only reason it works.

     `--gold` is the flat token for a hairline or a glow. A gold OBJECT
     wears `.gold`; gold TYPE wears `.gold-ink` and gets the material
     painted through the letters, which is the form the name takes.

     BOTH INKS ABOVE ARE NOW FALLBACKS, NOT THE FINISHED THING.
     What you actually see on either ground is a material — `.gold-ink` on
     the dark, `.surface-ink` on the metal. These two solids are what
     shows when a clipped background cannot: forced-colours mode, and any
     `.gold` object whose label is not wrapped. They still have to be
     right; they are just no longer what the page looks like. */
  --ink:         #dcd8e6;
  --ink-dim:     #918ea0;
  --ink-on-gold: #10173a;
  --gold:        #e9c46a;

  /* ── type ─────────────────────────────────────────────────────────────
     TWO sizes, because the page uses two. Every size a scale offers is a
     size two pages can disagree over, so the rule here is that a step gets
     added when something needs it and not in anticipation — a token with no
     consumer is a decision nobody has actually made yet.

     Sizes are `clamp()` on viewport width rather than a media query, so
     the display sizes shrink continuously between a narrow phone and a
     wide screen instead of stepping once. The floor of each clamp is the
     phone value — this site is designed at phone width first. */
  --font-display: "Tagesschrift", Rockwell, "Bookman Old Style",
                  Georgia, serif;
  --font-text:    ui-sans-serif, system-ui, "Helvetica Neue", Arial,
                  sans-serif;

  /* The loud size, and BOTH loud things wear it: the name of the site and
     the primary action. They are the two pieces of type on this page that
     are the point, so they are set at one size rather than in a hierarchy
     — a wordmark above a button in a smaller size says the button is a
     footnote to it, and it is not. */
  --fs-name: clamp(1.75rem, 8.5vw, 2.6rem);
  --fs-body: 1rem;

  /* One tracking value, because everything set in the display face is set
     at the loud size, where its letters already sit apart and want pulling
     slightly IN. There is no caps token: nothing on this site is set in
     caps. If something ever is, it needs its own POSITIVE value — blunt
     capital stems close up into a block at this one. */
  --track-tight: -.01em;

  /* ── motion ───────────────────────────────────────────────────────────
     One duration for a control answering a tap, one for something
     arriving, and one easing curve for both. The curve overshoots
     nothing — the page has weight, and nothing here bounces. */
  --speed:      .22s;
  --speed-slow: .34s;
  --ease:       cubic-bezier(.2, .8, .3, 1);

  /* Pills for things you press. Nothing on this site is a sharp corner. */
  --r-pill: 999px;
}

/* ── the base voice ─────────────────────────────────────────────────────
   Set once here so a page never has to. */

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

body {
  margin: 0;
  color: var(--ink);
  font: 400 var(--fs-body)/1.6 var(--font-text);
  /* The material's own base, from surface.css. What you look at is a
     `.surface` painted over this; the flat colour is what shows for the
     moment before the texture arrives, and behind an overscroll. */
  background: var(--surf-deep);
  -webkit-tap-highlight-color: transparent;
}

/* The name of the site, wherever it appears. Set in the display face,
   lowercase, and tracked slightly tight — at this size the letters
   already sit apart. `text-wrap: balance` because it is two words with a
   hyphen in the middle and a phone will break it. No weight declared
   anywhere in this block or the next: the display face ships one, and
   asking for another gets a synthetic one. */
.wordmark {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-name);
  line-height: 1.05;
  letter-spacing: var(--track-tight);
  text-wrap: balance;
}

/* ── the thing you act on ────────────────────────────────────────────────
   `.act` is the SHAPE of a primary action; `.gold` is the material it is
   made of. Two classes because the shape is reusable and the metal is
   expensive — a secondary control can take `.act` and wear something
   quieter.

   **It carries no type, because nothing here has a label.** An action on
   this page is a blank gold object you press. The reasoning is at `.join`
   in the page: a word tells you what will happen, and not being told is
   the point. So this is shape, target size and the press — the smallest
   set that makes an element read as pressable at all.

   No colour either. Each material owns the ink that is legible on it, so
   a colour written here would have to be right on every material there
   will ever be. */
.act {
  display: block;
  min-height: 52px;          /* a thumb, not a cursor */
  border: 0;
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: transform var(--speed) var(--ease);
}
.act:active { transform: translateY(1px); }

/* Ink, not gold: the outline sits ON the gold, and a gold ring on a gold
   button is invisible. */
.act:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

/* ── arriving ────────────────────────────────────────────────────────────
   Black, then the site fades up over half a second.

   The point is not a flourish, it is that there is no correct FIRST frame
   to show. Everything here arrives late and out of order: two typefaces
   swap in over their fallbacks, and three canvas textures are generated,
   encoded and handed over as blob URLs. Painted as they land, the page
   assembles itself in front of you — fallback type reflowing into
   Tagesschrift, a flat near-black ground turning to marble. A curtain
   costs half a second and replaces all of it with one arrival.

   A CURTAIN, not `opacity` on `body`. An opacity below 1 makes body a
   containing block for fixed descendants, and `.surface--ground` is fixed
   `inset: 0` — the ground would size itself to body's padded box instead
   of the viewport. Fading a separate layer out touches no layout at all.

   THE ONE WAY THIS FAILS IS STAYING BLACK, so it is guarded twice: the
   page reveals on a timeout whatever happened to the textures, and the
   `<noscript>` block in the page removes the curtain outright. Every
   callback it waits on fires on its failure paths too.

   `pointer-events: none` from the start: the curtain is over the whole
   page for half a second and a tap landing on it is a tap the grid did
   not get. Removed from the DOM on `transitionend` rather than left at
   zero opacity, because a full-viewport composited layer is not free. */
#boot {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: #000;
  pointer-events: none;
  transition: opacity .5s linear;
}
html[data-ready="true"] #boot { opacity: 0; }

/* ── for a screen reader only ───────────────────────────────────────────
   This site is nearly all texture, so the wording that is deliberately
   absent from the screen lives here instead — the name of each yarn, and
   what the group of them is for. */
.sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Everything that moves on this site moves because of a `transition` or
   an `animation`, so switching both off here is most of the job. The one
   thing it cannot reach is a frame loop in script, which has to check
   this query itself. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation: none !important;
  }
}
