/* ==========================================================================
   base.css — fonts, reset, typography, shell grid, header, footer, motion
   Depends on tokens.css. Loads before home.css / quote.css.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Self-hosted fonts
   Subsetted from Google Fonts and sliced with fontTools to the axes and
   weight ranges actually used, then re-encoded as woff2. No runtime request
   ever leaves the origin. See README "Fonts" for the regeneration recipe.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 700 800;
  font-display: swap;
  src: url("../fonts/bricolage-grotesque-latin.woff2") format("woff2");
  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: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 700 800;
  font-display: swap;
  src: url("../fonts/bricolage-grotesque-latin-ext.woff2") format("woff2");
  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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("../fonts/public-sans-latin.woff2") format("woff2");
  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: "Public Sans";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("../fonts/public-sans-latin-ext.woff2") format("woff2");
  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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-latin.woff2") format("woff2");
  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: "JetBrains Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
  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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Metric-matched fallbacks. Overrides computed from the real font tables
   against Arial (upm 2048 / asc 1854 / desc 434 / avg 904), so the swap from
   fallback to webfont does not move a single line. Keeps CLS at 0. */
@font-face {
  font-family: "Public Sans Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 119.73%;
  ascent-override: 79.34%;
  descent-override: 18.79%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Bricolage Fallback";
  src: local("Arial Bold"), local("Helvetica Bold"), local("Liberation Sans Bold");
  size-adjust: 105%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

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

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

body,
h1, h2, h3, h4,
p, figure, blockquote,
dl, dd, ul, ol {
  margin: 0;
}

ul[class],
ol[class] {
  padding: 0;
  list-style: none;
}

img,
picture,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button { background: none; border: 0; }

/* --------------------------------------------------------------------------
   3. Page canvas and base typography
   -------------------------------------------------------------------------- */

body {
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-body);
  font-weight: var(--weight-body);
  line-height: var(--lh-body);
  letter-spacing: var(--track-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  line-height: var(--lh-title);
  letter-spacing: var(--track-display);
  font-optical-sizing: auto;
  text-wrap: balance;
}

p { text-wrap: pretty; }

strong { font-weight: var(--weight-medium); }

/* --------------------------------------------------------------------------
   4. Links
   --signal is rare by design: links, focus, the active language, one
   underlined word in the hero. Never a large flat fill.
   -------------------------------------------------------------------------- */

a {
  color: var(--signal);
  text-decoration: underline;
  text-decoration-thickness: var(--rule-w);
  text-underline-offset: 0.18em;
  transition: text-decoration-thickness var(--dur-quick) var(--ease-out);
}

a:hover {
  text-decoration-thickness: var(--rule-w-thick);
}

/* --------------------------------------------------------------------------
   5. Focus
   One visible, high-contrast ring everywhere. 6.12:1 against --paper, well
   clear of the 3:1 that WCAG 1.4.11 asks of a focus indicator.
   -------------------------------------------------------------------------- */

:focus-visible {
  outline: var(--focus-w) solid var(--signal);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius);
}

:focus:not(:focus-visible) { outline: none; }

/* --------------------------------------------------------------------------
   6. Skip link
   -------------------------------------------------------------------------- */

.skip-link {
  position: absolute;
  top: var(--space-2xs);
  left: var(--space-2xs);
  z-index: 10;
  padding: var(--space-2xs) var(--space-sm);
  min-height: var(--target-min);
  display: inline-flex;
  align-items: center;
  background-color: var(--paper-raised);
  color: var(--signal);
  border: var(--rule-w) solid var(--signal);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  text-decoration: none;
  transform: translateY(calc(-100% - var(--space-lg)));
}

.skip-link:focus {
  transform: translateY(0);
}

/* --------------------------------------------------------------------------
   7. The shell and the annotation column
   Two columns above 900px: a narrow margin that holds nothing but mono
   labels, and a wide content column. Below 900px the margin collapses and
   each label reflows inline, above its own block.
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell-max);
  margin-inline: auto;
  padding-inline: var(--pad-inline);
}

.row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2xs) var(--gutter);
  align-items: start;
}

.row > .label { grid-column: 1; }
.row > .row__body { grid-column: 1; min-width: 0; }

@media (min-width: 900px) {
  .row {
    grid-template-columns: var(--margin-col) minmax(0, 1fr);
    gap: 0 var(--gutter);
  }
  .row > .label { grid-column: 1; }
  .row > .row__body { grid-column: 2; }
}

/* The label itself. Uppercase mono, 12px floor, --ink-soft at 5.00:1. */
.label {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: var(--weight-medium);
  line-height: var(--lh-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: var(--space-xs);
  text-wrap: balance;
}

@media (min-width: 900px) {
  .label {
    margin-bottom: 0;
    /* Optically align the cap-height of the label with the first text line
       of the block it annotates. */
    padding-top: 0.35em;
    position: sticky;
    top: var(--space-md);
  }
}

@media (prefers-reduced-motion: reduce) {
  .label { position: static; }
}

/* --------------------------------------------------------------------------
   8. Sections
   One rule, applied once. Every vertical gap between top-level sections
   comes from here and nowhere else — no per-section margin overrides, so
   there is no specificity contest over spacing.
   -------------------------------------------------------------------------- */

.section {
  padding-block: var(--space-section);
}

.section + .section {
  border-top: var(--rule-w) solid var(--rule);
}

/* --------------------------------------------------------------------------
   9. Header — sits outside the two-column grid, full shell width
   -------------------------------------------------------------------------- */

.masthead {
  border-bottom: var(--rule-w) solid var(--rule);
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  min-height: var(--target-min);
  padding-block: var(--space-xs);
}

.wordmark {
  /* Flexed to the full 44px target height rather than sitting at the 19px
     the type alone would give it. */
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}

.wordmark:hover { color: var(--signal); }

/* Language switch — mono, active state in --signal */
.langswitch {
  display: flex;
  align-items: center;
  gap: var(--space-3xs);
}

.langswitch__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--target-min);
  min-width: var(--target-min);
  padding-inline: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-soft);
  border-radius: var(--radius);
}

.langswitch__item:hover { color: var(--ink); }

.langswitch__item[aria-current="page"] {
  color: var(--signal);
  text-decoration: underline;
  text-decoration-thickness: var(--rule-w-thick);
  text-underline-offset: 0.3em;
}

.langswitch__sep {
  color: var(--rule-strong);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  user-select: none;
}

/* --------------------------------------------------------------------------
   10. Footer
   -------------------------------------------------------------------------- */

.colophon {
  border-top: var(--rule-w) solid var(--rule);
  padding-block: var(--space-lg);
}

.colophon__text {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: var(--weight-medium);
  line-height: var(--lh-mono);
  letter-spacing: var(--track-mono);
  color: var(--ink-soft);
  /* No measure here: this is one line of metadata, not prose. Constraining it
     to 62ch broke it across two lines mid-sentence on desktop. */
}

/* --------------------------------------------------------------------------
   11. Shared utilities
   -------------------------------------------------------------------------- */

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

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

/* An arrow that nudges on hover — the one piece of micro-motion allowed
   outside the load sequence, because it is a direct response to the pointer
   rather than an ambient effect. */
.arrow {
  display: inline-block;
  transition: transform var(--dur-quick) var(--ease-out);
}

a:hover .arrow { transform: translateX(0.2em); }

/* --------------------------------------------------------------------------
   12. Load sequence
   Content fades up; the margin labels follow 150ms later. That is the whole
   animation budget for the page. Nothing fires on scroll.

   The .js-enter class is set by an inline script in <head> so that the
   pre-animation state only ever applies when JS will actually run it —
   without JS the content is simply visible, never stuck at opacity 0.
   -------------------------------------------------------------------------- */

.js-enter .enter {
  opacity: 0;
  transform: translateY(var(--enter-shift));
}

.js-enter.is-loaded .enter {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dur-enter) var(--ease),
    transform var(--dur-enter) var(--ease);
}

.js-enter .label {
  opacity: 0;
}

.js-enter.is-loaded .label {
  opacity: 1;
  transition: opacity var(--dur-enter) var(--ease) var(--delay-labels);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .js-enter .enter,
  .js-enter.is-loaded .enter,
  .js-enter .label,
  .js-enter.is-loaded .label {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .arrow,
  a:hover .arrow { transition: none; transform: none; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
