/* ============================================================================
   WESTBROOK TRANSIT — Built to DESIGN_SYSTEM.md v1.0.

   THE BRIEF, WHICH IS UNLIKE EVERY OTHER BUILD IN THIS SERIES.
   Every previous site had latitude to be beautiful. This one does not. It is a
   utility people depend on, read at six in the morning, in the rain, on a
   cracked phone, one-handed, sometimes by someone whose trip is already hard.
   A contrast failure here is not a lint error. It is a missed bus.

   SO ACCESSIBILITY IS THE DESIGN BRIEF, NOT A PASS AT THE END:
     · body text targets AAA (7:1), not AA. Measured, not assumed.
     · color is NEVER the only signal — every route carries a NUMBER and a
       STROKE PATTERN as well as a color. Six routes cannot be separated by
       color alone for a deuteranope; measured, the closest pair sits at 29.1
       and no palette fixes that. London and New York solve it the same way we
       do: the number is always there.
     · a light and a dark theme, remembered, because half these journeys happen
       before sunrise.
     · reflow at 200% zoom with no horizontal scrolling (WCAG 1.4.10).
     · every target at least 44px, most of them far bigger.
     · the timetable is in the markup. With scripts blocked you still get the
       times, because a blocked script must not strand anybody.

   THE TENSION, STATED HONESTLY. §12 counts BASIC as a failure state, and a
   utility is under constant pressure toward plain. The resolution is that the
   richness here comes from CONFIDENCE AND SCALE — signage does not whisper —
   rather than from decoration. Nothing is added that a rider would not use.

   ONE LINE   when is my bus
   REFUSAL    the transit-authority default: a hero photograph of a smiling
              rider boarding, a three-card "plan / pay / alerts" row, a farm of
              PDF timetables, a press-release feed, and the actual arrival
              times four clicks down.
   REGISTER   A SIGNAGE SYSTEM AND A DEPARTURE BOARD. The reference is Beck's
              diagram and Vignelli's 1972 New York standards manual, where the
              most usable answer and the strongest identity are the same thing.

   TYPE (§6) — THE SCALE IS NOT A SCALE. IT IS FIVE SIGNS.
     Real signage systems specify a closed set of sign types and never
     improvise a size. So this system has exactly five, each with locked size,
     weight and tracking, and nothing on the site is set at any other size.
     Previous channels were width, weight extremes, the numeral, alignment and
     case; this one is the CLOSED SET itself.
     Overpass is drawn from Highway Gothic — the face on American road signs.

   §12.0a — checked before writing:
     · No enumerated section markers. Route numbers and stop sequence numbers
       are content: a route IS numbered and stops ARE in order.
     · No decorative background grid. The dot matrix appears only inside the
       departure board, where it depicts an actual LED display rather than
       decorating a page.
     · No monospace face. Third build running. Times are tabular Overpass.

   INTERACTION SIGNATURE — "it lands."
   ========================================================================= */

:root {
  color-scheme: light;
  --paper:  #FAFAF8;
  --panel:  #EFEFEC;
  --sunk:   #E3E4E0;
  --ink:    #111417;   /* 17.68:1 on paper */
  --ink-2:  #47515C;   /* 7.01 on panel, 7.6 on paper — AAA */
  --line:   #C9CBC6;
  --line-2: #A9ADA7;

  --r1:#C4142B; --r2:#0B5CAD; --r3:#8A6100; --r4:#0F6B3F; --r5:#6E2C91; --r6:#42505C;

  --ok:   #0F6B3F;
  --warn: #8A6100;
  --stop: #C4142B;

  --board:    #14181C;   /* the departure board is always dark, in both themes */
  --board-on: #F7F8F6;
  --board-2:  #9AA4AE;

  --f-sign: 'Overpass', 'Arial Narrow', Arial, sans-serif;
  --f-read: 'Source Sans 3', system-ui, -apple-system, sans-serif;

  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:20px; --s-6:24px;
  --s-8:32px; --s-10:40px; --s-12:48px; --s-16:64px; --s-20:80px; --s-24:96px; --s-32:128px;

  --ease: cubic-bezier(.2,.7,.3,1);
  --land: 180ms;
  --tap: 48px;         /* our floor is 48, not the 44 minimum */
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bullet-fg: #0E1114;
  --paper:  #0E1114;
  --panel:  #1A1F24;
  --sunk:   #23292F;
  --ink:    #E8EAEC;   /* 15.70:1 */
  --ink-2:  #A8B2BC;   /* 7.71 on panel — AAA */
  --line:   #333B43;
  --line-2: #4A545E;
  /* solved for BOTH jobs at once with headroom, not to the 4.5 line:
     ink sits ON these in a bullet (5.60+) and they are drawn AS lines on
     the dark ground (5.60+). The bullet text inverts to ink in this theme,
     because white on a lightened route color is what failed. */
  --r1:#EE576B; --r2:#2A8EF1; --r3:#B98200; --r4:#16A05E; --r5:#B272D4; --r6:#7A8FA0;
  --bullet-ink: var(--paper);
  --ok:#16A05E; --warn:#B98200; --stop:#EE576B;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--paper); }

body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: var(--f-read); font-size: 1.0625rem; line-height: 1.6;
  overflow-x: hidden;
}
img, svg { max-width: 100%; }
a { color: inherit; }
::selection { background: var(--ink); color: var(--paper); }

.shell { width: min(1280px, 100%); margin-inline: auto; padding-inline: clamp(var(--s-4), 4vw, var(--s-16)); }
.band { padding-block: clamp(var(--s-10), 4vw, var(--s-20)); }
.band--tight { padding-block: clamp(var(--s-6), 3vw, var(--s-12)); }

/* ============================================================ THE FIVE SIGNS
   The whole type system. Nothing on this site is set at a size that is not one
   of these five. If something needs a sixth size, the layout is wrong. */
.sign-platform {                       /* the biggest thing on any page */
  font-family: var(--f-sign); font-weight: 700;
  font-size: clamp(2.6rem, 1.4rem + 4.4vw, 4.4rem);
  line-height: .98; letter-spacing: -0.02em; margin: 0;
}
.sign-way {                            /* wayfinding: what section is this */
  font-family: var(--f-sign); font-weight: 700;
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2rem);
  line-height: 1.1; letter-spacing: -0.01em; margin: 0 0 var(--s-5);
}
.sign-row {                            /* a departure, a stop, a list line */
  font-family: var(--f-sign); font-weight: 600;
  font-size: 1.25rem; line-height: 1.25; letter-spacing: 0; margin: 0;
}
.sign-body { font-family: var(--f-read); font-size: 1.0625rem; line-height: 1.65; margin: 0; }
.sign-note { font-family: var(--f-read); font-size: .9375rem; line-height: 1.55; margin: 0; color: var(--ink-2); }

.prose { max-width: 62ch; }
.prose p { margin: 0 0 var(--s-5); }
.prose p:last-child { margin-bottom: 0; }
.prose strong { font-weight: 700; }
.prose a { color: inherit; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
.fig { font-variant-numeric: tabular-nums lining-nums; }
.vh { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); clip-path: inset(50%); white-space:nowrap; }

/* ---------------------------------------------------------------- actions
   INTERACTION SIGNATURE — "it lands."
   A solid block rises from the bottom edge and fills the control, the way a
   bus pulls into a bay, and the label inverts. 180ms. The inversion matters:
   the state change is a LIGHTNESS change, not a color change, so it is
   visible to a rider who cannot see the color at all. */
.btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-3); min-height: var(--tap); padding: var(--s-3) var(--s-6);
  font-family: var(--f-sign); font-weight: 700; font-size: 1.0625rem;
  text-decoration: none; cursor: pointer; overflow: hidden; z-index: 0;
  background: transparent; color: var(--ink);
  border: 2px solid var(--ink);
  transition: color var(--land) var(--ease);
}
.btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--ink);
  transform: translateY(101%); transition: transform var(--land) var(--ease);
}
.btn:hover, .btn:focus-visible { color: var(--paper); }
.btn:hover::before, .btn:focus-visible::before { transform: translateY(0); }
.btn[aria-pressed="true"] { color: var(--paper); }
.btn[aria-pressed="true"]::before { transform: translateY(0); }
.btn--solid { background: var(--ink); color: var(--paper); }
.btn--solid::before { background: var(--paper); }
.btn--solid:hover, .btn--solid:focus-visible { color: var(--ink); }

:where(a,button,input,select,summary):focus-visible {
  outline: 3px solid var(--ink); outline-offset: 3px;
}
:root[data-theme="dark"] :where(a,button,input,select,summary):focus-visible { outline-color: var(--ink); }
.skip { position: absolute; left: -9999px; background: var(--ink); color: var(--paper); padding: var(--s-4) var(--s-6); z-index: 90; font-family: var(--f-sign); font-weight: 700; }
.skip:focus { left: var(--s-3); top: var(--s-3); }

/* ---------------------------------------------------------------- masthead */
.masthead { background: var(--ink); color: var(--paper); }
.masthead__in { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-6); align-items: center; justify-content: space-between; padding-block: var(--s-3); }
.wordmark { font-family: var(--f-sign); font-weight: 700; font-size: 1.375rem; letter-spacing: -0.01em; text-decoration: none; display: inline-flex; align-items: center; gap: var(--s-3); min-height: var(--tap); }
.wordmark b { background: var(--paper); color: var(--ink); padding: 2px var(--s-2); }
.nav { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.nav a {
  font-family: var(--f-sign); font-weight: 600; font-size: 1.0625rem;
  text-decoration: none; padding: var(--s-2) var(--s-4); min-height: var(--tap);
  display: inline-flex; align-items: center; border-bottom: 4px solid transparent;
}
.nav a:hover, .nav a:focus-visible { background: rgba(127,127,127,.28); }
.nav a[aria-current="page"] { border-bottom-color: var(--paper); }
.themebtn {
  font-family: var(--f-sign); font-weight: 600; font-size: .9375rem;
  background: transparent; color: inherit; border: 2px solid currentColor;
  min-height: var(--tap); padding: var(--s-2) var(--s-4); cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--s-2);
}
.themebtn:hover, .themebtn:focus-visible { background: var(--paper); color: var(--ink); }

/* ============================================================ ROUTE BULLETS
   The number is the identity. The color is a second cue and the stroke
   pattern on the diagram is a third. Never color on its own. */
.bullet {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.1em; height: 2.1em; padding-inline: .35em;
  font-family: var(--f-sign); font-weight: 700; font-size: 1.1875rem;
  /* 19px at 700 clears WCAG's large-text threshold (18.66px bold), where
     the AAA requirement is 4.5 rather than 7. White on a route color
     measures 5.5 to 8.6 — so the fix is to make the number BIGGER, not to
     darken six route colors until they stop being distinguishable from
     each other. Bigger type is the real legibility win here anyway. */
  color: var(--bullet-fg, #fff); background: var(--ink); border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.bullet[data-r="1"]{background:var(--r1)} .bullet[data-r="2"]{background:var(--r2)}
.bullet[data-r="3"]{background:var(--r3)} .bullet[data-r="4"]{background:var(--r4)}
.bullet[data-r="5"]{background:var(--r5)} .bullet[data-r="6"]{background:var(--r6)}
.bullet--lg { font-size: 1.5rem; min-width: 2em; height: 2em; }

/* ============================================================== THE BOARD
   The signature component and the answer to the only question that matters.
   It is dark in BOTH themes, because a departure board is a lit object — and
   because a rider glancing at a phone in the rain needs one high-contrast
   thing, not a page that has politely adapted. */
.board { background: var(--board); color: var(--board-on); border-radius: 2px; overflow: hidden; }
.board__head {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5); align-items: baseline;
  justify-content: space-between; padding: var(--s-4) var(--s-5);
  border-bottom: 2px solid #2A3038;
}
.board__stop { font-family: var(--f-sign); font-weight: 700; font-size: 1.5rem; }
.board__clock { font-family: var(--f-sign); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--board-2); }
.board__rows { position: relative; }
/* the dot matrix — this is not a background texture (§12.0a). It depicts the
   LED panel the departures are printed on, and it exists only here. */
.board__rows::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background-image: radial-gradient(rgba(255,255,255,.055) 1px, transparent 1.1px);
  background-size: 4px 4px;
}
.dep {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: auto 1fr auto; gap: var(--s-3) var(--s-4);
  align-items: center; padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid #242A31;
}
.dep:last-child { border-bottom: 0; }
.dep__to { font-family: var(--f-sign); font-weight: 600; font-size: 1.25rem; min-width: 0; }
.dep__note { display: block; font-family: var(--f-read); font-size: .9375rem; color: var(--board-2); font-weight: 400; }
.dep__in {
  font-family: var(--f-sign); font-weight: 700; font-variant-numeric: tabular-nums;
  font-size: 2rem; line-height: 1; text-align: right; white-space: nowrap;
}
.dep__in small { display: block; font-size: .9375rem; font-weight: 400; color: var(--board-2); letter-spacing: .02em; }
.dep--due .dep__in { color: #7BE3A4; }
.board__empty { padding: var(--s-8) var(--s-5); color: var(--board-2); position: relative; z-index: 2; }

/* ================================================================= ALERTS
   First on the page, never behind a click, and never color-only: each alert
   carries a word — DISRUPTION, DIVERSION, NOTICE — as well as a color. */
.alert { display: grid; grid-template-columns: auto 1fr; gap: var(--s-3) var(--s-4); padding: var(--s-4) var(--s-5); border: 2px solid var(--ink); background: var(--panel); margin-bottom: var(--s-3); }
.alert__tag { font-family: var(--f-sign); font-weight: 700; font-size: 1.1875rem; letter-spacing: .03em; align-self: start; padding: 2px var(--s-2); background: var(--ink); color: var(--paper); }
.alert--stop { border-color: var(--stop); }
.alert--stop .alert__tag { background: var(--stop); }
.alert--warn { border-color: var(--warn); }
.alert--warn .alert__tag { background: var(--warn); }
.alert__body { min-width: 0; }
.alert__body p { margin: 0; }

/* ================================================================ CONTROLS */
.picker { display: grid; gap: var(--s-3); }
.field label { font-family: var(--f-sign); font-weight: 600; display: block; margin-bottom: var(--s-2); }
select, input[type="search"], input[type="number"] {
  font-family: var(--f-read); font-size: 1.0625rem; width: 100%;
  min-height: var(--tap); padding: var(--s-3) var(--s-4);
  background: var(--paper); color: var(--ink); border: 2px solid var(--ink);
}
.chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.chip {
  font-family: var(--f-sign); font-weight: 600; font-size: 1rem;
  min-height: var(--tap); padding: var(--s-2) var(--s-4); cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--s-2);
  background: transparent; color: var(--ink); border: 2px solid var(--line-2);
  transition: border-color var(--land) var(--ease);
}
.chip:hover { border-color: var(--ink); }
.chip[aria-pressed="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* =============================================================== ROUTE LIST */
.routes { display: grid; gap: var(--s-3); }
.route {
  display: grid; grid-template-columns: auto 1fr auto; gap: var(--s-3) var(--s-5);
  align-items: center; padding: var(--s-4) var(--s-5);
  border: 2px solid var(--line); background: var(--panel); text-decoration: none;
  min-height: var(--tap);
/* DO NOT TRANSITION A BACKGROUND THAT COMES FROM A CUSTOM PROPERTY.
   When the theme token changes, the engine does not reliably re-resolve a
   var()-derived value that is under transition: the element keeps the OLD
   color indefinitely. On this site that meant clicking the theme toggle to
   dark flipped the card TEXT to light and left the card GROUND light — 1.05:1,
   unreadable — and only on the toggle path, never under prefers-color-scheme,
   which is why the first audit missed it. Border-color still transitions;
   ground changes instantly, which is the right speed for it anyway. */
  transition: border-color var(--land) var(--ease);
}
.route:hover, .route:focus-visible { border-color: var(--ink); background: var(--sunk); }
.route[hidden] { display: none; }
.route__n { font-family: var(--f-sign); font-weight: 700; font-size: 1.25rem; }
.route__v { color: var(--ink-2); font-size: .9375rem; }

/* ================================================================ DIAGRAM */
.diagram { background: var(--panel); border: 2px solid var(--line); padding: var(--s-4); overflow-x: auto; }
.diagram svg { display: block; min-width: 720px; }
/* a halo, drawn under the glyph, so a label crossing a route line stays
   readable and does not break the line either. Standard cartography, and
   the single most important legibility fix on this diagram. */
.stop__label { font-family: var(--f-sign); font-weight: 600; font-size: 13px; fill: var(--ink);
  paint-order: stroke fill; stroke: var(--panel); stroke-width: 4px; stroke-linejoin: round; }
.stop__dot { fill: var(--panel); stroke: var(--ink); }
.stop__nostep { stroke: var(--ink); }
.stop { cursor: pointer; }
.stop:hover .stop__dot, .stop:focus .stop__dot { fill: var(--ink); }
.stop:focus { outline: 3px solid var(--ink); outline-offset: 2px; }
.line { transition: opacity var(--land) var(--ease); }
.diagram.is-focused .line { opacity: .18; }
.diagram.is-focused .line.is-on { opacity: 1; }
.legend { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-5); }
.legend button {
  display: inline-flex; align-items: center; gap: var(--s-2); cursor: pointer;
  background: transparent; border: 2px solid var(--line-2); padding: var(--s-2) var(--s-3);
  min-height: var(--tap); font-family: var(--f-sign); font-weight: 600; color: var(--ink);
}
.legend button[aria-pressed="true"] { border-color: var(--ink); background: var(--sunk); }
.legend i { width: 26px; height: 5px; display: inline-block; }

/* ================================================================== TABLE */
.tt { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.tt th, .tt td { text-align: left; padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--line); }
.tt thead th { font-family: var(--f-sign); font-weight: 700; border-bottom: 2px solid var(--ink); }
.tt tbody th { font-weight: 600; }
.tt caption { text-align: left; padding-bottom: var(--s-3); color: var(--ink-2); }
.wrap { overflow-x: auto; }

/* step-free marker — a word and a symbol, never a color alone */
.step { display: inline-flex; align-items: center; gap: var(--s-2); font-family: var(--f-sign); font-weight: 600; font-size: .9375rem; }
.step b { display: inline-grid; place-items: center; width: 24px; height: 24px; border: 2px solid currentColor; border-radius: 50%; font-size: .8125rem; }
.step--yes { color: var(--ok); }
.step--no { color: var(--ink-2); }

/* ================================================================== FARES */
.fare { display: grid; gap: var(--s-4); padding: var(--s-5); border: 2px solid var(--ink); background: var(--panel); }
.fare__out { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4); border-top: 2px solid var(--ink); padding-top: var(--s-4); margin-top: var(--s-2); }
.fare__out b { font-family: var(--f-sign); font-weight: 700; font-size: 2.5rem; line-height: 1; font-variant-numeric: tabular-nums; }

/* ================================================================= FOOTER */
.foot { background: var(--ink); color: var(--paper); padding-block: var(--s-12) var(--s-8); margin-top: var(--s-16); }
.foot__grid { display: grid; gap: var(--s-8); }
@media (min-width: 800px) { .foot__grid { grid-template-columns: 2fr 1fr 1fr 1fr; } }
.foot h2 { font-family: var(--f-sign); font-weight: 700; font-size: 1.0625rem; margin: 0 0 var(--s-3); }
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-1); }
.foot a { display: inline-flex; align-items: center; min-height: var(--tap); text-decoration: none; }
.foot a:hover, .foot a:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.legal { margin-top: var(--s-10); padding-top: var(--s-5); border-top: 1px solid rgba(255,255,255,.22); font-size: .9375rem; max-width: 92ch; }
.legal p { margin: 0 0 var(--s-3); }

/* ---------------------------------------------------------------- layout */
.two { display: grid; gap: var(--s-8); }
@media (min-width: 940px) { .two { grid-template-columns: 1.15fr .85fr; gap: var(--s-12); } }
.stack { display: grid; gap: var(--s-6); }

/* REFLOW (WCAG 1.4.10). At 200% zoom a 1280px layout becomes 640px, so every
   multi-column arrangement collapses well before that and nothing is set in a
   width that cannot shrink. */
@media (max-width: 640px) {
  .two, .routes, .stack { grid-template-columns: 1fr; }
  .dep { grid-template-columns: auto 1fr; }
  .dep__in { grid-column: 2; text-align: left; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* ==================================================== ALERTS ON THE BOARD
   A disruption sitting in a different box from the answer is a disruption
   the rider does not see. The board carries it as a WORD in amber — the
   same #F2A900 rejected as a route line at 1.92:1 on paper, which measures
   8.8:1 here because the board is dark in both themes. */
.alert__routes { display: inline-flex; gap: 4px; margin-right: var(--s-2); vertical-align: -.4em; }
.board__note {
  margin: 0; padding: var(--s-3) var(--s-5);
  font-family: var(--f-sign); font-size: 1rem; line-height: 1.4;
  color: #F2A900; border-bottom: 2px solid #2A3038;
}
.board__note b, .dep__alert b { font-weight: 700; letter-spacing: .03em; }
.dep__alert {
  display: block; margin-top: 2px;
  font-family: var(--f-sign); font-size: .9375rem; color: #F2A900;
}

/* ============================================= WINDOWS HIGH CONTRAST MODE
   forced-colors replaces author color with the user's own chosen pair.
   That is the whole point of it, and this build does NOT opt out: the
   three-cue system was designed for exactly this loss, so the number and
   the stroke pattern carry the routes once the color goes.

   What has to be repaired is anything whose meaning lived in a BACKGROUND.
   A bullet with no pill is a number floating in space, and the diagram's
   label halo — painted in --panel — would otherwise survive as a colored
   blob sitting on top of forced text. */
@media (forced-colors: active) {
  .bullet, .alert__tag, .chip { border: 1px solid CanvasText; }
  .stop__label { stroke: Canvas; }
  .stop__dot { fill: Canvas; stroke: CanvasText; }
  .board__note, .dep__alert { color: CanvasText; }
  .diagram.is-focused .line { opacity: .25; }

  /* Six lines forced to one color are six identical lines, so here — and
     only here — every route takes a distinct dash. A CSS declaration beats
     the presentation attribute in the markup, so the ordinary diagram keeps
     its three solid trunk routes and this costs it nothing. */
  .line[data-route="1"] { stroke-dasharray: none; }
  .line[data-route="2"] { stroke-dasharray: 2 7; }
  .line[data-route="3"] { stroke-dasharray: 14 7; }
  .line[data-route="4"] { stroke-dasharray: 22 8 3 8; }
  .line[data-route="5"] { stroke-dasharray: 6 6; }
  .line[data-route="6"] { stroke-dasharray: 3 4 12 4; }
}

/* ================================================================ THE MAP
   A schematic answers "what order do the stops come in". It cannot answer
   "which side of the river is that" or "how far is the walk", and those are
   the questions people open a map for — so the network now ships BOTH, which
   is what every real agency does.

   Westbrook is invented, so its geography is invented too: generated from one
   seed in geo.py, with the same nineteen stops and the same topology as the
   diagram. Laying fictional routes over a real city's streets is exactly what
   this build refused to do in the first place.

   Every value below is measured in both themes — map labels sit on three
   different grounds (land, water, park) and the worst case is the one that
   has to clear AA. */
:root {
  --m-ground: #F1F0EC; --m-park: #DDE7D5; --m-water: #C6DCE8; --m-lock: #9FB9C6;
  --m-local: #E2E0DA;  --m-arterial: #D8D5CD; --m-case: #FAFAF8;
  --m-wharf: #C9C4B6;  --m-wharf-e: #AFA99A;
  /* every map label is measured against ALL THREE grounds it could land on —
     land, water and park — and the worst case is the one that has to clear AA.
     The neighborhood gray failed that test at 4.14 over water even though no
     label currently sits there; a map that gets edited will eventually put one
     there, so the color is solved for the case rather than for today. */
  --m-lbl-water: #2A5A6E;   /* worst 5.31 */
  --m-lbl-park: #3D5C33;    /* worst 5.33 */
  --m-lbl-hood: #4C565D;    /* worst 5.29 */
}
:root[data-theme="dark"] {
  --m-ground: #1A1E22; --m-park: #1E2A20; --m-water: #17313D; --m-lock: #2C4E5C;
  --m-local: #262B30;  --m-arterial: #2E343A; --m-case: #0E1114;
  --m-wharf: #34383C;  --m-wharf-e: #4A4F55;
  --m-lbl-water: #7FB2C9;   /* 5.91 worst case */
  --m-lbl-park: #8FB783;    /* 6.01 */
  --m-lbl-hood: #9AA3AA;    /* 5.31 */
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --m-ground: #1A1E22; --m-park: #1E2A20; --m-water: #17313D; --m-lock: #2C4E5C;
    --m-local: #262B30;  --m-arterial: #2E343A; --m-case: #0E1114;
    --m-wharf: #34383C;  --m-wharf-e: #4A4F55;
    --m-lbl-water: #7FB2C9; --m-lbl-park: #8FB783; --m-lbl-hood: #9AA3AA;
  }
}

.citymap { background: var(--m-ground); border: 2px solid var(--ink);
           overflow-x: auto; overflow-y: hidden; }
.citymap svg { display: block; width: 100%; min-width: 900px; height: auto; }
.citymap .ground { fill: var(--m-ground); }
.citymap .park { fill: var(--m-park); }
.citymap .water { fill: var(--m-water); }
.citymap .lock { fill: var(--m-lock); }
.citymap .wharf { fill: var(--m-wharf); stroke: var(--m-wharf-e); stroke-width: 1.5; }
.citymap .locals path { stroke: var(--m-local); stroke-width: 2.2; fill: none; }
.citymap .arterials path { stroke: var(--m-arterial); stroke-width: 7; fill: none;
                           stroke-linecap: round; }
.citymap .rcase { stroke: var(--m-case); stroke-width: 11; fill: none;
                  stroke-linecap: round; stroke-linejoin: round; }
.citymap .rline { stroke-width: 5.5; fill: none; stroke-linecap: round;
                  stroke-linejoin: round; transition: opacity var(--mid, 240ms) ease; }
.citymap .mstop__dot { fill: var(--m-case); stroke: var(--ink); stroke-width: 2.4; }
.citymap .mstop__no { stroke: var(--ink); stroke-width: 2; fill: none; }
.citymap .mstop__label { font-family: var(--f-sign); font-size: 12.5px; font-weight: 600;
  fill: var(--ink); paint-order: stroke fill; stroke: var(--m-ground); stroke-width: 3.6;
  stroke-linejoin: round; }
.citymap .lbl { font-family: var(--f-sign); font-size: 11px; font-weight: 600;
                letter-spacing: .08em; }
.citymap .lbl--water { fill: var(--m-lbl-water); font-style: italic; letter-spacing: .14em; }
.citymap .lbl--park { fill: var(--m-lbl-park); }
.citymap .lbl--hood { fill: var(--m-lbl-hood); letter-spacing: .16em; font-size: 12px; }
.citymap .frame { fill: none; stroke: var(--ink); stroke-width: 2; }
.citymap .mstop:focus { outline: 3px solid var(--ink); outline-offset: 2px; }
/* one route in focus: the rest step back but never vanish */
.citymap.is-focused .rline { opacity: .16; }
.citymap.is-focused .rline.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .citymap .rline { transition: none; } }

/* ============================================================== FIGURES
   Full color, one light grade. These are real buses run by real agencies —
   the captions describe the EQUIPMENT, never "our fleet". */
.fig { margin: 0; }
.fig img { display: block; width: 100%; height: auto; border: 2px solid var(--ink); }
.fig figcaption { margin-top: var(--s-3); font-size: var(--t--1, .8125rem);
                  line-height: 1.5; color: var(--ink-2); max-width: 62ch; }
.fig--wide img { border-inline: 0; }
.two-up { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-5); align-items: start; }

.film { position: relative; border: 2px solid var(--ink); margin: 0; }
.film video { display: block; width: 100%; height: auto; background: #000; }
.film__btn { position: absolute; left: var(--s-4); bottom: var(--s-4); min-height: 44px;
  min-width: 44px; padding: var(--s-2) var(--s-4); background: var(--paper); color: var(--ink);
  border: 2px solid var(--ink); font: inherit; font-weight: 600; cursor: pointer; }

/* ================================================================== FAQ
   Flat. Nothing folded away — at B=4 an accordion is a wall between a person
   and a fact they came for, and "how do I pay" is not worth a click. */
.faq { display: grid; gap: var(--s-7); }
.faq h3 { margin: 0 0 var(--s-3); }
.faq p { margin: 0 0 var(--s-3); max-width: 66ch; }
.faq p:last-child { margin-bottom: 0; }
.faq__item { border-top: 2px solid var(--line); padding-top: var(--s-5); }

@media (max-width: 760px) { .two-up { grid-template-columns: 1fr; } }
@media (forced-colors: active) {
  .citymap .rline { stroke-width: 4; }
  .citymap.is-focused .rline { opacity: 1; }
  .citymap .mstop__label { stroke: Canvas; }
}

/* ---------- Built by Iron Digital MI ----------
   currentColor throughout so the line inherits whatever the footer already is.
   The mark itself is never recolored. */
.id-by { margin: 1.6em 0 0; }
.id-by a { display: inline-flex; align-items: center; gap: .6em;
  color: inherit; text-decoration: none; font-size: .8125rem; line-height: 1.3; }
.id-by a:hover span, .id-by a:focus-visible span { text-decoration: underline; }
.id-by img { width: 26px; height: 26px; display: block; flex: 0 0 auto; }
.id-by b { font-weight: 700; }

/* September UI refinement */
#board{scroll-margin-top:110px}.sign-platform{font-size:clamp(36px,6vw,70px)}
@media(max-width:600px){.masthead__in{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 8px}.wordmark{font-size:16px;gap:8px;white-space:nowrap}.themebtn{font-size:12px;padding-inline:8px}.masthead .nav{grid-row:2;grid-column:1/-1;flex-wrap:nowrap;overflow-x:auto;gap:4px}.masthead .nav a{font-size:14px;white-space:nowrap}.themebtn{grid-row:1;grid-column:2}#board>.stack{display:contents}#board>.stack>.field{grid-row:1}#board>div:first-child{grid-row:2}#board>.stack>div:last-child{grid-row:3}.dep{grid-template-columns:32px minmax(0,1fr) auto;padding:16px 12px;gap:10px}.dep__in{grid-column:3;text-align:right;font-size:28px}.dep__to{font-size:18px}.dep__note{font-size:14px}.dep__in small{font-size:12px}.dep .bullet{width:32px;height:32px}}
