/* ==========================================================================
   LiveWaits design system -- "wayfinding". Ported from the scratchpad design
   mockups (airport-v2 / ferry-border-v2 and the calc/home/hub rounds) into
   production on 2026-08-25, REPLACING the forest-green system that shipped
   2026-08-21.

   HISTORY, so the port is not silently undone again: this file previously
   carried a dark system -- #0E2B20 ground, Big Shoulders Display uppercase,
   one pop-yellow accent, cream/paper/panel cards. The owner ran many rounds
   of redesign in scratchpad artifacts and settled on the wayfinding system
   below; this file is where that design ships. The class names, ids, and the
   .d-* ramp vocabulary are UNCHANGED from the old file on purpose -- the JS
   (board.js, hub.js, leaveby.js, ...) and the seven quality gates address the
   markup by those names, so the redesign is a reskin over the same structure,
   not a rename. Do not rename a class here without updating the JS and gates.

   THE SYSTEM (wayfinding)

   The ground is cool paper. #E8EAEF fills the page -- a light neutral biased a
   hair toward the transit-blue accent, so it reads as chosen rather than a dead
   gray. Everything else is a WHITE card sitting on that ground: fill, not
   outline, does the separating. One light theme, a daytime departures board.

   Type is two faces. IBM Plex Sans for everything read as words -- headings
   (bold, sentence case, NOT uppercase) and body. IBM Plex Mono, tabular, for
   anything that is a measured value: a wait, a time, a code, a count. A number
   should look like an instrument reading.

   Card fill: one job -- WHITE data cards on the cool ground. The old three-fill
   list (paper/cream/panel) collapses to one: the headline card is no longer a
   separate cream fill, and the "result" panel is a white card marked by a
   transit-blue left edge instead of a dark fill.

   Status ramp: one job, unchanged in vocabulary. Color encodes delay ONLY on
   an element whose value IS a measured or modeled delay. .d-clear green,
   .d-moderate amber, .d-heavy red, .d-closed gray. There is now ONE ground
   (light), so the .on-dark half maps to the same light values -- the vocabulary
   is kept so the JS/gates that reference it still resolve. A count is not a
   delay and takes no ramp. The accent (transit blue) is separate from the ramp:
   it is for the answer, links, and controls, never for a delay.

   HAZARD kept from the old file: any rule that paints a background names its own
   color, and [hidden] must beat the staged-answer cards' display rules. Both
   are asserted below and both broke real builds before.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap');

:root {
  --ground:   #E8EAEF;   /* cool paper. the page. */
  --paper:    #FFFFFF;   /* the card */
  --panel:    #FFFFFF;   /* the result card (marked by a blue left edge) */
  --cream:    #FFFFFF;   /* headline card is fill-only now, kept as a token */
  --sink:     #EDEFF3;   /* a recessed well inside a white card */

  --ink:      #181A1E;
  --ink-2:    #5B616B;
  --ink-3:    #72787F;   /* muted, but dark enough to clear 3:1 on the cool ground */

  --pop:      #1C56C9;   /* transit blue: the answer, links, controls, hover */
  --heat:     #C0432A;   /* heatmap high end: busiest cell. mixed toward --paper */

  /* Instrument ramp. One ground now, so both halves share these values. */
  --clear:    #0E8A4A;
  --moderate: #B7710F;
  --heavy:    #CC3627;

  --rev-clear:    #0E8A4A;
  --rev-moderate: #B7710F;
  --rev-heavy:    #CC3627;

  --rule:      rgb(17 18 17 / .10);
  --rule-firm: rgb(17 18 17 / .16);
  --rule-rev:  rgb(17 18 17 / .10);

  --measure: 44rem;   /* prose */
  --wide:    64rem;   /* boards and instruments */
  --control-h: 3rem;

  --card-shadow: 0 1px 2px rgb(20 28 45 / .08), 0 6px 18px -8px rgb(20 28 45 / .22);
  --card-edge: 1px solid rgb(17 18 17 / .07);

  --font-sign: 'IBM Plex Sans', system-ui, 'Segoe UI', Arial, sans-serif;
  --font-body: 'IBM Plex Sans', system-ui, 'Segoe UI', Arial, sans-serif;
  --font-data: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Menlo, monospace;
}

/* --------------------------------------------------------------- reset -- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  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: none; text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--pop); }
:focus-visible { outline: 2px solid var(--pop); outline-offset: 2px; }

/* --------------------------------------------------------------- type --- */
/* Headings are Plex Sans, bold, SENTENCE case -- the wayfinding face does not
   shout in caps. Micro-labels (field labels, column heads, the tiny section
   slug tier) keep a small uppercase for the data-label feel, in Plex Sans so
   they read as clean captions, not the mono-uppercase look the owner flagged. */
h1, h2, h3, .display {
  font-family: var(--font-sign);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.05;
  text-wrap: balance;
  color: var(--ink);
}
h1 {
  font-size: clamp(1.7rem, 6vw, 2.6rem);
  line-height: 1.04; letter-spacing: -.03em;
  margin: 0 0 .3em;
}
h2 { font-size: clamp(1.25rem, 3.4vw, 1.55rem); margin: 2.4rem 0 .6rem; }
h3 { font-size: 1.0625rem; margin: 1.7rem 0 .35rem; }

.slug, .fld-label, th, .k {
  font-family: var(--font-sign);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.2;
}

/* 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; }

.eyebrow {
  font-family: var(--font-body); font-weight: 600;
  letter-spacing: 0; font-size: .875rem; color: var(--ink-2); margin: 0 0 .55rem;
}
h1.h1-cream { color: var(--ink); font-size: clamp(1.9rem, 6.5vw, 3rem);
              line-height: 1.03; letter-spacing: -.03em; }
.reading > .cream-h2 {
  font-size: clamp(1.5rem, 4.6vw, 2rem); line-height: 1.05; letter-spacing: -.02em;
  color: var(--ink); margin: 0 0 .6rem; padding: 0; border: 0;
}
.linkout.dark a { color: var(--pop); }
.linkout.dark a:hover { color: var(--pop); }
.linkout.light a { color: var(--pop); }
.linkout.light a:hover { color: var(--pop); }
/* The result panel and home's delayed list are white cards now, so their row
   rules and notes take ink, not paper. */
.card-panel .rows > li { border-bottom-color: var(--rule); }
.card-panel .rows .why, .card-panel .note { color: var(--ink-3); }
.card-panel .rows .nm a { color: var(--ink); }
.card-panel .rows .nm a:hover { color: var(--pop); }
.card-panel .val .unit { color: var(--ink-3); }

.standfirst {
  color: var(--ink-2);
  font-size: 1.0625rem; max-width: 46rem; 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.
   probe_theme enforces the shared left edge + the 1.1rem content padding. */
.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: a white fill on the cool ground. Fill, not outline, does
   the separating. */
.card, .reading, .figure-panel, .board, table.ledger, .controls, .lede-grid,
.strip {
  border-radius: 6px;
  box-shadow: var(--card-shadow);
  background: var(--paper);
  color: var(--ink);
  margin: 0 0 1.15rem;
}
.card-cream, .reading { background: var(--paper); color: var(--ink); }
/* The result-on-the-board: a white card marked by a transit-blue left edge,
   the wayfinding "answer plate", not a dark fill. */
.card-panel {
  background: var(--paper); color: var(--ink);
  border-left: 5px solid var(--pop);
}

/* An element that paints a background names its own color. */
.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); border-bottom: 1px solid var(--rule); }
.site-bar {
  display: flex; align-items: center; gap: 1rem;
  max-width: var(--measure); margin: 0 auto; padding: .95rem 1.1rem;
}
.wordmark {
  font-family: var(--font-sign); font-weight: 700;
  letter-spacing: -.02em; font-size: 1.3rem; line-height: 1;
  text-decoration: none; white-space: nowrap;
}
.wordmark:hover { color: inherit; }
.site-nav {
  display: flex; gap: 1.15rem; margin-left: auto;
  font-family: var(--font-body); font-weight: 600;
  letter-spacing: 0; font-size: .9375rem;
}
.site-nav a { color: var(--ink-2); text-decoration: none; }
.site-nav a:hover { color: var(--ink); }
.site-nav a[aria-current] { color: var(--ink); box-shadow: inset 0 -2px 0 var(--pop); padding-bottom: 3px; }

footer.site {
  margin-top: 3.5rem; border-top: 1px solid var(--rule);
  padding: 1.5rem 0 3rem;
  color: var(--ink-3); font-size: .8125rem;
}

footer.site a { color: var(--ink-2); }
footer.site a:hover { color: var(--pop); }

.crumbs {
  font-family: var(--font-body); font-weight: 500;
  letter-spacing: 0; font-size: .8125rem;
  color: var(--ink-3); margin: 0 0 .9rem;
}
.crumbs a { color: var(--ink-2); font-weight: 600; }

/* --------------------------------------------------- section title slug -- */
.slug {
  font-size: 1.0625rem; font-weight: 700; letter-spacing: -.01em;
  color: var(--ink);
  margin: 2rem 0 .7rem;
}
.card > .slug, .board-head .slug { color: var(--ink); margin: 0; }

/* ------------------------------------------------------ the board row --- */
/* One grammar for every repeating list: airports, crossings, lanes, hours,
   sailings. Name left, value right in tabular figures, hairline under each. */
.board { list-style: none; margin: 0 0 1.15rem; padding: 0 .25rem .35rem; }

.board-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .75rem; padding: .95rem .85rem .7rem;
  border-bottom: 1px 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;
  letter-spacing: -.01em; font-size: 1.0625rem; line-height: 1.15;
  color: var(--ink); text-decoration: none;
}
.board-row .name a:hover { color: var(--pop); 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);
}
.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;
  font-family: var(--font-data);
}
.usual.head {
  font-family: var(--font-body); font-weight: 600; text-transform: none;
  letter-spacing: 0; font-size: .8125rem; 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.3rem; line-height: 1;
  white-space: nowrap; font-variant-numeric: tabular-nums;
  font-family: var(--font-data);
}
.board-row .value .unit {
  color: var(--ink-3); font-size: .6875rem; font-weight: 400;
  margin-left: .2rem; font-family: var(--font-body);
}
/* The ranked bar: length = wait, color = the delay ramp, reusing the shared
   .bar-track / .bar-fill grammar. hub.js re-sizes it against the busiest
   airport at the visitor's instant; the baked width is the no-JS baseline. */
.board-row .row-bar { height: 4px; margin: .1rem 0 .4rem; max-width: 22rem; }
.board-row .rtime { font-family: var(--font-data); }
.board-row .name .dot { color: var(--ink-3); }

/* Delay color lives here and only here. One ground now, both halves equal. */
.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(--clear); }
.on-dark .d-moderate { color: var(--moderate); }
.on-dark .d-heavy    { color: var(--heavy); }
.on-dark .d-closed   { color: var(--ink-3); }

/* ------------------------------------------------- headline reading ----- */
.reading { padding: 1.5rem 1.4rem 1.4rem; }
.reading .label {
  font-family: var(--font-body); font-weight: 600; text-transform: none;
  letter-spacing: 0; font-size: .8125rem; color: var(--ink-2);
  margin: 0;
}
.reading .figure {
  font-family: var(--font-data); font-weight: 700;
  font-size: clamp(3rem, 13vw, 4.6rem); line-height: .9;
  letter-spacing: -.03em;
  display: block; margin: .35rem 0 .1rem;
  font-variant-numeric: tabular-nums;
}
.reading .figure.is-text {
  font-size: clamp(1.7rem, 6vw, 2.3rem); line-height: 1.02; letter-spacing: -.02em;
  font-family: var(--font-sign);
}
.reading .figure .unit {
  font-size: .28em; font-weight: 600; letter-spacing: 0;
  color: var(--ink-2); margin-left: .12em; font-family: var(--font-body);
}
.reading .sub { color: var(--ink-2); 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: 0;
  color: var(--ink-2); margin: 0; font-family: var(--font-body);
}
.lede-grid .v {
  font-family: var(--font-data); font-weight: 700; font-size: 1.6rem;
  line-height: 1; margin: .5rem 0 .4rem; font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.lede-grid .note { margin: 0; }

/* ============================================================ SIGNATURE ==
   The leave-by strip: the answer AND its own reasoning, each leg of the
   journey drawn to scale. HTML track, not SVG. ======================== */
.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-data); font-weight: 700;
  font-size: 1.3rem; line-height: 1; color: var(--ink); letter-spacing: -.02em;
}
.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 var(--paper);
  font-size: .75rem; font-weight: 600; color: var(--ink-2);
  white-space: nowrap; overflow: hidden;
  font-family: var(--font-data);
  transition: flex-basis .25s ease;
}
.strip-seg:last-child { border-right: 0; }
.strip-seg.is-wait { background: var(--moderate); color: #fff; font-weight: 700; }
.strip-seg.is-buffer {
  background: repeating-linear-gradient(
    135deg, transparent 0 5px, rgb(17 18 17 / .07) 5px 10px);
}
.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); font-family: var(--font-data); }

@media (prefers-reduced-motion: reduce) { .strip-seg { transition: none; } }

/* ------------------------------------------------------- hour heatmap --- */
/* The measured half of the model: departures per hour, every weekday. The
   cell fill is a template-side color-mix over var(--ground); with a light
   ground the ramp reads shorter->paper, longer->deep. */
.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-data); font-weight: 500; font-size: .6875rem;
  letter-spacing: 0; color: var(--ink-3); text-align: center;
  padding-bottom: .25rem;
}
.heat th.dy {
  font-family: var(--font-body); font-weight: 600; font-size: .75rem;
  letter-spacing: 0; 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: .6875rem; letter-spacing: .06em; text-transform: uppercase;
  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: 700;
  font-family: var(--font-data);
}
table.ledger th.num { font-family: var(--font-body); 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-body); font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; font-size: .6875rem; 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: .9375rem; line-height: 1.2;
  padding: 0 .8rem; border: 1px solid var(--rule-firm); 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(--pop); outline-offset: 2px; border-color: var(--pop);
}
.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(--pop); 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-body); font-weight: 700; text-transform: none;
  letter-spacing: 0; font-size: .9375rem; line-height: 1;
  padding: 0 1.4rem; border: 0; border-radius: 4px; cursor: pointer;
  white-space: nowrap; background: var(--pop); color: #fff;
  transition: background-color .15s ease;
}
.btn:hover { background: #1848a8; color: #fff; }

/* -------------------------------------------------------- typeahead ----- */
.searchbox { position: relative; margin: 1.4rem 0 1.9rem; max-width: 34rem; }
.searchbox .fld-label { color: var(--ink-2); margin-bottom: .45rem; }
.searchbox input {
  width: 100%; height: var(--control-h);
  font: inherit; font-size: .9375rem; padding: 0 .8rem;
  border: 1px solid var(--rule-firm); border-radius: 4px;
  background: var(--paper); color: var(--ink);
}
.searchbox input:focus { outline: 2px solid var(--pop); outline-offset: 2px; border-color: var(--pop); }
.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: 1px solid var(--rule-firm); border-radius: 4px;
  box-shadow: 0 14px 30px -12px rgb(20 28 45 / .3);
}
.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(--sink); color: var(--ink);
}
.results .code {
  font-family: var(--font-data); font-weight: 700; letter-spacing: 0;
  color: var(--ink-2);
}

/* ------------------------------------------------------------- source --- */
.source {
  color: var(--ink-3); font-size: .8125rem; line-height: 1.5;
  max-width: 44rem; margin: 1.4rem 0 0;
}
.source a { color: var(--ink-2); font-weight: 600; }

/* ============================================================== grid ==
   Cards sit on a twelve column field: 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; }
}
.grid12 > .card, .grid12 > .reading { display: flex; flex-direction: column; }
.pin { margin-top: auto; padding-top: 1rem; }
.grid12 > .card > .rows { flex: 1 1 auto; }

.card { padding: 1.3rem 1.25rem; }
/* A heading inside a card is the card's own title, sits in a header band with
   a hairline under it. */
.card > h2 {
  margin: 0 0 .9rem; padding-bottom: .55rem;
  border-bottom: 1px solid var(--rule); font-size: 1.0625rem; letter-spacing: -.01em;
}
.card > h2 + p { margin-top: 0; }
.card p { margin: .7rem 0 0; }
.card > p:first-child { margin-top: 0; }

/* -------------------------------------------------------- status band --- */
.band { display: grid; gap: 1.1rem 2.2rem; }
@media (min-width: 34rem) { .band { grid-template-columns: auto 1fr; } }
.band .lede {
  font-family: var(--font-body); font-weight: 600; text-transform: none;
  letter-spacing: 0; font-size: .8125rem; color: var(--ink-2);
  margin: 0;
}
.band .fig {
  font-family: var(--font-data); font-weight: 700; line-height: .9;
  font-size: clamp(3.2rem, 15vw, 5rem); letter-spacing: -.03em;
  margin: .5rem 0 0; display: inline-flex; align-items: baseline; gap: .1em;
  font-variant-numeric: tabular-nums;
}
.band .fig .unit {
  font-size: .26em; font-weight: 600; text-transform: none;
  letter-spacing: 0; color: var(--ink-2); font-family: var(--font-body);
}
.band .say { color: var(--ink-2); font-size: .9375rem; line-height: 1.6; }
@media (min-width: 34rem) {
  .band .right { border-left: 1px solid var(--rule); padding-left: 2.2rem; }
}
.band-foot {
  margin-top: 1.2rem; padding-top: .9rem;
  border-top: 1px solid var(--rule);
  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: var(--ink-3); font-size: .8125rem; flex: 0 0 auto;
                    font-family: var(--font-data); }

/* The trend sparkline: the last seven hours of this airport's own curve. */
.spark { display: flex; align-items: flex-end; gap: 5px; height: 3rem; width: 9.5rem;
         margin: 1.1rem 0 0; }
.spark i { flex: 1; border-radius: 2px 2px 0 0; background: rgb(17 18 17 / .14); }
.spark i.is-now { background: var(--pop); }
.spark-note { color: var(--ink-2); font-size: .8125rem; margin: .5rem 0 0; }

/* Provenance, not delay: measured/modeled takes NO ramp color. Measured is
   the transit-blue accent (a fresh feed is driving the figure); modeled is a
   quiet outline. */
.feed-badge {
  display: inline-block; vertical-align: middle; margin-left: .5rem;
  font-family: var(--font-body); font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; font-size: .6875rem; line-height: 1;
  padding: .3em .5em; border-radius: 3px;
  border: 1px solid var(--rule-firm); color: var(--ink-2);
}
.feed-badge.is-measured {
  background: var(--pop); color: #fff; border-color: var(--pop);
}
.feed-stamp {
  color: var(--ink-2); font-size: .8125rem; margin: .5rem 0 0;
  font-variant-numeric: tabular-nums; font-family: var(--font-data);
}

/* ------------------------------------------------------------- bars ----- */
.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: none;
  letter-spacing: -.01em; font-size: 1.0625rem; line-height: 1.1;
}
.rows .nm a { color: inherit; text-decoration: none; }
.rows .nm a:hover { color: var(--pop); text-decoration: underline; }
.rows .val {
  flex: 0 0 auto; font-weight: 700; font-size: 1.6rem; line-height: 1;
  font-variant-numeric: tabular-nums; font-family: var(--font-data);
  letter-spacing: -.02em;
}
.rows .val .unit { font-size: .6875rem; font-weight: 400; color: var(--ink-3);
                   margin-left: .2rem; font-family: var(--font-body); }
.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: 3px; background: rgb(17 18 17 / .08);
             margin-top: .6rem; overflow: hidden; }
.bar-fill { display: block; height: 100%; border-radius: 3px; }
.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: .9375rem; }
.rows.mini .val { font-size: 1.3rem; }
.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; }

.linkout {
  font-family: var(--font-body); font-weight: 600; text-transform: none;
  letter-spacing: 0; font-size: .875rem;
}
.linkout a { color: var(--pop); text-decoration: none; }
.linkout a:hover { text-decoration: underline; color: var(--pop); }

.linkbtn {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--pop); text-decoration: underline; text-underline-offset: 3px;
}
.linkbtn:hover { color: var(--ink); }

/* -------------------------------------------------------- day chart ----- */
/* Twenty four hours of today. The blue bar is now; the amber bar is the hour
   the traveler actually reaches the checkpoint. */
.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 / .16); }
.daychart i.is-now { background: var(--pop); }
.daychart i.is-you { background: var(--moderate); }
.daykey {
  display: flex; justify-content: space-between; margin: .5rem 0 0;
  font-family: var(--font-data); font-weight: 500; text-transform: none;
  letter-spacing: 0; font-size: .6875rem; color: var(--ink-3);
}

/* ------------------------------------------------- the answer, staged --- */
/* Before the traveler has said anything the answer slot holds a placeholder.
   A dashed light card, the one surface deliberately not a filled card. */
.slot-empty {
  border: 2px dashed var(--rule-firm); border-radius: 6px;
  background: var(--sink); color: var(--ink);
  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-data); font-weight: 700; line-height: .9;
  font-size: clamp(2.4rem, 10vw, 3.6rem); color: rgb(17 18 17 / .22);
  margin: 0; user-select: none;
}
.slot-empty p { margin: 0; color: var(--ink-2); font-size: .9375rem;
                line-height: 1.6; }

.result-label {
  font-family: var(--font-body); font-weight: 600; text-transform: uppercase;
  letter-spacing: .1em; font-size: .75rem; color: var(--ink-2); margin: 0;
}
.result-time {
  font-family: var(--font-data); font-weight: 700; line-height: .9;
  font-size: clamp(2.6rem, 11vw, 4rem); color: var(--pop);
  margin: .5rem 0 0; display: inline-flex; align-items: baseline; gap: .06em;
  font-variant-numeric: tabular-nums; letter-spacing: -.03em;
}
.result-time .mer { font-size: .34em; text-transform: none; letter-spacing: 0;
                    font-family: var(--font-body); font-weight: 600; }
.card-panel .note { color: var(--ink-2); }
.card-panel a { color: var(--pop); }

/* The timeline reads as separate legs with their own labels. */
.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: 4px; background: var(--sink); color: var(--ink-2);
  display: flex; align-items: flex-end; padding: 0 .5rem .4rem;
  font-weight: 700; font-size: 1.0625rem; line-height: 1;
  font-variant-numeric: tabular-nums; overflow: hidden; font-family: var(--font-data);
}
.timeline .leg.is-hot { background: var(--moderate); color: #fff; }
.timeline .lab {
  display: block; margin-top: .45rem;
  font-family: var(--font-body); font-weight: 600; text-transform: none;
  letter-spacing: 0; 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;
                      font-family: var(--font-data); }

@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 --- */
.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 transit blue, the noun in ink. */
.wordmark .w-live { color: var(--pop); }
.wordmark .w-waits { color: var(--ink); }
.wordmark:hover .w-live { color: var(--pop); }
.wordmark:hover .w-waits { color: var(--ink); }
.site-clock {
  margin-left: auto;
  font-family: var(--font-body); font-weight: 500; text-transform: none;
  letter-spacing: 0; 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-body); font-weight: 500; text-transform: none;
  letter-spacing: 0; font-size: .8125rem; color: var(--ink-3);
  margin: 0 0 .9rem;
}

/* Browse-by-state / metro index on the national hub. */
.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(--pop); }
.browse-n { color: var(--ink-3); font-size: .8125rem; font-weight: 400;
            font-variant-numeric: tabular-nums; font-family: var(--font-data); }

/* The server-rendered worked example: a real answer for crawlers and no-JS
   readers, distinct from the interactive result below it. */
.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;
}

/* ---- terminal schematic map -------------------------------------------- */
/* A legible schematic drawn server-side from real OSM gate coordinates. Every
   painted element names its own color. */
.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 / .10); 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(--pop); 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(--pop); border-radius: 2px; }

/* One breakpoint, one discipline: below it every surface shows FEWER facts,
   never smaller facts. */
@media (max-width: 34rem) {
  body { font-size: .9375rem; }
  .wrap, .wrap-wide { padding-top: 1.6rem; }
  .site-bar { padding: .7rem 1.1rem; flex-wrap: wrap; row-gap: .35rem; }
  .site-nav { gap: .7rem; font-size: .875rem; letter-spacing: 0; }
  .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; }
  .board-row .meta.secondary, .usual { display: none; }
  .reading { padding: 1.2rem 1.1rem 1.15rem; }
  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: .6875rem; letter-spacing: 0; }
  .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 instruments are catchability (a time) and vehicle capacity,
   neither a delay; they take their own classes, kept separate from .d-*. */
.sailings .value {
  font-family: var(--font-body); text-transform: none;
  letter-spacing: 0; font-size: .875rem; white-space: nowrap;
  font-weight: 600;
}
.sailings .s-time { font-variant-numeric: tabular-nums; font-size: .9375rem;
                    font-family: var(--font-data); }
.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; }

/* Live departure delay chip (measured, from AeroDataBox). Populated by
   delays.js; hidden until real data arrives. A measured signal, so it carries
   the delay ramp on its own value like any other real reading. */
.delaychip { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 10px;
             margin: 14px 0 0; font-size: .875rem; }
.delaychip .dot { width: 8px; height: 8px; border-radius: 50%;
                  align-self: center; background: var(--ink-3); }
.delaychip .dot.d-clear { background: var(--clear); }
.delaychip .dot.d-moderate { background: var(--moderate); }
.delaychip .dot.d-heavy { background: var(--heavy); }
.delaychip .meta { color: var(--ink-2); font-family: var(--font-data);
                   font-size: .8125rem; }

/* Ferry service alerts. Informational bulletins (baked, fetch-stamped); a
   disruption gets the heavy accent, everything else the neutral card. */
.svcalerts { background: var(--paper); border-radius: 6px; box-shadow: var(--card-shadow);
             border-left: 4px solid var(--moderate);
             padding: clamp(14px, 2vw, 18px); margin: 0 0 1.15rem; }
.svcalerts .svchead { font-weight: 700; font-size: .9375rem;
                      margin-bottom: 10px; }
.svcalerts .alertlist { list-style: none; margin: 0; padding: 0;
                        display: grid; gap: 8px; }
.svcalerts .alertlist li { font-size: .875rem; line-height: 1.4;
                           padding-left: 14px; position: relative; }
.svcalerts .alertlist li::before { content: ""; position: absolute;
    left: 0; top: .5em; width: 6px; height: 6px; border-radius: 50%;
    background: var(--moderate); }
.svcalerts .alertlist li.disrupt::before { background: var(--heavy); }
.svcalerts .alertlist li.disrupt { font-weight: 600; }
.svcalerts .note { margin: 12px 0 0; }

/* "Which sailings fill up" -- TYPICAL car-deck fullness by sailing. The bar
   fill takes the cap-* capacity ramp (a full deck is a capacity reading, not a
   delay, so it never takes the .d-* delay ramp). */
.crowd { display: grid; gap: 9px; }
.crow  { display: grid; grid-template-columns: 72px 1fr 46px;
         align-items: center; gap: 12px; font-size: .8125rem; }
.crow .ct { color: var(--ink-2); font-family: var(--font-data); }
/* Homepage thin-bar standard: 7px pill, capacity ramp (a full deck is capacity). */
.crow .cbar { height: 7px; background: var(--sink);
              border-radius: 99px; overflow: hidden; }
.crow .cbar i { display: block; height: 100%; border-radius: 99px; }
.crow .cbar i.cap-open    { background: var(--clear); }
.crow .cbar i.cap-limited { background: var(--moderate); }
.crow .cbar i.cap-full    { background: var(--heavy); }
.crow .cv { text-align: right; font-weight: 700; font-family: var(--font-data); }
/* Capacity-ramp fills for the shared thin bar (.slim), used by the gauge. */
.slim i.cap-open    { background: var(--clear); }
.slim i.cap-limited { background: var(--moderate); }
.slim i.cap-full    { background: var(--heavy); }
.ledger.sched td { white-space: nowrap; }
.ledger.sched .secondary { color: var(--ink-3); }
.ledger.fares td.num { font-family: var(--font-data); white-space: nowrap; }

/* Ferry drive-up gauge (label + the shared thin bar) + terminal details. */
.gaugelab { font-size: .9375rem; font-weight: 700; margin: 0 0 .4rem;
            font-family: var(--font-sign); }
.gaugelab b { font-weight: 700; }
.gauge .slim { margin: 0; }
.gaugenote { margin: .6rem 0 0; color: var(--ink-2); font-size: .9375rem; }
.gaugenote b { color: var(--ink); }
.terminfo { display: grid; gap: 0; }
.terminfo .trow { display: grid; gap: .12rem; padding: .7rem 0;
                  border-top: 1px solid var(--rule); }
.terminfo .trow:first-child { border-top: 0; padding-top: 0; }
.terminfo .trow b { font-family: var(--font-sign); font-weight: 700; font-size: .9375rem; }
.terminfo .trow .addr { font-size: .8125rem; color: var(--ink-2); }
.terminfo .trow .park { color: var(--ink-3); font-size: .8125rem; }

/* --------------------------------------------------- border crossing ---- */
/* Status band: the headline reading beside the live per-lane tiles. The tiles
   are leaveby.js's live targets; their inner .value carries the ramp color. */
/* Rendered inside a .titled card (final mockup .bband): a centred headline
   reading with a divider, beside the live per-lane tiles. #pv-figure keeps the
   .figure class leaveby.js rewrites; the tiles' inner .value carries the ramp. */
.statusband .bband { display: grid; grid-template-columns: minmax(150px, 210px) 1fr;
  gap: 1.4rem; align-items: stretch; }
.statusband .bb-main { display: flex; flex-direction: column; gap: 3px;
  justify-content: center; align-items: center; text-align: center;
  min-width: 150px; padding-right: 1.4rem; border-right: 1px solid var(--rule); }
.statusband .bb-main .figure { font-family: var(--font-data); font-weight: 700;
  font-size: clamp(2.8rem, 7vw, 3.4rem); line-height: .9; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; }
/* A text status ("Update Pending" / "Closed") is not a number: render it small
   so it does not blow up the figure column and stack the lane tiles vertically
   (d-closed is only ever set when there is no numeric reading). */
.statusband .bb-main .figure.d-closed { font-size: 1.3rem; line-height: 1.15;
  letter-spacing: 0; }
.statusband .bb-main .figure .unit { font-size: .28em; font-weight: 600;
  color: var(--ink-2); margin-left: .12em; font-family: var(--font-body); }
.statusband .bb-main .label { font-family: var(--font-body); font-weight: 600;
  font-size: .8125rem; color: var(--ink-2); }
.statusband .bb-main .cause { color: var(--heavy); font-weight: 700;
  font-size: .8125rem; margin: .3rem 0 0; }
.statusband .bb-main .sub { color: var(--ink-3); font-size: .75rem; margin: .3rem 0 0; }
.bb-lanes { display: grid; grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
            gap: .5rem; align-content: center; }
.bb-lanes .lanegroup { display: contents; }
.bb-lanes .bl { padding: .7rem .8rem; background: var(--sink); border-radius: 5px; }
/* Reserve two lines for the tile name so a wrapping label (e.g. "Cars ·
   NEXUS/SENTRI") does not push its minutes below the single-line tiles beside
   it -- the numbers read across the row on one baseline. */
.bb-lanes .bn { font-family: var(--font-body); font-weight: 700; font-size: .8125rem;
                color: var(--ink); line-height: 1.25; min-height: 2.5em; }
.bb-lanes .bw { margin: .3rem 0 .1rem; }
.bb-lanes .bw .value { font-family: var(--font-data); font-weight: 700; font-size: 1.3rem;
                       line-height: 1; font-variant-numeric: tabular-nums; }
/* A text status in a tile ("Update Pending") reads small so the tile stays the
   height of its numeric neighbours instead of towering over them. */
.bb-lanes .bw .value.d-closed { font-size: .8125rem; line-height: 1.2; }
.bb-lanes .bs { font-size: .75rem; color: var(--ink-3); }

/* Which-lane comparison cards + the mobile Option-B baseline mechanism. */
.lanescmp { display: grid; grid-template-columns: repeat(3, 1fr); gap: .9rem; }
.lanecard { background: var(--sink); border-radius: 6px; padding: .95rem 1rem 1rem;
            display: flex; flex-direction: column; }
/* The card carries fuller copy (cost, fine print) in its title tooltip; hint it. */
.lanecard[title] { cursor: help; }
.lanecard .ltop { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.lanecard .lname { font-family: var(--font-sign); font-weight: 700; font-size: 1.0625rem; }
.lanecard .lbig .value { font-family: var(--font-data); font-weight: 700; font-size: 1.6rem;
                         line-height: 1; font-variant-numeric: tabular-nums; }
.lanecard .ln { color: var(--ink-2); font-size: .875rem; margin: .5rem 0 0; flex: 1 1 auto; }
.lanecard .lfoot { color: var(--ink-3); font-size: .8125rem; margin: .6rem 0 0;
                   font-family: var(--font-data); }
.lanecard .lfoot .dot { color: var(--ink-3); }
/* On wide screens the number stacks UNDER the name (Option A). */
.lanecard.resp .ltop { flex-direction: column; align-items: flex-start; gap: 0; }
.lanecard.resp .lbig { margin-top: .3rem; }

/* This crossing vs its nearest neighbor: two gray wells inside the white
   card, the strictly-faster one ringed green (leaveby.js re-picks it live). */
/* Cards stretch to a shared height; inside each, the name reserves two lines so
   a wrapping name (e.g. "Passenger (Otay Mesa)") does not drop its number below
   the single-line card beside it -- number and subtitle read across on one line. */
.vs { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: stretch; }
.vs .vscard { text-align: center; background: var(--sink); border-radius: 6px;
              padding: 1rem .9rem; display: flex; flex-direction: column;
              justify-content: center; }
.vs .vscard.is-faster { outline: 2px solid var(--clear); outline-offset: -2px; }
.vs .vscard .nm { display: flex; align-items: center; justify-content: center;
                  font-family: var(--font-sign); font-weight: 700;
                  line-height: 1.2; min-height: 2.4em; }
.vs .vscard .v { display: block; font-family: var(--font-data); font-weight: 700;
                 font-size: clamp(2rem, 7vw, 2.6rem); line-height: 1; margin: .2rem 0;
                 font-variant-numeric: tabular-nums; }
.vs .vscard .l { display: block; color: var(--ink-3); font-size: .8125rem; }
.vs .vsmid { align-self: center; color: var(--ink-3); font-weight: 600;
             text-transform: uppercase; font-size: .8125rem; }

/* Documents (static-factual). */
.docs { display: grid; gap: 0; }
.docs .docrow { display: grid; grid-template-columns: 9rem 1fr; gap: .875rem;
                font-size: .8125rem; padding: .56rem 0; border-top: 1px solid var(--rule); }
.docs .docrow:first-child { border-top: 0; }
.docs .who { font-weight: 700; color: var(--ink); }
.docs .what { color: var(--ink-2); }

/* detail-page lead stamp with a live indicator (border/ferry) */
.lead2 + .stamp { margin: .5rem 0 1.1rem; color: var(--ink-3); font-size: .8125rem; }
.stamp .live { display: inline-flex; align-items: center; gap: .45rem; }
.stamp .live i { width: 8px; height: 8px; border-radius: 2px; background: var(--clear);
  display: inline-block; }
.stamp .live b { color: var(--ink); font-weight: 700; }

/* Best-time-to-cross chart (baked typical curve). */
.chartwrap { display: flex; gap: .7rem; align-items: stretch; }
.chartwrap .yaxis { display: flex; flex-direction: column; justify-content: space-between;
                    font-size: .6875rem; color: var(--ink-3); font-family: var(--font-data);
                    padding-bottom: 1.1rem; }
.chartwrap .chartmain { flex: 1; min-width: 0; }
.bchart { display: flex; align-items: flex-end; gap: 2px; height: 7rem; }
.bchart i { flex: 1; background: #D3D7DF; border-radius: 2px 2px 0 0;
            min-height: 2px; position: relative; }
/* Current hour: the transit-blue bar, tagged "now" above it, so the reader sees
   where they sit on the typical curve (leaveby.js sets .now client-side). */
.bchart i.now { background: var(--pop); }
.bchart i.now::after { content: "now"; position: absolute; top: -1.15rem; left: 50%;
            transform: translateX(-50%); font-family: var(--font-data);
            font-size: .6875rem; font-weight: 700; color: var(--pop); }
.chartwrap .daxis { display: flex; justify-content: space-between; margin-top: .35rem;
                    font-size: .6875rem; color: var(--ink-3); }

/* FAQ accordion. */
.faq details { border-top: 1px solid var(--rule); }
.faq details:first-of-type { border-top: 0; }
/* The card padding already sets the space above the first question; drop the
   summary's own top padding there so it does not read as a double gap. */
.faq details:first-of-type summary { padding-top: 0; }
.faq summary { cursor: pointer; font-family: var(--font-sign); font-weight: 700;
               font-size: .875rem; padding: .8rem 1.6rem .8rem 0; position: relative;
               list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; position: absolute; right: .2rem; top: .7rem;
                      font-family: var(--font-data); color: var(--ink-3); }
.faq details[open] summary::after { content: "\2013"; }
/* When open, let the answer hug its own question instead of floating midway to
   the next one: drop the summary's bottom padding and the answer's top margin. */
.faq details[open] summary { padding-bottom: .2rem; }
.faq details p { color: var(--ink-2); font-size: .875rem; line-height: 1.55; margin: 0 0 1rem; }

/* Related link groups. Matches the final mockup: no card, ruled rows, small
   uppercase group labels, and links joined by a middot rather than a card. */
.related .relgrp { padding: .875rem 0; border-top: 1px solid var(--rule); }
.related .relgrp:first-of-type { border-top: 0; padding-top: 0; }
.related .relgrp:last-of-type { padding-bottom: 0; }
.related .g { display: block; font-family: var(--font-body); font-weight: 700;
              font-size: .6875rem; color: var(--ink-3); margin-bottom: .5rem;
              text-transform: uppercase; letter-spacing: .07em; }
.related .links { display: flex; flex-wrap: wrap; gap: .625rem; }
.related .links a { font-weight: 600; font-size: .8125rem; color: var(--pop); }
.related .links a:not(:last-child)::after { content: "\00b7"; color: var(--ink-3);
              margin-left: .625rem; font-weight: 400; }

@media (max-width: 34rem) {
  .statusband .bband { grid-template-columns: 1fr; gap: 1rem; }
  .statusband .bb-main { border-right: 0; border-bottom: 1px solid var(--rule);
    padding-right: 0; padding-bottom: 1rem; }
  .lanescmp { grid-template-columns: 1fr; }
  .vs { grid-template-columns: 1fr; }
  .vs .vsmid { display: none; }
  .docs .docrow { grid-template-columns: 1fr; gap: .1rem; }
  /* Option-B: the number drops back onto ONE baseline beside the name. */
  .lanecard.resp .ltop { flex-direction: row; align-items: baseline;
                         justify-content: space-between; gap: 8px; }
  .lanecard.resp .lbig { margin-top: 0; }
  .lanecard.resp .lbig .value { font-size: 1.3rem; }
}

/* ------------------------------------------ airport detail (wayfinding) -- */
/* The structural port of the airport page. Reuses the shared vocabulary
   (.reading, .spark, .feed-badge, .rows, .bar-fill, .daychart, .chartwrap,
   .faq, .related) and adds the page's own composition classes below. The
   mock's s-star / bg-star ramp is folded into the site .d-* ramp: color still
   means delay, and only on an element whose value IS a delay. */

/* Two-up field for the section pairs, and the shared block/titled cards. */
/* Cards size to their own content (align-items:start) so a short card next to a
   tall one no longer stretches into an ugly void of whitespace + orphaned text. */
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.15rem;
         align-items: start; margin: 0 0 1.15rem; }
.grid2 > * { margin-bottom: 0; min-width: 0; }
.grid2 > .sect { display: flex; flex-direction: column; gap: .6rem; }
.grid2 > .sect > .block, .grid2 > .sect > .titled { flex: 1 1 auto; margin-bottom: 0; }
.grid2 .sect > h2 { margin: 0 0 .2rem; }
.block { background: var(--paper); border-radius: 6px; box-shadow: var(--card-shadow);
         padding: 1.15rem 1.2rem; margin: 0 0 1.15rem; }
/* Card-grid board: no outer panel, so the cards sit on the ground and read as
   distinct cards rather than white-on-white inside a panel. */
.block.cardsblock { background: transparent; box-shadow: none; border: 0; padding: 0; }
.block.cardsblock .boardhead { padding: 0 .1rem; }
.titled { background: var(--paper); border-radius: 6px; box-shadow: var(--card-shadow);
          overflow: hidden; display: flex; flex-direction: column; margin: 0 0 1.15rem; }
.cardtitle { font-family: var(--font-sign); font-weight: 700; font-size: .9375rem;
             padding: .8rem 1.1rem; border-bottom: 1px solid var(--rule); }
.cardtitle .ctsub { font-weight: 500; color: var(--ink-3); font-size: .75rem; }
.cardtitle .ctsub::before { content: "·"; margin: 0 .4rem 0 .5rem; color: var(--ink-3); }
.cardbody { padding: 1.1rem; flex: 1 1 auto; display: flex; flex-direction: column; }
/* A .prose subtitle/intro under a heading owns the gap to the content below it,
   in one place (this was applied inconsistently: the terminals subtitle butted
   its card). The tighter title->subtitle gap is owned by `h2 + p` above. */
.prose { color: var(--ink-2); font-size: .9375rem; line-height: 1.55; margin: 0 0 .9rem; max-width: 64rem; }
.prose b { color: var(--ink); font-weight: 700; }

/* D -- lead paragraph, in a desktop and a phone form. */
.lead2 { color: var(--ink-2); font-size: 1.0625rem; line-height: 1.55; max-width: 64rem;
         margin: .2rem 0 .3rem; }
.lead2 b { color: var(--ink); font-weight: 700; }
.stampline { margin: 0 0 1.15rem; }
.mtxt { display: none; }

/* E -- hero, three centered thirds with dividers. Sits on .reading, so it keeps
   the card treatment; its own padding/grid win over the .reading defaults. */
.hero3 { display: grid; grid-template-columns: repeat(3, 1fr); padding: 0; gap: 0; }
.hero3 > div { padding: 1.4rem 1.2rem; display: flex; flex-direction: column;
               align-items: center; justify-content: center; gap: .5rem;
               text-align: center; border-left: 1px solid var(--rule); }
.hero3 > div:first-child { border-left: 0; }
.hero3 .h3lab { color: var(--ink-3); font-size: .8125rem; margin: 0; }
.hero3 .h3num { display: flex; align-items: baseline; gap: .3rem; margin: 0; }
.hero3 .h3num .n { font-family: var(--font-data); font-weight: 700; font-size: 2.2rem;
                   line-height: .9; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.hero3 .h3num .u { font-size: .8125rem; color: var(--ink-2); font-weight: 600; }
.hero3 .feed-badge { margin-left: 0; }
.hero3 .feed-stamp { margin-top: .2rem; }
.hero3 .spark { margin: 0 auto; width: 100%; max-width: 13rem; }
.hero3 .bandline { color: var(--ink-2); font-size: .8125rem; margin: 0; }
.hero3 .bandline b { color: var(--ink); font-weight: 700; }
.hero3 .bandline.muted { color: var(--ink-3); }
.hero3 .h3title { font-family: var(--font-sign); font-weight: 700; font-size: .8125rem;
                  margin: 0 auto .3rem; padding-bottom: .45rem;
                  border-bottom: 1px solid var(--rule); width: 100%; max-width: 11rem; }
/* The glance lanes keep prod's .rows.mini markup (so the JS reader + the "lane
   cards agree" probe resolve); the hero just shows a cleaner two-column row. */
.lanemini { width: 100%; max-width: 12rem; margin: 0; }
.lanemini > li { padding: .3rem 0; border-bottom: 0; }
.lanemini .top { gap: .6rem; }
.lanemini .nm { font-size: .9375rem; }
.lanemini .val { font-size: 1.0625rem; }
.lanemini .with { display: none; }

/* G -- today's chart (reuses .chartwrap/.daychart) + the by-day ranking. */
.chartwrap .chartmain .daychart { margin-top: 0; }
.rank { display: flex; flex-direction: column; gap: .1rem; }
.rank.fill { flex: 1 1 auto; justify-content: space-between; }
.rrow { display: grid; grid-template-columns: 3.6rem 1fr auto; align-items: center;
        gap: .7rem; padding: .5rem 0; border-top: 1px solid var(--rule); }
.rrow:first-child { border-top: 0; }
/* Home board: widen the code+city column so multi-word city subtitles
   (Dallas/Fort Worth, Salt Lake City) hold one line -- the status bar takes
   the rest. Scoped to the hero so the hub/ferry boards keep their own widths. */
.hero .rrow { grid-template-columns: 7.25rem 1fr auto; }
/* Nearby-airports card: same idea -- widen the code+city column and compress
   the thin bar so a city name under the code (Long Beach, San Diego) shows in
   full. Only the rows that carry a .barB (nearby), not the day-rank (Mon/Tue). */
.rank.fill .rrow:has(.barB) { grid-template-columns: 8.5rem 1fr auto; }
.rc { font-family: var(--font-sign); font-weight: 700; font-size: .875rem; }
.rc a { color: inherit; text-decoration: none; white-space: nowrap; }
.rc a:hover { color: var(--pop); }
.rc small { display: block; font-weight: 500; font-size: .6875rem; color: var(--ink-3);
            font-family: var(--font-body);
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Home board bar (bug 2): the label lifts OUT of the bar to its own line in
   ink, and the bar becomes a slim ramp-colored meter on a light track. This
   replaced the dark #4b5563 slate track, which existed only so a white in-bar
   label could read past a short fill -- with the label gone from inside the
   bar, the slate has no job and read as a heavy dark slab. */
.barB { min-width: 0; }
/* The label is name + local time on one line. The time is pinned (flex:none) so
   a long name (bug 26: "Ronald Reagan Washington National") ellipsizes the NAME
   and never clips the time. */
.barB .lab { display: flex; align-items: baseline; gap: .3rem;
             font-size: .75rem; color: var(--ink); font-weight: 600; margin-bottom: .28rem; }
.barB .lab .rnm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The nearby-airports board keeps name + miles on ONE line: the name ellipsizes
   and the miles are pinned (flex:none on .rloc), so a long name like SUX's never
   pushes the distance onto a second line above its bar. */
.rank.fill .barB .lab { flex-wrap: nowrap; }
.barB .lab .rloc { flex: none; white-space: nowrap;
                   color: var(--ink-2); font-weight: 500; font-family: var(--font-data); }
.slim { height: 7px; background: var(--sink); border-radius: 99px; overflow: hidden; }
.slim i { display: block; height: 100%; border-radius: 99px; }
.slim i.d-clear { background: var(--clear); }
.slim i.d-moderate { background: var(--moderate); }
.slim i.d-heavy { background: var(--heavy); }
/* Slate track so the white in-bar label reads over the WHOLE bar, not just the
   colored fill -- a light track stranded the label's tail past a short fill
   (white on near-white). The ramp fill sits on top of the slate. */
/* Thin-bar standard site-wide: 7px pill on a light track, ramp-colored fill,
   the label OUTSIDE the bar (in .rc / .rval) rather than white text inside. */
.rtrack { height: 7px; background: var(--sink); border-radius: 99px;
          overflow: hidden; position: relative; }
.rtrack i { display: block; height: 100%; border-radius: 99px; }
.rtrack i.d-clear { background: var(--clear); }
.rtrack i.d-moderate { background: var(--moderate); }
.rtrack i.d-heavy { background: var(--heavy); }
.rtrack i.d-closed { background: var(--ink-3); }
/* Ferry board: car-deck fullness on the mock's saturated capacity ramp
   (green/amber/red) and a neutral service-frequency bar where WSF publishes no
   deck space. White label on a solid slate track (below), so it stays legible
   when a fullness bar is short or near-empty -- a light track strands the tail
   of the label past a short bar, which the mock never hit (it faked >=30%). */
.rtrack i.cap-open { background: #0e8a4a; }
.rtrack i.cap-limited { background: #b7710f; }
.rtrack i.cap-full { background: #cc3627; }
.rtrack i.freq { background: #2f5fc9; }
.rtrack b { position: absolute; left: .55rem; right: .55rem; top: 0;
            height: 1.25rem; line-height: 1.25rem; color: #fff; font-weight: 600;
            font-size: .6875rem; white-space: nowrap; overflow: hidden;
            text-overflow: ellipsis; text-shadow: 0 1px 2px rgb(17 18 17 / .5); }
/* Solid slate track, so the white ferry label reads over both the saturated
   fill and the empty portion of a short bar (the shared alpha track is too pale
   under a near-empty fullness bar). */
.ferryhub .rtrack { background: #4b5563; }
.rval { font-family: var(--font-data); font-weight: 700; font-size: .9375rem;
        min-width: 3.4rem; text-align: right; font-variant-numeric: tabular-nums; }
.rval small { font-weight: 400; color: var(--ink-3); font-size: .6875rem;
              font-family: var(--font-body); }

/* H -- the short, now-anchored hour table. */
.htable { width: 100%; border-collapse: collapse; font-size: .875rem; }
.htable th { text-align: left; font-size: .6875rem; letter-spacing: .04em;
             text-transform: uppercase; color: var(--ink-3); font-weight: 700;
             padding: 0 .6rem .5rem; }
.htable td { padding: .55rem .6rem; border-top: 1px solid var(--rule); }
.htable td.hr { font-family: var(--font-data); color: var(--ink-2); }
.htable td.n { font-family: var(--font-data); font-weight: 700;
               font-variant-numeric: tabular-nums; }
.htable th:nth-child(n+2), .htable td:nth-child(n+2) { text-align: right; }
.htable tr.now td { background: var(--sink); }
.htable tr.now td.hr { color: var(--pop); font-weight: 700; }

/* I -- terminal walk-band cards. The number is a WALK band, ramp-colored
   because a walk time is a duration; it is never a per-terminal wait. */
.termgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
            gap: .7rem; }
.termcard { background: var(--sink); border-radius: 5px; padding: .9rem .8rem;
            text-align: center; }
.termcard .tn { font-family: var(--font-sign); font-weight: 700; font-size: .875rem; }
.termcard .tw { font-family: var(--font-data); font-weight: 700; font-size: 1.6rem;
                margin: .4rem 0 .1rem; font-variant-numeric: tabular-nums; }
.termcard .tu { font-size: .6875rem; color: var(--ink-3); }
.termcard .ta { font-size: .75rem; color: var(--ink-2); margin-top: .3rem; }

/* J -- airlines: a share bar (a COUNT, so it takes the accent, never the ramp). */
.airlines { display: grid; gap: .7rem; }
.airow { display: grid; grid-template-columns: 1fr auto; gap: .7rem;
         align-items: center; font-size: .875rem; }
.airow .act { display: flex; align-items: center; gap: .6rem; }
.airow .abar { height: .9rem; width: 7rem; background: rgb(17 18 17 / .08);
               border-radius: 3px; overflow: hidden; }
.airow .abar i { display: block; height: 100%; background: var(--pop); opacity: .85; }
.airow .av { font-family: var(--font-data); font-weight: 700; min-width: 3rem;
             text-align: right; font-variant-numeric: tabular-nums; }
.airow .av small { font-family: var(--font-body); font-weight: 500; color: var(--ink-3); }
.cardnote { font-size: .8125rem; color: var(--ink-3); margin: .8rem 0 0; }
/* An explanatory note dropped to the bottom of a card, ruled off from the
   content above it (airlines card: the "regional carriers…" footnote). */
.cardfoot { margin: .8rem 0 0; padding-top: .6rem; border-top: 1px solid var(--rule);
            font-size: .8125rem; color: var(--ink-3); }
/* In a flex-column card body, sink the footnote to the very bottom edge. */
.cardbody .cardfoot { margin-top: auto; }

/* L -- tips from the data. */
.tips { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column;
        flex: 1 1 auto; }
.tips li { display: grid; grid-template-columns: 1rem 1fr; gap: .6rem;
           font-size: .9375rem; color: var(--ink-2); line-height: 1.5;
           padding: .7rem 0; border-top: 1px solid var(--rule); }
.tips li:first-child { border-top: 0; padding-top: 0; }
.tips li:last-child { padding-bottom: 0; }
.tips li::before { content: "\2192"; color: var(--pop); font-weight: 700; }
.tips li b { color: var(--ink); font-weight: 700; }

/* The two-ups collapse before the phone copy swaps, so a tablet keeps the
   full copy in one column. Below the main breakpoint, fewer facts. */
@media (max-width: 44rem) {
  .grid2, .hero3 { grid-template-columns: 1fr; }
  .hero3 > div { border-left: 0; border-top: 1px solid var(--rule); }
  .hero3 > div:first-child { border-top: 0; }
}
@media (max-width: 34rem) {
  .dtxt { display: none; }
  .mtxt { display: inline; }
}

/* ------------------------------------------------- home (wayfinding) ---- */
/* The home hero: two cards (calculate + board), a reference strip, a foot.
   Reuses the shared .rank/.rrow/.rc/.rtrack/.rval for the board; adds the
   calculate card, day-curve, refstrip and homefoot below. */
.eyebrow.plain { font-family: var(--font-body); text-transform: none;
                 letter-spacing: normal; font-weight: 600; font-size: .8125rem;
                 color: var(--ink-2); }
.hl { font-size: clamp(1.85rem, 4.4vw, 2.75rem); font-weight: 700;
      letter-spacing: -.03em; line-height: 1.04; margin: .2rem 0 1.15rem;
      text-wrap: balance; }

.hero { display: grid; grid-template-columns: 1fr 1fr; gap: 1.15rem;
        align-items: stretch; margin: 0 0 1.15rem; }
.hcard { background: var(--paper); border-radius: 6px; box-shadow: var(--card-shadow);
         border: var(--card-edge);
         padding: clamp(1rem, 2vw, 1.4rem); display: flex; flex-direction: column;
         gap: .85rem; min-width: 0; }
.hcard .grow { margin-top: auto; }

.calchead { display: flex; align-items: baseline; justify-content: space-between;
            gap: .75rem; }
.calchead .t { font-family: var(--font-sign); font-weight: 700; font-size: .9375rem;
               letter-spacing: -.01em; min-width: 0; }
.calchead .m { font-family: var(--font-data); font-size: .75rem; color: var(--ink-3);
               white-space: nowrap; flex: none; }

/* Lane selector: a real segmented control writing the hidden #lane value. */
.lanesel { display: flex; background: var(--sink); border-radius: 4px; padding: 3px; }
.lanesel.full { width: 100%; }
.lanesel button { flex: 1; position: relative; font: inherit; font-size: .8125rem;
                  font-weight: 700; color: var(--ink-2); background: transparent;
                  border: 0; border-radius: 3px; padding: .55rem .75rem; cursor: pointer;
                  white-space: nowrap; }
.lanesel button:not(:last-child)::after { content: ""; position: absolute; right: 0;
                  top: 6px; bottom: 6px; width: 1px; background: rgb(17 18 17 / .12); }
.lanesel button.on { background: var(--pop); color: #fff; }
.lanesel button.on::after, .lanesel button:has(+ .on)::after { background: transparent; }

/* Flight + address fields. Real inputs inside a well; a resolved line under. */
.cfields { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
/* Route-first front door: From / To / Date, plus its caption + step label. */
.cfields3 { display: grid; grid-template-columns: 1fr 1fr 1.15fr; gap: .6rem; }
.subcap { font-size: .8125rem; color: var(--ink-2); margin: 0 0 .1rem; line-height: 1.4; }
.stepcap { font-family: var(--font-data); font-size: .6875rem; letter-spacing: .13em;
           text-transform: uppercase; color: var(--ink-3); margin: .15rem 0 .1rem; }
.cf select.cfin { -webkit-appearance: none; appearance: none; cursor: pointer; }
.cf { background: var(--sink); border-radius: 4px; padding: .6rem .8rem; min-width: 0; }
.cf .k { display: block; font-family: var(--font-data); font-size: .6875rem;
         letter-spacing: .13em; text-transform: uppercase; color: var(--ink-3); }
.cf .cfin { width: 100%; border: 0; background: transparent; font: inherit;
            font-size: 1.0625rem; font-weight: 700; letter-spacing: -.01em;
            margin-top: .25rem; padding: 0; color: var(--ink); outline: none;
            text-overflow: ellipsis; }
.cf .cfin.addr { font-size: .9375rem; }
.cf .cfin::placeholder { color: var(--ink-3); font-weight: 600; }
.cf .rz { font-size: .75rem; color: var(--ink-2); margin-top: .35rem; line-height: 1.3;
          white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-height: 1em; }
.cf .rz b { color: var(--ink); font-weight: 700; }
.cf .rz .ok { color: var(--pop); font-weight: 700; }

/* Autocomplete dropdown under the flight/address fields. A white popover that
   floats over the day-curve and board; the .cf field well is its anchor. */
.achost { position: relative; }
.acmenu { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30;
          background: var(--paper); border: 1px solid var(--rule); border-radius: 4px;
          box-shadow: var(--card-shadow); max-height: 15rem; overflow-y: auto; padding: .2rem; }
.acmenu[hidden] { display: none; }
.acitem { padding: .5rem .6rem; border-radius: 3px; font-size: .875rem; color: var(--ink);
          white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.acitem b { font-family: var(--font-data); font-weight: 700; letter-spacing: .01em; }
.acitem[aria-selected="true"] { background: var(--sink); }

.calcbtn { width: 100%; background: var(--pop); color: #fff; border: 0; border-radius: 4px;
           padding: .8rem 1.1rem; font: inherit; font-weight: 700; font-size: .9375rem;
           cursor: pointer; display: flex; align-items: center; justify-content: center;
           gap: .55rem; }
.calcbtn svg { width: 1rem; height: 1rem; }

/* The day-curve fills the rest of the card so it earns its space. */
.daycurve { border-top: 1px solid var(--rule); padding-top: .8rem; display: flex;
            flex-direction: column; flex: 1 1 auto; min-height: 8rem; }
.dch { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; }
.dch .t { font-family: var(--font-sign); font-weight: 700; font-size: .8125rem; }
.dch .t b { font-weight: 700; }
.dch .m { font-family: var(--font-data); font-size: .6875rem; color: var(--ink-3); }
/* Airport tabs for the curve: underlined like the header nav, no pills. */
.dctabs { display: flex; gap: .9rem; flex-wrap: wrap; margin: .55rem 0 .2rem; }
.dctabs button { font-family: var(--font-data); font-size: .6875rem; font-weight: 600;
                 letter-spacing: .02em; color: var(--ink-3); background: none; border: 0;
                 padding: 0 0 3px; cursor: pointer; }
.dctabs button.on { color: var(--ink); box-shadow: inset 0 -2px 0 var(--pop); }
.dctabs button:hover { color: var(--ink); }
.dcbars { display: flex; align-items: flex-end; gap: 3px; flex: 1 1 auto; min-height: 3.5rem;
          margin-top: .9rem; }
.dcbars i { flex: 1; background: rgb(17 18 17 / .12); border-radius: 2px 2px 0 0;
            min-height: 3px; position: relative; }
.dcbars i.now { background: var(--pop); }
.dcbars i.now::after { content: "now"; position: absolute; top: -.95rem; left: 50%;
            transform: translateX(-50%); font-family: var(--font-data); font-size: .6875rem;
            color: var(--pop); font-weight: 700; }
.dcx { display: flex; justify-content: space-between; font-family: var(--font-data);
       font-size: .6875rem; color: var(--ink-3); margin-top: .45rem; }

/* The board card head + its in-bar local time + the all-airports link. */
.boardhead { display: flex; justify-content: space-between; align-items: baseline;
             margin-bottom: .3rem; padding-bottom: .6rem; border-bottom: 1px solid var(--rule); }
.boardhead .t { font-family: var(--font-sign); font-weight: 700; font-size: .9375rem;
                letter-spacing: -.01em; }
.boardhead .m { font-size: .75rem; color: var(--ink-3); }
.rloc { font-weight: 400; opacity: .85; }
.allrow { padding-top: .8rem; }
.allrow a { font-size: .75rem; font-weight: 700; color: var(--pop); text-decoration: none; }

/* Reference strip: two teaser cards, borders + ferries. */
.refstrip { display: grid; grid-template-columns: 1fr 1fr; gap: 1.15rem; margin: 0 0 1.15rem; }
.ref { background: var(--paper); border-radius: 6px; box-shadow: var(--card-shadow);
       border: var(--card-edge);
       padding: .95rem 1.1rem; display: flex; flex-direction: column; gap: .6rem;
       text-decoration: none; }
.ref .rh { display: flex; align-items: baseline; justify-content: space-between; gap: .6rem; }
.ref .rh .rt { font-family: var(--font-sign); font-weight: 700; font-size: .9375rem; }
.ref .rh .rl { font-size: .75rem; font-weight: 700; color: var(--pop); white-space: nowrap; }
.ref .ri { display: flex; align-items: baseline; justify-content: space-between; gap: .7rem;
           font-size: .8125rem; }
.ref .ri .name { color: var(--ink-2); }
.ref .ri .num { font-family: var(--font-data); font-weight: 700; font-variant-numeric: tabular-nums;
                white-space: nowrap; }
.ref .ri .num small { color: var(--ink-3); font-weight: 400; }

/* Homefoot: popular chips + one method line. */
.homefoot { border-top: 1px solid var(--rule); padding-top: 1rem; display: flex;
            flex-direction: column; gap: .75rem; }
.popular { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .9rem; }
.popular .pl { font-family: var(--font-sign); font-weight: 700; font-size: .8125rem;
               color: var(--ink); margin-right: .2rem; }
.popular a { font-size: .8125rem; font-weight: 600; color: var(--pop); text-decoration: none; }
.popular a small { color: var(--ink-3); font-weight: 400; font-family: var(--font-data); }
.popular a.all { color: var(--ink-2); }
.methodline { font-size: .8125rem; color: var(--ink-2); margin-top: 1.75rem; }
.methodline a { color: var(--pop); font-weight: 700; text-decoration: none; }
/* Ferry hub stacked-card rhythm (bug 5) is now handled with the rest of the
   section rhythm at the end of this file. */

/* -------------------------------------------- route flight list (/flights/) */
.listwrap { max-width: 44rem; }
.backlink { display: inline-block; font-size: .8125rem; font-weight: 700;
            color: var(--pop); text-decoration: none; margin-bottom: .6rem; }
.backlink:hover { text-decoration: underline; }
.routehead { display: flex; align-items: baseline; justify-content: space-between;
             gap: 1rem; flex-wrap: wrap; margin-bottom: .2rem; }
.routehead h1 { font-size: clamp(1.6rem, 3.5vw, 2.1rem); letter-spacing: -.02em; }
.routehead .when { font-family: var(--font-data); font-size: .875rem; color: var(--ink-3);
                   white-space: nowrap; }
.pickcap { font-size: .875rem; color: var(--ink-2); margin: .4rem 0 1rem; line-height: 1.5; }
.flcard { background: var(--paper); border-radius: 6px; box-shadow: var(--card-shadow);
          border: var(--card-edge); padding: 1rem 1.1rem; }
.flstatus { font-size: .875rem; color: var(--ink-2); padding: .8rem .3rem; }
.flstatus a { color: var(--pop); font-weight: 700; }
.frow { display: grid; grid-template-columns: auto 1fr auto auto auto; align-items: center;
        gap: 1rem; width: 100%; text-align: left; background: transparent; border: 0;
        border-bottom: 1px solid var(--rule); padding: .85rem .3rem; cursor: pointer; font: inherit; }
.frow:last-child { border-bottom: 0; }
.frow:hover { background: var(--sink); }
.fr-code { font-family: var(--font-data); font-weight: 700; font-size: 1.0625rem; min-width: 4.6rem; }
.fr-air { font-size: .875rem; color: var(--ink-2); }
.fr-term { font-family: var(--font-data); font-size: .75rem; }
.fr-term .yes { color: var(--ink-2); }
.fr-term .no { color: #b06a00; }
.fr-time { font-family: var(--font-data); font-weight: 700; font-size: 1.0625rem;
           text-align: right; min-width: 5rem; }
.fr-go { color: var(--ink-3); font-weight: 700; }
.frow:hover .fr-go { color: var(--pop); }
.foot-note { font-size: .75rem; color: var(--ink-3); margin-top: 1rem; }
.wrap-inner { margin-top: 2rem; }
.wrap-inner h2 { font-size: 1.3rem; margin-bottom: .5rem; }
.wrap-inner p { margin-bottom: .8rem; line-height: 1.55; }
@media (max-width: 34rem) {
  .frow { grid-template-columns: auto 1fr auto; gap: .5rem; }
  .fr-air, .fr-go { display: none; }   /* fewer facts, not smaller: airline is in the code */
}

/* leave-by flight-context header (route-first handoff) + the cold prompt. The
   header is a divider row inside the white calc card, so the gray wells and
   lane track below it read against white. */
.flightctx { display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem .9rem;
             padding-bottom: .85rem; border-bottom: 1px solid var(--rule); }
.flightctx[hidden] { display: none; }
.fc-code { font-family: var(--font-data); font-weight: 700; font-size: 1.0625rem; }
.fc-sep { color: var(--ink-3); }
.fc-sep[hidden] { display: none; }
.fc-meta { font-size: .875rem; color: var(--ink-2); }
.fc-term { font-family: var(--font-data); font-size: .8125rem; color: var(--ink-2); }
.coldprompt { font-size: .875rem; color: var(--ink-2); margin: 0; line-height: 1.45; }
.coldprompt[hidden] { display: none; }
.coldprompt a { color: var(--pop); font-weight: 700; }

/* ------------------------------------------ leave-by calculator (wayfind) -- */
.calc { display: flex; flex-direction: column; gap: .9rem; }
/* The answer as its own signage bar: a blue-edged strip, the leave-by numeral
   large in mono, the door-to-gate total to the right. The full sentence (with
   the bag-cutoff warning) stays in #strip-summary below, never clipped here. */
.answerbar { display: flex; align-items: center; gap: 1rem; flex-wrap: nowrap;
  background: var(--sink); padding: .8rem 1.1rem; border-radius: 4px; }
.answerbar.bar { border-left: 5px solid var(--pop); border-radius: 0 4px 4px 0; }
.answerbar .k { font-family: var(--font-data); font-size: .6875rem; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-2); white-space: nowrap; flex: none; }
.answerbar .v { font-weight: 700; font-size: clamp(1.6rem, 4vw, 2.1rem); color: var(--pop);
  letter-spacing: -.02em; line-height: 1; font-variant-numeric: tabular-nums;
  font-family: var(--font-data); white-space: nowrap; flex: none; }
.answerbar .v .mer { font-size: .55em; margin-left: .12em; font-weight: 700; }
.answerbar .sub { font-size: .8125rem; color: var(--ink-2); margin-left: auto; text-align: right;
  min-width: 0; font-family: var(--font-data); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }

/* The node timeline: three grouped bands on the track, pinned boundary nodes
   on the axis (drawn by leaveby.js drawStrip's .utl branch). */
.utl { position: relative; padding-top: .2rem; }
.utl .axis { position: relative; height: 3.9rem; }
.utl .track { position: absolute; left: 10px; right: 10px; top: 1.35rem; height: 7px;
  border-radius: 4px; background: var(--rule); overflow: hidden; display: flex; }
.utl .track span { display: block; height: 100%; }
.seg-drive { background: var(--ink-3); }
.seg-wait { background: var(--moderate); }
.seg-buf { background: rgb(17 18 17 / .18); }
.utl .nd { position: absolute; top: .85rem; transform: translateX(-50%); width: 5.4rem;
  text-align: center; }
.utl .nd .dot { width: 13px; height: 13px; border-radius: 50%; background: var(--paper);
  border: 3.5px solid var(--ink); margin: 0 auto; }
.utl .nd.lv .dot { border-color: var(--pop); width: 15px; height: 15px; border-width: 4px; }
.utl .nd .lb { font-size: .6875rem; font-weight: 700; margin-top: .38rem; line-height: 1.12;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.utl .nd .tm { font-size: .6875rem; color: var(--ink-2); margin-top: .12rem; }
.utl .nd.first { left: 10px; transform: none; text-align: left; width: 7rem; }
.utl .nd.first .dot { margin: 0 auto 0 1px; }
.utl .nd.last { left: auto; right: 10px; transform: none; text-align: right; width: 7rem; }
.utl .nd.last .dot { margin: 0 1px 0 auto; }

.tcap { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: .75rem;
  font-family: var(--font-data); font-size: .6875rem; color: var(--ink-2); align-items: center; }
.tcap-legend { display: contents; }
.tcap span { display: inline-flex; align-items: center; gap: .38rem; }
.tcap i { width: 11px; height: 7px; border-radius: 2px; display: inline-block; flex: none; }
.tcap .share { margin-left: auto; color: var(--pop); font-weight: 700; cursor: pointer;
  white-space: nowrap; }

/* Leave-by gated flow (the entrance, the placeholder, the answer) + the
   vertical stepper (bug 7). The calculator's cold state is the route entrance,
   not a pre-filled answer: nothing is computed for the reader until they pick a
   flight or set the details by hand. */
.entrance, .answerwrap { display: flex; flex-direction: column; gap: .9rem; }
.entrance[hidden], .answerwrap[hidden], .answerslot[hidden] { display: none; }
/* The placeholder is the one surface deliberately not a card: a dashed slot. */
.answerslot { display: flex; align-items: center; gap: .7rem; padding: 1.05rem 1.1rem;
  border: 1.5px dashed var(--rule-firm); border-radius: 6px; color: var(--ink-3); }
.answerslot .as-ico { width: 26px; height: 26px; border-radius: 50%; font-size: .9375rem;
  border: 2px dashed var(--rule-firm); display: grid; place-items: center; flex: none; }
.answerslot .as-msg { font-size: .875rem; }
.answerslot .as-msg b { color: var(--ink-2); font-weight: 700; }
.adjnote { font-size: .8125rem; color: var(--ink-3); margin: .1rem 0 .5rem; }

/* The vertical stepper: time on the left, milestones down a rail, legs between.
   Structurally immune to the horizontal-node collision (bug 7) -- each stop owns
   a row whether or not two are close in time -- and the natural shape on a
   phone, where most of the traffic is. */
.vstep { list-style: none; margin: 0; padding: 0; }
.vstep li { display: grid; grid-template-columns: 5.6rem 1.6rem 1fr; align-items: stretch; }
.vstep .vt { font-family: var(--font-data); font-size: .8125rem; color: var(--ink-2);
  font-weight: 600; text-align: right; padding: .5rem .7rem 0 0; }
.vstep .rail { position: relative; }
.vstep .rail::before { content: ""; position: absolute; left: 50%; top: 0; bottom: 0;
  width: 2px; background: var(--sink); transform: translateX(-50%); }
.vstep li.start .rail::before { top: .85rem; }
.vstep li.end .rail::before { bottom: calc(100% - .85rem); }
.vstep li.ms .rail::after { content: ""; position: absolute; left: 50%; top: .85rem;
  width: 13px; height: 13px; border-radius: 50%; background: var(--paper);
  border: 3px solid var(--ink); transform: translate(-50%, -50%); }
.vstep li.start .rail::after { border-color: var(--pop); background: var(--pop);
  width: 15px; height: 15px; border-width: 4px; }
.vstep li.mid .rail::after { border-color: var(--moderate); }
.vstep li.ms .nm { font-weight: 700; font-size: .9375rem; padding: .4rem 0 .55rem; }
.vstep li.leg { min-height: 1.5rem; }
.vstep li.leg .lchip { font-size: .75rem; color: var(--ink-3); font-family: var(--font-data);
  padding: .2rem 0 .4rem; display: inline-flex; align-items: center; gap: .45rem; }
.vstep li.leg .lchip .amber { width: 8px; height: 8px; border-radius: 2px;
  background: var(--moderate); display: inline-block; flex: none; }

/* The engine inputs, folded into a disclosure: the flight/address fields lead,
   the full control set is one click away and stays the computation source. */
.adjust { border-top: 1px solid var(--rule); padding-top: .3rem; }
.adjust > summary { font-family: var(--font-sign); font-weight: 700; font-size: .875rem;
  cursor: pointer; padding: .5rem 0; color: var(--ink); list-style: none; }
.adjust > summary::-webkit-details-marker { display: none; }
.adjust > summary::after { content: "+"; color: var(--pop); font-weight: 700; margin-left: .4rem; }
.adjust[open] > summary::after { content: "\2013"; }
.adjust .controls { margin-top: .4rem; }

@media (max-width: 44rem) {
  .hero, .refstrip { grid-template-columns: 1fr; }
  .utl .nd { width: 4rem; }
  .utl .nd.first, .utl .nd.last { width: 5.75rem; }
}
@media (max-width: 30rem) {
  .cfields, .cfields3 { grid-template-columns: 1fr; }
}
/* The board cards are narrow until the wide desktop; drop the in-bar local
   time there so the label never overruns the track. Fewer facts, not smaller. */
@media (max-width: 64rem) {
  .rloc { display: none; }
}

@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; }
}

/* ============================================ airport final port (rev) ==
   Classes from mocks/wayfinding/final-mockups.html (screen 02), token-mapped
   to the prod system (--card->--paper, --well->--sink, --route->--pop,
   --mut->--ink-2, --faint->--ink-3, --hair2->--rule, mono->--font-data).
   Appended last so it wins over any earlier stale rule for the same class. */
.h2 { font-size: 1.3rem; font-weight: 700; letter-spacing: -.02em; margin: 0 0 .75rem;
  font-family: var(--font-sign); }

/* compact leave-by plug (replaces the airport's in-page calculator) */
.calcplug { background: var(--paper); border-radius: 6px; padding: 16px 22px;
  display: flex; gap: 18px; align-items: center; flex-wrap: wrap;
  border-left: 4px solid var(--pop); box-shadow: var(--card-shadow); }
.calcplug .ctwrap { flex: 1 1 220px; }
.calcplug .ct { font-weight: 700; font-size: .9375rem; font-family: var(--font-sign); }
.calcplug .cs { font-size: .8125rem; color: var(--ink-2); margin-top: 2px; }
.calcfields { display: flex; gap: 8px; flex-wrap: wrap; margin-left: auto;
  align-items: stretch; }
.mini-cf { background: var(--sink); border-radius: 4px; padding: 8px 14px;
  min-width: 160px; display: flex; flex-direction: column; justify-content: center;
  text-align: center; cursor: text;
  /* The chip's VALUE (a plain text node, not an input) had no font of its own
     and inherited oddly; give it the same face as the input chips. */
  font-family: var(--font-body); font-weight: 700; font-size: .875rem; color: var(--ink); }
.mini-cf small { font-weight: 600; font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 3px;
  font-family: var(--font-data); }
.mini-cf input { border: 0; background: transparent; font: inherit;
  font-weight: 700; font-size: .875rem; color: var(--ink); width: 100%;
  text-align: center; outline: none; padding: 0; }
.mini-cf input::placeholder { color: var(--ink-3); font-weight: 600; }
.calcgo { background: var(--pop); color: #fff; border: 0; border-radius: 4px;
  padding: 0 20px; font: inherit; font-weight: 700; font-size: .875rem;
  cursor: pointer; white-space: nowrap; }

/* the three lanes as a vertical list */
.lanevert { display: flex; flex-direction: column; justify-content: space-between;
  flex: 1; width: 100%; }
.lanevert .lv-row { display: flex; justify-content: space-between;
  align-items: center; gap: 12px; padding: 14px 0; border-top: 1px solid var(--rule); }
.lanevert .lv-row:first-child { border-top: 0; padding-top: 0; }
.lanevert .lv-row:last-child { padding-bottom: 0; }
.lanevert .lv-name { font-weight: 700; font-size: .9375rem; }
.lanevert .lv-name small { display: block; font-weight: 500; color: var(--ink-2);
  font-size: .75rem; margin-top: 3px; }
.lanevert .lv-num { font-family: var(--font-data); font-weight: 700; font-size: 1.6rem;
  font-variant-numeric: tabular-nums; }
.lanevert .lv-num .val { color: inherit; }
/* Lane minutes carry the delay ramp (a lane wait IS a delay), matching the mockup. */
.lanevert .lv-num .val.d-clear { color: var(--clear); }
.lanevert .lv-num .val.d-moderate { color: var(--moderate); }
.lanevert .lv-num .val.d-heavy { color: var(--heavy); }
.lanevert .lv-num .u { font-size: .8125rem; color: var(--ink-2); font-weight: 600; }

/* hero mini-lanes as a clean two-column list */
.lanemini { display: grid; gap: 6px; width: 100%; max-width: 190px; margin: 0 auto;
  list-style: none; padding: 0; }
.lanemini > div, .lanemini > li { display: flex; justify-content: space-between;
  align-items: baseline; font-size: .8125rem; }
.lanemini b { font-family: var(--font-data); font-weight: 700; }
.lanemini .u { font-size: .6875rem; color: var(--ink-2); font-weight: 600; }

/* airlines list */
.airlines { display: grid; gap: 11px; }
.airlines .airow { display: grid; grid-template-columns: 1fr auto; gap: 12px;
  align-items: center; font-size: .8125rem; }
.airlines .airow .an { font-weight: 600; }
.airlines .airow .abar { height: 15px; background: #d3d7df; border-radius: 3px;
  overflow: hidden; width: 120px; }
.airlines .airow .abar i { display: block; height: 100%; background: var(--pop);
  opacity: .85; }
.airlines .airow .act { display: flex; align-items: center; gap: 10px; }
.airlines .airow .av { font-family: var(--font-data); font-weight: 700;
  min-width: 78px; text-align: right; }
.airlines .airow .av small { font-family: var(--font-body); font-weight: 500;
  color: var(--ink-3); }
.airl-t { font-size: .6875rem; color: var(--ink-3); font-weight: 500; }
.airow .reg { font-size: .6875rem; color: var(--ink-3); }

/* terminal cards: per-terminal modeled wait + carriers */
.termgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.termgrid .termcard { background: var(--sink); border-radius: 5px; padding: 14px 12px;
  text-align: center; }
.termgrid .termcard .tn { font-weight: 700; font-size: .8125rem; }
.termgrid .termcard .tw { font-family: var(--font-data); font-weight: 700;
  font-size: 1.6rem; margin: 7px 0 3px; font-variant-numeric: tabular-nums; }
.termgrid .termcard .tu { font-size: .6875rem; color: var(--ink-3); }
.termgrid .termcard .ta { font-size: .6875rem; color: var(--ink-2); margin-top: 5px; }

/* email signup */
/* Blue-edged variant: sits where the border page's leave-by plug used to be,
   echoing the plug's transit-blue edge. */
.signup.bar { border-left: 5px solid var(--pop); border-radius: 0 6px 6px 0; }
.signup { background: var(--paper); border-radius: 6px; padding: 20px 24px;
  display: flex; gap: 22px; align-items: center; flex-wrap: wrap;
  justify-content: space-between; box-shadow: var(--card-shadow); }
.signup .sut { font-weight: 700; font-size: 1.0625rem; font-family: var(--font-sign); }
.signup .sus { font-size: .8125rem; color: var(--ink-2); margin-top: 3px; max-width: 56ch; }
.suform { display: flex; gap: 8px; align-items: stretch; flex: 0 1 400px; }
.suform input { flex: 1; border: 1px solid var(--rule); border-radius: 4px;
  padding: 11px 14px; font: inherit; font-size: .875rem; background: var(--sink);
  color: var(--ink); outline: none; min-width: 150px; }
.suform button { background: var(--pop); color: #fff; border: 0; border-radius: 4px;
  padding: 0 22px; font: inherit; font-weight: 700; font-size: .875rem;
  cursor: pointer; white-space: nowrap; }

@media (max-width: 700px) {
  .termgrid { grid-template-columns: 1fr 1fr; }
  .calcfields { margin-left: 0; width: 100%; flex-direction: column; }
  .mini-cf, .calcgo { width: 100%; }
  .calcgo { padding: 12px 20px; }
}

/* ============================================================ hub (wayfinding)
   The national/scoped/border boards: a stats row, a search + segmented filter
   + sort control, then the .rank board (already defined above). Ported from
   mocks/wayfinding/final-mockups.html, tokens mapped to prod. */
.pgsub { font-size: .9375rem; color: var(--ink-2); margin: .25rem 0 1.25rem; max-width: 74ch; }

.stats { display: flex; flex-wrap: wrap; gap: .75rem; margin: 1.25rem 0; }
.stat { background: #fff; border-radius: 6px; padding: .8rem 1.15rem; flex: 1 1 9rem;
  box-shadow: var(--card-shadow); border: var(--card-edge); }
.stat .n { font-family: var(--font-data); font-weight: 700; font-size: 1.6rem;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em; line-height: 1.05; }
.stat .n small { font-size: .875rem; color: var(--ink-2); font-weight: 600; }
.stat .n .code { font-family: var(--font-sign); font-size: 1.0625rem; }
.stat .n .v { font-family: var(--font-data); }
.stat .n .v.d-clear { color: var(--clear); }
.stat .n .v.d-moderate { color: var(--moderate); }
.stat .n .v.d-heavy { color: var(--heavy); }
/* A plain colored stat (median wait): the ramp on the number itself. */
.stat .n.d-clear { color: var(--clear); }
.stat .n.d-moderate { color: var(--moderate); }
.stat .n.d-heavy { color: var(--heavy); }
.stat .l { font-size: .75rem; color: var(--ink-2); margin-top: .15rem; }
/* Conditions cards (airports/ferries hubs): an uppercase label above the
   figure, a one-line read below, and a left edge that carries the ramp ONLY
   where the figure is itself a delay (median) or capacity (deck fullness). A
   count -- airports-over-20, sailings -- gets the neutral edge, never a ramp. */
.stat .k { font-family: var(--font-data); font-size: .6875rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: .2rem; }
.stat .sub { font-size: .75rem; color: var(--ink-3); margin-top: .15rem; }
.stat.hi { border-left: 4px solid var(--ink-3); }
.stat.hi.d-clear { border-left-color: var(--clear); }
.stat.hi.d-moderate { border-left-color: var(--moderate); }
.stat.hi.d-heavy { border-left-color: var(--heavy); }
.stat.hi.cap-open { border-left-color: var(--clear); }
.stat.hi.cap-limited { border-left-color: var(--moderate); }
.stat.hi.cap-full { border-left-color: var(--heavy); }

.controls { display: flex; gap: .75rem; flex-wrap: wrap; align-items: center; margin: 0 0 1rem;
  /* Not a card itself: the search / filter / sort pills are the cards, floating
     distinctly on the ground, so there is no redundant box-in-a-box. padding:0
     is load-bearing -- the grid .controls rule (calculator forms) sets
     padding:1.1rem 1rem, and without this reset the hub search sits ~1rem inboard
     of the stats and card grid it should line up with. */
  padding: 0; background: transparent; box-shadow: none; border: 0; }
.search { flex: 1 1 15rem; display: flex; align-items: center; gap: .55rem;
  background: #fff; border-radius: 6px; padding: .7rem .9rem;
  box-shadow: var(--card-shadow); border: var(--card-edge); }
.search svg { color: var(--ink-3); flex: none; }
.search input { border: 0; background: transparent; font: inherit; font-size: .875rem;
  color: var(--ink); width: 100%; outline: none; }
.seg { display: flex; background: #fff; border-radius: 6px; padding: 3px; gap: 0;
  box-shadow: var(--card-shadow); border: var(--card-edge); }
.seg button { position: relative; font: inherit; font-size: .8125rem; font-weight: 700;
  color: var(--ink-2); background: transparent; border: 0; border-radius: 4px;
  padding: .5rem .9rem; cursor: pointer; white-space: nowrap; }
.seg button:not(:last-child)::after { content: ""; position: absolute; right: 0;
  top: 6px; bottom: 6px; width: 1px; background: rgb(17 18 17 / .12); }
.seg button.on { background: var(--pop); color: #fff; }
.seg button.on::after, .seg button:has(+ .on)::after { background: transparent; }
.sortsel { display: flex; align-items: center; gap: .5rem; background: #fff;
  border-radius: 6px; padding: .55rem .9rem; font-size: .8125rem; font-weight: 600;
  color: var(--ink-2); box-shadow: var(--card-shadow); border: var(--card-edge); }
.sortsel select { border: 0; background: transparent; font: inherit; font-weight: 700;
  color: var(--ink); cursor: pointer; outline: none; }

.boardhead .m { font-size: .75rem; color: var(--ink-3); }
.rrow.is-empty .rtrack { background: transparent; }
.rrow.is-empty b { color: var(--ink-2); font-weight: 500; }

.sh { font-weight: 700; font-size: 1.0625rem; margin: 0 0 .75rem; letter-spacing: -.01em; }
.browse { display: flex; flex-wrap: wrap; gap: .45rem 1rem; }
.browse a { font-size: .8125rem; font-weight: 600; color: var(--pop); }
.browse a small { color: var(--ink-3); font-weight: 400; font-family: var(--font-data); margin-left: .2rem; }

/* Airport hub card grid (board_layout=cards): a scannable directory of white
   cards, severity on the number + a left tick (never a full tint), each the
   link. Adds the typical band, PreCheck, and a live/typical tag the bar board
   could not carry. hub.js re-times the number, band, PreCheck and clock. */
.wgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: .85rem; }
.wcard { position: relative; display: block; background: var(--paper); border: var(--card-edge);
  border-left: 4px solid var(--ink-3); box-shadow: var(--card-shadow); border-radius: 8px;
  padding: .85rem .95rem .8rem; color: var(--ink); }
.wcard:hover { box-shadow: 0 2px 4px rgb(20 28 45 / .10), 0 12px 26px -10px rgb(20 28 45 / .30); }
.wcard.d-clear { border-left-color: var(--clear); }
.wcard.d-moderate { border-left-color: var(--moderate); }
.wcard.d-heavy { border-left-color: var(--heavy); }
.wc-top { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; min-width: 0; }
.wc-code { font-family: var(--font-sign); font-weight: 700; font-size: 1.0625rem; letter-spacing: -.01em;
  min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wc-code small { font-weight: 500; font-size: .75rem; color: var(--ink-3); margin-left: .35rem; letter-spacing: 0; }
.wc-tag { font-family: var(--font-data); font-size: .6875rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3); display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; flex: none; }
.wc-tag .lv { width: 7px; height: 7px; border-radius: 50%; background: var(--clear); flex: none; }
.wc-big { display: flex; align-items: baseline; gap: .35rem; margin: .5rem 0 .1rem; }
.wc-big .rval { font-family: var(--font-data); font-weight: 700; font-size: 1.9rem; letter-spacing: -.02em;
  line-height: 1; min-width: 0; text-align: left; }
.wc-u { font-size: .6875rem; color: var(--ink-3); font-weight: 600; }
.wc-band { font-size: .75rem; color: var(--ink-3); }
.wc-row2 { display: flex; justify-content: space-between; gap: .5rem; margin-top: .6rem; padding-top: .55rem;
  border-top: 1px solid var(--rule); font-size: .75rem; color: var(--ink-2); }
.wc-row2 .pcv { font-family: var(--font-data); font-weight: 700; color: var(--ink); }
.wc-row2 .wc-loc { font-family: var(--font-data); color: var(--ink-3); }
.wc-name { font-size: .75rem; color: var(--ink-3); margin-top: .5rem; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
.wcard.is-empty { grid-column: 1 / -1; border-left-color: var(--ink-3); }
.wc-empty { font-size: .875rem; color: var(--ink-2); }

/* Border hub crossing cards (board_layout=crossing-cards): live CBP wait +
   the three passenger lanes + border side, severity on the number and a tick. */
.cgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: .85rem; }
.ccard { position: relative; display: block; background: var(--paper); border: var(--card-edge);
  border-left: 4px solid var(--ink-3); box-shadow: var(--card-shadow); border-radius: 8px;
  padding: .85rem .95rem .8rem; color: var(--ink); }
.ccard:hover { box-shadow: 0 2px 4px rgb(20 28 45 / .10), 0 12px 26px -10px rgb(20 28 45 / .30); }
.ccard.d-clear { border-left-color: var(--clear); }
.ccard.d-moderate { border-left-color: var(--moderate); }
.ccard.d-heavy { border-left-color: var(--heavy); }
.ccard .ct { display: flex; align-items: flex-start; justify-content: space-between; gap: .5rem; min-width: 0; }
/* Option B: the name wraps to two lines instead of truncating into the port
   line below it (the old ellipsis buried long crossing names). */
.ccard .nm { font-weight: 700; font-size: .9375rem; line-height: 1.2; letter-spacing: -.01em; min-width: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ccard .side { font-family: var(--font-data); font-size: .6875rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); white-space: nowrap; flex: none; margin-top: .12rem; }
.ccard .port { font-size: .75rem; color: var(--ink-3); margin-top: .1rem; }
.ccard .big { display: flex; align-items: baseline; gap: .3rem; margin: .6rem 0 .35rem; }
.ccard .big .n { font-family: var(--font-data); font-weight: 700; font-size: 1.9rem; letter-spacing: -.02em; line-height: 1; }
.ccard .big .u { font-size: .6875rem; color: var(--ink-3); font-weight: 600; }
/* Severity bar, homepage thin-bar standard: 7px pill, absolute 0-60min scale. */
.ccard .ccbar { height: 7px; background: var(--sink); border-radius: 99px; overflow: hidden; margin: 0 0 .45rem; }
.ccard .ccbar i { display: block; height: 100%; border-radius: 99px; background: var(--ink-3); }
.ccard .ccbar i.d-clear { background: var(--clear); }
.ccard .ccbar i.d-moderate { background: var(--moderate); }
.ccard .ccbar i.d-heavy { background: var(--heavy); }
.ccard .ccfoot { font-size: .6875rem; color: var(--ink-3); }
/* A crossing CBP isn't reporting right now: muted, neutral tick, sorts last. */
.ccard.noread { border-left-color: #c9ccd2; }
.ccard .ccstat { font-size: .75rem; color: var(--ink-3); margin-top: .55rem;
  display: flex; align-items: center; gap: .4rem; }
.ccard .ccstat::before { content: ""; width: 6px; height: 6px; border-radius: 99px;
  background: #c9ccd2; flex: none; }
.ccard.is-empty { grid-column: 1 / -1; border-left-color: var(--ink-3); }

/* Ferry hub route cards (board_layout=route-cards): next sailing + a drive-up
   space gauge (capacity ramp, never the delay ramp; labeled by fullness, not
   "live"). No leave-by on the card. */
.fgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: .85rem; }
.fcard { display: block; background: var(--paper); border: var(--card-edge); box-shadow: var(--card-shadow);
  border-radius: 9px; padding: .95rem 1rem; color: var(--ink);
  /* bug 6b: a left edge colored by drive-up space, the same card grammar the
     airport cards use -- capacity ramp (a full deck is capacity, not a delay).
     A route WSF publishes no space for keeps the neutral edge, which is honest:
     gray means no reading, not "open". */
  border-left: 4px solid var(--ink-3); }
.fcard.cap-open { border-left-color: var(--clear); }
.fcard.cap-limited { border-left-color: var(--moderate); }
.fcard.cap-full { border-left-color: var(--heavy); }
.fcard:hover { box-shadow: 0 2px 4px rgb(20 28 45 / .10), 0 12px 26px -10px rgb(20 28 45 / .30); }
.fcard .rt { font-weight: 700; font-size: .9375rem; letter-spacing: -.01em; }
.fcard .meta { font-size: .75rem; color: var(--ink-3); margin-top: .1rem; }
.fcard .fnext { display: flex; align-items: baseline; gap: .5rem; margin: .7rem 0 .2rem; }
.fcard .fnext .t { font-family: var(--font-data); font-weight: 700; font-size: 1.6rem; letter-spacing: -.01em; }
.fcard .fnext .lab { font-size: .75rem; color: var(--ink-3); font-weight: 600; }
.gauge { margin-top: .55rem; }
.gauge .gl { display: flex; justify-content: space-between; gap: .5rem; font-size: .6875rem; color: var(--ink-3); margin-bottom: .3rem; }
.gauge .gl .cap-txt { font-weight: 700; }
.gauge .gl .cap-txt.cap-open { color: var(--clear); }
.gauge .gl .cap-txt.cap-limited { color: var(--moderate); }
.gauge .gl .cap-txt.cap-full { color: var(--heavy); }
.gauge .tk { height: 9px; border-radius: 5px; background: var(--sink); overflow: hidden; }
.gauge .tk i { display: block; height: 100%; }
.gauge .tk i.cap-open { background: var(--clear); }
.gauge .tk i.cap-limited { background: var(--moderate); }
.gauge .tk i.cap-full { background: var(--heavy); }
.fcard.is-empty { grid-column: 1 / -1; }

/* Ferry hub ranked list (board_layout=ferry-rank, the final mockup): each route
   leads with how full its next boat is -- a thin capacity bar (live where WSF
   publishes drive-up space, modeled from ridership otherwise) -- then the next
   sailing time. Same thin-bar standard as the home board. */
.frank { display: block; }
.frow { display: grid; grid-template-columns: 1fr 150px 84px; align-items: center;
  gap: .5rem 1.15rem; padding: .8rem .35rem; border-bottom: 1px solid var(--rule);
  color: var(--ink); border-radius: 4px; }
.frow:last-of-type { border-bottom: 0; }
.frow:hover { background: rgb(28 86 201 / .035); }
.frow .rn { font-weight: 700; font-size: .9375rem; letter-spacing: -.01em; min-width: 0; }
.frow .rn small { display: block; font-weight: 500; font-size: .75rem; color: var(--ink-3);
  margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.frow .rn small b { font-weight: 700; color: var(--ink); }
/* The wait-rank corollary stat (PreCheck wait / lanes open), ramp-colored. */
.frow .rn small b.coro.d-clear { color: var(--clear); }
.frow .rn small b.coro.d-moderate { color: var(--moderate); }
.frow .rn small b.coro.d-heavy { color: var(--heavy); }
.frow .rn small b.cap-open { color: var(--clear); }
.frow .rn small b.cap-limited { color: var(--moderate); }
.frow .rn small b.cap-full { color: var(--heavy); }
.frow .ftrack { height: 7px; background: var(--sink); border-radius: 99px; overflow: hidden; }
.frow .ftrack i { display: block; height: 100%; border-radius: 99px; background: var(--ink-3); }
.frow .ftrack i.cap-open { background: var(--clear); }
.frow .ftrack i.cap-limited { background: var(--moderate); }
.frow .ftrack i.cap-full { background: var(--heavy); }
.frow .ftrack i.freq { background: var(--ink-3); opacity: .4; }
/* The wait-rank board (airports + borders) colors the bar by the delay ramp. */
.frow .ftrack i.d-clear { background: var(--clear); }
.frow .ftrack i.d-moderate { background: var(--moderate); }
.frow .ftrack i.d-heavy { background: var(--heavy); }
.frow .ftrack i.d-closed { background: var(--ink-3); }
/* Wait value in the third column: mono, ramp-colored, right-aligned. */
.waitrank .rval { font-family: var(--font-data); font-weight: 700; font-size: 1.0625rem;
                  text-align: right; font-variant-numeric: tabular-nums; }
.waitrank .rval small { font-family: var(--font-body); font-weight: 400;
                        color: var(--ink-3); font-size: .6875rem; }
/* Next sailing: mono time with the AM/PM set small inline, matching the site's
   number style; a boarding row stacks "now / boarding" instead. */
.frow .rnext { font-family: var(--font-data); font-weight: 700; font-size: 1.0625rem;
  text-align: right; white-space: nowrap; color: var(--ink); line-height: 1.05;
  font-variant-numeric: tabular-nums; }
.frow .rnext small { font-family: var(--font-body); font-weight: 500;
  font-size: .6875rem; color: var(--ink-3); }
.frow .rnext.boarding { display: flex; flex-direction: column; align-items: flex-end;
  color: var(--clear); line-height: 1.1; }
.frow .rnext.boarding small { color: var(--clear); font-weight: 700; font-size: .6875rem; }
.frow.is-empty { display: block; padding: .9rem .35rem; color: var(--ink-2); font-size: .875rem; }
/* Collapse the quiet (near-empty) routes behind a toggle so the board leads
   with the boats that are somewhat full. */
.frank:not(.expanded) .frow[data-quiet] { display: none; }
/* GTFS operators publish no fullness, so the bar column is dropped entirely. */
.frank.no-bars .frow { grid-template-columns: 1fr auto; }
.frank.no-bars .ftrack { display: none; }
.ferry-expand { display: inline-flex; align-items: center; gap: .4rem; margin: .35rem 0 1.15rem;
  background: none; border: 0; color: var(--pop); font: inherit; font-weight: 600;
  font-size: .875rem; cursor: pointer; padding: .5rem .35rem; }
.ferry-expand:hover { text-decoration: underline; }
@media (max-width: 34rem) {
  .frow { grid-template-columns: 1fr auto; }
  .frow .ftrack { display: none; }
}

/* ---- ferry route (wayfinding final) ----------------------------------- */
/* .calcgo works as a link too (border/ferry handoff), not only a button. */
.calcgo { display: inline-flex; align-items: center; justify-content: center;
  text-decoration: none; }
/* gauge: the fullness label rides inside the bar (finalmocks/03). */
.gauge .gaugebar { position: relative; height: 1.6rem; display: flex;
  align-items: center; }
.gauge .gaugebar b { position: absolute; left: .7rem; color: var(--ink);
  font-size: .8125rem; font-weight: 700; white-space: nowrap; }
.gauge .gaugenote b { color: var(--ink); }
/* today's schedule: two columns of time chips, marked past/next/later. */
.sched { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; }
.schcol .sct { font-family: var(--font-sign); font-weight: 700; font-size: .9375rem;
  margin: 0 0 .6rem; }
.schcol.right { text-align: right; }
.schtimes { display: flex; flex-wrap: wrap; gap: .4rem; }
.schcol.right .schtimes { justify-content: flex-end; }
/* Uniform-width chips so the grid reads as a clean matrix, not a ragged row. */
.schtimes .t { font-family: var(--font-data); font-size: .8125rem; font-weight: 600;
  width: 5.6rem; padding: .28rem 0; text-align: center; box-sizing: border-box;
  border-radius: 4px; background: var(--sink); color: var(--ink-2); }
.schtimes .t.past { color: var(--ink-3); opacity: .55; text-decoration: line-through; }
.schtimes .t.next { background: var(--pop); color: #fff; }
/* Collapsed by default: only the symmetric window shows; the toggle reveals all. */
.sched:not(.expanded) .t.sch-extra { display: none; }
.sched-more { margin-left: auto; background: none; border: 0; color: var(--pop);
  font: inherit; font-weight: 600; font-size: .8125rem; cursor: pointer; padding: .1rem .3rem; }
.sched-more:hover { text-decoration: underline; }
.schlegend { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center;
  margin-top: 1rem; font-size: .8125rem; color: var(--ink-2); }
.schlegend span { display: inline-flex; align-items: center; gap: .4rem; }
.schlegend i { width: .7rem; height: .7rem; border-radius: 2px; display: inline-block; }
.schlegend .sw-next { background: var(--pop); }
.schlegend .sw-day { background: var(--sink); }
.schlegend .sw-past { background: var(--track, #d3d7df); opacity: .55; }
/* Fares: one full-width row, evenly divided by the number of fare options
   (--fare-cols is set inline from the item count), each a label / price / note
   column with a hairline divider between. */
.faregrid { display: grid; grid-template-columns: repeat(var(--fare-cols, 4), 1fr);
  gap: 0; }
.farecell { padding: .1rem 1.2rem; border-left: 1px solid var(--rule); }
.farecell:first-child { border-left: 0; padding-left: 0; }
.farecell .fl { font-weight: 600; font-size: .875rem; }
.farecell .fp { font-family: var(--font-data); font-weight: 700; font-size: 1.3rem;
  line-height: 1.1; margin: .35rem 0 .15rem; }
.farecell .fn { color: var(--ink-3); font-size: .75rem; line-height: 1.4; }
@media (max-width: 640px) {
  .faregrid { grid-template-columns: 1fr 1fr; gap: 1.1rem .4rem; }
  .farecell { border-left: 0; padding-left: 0; }
}
/* Terminals full-width beneath: name on the left, address/parking on the right,
   so the wide card is used instead of a lone narrow column. Keeps the hairline
   row separators (still a vertical stack). Stacks on phones. */
.terminfo.termcols .trow { grid-template-columns: 13rem 1fr; column-gap: 1.6rem;
  align-items: baseline; }
.terminfo.termcols .trow > b { grid-column: 1; }
.terminfo.termcols .trow > .addr,
.terminfo.termcols .trow > .park { grid-column: 2; }
@media (max-width: 640px) {
  .terminfo.termcols .trow { grid-template-columns: 1fr; }
  .terminfo.termcols .trow > b,
  .terminfo.termcols .trow > .addr,
  .terminfo.termcols .trow > .park { grid-column: 1; }
}

@media (max-width: 640px) {
  .sched { grid-template-columns: 1fr; gap: 1rem; }
  .schcol.right, .schcol.right .schtimes { text-align: left; justify-content: flex-start; }
}

/* ---- ferries hub (wayfinding final) ----------------------------------- */
.stategrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: .7rem; }
.stateblock { background: var(--sink); border-radius: 5px; padding: .7rem .8rem;
  display: block; }
.stateblock b { display: block; font-size: .875rem; }
/* Three stacked lines: state name, then the operator name(s), then
   "X routes · running now" on its own line below the operators. */
.stateblock .ops { display: block; margin-top: .12rem; font-size: .75rem;
                   color: var(--ink); font-weight: 600; }
.stateblock .cnt { display: block; margin-top: .1rem; font-size: .75rem;
                   color: var(--ink-2); }
/* Ferries-by-state card: pin the "X routes · running now" line to the bottom
   edge, so cards with one vs two operators still line their counts up. */
.stategrid.fx .stateblock { display: flex; flex-direction: column; }
.stategrid.fx .stateblock .cnt { margin-top: auto; padding-top: .35rem; }
.stateblock.dim { opacity: .5; }
.gtk { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0; }
.gtkcell { padding: .9rem 1.1rem; font-size: .875rem; color: var(--ink-2);
  line-height: 1.5; border-top: 1px solid var(--rule); }
.gtkcell:nth-child(odd) { border-right: 1px solid var(--rule); }
.gtkcell:nth-child(-n+2) { border-top: 0; }
.gtkcell b { display: block; color: var(--ink); font-size: .875rem; margin-bottom: .2rem; }
.routegrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .7rem; }
.routecard { background: var(--sink); border-radius: 5px; padding: .9rem 1rem;
  display: block; }
.routecard .rt { font-weight: 700; font-size: .9375rem; }
.routecard .rc-meta { font-size: .75rem; color: var(--ink-3); margin-top: .15rem; }
.routecard .rc-next { font-family: var(--font-data); font-weight: 700;
  font-size: 1.0625rem; color: var(--pop); margin-top: .5rem; }
/* Next sailing colored by how soon it is (final mockup): catch-it-now green,
   a while off amber. */
.routecard .rc-next.d-clear { color: var(--clear); }
.routecard .rc-next.d-moderate { color: var(--moderate); }
.routecard .rc-next.d-heavy { color: var(--heavy); }
.routecard .rc-next small { font-family: var(--font-body); font-weight: 500;
  font-size: .75rem; color: var(--ink-3); }

@media (max-width: 760px) {
  .stategrid { grid-template-columns: repeat(2, 1fr); }
  .gtk, .routegrid { grid-template-columns: 1fr; }
  .gtkcell:nth-child(odd) { border-right: 0; }
  .gtkcell:nth-child(2) { border-top: 1px solid var(--rule); }
}

/* ==========================================================================
   Section vertical rhythm — the ONE place page sections get their spacing.

   The recurring "section title butting up against the card above it" bug:
   section spacing used to depend entirely on the PREVIOUS element carrying a
   margin-bottom. A section that follows a margin-less card (.calcplug, a
   gauge, a card grid) therefore collapsed the gap to zero and the heading
   touched the card. Fix it at the source: every section owns a top margin,
   so a heading always clears whatever sits above it, no matter what that is.
   Margin-collapsing keeps this from double-spacing the normal block case
   (a section whose predecessor already has a bottom margin collapses to the
   larger of the two, i.e. this one). Grid-paired sections opt out — they sit
   side by side, not stacked. New section types inherit the rhythm for free
   as long as they use .sect; the non-.sect section cards are listed too. */
.sect,
.calcplug,
.signup,
.grid2,
.grid37 { margin-top: 1.5rem; }
.grid2 > .sect,
.grid37 > .sect { margin-top: 0; }

/* Border page pairing (final mockup): typical-by-hour chart beside the
   which-lane cards, chart in the narrower column. Equal height; stacks on
   phones. */
.grid37 { display: grid; grid-template-columns: 1fr 1.5fr; gap: 1.15rem;
  align-items: stretch; }
.grid37 > .sect { display: flex; flex-direction: column; gap: .6rem; }
.grid37 > .sect > .block { flex: 1 1 auto; }
/* Chart grows to fill the card height so it matches the taller which-lane card
   instead of leaving a void below it (the bars scale to the new height). */
.grid37 .chartwrap { flex: 1 1 auto; }
.grid37 .chartmain { display: flex; flex-direction: column; }
.grid37 .bchart { flex: 1 1 auto; height: auto; min-height: 6.5rem; }
@media (max-width: 820px) { .grid37 { grid-template-columns: 1fr; } }
/* Border page vs/documents pair: equal height like the mockup, with each card
   centring its content so the shorter one is balanced, not voided. */
body.crossing .grid2 { align-items: stretch; }
body.crossing .grid2 > .sect > .block { height: 100%; }

/* Airport page: side-by-side cards match height (owner ask). The .titled cards
   fill via .cardbody{flex:1} and the .sect blocks via flex:1; setting stretch is
   what lets those fills reach the row height. Charts/lists grow to fill so the
   shorter card is not left with a void. */
body.airport .grid2 { align-items: stretch; }
body.airport .grid2 > .titled { height: 100%; }
/* Chart grows to fill the card. Keep .daychart's own align-items:stretch (the
   bar spans must stretch to full height or the height:% bars collapse); only
   swap the fixed height for a flexible one. */
body.airport .grid2 .chartwrap { flex: 1 1 auto; }
body.airport .grid2 .chartmain { display: flex; flex-direction: column; }
body.airport .grid2 .chartmain .daychart { flex: 1 1 auto; height: auto; min-height: 9rem; }
body.airport .grid2 .rank.fill { flex: 1 1 auto; display: flex; flex-direction: column;
  justify-content: space-between; }
.article > .svcalerts { margin-top: 1.5rem; }
/* The ferry hub's stacked cards (bug 5) now share the site-wide rhythm; keep
   the value in one place rather than the old per-hub 1.15rem override. */
body.ferryhub .svcalerts,
body.ferryhub .calcplug,
body.ferryhub .titled,
body.ferryhub .block.faq,
body.ferryhub .signup { margin-top: 1.5rem; }

/* (Ferry Fares/Terminals are now full-width stacked sections, not a grid2 —
   Fares is a full-width .faregrid, Terminals full-width beneath; see below.) */

/* Schedule (bug 22): as the day advances, chips that were upcoming at build
   time turn .past. leaveby.js keeps only the single most-recent departed chip
   and marks the older ones .sch-gone, so the default view never grows a wall
   of strike-throughs. Full-timetable expands everything. */
.sched:not(.expanded) .t.sch-gone { display: none; }

/* Multi-destination services (interisland WSF like Anacortes / San Juan
   Islands): pick a route first (Option B -- two grouped pill rows), then the
   standard two-column schedule card for that pair shows below. */
.rsel { border-bottom: 1px solid var(--rule); padding-bottom: 1.1rem; }
.rsel .rsel-lab { font-size: .6875rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3); margin: 0 0 .5rem; }
.rsel .rsel-lab + .rpills { margin-bottom: 1rem; }
.rsel .rpills:last-child { margin-bottom: 0; }
.rsel .rpills { display: flex; flex-wrap: wrap; gap: .5rem; }
.rpill { font: inherit; font-weight: 600; font-size: .875rem; padding: .5rem .9rem;
  border-radius: 6px; border: 1px solid #c4cad4; background: #fff; color: var(--ink);
  cursor: pointer; font-family: var(--font-sign); }
.rpill:hover { border-color: var(--pop); }
.rpill.on { background: var(--pop); color: #fff; border-color: var(--pop); }
.pairsched { margin-top: 1.1rem; }
.schnote { margin-top: 1rem; }
