*,*::before,*::after{box-sizing:border-box}
:root{
  --page:#F1F4F6; --surface:#FFFFFF; --ink:#101A21; --ink-2:#4B5B66;
  --rule:#C7D1D8; --brand:#0B3D5C;
  --band:#0B3D5C; --band-fg:#FFFFFF;
  --ok:#186A3B;  --ok-bg:#E4F1E8;
  --warn:#7A4A00;--warn-bg:#FBEFD8;
  --bad:#A32118; --bad-bg:#FBE6E3;
  --grey:#4B5B66;--grey-bg:#E7EBEE;
  --btn-bg:#0B3D5C; --btn-fg:#FFFFFF;
  --radius:6px;
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
@media (prefers-color-scheme: dark){
  :root{
    --page:#0C1216; --surface:#151E24; --ink:#E9EFF2; --ink-2:#9FB2BD;
    --rule:#2C3A44; --brand:#8FC7E8;
    --band:#0A1A24; --band-fg:#FFFFFF;
    --ok:#6FCE95;  --ok-bg:#12291C;
    --warn:#F0B95C;--warn-bg:#2E2210;
    --bad:#FF9086; --bad-bg:#331815;
    --grey:#9FB2BD;--grey-bg:#1E282F;
    --btn-bg:#1D4F6B; --btn-fg:#EAF4FA;
  }
}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--page);color:var(--ink);
  font:400 19px/1.45 var(--font);
  -webkit-font-smoothing:antialiased}
h1,h2,h3,p,ol,ul,figure{margin:0}
ol,ul{list-style:none;padding:0}
a{color:var(--brand);text-underline-offset:.18em}

/* header ------------------------------------------------------------- */
.top{background:var(--band);color:var(--band-fg)}
@media (prefers-color-scheme: dark){ .top{border-bottom:1px solid var(--rule)} }
.top .bar{max-width:56rem;margin:0 auto;padding:var(--s3) var(--s4);
  display:flex;align-items:center;justify-content:space-between;gap:var(--s3)}
.brand{font:700 21px/1 var(--font);color:var(--band-fg);text-decoration:none;letter-spacing:-.01em}
.top .clock-now{font:700 17px/1 var(--font);font-variant-numeric:tabular-nums;color:var(--band-fg);opacity:.85}
.tabs{max-width:56rem;margin:0 auto;padding:0 var(--s4);display:flex;gap:var(--s5);
  overflow-x:auto;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tabs a{color:var(--band-fg);opacity:.72;text-decoration:none;font:600 15px/1 var(--font);
  padding:var(--s3) 0 10px;border-bottom:2px solid transparent;white-space:nowrap;
  min-height:44px;display:flex;align-items:center}
.tabs a[aria-current]{opacity:1;border-bottom-color:var(--band-fg)}

/* layout ------------------------------------------------------------- */
main{max-width:56rem;margin:0 auto;padding:var(--s5) var(--s4) var(--s6)}
h1{font:700 26px/1.15 var(--font);letter-spacing:-.015em;margin-bottom:var(--s2)}
h2{font:700 21px/1.2 var(--font);letter-spacing:-.01em;margin:var(--s6) 0 var(--s3)}
h3{font:600 19px/1.25 var(--font);margin:var(--s5) 0 var(--s2)}
.sub{color:var(--ink-2);font-size:17px;margin-bottom:var(--s4)}
.card{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);
  margin:var(--s3) 0}
.pad{padding:var(--s4)}
.muted{color:var(--ink-2);font-size:15px}

/* picker ------------------------------------------------------------- */
.picker{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);
  padding:var(--s3);display:grid;gap:var(--s2)}
.picker > *{min-width:0}
.field{position:relative;display:block;border:1px solid var(--rule);
  border-radius:var(--radius);background:var(--surface);
  padding:var(--s2) var(--s3) 10px;overflow:hidden}
.field .lab{display:block;font:700 13px/1 var(--font);letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-2);margin-bottom:2px}
.field select{appearance:none;border:0;background:transparent;color:var(--ink);
  font:600 19px/1.2 var(--font);width:100%;min-width:0;
  padding:6px 22px 6px 0;min-height:32px;text-overflow:ellipsis}
.field .caret{position:absolute;right:var(--s3);bottom:16px;color:var(--ink-2)}
.actions{display:flex;gap:var(--s2);min-width:0}
.actions .btn{min-width:0}
.btn{font:700 17px/1 var(--font);min-height:52px;border-radius:var(--radius);
  border:1px solid var(--btn-bg);background:var(--btn-bg);color:var(--btn-fg);
  display:flex;align-items:center;justify-content:center;gap:var(--s2);
  flex:1;text-decoration:none;cursor:pointer;padding:0 var(--s4)}
.btn.ghost{background:var(--surface);color:var(--brand);flex:none;width:52px;padding:0}
.btn svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:2}

/* mode filter -------------------------------------------------------- */
.modes{display:flex;flex-wrap:wrap;gap:var(--s2);margin:var(--s3) 0 0}
.modes:empty{display:none}
.modes .mode{font:700 15px/1 var(--font);min-height:40px;padding:0 var(--s3);
  border:1px solid var(--rule);border-radius:var(--radius);
  background:var(--surface);color:var(--ink);cursor:pointer}
.modes .mode[aria-pressed="true"]{background:var(--btn-bg);color:var(--btn-fg);
  border-color:var(--btn-bg)}
.modes .mode[disabled]{color:var(--ink-2);opacity:.55;cursor:default}

/* freshness ---------------------------------------------------------- */
.asof{display:flex;align-items:center;gap:var(--s2) var(--s3);flex-wrap:wrap;
  color:var(--ink-2);font-size:15px;margin:var(--s3) 0 0;line-height:1.3}
.asof b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.asof .f{display:flex;align-items:center;gap:6px;white-space:nowrap}
/* the bus pages' note is a sentence, not a stamp: it wraps rather than
   running off the right edge of a 414px phone */
.asof .f.long{white-space:normal;flex:1 1 100%;min-width:0}
.asof .f svg{width:9px;height:9px;flex:none;fill:var(--ok)}
.asof .f.stale svg{fill:var(--grey)}
.banner{display:flex;gap:var(--s3);align-items:flex-start;border-radius:var(--radius);
  padding:var(--s3) var(--s4);margin:var(--s3) 0;font-size:17px;line-height:1.35}
.banner svg{width:18px;height:18px;flex:none;margin-top:4px}
.banner.grey{background:var(--grey-bg);color:var(--grey);fill:var(--grey)}
.banner.warn{background:var(--warn-bg);color:var(--warn);fill:var(--warn)}
.banner.bad{background:var(--bad-bg);color:var(--bad);fill:var(--bad)}
.banner b{font-weight:700}

/* chips -------------------------------------------------------------- */
.chip{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  font:700 13px/1 var(--font);letter-spacing:.01em;
  padding:6px 9px;border-radius:var(--radius)}
.chip svg{width:11px;height:11px;flex:none}
.chip.ok{background:var(--ok-bg);color:var(--ok);fill:var(--ok)}
.chip.warn{background:var(--warn-bg);color:var(--warn);fill:var(--warn)}
.chip.bad{background:var(--bad-bg);color:var(--bad);fill:var(--bad)}
.chip.grey{background:var(--grey-bg);color:var(--grey);fill:var(--grey)}
.chip.bad.solid{background:var(--bad);color:var(--surface);fill:var(--surface)}
.chip.warn.solid{background:var(--warn);color:var(--surface);fill:var(--surface)}

/* day heading -------------------------------------------------------- */
.day{position:sticky;top:0;z-index:2;background:var(--page);
  font:700 13px/1 var(--font);letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-2);padding:var(--s4) 0 var(--s2);
  border-bottom:1px solid var(--rule)}

/* now line ----------------------------------------------------------- */
.nowline{display:flex;align-items:center;gap:var(--s3);margin:var(--s3) 0 0}
.nowline i{flex:1;height:2px;background:var(--brand);display:block}
.nowline span{font:700 13px/1 var(--font);letter-spacing:.06em;text-transform:uppercase;
  color:var(--brand);font-variant-numeric:tabular-nums}

/* departure row ------------------------------------------------------ */
.list{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);
  margin-top:var(--s2);overflow:hidden}
.dep{display:grid;grid-template-columns:92px minmax(0,1fr);column-gap:var(--s3);
  padding:var(--s3) var(--s4);border-top:1px solid var(--rule);align-items:start}
.list .dep:first-child{border-top:0}
.dep .clock{grid-column:1;grid-row:1;font:700 28px/1.05 var(--font);
  font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.dep .rel{grid-column:1;grid-row:2/span 2;color:var(--ink-2);font-size:15px;
  font-variant-numeric:tabular-nums;padding-top:2px}
.dep .od{grid-column:2;grid-row:1;font:600 19px/1.25 var(--font);
  display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;
  min-height:26px;padding-right:0}
.dep .od .chip{margin-left:auto;align-self:center}
.dep .gd{grid-column:2;grid-row:2;color:var(--ink-2);font-size:15px;line-height:1.3}
.dep .foot{grid-column:2;grid-row:3;display:flex;align-items:center;gap:var(--s2);
  flex-wrap:wrap;margin-top:4px;color:var(--ink-2);font-size:15px;
  font-variant-numeric:tabular-nums}
.arw{color:var(--ink-2);font-weight:400}
.dep.past .clock,.dep.past .od{color:var(--ink-2);font-weight:600}
.dep .was{display:block;color:var(--ink-2);text-decoration:line-through;
  font:400 17px/1.1 var(--font);font-variant-numeric:tabular-nums;margin-bottom:1px}
.dep .clock.retimed{color:var(--warn)}
.dep.cancelled .clock{color:var(--ink-2);text-decoration:line-through}
.dep .clock small{font-size:17px;color:var(--ink-2);font-weight:400;
  margin-left:2px;vertical-align:top}

/* route card --------------------------------------------------------- */
.route{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);
  margin:var(--s3) 0;overflow:hidden}
.route > header{padding:var(--s4);display:flex;gap:var(--s3);align-items:flex-start;
  justify-content:space-between}
.route h2{margin:0;font:700 19px/1.25 var(--font)}
.route h2 a{color:var(--ink);text-decoration:none}
.route .gd{color:var(--ink-2);font-size:15px;margin-top:2px}
.route .notice-line{padding:var(--s3) var(--s4);border-top:1px solid var(--rule);
  display:flex;gap:var(--s2);align-items:flex-start;font-size:15px;color:var(--ink-2)}
.route .notice-line svg{width:12px;height:12px;flex:none;margin-top:5px;fill:var(--warn)}
.route .notice-line.bad svg{fill:var(--bad)}
.route .rows{border-top:1px solid var(--rule)}
.route .rows .rowday{padding:var(--s2) var(--s4);border-top:1px solid var(--rule);
  background:var(--page);font:700 13px/1 var(--font);letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-2)}
.route .rows .dep{padding:10px var(--s4)}
.route .rows .dep .clock{font-size:24px}
.route .more{display:block;padding:var(--s3) var(--s4);border-top:1px solid var(--rule);
  font:600 17px/1 var(--font);text-decoration:none;min-height:48px;
  display:flex;align-items:center;justify-content:space-between}

/* notices ------------------------------------------------------------ */
.notice{border:1px solid var(--rule);border-left:4px solid var(--warn);
  border-radius:var(--radius);background:var(--surface);padding:var(--s4);margin:var(--s3) 0}
.notice.bad{border-left-color:var(--bad)}
.notice.info{border-left-color:var(--rule)}
.notice h3{margin:0 0 var(--s1);font:700 19px/1.25 var(--font)}
.notice p{font-size:17px;line-height:1.4}
.notice .when{color:var(--ink-2);font-size:15px;margin-top:var(--s2)}
.notice details{margin-top:var(--s2)}
.notice summary{font:600 15px/1 var(--font);color:var(--brand);cursor:pointer;
  min-height:44px;display:flex;align-items:center}

/* tables ------------------------------------------------------------- */
.tablewrap{overflow-x:auto;border:1px solid var(--rule);border-radius:var(--radius);
  background:var(--surface)}
table{border-collapse:collapse;width:100%;font-size:17px;font-variant-numeric:tabular-nums}
th,td{padding:10px var(--s3);border-top:1px solid var(--rule);text-align:left;white-space:nowrap}
thead th{border-top:0;font:700 13px/1.2 var(--font);letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-2);vertical-align:bottom}
td.n,th.n{text-align:right}
tbody th{font-weight:600}
thead th{white-space:normal}
@media (max-width:520px){
  table{font-size:15px}
  th,td{padding:8px}
}
.gap{height:var(--s3)}

.stats{background:var(--surface);border:1px solid var(--rule);
  border-radius:var(--radius);overflow:hidden}
.stats h4{margin:0;padding:10px var(--s4);background:var(--page);
  font:700 13px/1 var(--font);letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-2);border-bottom:1px solid var(--rule)}
.stats dl{margin:0}
.stats h4 + dl .row:first-child,.stats h4 + .row{border-top:0}
.stats .row{display:flex;justify-content:space-between;gap:var(--s4);
  padding:10px var(--s4);border-top:1px solid var(--rule);font-size:17px}
.stats .row dt{color:var(--ink-2);min-width:0}
.stats .row dd{margin:0;font-weight:700;font-variant-numeric:tabular-nums;
  white-space:nowrap}

/* buttons row -------------------------------------------------------- */
.calbtns{display:flex;gap:var(--s2);flex-wrap:wrap;margin-top:var(--s2)}
.calbtns a{flex:1 1 12rem;min-height:52px;border:1px solid var(--brand);color:var(--brand);
  border-radius:var(--radius);display:flex;align-items:center;justify-content:center;
  text-decoration:none;font:700 17px/1 var(--font);background:var(--surface)}

/* empty state -------------------------------------------------------- */
.empty{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);
  padding:var(--s5) var(--s4);margin-top:var(--s2)}
.empty b{display:block;font:700 19px/1.3 var(--font);margin-bottom:var(--s1)}
.empty p{color:var(--ink-2);font-size:17px}

/* footer ------------------------------------------------------------- */
footer{max-width:56rem;margin:var(--s6) auto 0;padding:var(--s5) var(--s4) var(--s6);
  border-top:1px solid var(--rule);color:var(--ink-2);font-size:15px;line-height:1.5}
footer p + p{margin-top:var(--s3)}

@media (min-width:720px){
  h1{font-size:32px}
  .picker{grid-template-columns:1fr 1fr;align-items:end}
  .actions{grid-column:1/-1}
  .dep{grid-template-columns:120px minmax(0,1fr)}
  .dep .clock{font-size:30px}
}

/* --------------------------------------------------------------------
   Live-site additions to the approved mockup sheet. Same kit: type, a
   rule, or a state name. Nothing here is an effect.
   -------------------------------------------------------------------- */

/* the now line also renders INSIDE a list, between the last past departure
   and the next future one (design direction sec. 6); as the first child of a
   list it is the standalone form the mockups show above the card */
.list li.nowline{display:flex;align-items:center;gap:var(--s3);
  padding:10px var(--s4);border-top:1px solid var(--rule);margin:0}
.list li.nowline:first-child{border-top:0}
.dep.past .rel,.dep.past .gd,.dep.past .foot{color:var(--ink-2)}

/* keyboard focus: the one other job --brand does */
a:focus-visible,button:focus-visible,select:focus-visible,summary:focus-visible{
  outline:3px solid var(--brand);outline-offset:2px}
.top a:focus-visible,.tabs a:focus-visible{outline-color:var(--band-fg)}
/* the tab strip scrolls horizontally, so an outset ring is clipped to two
   vertical bars; inset it and the whole ring survives */
.tabs a:focus-visible{outline-offset:-3px}

/* pickers list ports and airports apart; the OS wheel already knows how to
   draw a group heading */
.field optgroup{font-weight:700;color:var(--ink)}
.field option{font-weight:400}

/* the projected-time asterisk legend, and any line that trails a list */
.legend{color:var(--ink-2);font-size:15px;margin-top:var(--s2)}

/* route cards: the timetable sentence sits where the notice line does */
.route .notice-line.plain{color:var(--ink-2)}
.route .rows .dep .od{padding-right:0}

/* board-fallback list heading inside a route card */
.route h3{margin:var(--s4) var(--s4) var(--s2);font:600 17px/1.25 var(--font)}
.route .muted{padding:0 var(--s4) var(--s3);display:block}
.route .list{margin:0 var(--s4) var(--s4)}

/* journeys: one card per two-leg option, the wait line under it */
.journey{margin-top:var(--s3)}
.journey + .journey{margin-top:var(--s5)}

/* live map ------------------------------------------------------------
   A diagram in the same kit as everything else: a line, a mark, a word.
   No tiles, no external request, no effect. Marks are sized in user units
   by map.js (styleFor), so only colour and dash live here. */
.mapfig{margin:var(--s4) 0 0}
.mapbox{background:var(--surface);border:1px solid var(--rule);
  border-radius:var(--radius);overflow:hidden}
.mapbox .empty{border:0;background:transparent;margin:0}
.mapbox .empty span{display:block;color:var(--ink-2);font-size:17px}
.map{display:block;width:100%;height:auto;max-height:80vh;font-family:var(--font)}
.mapfig.panel .map{height:220px;max-height:220px}
[data-map-note]{display:block;margin-top:var(--s2)}
[data-map-note] span{display:block}
/* the drawing in words, for a reader who cannot see it */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

/* the land, the routes and the places */
.map .coast{fill:none;stroke:var(--ink-2);stroke-linejoin:round;stroke-linecap:round}
.map .leg{fill:none;stroke:var(--ink-2);stroke-dasharray:6 5;stroke-linecap:round}
.map text{paint-order:stroke;stroke:var(--surface);stroke-linejoin:round}
.map .lab{fill:var(--ink-2);font-weight:600}
.map .edge{fill:var(--ink-2);font-weight:400}
.map .vlab{fill:var(--ink);font-weight:700;font-variant-numeric:tabular-nums}
.map .veh.stale .vlab{fill:var(--grey)}

/* the marks, shared with the legend so the two cannot drift apart */
.port{fill:var(--ink-2)}
.airport{fill:var(--ink-2)}
.ship{fill:var(--brand);stroke:none}
.cog{fill:var(--brand)}
.ac{fill:var(--brand);stroke:none}
.bus{fill:none;stroke:var(--ink-2)}
.veh.stale .ship,.ship.stale-mark{fill:none;stroke:var(--grey)}
.veh.stale .cog{fill:var(--grey)}
.veh.stale .ac{fill:none;stroke:var(--grey)}

/* legend: one row per mark, the word beside the shape */
.maplegend{margin-top:var(--s2);background:var(--surface);border:1px solid var(--rule);
  border-radius:var(--radius);overflow:hidden}
.maplegend li{display:flex;gap:var(--s3);align-items:flex-start;
  padding:var(--s3) var(--s4);border-top:1px solid var(--rule);
  font-size:15px;color:var(--ink-2);line-height:1.35}
.maplegend li:first-child{border-top:0}
.maplegend svg{width:26px;height:26px;flex:none}
.maplegend b{color:var(--ink);font-weight:700}
.maplegend .coming,.maplegend .coming b{color:var(--grey)}
.maplegend .coming .bus{stroke:var(--grey)}

/* --------------------------------------------------------------------
   Buses (Task 15b). Same kit as everything else: type, a rule, a state
   name. Tokens only; nothing here introduces a colour.
   -------------------------------------------------------------------- */

/* the typeahead. The <select> is still the field that holds the value, so it
   is hidden rather than removed, and without JavaScript nothing below applies
   and the OS wheel is what a reader gets. */
.field.ta{overflow:visible}
.ta .ta-input{appearance:none;border:0;background:transparent;color:var(--ink);
  font:600 19px/1.2 var(--font);width:100%;min-width:0;
  padding:6px 22px 6px 0;min-height:32px;text-overflow:ellipsis}
.ta .ta-input::-webkit-search-cancel-button{display:none}
.ta .ta-input::placeholder{color:var(--ink-2);font-weight:400}
.ta-list{position:absolute;z-index:5;left:-1px;right:-1px;top:calc(100% + 4px);
  max-height:min(60vh,22rem);overflow-y:auto;background:var(--surface);
  border:1px solid var(--rule);border-radius:var(--radius)}
.ta-group{font:700 13px/1 var(--font);letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-2);padding:var(--s3) var(--s4) var(--s2);background:var(--page);
  border-top:1px solid var(--rule)}
.ta-list > .ta-group:first-child{border-top:0}
.ta-opt{padding:10px var(--s4);border-top:1px solid var(--rule);cursor:pointer;
  min-height:44px;display:flex;flex-direction:column;justify-content:center}
.ta-group + .ta-opt{border-top:0}
.ta-opt b{font:600 17px/1.25 var(--font);color:var(--ink)}
.ta-opt span{font-size:15px;color:var(--ink-2);line-height:1.3}
.ta-opt[aria-selected="true"]{background:var(--grey-bg)}
.ta-opt[aria-selected="true"] b{color:var(--ink)}
@media (hover:hover){ .ta-opt:hover{background:var(--grey-bg)} }
.ta-none{padding:var(--s4);font-size:15px;color:var(--ink-2)}
.ta .ta-input:focus-visible{outline:3px solid var(--brand);outline-offset:2px}

/* the line number, on a card head and a page title: a label, not a badge */
.line{font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.route.bus h2 .line{color:var(--ink)}

/* the trips table: stop names down, journeys across. It scrolls inside its
   own container, which the site already has; the stop column stays put so a
   time three columns right still has a name against it. */
table.trips th[scope="row"]{position:sticky;left:0;background:var(--surface);
  font:400 15px/1.25 var(--font);white-space:nowrap;max-width:14rem;
  overflow:hidden;text-overflow:ellipsis;border-right:1px solid var(--rule)}
table.trips tr.tp th[scope="row"]{font-weight:700;color:var(--ink)}
table.trips thead th{font-variant-numeric:tabular-nums;font-size:15px;
  text-transform:none;letter-spacing:0;color:var(--ink)}
table.trips thead th:first-child{position:sticky;left:0;background:var(--page);
  text-align:left;color:var(--ink-2);border-right:1px solid var(--rule)}
table.trips td{color:var(--ink-2);font-size:15px}
table.trips td:not(:empty){color:var(--ink)}
table.trips .fn{font-weight:700;color:var(--ink-2);margin-left:2px}
.tablewrap{max-height:70vh;overflow:auto}

/* the printed sheets, listed as links */
.pdfs{margin-top:var(--s2);background:var(--surface);border:1px solid var(--rule);
  border-radius:var(--radius);overflow:hidden}
.pdfs li{padding:var(--s3) var(--s4);border-top:1px solid var(--rule);font-size:17px}
.pdfs li:first-child{border-top:0}
.pdfs .muted{font-size:15px}

/* a bus card carries its state in the header, so the rows carry only times */
.route.bus .notice-line.plain svg{fill:var(--grey)}
