/* ===========================================================================
   airframehub — "Technical Archive" design system
   ---------------------------------------------------------------------------
   Tokens are the ONLY source of colour. Never write a hex value in a component
   rule; add a token instead. Light and dark are both first-class.

   Type: self-hosted woff2 is a Phase-1 task (Space Grotesk / Inter / IBM Plex
   Mono per the plan). Until then this uses a deliberately chosen system stack —
   the mono role in particular renders SF Mono on macOS, which is the right
   register for registrations and serials. No webfont is linked, so nothing can
   silently fall back.
   =========================================================================== */

:root {
  --paper:#F5F1E8; --surface:#FFFEFB; --sunk:#EBE5D8;
  --ink:#000000; --ink-mid:#000000; --ink-faint:#000000;
  --muted:#556270;                 /* NOT for text — placeholders and de-emphasised marks only */
  --rule:#CFC7B6; --rule-soft:#E0D8C7;
  --petrol:#0E3A53; --link:#B83612; --link-hover:#7E2308;
  --signal:#B83612; --signal-soft:#F7E7E0;

  /* status semantics — colour is NEVER the only signal, every chip carries a label */
  /* Measured, not chosen: #A9761A was 3.52:1 and #7C8B98 was 3.10:1 on --paper — both
     failures of AA, and 3.10 is the exact value that made --ink-faint unreadable. A status
     colour IS text: the label is rendered in it. See tests/contrast.test.ts. */
  --st-airworthy:#2F6B4A; --st-restoration:#8A5F12; --st-static:#4A6274;
  --st-stored:#586570;    --st-gone:#8A3A34;

  --disp: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --body: var(--disp);
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  --measure: 68ch;
  /* The page column. Header, main and footer all read these two — never a literal.
     In REM, not ch: `ch` resolves against the element's OWN font-size, so the footer — which sets
     .92rem — computed 78ch as 723px while <main> got 883px. The column looked centred and was not.
     `--measure` below stays in ch, which is correct there: prose measure SHOULD track its text. */
  --page: 49rem;
  --page-pad: clamp(1rem, 4vw, 2.5rem);
  --gap: clamp(1rem, 2.5vw, 1.9rem);

  /* Focus is its own token, not a second use of --signal: the day the accent changes, the focus
     ring must not silently change with it. */
  --focus: var(--signal);

  /* Spacing scale, base 8. Ad-hoc rems drift; a scale does not. */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;
  --hairline: 1px;
  --border: var(--hairline) solid var(--rule);
  --border-soft: var(--hairline) solid var(--rule-soft);
  /* Near-square. Archival, not app-like. */
  --radius-1: 2px; --radius-2: 3px; --radius-pill: 999px;
  /* An older reader has to hit it. */
  --tap-min: 40px;

  /* Native scrollbars, form controls and the default canvas follow the theme. Without this the
     browser paints its own chrome light while the page is dark. */
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:#0C1116; --surface:#141B22; --sunk:#0A0E13;
    --ink:#FFFFFF; --ink-mid:#FFFFFF; --ink-faint:#FFFFFF;
    --muted:#9AA8B4;
    --rule:#2A3742; --rule-soft:#1E2830;
    --petrol:#5FA3CC; --link:#FF8C66; --link-hover:#FFB59B;
    --signal:#FF8C66; --signal-soft:#2A1710;
    --st-airworthy:#57A87B; --st-restoration:#D2A24A; --st-static:#7FA0B8;
    --st-stored:#9AA8B4;    --st-gone:#C4706A;
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --paper:#0C1116; --surface:#141B22; --sunk:#0A0E13;
  --ink:#FFFFFF; --ink-mid:#FFFFFF; --ink-faint:#FFFFFF;
  --muted:#9AA8B4;
  --rule:#2A3742; --rule-soft:#1E2830;
  --petrol:#5FA3CC; --link:#FF8C66; --link-hover:#FFB59B;
  --signal:#FF8C66; --signal-soft:#2A1710;
  --st-airworthy:#57A87B; --st-restoration:#D2A24A; --st-static:#7FA0B8;
  --st-stored:#9AA8B4;    --st-gone:#C4706A;
  color-scheme: dark;
}
:root[data-theme="light"] {
  --paper:#F5F1E8; --surface:#FFFEFB; --sunk:#EBE5D8;
  --ink:#000000; --ink-mid:#000000; --ink-faint:#000000;
  --muted:#556270;                 /* NOT for text — placeholders and de-emphasised marks only */
  --rule:#CFC7B6; --rule-soft:#E0D8C7;
  --petrol:#0E3A53; --link:#B83612; --link-hover:#7E2308;
  --signal:#B83612; --signal-soft:#F7E7E0;
  /* Measured, not chosen: #A9761A was 3.52:1 and #7C8B98 was 3.10:1 on --paper — both
     failures of AA, and 3.10 is the exact value that made --ink-faint unreadable. A status
     colour IS text: the label is rendered in it. See tests/contrast.test.ts. */
  --st-airworthy:#2F6B4A; --st-restoration:#8A5F12; --st-static:#4A6274;
  --st-stored:#586570;    --st-gone:#8A3A34;
  color-scheme: light;
}

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 18px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--link);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}
a:hover { color: var(--link-hover); text-decoration-thickness: 3px; }
a:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 2px; }

/* ── header / footer ─────────────────────────────────────────────────────── */
header {
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}
/* Same column as <main>: identical max-width and identical horizontal padding, so the wordmark
   sits directly above the h1 rather than out at the window edge. */
/* One column, three places. `--page` is the single value <main>, the header bar and the footer
   bar all use — three separate 78ch literals had already drifted once. */
header .bar {
  max-width: var(--page); margin: 0 auto;
  padding: .85rem var(--page-pad);
  display: flex; align-items: center; gap: 1rem;
}
/* THE WORDMARK ONLY. Scoped to the first child, not to `header a` — as a blanket rule it also
   stripped the underline from the section navigation beside it, which is prose and must look like
   every other link on the site. */
header .bar > a:first-child {
  font-size: 1.25rem; letter-spacing: .02em; text-transform: uppercase;
  color: var(--ink); text-decoration: none; font-weight: 700;
}
/* wordmark: "airframe" in medium, "hub" bold in the signal colour */
header .bar > a:first-child strong { font-weight: 800; color: var(--signal); }

/* Section navigation. Underlined like every other link — the header is not a place where the
   site's link rule gets an exception; only the wordmark is. */
header .nav { display: flex; gap: 1.1rem; margin-right: auto; font-size: .95rem; }
header .nav a {
  text-transform: none; letter-spacing: 0; font-weight: 500; color: var(--link);
  text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px;
}
header .nav a:hover { color: var(--link-hover); text-decoration-thickness: 3px; }

footer { border-top: 1px solid var(--rule); margin-top: calc(var(--gap) * 2); }
/* Same column as the header and <main>. */
footer .bar {
  max-width: var(--page); margin-inline: auto;
  padding: 1.4rem var(--page-pad) 2rem;
  color: var(--ink-mid); font-size: .92rem;
  /* One line, two columns: the invitation left, the legal links right. Wraps to two rows on a
     narrow screen rather than crushing either side. */
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: .6rem 2rem;
}
footer .what { margin: 0; max-width: none; }
footer .legal-nav { display: flex; flex-wrap: wrap; gap: .4rem 1.1rem; }

/* ── "Why this exists" — the one editorial block on the site ──────────────── */
.about-site { margin-top: 3rem; border-top: 1px solid var(--rule); padding-top: 1.6rem; }
.about-site h2 { margin-top: 0; }
.about-site p { max-width: var(--measure); }
/* The closing line. Larger and heavier than the prose above it, because it is the point. */
.about-site .promise {
  font-size: 1.3rem; font-weight: 700; letter-spacing: -.01em;
  color: var(--ink); margin-top: 1.2rem;
}

/* ── legal pages ──────────────────────────────────────────────────────────── */
.legal h2 { font-size: 1.1rem; margin: 1.8rem 0 .5rem; }
.legal ul { max-width: var(--measure); padding-left: 1.2rem; }
.legal li { margin-bottom: .35rem; }
.legal dl {
  display: grid; grid-template-columns: minmax(8rem, 12rem) 1fr;
  max-width: 46rem; border-top: var(--border); margin: .8rem 0 0;
}
.legal dt {
  padding: var(--sp-3) var(--sp-4) var(--sp-3) 0; border-bottom: var(--border-soft);
  font-weight: 600; color: var(--ink-mid);
}
.legal dd { padding: var(--sp-3) 0; border-bottom: var(--border-soft); margin: 0; }
@media (max-width: 480px) {
  .legal dl { grid-template-columns: 1fr; }
  .legal dt { padding-bottom: 0; border-bottom: 0; }
}

main {
  max-width: var(--page);
  margin: 0 auto;
  padding: clamp(1.4rem, 4vw, 2.8rem) var(--page-pad) 0;
}

/* ── breadcrumbs — a technical-drawing rail, not a decorative one ─────────── */
.crumbs ol {
  list-style: none; margin: 0 0 1.1rem; padding: 0;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem .55rem;
  /* Sentence case, not uppercase: capitals remove word shape, which is the main cue an older
     reader uses to skim. Body face rather than mono for the same reason. */
  font-size: .86rem; letter-spacing: 0;
}
.crumbs li { display: flex; align-items: baseline; gap: .5rem; color: var(--ink-faint); }
.crumbs li + li::before { content: "/"; color: var(--rule); }
.crumbs a { color: var(--link); }
.crumbs a:hover { color: var(--signal); }
.crumbs [aria-current="page"] { color: var(--ink-mid); }

/* ── type ────────────────────────────────────────────────────────────────── */
h1 {
  font-size: clamp(1.85rem, 4.6vw, 2.9rem);
  line-height: 1.08; letter-spacing: -.015em; font-weight: 800;
  margin: 0 0 .6rem;
  /* NOT `text-wrap: balance`. Balancing evens out the line lengths, which means it breaks a
     heading that would have fitted — "Aircraft at Pima Air & Space Museum" was split across two
     short lines with the full column width sitting unused beside it. A heading uses the width it
     has and breaks only when it runs out. */
  /* Plain wrapping: break only on running out of width. `nowrap` would be the other error —
     it does not break at all, so a long heading overflows a narrow screen sideways. */
  text-wrap: wrap;
}
h2 { font-size: 1.35rem; line-height: 1.25; margin: 2rem 0 .6rem; font-weight: 700; }
/* `pretty` keeps a one-word last line off the end of a paragraph — free, and it is the difference
   between a generated sentence looking typeset and looking dumped. */
p, li { max-width: var(--measure); text-wrap: pretty; }
p { margin: 0 0 1rem; }
.teaser { color: var(--ink-mid); font-size: 1.08rem; }

/* Identifiers — registrations, serials, Mode S. Mono is not decoration here:
   unambiguous 0/O and 1/l matters when the page is ABOUT "G-ASJV". */
/* Ligatures off: a serial is characters, not words — no font may weld two of them together. */
.ident, code, kbd, samp {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-variant-ligatures: none; letter-spacing: .01em;
}

/* One list treatment site-wide: the table in `.rows`. There is deliberately no second, flex-based
   list style — the home page briefly had "Where to go" as a table and "Browse" as a flex list, which
   read as two different kinds of thing. If a new list appears, it uses `.rows`. */

/* ── tables (spec sheets, data plates) ───────────────────────────────────── */
table { border-collapse: collapse; width: 100%; margin: 1.2rem 0; }
th, td { text-align: left; padding: .55rem .4rem; border-bottom: 1px solid var(--rule-soft); }
th { font-size: .88rem; font-weight: 600; color: var(--ink-mid); }

/* ── wide content never scrolls the page sideways ────────────────────────── */
table, pre { display: block; max-width: 100%; overflow-x: auto; }
/* Ships BEFORE the photo feature, so the first image cannot break the layout. */
img { max-width: 100%; height: auto; }
::selection { background: var(--sunk); }

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

/* A section is separated by SPACE, not by a rule across the page.
   A full-width hairline directly under the lead sentence reads as the end of the page, and it was
   doing that on every venue and manufacturer page. Hairlines belong inside tables, where they
   separate comparable rows; between sections the heading and the gap already do the work. */

/* Section spacing. The heading IS the question the block answers.
   NOTE: no `main section ul` rule — that is what let a second, flex-based list style exist
   alongside the table and made "Where to go" and "Browse" look like different kinds of thing. */
main section { margin-top: 1.8rem; }
main section h2 { margin-bottom: .2rem; }

/* ── theme toggle — hidden until theme.js enables it, so there is never a dead control ── */
header .bar > a:first-child { margin-right: 1.4rem; }
.theme {
  /* a control an older reader has to hit: readable label, generous tap target */
  font: inherit; font-size: .88rem;
  color: var(--ink-mid); background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--radius-pill); padding: .45rem .9rem; cursor: pointer; min-height: var(--tap-min);
}
.theme:hover { color: var(--signal); border-color: var(--signal); }
.theme:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* ── venue: visiting facts ────────────────────────────────────────────────── */
.visit { margin-top: 2.2rem; }
.visit table { margin: .6rem 0 1rem; }
.visit th {
  width: 11rem; vertical-align: baseline;
  font-size: .95rem; font-weight: 600; color: var(--ink-mid);
  letter-spacing: 0; text-transform: none;
}
.visit td { color: var(--ink); }
/* Paid links are labelled, visibly and in words. */
.ad-label {
  font-size: .78rem; letter-spacing: .04em; text-transform: uppercase;
  border: 1px solid var(--rule); border-radius: var(--radius-1);
  padding: .05rem .4rem; margin-left: .4rem; color: var(--ink-mid);
}


/* ── photograph — the credit is part of the component, not an option ─────── */
.photo { margin: 1.6rem 0 0; }
.photo img {
  display: block; width: 100%; height: auto;
  /* The width/height attributes give the intrinsic ratio; this keeps the box the right shape even
     if a file is ever replaced by one of different proportions. */
  aspect-ratio: attr(width) / attr(height);
  border: var(--border); background: var(--sunk);
}
.photo figcaption {
  margin-top: .5rem; font-size: .86rem; color: var(--ink-mid);
  max-width: var(--measure);
}
/* WHICH AEROPLANE THIS IS is not a credit, and must not read as one. A variant that borrows its
   family's photograph says so here, and at the caption's muted weight the one line that corrects
   the reader's assumption would be the easiest line to skip. Full ink, not --ink-mid. */
.photo .pictured { color: var(--ink); font-weight: 600; }

/* A LOGO is not a photograph. Contained, small, no frame — a flat mark stretched across the
   column with a hairline round its whitespace looks broken, and for a trademark it reads as
   misuse rather than identification. */
.photo.logo img {
  width: auto; max-width: min(260px, 60%); max-height: 110px;
  border: 0; background: transparent; object-fit: contain;
}
.photo.logo { margin-top: 1.2rem; }

/* ── sourced facts — the claim and its provenance in one glance ───────────── */
.about { margin-top: 2.2rem; }
.about h2 { margin-top: 0; }
.about dl {
  display: grid; grid-template-columns: minmax(9rem, 13rem) 1fr;
  margin: .6rem 0 .5rem; max-width: 46rem; border-top: var(--border);
}
.about dt {
  padding: var(--sp-3) var(--sp-4) var(--sp-3) 0; border-bottom: var(--border-soft);
  font-size: .95rem; font-weight: 600; color: var(--ink-mid);
}
/* A value is a fact, not an identifier — body face with tabular figures, never mono. */
.about dd {
  padding: var(--sp-3) 0; border-bottom: var(--border-soft); margin: 0;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
@media (max-width: 480px) {
  /* One column rather than a 9rem label squeezing the value to nothing. */
  .about dl { grid-template-columns: 1fr; }
  .about dt { padding-bottom: 0; border-bottom: 0; }
}
/* The credit sits with the facts it covers. Small, but never below the AA floor. */
.prov { font-size: .86rem; color: var(--ink-mid); margin: 0; }

/* ── the museum↔type connection, as a real table ─────────────────────────── */
.rows { margin-top: 2.2rem; }
.rows h2 { margin-bottom: .4rem; }
.rows .intro { color: var(--ink-mid); margin: 0 0 .7rem; }
.rows .scroll { overflow-x: auto; }          /* wide content scrolls itself, never the page */
.rows table {
  width: 100%; border-collapse: collapse; margin: 0; display: table;
}
/* FIXED layout only for the DIRECTORY tables — the ones with a Country column.
   Under `auto` a declared width is only a hint, so two stacked lists on the home page sized their
   columns from their own content and put "Country" 33px apart. But `fixed` also takes `width: 1%`
   literally, and `1%` is how the identity and status columns say "shrink to fit" — applying it
   everywhere collapsed every collection table on the site. So it is scoped to the tables whose
   alignment was the problem, and the rest keep the auto sizing that was working. */
.rows.grid table { table-layout: fixed; }
.rows.grid td:first-child, .rows.grid th:first-child { overflow-wrap: anywhere; }
.rows thead th {
  text-align: left; white-space: nowrap; padding: .55rem .8rem .55rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: .88rem; font-weight: 600; color: var(--ink-mid);
  letter-spacing: 0; text-transform: none;
}
.rows tbody td {
  padding: .62rem .7rem .62rem 0; border-bottom: 1px solid var(--rule-soft);
  vertical-align: baseline;
}
/* No row hover. The rows are not clickable — only the link in the first cell is — so a whole-row
   highlight promises a target that is not there. The link's own underline is the affordance. */
.rows td a { font-weight: 500; }
.rows td a:hover { text-decoration: underline; }

/* identity gets its own aligned column — mono, tabular, so serials line up down the page */
.rows td.ident {
  /* mono survives here on purpose: unambiguous 0/O and 1/l matters for a serial */
  font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: .95rem;
  letter-spacing: .02em; white-space: nowrap; width: 1%; color: var(--ink);
}
.rows td.status {
  font-size: .92rem; color: var(--ink-mid); white-space: nowrap; width: 1%;
}

/* ── status semantics ─────────────────────────────────────────────────────────
   NO COLOUR ON THE WORD. Static text is black in light and white in dark, site
   wide, and a status label is static text — colouring it was me applying the
   status palette to the first surface that would take it rather than to a
   surface it belongs on.

   The --st-* tokens stay defined and contrast-checked, and they stay UNUSED
   until there is a non-text carrier for them: a chip border, a marker, a rule.
   The `st-<value>` class is still emitted on the cell so that carrier has a
   hook when it is built, and so a status is machine-identifiable meanwhile. */
/* A COUNT is not an identifier. It keeps the body face — only serials earn mono (§8.3) — and gets
   tabular figures so the column reads as a column. Every count column renders identically, which
   is the whole point: "Types" and "Aircraft" are the same kind of thing and must look it. */
.rows th.col-num, .rows td.num {
  font-variant-numeric: tabular-nums;
  /* FIXED, not shrink-to-fit. At width:1% each table sized this column from its own header, so
     "Aircraft" and "Types" were different widths and pushed the Country column 11px apart in two
     tables stacked on the same page. A fixed width is what makes the two read as one grid. */
  width: 6rem;
  text-align: right; padding-right: 1.1rem;
}
/* The VALUE never wraps; the HEADER may. A long label like "Examples on display" held to one line
   inside a 6rem fixed column overflowed it and forced the whole table into horizontal scroll. */
.rows td.num { white-space: nowrap; }
.rows th.col-num, .rows th.col-place { overflow-wrap: anywhere; }
.rows th.col-ident, .rows th.col-status { white-space: nowrap; width: 1%; }

/* A place column is a FIXED width, not shrink-to-fit.
   Two ranked tables sit under each other on the home page, and each one sized its own columns
   from its own longest name — so "Country" landed in two different places a few rows apart and
   the pair read as two unrelated blocks. Same width in every table, so the eye tracks one grid. */
.rows th.col-place, .rows td.place { width: 11rem; white-space: nowrap; }
@media (max-width: 560px) {
  .rows th.col-place, .rows td.place { width: 6.5rem; white-space: normal; }
  .rows th.col-num, .rows td.num { width: 4rem; }
}
.rows td.num { color: var(--ink); }
.rows td .none { color: var(--muted); }

/* The way out of a truncated table — under it, not a row inside it. */
.rows .more { margin: .8rem 0 0; font-size: .95rem; }

@media (max-width: 560px) {
  .rows thead th, .rows tbody td { padding-right: .5rem; font-size: .92rem; }
  .rows td.status { font-size: .88rem; }
  .rows th.col-num, .rows td.num { padding-right: .5rem; }
}

/* ── collection at a glance — computed from our own rows, never typed ─────── */
.facts { margin-top: 2.2rem; }
.facts h3 {
  font-size: 1rem; font-weight: 600; color: var(--ink-mid);
  letter-spacing: 0; text-transform: none; margin: 1.4rem 0 .55rem;
}
/* `main section li` from the link-list rules has equal specificity and would win by order —
   scope these under main .facts so the chips cannot be flattened into full-width rows. */
main .facts .facts-list {
  list-style: none; margin: 0; padding: 0; border-top: 0;
  display: flex; flex-wrap: wrap; gap: .45rem .5rem;
}
main .facts .facts-list li {
  display: inline-flex; align-items: baseline; gap: .4rem; flex: 0 0 auto;
  border: 1px solid var(--rule); background: var(--surface); border-radius: 999px;
  padding: .38rem .85rem; font-size: .95rem; color: var(--ink-mid);
  /* a pill is one line — without this the count and its label break apart */
  white-space: nowrap;
}
main .facts .facts-list li b {
  /* Body face, NOT mono — same rule as a count column in `.rows`. Mono is for identifiers only,
     and a pill reading "92 aircraft" in mono while the table beside it sets counts in the body
     face is the same number rendered two ways on one page. */
  font-variant-numeric: tabular-nums;
  font-weight: 700; color: var(--ink);
}


