/* ==========================================================================
   LiveWaits design system. Ported out of the `mocks/tw/` design mock and
   into production on 2026-08-21. (The mock is one unversioned set now; the
   v11/v12 names below are the design ROUNDS it descends from, kept as history
   in the prose, not as filenames.)

   HISTORY, so the port is not silently undone again: this file used to
   carry a different system -- cool paper ground, Archivo on its width axis,
   one departure-amber accent, a `--wash` tint with a three-job list. That
   system was superseded by twelve rounds of mock work in `mocks/tw/`, but
   the mocks lived outside the build and this file plus the doctrine in
   CLAUDE.md still described the old one. A build made from the written
   doctrine therefore rebuilt the superseded system. The mocks are the
   design; this file is where the design ships.

   THE SYSTEM

   The ground is the brand. #0E2B20 fills the page and everything else is a
   card sitting on it. That single move is what makes the site recognisable
   from a thumbnail, and it is why type on the ground and type on a card are
   different colours drawn from different halves of the ramp.

   Type is two faces doing two jobs. Big Shoulders Display, condensed and
   uppercase, for anything that behaves like signage: headings, labels,
   column heads, controls. Public Sans for anything a person reads in
   sentences. Numbers are Public Sans with tabular figures, because a
   measured value should look like the page it sits on, not like code.

   CARD FILL JOB LIST (exactly three, do not extend):
     paper  -- data. the default card.
     cream  -- the ONE headline metric on the page. never twice.
     panel  -- a result on the field: a card that stays dark on the ground.

   STATUS RAMP JOB LIST (exactly one, do not extend):
     colour may encode delay ONLY on an element whose value IS a measured or
     modelled delay. It is an instrument, not decoration. No status colour
     on nav, links, headings, borders, or anything a person cannot read
     minutes off of. The ramp has two halves because the site has two
     grounds: `.d-*` on a light card, `.d-*` inside `.on-dark` on the field.
     A count is not a delay and takes neither.

   TWO HAZARDS THIS FILE IS BUILT AROUND
     1. Any rule that paints a background MUST name its own colour. The page
        has a dark ground and light cards, so an element that inherits
        colour across that boundary renders paper on paper or ink on ink.
     2. This is a committed single-theme design, not an un-themed one. It
        does not invert under `prefers-color-scheme: dark`, because its
        ground is already dark and inverting would destroy the one move the
        identity rests on. Every colour is stated explicitly so the page
        holds whatever the host paints behind it.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@400;600;700;800&family=Public+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap');

:root {
  --ground:   #0E2B20;   /* the field. the brand. */
  --panel:    #1E4735;   /* a card that stays on the field */
  --paper:    #FAF9F6;
  --cream:    #F0E5C9;   /* reserved for the one headline metric */
  --sink:     #EDEAE1;   /* a recessed row inside a paper card */

  --ink:      #111211;
  --ink-2:    #55584F;
  --ink-3:    #83867C;

  --pop:      #EFE04B;   /* headings on the ground, and hover */

  /* Instrument ramp, light half: on paper and cream cards. */
  --clear:    #0E6B3E;
  --moderate: #A96A00;
  --heavy:    #B72E1B;

  /* Instrument ramp, dark half: on the ground and on panel cards. The same
     three readings, lifted until they carry on #0E2B20. */
  --rev-clear:    #7BD9A8;
  --rev-moderate: #EFE04B;
  --rev-heavy:    #FF8B6E;

  --rule:      rgb(17 18 17 / .12);
  --rule-firm: rgb(17 18 17 / .30);
  --rule-rev:  rgb(250 249 246 / .18);

  --measure: 44rem;   /* prose */
  --wide:    64rem;   /* boards and instruments */
  --control-h: 3rem;

  --card-shadow: 0 1px 2px rgb(0 0 0 / .18), 0 12px 28px -12px rgb(0 0 0 / .5);

  --font-sign: 'Big Shoulders Display', 'Arial Narrow', Arial, sans-serif;
  --font-body: 'Public Sans', 'Helvetica Neue', Arial, sans-serif;
  --font-data: 'Public Sans', 'Helvetica Neue', Arial, sans-serif;
}

/* --------------------------------------------------------------- reset -- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--ground);
  color: var(--paper);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.55;
  font-variant-numeric: tabular-nums;
}
img, svg { max-width: 100%; }
/* Any rule that sets display beats the user agent's [hidden] rule, and this
   system sets display on nearly every card. Without this the staged answer
   never actually hides and the page shows its empty state and its result at
   the same time. */
[hidden] { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--pop); }
:focus-visible { outline: 2px solid var(--pop); outline-offset: 3px; }

/* --------------------------------------------------------------- type --- */
/* Signage type is condensed, uppercase and tight. It is not a size step of
   the body face; it is a different voice, and mixing the two inside one
   line is how the system starts looking like decoration. */
h1, h2, h3, .display, .slug, .fld-label, th, .k {
  font-family: var(--font-sign);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .01em;
  line-height: 1;
  text-wrap: balance;
}
h1 {
  font-size: clamp(2rem, 7.5vw, 3.2rem);
  line-height: .95; letter-spacing: -.005em;
  color: var(--pop);
  margin: 0 0 .3em;
}
h2 { font-size: clamp(1.35rem, 4vw, 1.75rem); margin: 2.4rem 0 .6rem; }
h3 { font-size: 1.15rem; margin: 1.7rem 0 .35rem; letter-spacing: .02em; }

/* Titles own their content: more air above a heading than below it. */
h1 + .standfirst, h2 + p, h3 + p { margin-top: .3rem; }
main > .wrap > :first-child, main > .wrap-wide > :first-child { margin-top: 0; }

/* The home page leads in cream rather than pop: it is the widest headline on
   the site and pop at that size stops being an accent. Inner pages keep pop,
   so the two read as the same system at two volumes. */
.eyebrow {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .16em; font-size: .8125rem; color: var(--pop); margin: 0 0 .7rem;
}
h1.h1-cream { color: var(--cream); font-size: clamp(2.4rem, 9vw, 4.4rem);
              line-height: .92; }
.reading > .cream-h2 {
  font-size: clamp(1.7rem, 5.5vw, 2.4rem); line-height: .95; letter-spacing: .01em;
  color: var(--ink); margin: 0 0 .6rem; padding: 0; border: 0;
}
.linkout.dark a { color: var(--ground); }
.linkout.dark a:hover { color: var(--ground); }
.linkout.light a { color: var(--pop); }
.linkout.light a:hover { color: var(--pop); }
/* On the dark panel a row rule has to be paper, not ink. */
.card-panel .rows > li { border-bottom-color: rgb(250 249 246 / .16); }
.card-panel .rows .why, .card-panel .note { color: rgb(250 249 246 / .6); }
.card-panel .rows .nm a { color: var(--paper); }
.card-panel .rows .nm a:hover { color: var(--pop); }
.card-panel .val .unit { color: rgb(250 249 246 / .55); }

.standfirst {
  color: rgb(250 249 246 / .72);
  font-size: 1.06rem; max-width: 42rem; margin: 0 0 1.5rem;
}
.note { color: var(--ink-3); font-size: .875rem; line-height: 1.5; }
.data { font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- layout -- */
/* Two measures: prose reads at 44rem, boards and instruments need 64rem.
   The header, the footer and the content must all align on the SAME left
   edge, so the page states which measure it is and the chrome follows it.
   A wordmark that starts 110px left of the headline under it reads as a
   broken template, and it is the first thing the eye catches. */
.wrap      { max-width: var(--measure); margin: 0 auto; padding: 2.2rem 1.1rem 0; }
.wrap-wide { max-width: var(--wide);    margin: 0 auto; padding: 2.2rem 1.1rem 0; }
.measure-box { max-width: var(--measure); margin: 0 auto; padding: 0 1.1rem; }
body.wide .measure-box, body.wide .site-bar { max-width: var(--wide); }

/* ---------------------------------------------------------------- card -- */
/* ONE card treatment. The moment there are two, the system is decoration
   rather than structure. The fill says what the card is FOR. */
.card, .reading, .figure-panel, .board, table.ledger, .controls, .lede-grid,
.strip {
  border-radius: 5px;
  box-shadow: var(--card-shadow);
  background: var(--paper);
  color: var(--ink);
  margin: 0 0 1.15rem;
}
.card-cream, .reading { background: var(--cream); color: var(--ink); }
.card-panel { background: var(--panel); color: var(--paper); }

/* An element that paints a background names its own colour. On a page with
   a dark ground and light cards, inheriting across that boundary renders
   paper on paper. This is the single most expensive bug this system can
   have, so it is stated as a rule rather than left to care. */
.card p, .card li, .card td, .card th,
.reading p, .figure-panel p, table.ledger td, table.ledger th { color: inherit; }

/* -------------------------------------------------------------- chrome -- */
header.site { background: var(--paper); color: var(--ink); }
.site-bar {
  display: flex; align-items: center; gap: 1rem;
  max-width: var(--measure); margin: 0 auto; padding: .85rem 1.1rem;
}
.wordmark {
  font-family: var(--font-sign); font-weight: 800; text-transform: uppercase;
  letter-spacing: .01em; font-size: 1.35rem; line-height: 1;
  color: var(--clear); text-decoration: none; white-space: nowrap;
}
.wordmark:hover { color: var(--ink); }
.site-nav {
  display: flex; gap: 1.15rem; margin-left: auto;
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; font-size: .9375rem;
}
.site-nav a { color: var(--ink-2); text-decoration: none; }
.site-nav a:hover, .site-nav a[aria-current] { color: var(--clear); }

footer.site {
  margin-top: 3.5rem; border-top: 1px solid var(--rule-rev);
  padding: 1.5rem 0 3rem;
  color: rgb(250 249 246 / .55); font-size: .8125rem;
}

footer.site a { color: rgb(250 249 246 / .8); }
footer.site a:hover { color: var(--pop); }

.crumbs {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; font-size: .8125rem;
  color: rgb(250 249 246 / .55); margin: 0 0 .9rem;
}
.crumbs a { color: rgb(250 249 246 / .75); }

/* --------------------------------------------------- section title slug -- */
/* Inside a card, so it takes the card's ink and a hairline under it. On the
   ground it takes paper. It never carries its own fill: a band inside a
   card is a second card treatment. */
.slug {
  font-size: 1.0625rem; font-weight: 700; letter-spacing: .04em;
  color: rgb(250 249 246 / .9);
  margin: 2rem 0 .7rem;
}
.card > .slug, .board-head .slug { color: var(--ink); margin: 0; }

/* ------------------------------------------------------ the board row --- */
/* ONE grammar for every repeating list on the site: airports, crossings,
   lanes, hours, sailings. Name left, value right in tabular figures,
   hairline under each row. */
.board { list-style: none; margin: 0 0 1.15rem; padding: 0 .25rem .35rem; }

/* The board names itself and states its own count, inside the card rather
   than floating above it. A count is not a delay, so it takes no ramp. */
.board-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .75rem; padding: .95rem .85rem .7rem;
  border-bottom: 2px solid var(--rule-firm);
  color: var(--ink);
}
.board-head .slug { color: var(--ink); margin: 0; margin-right: auto; }
.board-row.is-empty .name { color: var(--ink-2); font-size: .9375rem; }
.board > li, .board-row {
  display: flex; align-items: baseline; gap: .75rem;
  border-bottom: 1px solid var(--rule);
  padding: .7rem .85rem;
  color: var(--ink);
}
.board > li:last-child, .board-row:last-child { border-bottom: 0; }
.board-row > .name { flex: 1 1 auto; min-width: 0; }
.board-row .name a {
  font-family: var(--font-sign); font-weight: 700; text-transform: uppercase;
  letter-spacing: .02em; font-size: 1.15rem; line-height: 1.1;
  color: var(--ink); text-decoration: none;
}
.board-row .name a:hover { color: var(--clear); text-decoration: underline; }
.board-row .meta {
  display: block; color: var(--ink-3); font-size: .8125rem;
  letter-spacing: 0; text-transform: none; font-family: var(--font-body);
}
/* The band this airport usually sits in at this hour. It is context for
   the reading beside it, not a second reading, so it takes no ramp colour
   and it is the first thing the phone sheds. */
.usual {
  flex: 0 0 auto; color: var(--ink-3); font-size: .875rem;
  white-space: nowrap; font-variant-numeric: tabular-nums;
  text-align: right; min-width: 5.5rem;
}
.usual.head {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; font-size: .75rem; color: var(--ink-2);
  margin-left: auto;
}
.board-head .note { margin: 0; white-space: nowrap; min-width: 5.5rem;
                    text-align: right; }

.board-row .value {
  flex: 0 0 auto; font-weight: 700; font-size: 1.35rem; line-height: 1;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.board-row .value .unit {
  color: var(--ink-3); font-size: .75rem; font-weight: 500;
  margin-left: .2rem;
}

/* Delay colour lives here and only here. Two halves, one job. */
.d-clear    { color: var(--clear); }
.d-moderate { color: var(--moderate); }
.d-heavy    { color: var(--heavy); }
.d-closed   { color: var(--ink-3); }
.on-dark .d-clear    { color: var(--rev-clear); }
.on-dark .d-moderate { color: var(--rev-moderate); }
.on-dark .d-heavy    { color: var(--rev-heavy); }
.on-dark .d-closed   { color: rgb(250 249 246 / .5); }

/* ------------------------------------------------- headline reading ----- */
/* The cream card. Exactly one per page: it is the page's single answer, and
   a second cream card means the page has stopped having one. */
.reading { padding: 1.5rem 1.4rem 1.4rem; }
.reading .label {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .09em; font-size: .8125rem; color: rgb(17 18 17 / .6);
  margin: 0;
}
.reading .figure {
  font-family: var(--font-sign); font-weight: 800;
  font-size: clamp(3.4rem, 15vw, 5.2rem); line-height: .8;
  letter-spacing: -.01em;
  display: block; margin: .5rem 0 .1rem;
  font-variant-numeric: tabular-nums;
}
.reading .figure.is-text {
  font-size: clamp(1.9rem, 7vw, 2.6rem); line-height: 1; letter-spacing: 0;
}
.reading .figure .unit {
  font-size: .3em; font-weight: 700; letter-spacing: .02em;
  color: rgb(17 18 17 / .65); margin-left: .1em;
}
.reading .sub { color: rgb(17 18 17 / .72); font-size: .9375rem; margin: .8rem 0 0; }

/* --------------------------------------------------------- summary trio -- */
.lede-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  overflow: hidden; padding: 0;
}
.lede-grid div { padding: .9rem 1rem 1rem; color: var(--ink); }
.lede-grid div + div { border-left: 1px solid var(--rule); }
.lede-grid .k {
  font-size: .8125rem; font-weight: 600; letter-spacing: .08em;
  color: var(--ink-2); margin: 0;
}
.lede-grid .v {
  font-family: var(--font-sign); font-weight: 800; font-size: 1.7rem;
  line-height: 1; margin: .5rem 0 .4rem; font-variant-numeric: tabular-nums;
}
.lede-grid .note { margin: 0; }

/* ============================================================ SIGNATURE ==
   The leave-by strip. Every other site in this lane answers "how long is
   the wait"; the question a traveller actually has is "when do I leave".
   The strip is the answer AND its own reasoning: each segment of the
   journey drawn to scale, labelled with its own minutes.

   HTML track, not SVG: an SVG scales its type with its width and is comic
   at 720px and illegible at 390px. (Property #1 learned this the hard way.)
   ======================================================================== */
.strip { padding: 1.1rem 1rem 1rem; }
.strip-ends {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: .8125rem; color: var(--ink-2); padding: 0 .1rem .35rem;
}
.strip-ends b {
  display: block; font-family: var(--font-sign); font-weight: 800;
  font-size: 1.4rem; line-height: 1; color: var(--ink);
}
.strip-ends .right { text-align: right; }
.strip-track {
  display: flex; width: 100%; height: 2.5rem;
  border-radius: 4px; overflow: hidden;
  background: var(--sink);
}
.strip-seg {
  display: flex; align-items: center; justify-content: center;
  min-width: 0; padding: 0 .2rem;
  border-right: 1px solid rgb(250 249 246 / .6);
  font-size: .75rem; font-weight: 600; color: var(--ink-2);
  white-space: nowrap; overflow: hidden;
  transition: flex-basis .25s ease;
}
.strip-seg:last-child { border-right: 0; }
.strip-seg.is-wait { background: var(--pop); color: var(--ink); font-weight: 700; }
.strip-seg.is-buffer {
  background: repeating-linear-gradient(
    135deg, transparent 0 5px, rgb(17 18 17 / .07) 5px 10px);
}
/* A segment too narrow for its own label shows nothing rather than a
   truncated number that reads as a different number. */
.strip-seg.is-tight { font-size: 0; }
.strip-key {
  display: flex; flex-wrap: wrap; gap: .1rem 1rem; margin: .6rem 0 0;
  padding: 0; list-style: none; font-size: .8125rem; color: var(--ink-2);
}
.strip-key li { display: flex; gap: .4rem; }
.strip-key .k-min { font-weight: 700; color: var(--ink); }

@media (prefers-reduced-motion: reduce) { .strip-seg { transition: none; } }

/* ------------------------------------------------------- hour heatmap --- */
/* The measured half of the model: departures per hour, every weekday. A
   grid of blocks, not a chart library. */
.figure-panel { padding: 1.1rem 1rem .9rem; overflow-x: auto; }
.figure-panel .cap { font-size: .8125rem; color: var(--ink-2); margin: .7rem 0 0; }
.heat { border-collapse: collapse; width: 100%; min-width: 20rem; }
.heat th, .heat td { padding: 0; }
.heat th.hr {
  font-family: var(--font-sign); font-weight: 600; font-size: .6875rem;
  letter-spacing: .04em; color: var(--ink-3); text-align: center;
  padding-bottom: .25rem;
}
.heat th.dy {
  font-family: var(--font-sign); font-weight: 700; font-size: .75rem;
  letter-spacing: .06em; color: var(--ink-2);
  text-align: right; padding-right: .45rem; width: 2.4rem;
}
.heat td.cell { height: 1.05rem; border: 1px solid var(--paper); }
.heat td.cell.now { outline: 2px solid var(--ink); outline-offset: -2px; }

/* ------------------------------------------------------------ tables ---- */
table.ledger { border-collapse: collapse; width: 100%; overflow: hidden; }
table.ledger caption {
  text-align: left; color: var(--ink-2); font-size: .8125rem;
  padding: .8rem .9rem .5rem;
}
table.ledger th, table.ledger td {
  text-align: left; padding: .6rem .9rem; color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
table.ledger tr:last-child td { border-bottom: 0; }
table.ledger th {
  font-size: .75rem; letter-spacing: .08em; color: var(--ink-2);
  font-weight: 600; border-bottom: 1px solid var(--rule-firm);
}
table.ledger td.num, table.ledger th.num {
  text-align: right; font-variant-numeric: tabular-nums; font-weight: 600;
}

/* ------------------------------------------------------------ controls -- */
.controls {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .9rem; padding: 1.1rem 1rem;
}
.controls .full { grid-column: 1 / -1; }
.field { display: flex; flex-direction: column; gap: .35rem; min-width: 0; }
.field label, .fld-label {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .09em; font-size: .75rem; color: var(--ink-2);
}
.field input:not([type="checkbox"]):not([type="radio"]),
.field select, .fld {
  width: 100%; max-width: 100%; height: var(--control-h);
  font: inherit; font-size: 1rem; line-height: 1.2;
  padding: 0 .8rem; border: 2px solid var(--ink); border-radius: 4px;
  background: var(--paper); color: var(--ink);
  appearance: none; -webkit-appearance: none; color-scheme: light;
}
.field select { padding-right: 2rem; }
.field input::placeholder { color: var(--ink-3); }
.field input:focus:not([type="checkbox"]), .field select:focus {
  outline: 2px solid var(--clear); outline-offset: 2px;
}
/* `.field` is a column; a check row is not. Without the explicit reset the
   checkboxes inherit the column direction and `align-items: center` then
   centres each label on its own line, which reads as a layout accident. */
.field.checks, .checks {
  display: flex; flex-flow: row wrap; gap: .5rem 1.1rem; align-items: center;
}
.checks label {
  display: flex; align-items: center; gap: .45rem;
  font-family: var(--font-body); text-transform: none; letter-spacing: 0;
  font-size: .9375rem; color: var(--ink);
}
.checks input {
  appearance: auto; -webkit-appearance: auto;
  accent-color: var(--clear); width: 1.1rem; height: 1.1rem;
  border: 0; padding: 0; margin: 0; flex: 0 0 auto;
}
.checks { justify-content: flex-start; }

.btn {
  height: var(--control-h);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-sign); font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; font-size: 1.05rem; line-height: 1;
  padding: 0 1.5rem; border: 0; border-radius: 4px; cursor: pointer;
  white-space: nowrap; background: var(--ink); color: var(--paper);
  transition: background-color .15s ease;
}
.btn:hover { background: var(--clear); color: var(--paper); }

/* -------------------------------------------------------- typeahead ----- */
/* The search box sits on the ground, not in a card, so its label takes the
   ground's own ink. A label styled for a card is invisible here. */
.searchbox { position: relative; margin: 1.4rem 0 1.9rem; max-width: 34rem; }
.searchbox .fld-label { color: rgb(250 249 246 / .72); margin-bottom: .45rem; }
.searchbox input {
  width: 100%; height: var(--control-h);
  font: inherit; font-size: 1rem; padding: 0 .8rem;
  border: 2px solid var(--ink); border-radius: 4px;
  background: var(--paper); color: var(--ink);
}
.results {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + .4rem);
  max-height: 17rem; overflow-y: auto; margin: 0; padding: 0; list-style: none;
  background: var(--paper); color: var(--ink);
  border: 2px solid var(--ink); border-radius: 4px;
  box-shadow: 0 14px 30px -10px rgb(0 0 0 / .5);
}
.results li + li { border-top: 1px solid var(--rule); }
.results li a {
  display: flex; gap: .6rem; padding: .55rem .7rem;
  color: var(--ink); text-decoration: none;
}
.results li a:hover, .results li a:focus {
  background: var(--pop); color: var(--ink);
}
.results .code {
  font-family: var(--font-sign); font-weight: 700; letter-spacing: .04em;
  color: var(--ink-2);
}

/* ------------------------------------------------------------- source --- */
.source {
  color: rgb(250 249 246 / .5); font-size: .8125rem; line-height: 1.5;
  max-width: 44rem; margin: 1.4rem 0 0;
}
.source a { color: rgb(250 249 246 / .75); }


/* ============================================================== v11 grid ==
   Cards sit on a twelve column field. This is the composition layer the v11
   round settled on: a status band beside a glance card, then full-width
   instruments, then two-up explainer cards. One column on a phone, always.
   ========================================================================= */
.grid12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
          gap: 1.15rem; align-items: stretch; }
.grid12 > * { grid-column: 1 / -1; margin-bottom: 0; }
@media (min-width: 48rem) {
  .c6 { grid-column: span 6; } .c7 { grid-column: span 7; }
  .c5 { grid-column: span 5; }
}
@media (min-width: 64rem) {
  .c8 { grid-column: span 8; } .c4 { grid-column: span 4; }
}
/* A card in the grid is a column, so a link or a note can be pinned to its
   bottom edge and two cards side by side end level. */
.grid12 > .card, .grid12 > .reading { display: flex; flex-direction: column; }
.pin { margin-top: auto; padding-top: 1rem; }
/* Two cards side by side end level, so the list between the heading and the
   pinned link takes the slack rather than leaving it under the last row. */
.grid12 > .card > .rows { flex: 1 1 auto; }

.card { padding: 1.4rem 1.3rem; }
/* A heading inside a card is the card's own title and carries the rule. */
.card > h2 {
  margin: 0 0 .9rem; padding-bottom: .5rem;
  border-bottom: 2px solid var(--ink); font-size: 1.35rem; letter-spacing: .04em;
}
.card-panel > h2 { border-bottom-color: rgb(250 249 246 / .25); }
.card > h2 + p { margin-top: 0; }
.card p { margin: .7rem 0 0; }
.card > p:first-child { margin-top: 0; }

/* -------------------------------------------------------- status band --- */
/* The cream card is two columns with a rule between and a pinned bottom row.
   The bottom row exists because an earlier round left the cream stretching
   empty beside a taller neighbour; a card that fills with air is a card
   holding nothing. */
.band { display: grid; gap: 1.1rem 2.2rem; }
@media (min-width: 34rem) { .band { grid-template-columns: auto 1fr; } }
.band .lede {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; font-size: .8125rem; color: rgb(17 18 17 / .6);
  margin: 0;
}
.band .fig {
  font-family: var(--font-sign); font-weight: 800; line-height: .8;
  font-size: clamp(3.6rem, 17vw, 5.6rem); letter-spacing: -.01em;
  margin: .6rem 0 0; display: inline-flex; align-items: baseline; gap: .06em;
  font-variant-numeric: tabular-nums;
}
.band .fig .unit {
  font-size: .3em; font-weight: 800; text-transform: uppercase;
  letter-spacing: .03em; color: rgb(17 18 17 / .7);
}
.band .say { color: rgb(17 18 17 / .82); font-size: .9375rem; line-height: 1.6; }
@media (min-width: 34rem) {
  .band .right { border-left: 1px solid rgb(17 18 17 / .2); padding-left: 2.2rem; }
}
.band-foot {
  margin-top: 1.2rem; padding-top: .9rem;
  border-top: 1px solid rgb(17 18 17 / .2);
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: .35rem 1.5rem;
}
.band-foot p { margin: 0; }
.band-foot .stamp { color: rgb(17 18 17 / .55); font-size: .8125rem; flex: 0 0 auto; }

/* The trend sparkline: the last seven hours of this airport's own curve, so
   the headline number has a direction as well as a value. */
.spark { display: flex; align-items: flex-end; gap: 5px; height: 3rem; width: 9.5rem;
         margin: 1.2rem 0 0; }
.spark i { flex: 1; border-radius: 2px 2px 0 0; background: rgb(14 43 32 / .45); }
.spark i.is-now { background: var(--ground); }
.spark-note { color: rgb(17 18 17 / .65); font-size: .8125rem; margin: .5rem 0 0; }

/* Provenance, not delay: the measured/modelled badge says where the number
   came from, so it takes NO status-ramp colour (a source is not a wait). Two
   states only -- measured (a fresh official feed is driving the figure) reads
   as the brand ground on the cream card; modelled is a quiet outline. */
.feed-badge {
  display: inline-block; vertical-align: middle; margin-left: .5rem;
  font-family: var(--font-sign); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; font-size: .625rem; line-height: 1;
  padding: .28em .5em; border-radius: 3px;
  border: 1px solid rgb(17 18 17 / .3); color: rgb(17 18 17 / .6);
}
.feed-badge.is-measured {
  background: var(--ground); color: var(--paper); border-color: var(--ground);
}
.feed-stamp {
  color: rgb(17 18 17 / .6); font-size: .8125rem; margin: .5rem 0 0;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- bars ----- */
/* A lane, a neighbour, a sibling crossing: same row grammar, a bar under the
   number so three readings compare at a glance instead of one at a time. */
.rows { margin: 0; padding: 0; list-style: none; }
.rows > li { padding: .8rem 0; border-bottom: 1px solid var(--rule); }
.rows > li:last-child { border-bottom: 0; }
.rows .top {
  display: flex; align-items: baseline; justify-content: space-between; gap: .75rem;
}
.rows .nm {
  font-family: var(--font-sign); font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; font-size: 1.15rem; line-height: 1;
}
.rows .nm a { color: inherit; text-decoration: none; }
.rows .nm a:hover { color: var(--clear); text-decoration: underline; }
.rows .val {
  flex: 0 0 auto; font-weight: 700; font-size: 1.6rem; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.rows .val .unit { font-size: .75rem; font-weight: 500; color: var(--ink-3);
                   margin-left: .2rem; }
.rows .why { margin: .55rem 0 0; font-size: .8125rem; line-height: 1.45;
             color: var(--ink-3); }
.rows .saves { color: var(--clear); font-weight: 700; }

.bar-track { height: 6px; border-radius: 2px; background: rgb(17 18 17 / .08);
             margin-top: .6rem; overflow: hidden; }
.bar-fill { display: block; height: 100%; border-radius: 2px; }
.bar-fill.d-clear    { background: var(--clear); }
.bar-fill.d-moderate { background: var(--moderate); }
.bar-fill.d-heavy    { background: var(--heavy); }
.bar-fill.d-closed   { background: var(--ink-3); }

/* Compact variant for the glance card beside the headline. */
.rows.mini > li { padding: .6rem 0; }
.rows.mini .nm { font-size: 1.05rem; }
.rows.mini .val { font-size: 1.35rem; }
.rows.mini .with { display: flex; align-items: center; gap: .55rem; margin-top: .5rem; }
.rows.mini .with .bar-track { flex: 1 1 auto; margin-top: 0; height: 5px; }
.rows.mini .tag { flex: 0 0 auto; font-size: .75rem; color: var(--ink-3); }
.rows.mini .tag.saves { color: var(--clear); font-weight: 700; }

/* An outbound link that reads as signage, pinned to a card's bottom edge. */
.linkout {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .08em; font-size: .8125rem;
}
.linkout a { color: var(--clear); text-decoration: none; }
.linkout a:hover { text-decoration: underline; color: var(--clear); }

/* A button that behaves like a link, for an action inside a sentence. */
.linkbtn {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--clear); text-decoration: underline; text-underline-offset: 3px;
}
.linkbtn:hover { color: var(--ink); }

/* -------------------------------------------------------- day chart ----- */
/* Twenty four hours of today. The dark bar is now; the pop bar is the hour
   the traveller actually reaches the checkpoint, which is the only hour the
   question "is another time better" is really about. */
.daychart { display: flex; align-items: stretch; gap: 3px; height: 9rem;
            margin: 1.2rem 0 0; }
.daychart > span { flex: 1; display: flex; align-items: flex-end; }
.daychart i { display: block; width: 100%; border-radius: 2px 2px 0 0;
              background: rgb(17 18 17 / .18); }
.daychart i.is-now { background: var(--ink); }
.daychart i.is-you { background: var(--pop); }
.daykey {
  display: flex; justify-content: space-between; margin: .5rem 0 0;
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .08em; font-size: .6875rem; color: var(--ink-3);
}

/* ------------------------------------------------- the answer, staged --- */
/* Before the traveller has said anything the answer slot holds a placeholder
   rather than a number nobody asked for. The empty state is dashed and flat:
   it is the one surface on the site that is deliberately not a card. */
.slot-empty {
  border: 2px dashed rgb(250 249 246 / .25); border-radius: 5px;
  background: rgb(30 71 53 / .55); color: var(--paper);
  box-shadow: none; padding: 1.5rem 1.4rem;
  display: grid; gap: .6rem 2rem; align-items: center;
}
@media (min-width: 34rem) { .slot-empty { grid-template-columns: auto 1fr; } }
.slot-empty .ghost {
  font-family: var(--font-sign); font-weight: 800; line-height: .8;
  font-size: clamp(2.6rem, 11vw, 4rem); color: rgb(250 249 246 / .3);
  margin: 0; user-select: none;
}
.slot-empty p { margin: 0; color: rgb(250 249 246 / .78); font-size: .9375rem;
                line-height: 1.6; }

.result-label {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; font-size: .8125rem; color: var(--pop); margin: 0;
}
.result-time {
  font-family: var(--font-sign); font-weight: 800; line-height: .8;
  font-size: clamp(3rem, 12vw, 4.4rem); color: var(--pop);
  margin: .6rem 0 0; display: inline-flex; align-items: baseline; gap: .08em;
  font-variant-numeric: tabular-nums;
}
.result-time .mer { font-size: .33em; text-transform: uppercase; letter-spacing: .03em; }
.card-panel .note { color: rgb(250 249 246 / .75); }
.card-panel a { color: var(--pop); }

/* The timeline reads as separate legs with their own labels, not as one
   continuous track. A traveller checks a single leg ("is thirty eight minutes
   of driving right?"), and a continuous track makes that the hardest read. */
.timeline { display: flex; gap: 6px; margin: 0; padding: 0; list-style: none; }
.timeline li { flex-grow: 1; flex-basis: 0; min-width: 0; }
.timeline .leg {
  height: 3.5rem; border-radius: 3px; background: var(--sink); color: var(--ink-2);
  display: flex; align-items: flex-end; padding: 0 .5rem .4rem;
  font-weight: 700; font-size: 1.1rem; line-height: 1;
  font-variant-numeric: tabular-nums; overflow: hidden;
}
.timeline .leg.is-hot { background: var(--pop); color: var(--ink); }
.timeline .lab {
  display: block; margin-top: .45rem;
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; font-size: .75rem; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.timeline-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: .75rem; margin-bottom: .9rem;
}
.timeline-head h2 { margin: 0; padding: 0; border: 0; }
.timeline-head .tot { font-weight: 700; color: var(--ink-2); font-size: .875rem;
                      flex: 0 0 auto; font-variant-numeric: tabular-nums; }

@keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes rise { from { opacity: 0; transform: translateY(.35em); }
                  to { opacity: 1; transform: none; } }
.anim-grow { transform-origin: left center;
             animation: grow .34s cubic-bezier(.22,.61,.36,1) both; }
.anim-rise { animation: rise .3s ease-out both; }
@media (prefers-reduced-motion: reduce) {
  .anim-grow, .anim-rise { animation: none !important; }
}

/* -------------------------------------------------------- form layout --- */
/* Three fields across on desktop, one on a phone, and a real button. The
   button matters: the answer appears because the traveller asked for it. */
.form3 { display: grid; gap: 1rem 1.2rem; align-items: start; margin-top: 1.1rem; }
@media (min-width: 48rem) { .form3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.form3 .hint { margin: .5rem 0 0; font-size: .8125rem; color: var(--ink-3); }
.form3 .checks { grid-column: 1 / -1; }

/* -------------------------------------------------------- site chrome --- */
/* The wordmark is two tone: the qualifier in the brand green, the noun in
   ink. It is the one place the site says its own name, so it says it in the
   two colours the whole system is built from. */
.wordmark .w-live { color: var(--clear); }
.wordmark .w-waits { color: var(--ink); }
.wordmark:hover .w-live, .wordmark:hover .w-waits { color: var(--ink-2); }
.site-clock {
  margin-left: auto;
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .08em; font-size: .8125rem; color: var(--ink-2);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.site-clock:empty { display: none; }
.site-nav + .site-clock { margin-left: 1.15rem; }
footer.site .stat {
  font-family: var(--font-sign); font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; font-size: .8125rem; color: rgb(250 249 246 / .55);
  margin: 0 0 .9rem;
}


/* Browse-by-state / metro index on the national hub. A dense link grid, one
   card, so all 52 states and the metros are one tap from the board and no
   scoped page is an orphan. */
.browse { margin-top: 1.15rem; }
.browse-list {
  list-style: none; margin: .3rem 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: .1rem 1.4rem;
}
.browse-list li { border-bottom: 1px solid var(--rule); }
.browse-list a {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .5rem; padding: .5rem .1rem; color: var(--ink); text-decoration: none;
  font-weight: 600;
}
.browse-list a:hover { color: var(--clear); }
.browse-n { color: var(--ink-3); font-size: .8125rem; font-weight: 400;
            font-variant-numeric: tabular-nums; }


/* The server-rendered worked example: a real answer in the HTML for crawlers
   and no-JS readers, distinct from the interactive result below it. Tinted
   sink so it reads as a worked aside, not as the live answer. */
.worked {
  background: var(--sink); color: var(--ink);
  border-radius: 4px; padding: .8rem 1rem; margin-top: 1rem !important;
  font-size: .9375rem; line-height: 1.55;
}
.worked strong { font-weight: 700; }

.rows .reg {
  font-family: var(--font-body); font-weight: 500; text-transform: none;
  letter-spacing: 0; font-size: .6875rem; color: var(--ink-3);
  border: 1px solid var(--rule-firm); border-radius: 3px; padding: 0 .3rem;
  vertical-align: middle;
}

/* ------------------------------------------------------------- phone ---- */
/* ---- terminal schematic map -------------------------------------------- */
/* A legible schematic drawn server-side from real OSM gate coordinates, NOT a
   vendor floorplan. It rides in a .figure-panel, which already scrolls on
   overflow; the SVG scales to the card and keeps its aspect. Every painted
   element names its own colour (the dark-ground/light-card hazard). */
.tmap-svg {
  display: block; width: 100%; height: auto; background: var(--paper);
}
.tmap-svg .bldg {
  fill: var(--sink); stroke: var(--rule-firm); stroke-width: 1;
  stroke-linejoin: round;
}
.tmap-svg .lnk { stroke: rgb(17 18 17 / .07); stroke-width: .6; }
.tmap-svg .g { stroke: var(--paper); stroke-width: .8; }
.tmap-svg .g.d-clear    { fill: var(--clear); }
.tmap-svg .g.d-moderate { fill: var(--moderate); }
.tmap-svg .g.d-heavy    { fill: var(--heavy); }
.tmap-svg .cp { fill: var(--ink); stroke: var(--paper); stroke-width: 1.5; }
.tmap-legend {
  list-style: none; display: flex; flex-wrap: wrap; gap: .35rem 1.1rem;
  margin: .85rem 0 0; padding: 0; font-size: .8125rem; color: var(--ink-2);
}
.tmap-legend li { display: flex; align-items: center; gap: .4rem; }
.tmap-legend .sw {
  width: 12px; height: 12px; border-radius: 50%; display: inline-block;
  flex: none;
}
.tmap-legend .sw.d-clear    { background: var(--clear); }
.tmap-legend .sw.d-moderate { background: var(--moderate); }
.tmap-legend .sw.d-heavy    { background: var(--heavy); }
.tmap-legend .sw.cp { background: var(--ink); border-radius: 2px; }

/* One breakpoint, one discipline: below it every surface shows FEWER facts,
   never smaller facts. */
@media (max-width: 34rem) {
  body { font-size: 1rem; }
  .wrap, .wrap-wide { padding-top: 1.6rem; }
  .site-bar { padding: .7rem 1.1rem; flex-wrap: wrap; row-gap: .35rem; }
  /* Four lanes now, so on the narrowest screens the nav tightens and the
     visitor clock (a nicety) steps aside rather than pushing the bar wider
     than the viewport. FEWER facts, never smaller ones. */
  .site-nav { gap: .62rem; font-size: .8125rem; letter-spacing: .03em; }
  .site-clock { display: none; }
  .controls { grid-template-columns: 1fr; }
  .lede-grid { grid-template-columns: repeat(2, 1fr); }
  .lede-grid div + div { border-left: 1px solid var(--rule); }
  .lede-grid div:nth-child(3) { border-left: 0; border-top: 1px solid var(--rule); }
  .lede-grid div:last-child:nth-child(odd) { grid-column: 1 / -1; }
  /* The board sheds its least urgent meta rather than shrinking it. */
  .board-row .meta.secondary, .usual { display: none; }
  .reading { padding: 1.2rem 1.1rem 1.15rem; }
  /* Tables tighten their gutters rather than their type: a narrower cell is
     still readable, a smaller number is not. */
  table.ledger th, table.ledger td { padding: .5rem .5rem; }
  table.ledger caption { padding: .7rem .5rem .45rem; }
  .strip-track { height: 2.7rem; }
  .heat th.hr.odd { visibility: hidden; }
  .daychart { height: 6.5rem; gap: 2px; }
  .timeline { gap: 3px; }
  .timeline .leg { height: 3rem; font-size: .9375rem; padding: 0 .3rem .3rem; }
  .timeline .lab { font-size: .625rem; letter-spacing: .04em; }
  .card { padding: 1.15rem 1.05rem; }
  .grid12 { gap: .95rem; }
}

/* --------------------------------------------------------- ferries ------ */
/* A ferry page carries NO wait-minutes, so the delay ramp (.d-*) never appears
   on one. Its two instruments are catchability (a time: can you still make this
   sailing?) and vehicle capacity (availability: is there car space?), neither a
   delay. They take these classes, kept deliberately separate from .d-* so the
   status ramp stays reserved for a value that IS a delay. All colours name
   themselves, on the paper cards these live on. */
.sailings .value {
  font-family: var(--font-sign); text-transform: uppercase;
  letter-spacing: .04em; font-size: .9rem; white-space: nowrap;
  font-weight: 600;
}
.sailings .s-time { font-variant-numeric: tabular-nums; font-size: 1rem; }
.s-open      { color: var(--clear); }
.s-go        { color: var(--ink); font-weight: 700; }
.s-gone      { color: var(--ink-3); }
.cap-open    { color: var(--clear); }
.cap-limited { color: var(--moderate); }
.cap-full    { color: var(--heavy); font-weight: 600; }
.ledger.sched td { white-space: nowrap; }
.ledger.sched .secondary { color: var(--ink-3); }

@media print {
  header.site, footer.site, .site-nav, .searchbox, .controls { display: none; }
  body { background: #fff; color: #000; }
  .card, .reading, .board, .figure-panel, table.ledger { box-shadow: none; }
}
