/* ==========================================================================
   IO Patina — common theme
   The shared layer, version 1.0.0
   --------------------------------------------------------------------------
   Transcribed from the approved Claude Design document "IO Patina Common
   Theme" (archived at design-package/IO Patina Common Theme.dc.html). That
   document expressed every rule as an inline style attribute; production moves
   them into named classes so the markup stays semantic and a Content-Security-
   Policy can forbid inline styles outright.

   This file is property-agnostic. It carries no page, no route, no company
   fact and no site-specific selector, so iopatina.com, iopatina.org, a product
   landing page, a store and a docs site can all load the same bytes. What
   changes per property is one accent triple — see patina-accents.css.

   WHAT IT CONTAINS
     1. Tokens          palette, type, scale, spacing, the accent contract
     2. Base            reset, document defaults, focus, motion
     3. The four devices   taken from the mark: the bar, the spoke rule,
                           metal, the off-centre void
     4. The eight parts    header, buttons, record, numbered index, image
                           slot, dark band, status line, footer
     5. Utilities       spacing steps and a11y helpers

   WHAT IT DELIBERATELY DOES NOT CONTAIN
     - @font-face. Font URLs differ per host and per build pipeline, so they
       live in patina-fonts.css, whose paths are relative to itself. A site
       with its own font route (as iopatina.com has) declares its own instead.
       Either way, the three families named in --font-ui / --font-display /
       --font-mono must resolve, or the theme falls back to system faces.
     - Any component that needs JavaScript. Everything here is static CSS.

   HOW TO USE IT
     Plain HTML:  <link rel="stylesheet" href="theme/patina-fonts.css">
                  <link rel="stylesheet" href="theme/patina-theme.css">
                  <link rel="stylesheet" href="theme/patina-accents.css">
                  <html data-property="verdigris">
     Bundled:     @import '<path>/patina-theme.css' layer(patina);
                  Putting it in a cascade layer means the site's own rules win
                  without a specificity contest. See theme/README.md.

   Full guide, including the per-property accent table and the measured
   contrast for every value below: theme/README.md
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   --------------------------------------------------------------------------
   The palette is IO Patina Brand Asset Kit v3.0. Three of the kit's five
   values cannot be used as the kit states them — measured against Paper,
   Stone Gray is 2.81:1, Portal Gold 1.85:1 and Mist 1.10:1, all far below the
   4.5:1 that AA needs for text. Each is carried at its stated value where it
   passes and darkened, at the same hue, where it does not. Every ratio in the
   comments below is measured, not estimated.
   -------------------------------------------------------------------------- */

:root {
  /* --- Surfaces ---------------------------------------------------------
     Paper is the only light background in the system. There are no white
     cards: a card is Paper with a hairline, and the 1px grid gap is what
     separates it from its neighbour. */
  --paper: #f3f1ed; /* Paper — the page ground, and text on dark */
  --ink: #0f1114; /* Deep Ink — headlines, primary buttons, dark ground */
  /* The dark band sits one step off Deep Ink so a footer still reads as a
     surface against black browser chrome rather than merging into it. */
  --deep: #14171b;

  /* --- Accent -----------------------------------------------------------
     The one thing each property overrides. Defaults to Bronze, the accent of
     iopatina.com; patina-accents.css carries the other three. Portal Gold is
     a light colour and works only on a dark ground, so the light-surface
     accent is the same hue taken down until it can carry link text. */
  --accent: #7c5f3e; /* links and marks on light — 5.22:1 on Paper */
  --accent-deep: #5e4629; /* hover, pressed — 7.81:1 on Paper */
  --accent-light: #c8b092; /* Portal Gold — dark surfaces only, 9.08:1 on Ink */

  /* --- Neutrals ---------------------------------------------------------- */
  --graphite: #4a4c4e; /* body copy, everywhere — 7.65:1 on Paper */
  --ink-soft: #2c2f33; /* serif narrative body — 11.92:1 */
  /* Stone, darkened from the kit's #8f918f (2.81:1) to reach AA. Micro-labels
     and eyebrows only — never a paragraph. */
  --ash: #6b6d6b; /* 4.63:1 on Paper */
  --hairline: #e2ded6; /* decorative rules only — 1.19:1, never a border a
                          control depends on */
  /* Borders on inputs and controls, which WCAG 2.2 SC 1.4.11 holds to 3:1.
     The kit has no value that meets it, so this is derived rather than
     transcribed. */
  --hairline-strong: #8a8781; /* 3.18:1 on Paper */

  /* --- On dark surfaces -------------------------------------------------- */
  --dark-body: #c6c4bf; /* 10.32:1 on the dark band */
  --dark-label: #95948f; /* 5.92:1 */
  --dark-rule: #24272b;
  --dark-border: #2a2d31;
  /* The control border on dark. WCAG 2.2 SC 1.4.11 holds it to 3:1 against
     the surface behind it, and the value this theme inherited (#4a4f55) was
     measured at 2.18:1 on the band — it never met the rule it was written
     for. Raised until it does; see theme/check-contrast.mjs. */
  --dark-border-strong: #62676e; /* 3.15:1 on the band, 3.32:1 on Deep Ink */

  /* --- Status ------------------------------------------------------------ */
  --error: #8c3f30; /* 6.49:1 on Paper */

  /* --- Metal ------------------------------------------------------------
     Device 03. The stops are the published gradient of the mark itself,
     reused verbatim: the bar's vertical wash and the ring's radial wash. */
  --metal-lip: #e5c7ac;
  --metal-mid: #b99f87;
  --metal-base: #8a7663;
  --metal-wash-near: rgb(216 200 182 / 22%);
  --metal-wash-far: rgb(135 106 76 / 12%);

  /* --- Type -------------------------------------------------------------
     Three faces, three jobs, no overlap.
       display   page titles and statements. 30-62px, never below 26px.
       ui        section headings, navigation, buttons, body copy.
       mono      eyebrows, labels, and EVERY DIGIT on the site, so that
                 anything measured reads as measured. */
  --font-display: 'Source Serif 4', Georgia, 'Times New Roman', serif;
  --font-ui: Archivo, 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-mono: 'Martian Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  /* --- Grid and measure -------------------------------------------------
     12 columns at 1240 with a 32 gutter. Every section is a 3-column rail —
     bar, eyebrow, heading — beside a 9-column body. */
  --measure: 1240px;
  --gutter: clamp(20px, 5vw, 56px);
  --measure-text: 66ch; /* the cap on any line of running text */

  /* --- Spacing steps ----------------------------------------------------
     8 · 14 · 22 · 36 · 56 · 72 · 104. Nothing in between. */
  --space-1: 8px;
  --space-2: 14px;
  --space-3: 22px;
  --space-4: 36px;
  --space-5: 56px;
  --space-6: 72px;
  --space-7: 104px;

  /* --- Device constants -------------------------------------------------
     The bar is the mark's 12.99-unit stem scaled to a rule. The pitch is the
     fan's spoke pitch at the size a divider is drawn. */
  --rail-bar: 5px; /* Device 01 — the bar */
  --rail-gap: 20px;
  --spoke-pitch: 6px; /* Device 02 — one tick plus one gap */
  --spoke-duty: 3px; /* 50% duty, exactly as the fan is drawn */
  --spoke-height: 10px;
  --metal-edge: 13px; /* Device 03 — the bar wash as a page edge */
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */

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

/* Square corners and no shadows are load-bearing, not stylistic: the mark is
   drawn from hard geometry, and a rounded, floating card contradicts it. The
   reset is blanket rather than per-component so a future addition cannot
   quietly reintroduce either. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--graphite);
  font-family: var(--font-ui);
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
blockquote,
dl,
dd {
  margin: 0;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-weight: 600;
  text-wrap: balance;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

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

img,
video {
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

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

/* Numerals are Martian Mono wherever they carry information, and where they
   share a line with prose they are at least tabular, so columns of figures
   line up rather than shimmer. */
table,
.tabular {
  font-variant-numeric: tabular-nums;
}

/* Inline code, and anything else that should read as typed rather than set. */
code,
kbd,
samp,
pre {
  font-family: var(--font-mono);
  font-size: 0.86em;
}

::selection {
  background: #ecdfcb;
  color: var(--ink);
}

/* A visible focus ring on every interactive thing, in the accent, offset so
   it never sits on top of the glyphs it is marking. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* On dark surfaces the accent ring is too dark to see; Portal Gold is the
   on-dark pair for exactly this reason. */
.band-dark :focus-visible,
.on-dark :focus-visible {
  outline-color: var(--accent-light);
}

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

/* --------------------------------------------------------------------------
   3. The four devices
   --------------------------------------------------------------------------
   Each is derived from a measurement published on the brand page. They are
   structural, not decorative: they mark sections, divide content, and carry
   surfaces. Used together the page reads as the mark enlarged rather than as
   a page with a mark stuck on it.

   Budget per page: one metal surface, one Display cut of the mark, one dark
   band, and as many bars and spoke rules as the content has sections.
   Exceeding the budget is what turns an identity back into decoration.
   -------------------------------------------------------------------------- */

/* --- Device 01 · The bar ---------------------------------------------------
   The mark's 12.99-unit stem, scaled to a 5px rule, marking every section
   heading. It is the most recognisable element of the identity, and it now
   appears on every page, many times, at no cost.

   .split__rail carries it too: in this system a rail column IS a section
   marker, so a page gets the device by using the layout rather than by
   remembering a class at each call site. A block that must not have the bar
   simply is not a rail.

   Drawn as a pseudo-element rather than as border-left, for two reasons. A
   rail is a flex item, so a border stretches to the full height of the row —
   beside a five-item index that is a 400px stripe, not a mark. And a rail
   holding only an eyebrow would get a 14px dash instead of a bar. The
   pseudo-element takes the block's own height with a floor under it, so the
   bar is a bar at both extremes. */
.rail,
.split__rail {
  position: relative;
  padding-left: calc(var(--rail-bar) + var(--rail-gap));
}

.split__rail {
  align-self: flex-start;
}

.rail::before,
.split__rail::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: var(--rail-bar);
  height: 100%;
  min-height: 58px;
  background: var(--accent);
}

/* On a dark ground the bar is Portal Gold, like every other accent there. */
.rail--light::before,
.band-dark .rail::before,
.band-dark .split__rail::before {
  background: var(--accent-light);
}

/* --- Device 02 · The spoke rule --------------------------------------------
   Major dividers are drawn at the spoke pitch — ticks at 50% duty, thinning
   as they travel, exactly as the fan does. Minor dividers stay a plain
   hairline, so the drawn rule keeps its weight.

   currentColor rather than a fixed value: the rule then works on Paper and on
   Deep Ink from the same declaration, and inherits the accent of whichever
   property loaded it. */
.rule-spoke {
  height: var(--spoke-height);
  border: 0;
  margin: 0;
  color: var(--accent);
  background-image: repeating-linear-gradient(
    90deg,
    currentColor 0 var(--spoke-duty),
    transparent var(--spoke-duty) var(--spoke-pitch)
  );
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 55%, rgb(0 0 0 / 12%) 100%);
  mask-image: linear-gradient(90deg, #000 0%, #000 55%, rgb(0 0 0 / 12%) 100%);
}

.rule-spoke--light {
  color: var(--accent-light);
}

/* The minor divider. A plain hairline, and deliberately so. */
.rule-hair {
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--hairline);
}

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

/* --- Device 03 · Metal ----------------------------------------------------
   A surface, not a highlight. One metal surface per page, always behind a
   hero or a dark band, never behind body text that has to be read. */
.metal-edge {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--metal-edge);
  background: linear-gradient(
    180deg,
    var(--metal-lip) 0%,
    var(--metal-mid) 50%,
    var(--metal-base) 100%
  );
  pointer-events: none;
}

.metal-wash {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    120% 95% at 80% 14%,
    var(--metal-wash-near) 0%,
    var(--metal-wash-far) 40%,
    transparent 72%
  );
  pointer-events: none;
}

/* Struck from the other corner, for a second dark band on a long page. */
.metal-wash--left {
  background: radial-gradient(
    110% 95% at 22% 18%,
    rgb(200 176 146 / 16%) 0%,
    transparent 68%
  );
}

/* --- Device 04 · The off-centre void ---------------------------------------
   The mark's void sits 2.53 units left of centre, and the layout copies that
   asymmetry: the text column is wider than the record column, and the Display
   mark is bled off the right edge so the ring's void lands on the last grid
   column. The fill is capped at 18% so text crossing it keeps its measured
   contrast. */
.void-host {
  position: relative;
  overflow: hidden;
}

.void-mark {
  position: absolute;
  right: -4%;
  bottom: -8%;
  width: 40%;
  min-width: 220px;
  color: rgb(200 176 146 / 16%);
  pointer-events: none;
}

.void-mark > svg {
  width: 100%;
  height: auto;
}

/* The same asymmetry, as a layout. The text column is wider than the record
   column in the mark's own proportion, so a hero built from .split--hero is
   off-centre by construction rather than by eye. Source order is text then
   record; the rail keeps its width and the body takes the rest. */
.split--hero {
  gap: clamp(36px, 5vw, 72px);
  align-items: flex-end;
}

.split--hero > .split__body {
  flex: 1.35 1 460px;
}

/* The rail is align-self: flex-start so its bar matches its own height rather
   than the row's. In a hero it is the record column, which sits on the
   headline's baseline, so it takes the alignment back. */
.split--hero > .split__rail {
  align-self: flex-end;
  flex: 1 1 300px;
  max-width: 380px;
}

/* --------------------------------------------------------------------------
   4. The eight parts
   --------------------------------------------------------------------------
   If a page needs a ninth, the page is wrong before the part is.
   -------------------------------------------------------------------------- */

/* --- Layout shells --------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.section {
  padding: clamp(60px, 7.5vw, var(--space-7)) 0;
}

/* The 3-col rail beside the 9-col body — the house two-column pattern, and
   the reason the bar appears on every page. */
.split {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(28px, 5vw, 80px);
}

.split__rail {
  flex: 0 1 240px;
  min-width: 190px;
}

.split__body {
  flex: 1 1 520px;
  min-width: 280px;
}

/* --- Part · Type ----------------------------------------------------------- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ash);
}

.eyebrow--light {
  color: var(--accent-light);
}

.micro {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ash);
}

.micro--accent {
  color: var(--accent);
}

/* Display: page titles and statements only. Never below 26px — under that the
   serif stops being a voice and becomes a texture. */
.page-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(38px, 5.4vw, 62px);
  line-height: 1.04;
  letter-spacing: -0.018em;
  color: var(--ink);
  max-width: 22ch;
}

.statement {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(24px, 2.6vw, 30px);
  line-height: 1.22;
  color: var(--ink);
  max-width: 34ch;
  text-wrap: pretty;
}

/* Interface: section headings are Archivo, not the serif. This is the single
   most visible correction the theme makes — it puts the serif back in the one
   place it earns its keep and lets the interface face do the structural work. */
.section-title {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(22px, 2.2vw, 26px);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.section-title--light {
  color: var(--paper);
}

.body {
  font-size: 17px;
  line-height: 1.62;
  color: var(--graphite);
  max-width: var(--measure-text);
  text-wrap: pretty;
}

/* Self-sufficient rather than a modifier of .body: on a dark band the lead
   paragraph is often the only body text, and pairing two classes to get one
   paragraph is a trap. Slightly looser and slightly narrower than .body,
   because light-on-dark type needs more air to stay readable. */
.body--light {
  font-size: 17px;
  line-height: 1.68;
  color: var(--dark-body);
  max-width: 60ch;
  text-wrap: pretty;
}

/* --- Part · Header --------------------------------------------------------
   66px, hairline base, mark + 1px divider + wordmark. The current page is
   marked with a 2px accent underline and nothing else. */
.site-header {
  border-bottom: 1px solid var(--hairline);
  background: var(--paper);
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 66px;
}

.nav-link {
  font-size: 14px;
  color: var(--graphite);
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}

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

.nav-link[aria-current='page'] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/* --- Part · Buttons -------------------------------------------------------
   Square, 1px, no radius, no shadow. Four kinds and no more: solid on light,
   outline on light, solid on dark, outline on dark. A text link with a
   hairline underline covers everything else. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 48px;
  padding: 0 22px;
  border-radius: 0;
  box-shadow: none;
  white-space: nowrap;
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.02em;
  cursor: pointer;
}

.btn--primary {
  background: var(--ink);
  color: var(--paper);
  border: 0;
  transition: background 0.18s ease;
}

.btn--primary:hover {
  background: var(--accent);
  color: var(--paper);
}

.btn--primary:active {
  background: var(--accent-deep);
}

.btn--secondary {
  background: transparent;
  border: 1px solid var(--hairline-strong);
  color: var(--ink);
  transition: border-color 0.18s ease;
}

.btn--secondary:hover {
  border-color: var(--ink);
}

/* On a dark ground the solid button inverts: Paper carries the label, because
   Portal Gold on Deep Ink is an accent, not a surface. */
.btn--onLight {
  background: var(--paper);
  color: var(--ink);
  border: 0;
}

.btn--onDark {
  background: transparent;
  border: 1px solid var(--dark-border-strong);
  color: var(--paper);
  transition: border-color 0.18s ease;
}

.btn--onDark:hover {
  border-color: var(--accent-light);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* The third action: a text link with a hairline, used where a button would be
   too loud for a secondary route. */
.text-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--accent);
  border-bottom: 1px solid rgb(0 0 0 / 0%);
  border-bottom-color: color-mix(in srgb, currentColor 42%, transparent);
  padding-bottom: 2px;
}

.text-link:hover {
  color: var(--accent-deep);
  border-bottom-color: currentColor;
}

/* Derived from currentColor, the same way .text-link is, rather than from a
   literal. The value it replaced was Portal Gold written out — identical on
   bronze, and a gold underline under a teal link on every other property. */
.link-light {
  color: var(--accent-light);
  border-bottom: 1px solid rgb(0 0 0 / 0%);
  border-bottom-color: color-mix(in srgb, currentColor 40%, transparent);
  padding-bottom: 2px;
}

/* --- Part · Record --------------------------------------------------------
   The house pattern for facts. Mono uppercase key, hairline rows, value in
   the interface face. Anything that is a measurement, a date or a count sets
   its value in mono as well. */
.record {
  border-top: 1px solid var(--ink);
}

.record__row {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  padding: 11px 0;
  border-bottom: 1px solid var(--hairline);
}

.record__key {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ash);
  padding-top: 3px;
}

.record__value {
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  text-align: right;
}

/* A value that is a figure, a date or a version is mono, so specs read as
   specs rather than as prose that happens to contain digits. */
.record__value--data {
  font-family: var(--font-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.record--on-dark {
  border-top-color: rgb(243 241 237 / 20%);
}

.record--on-dark .record__row {
  border-bottom-color: rgb(243 241 237 / 14%);
}

.record--on-dark .record__key {
  color: rgb(243 241 237 / 55%);
}

.record--on-dark .record__value {
  color: var(--paper);
}

@media (max-width: 520px) {
  .record__row {
    flex-direction: column;
    gap: 4px;
  }

  .record__value {
    text-align: left;
  }
}

/* --- Part · Numbered index ------------------------------------------------
   Replaces feature cards. A mono accent number, a title, and a line of text
   on a hairline row. It scales to any count without stranding a cell, which
   a three-up card grid does not. */
.numbered {
  border-top: 1px solid var(--hairline);
}

.numbered__item {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  padding: 18px 0;
  border-bottom: 1px solid var(--hairline);
}

.numbered__num {
  flex: 0 0 44px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  padding-top: 4px;
}

.numbered__body {
  flex: 1 1 380px;
  min-width: 240px;
}

.numbered__title {
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
}

.numbered__text {
  margin-top: 6px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--graphite);
  max-width: 56ch;
  text-wrap: pretty;
}

/* --- Part · Card grid -----------------------------------------------------
   The 1px gap IS the rule: the container's hairline shows through it, so
   cards share edges instead of floating. A card is Paper with a hairline —
   there is no lifted white ground in this system.

   Column counts are explicit rather than auto-fit, because the gap colour
   also shows through any unfilled cell in the last row. */
.card-grid {
  display: grid;
  gap: 1px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
  grid-template-columns: 1fr;
}

.card {
  background: var(--paper);
  padding: 24px 26px;
}

/* Explicit counts, named for how many items the grid holds. Pick the one that
   divides the item count evenly at every breakpoint; a leftover cell renders
   as a block of gap colour, which is the bug auto-fit introduces. */
@media (min-width: 600px) {
  .card-grid--2,
  .card-grid--4,
  .card-grid--6 {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 860px) {
  .card-grid--3,
  .card-grid--6 {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1000px) {
  .card-grid--4 {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* --- Part · Dark band -----------------------------------------------------
   One per page. Portal Gold is the accent here and only here; the rail bar
   switches to it, and tags are outlines rather than fills. */
.band-dark {
  position: relative;
  overflow: hidden;
  background: var(--deep);
  color: var(--dark-body);
  padding: clamp(64px, 8vw, 124px) 0;
}

.band-dark--ink {
  background: var(--ink);
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.tag {
  border: 1px solid var(--hairline-strong);
  color: var(--graphite);
  padding: 6px 12px;
  font-family: var(--font-mono);
  font-size: 11px;
}

.tag--dark {
  border-color: rgb(243 241 237 / 30%);
  color: rgb(243 241 237 / 88%);
}

/* --- Part · Status line ---------------------------------------------------
   Plain sentences, no badges. A state the site is in is stated once, in mono,
   and never dressed up as a feature. */
.status-line {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  color: var(--ash);
}

/* --- Part · Footer --------------------------------------------------------
   The mark, a mono record line, and a plain row of routes. */
.site-footer {
  background: var(--ink);
  color: var(--dark-body);
  padding: clamp(32px, 4vw, 48px) 0;
}

.site-footer a:hover {
  color: var(--paper);
}

/* --------------------------------------------------------------------------
   5. Utilities
   -------------------------------------------------------------------------- */

.flex-between {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
}

.mt-1 {
  margin-top: var(--space-1);
}
.mt-2 {
  margin-top: var(--space-2);
}
.mt-3 {
  margin-top: var(--space-3);
}
.mt-4 {
  margin-top: var(--space-4);
}
.mt-5 {
  margin-top: var(--space-5);
}
.mt-6 {
  margin-top: var(--space-6);
}

/* Available to assistive technology, invisible on screen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 99;
  background: var(--ink);
  color: var(--paper);
  padding: 10px 16px;
  font-size: 13px;
}

.skip-link:focus {
  left: 12px;
}
