/* FlyGamma - Aurora Glass

   The map is the page. Every other surface is glass laid over the world, so
   the traffic carries on underneath whatever is being read, and nothing takes
   a column away from the thing people came to look at.

   Dark is the default. The light theme is designed against paper-white rather
   than being the dark one inverted: the accent darkens, the glass turns to
   frosted white, and the ink is chosen against the ground it actually lands
   on rather than assumed from the other theme. */
:root {
  /* Ground and glass. The panels are translucent by design - the world behind
     them is the point - so every "background" here carries an alpha and the
     text tokens below are measured against the worst ground they can land on,
     which is the glass over bright ocean rather than the ground itself. */
  --bg: #07131a;
  --bg-panel: rgba(11, 29, 35, 0.80);
  --bg-raised: rgba(19, 45, 52, 0.72);
  --bg-hover: rgba(45, 212, 191, 0.11);
  --line: rgba(148, 232, 222, 0.16);
  --line-soft: rgba(148, 232, 222, 0.09);
  --text: #e8f4f2;
  --text-dim: #a9c1c2;
  /* Was #55677c, which measured 3.31:1 on the panel and 2.82:1 on a hovered
     row against a 4.5 requirement - and it is the token that names every
     figure on the console. */
  --text-faint: #8ba7ab;

  /* One accent used to mean brand, link, tab, focus ring, selection, hover,
     bar fill and clock all at once, which left nothing able to lead. The roles
     are separated: brand is the mark and nothing else, accent is anything you
     can act on, focus is reserved for the ring, and saved has its own colour
     so a starred flight never reads as a selected one. */
  --brand: #35d6cf;
  --accent: #35d6cf;
  --accent-dim: #0d9488;
  --focus: #7ff2e0;
  --saved: #a9b8ff;

  /* Six parts of the world, six colours, kept apart from the status palette on
     purpose. Amber and coral mean a flight is doing something; these mean an
     airport is somewhere, which is not a state and must not borrow the colours
     of one. Hues spread round the wheel so no two regions read as neighbours,
     and tuned per theme rather than one value squinting on both: measured
     against the panel each sits on, the worst of the fourteen is 5.1 to 1
     where AA wants 4.5.

     Seven, not six. The published airport table has six regions and the
     curated one the interface actually reads has seven - it separates the
     Middle East - so building the palette from the published file left DXB,
     DOH, AUH and thirteen others falling back to the accent. Read the table
     the list reads.

     Africa and the Middle East are the closest pair at sixteen degrees of hue,
     an orange against a gold. Seven hues in a band narrow enough to stay
     legible on both themes cannot all be far apart, and if two must be near
     neighbours it may as well be two regions that are near neighbours. */
  --region-asia: #7ad9c4;
  --region-europe: #8fbcff;
  --region-north-america: #c9a9ff;
  --region-south-america: #8fe08a;
  --region-africa: #ffb877;
  --region-middle-east: #e8cd7a;
  --region-oceania: #f7a3c4;

  /* Sand is attention, coral is failure. They used to be the same red, which
     made cancelled and delayed the same colour, and boarding and departed the
     same amber. */
  --amber: #f5c58a;
  --danger: #ff8878;
  --ok: #6ee7a8;

  --overlay: rgba(3, 12, 16, 0.62);
  --tool-bg: rgba(11, 29, 35, 0.82);
  --brand-ink: #032420;
  --brand-glow: rgba(94, 234, 212, 0.30);
  --shadow: 0 24px 60px -18px rgba(0, 0, 0, 0.72), 0 2px 8px rgba(0, 0, 0, 0.34);
  --scroll: rgba(148, 232, 222, 0.20);
  --scroll-hover: rgba(148, 232, 222, 0.34);
  --map-ground: #07131a;
  --map-match: #ff4dc4;
  --map-airport: #76b9ff;
  --sel-bg: rgba(45, 212, 191, 0.13);
  /* The same panel with the world taken out from behind it. */
  --bg-solid: #0c1f26;

  --mono: "JetBrains Mono", "Cascadia Mono", Consolas, "SF Mono", monospace;
  --sans: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --radius: 10px;
  --radius-lg: 18px;
  --blur: saturate(150%) blur(18px);

  --rail-w: 68px;
  --gap: 16px;
  --sidebar-w: 372px;
  --detail-w: 372px;
  /* Measured by app.js: the top row wraps, so nothing may assume its height. */
  --top-h: 60px;
  --dock-h: 46px;
}

:root[data-theme="light"] {
  --bg: #dfeaea;
  --bg-panel: rgba(252, 254, 253, 0.86);
  --bg-raised: rgba(255, 255, 255, 0.80);
  --bg-hover: rgba(10, 117, 112, 0.10);
  --line: rgba(12, 74, 71, 0.18);
  --line-soft: rgba(12, 74, 71, 0.10);
  --text: #08201f;
  --text-dim: #3d5c5c;
  --text-faint: #4f6d6d;

  --brand: #0b7d75;
  --accent: #087b77;
  --accent-dim: #0d9488;
  --focus: #06615d;
  --saved: #4b52b8;

  /* The same six, darkened for paper. A hue that carries on a dark panel is
     invisible on a white one, so these are their own values rather than the
     dark set at another opacity. */
  --region-asia: #00695c;
  --region-europe: #1d4ed8;
  --region-north-america: #6d28d9;
  --region-south-america: #2f7d32;
  --region-africa: #a34d00;
  --region-middle-east: #7d5b00;
  --region-oceania: #a3316a;

  /* Sand and coral both fail on paper, so the light theme takes their darker
     relatives rather than the same hex at a different opacity. */
  --amber: #8a5400;
  --danger: #b23325;
  --ok: #12714a;

  --overlay: rgba(16, 46, 48, 0.38);
  --tool-bg: rgba(252, 254, 253, 0.90);
  --brand-ink: #f2fffe;
  --brand-glow: rgba(10, 117, 112, 0.18);
  --shadow: 0 20px 44px -18px rgba(14, 58, 60, 0.34), 0 1px 3px rgba(14, 58, 60, 0.12);
  --scroll: rgba(12, 74, 71, 0.22);
  --scroll-hover: rgba(12, 74, 71, 0.36);
  --map-ground: #bcd7e4;
  --map-match: #ce1194;
  --map-airport: #174ea6;
  --sel-bg: rgba(10, 117, 112, 0.14);
  --bg-solid: #f7fbfa;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  overflow: hidden;
}

/* Mobile browser chrome makes the visual viewport shorter than 100% claims,
   which clipped the bottom of the map and the detail sheet. dvh tracks the
   chrome as it hides and returns; the percentages above stay as the fallback. */
@supports (height: 100dvh) {
  html, body { height: 100dvh; }
}

button, input, select { font-family: inherit; font-size: inherit; color: inherit; }

/* Present to a screen reader, absent to everyone else. Not display:none,
   which would take it out of the accessibility tree along with everything
   else. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* -------------------------------------------------------------- boot state */

/* The engine builds 2,384 legs before there is anything to show, so say so
   rather than presenting an empty console as though that were the answer. */
.boot-bar {
  position: fixed; top: 0; left: 0; right: 0; height: 2px;
  z-index: 60;
  overflow: hidden;
  display: none;
}
body.is-booting .boot-bar { display: block; }
.boot-bar::after {
  content: "";
  position: absolute; inset: 0 auto 0 0;
  width: 38%;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  animation: boot-sweep 1.15s ease-in-out infinite;
}
@keyframes boot-sweep {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(340%); }
}

.noscript {
  max-width: 46ch;
  margin: 14vh auto;
  padding: 0 24px;
  line-height: 1.65;
}
.noscript h1 { font-size: 20px; font-weight: 600; margin: 0 0 12px; color: var(--accent); }
.noscript p { margin: 0 0 12px; font-size: 13.5px; color: var(--text-dim); }

/* One focus ring for everything that can hold focus. :where() keeps it at zero
   specificity so a component can still opt out, but nothing may go back to
   drawing no ring at all - a border tint is not an indicator anyone can see. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scroll); border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: var(--scroll-hover); }

/* ------------------------------------------------------------ multiselect */

.ms { position: relative; min-width: 0; }
.ms-button {
  display: flex; align-items: center; gap: 6px;
  width: 100%;
  padding: 7px 8px;
  background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: 6px;
  color: var(--text);
  cursor: pointer;
  text-align: left;
}
.ms-button:hover { border-color: var(--accent-dim); }
.ms-button.is-set { border-color: var(--accent-dim); color: var(--accent); }
.ms-value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-caret { flex: none; font-size: 9px; color: var(--text-faint); }
.ms-button[aria-expanded="true"] .ms-caret { transform: rotate(180deg); }

/* Wider than the control that opened it: the button has to fit a half-column
   and the names do not. */
.ms-pop {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 40;
  width: max(100%, 250px);
  display: flex; flex-direction: column;
  background: var(--bg-raised);
  border: 1px solid var(--accent-dim); border-radius: 8px;
  box-shadow: 0 16px 40px var(--shadow);
  overflow: hidden;
}
.ms-pop[hidden] { display: none; }
/* The right-hand column would hang off the sidebar, so it opens leftwards. */
.filters .field:nth-child(even) .ms-pop { left: auto; right: 0; }

.ms-search {
  margin: 8px 8px 4px;
  padding: 7px 9px;
  background: var(--bg);
  border: 1px solid var(--line); border-radius: 6px;
  font-size: 12px;
}
.ms-search::placeholder { color: var(--text-faint); }

.ms-list { overflow-y: auto; max-height: 260px; padding: 4px; overscroll-behavior: contain; }
.ms-head {
  padding: 7px 6px 3px;
  font-size: 8.5px; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-faint);
}
.ms-opt {
  display: flex; align-items: baseline; gap: 7px;
  padding: 5px 7px;
  border-radius: 5px;
  font-size: 12px;
  cursor: pointer;
}
.ms-opt.is-active { background: var(--bg-hover); }
.ms-opt.is-on { color: var(--accent); }
.ms-tick { flex: none; width: 11px; font-size: 10px; }
.ms-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-empty { padding: 14px 10px; margin: 0; font-size: 11.5px; color: var(--text-faint); }

/* A short list needs no search box. The field is taken off the screen rather
   than out of the popup, so it still catches focus on opening: the arrow keys
   keep working, and typing still narrows the list the way a native select
   does without showing a box either. Same treatment the wordmark gets on a
   narrow screen. */
.ms-quiet .ms-search {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  border: 0; overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Clear sits above the list rather than under it, because that is where the
   thing it clears now sits. Tinted, so the bar reads as belonging to the
   selection it summarises rather than as another row of the list. */
.ms-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 7px 10px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--sel-bg);
}
.ms-bar[hidden] { display: none; }
/* Between what was chosen and everything else. Dashed rather than solid: it
   separates two halves of one list, not two lists. */
.ms-split { border-top: 1px dashed var(--line); margin: 5px 8px; }
.ms-clear {
  background: none; border: none; padding: 0;
  color: var(--accent); cursor: pointer;
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
}
.ms-clear:hover { text-decoration: underline; }
/* Undo stands where Clear stood, so the eye does not have to go looking for
   the way back from a button it did not mean to press. Amber rather than the
   accent: it is an offer that expires, not a control that is always there. */
.ms-undo {
  background: none; border: none; padding: 0;
  color: var(--amber); cursor: pointer;
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
}
.ms-undo:hover { text-decoration: underline; }
.ms-undo[hidden], .ms-clear[hidden] { display: none; }
.ms-count { font-size: 10px; color: var(--text-faint); }

.link-btn { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; padding: 0; }
.link-btn:hover { text-decoration: underline; }
.link-btn[hidden] { display: none; }

.list { flex: 1; overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable; }

.row {
  display: block;
  width: 100%;
  padding: 10px 14px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--line-soft);
  text-align: left;
  cursor: pointer;
  transition: background 0.12s;
}
.row:hover { background: var(--bg-hover); }
/* Rows sit flush inside a scroller, so the ring has to be drawn inwards or the
   scroll container clips it. */
.row:focus-visible, .ap-row:focus-visible { outline-offset: -3px; }
.row.is-selected { background: var(--sel-bg); box-shadow: inset 3px 0 0 var(--accent); }

.row-top { display: flex; align-items: center; gap: 8px; }
/* The route is the headline.

   It used to be the second line in 12px while the first line's widest element
   was the operator's name - and on three rows in four that name was the string
   "operator not given", because the feed reports a great many aircraft without
   naming who is flying them. So the biggest thing in the row was a sentence
   saying nothing, repeated the whole way down the list, and the thing a person
   actually scans for was underneath it in the smallest type on the row.
   Swapped. Where the operator is unknown nothing takes its place: the absence
   of a fact is not itself a fact and does not need a line. */
.row-where { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; font-family: var(--mono); }
.row-where .iata { font-size: 14px; color: var(--text); letter-spacing: 0.03em; }
.row-arrow { flex: 1; height: 1px; background: var(--line); position: relative; min-width: 16px; }
.row-arrow::after {
  content: ""; position: absolute; right: -1px; top: -2px;
  border-left: 5px solid var(--line); border-top: 2.5px solid transparent; border-bottom: 2.5px solid transparent;
}
.row-nowhere { font-size: 11px; color: var(--text-faint); font-family: var(--sans); }

/* Number, operator if there is one, aircraft - joined by middots rather than
   laid out in columns, so a missing middle closes up instead of leaving a gap
   where the name would have been. */
.row-sub { display: flex; align-items: baseline; gap: 8px; margin-top: 5px; }
.row-said {
  flex: 1; min-width: 0; font-size: 11px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A flight number is a code and is read a character at a time, so it is set in
   the same mono as every other code on the site. It was, as .row-cs; the rule
   did not survive the rename and the number spent one deploy as body text. */
.row-no { font-family: var(--mono); color: var(--text); font-variant-numeric: tabular-nums; }
.row-level {
  font-family: var(--mono); font-size: 10.5px; color: var(--text-faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.row-pct { margin-left: auto; font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* The middots live here rather than in the string, drawn before each part that
   follows another. That is what makes a missing operator close up: the
   separator belongs to the thing after it, so when there is nothing after it
   there is no separator either - and the compact density can hide a part
   without leaving a dot hanging behind it. */
.row-said > span + span::before { content: " · "; color: var(--text-faint); }

/* --------------------------------------------------------- inline flights */

/* The route belongs in the list even before a flight is opened. The former
   five-column board hid the cities and carrier to fit level, speed and state
   into one line; the selected flight then vanished behind a right-hand sheet
   on phones. One row now grows in place, with the real logo and both cities
   still visible while its useful journey facts unfold below. */
.list.is-compact .flight-inline { border-bottom: 1px solid var(--line-soft); }
.list.is-compact .flight-inline-trigger {
  display: grid;
  grid-template-columns: 26px 28px minmax(0, 1fr);
  align-items: center; column-gap: 7px;
  min-height: 50px; padding: 7px 10px;
  border-bottom: 0;
}
.list.is-compact .flight-inline-trigger.is-selected { box-shadow: inset 3px 0 0 var(--accent); }
/* All three expanding lists use the same left-hand cue. A chevron at the far
   right was hard to find beside the live counts, especially in narrow rows. */
.flight-inline-disclosure, .al-expand-glyph, .ac-type-disclosure, .ap-expand-glyph {
  display: grid; place-items: center; width: 26px; height: 26px;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--bg-raised); color: var(--accent);
  font: 600 19px/1 var(--sans);
}
/* The whole row remains one target. The left control names its action, while
   a tap on the flight or city still opens the same answer. */
.flight-inline-trigger:hover .flight-inline-disclosure,
.flight-inline-trigger:focus-visible .flight-inline-disclosure,
.al-expand:hover .al-expand-glyph,
.al-expand:focus-visible .al-expand-glyph,
.ac-type-row:hover .ac-type-disclosure,
.ac-type-row:focus-visible .ac-type-disclosure { border-color: var(--accent); }
.flight-inline.is-open .flight-inline-disclosure,
.al-expand[aria-expanded="true"] .al-expand-glyph,
.ac-type-row[aria-expanded="true"] .ac-type-disclosure {
  border-color: var(--accent); background: var(--accent); color: var(--brand-ink);
}
.flight-inline-logo { position: relative; display: grid; place-items: center; width: 28px; height: 28px; }
.flight-inline-logo .mark { width: 28px; height: 28px; }
.flight-inline-logo .row-star {
  position: absolute; top: -5px; left: -5px; z-index: 1;
}
.flight-inline-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.flight-inline-head { display: flex; justify-content: space-between; align-items: center; gap: 6px; min-width: 0; }
.flight-inline-airline {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11px; color: var(--text-dim);
}
/* A collapsed row has exactly two reading lines: carrier/flight/state above,
   both code-and-city pairs plus the arrival clock below. Long city names may
   shorten at a narrow phone width, but the button's full label still reads them. */
.flight-inline-head-facts { display: flex; align-items: baseline; gap: 6px; flex: none; white-space: nowrap; }
.flight-inline-head-facts b { color: var(--accent); font: 500 12px var(--mono); }
.flight-inline-head-facts small {
  max-width: 92px; overflow: hidden; text-overflow: ellipsis;
  color: var(--text-faint); font-size: 10.5px;
}
.flight-inline-route {
  display: grid; grid-template-columns: minmax(0, 1fr) 12px minmax(0, 1fr) auto;
  align-items: baseline; gap: 5px; min-width: 0;
}
.flight-inline-place { display: flex; align-items: baseline; min-width: 0; gap: 4px; white-space: nowrap; }
.flight-inline-place strong { flex: none; font: 500 13px var(--mono); color: var(--text); }
.flight-inline-place small {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11px; color: var(--text-faint);
}
.flight-inline-arrow { color: var(--accent); font-size: 15px; text-align: center; }
.flight-inline-eta { text-align: right; white-space: nowrap; }
.flight-inline-eta strong { font: 500 13px var(--mono); color: var(--text); }
.flight-inline-detail { padding: 2px 10px 10px 78px; font-size: 11px; }
.flight-inline-arrival { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.flight-inline-arrival > span { display: flex; align-items: baseline; gap: 5px; flex-wrap: wrap; }
.flight-inline-arrival strong { color: var(--text); font: 500 17px var(--mono); }
.flight-inline-arrival small { color: var(--text-faint); font-size: 10.5px; }
.flight-inline-arrival em { color: var(--accent); font-style: normal; white-space: nowrap; }
.flight-inline-arrival em.is-late { color: var(--amber); }
.flight-inline-progress-meta { display: flex; justify-content: space-between; gap: 8px; margin-top: 9px; }
.flight-inline-progress-meta strong { font-weight: 500; }
.flight-inline-progress-meta span { color: var(--text-faint); }
.flight-inline-track { height: 3px; margin-top: 6px; overflow: hidden; border-radius: 3px; background: var(--line-soft); }
.flight-inline-track i { display: block; height: 100%; background: var(--accent); }
.flight-inline-foot { display: flex; align-items: center; justify-content: space-between; gap: 5px 8px; flex-wrap: wrap; margin-top: 7px; color: var(--text-faint); }
.flight-inline-foot b { color: var(--text); font-weight: 500; }
.flight-inline-loading { display: block; margin-top: 6px; color: var(--text-faint); }
.flight-inline-map {
  border: 0; background: transparent; color: var(--accent); font: 500 11px var(--sans);
  padding: 6px 0; margin-left: auto; cursor: pointer;
}
.flight-inline-map:hover { text-decoration: underline; text-underline-offset: 2px; }
.flight-inline-map:focus-visible { outline-offset: 2px; }
@media (max-width: 600px) {
  .flight-inline-map { min-height: 40px; }
}
.field select { color-scheme: dark; }
:root[data-theme="light"] .field select { color-scheme: light; }
.field select option { background: var(--bg-raised); color: var(--text); }

.row-bar { height: 3px; background: var(--line-soft); border-radius: 2px; margin-top: 7px; overflow: hidden; }
.row-bar i { display: block; height: 100%; background: var(--accent); border-radius: 2px; }

.row-meta { display: flex; align-items: center; gap: 8px; margin-top: 7px; font-size: 10.5px; color: var(--text-faint); }
.row-meta .time { font-family: var(--mono); }

.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px; letter-spacing: 0.05em; text-transform: uppercase;
  font-weight: 500;
  border: 1px solid currentColor;
}
/* Colour alone had boarding and departed the same amber and cancelled and
   delayed the same red, so scanning the list grouped the states wrongly. Fill
   is the second channel: the four states worth looking up for are solid, the
   four that are simply where a flight has got to are outlined. */
.pill.s-scheduled { color: var(--text-dim); }
.pill.s-departed  { color: var(--amber); }
.pill.s-enroute   { color: var(--accent); }
.pill.s-landed    { color: var(--ok); }
.pill.s-delayed   { color: var(--danger); }
.pill-position { background: transparent; font: inherit; cursor: pointer; }
.pill-position:hover { background: var(--bg-raised); }
.pill-position:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pill.s-boarding,
.pill.s-landing,
.pill.s-cancelled { border-color: transparent; color: var(--brand-ink); }
.pill.s-boarding  { background: var(--amber); }
.pill.s-landing   { background: var(--accent); }
.pill.s-cancelled { background: var(--danger); }

.empty { padding: 34px 20px; text-align: center; color: var(--text-faint); font-size: 12px; line-height: 1.7; }
/* The filters an empty list is blaming. Centred as a block but ranged left
   inside it, so three of them read as a list rather than as a paragraph that
   happens to have line breaks in it. */
.empty-filters {
  display: inline-flex; flex-direction: column; gap: 3px;
  margin: 9px auto 10px; padding: 0;
  list-style: none; text-align: left;
}
.empty-filters li { color: var(--text-dim); }
.empty-filters li::before { content: '· '; color: var(--text-faint); }

/* ------------------------------------------------------- live vs archive */

/* Two bands on a carrier's profile that must never be mistaken for each other:
   what is in the air this minute, and what has been seen over a period. They
   get different headings, different colours and a badge each. */
.band { margin-top: 20px; }
.band + .band { padding-top: 18px; border-top: 1px solid var(--line); }
.band-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-bottom: 11px; }
.band-head h5 {
  margin: 0; font-size: 11px; font-family: var(--mono);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-faint); font-weight: 600;
}
.band.now .kv b { color: var(--amber); }
.band.kept .kv b { color: var(--accent); }

.badge-archive {
  background: var(--sel-bg); color: var(--accent);
  border: 1px solid var(--accent-dim);
  font-family: inherit; cursor: pointer;
}
.badge-archive:hover { background: var(--bg-hover); }
.badge-archive:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Registrations are a set, not a ranking, so they are listed rather than
   charted. */
.tail-list { display: flex; flex-wrap: wrap; gap: 5px; margin: 8px 0 0; }
.tail {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.02em;
  padding: 2px 7px; border-radius: 5px;
  background: var(--bg); border: 1px solid var(--line); color: var(--text-dim);
}

/* ---------------------------------------------------------------- archive */

/* A wide table on a phone is the one thing that must never widen the page, so
   it scrolls inside its own box rather than pushing the layout sideways. */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.arc-tabs { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 14px; }
.arc-tab {
  font: inherit; font-size: 12.5px; padding: 6px 13px; border-radius: 999px;
  border: 1px solid var(--line); background: none; color: var(--text-faint);
  cursor: pointer;
}
.arc-tab:hover { color: var(--text); border-color: var(--accent-dim); }
.arc-tab.is-on {
  background: var(--accent); border-color: var(--accent);
  color: var(--bg); font-weight: 600;
}
.arc-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The archive's numbers are counts over a period and the live ones are counts
   at an instant. They are never the same colour. */
#archive-body .kv b { color: var(--accent); }

/* ------------------------------------------------------------------ marks */

/* Generated carrier tiles. The hue and the ink come from brand.js, which picks
   the ink by measuring contrast rather than assuming white works on every
   colour it might land on. */
.mark {
  display: inline-grid; place-items: center;
  flex: none;
  border-radius: 5px;
  background: hsl(var(--mark-h, 174) 55% var(--mark-l, 42%));
  color: var(--mark-ink, #fff);
  font-family: var(--mono);
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1;
  user-select: none;
}

/* Square, because what goes in them is square.
   These were 28x20, 30x22 and 46x34 - the proportions of a wordmark, which is
   what the tile used to hold. brand.js then measured the wordmark at this size
   and abandoned it ("the icon is a true 200x200 square and draws 22x22"), but
   the tiles kept the old shape. So every logo since has been a square drawn
   inside a rectangle: object-fit: contain letterboxed it, and the 4px down
   each side showed the white underneath. On a dark list that read as a white
   box around the airline's logo, which is what it looked like because it was.
   Measured across ten carriers, every icon is a fully opaque square whose
   outermost pixel is the airline's own colour, so a square tile shows the
   logo's edge and nothing else. Widths come off, heights stay, so no row
   changes height. */
.mark-sm { width: 20px; height: 20px; font-size: 10px; }
.mark-md { width: 22px; height: 22px; font-size: 11px; border-radius: 6px; }
.mark-lg { width: 34px; height: 34px; font-size: 15px; border-radius: 8px; }

/* A licensed logo replaces the tile entirely, so it gets no background to
   show through a transparent SVG. */
.mark-img { background: none; object-fit: contain; }
.mark-sm.mark-img { width: 22px; height: 22px; }
.mark-md.mark-img { width: 26px; height: 26px; }
.mark-lg.mark-img { width: 40px; height: 40px; }

.board-title-brand { display: grid; grid-template-columns: auto 1fr; gap: 0 14px; align-items: center; }
.board-title-brand h2 { grid-column: 2; }
.board-title-brand p { grid-column: 2; }
.board-title-brand .mark { grid-row: 1 / 3; }

.bar-row.has-mark { grid-template-columns: 28px 76px minmax(0, 1fr) 42px; }

/* --------------------------------------------------------------- airports */

.ap-row {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 10px 14px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--line-soft);
  text-align: left;
  cursor: pointer;
}
.ap-row:hover { background: var(--bg-hover); }
/* The code is the airport's name as far as anybody flying is concerned, so it
   is the thing that carries the colour. Which part of the world it is in is
   the one fact about an airport that a list of four thousand of them can show
   at a glance and never has - and it costs nothing, because the region is
   already in the table. Falls back to the accent for the handful with no
   region recorded, which is the colour it has always been. */
.ap-code { font-family: var(--mono); font-size: 13px; color: var(--accent); width: 38px; }
.ap-row[data-region="Asia"] .ap-code { color: var(--region-asia); }
.ap-row[data-region="Europe"] .ap-code { color: var(--region-europe); }
.ap-row[data-region="North America"] .ap-code { color: var(--region-north-america); }
.ap-row[data-region="South America"] .ap-code { color: var(--region-south-america); }
.ap-row[data-region="Africa"] .ap-code { color: var(--region-africa); }
.ap-row[data-region="Middle East"] .ap-code { color: var(--region-middle-east); }
.ap-row[data-region="Oceania"] .ap-code { color: var(--region-oceania); }
/* One line, like the carrier row: "Dubai International - Dubai, United Arab
   Emirates". The owner's call. A long name is cut with an ellipsis; the
   whole of it is on the row's title and on the airport's own page. */
.ap-name { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 5px; white-space: nowrap; overflow: hidden; }
.ap-name strong { font-size: 12.5px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; flex: none; max-width: 60%; }
.ap-name span { font-size: 10.5px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; }
.ap-name span::before { content: "– "; }
.ap-load { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }

/* Airport actions stay underneath their own row. The pale surface and narrow
   edge match the other lists without turning the entire answer teal. */
.ap-entry { border-bottom: 1px solid var(--line-soft); }
.ap-entry.is-open { background: var(--bg-raised); box-shadow: inset 3px 0 0 var(--accent); }
.ap-entry .ap-row { border-bottom: 0; min-height: 60px; }
.ap-entry .ap-code, .ap-expand-glyph { flex: none; }
.ap-entry .ap-name { flex-direction: column; align-items: stretch; gap: 3px; }
.ap-entry .ap-name strong { max-width: 100%; }
.ap-entry .ap-name span::before { content: none; }
.ap-row[aria-expanded="true"] .ap-expand-glyph {
  background: var(--accent); border-color: var(--accent); color: var(--brand-ink);
}
.ap-row:focus-visible, .ap-action:focus-visible {
  outline: 2px solid var(--focus); outline-offset: -3px;
}
.ap-inline { padding: 0 14px 10px 50px; }
.ap-inline[hidden] { display: none; }
.ap-action {
  display: grid; grid-template-columns: 28px minmax(0, 1fr) 14px; gap: 10px;
  align-items: center; width: 100%; min-height: 58px; padding: 10px 0;
  border: 0; border-top: 1px solid var(--line-soft); background: none;
  text-align: left; font: inherit; color: var(--text); cursor: pointer;
}
.ap-action:hover { background: var(--bg-hover); }
.ap-action strong { display: block; font-size: 13px; font-weight: 500; }
.ap-action small { display: block; margin-top: 3px; font-size: 11px; color: var(--text-dim); }
.ap-action-icon { text-align: center; font-size: 20px; color: var(--accent); }
.ap-action-arrow { color: var(--accent); }

/* Airport schedules share the Flights scroller. Keep the airport and direction
   above it so the visitor can change or remove that scope without scrolling. */
.airport-schedule { flex: none; padding: 4px 14px 10px; border-bottom: 1px solid var(--line-soft); }
.airport-schedule[hidden] { display: none; }
.schedule-filter {
  display: inline-flex; align-items: center; gap: 10px; max-width: 100%;
  padding: 7px 10px; border: 1px solid var(--accent); border-radius: 6px;
  background: var(--bg-raised); color: var(--accent); font: inherit; font-size: 12px; cursor: pointer;
}
.schedule-directions { display: flex; gap: 7px; margin-top: 9px; }
.schedule-directions button {
  flex: 1; min-height: 38px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--bg-raised); color: var(--text-dim); font: inherit; cursor: pointer;
}
.schedule-directions button[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: var(--bg-hover); }
.schedule-note { padding: 9px 14px; margin: 0; font-size: 11px; color: var(--text-dim); }
.schedule-entry { border-bottom: 1px solid var(--line-soft); }
.schedule-entry.is-open { background: var(--bg-raised); box-shadow: inset 3px 0 0 var(--accent); }
.schedule-row {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 12px 14px;
  border: 0; text-align: left; background: none; color: var(--text); font: inherit; cursor: pointer;
}
.schedule-row:hover { background: var(--bg-hover); }
.schedule-row .flight-inline-disclosure { flex: none; }
.schedule-entry.is-open .flight-inline-disclosure { background: var(--accent); color: var(--brand-ink); }
.schedule-main { flex: 1; min-width: 0; display: grid; gap: 5px; font-size: 12px; }
.schedule-main > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.schedule-main strong { color: var(--accent); font-family: var(--mono); }
.schedule-main small { color: var(--text-dim); font-size: 11px; }
.schedule-route { display: flex; align-items: center; gap: 5px; font-size: 11px; }
.schedule-route > span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.schedule-route i { font-style: normal; color: var(--accent); }
.schedule-route b { font-family: var(--mono); }
.schedule-time { flex: none; max-width: 78px; text-align: right; display: grid; gap: 4px; }
.schedule-time strong { font: 600 13px var(--mono); }
.schedule-time small { font-size: 10px; color: var(--text-dim); }
.schedule-detail { padding: 0 14px 14px 50px; }
.schedule-detail[hidden] { display: none; }
.schedule-detail p { margin: 0 0 10px; color: var(--text-dim); font-size: 11px; }
.schedule-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 11px 14px; }
.schedule-facts span { display: block; color: var(--text-dim); font-size: 10px; margin-bottom: 3px; }
.schedule-facts strong { font-size: 12px; font-weight: 500; }
.schedule-row:focus-visible, .schedule-filter:focus-visible, .schedule-directions button:focus-visible {
  outline: 2px solid var(--focus); outline-offset: -2px;
}

/* ------------------------------------------------------------------- stats */

/* The archive keeps its own scrolling area below the section heading. */
.stats-scroll { overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 18px; }
.stat-block h3 { margin: 0 0 10px; font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-faint); font-weight: 600; }
.kv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.kv { background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius); padding: 10px; }
.kv b { display: block; font-family: var(--mono); font-size: 17px; font-weight: 500; }
.kv span { display: block; font-size: 9.5px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint); transition: color 0.15s; }
/* The cards in the Network tab are buttons into the same breakdowns the topbar
   chips open, and the only cards that are not are the ones inside a breakdown
   already. Same rest state either way; only the hover gives the door away. */
/* Anchors join the buttons here rather than getting a rule of their own. Two
   of a carrier's archive figures answer with a written page, so they are real
   links - right-clickable, openable in a tab - and an <a> that looked like a
   link would be the only underlined blue text in a grid of six identical
   boxes. Same object, same look, whichever element it is. */
button.kv, a.kv {
  width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
  text-decoration: none; display: block; box-sizing: border-box;
  transition: border-color 0.15s, background 0.15s;
}
button.kv:hover, a.kv:hover { border-color: var(--accent-dim); background: var(--bg-hover); }
button.kv:hover span, a.kv:hover span { color: var(--accent); }

.bar-row { display: grid; grid-template-columns: 82px 1fr 42px; align-items: center; gap: 9px; margin-bottom: 7px; font-size: 11px; }
.bar-row .bar-label { color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-row .bar-track { height: 7px; background: var(--line-soft); border-radius: 4px; overflow: hidden; }
.bar-row .bar-track i { display: block; height: 100%; background: linear-gradient(90deg, var(--accent-dim), var(--accent)); }
.bar-row .bar-value { font-family: var(--mono); text-align: right; color: var(--text-dim); }

/* The filters with no control of their own announce themselves here. */
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 14px; border-bottom: 1px solid var(--line-soft); }
.chip-row[hidden] { display: none; }
.chip-tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 9px;
  background: var(--sel-bg);
  border: 1px solid var(--accent-dim); border-radius: 999px;
  color: var(--accent); cursor: pointer;
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
}
.chip-tag:hover { border-color: var(--danger); color: var(--danger); }
/* The carrier choice belongs to Aircraft after navigation, not to the old
   airline row. Name it beside a removable chip so the narrowed counts cannot
   be mistaken for totals across every airline. */
.aircraft-filter { align-items: center; }
.aircraft-filter-label { color: var(--text-faint); font-size: 10px; }
.aircraft-filter .chip-tag { min-height: 34px; font-size: 11px; letter-spacing: 0; text-transform: none; }
/* A route is a path through choices, not a new search for every carrier.
   Wrap the steps in the narrow sidebar while keeping each choice editable. */
.route-path { display: flex; align-items: end; gap: 7px; flex-wrap: wrap;
  padding: 10px 14px 3px; border-bottom: 1px solid var(--line-soft); }
.route-path-root { padding-bottom: 8px; color: var(--text-dim); font-size: 11px; font-weight: 600; }
.route-path-arrow { padding-bottom: 8px; color: var(--text-faint); font-size: 15px; }
.route-path-field { display: flex; flex: 1 1 120px; flex-direction: column; gap: 3px;
  min-width: 0; color: var(--text-faint); font-size: 10px; }
.route-path-field .ms-button, .route-path-field select { min-height: 35px; width: 100%;
  padding: 7px 8px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--bg-raised); color: var(--text); font: inherit; font-size: 11px; }
.route-path-field select { cursor: pointer; }
.route-path-field .ms-pop { width: max(100%, 230px); }
.route-path-clear { min-height: 35px; padding: 6px 8px; border: 0; background: transparent;
  color: var(--accent); font: inherit; font-size: 11px; cursor: pointer; }
.route-path-clear:hover { text-decoration: underline; }
.route-path-note { margin: 0; padding: 5px 14px 8px; color: var(--text-faint);
  font-size: 10px; line-height: 1.4; }
@media (max-width: 560px) {
  .route-path { gap: 5px; }
  .route-path-arrow { display: none; }
  .route-path-field { flex-basis: 100px; }
  .route-path-field:first-of-type { flex-basis: 100%; }
  .route-path-field .ms-button, .route-path-field select, .route-path-clear { min-height: 44px; }
}
@media (max-width: 1000px) {
  .aircraft-filter .chip-tag { min-height: 44px; }
}

/* A broad aircraft filter paints two kinds of dot over the same globe. Keep
   their key beside the removable choice so the map remains readable on phones,
   where the floating map caption is deliberately hidden. */
.filter-map-key {
  display: flex; flex-wrap: wrap; gap: 6px 16px;
  padding: 6px 14px 8px; border-bottom: 1px solid var(--line-soft);
  color: var(--text-dim); font-size: 10px;
}
.filter-map-key[hidden] { display: none; }
.filter-map-key span { display: inline-flex; align-items: center; gap: 6px; }
.filter-map-key i { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.filter-map-key-flight { background: var(--map-match); }
.filter-map-key-airport { background: var(--map-airport); }

.row-star { color: var(--saved); font-size: 10px; line-height: 1; }

.bar-link {
  width: 100%;
  background: none; border: none;
  text-align: left; cursor: pointer;
  padding: 2px 4px; margin-left: -4px;
  border-radius: 5px;
}
.bar-link:hover { background: var(--bg-hover); }

.btn-watch.is-on { color: var(--saved); border-color: var(--saved); }
.link-inline {
  padding: 0; background: none; border: none;
  color: var(--accent); cursor: pointer; font: inherit;
  text-decoration: underline; text-underline-offset: 2px;
}

/* ----------------------------------------------------------------- welcome */

/* Sits over the map, not in front of it: a first-time visitor came to see the
   aircraft, and a modal standing between them and the map is a worse
   introduction than no introduction. */
.welcome {
  position: absolute; left: 14px; bottom: 52px; z-index: 8;
  width: min(320px, calc(100% - 28px));
  padding: 16px 16px 13px;
  background: var(--bg-raised);
  border: 1px solid var(--accent-dim);
  border-radius: 10px;
  box-shadow: 0 18px 46px var(--shadow);
}
.welcome[hidden] { display: none; }
.welcome h2 { margin: 0 0 6px; padding-right: 26px; font-size: 15px; font-weight: 600; }
.welcome-lead { margin: 0 0 12px; font-size: 11.5px; line-height: 1.55; color: var(--text-dim); }
.welcome-close {
  position: absolute; top: 10px; right: 11px;
  width: 22px; height: 22px;
  background: none; border: 1px solid var(--line); border-radius: 5px;
  color: var(--text-faint); cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.welcome-close:hover { color: var(--danger); border-color: var(--danger); }

.welcome-try { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.welcome-try button {
  display: block; width: 100%; text-align: left;
  padding: 8px 10px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 7px;
  cursor: pointer;
}
.welcome-try button:hover { border-color: var(--accent-dim); background: var(--bg-hover); }
.welcome-try b { display: block; font-size: 12px; font-weight: 600; color: var(--accent); }
.welcome-try span { display: block; margin-top: 2px; font-size: 10.5px; line-height: 1.45; color: var(--text-faint); }

/* Tried, and visibly so - the list is a short errand, not a wall of advice. */
.welcome-try li.is-done button { border-color: var(--ok); opacity: 0.55; }
.welcome-try li.is-done b::after { content: " ✓"; color: var(--ok); }

.welcome-more { margin: 12px 0 0; font-size: 10px; color: var(--text-faint); }
.welcome-more b {
  padding: 1px 5px; font-family: var(--mono); font-weight: 500;
  background: var(--bg); border: 1px solid var(--line); border-radius: 4px;
  color: var(--text-dim);
}

/* Pointing at the control the card just used, so it is found again later. */
.timebar.is-flagged { border-color: var(--accent); box-shadow: 0 0 0 3px var(--sel-bg); }

.help-lead { margin: 0 0 16px; font-size: 12.5px; line-height: 1.6; color: var(--text-dim); }
.help-tour { margin: 0 0 18px; padding-left: 18px; display: grid; gap: 7px; }
.help-tour li { font-size: 12px; line-height: 1.55; color: var(--text-dim); }
.help-tour b { color: var(--text); font-weight: 600; }
.help-sub { margin: 0 0 10px; font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); font-weight: 600; }

/* help-sub was written to sit directly under a lead paragraph. This one
   follows a definition list, so it has to make its own room. */
.help-sub-after { margin-top: 22px; }

/* Sits under the shortcuts, so it needs the top margin the heading above it
   does not carry. Unbulleted: three credits read as a list already, and the
   markers would make them look like more of the tour. */
.help-sources { margin: 18px 0 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.help-sources li { font-size: 12px; line-height: 1.55; color: var(--text-dim); }
.help-sources a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.help-sources a:hover, .help-sources a:focus-visible { color: var(--accent); }

@media (max-width: 1000px) {
  .welcome { bottom: 104px; }
}

/* -------------------------------------------------------------------- jump */

/* Near the top rather than centred: the list grows downwards as you type, and
   a centred panel would jump about under the cursor while it did. */
.jump-overlay { place-items: start center; padding-top: 11vh; }
.jump-inner { width: min(620px, 100%); padding: 16px 16px 12px; gap: 12px; }

.jump-input {
  width: 100%;
  padding: 12px 44px 12px 14px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 15px;
}
.jump-input::placeholder { color: var(--text-faint); }
.jump-input:focus { border-color: var(--accent-dim); }

.jump-list { overflow-y: auto; max-height: min(52vh, 460px); margin-top: 12px; }
.jump-opt {
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr);
  gap: 2px 10px;
  align-items: baseline;
  padding: 7px 9px;
  border-radius: 6px;
  cursor: pointer;
}
.jump-opt.is-active { background: var(--sel-bg); box-shadow: inset 2px 0 0 var(--accent); }
/* The three-part row - badge column, title, subtitle - is the TIME-ZONE
   picker's shape now, not the search dropdown's. #zones-list still writes all
   three spans and needs every one of them: the clock time in the badge slot,
   the zone's name, and the zone's own id underneath. The search panel overrides
   this to a single plain line further down, scoped to .cmd-drop. Do not delete
   these rules as leftovers of the search redesign - the clock picker is the
   reader. */
.jump-kind {
  grid-row: 1 / 3;
  font-size: 8.5px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent-dim); border-radius: 4px;
  padding: 2px 0; text-align: center;
}
.jump-title { font-size: 13px; }
.jump-sub { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }
.jump-empty { padding: 18px 6px; color: var(--text-faint); font-size: 12.5px; }

/* The one line that says what the map is now showing. Quiet, because it is a
   note about something that happened elsewhere rather than a thing to press,
   and it sits above the results so it reads before them. */
.jump-note {
  margin: 0;
  padding: 8px 10px 6px;
  color: var(--text-dim);
  font-size: 12.5px;
}
.jump-note:empty { display: none; }
.jump-note p { margin: 0; }
/* A named aeroplane's row carries its carrier's mark in front of the words. */
.cmd-drop .jump-opt .mark { vertical-align: middle; margin-right: 8px; }

/* A search result is one plain line, so it does not want the two-column grid
   above. The owner's word for the old panel was "technical", and the uppercase
   LIVE/FLIGHT/FILTER badge and the grey monospace second line were most of
   that: what is left is the sentence a person would read out.

   Scoped to .cmd-drop on purpose. These same class names dress the time-zone
   picker, which still needs the grid - changing .jump-opt itself would collapse
   the clock times in it.

   Truncating rather than wrapping is not only tidier. It keeps every row the
   same height, which is what the arrow keys and scrollIntoView assume as they
   step down the list; a row that wrapped to two lines would make the list jump
   under the selection. */
.cmd-drop .jump-opt {
  display: block;
  padding: 9px 10px;
  font-size: 13.5px;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The rows that do something rather than open something sit under a hairline
   instead of under a heading - the grouping without the word for it. Only the
   first of them draws the line, or two tails in a row would draw two. */
.cmd-drop .jump-opt.is-more { margin-top: 4px; border-top: 1px solid var(--line-soft); color: var(--text-dim); }
.cmd-drop .jump-opt.is-more + .jump-opt.is-more { margin-top: 0; border-top: 0; }

.jump-hint {
  display: flex; gap: 16px; flex-wrap: wrap;
  margin: 10px 0 0; padding-top: 10px;
  border-top: 1px solid var(--line-soft);
  font-size: 10px; color: var(--text-faint);
}
.jump-hint b {
  display: inline-block; min-width: 16px; text-align: center;
  padding: 1px 5px; margin-right: 3px;
  font-family: var(--mono); font-weight: 500;
  background: var(--bg-raised); border: 1px solid var(--line); border-radius: 4px;
  color: var(--text-dim);
}

.records { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.record {
  display: block; text-align: left; width: 100%;
  padding: 9px 10px;
  background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: var(--radius);
  cursor: pointer;
}
.record:hover { border-color: var(--accent-dim); background: var(--bg-hover); }
.rec-label { display: block; font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint); }
.rec-value { display: block; font-family: var(--mono); font-size: 14px; font-weight: 500; margin: 3px 0 2px; }
.rec-sub { display: block; font-family: var(--mono); font-size: 9.5px; color: var(--text-faint); }

/* ---------------------------------------------------------------- metrics */

/* A breakdown is a board, so it reuses the board's blocks, bars and record
   cards outright. All this adds is the rhythm between them and a headline
   that repeats the number the visitor clicked, so they can see they arrived
   where they meant to. */
.metric-body { display: flex; flex-direction: column; gap: 18px; }
.metric-head { margin-bottom: -4px; }
.metric-headline { margin: 0; font-size: 12px; color: var(--text-faint); line-height: 1.6; }
.metric-headline b {
  font-family: var(--mono); font-size: 22px; font-weight: 500; color: var(--accent);
  margin-right: 7px; vertical-align: -1px;
}
.metric-body .kv-grid { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.metric-body .bar-row { grid-template-columns: 132px minmax(0, 1fr) 48px; }
.metric-body .bar-row.has-mark { grid-template-columns: 28px 118px minmax(0, 1fr) 48px; }
/* The flights behind one band, listed inside the breakdown that counted them.
   The rows are the sidebar's own and arrive with their separators already, so
   all this adds is a frame to hold them and room for the way back. */
.band-view .band-back { display: inline-block; margin-bottom: 9px; }
.band-more { margin: -10px 0 0; font-size: 11px; color: var(--text-faint); }
.band-rows {
  border: 1px solid var(--line-soft);
  border-radius: 8px;
  overflow: hidden;
}
/* The frame draws the last line, so the row underneath must not draw it too. */
.band-rows .row:last-child { border-bottom: 0; }

.metric-note {
  margin: 0; padding-top: 4px;
  border-top: 1px solid var(--line-soft);
  font-size: 11px; color: var(--text-faint); line-height: 1.7;
}
@media (max-width: 560px) {
  .metric-body .bar-row { grid-template-columns: 96px minmax(0, 1fr) 44px; }
  .metric-body .bar-row.has-mark { grid-template-columns: 24px 84px minmax(0, 1fr) 44px; }
}

.timebar {
  position: absolute; bottom: 12px; right: 14px; z-index: 6;
  display: flex; align-items: center; gap: 10px;
  padding: 7px 12px;
  background: var(--tool-bg);
  border: 1px solid var(--line);
  border-radius: 7px;
}
.tb-live {
  padding: 4px 10px;
  background: none;
  border: 1px solid var(--line); border-radius: 5px;
  color: var(--text-faint); cursor: pointer;
  font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase;
}
.tb-live.is-on { color: var(--ok); border-color: var(--ok); }
.tb-range, #tb-range { width: 240px; accent-color: var(--accent); cursor: pointer; }
.tb-out {
  min-width: 74px;
  font-family: var(--mono); font-size: 11px; color: var(--text-dim);
  text-align: right;
}
/* A moved clock has to be obvious, or the numbers look like a bug. */
.clock.is-scrubbed .clock-main { color: var(--amber); }
.clock.is-scrubbed .clock-sub { color: var(--amber); }

/* ------------------------------------------------------------------ units */

.board-inner.units-inner { width: min(640px, 100%); }
.units-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.units-set:last-child { grid-column: 1 / -1; }
.units-set:last-child .units-opt { display: inline-flex; margin-right: 18px; }
.units-set {
  margin: 0; padding: 10px 12px 11px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-raised);
}
.units-set legend {
  padding: 0 5px;
  font-size: 9px; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--accent);
}
.units-opt {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 2px;
  font-size: 12px; color: var(--text-dim);
  cursor: pointer;
}
.units-opt input { accent-color: var(--accent); margin: 0; }
.units-opt:hover { color: var(--text); }
.units-opt input:checked + span { color: var(--accent); }

.help-inner { width: min(460px, 100%); }
.help-body { overflow-y: auto; min-height: 0; overscroll-behavior: contain; }
.shortcuts { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; margin: 0; align-items: baseline; }
.shortcuts dt {
  font-family: var(--mono); font-size: 11px;
  padding: 2px 8px; justify-self: start;
  background: var(--bg-raised); border: 1px solid var(--line); border-radius: 5px;
  color: var(--accent);
}
.shortcuts dd { margin: 0; font-size: 12px; color: var(--text-dim); }

.map-readout {
  position: absolute; bottom: 12px; left: 14px; z-index: 5;
  display: flex; gap: 9px; align-items: center;
  padding: 6px 12px;
  background: var(--tool-bg);
  border: 1px solid var(--line);
  border-radius: 7px;
  font-family: var(--mono); font-size: 10.5px; color: var(--text-dim);
}
.map-readout .sep { color: var(--line); }

.tooltip {
  position: absolute; z-index: 20; pointer-events: none;
  padding: 8px 11px;
  background: var(--tool-bg);
  border: 1px solid var(--accent-dim);
  border-radius: 7px;
  font-size: 11.5px; line-height: 1.55;
  box-shadow: 0 10px 26px var(--shadow);
  max-width: 240px;
}
.tooltip b { font-family: var(--mono); color: var(--accent); }
.tooltip .t-sub { color: var(--text-faint); font-size: 10.5px; }

/* ------------------------------------------------------------------- board */

.board-overlay {
  position: absolute; inset: 0; z-index: 25;
  background: var(--overlay);
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  padding: 26px;
}
/* The class sets display, so it beats the browser's own [hidden] rule and the
   panel would sit over the map for ever - visible, empty and swallowing every
   click meant for the canvas. Spell the hidden state out, as .detail does. */
.board-overlay[hidden] { display: none; }
/* The panel itself must NOT scroll. It is the positioning context for the
   close button, so if it scrolled the button would ride up out of the panel
   and land behind the header - clicks meant for it hit the toolbar instead.
   The content scrolls inside it instead. */
.board-inner {
  position: relative;
  width: min(920px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  /* Raised surface, not the panel colour: with the blur gone this is the only
     thing lifting the modal off a dark map behind it. */
  background: var(--bg-raised);
  border: 1px solid var(--accent-dim);
  border-radius: 12px;
  padding: 22px 24px 26px;
  box-shadow: 0 24px 70px var(--shadow), 0 2px 10px var(--shadow);
}

#board-content {
  overflow-y: auto;
  min-height: 0;          /* let the flex child actually shrink and scroll */
  overscroll-behavior: contain;
  /* A gutter for the scrollbar. Without it the column of counts on the right
     of every breakdown ends exactly where the bar begins, and the last stat
     card is cropped by it - the numbers are the point of those rows, and they
     were the one thing touching it. */
  padding-right: 16px;
}
/* Every dismiss cross on the site is this one drawn glyph.
   The &times; character it replaces sits on the maths axis - above the middle
   of a line - so a typed cross rides high in its button however carefully the
   box is centred, and it rode high by a different amount in each of the six
   places we used one. Two strokes in a square viewBox are centred because the
   geometry says so, at any size and in any font. */
.x-glyph { display: block; flex: none; }
.board-close, .detail-close, .welcome-close, .zone-drop {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
}
.board-close, .detail-close {
  position: absolute; top: 12px; right: 14px;
  z-index: 3;
  width: 28px; height: 28px;
  background: none; border: 1px solid var(--line); border-radius: 6px;
  color: var(--text-dim); cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.board-close:hover, .detail-close:hover { color: var(--danger); border-color: var(--danger); }
/* The board's cross sits over the top of the scrolling region, so the
   scrollbar runs underneath it. Transparent, the bar showed through the glyph
   and the two read as one broken control; the panel's own colour puts the
   button in front of it. The detail panel's cross does not need this - nothing
   scrolls behind it. */
.board-close { background: var(--bg-raised); }

.board-title h2 { margin: 0 0 2px; padding-right: 44px; font-size: 19px; font-weight: 600; }
.board-title p { margin: 0 0 18px; font-size: 12px; color: var(--text-faint); }
.board-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
@media (max-width: 900px) { .board-grid { grid-template-columns: 1fr; } }

/* The airline answer now fits beside the map. Its large photograph and
   archive grid made a live question start with history and require scrolling;
   the deeper record is still available after the two current counts. */
/* The same board also hosts modal airport and metric answers. Only a carrier
   moves into the deck: the clear overlay leaves the map and flight list usable,
   while the sheet lines up with the existing right-hand detail card. */
#board[data-kind="airline"] {
  position: absolute; inset: 0; display: block; padding: 0;
  background: transparent; pointer-events: none;
}
#board[data-kind="airline"][hidden] { display: none; }
#board[data-kind="airline"] .board-inner {
  position: absolute; top: 20px; right: var(--gap);
  width: var(--detail-w); max-height: calc(100% - 100px);
  padding: 16px; pointer-events: auto;
  background: var(--bg-solid); border-color: var(--line);
  border-radius: 15px; box-shadow: var(--shadow);
}
.deck:has(> #board[data-kind="airline"]:not([hidden])) > .detail {
  visibility: hidden;
}
@media (max-width: 1000px) {
  .layout:has(#board[data-kind="airline"]:not([hidden])) .deck { z-index: auto; }
  /* The phone's list collapses to a lower sheet rather than disappearing.
     Hide it while the carrier sheet is open so two drawers do not stack. */
  .layout:has(#board[data-kind="airline"]:not([hidden])) .sidebar { visibility: hidden; }
  #board[data-kind="airline"] .board-inner {
    position: fixed; top: auto; left: 0; right: 0;
    width: auto; max-height: min(74dvh, 620px);
    bottom: calc(62px + var(--footer-h));
    border-radius: 19px 19px 0 0;
  }
}
.board-inner:has(.airline-snapshot) { width: min(470px, 100%); padding: 14px; }
#board-content:has(.airline-snapshot) { padding-right: 0; }
.airline-snapshot { font-size: 12px; }
.airline-snapshot-head { display: flex; align-items: center; gap: 10px; padding-right: 32px; margin-bottom: 14px; }
.airline-snapshot-head h2 { margin: 0 0 3px; font-size: 16px; font-weight: 600; line-height: 1.2; }
.airline-snapshot-head h2 span { color: var(--accent); }
.airline-snapshot-head p { margin: 0; color: var(--text-faint); font-size: 11px; }
.airline-snapshot-link { border: 0; background: none; color: var(--accent); padding: 0; font: inherit; text-align: right; cursor: pointer; }
.airline-snapshot-link:hover { text-decoration: underline; }
.airline-snapshot-link small { margin-left: 4px; color: var(--text-faint); font-size: 10px; }
.airline-snapshot-live { padding: 13px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg-panel); }
.airline-snapshot-section-head { display: flex; justify-content: space-between; align-items: center; }
.airline-snapshot-section-head h3, .airline-snapshot-highlights h3 { margin: 0; color: var(--text-faint); font-size: 10px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; }
.airline-snapshot-counts { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.airline-snapshot-counts button { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; border: 0; background: none; color: var(--text); padding: 0; text-align: left; cursor: pointer; }
.airline-snapshot-counts button + button { border-left: 1px solid var(--line); padding-left: 12px; }
.airline-snapshot-counts button:hover strong { color: var(--accent); }
.airline-snapshot-counts strong { font-family: var(--mono); font-size: 23px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
.airline-snapshot-counts span { color: var(--text-faint); font-size: 10px; }
.airline-snapshot-track { height: 3px; margin-top: 13px; border-radius: 3px; background: var(--line); overflow: hidden; }
.airline-snapshot-track span { display: block; height: 100%; background: var(--accent); }
.airline-snapshot-highlights { margin-top: 13px; }
.airline-snapshot-highlights h3 { margin-bottom: 3px; }
.airline-snapshot-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line-soft); }
.airline-snapshot-row > span { color: var(--text-dim); font-size: 11px; }
.airline-snapshot-row strong { font-size: 12px; font-weight: 600; text-align: right; }
.airline-snapshot-row small { color: var(--text-faint); font-size: 10px; }
.airline-snapshot-archive { display: flex; justify-content: space-between; gap: 10px; margin-top: 9px; color: var(--text-faint); font-size: 10px; }
.airline-snapshot-archive a { color: var(--accent); text-decoration: none; }
.airline-snapshot-archive a:hover { text-decoration: underline; }
.airline-snapshot-archive strong { font-family: var(--mono); font-size: 13px; color: var(--text); }
.airline-snapshot-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; margin-top: 14px; }
.airline-snapshot-actions button { min-height: 34px; border-radius: 6px; padding: 6px 8px; font-size: 11px; font-weight: 600; cursor: pointer; }
.airline-snapshot-primary { border: 1px solid var(--accent); background: var(--accent); color: var(--brand-ink); }
.airline-snapshot-primary:hover { background: var(--accent-dim); }
.airline-snapshot-secondary { border: 1px solid var(--line); background: var(--bg-raised); color: var(--text); }
.airline-snapshot-secondary:hover, .airline-snapshot-secondary[aria-expanded="true"] { color: var(--accent); border-color: var(--accent-dim); }
.airline-snapshot-more { border-top: 1px solid var(--line); margin-top: 16px; padding-top: 16px; }
.airline-snapshot-more[hidden] { display: none; }
.airline-snapshot-more .board-tools { margin: 0 0 12px; }
.airline-snapshot-more .board-grid { margin-top: 14px; }
@media (max-width: 480px) {
  #board:has(.airline-snapshot) { padding: 12px; }
  .board-inner:has(.airline-snapshot) { padding: 12px; }
  .airline-snapshot-head { margin-bottom: 10px; }
  .airline-snapshot-live { padding: 10px; }
  .airline-snapshot-highlights { margin-top: 10px; }
  .airline-snapshot-actions { margin-top: 10px; }
}
/* Desktop is deliberately zoomed to 75% below. At the unscaled card width
   the new snapshot looked like a tiny thumbnail, despite having plenty of map
   room. These desktop sizes land near the approved 470px-wide mock in view. */
@media (min-width: 1001px) {
  .board-inner:has(.airline-snapshot) { width: min(650px, 100%); padding: 20px; }
  .airline-snapshot { font-size: 16px; }
  .airline-snapshot-head { gap: 14px; margin-bottom: 18px; }
  .airline-snapshot-head h2 { font-size: 22px; }
  .airline-snapshot-head p { font-size: 14px; }
  .airline-snapshot-live { padding: 18px; }
  .airline-snapshot-section-head h3, .airline-snapshot-highlights h3 { font-size: 13px; }
  .airline-snapshot-counts { margin-top: 18px; gap: 18px; }
  .airline-snapshot-counts button + button { padding-left: 18px; }
  .airline-snapshot-counts strong { font-size: 31px; }
  .airline-snapshot-counts span { font-size: 13px; }
  .airline-snapshot-track { margin-top: 18px; height: 4px; }
  .airline-snapshot-highlights { margin-top: 18px; }
  .airline-snapshot-row { padding: 12px 0; }
  .airline-snapshot-row > span, .airline-snapshot-row strong { font-size: 14px; }
  .airline-snapshot-link small, .airline-snapshot-row small { font-size: 12px; }
  .airline-snapshot-archive { margin-top: 12px; font-size: 13px; }
  .airline-snapshot-archive strong { font-size: 16px; }
  .airline-snapshot-actions { margin-top: 18px; gap: 10px; }
  .airline-snapshot-actions button { min-height: 44px; font-size: 14px; }
}

/* Aircraft and airport answers sit in the narrow map drawer, not the airline
   board. Give them the same snapshot rhythm without inheriting the board's
   enlarged desktop type or making a long name push the close button away. */
#detail .d-quick.subject-snapshot,
#detail .d-quick:has(> .subject-snapshot) { padding: 47px 16px 16px; }
#detail .subject-snapshot { min-width: 0; font-size: 12px; }
#detail .subject-snapshot .airline-snapshot-head {
  min-width: 0; gap: 10px; padding-right: 0; margin-bottom: 13px;
}
#detail .subject-snapshot .airline-snapshot-head > div { min-width: 0; }
#detail .subject-snapshot .airline-snapshot-head h2 {
  margin: 0 0 3px; font-size: 17px; line-height: 1.2; overflow-wrap: anywhere;
}
#detail .subject-snapshot .airline-snapshot-head p {
  font-size: 11px; line-height: 1.3; overflow-wrap: anywhere;
}
#detail .subject-snapshot-hint { margin: 3px 0 0; color: var(--text-faint); font-size: 11px; line-height: 1.3; }
#detail .subject-snapshot-icon {
  display: grid; place-items: center; flex: none; width: 28px; height: 28px;
  border: 1px solid var(--line); border-radius: 7px; background: var(--bg-raised);
  color: var(--accent); font-family: var(--mono); font-size: 13px; font-weight: 650;
  line-height: 1;
}
#detail .subject-snapshot-model {
  padding: 0; border: 0; background: none; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
  text-decoration: underline; text-decoration-color: var(--line);
  text-underline-offset: 3px;
}
#detail .subject-snapshot-model:hover {
  color: var(--accent); text-decoration-color: currentColor;
}
#detail .subject-snapshot-code {
  padding: 0; border: 0; background: none; color: var(--accent);
  font: inherit; cursor: pointer; text-decoration: underline;
  text-underline-offset: 3px;
}
#detail .subject-snapshot-code:hover { text-decoration-color: var(--text); }
#detail .subject-snapshot .airline-snapshot-live { padding: 13px; }
#detail .subject-snapshot .airline-snapshot-section-head h3,
#detail .subject-snapshot .airline-snapshot-highlights h3 { font-size: 10px; }
#detail .subject-snapshot .airline-snapshot-counts { gap: 12px; margin-top: 12px; }
#detail .subject-snapshot .airline-snapshot-counts > * { min-width: 0; }
#detail .subject-snapshot .airline-snapshot-counts button + button { padding-left: 12px; }
#detail .subject-snapshot .airline-snapshot-counts strong { font-size: 23px; }
#detail .subject-snapshot .airline-snapshot-counts span { font-size: 10px; line-height: 1.3; }
#detail .subject-snapshot .airline-snapshot-track { height: 3px; margin-top: 13px; }
#detail .subject-snapshot .airline-snapshot-highlights { margin-top: 13px; }
#detail .subject-snapshot .airline-snapshot-row { gap: 10px; padding: 9px 0; }
#detail .subject-snapshot .airline-snapshot-row > span { min-width: 0; font-size: 11px; }
#detail .subject-snapshot .airline-snapshot-row strong,
#detail .subject-snapshot .airline-snapshot-link { min-width: 0; font-size: 12px; overflow-wrap: anywhere; }
#detail .subject-snapshot .airline-snapshot-row small { font-size: 10px; white-space: nowrap; }
/* An operator ranking is five links, not five extra cards. Thin rules keep it
   scannable beside the airline snapshot's other two-line facts. */
#detail .subject-snapshot-ranking {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  width: 100%; min-width: 0; padding: 9px 0;
  border: 0; border-bottom: 1px solid var(--line-soft); border-radius: 0;
  background: none; color: var(--accent); font: inherit; font-size: 12px;
  text-align: left; cursor: pointer;
}
#detail .subject-snapshot-ranking span { min-width: 0; overflow-wrap: anywhere; }
#detail .subject-snapshot-ranking small {
  flex: none; color: var(--text-faint); font-size: 10px;
  font-variant-numeric: tabular-nums;
}
#detail .subject-snapshot-ranking:hover span { text-decoration: underline; text-underline-offset: 2px; }
#detail .subject-snapshot .airline-snapshot-actions { gap: 7px; margin-top: 14px; }
#detail .subject-snapshot .airline-snapshot-actions > * { min-width: 0; }
#detail .subject-snapshot .airline-snapshot-actions > :only-child { grid-column: 1 / -1; }
#detail .subject-snapshot .airline-snapshot-actions button { min-height: 39px; font-size: 11px; }
/* The airline board already has hover styling. Drawer snapshots also need a
   visible keyboard stop because every count and named fact can open its answer. */
#detail .subject-snapshot button:focus-visible,
#detail .subject-snapshot a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (max-width: 480px) {
  #detail .d-quick.subject-snapshot,
  #detail .d-quick:has(> .subject-snapshot) { padding: 44px 12px 10px; }
  #detail .subject-snapshot .airline-snapshot-head { margin-bottom: 10px; }
  #detail .subject-snapshot .airline-snapshot-live { padding: 10px; }
  #detail .subject-snapshot .airline-snapshot-highlights { margin-top: 10px; }
  #detail .subject-snapshot .airline-snapshot-actions { margin-top: 10px; }
}

.board-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: -8px 0 18px; }
.btn {
  padding: 6px 13px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 11px; letter-spacing: 0.05em;
  transition: color 0.15s, border-color 0.15s;
}
.btn:hover:not(:disabled) { color: var(--accent); border-color: var(--accent-dim); }
.btn:disabled { opacity: 0.55; cursor: default; }
.board-note { font-size: 11px; color: var(--text-faint); }

/* A photograph, and the credit its licence requires.
 *
 * The caption is not styling, it is the terms of use: these come from
 * Wikimedia and almost all are CC BY-SA, where naming the photographer is a
 * condition of showing the picture at all. It is small and quiet, which is
 * allowed - it is not hidden, which is not.
 *
 * object-fit: cover is right here and wrong forty lines up, and the difference
 * is worth stating so nobody harmonises them. .mark-sm/md/lg hold a logo,
 * where cover crops the artwork and clips the top and bottom off a wordmark.
 * This holds a photograph of an aeroplane or a terminal, where the subject is
 * in the middle, the edges are sky and apron, and a fixed frame across a list
 * of them is what stops the panel jumping about as each one loads. Cropping a
 * photograph is normal. Cropping a logo is damage.
 *
 * The frame is declared as an aspect-ratio rather than a height because the
 * files arrive at whatever shape Wikimedia had - the manifest does not record
 * their dimensions - and without a reserved box every picture would shove the
 * text under it downwards on arrival. */
.photo {
  margin: 0 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-raised);
}
.photo img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}
.photo figcaption {
  padding: 4px 8px;
  border-top: 1px solid var(--line-soft);
  font-size: 10px;
  color: var(--text-faint);
}
.photo figcaption a { color: inherit; text-decoration: underline; }
.photo figcaption a:hover { color: var(--accent); }
/* Wider than it is tall, for the top of a carrier board where it is the first
 * thing under the name and a tall picture would push the numbers off screen. */
.photo-wide img { aspect-ratio: 21 / 9; }
.archive-details {
  margin-top: 14px;
  border-top: 1px solid var(--line-soft);
}
.archive-details summary {
  cursor: pointer;
  padding: 12px 0;
  color: var(--accent);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.archive-details[open] summary { border-bottom: 1px solid var(--line-soft); }
.archive-details .board-grid { padding-top: 14px; }
.btn-share { padding: 3px 9px; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; }
/* An anchor wearing .btn needs the anchor defaults undone. */
.btn-wiki {
  display: inline-block;
  padding: 3px 9px;
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  text-decoration: none;
}
.btn-wiki:hover { color: var(--accent); border-color: var(--accent-dim); }

.toast {
  position: absolute; z-index: 50;
  left: 50%; bottom: 26px; transform: translateX(-50%);
  padding: 9px 16px;
  background: var(--tool-bg);
  border: 1px solid var(--accent-dim);
  border-radius: 7px;
  color: var(--text);
  font-size: 12px;
  max-width: min(520px, 86%);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  box-shadow: 0 10px 26px var(--shadow);
}
.toast[hidden] { display: none; }

.badge {
  display: inline-block; padding: 2px 8px; border-radius: 4px;
  font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  border: 1px solid currentColor;
}
/* Readable on purpose: this badge is the disclosure. */
.badge-sim { color: var(--text-dim); }
.badge-sample { color: var(--amber); }
.badge-live { color: var(--ok); }
.badge-feed { background: transparent; font: inherit; cursor: pointer; }
.badge-feed:hover { background: var(--bg-raised); }
.badge-feed:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.feed-note { margin: 8px 0 0; color: var(--text-dim); font-size: 11px; line-height: 1.5; }
.wx-chip { font-size: 11px; color: var(--text-dim); margin-left: auto; }

.board-col h3 { margin: 0 0 8px; font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.board-unavailable { color: var(--amber); }
.airport-board-photo { margin-top: 22px; }
table.board-table { width: 100%; border-collapse: collapse; font-size: 11.5px; }
table.board-table th {
  text-align: left; padding: 5px 6px;
  font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint);
  border-bottom: 1px solid var(--line);
}
table.board-table td { padding: 6px; border-bottom: 1px solid var(--line-soft); }
table.board-table tr { cursor: pointer; }
table.board-table tr:hover td { background: var(--bg-hover); }
table.board-table .mono { font-family: var(--mono); }
/* A clock reading, a flight number and a status are each a single token. Split
   across two lines "KQ 210" reads as two flights and "EN ROUTE" as a stacked
   fragment, which is what the narrow panel was doing to all three. The header
   is left free to wrap: it sits above the data and costs nothing there, while
   holding "Time UTC" on one line would widen the column for every row under it.
   The place is the only thing in the row of unpredictable length, so it is the
   only thing still allowed to give. */
table.board-table td:nth-child(1),
table.board-table td:nth-child(2),
table.board-table td:nth-child(4) { white-space: nowrap; }
.pill { white-space: nowrap; }
.cell-btn { padding: 0; background: none; border: none; font: inherit; color: inherit; cursor: pointer; }
.strike { text-decoration: line-through; color: var(--text-faint); }

/* ----------------------------------------------------------------- partners */

/* Deliberately quieter than the data around it. This is the least important
   thing on the page and should look it.

   The price is the exception, and the only one. It is the single part of this
   block a visitor might actually have wanted, so it is set in the mono face and
   the accent the console gives every other number - which makes it louder than
   its neighbours here while still being quieter than the schedule above it. */
.promo { margin: 0 0 18px; }
.promo-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
}
.promo-title {
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent);
}
.promo-mark {
  font-size: 8px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint);
}
.promo-back {
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent); background: none; border: 0; padding: 0; cursor: pointer;
}
.promo-back:hover { text-decoration: underline; }

/* The slots a feed can put a figure on. */
.promo-hero {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 6px;
}
.promo-tile {
  display: block; width: 100%; text-align: left; font-family: inherit;
  padding: 9px 10px 10px;
  background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: 8px;
  text-decoration: none; color: inherit; cursor: pointer;
}
.promo-tile:hover { border-color: var(--accent-dim); background: var(--bg-hover); }
.promo-tile-top {
  display: flex; align-items: center; gap: 5px;
  font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint);
}
.promo-from {
  display: block; margin-top: 6px;
  font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint);
}
.promo-amt {
  display: block;
  font-family: var(--mono); font-size: 21px; font-weight: 500;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.promo-search {
  display: block; margin-top: 6px;
  font-family: var(--mono); font-size: 13px; color: var(--text-dim);
}
.promo-who {
  display: block; margin-top: 3px;
  font-size: 9.5px; color: var(--text-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The slots with nothing to price. Small on purpose: a search is worth less
   than a price and should not be dressed as its equal. */
.promo-thin { display: flex; gap: 6px; margin-top: 6px; }
.promo-min {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 4px; font-size: 13px;
  border: 1px solid var(--line); border-radius: 8px;
  text-decoration: none; color: inherit;
}
.promo-min:hover { border-color: var(--accent-dim); background: var(--bg-hover); }
.promo-min b { font-size: 10px; font-weight: 500; color: var(--text-dim); }

.promo-note { margin: 8px 0 0; font-size: 9.5px; line-height: 1.5; color: var(--text-faint); }
.promo-note.is-sample { color: var(--amber); }

/* The Travel tab gives booking searches their own home. It borrows the quiet
   partner cards above, but the destination picker must still read as a search
   result rather than as an offer somebody has already chosen. */
.travel-intro { padding: 4px 12px 10px; border-bottom: 1px solid var(--line-soft); }
.travel-intro h2 { margin: 0; font-size: 15px; font-weight: 600; }
.travel-intro p { margin: 4px 0 0; font-size: 10.5px; line-height: 1.45; color: var(--text-faint); }
.travel-matches { display: flex; flex-direction: column; margin-top: 8px; border-top: 1px solid var(--line-soft); }
.travel-match {
  display: grid; grid-template-columns: 42px 1fr; gap: 2px 7px;
  padding: 9px 12px; background: none; border: 0; border-bottom: 1px solid var(--line-soft);
  color: inherit; text-align: left; cursor: pointer;
}
.travel-match:hover { background: var(--bg-hover); }
.travel-match b { grid-row: 1 / 3; align-self: center; font-family: var(--mono); font-size: 13px; font-weight: 500; color: var(--accent); }
.travel-match span { font-size: 12px; font-weight: 500; }
.travel-match small { font-size: 9.5px; color: var(--text-faint); }

/* The stays panel: the list that means the visitor does not have to leave to
   find out what a room costs. */
.promo-crit {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 6px 9px; margin-bottom: 8px;
  background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: 6px;
  font-size: 10.5px; color: var(--text-faint);
}
.promo-crit b { font-family: var(--mono); font-size: 11px; font-weight: 500; color: var(--text); }
.promo-offers { display: flex; flex-direction: column; gap: 5px; }
.promo-offer {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
  padding: 9px 10px;
  background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: 8px;
  text-decoration: none; color: inherit;
}
.promo-offer:hover { border-color: var(--accent-dim); background: var(--bg-hover); }
.promo-offer-name { font-size: 12.5px; font-weight: 600; }
.promo-offer-meta { font-size: 9.5px; color: var(--text-faint); }
.promo-offer-price {
  grid-row: 1 / 3; align-self: center; text-align: right;
  font-family: var(--mono); font-size: 17px; font-weight: 500;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.promo-offer-price i {
  display: block; font-style: normal; font-family: var(--sans);
  font-size: 8px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint);
}
.promo-offer-go {
  grid-column: 1 / -1; margin-top: 6px;
  font-size: 10px; letter-spacing: 0.06em; color: var(--accent);
}
.promo-score {
  display: inline-block; margin-right: 6px; padding: 0 4px;
  font-family: var(--mono); font-size: 9.5px;
  color: var(--ok); border: 1px solid currentColor; border-radius: 3px;
}

/* A paragraph borrowed from Wikipedia, and the credit that is the condition
   of borrowing it. The two are one figure because they are one thing: see
   wikiPanel() in ui.js. */
.wiki-fig { margin: 12px 16px 0; }
.wiki-text {
  margin: 0; padding: 10px 12px;
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 12.5px; line-height: 1.55; color: var(--text-dim);
}
.wiki-credit {
  margin-top: 6px;
  font-size: 10.5px; color: var(--text-faint);
}
.wiki-credit a { color: var(--accent); }
.wiki-wait { margin: 12px 16px 0; font-size: 11.5px; color: var(--text-faint); }

/* Computed weather left with the simulation. The live airport report now has
   its own scoped rows in the drawer; old unscoped grid rules once restyled
   those rows by accident, so keep its selectors beside the drawer below. */
/* ------------------------------------------------------------------ detail */

/* Same rule as the board: the drawer must not scroll, or its close button
   rides away with the content. #detail-body scrolls instead. */
.detail {
  position: relative;
  background: var(--bg-panel);
  border-left: 1px solid var(--line);
  display: flex;
  flex-direction: column;
}

#detail-body {
  overflow-y: auto;
  min-height: 0;
  overscroll-behavior: contain;
}
.detail[hidden] { display: none; }

/* The detail summary shares the highlight cards' route and clock layout.
   A flight opened from the strip above the map should look familiar here. */
.d-quick { padding: 55px 18px 17px; }
.dq-photo { width: 120px; min-width: 0; margin-top: 12px; }
.dq-photo .photo { margin: 0; overflow: hidden; }
.dq-photo .photo img { width: 100%; height: 70px; aspect-ratio: auto; object-fit: contain; }
.dq-photo .photo figcaption { padding: 3px 4px; font-size: 8px; line-height: 1.2; }
.dq-photo > span { display: block; margin-top: 2px; color: var(--text-faint); font-size: 9px; }
.dq-progress { margin-top: 16px; }
.dq-progress-track { height: 4px; overflow: hidden; border-radius: 5px; background: var(--line); }
.dq-progress-track i { display: block; height: 100%; border-radius: inherit; background: var(--accent); }
.dq-progress-meta { display: flex; justify-content: space-between; gap: 8px; margin-top: 7px; color: var(--text-dim); font-size: 11px; }
.dq-progress-meta strong { color: var(--text); font-weight: 600; text-align: right; }
/* Keep distance and duration together. Terminals and gates belong under
   their airport clocks, where they cannot be mistaken for route totals. */
.dq-journey-facts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px 12px;
  padding-top: 6px; border-top: 1px solid var(--line);
}
.dq-journey-facts span { display: flex; align-items: baseline; justify-content: space-between; min-width: 0; gap: 6px; }
.dq-journey-facts small { color: var(--text-dim); font-size: 10px; }
.dq-journey-facts strong { color: var(--text); font-size: 11px; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
/* Live and airport weather now answer the first tap. Thin rules keep the
   readings in the same visual vocabulary as the route card without stacking
   more cards inside an already narrow flight sheet. */
.dq-glance { margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--line); }
.dq-glance h3 { margin: 0 0 8px; color: var(--text-dim); font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.dq-glance h3:has(.dq-freshness) { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.dq-freshness { color: var(--text-faint); font-size: 9px; font-weight: 400; letter-spacing: normal; text-transform: none; }
/* Keep the four position readings together below journey progress. One box
   gives them a clear boundary without the height of four separate cards. */
.dq-live-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px;
  padding: 8px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-raised);
}
.dq-live-grid > div { min-width: 0; }
.dq-live-grid b { display: block; color: var(--text); font-family: var(--mono); font-size: 15px; font-weight: 600; line-height: 1.3; white-space: nowrap; }
.dq-live-grid span { display: block; margin-top: 2px; color: var(--text-dim); font-size: 9px; line-height: 1.25; text-transform: uppercase; letter-spacing: .04em; }
/* Pair each temperature with its airport, using the same left-to-right
   departure and arrival order as the flight card above. */
.dq-weather-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.dq-weather-airport { min-width: 0; }
.dq-weather-airport + .dq-weather-airport { padding-left: 12px; border-left: 1px solid var(--line); }
.dq-weather-temperature { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.dq-weather-temperature strong { color: var(--text); font-family: var(--mono); font-size: 12px; }
.dq-weather-temperature b { color: var(--text); font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.dq-weather-report { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin-top: 3px; min-height: 15px; }
.dq-weather-report .wx-cat { font-size: 8px; }
.dq-weather-report small { color: var(--text-faint); font-size: 9px; font-weight: 400; }
/* The type links to its own right-hand answer. Keep it visually separate from
   the journey so a registration is not mistaken for a flight number. */
.dq-aircraft {
  margin-top: 10px; padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-raised);
}
.dq-aircraft-head { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.dq-aircraft-head h3 {
  flex: none; margin: 0; color: var(--text-dim);
  font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
}
.dq-aircraft-head strong {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text); font-size: 13px; font-weight: 600;
}
.dq-aircraft-link {
  min-width: 0; padding: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  border: 0; background: transparent; color: var(--accent); font: inherit;
  font-size: 13px; font-weight: 600; text-align: left; cursor: pointer;
}
.dq-aircraft-link:hover { text-decoration: underline; }
.dq-aircraft-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dq-aircraft-head > span { flex: none; margin-left: auto; color: var(--text-dim); font-size: 11px; }
.dq-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 15px; }
.dq-actions button { min-height: 39px; padding: 8px 10px; border-radius: 8px; font: inherit; font-size: 11px; font-weight: 600; cursor: pointer; }
.dq-map { flex: 1 0 110px; border: 1px solid var(--accent); background: var(--accent); color: var(--brand-ink); }
.dq-more { flex: 1; border: 1px solid var(--line); background: var(--bg-raised); color: var(--text); }
.dq-actions button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The right sheet changes subject with the selected list row. Reuse its
   spacing and actions, but give types, carriers and airports their own facts
   rather than filling the flight card with unrelated labels. */
.subject-card { padding: 16px; border: 1px solid var(--line); border-radius: 11px; background: var(--bg-raised); }
.subject-top { display: flex; justify-content: space-between; gap: 10px; color: var(--text-dim); font-size: 11px; text-transform: uppercase; letter-spacing: .06em; }
.subject-top strong { color: var(--accent); font-size: 12px; }
.subject-card h2 { margin: 14px 0 0; color: var(--text); font-size: 21px; line-height: 1.15; letter-spacing: -.03em; }
/* These facts are destinations, not decoration. Keep the compact card shape
   but give keyboard and pointer users the same visible link affordance. */
.subject-maker-link { padding: 0; border: 0; background: none; color: var(--accent); font: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.subject-stat-link { display: flex; flex-direction: column; gap: 3px; width: 100%; padding: 0; border: 0; background: none; font: inherit; text-align: left; cursor: pointer; }
.subject-stat-link strong { color: var(--accent); }
.subject-stat-link:hover strong, .subject-stat-link:focus-visible strong { text-decoration: underline; text-underline-offset: 2px; }
.subject-maker-link:focus-visible, .subject-stat-link:focus-visible, .subject-operators button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
/* The carrier's name, country and hub each lead to a different answer. The
   logo shares the name's hit area so it cannot look clickable but do nothing. */
.subject-code-link, .subject-name-link, .subject-country-link, .subject-hub-link { padding: 0; border: 0; background: none; font: inherit; text-align: inherit; cursor: pointer; }
.subject-code-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.subject-name-link { display: inline-flex; align-items: center; gap: 10px; color: inherit; }
.subject-country-link { color: var(--accent); }
.subject-hub-link { color: var(--accent); }
.subject-name-link:hover span, .subject-country-link:hover, .subject-hub-link:hover { text-decoration: underline; text-underline-offset: 2px; }
.subject-code-link:focus-visible, .subject-name-link:focus-visible, .subject-country-link:focus-visible, .subject-hub-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
.subject-name-link span { text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 3px; }
.subject-name-link:hover span { color: var(--accent); }
.subject-grid .subject-stat-link strong, .subject-meta .subject-hub-link strong { color: var(--accent); }
.subject-operators { display: grid; gap: 5px; margin-top: 13px; padding-top: 11px; border-top: 1px solid var(--line); }
.subject-operators > span { color: var(--text-dim); font-size: 11px; }
.subject-operators > div { display: grid; gap: 2px; }
.subject-operators button { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; width: 100%; padding: 2px 0; border: 0; background: none; color: var(--accent); font: inherit; font-size: 12px; text-align: left; cursor: pointer; }
.subject-operators button:hover { text-decoration: underline; text-underline-offset: 2px; }
.subject-operators small { color: var(--text-dim); font-size: 10px; font-variant-numeric: tabular-nums; }
.subject-name { display: flex; align-items: center; gap: 10px; }
.subject-name h2 { margin-top: 12px; }
.subject-sub { margin: 5px 0 0; color: var(--text-dim); font-size: 12px; }
.subject-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 18px; padding-top: 12px; border-top: 1px solid var(--line); }
.subject-grid > div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.subject-grid strong { color: var(--text); font-size: 20px; font-weight: 650; }
.subject-grid span { color: var(--text-dim); font-size: 11px; }
.subject-meta { display: flex; justify-content: space-between; gap: 12px; margin: 13px 0 0; padding-top: 11px; border-top: 1px solid var(--line); color: var(--text-dim); font-size: 12px; }
.subject-meta strong { color: var(--text); text-align: right; font-weight: 600; }
.d-section { padding: 10px 18px; border-bottom: 1px solid var(--line); }
.d-section h4 { margin: 0 0 9px; font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-faint); font-weight: 600; }

/* The route already owns origin, destination and progress in the first card.
   Each flight row therefore spends its space on the comparison a passenger
   needs: scheduled, expected and actual in the same positions at both ends. */
.fl-row { display: grid; grid-template-columns: minmax(74px, 1fr) minmax(0, 4fr);
  gap: 14px; padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
.fl-row:first-child { padding-top: 4px; }
.fl-place b { display: block; font-family: var(--mono); font-size: 17px; font-weight: 500; }
.fl-place span { display: block; color: var(--text-dim); font-size: 10.5px; }
.fl-info { min-width: 0; }
.fl-times { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.fl-times > div > span { display: block; color: var(--text-faint); font-size: 9px;
  letter-spacing: .08em; text-transform: uppercase; }
.fl-times b { display: block; margin-top: 4px; font-family: var(--mono);
  font-size: 14px; font-variant-numeric: tabular-nums; font-weight: 500; }
.fl-times i { font-style: normal; color: var(--text-faint); font-size: 9px; margin-left: 2px; }
.fl-times .sc-none { color: var(--text-faint); }
.fl-times .sc-done { color: var(--accent); }
.fl-stand { margin-top: 7px; color: var(--text-dim); font-size: 11px; }
.fl-late { color: var(--danger); }
.fl-foot { display: flex; flex-wrap: wrap; gap: 6px 15px; padding-top: 10px;
  color: var(--text-dim); font-size: 11px; }
.fl-foot b { color: var(--text); font-family: var(--mono); font-weight: 500; }
.d-record { margin-top: 11px; }
.ac-photo-label { margin: 0 0 6px; color: var(--text-faint); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; }
.ac-more { margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--line-soft); }
.ac-more summary { color: var(--accent); font-size: 11px; cursor: pointer; }
@media (max-width: 420px) {
  .fl-row { grid-template-columns: 62px minmax(0, 1fr); gap: 9px; }
  .fl-times { gap: 3px; }
  .fl-times b { font-size: 12px; }
  .fl-times i { display: block; margin-left: 0; }
}

/* The journey thread. Layout only - every colour here is a token the drawer
   already uses, so it follows the theme switch without a rule of its own. */
.th { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: auto 16px minmax(0, 1fr); }
.th-row { display: contents; }
.th-at { font-family: var(--mono); font-size: 11px; color: var(--accent); text-align: right; white-space: nowrap; }
.th-rail { position: relative; display: flex; justify-content: center; }
.th-rail::before { content: ""; width: 1px; background: var(--line); }
.th-rail i {
  position: absolute; top: 3px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent);
}
.th-body { padding: 0 0 15px 11px; min-width: 0; }
.th-body b { display: block; font-size: 12px; font-weight: 500; color: var(--text); }
.th-body small { display: block; margin-top: 2px; font-size: 11px; color: var(--text-faint); }
.th-row:last-child .th-rail::before { display: none; }
.th-row:last-child .th-body { padding-bottom: 0; }

/* What has not happened yet must not read like what has. */
.th-future .th-at { color: var(--text-faint); }
.th-future .th-rail i { background: var(--bg-panel); border: 1px solid var(--text-faint); }
.th-future .th-body b { color: var(--text-faint); font-weight: 400; }

/* The present is the one row worth finding at a glance. */
.th-now .th-at { font-weight: 600; }
.th-now .th-rail i {
  top: 0; width: 14px; height: 14px;
  background: var(--bg-panel); border: 2px solid var(--accent);
}
.th-now .th-body b { color: var(--accent); }
.th-now .th-body small { color: var(--text-dim); }

/* The two-cell Off/On pair these dressed is a six-column table now, so the
   rules went with the markup rather than being left to match nothing. */

/* The two panels under an airport board: its published network, and what is
   running late. Both arrive after the board and are simply absent if they do
   not, so they carry their own separation rather than relying on the board
   above having left room. */
.board-extra { margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--line); }
.board-extra h3 { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.rt-count { font-size: 11px; font-weight: 400; color: var(--text-faint); font-family: var(--mono); }
.rt-wrap { overflow-x: auto; max-height: 340px; overflow-y: auto; }
.rt-by { color: var(--text-dim); font-size: 11px; }
/* The week as seven letters. A schedule's shape - daily, weekdays, twice a
   week - reads as a pattern far faster than it reads as a list of names. */
.rt-days { white-space: nowrap; }
.rt-days i {
  display: inline-block; width: 13px; font-style: normal; text-align: center;
  font-family: var(--mono); font-size: 10px; color: var(--text-faint);
  border-bottom: 2px solid transparent;
}
.rt-days i.on { color: var(--accent); border-bottom-color: var(--accent); }
.dl-late { color: var(--danger); font-family: var(--mono); font-size: 12px; white-space: nowrap; }
.board-table small { display: block; font-size: 10px; color: var(--text-faint); }

/* The schedule as a grid: two rows, three clocks each, so planned and actual
   sit in the same column and the comparison reads without arithmetic. It
   scrolls in its own box rather than widening the drawer. */
.sc-wrap { overflow-x: auto; }
.sc { border-collapse: collapse; width: 100%; font-size: 12px; }
.sc th, .sc td { text-align: left; padding: 7px 10px 7px 0; vertical-align: baseline; }
.sc thead th {
  font-size: 8.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 400; padding-bottom: 4px;
  border-bottom: 1px solid var(--line);
}
.sc tbody th { white-space: nowrap; padding-right: 16px; }
.sc tbody th b { display: block; font-family: var(--mono); font-size: 14px; font-weight: 500; }
.sc tbody th span { font-size: 10px; color: var(--text-faint); }
.sc tbody td {
  font-family: var(--mono); font-size: 13px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  border-bottom: 1px solid var(--line-soft);
}
.sc tbody tr:last-child td { border-bottom: none; }
.sc td i { font-style: normal; font-size: 9px; color: var(--text-faint); margin-left: 2px; }
.sc .sc-done { color: var(--accent); }
.sc .sc-none { color: var(--text-faint); }
.sc .sc-place { font-family: var(--sans); font-size: 11px; color: var(--text-dim); }
.sc .sc-late { color: var(--danger); font-size: 11.5px; }


/* The journey is a short horizontal progress view where there is room: where
   it left, its latest reported position, and where it is due. These are the
   only three stages the feed can support without making up intermediate stops.
   A narrow drawer returns to the vertical reading order below. */
.jn-rail {
  list-style: none; margin: 0; padding: 0; position: relative;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
}
.jn-rail::before {
  content: ""; position: absolute; left: 16.666%; right: 16.666%; top: 5px;
  height: 1px; background: var(--line);
}
.jn { position: relative; min-width: 0; padding-top: 20px; }
.jn-dot {
  position: absolute; left: 50%; top: 0; width: 11px; height: 11px;
  transform: translateX(-50%);
  border-radius: 50%; background: var(--bg-raised);
  border: 2px solid var(--line); box-sizing: border-box;
}
.jn-live { border-color: var(--accent); background: var(--accent); }
.jn-body { text-align: center; }
.jn-head { display: flex; align-items: baseline; justify-content: center; gap: 6px; flex-wrap: wrap; }
.jn-head b { font-family: var(--mono); font-size: 14px; font-weight: 500; }
.jn-head span { font-size: 12px; color: var(--text-dim); }
.jn-when { font-size: 11px; color: var(--text-faint); margin-top: 2px; }
.jn-near { font-size: 11px; color: var(--text-dim); margin-top: 3px; }
.jn-alt { font-size: 10px; color: var(--text-faint); margin-top: 1px; font-family: var(--mono); }
.jn-now .jn-head b { color: var(--accent); }
.jn-foot {
  display: flex; gap: 16px; flex-wrap: wrap; margin-top: 12px;
  padding-top: 10px; border-top: 1px solid var(--line-soft);
  font-size: 11.5px; color: var(--text-dim);
}
.jn-foot b { font-family: var(--mono); font-weight: 500; color: var(--text); }
.jn-late b { color: var(--danger); }

@media (max-width: 620px) {
  .jn-rail { display: block; }
  .jn-rail::before { left: 5px; right: auto; top: 10px; bottom: 10px; width: 1px; height: auto; }
  .jn { padding: 0 0 16px 22px; }
  .jn:last-child { padding-bottom: 0; }
  .jn-dot { left: 0; top: 4px; transform: none; }
  .jn-body { text-align: left; }
  .jn-head { justify-content: flex-start; gap: 8px; }
}

/* The filed flight category is the one weather value with a status colour.
   Keep its four meanings identical wherever the compact report appears. */
.wx-none { margin: 6px 0 0; font-size: 11px; color: var(--text-faint); }
.wx-cat {
  display: inline-block; flex: none; padding: 3px 8px;
  border: 1px solid currentColor; border-radius: 999px;
  background: var(--bg-raised); font-family: var(--mono);
  font-size: 10px; font-weight: 600; letter-spacing: 0.06em;
}
.wx-cat.wx-good { color: var(--ok); }
.wx-cat.wx-fair { color: var(--accent); }
.wx-cat.wx-poor { color: var(--amber); }
.wx-cat.wx-bad  { color: var(--danger); }
.telemetry { display: grid; grid-template-columns: repeat(2, 1fr); gap: 9px; }
.d-tele { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
.tele {
  background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 9px 11px;
}
.tele b { display: block; font-family: var(--mono); font-size: 16px; font-weight: 500; }
.tele span { font-size: 9px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint); }

/* Block, remaining and distance are three short numbers; stacking them cost
   three lines to say what one row says. Tiled like the telemetry readouts they
   sit beside in the next pane - the same kind of value deserves the same box. */
.kv-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px; margin-top: 11px; }
.kv-cell {
  background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 5px 9px;
  min-width: 0;
}
.kv-cell span { display: block; font-size: 9px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 1px; }
.kv-cell b { display: block; font-family: var(--mono); font-size: 12px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.kv-list { display: flex; flex-direction: column; gap: 7px; }
.kv-line { display: flex; justify-content: space-between; gap: 12px; font-size: 12px; }
.kv-line span { color: var(--text-faint); }
.kv-line b { font-weight: 500; font-family: var(--mono); font-size: 11.5px; }


/* ============================================================== aurora shell

   Layout comes last on purpose. Everything above styles a component; this
   places them, and where the two disagree the placement is the one that meant
   it. */

.layout {
  position: relative;
  height: 100%;
  overflow: hidden;
  background: var(--map-ground);
}

/* The map is the whole window. It was the residual of two fixed columns, which
   left it 716px of 1440 the moment a flight was open - less than the chrome
   around it, for the one thing a visitor came to look at. */
.stage { position: absolute; inset: 0; z-index: 0; }
/* touch-action: none hands every gesture to the map, so a drag pans it instead
   of scrolling the page and a pinch zooms it instead of zooming the browser. */
#map { display: block; width: 100%; height: 100%; cursor: grab; touch-action: none; }
/* The ring is drawn inside: the canvas fills the stage, so an outset one would
   be clipped away by it. */
#map:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
#map.is-dragging { cursor: grabbing; }

/* Every floating surface is the same glass. The solid colour comes first, so a
   browser without backdrop-filter gets an opaque panel rather than text laid
   over moving traffic. */
.pane, .sidebar, .detail, .map-tools, .map-layers, .timebar, .map-readout,
.welcome, .routes-clear, .tooltip {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pane, .sidebar, .detail, .map-tools, .map-layers, .timebar, .map-readout,
  .welcome, .routes-clear {
    -webkit-backdrop-filter: var(--blur);
            backdrop-filter: var(--blur);
  }
}

/* ------------------------------------------------------------------- rail */

.rail {
  position: absolute; top: 0; bottom: 0; left: 0; z-index: 24;
  width: var(--rail-w);
  display: flex; flex-direction: column; align-items: center;
  gap: 6px;
  padding: 14px 0 12px;
  background: var(--bg-panel);
  border-right: 1px solid var(--line-soft);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .rail { -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur); }
}

.rail-brand {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  margin-bottom: 10px;
  color: var(--brand); text-decoration: none;
}
.brand-mark {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  font-size: 24px; font-weight: 600; line-height: 1;
  color: var(--brand);
}
/* ?v=3 on every brand URL. These are served with a week of cache, which is
   right for a logo and wrong for the day the logo changes: without a new URL
   a returning visitor keeps the old mark until the cache lets go. Bump it
   whenever tools/build_brand.py draws something different. */
@supports (mask-image: url("../brand/mark-mono.svg?v=3")) or
          (-webkit-mask-image: url("../brand/mark-mono.svg?v=3")) {
  .brand-mark {
    color: transparent;
    background: var(--brand);
    -webkit-mask: url("../brand/mark-mono.svg?v=3") center / contain no-repeat;
            mask: url("../brand/mark-mono.svg?v=3") center / contain no-repeat;
    filter: drop-shadow(0 0 10px var(--brand-glow));
  }
}

/* The same tabs move between the desktop map edge and the bottom phone bar.
   One set of buttons keeps selection and keyboard focus in step. */
.rail .tabs { display: flex; flex-direction: column; gap: 4px; width: 100%; align-items: center; }

.tab {
  position: relative;
  width: 52px; height: 48px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  background: none; border: 0; border-radius: 12px;
  color: var(--text-faint);
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.tab:hover { color: var(--text-dim); background: var(--bg-hover); }
.tab.is-active { color: var(--brand-ink); background: var(--accent); }
.rail-ic { width: 19px; height: 19px; fill: currentColor; }
/* The outline glyphs are drawn as strokes; the solid one carries its own shape
   and would fill in on itself. */
.rail-ic.o { fill: none; stroke: currentColor; stroke-width: 1.7;
             stroke-linecap: round; stroke-linejoin: round; }
/* The words under the rail icons, back on screen.

   They went out with the subtitles, on the reasoning that the phone bar has
   always been icons only so the two layouts may as well agree. Rejected on
   sight: eight icons in a column with nothing naming them is a puzzle, and the
   tooltip that solves it costs a pointer and a pause - two things a visitor
   should not have to spend to learn what a button does.

   A word under an icon is not a subtitle. It is the only name the thing has. */
.rail-label {
  font-size: 8.5px; letter-spacing: 0.04em; line-height: 1;
  color: var(--text-faint);
}
.tab.is-active .rail-label { color: var(--brand-ink); }

.rail-foot { margin-top: auto; display: flex; flex-direction: column; gap: 4px; }
.rail-btn {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  background: none; border: 1px solid transparent; border-radius: 11px;
  color: var(--text-faint); cursor: pointer;
  font-size: 15px; line-height: 1;
  transition: color 0.15s, background 0.15s;
}
.rail-btn:hover { color: var(--accent); background: var(--bg-hover); }
.theme-icon { font-size: 15px; }

/* ---------------------------------------------------------------- topline */

/* Islands rather than a bar, so the world carries on between them - and they
   wrap rather than shedding anything. The six figures used to be hidden two at
   1500px, four at 1240 and all six at 1180, which put the number a visitor
   came for behind a tab at exactly the width most laptops are. */
.topline {
  position: absolute; z-index: 22;
  top: var(--gap);
  left: calc(var(--rail-w) + var(--gap));
  right: var(--gap);
  /* Every island on a row is as tall as the tallest one on it. They used to
     sit at flex-start, each at its own content height, so on a phone the
     name (one line) stood beside the clock (two lines) 7px shorter, and the
     owner saw two boxes that were meant to match and did not. */
  display: flex; align-items: stretch; flex-wrap: wrap;
  gap: 10px;
  pointer-events: none;
}
.topline > * { pointer-events: auto; }

/* One command area makes the first decision obvious: identify the site,
   search it, then glance at the live state. The old islands made six changing
   figures look like six competing calls to action before a visitor had typed a
   question. Their node moves into Flights in app.js, while this shell keeps the
   brand, search and feed status in one visual sentence. */
.topline.command-bar {
  align-items: center; flex-wrap: nowrap; gap: 8px; padding: 0;
  background: transparent; border: 0; box-shadow: none;
}
.topline.command-bar > .brand.pane,
.topline.command-bar > .cmd.pane,
.topline.command-bar > .cluster {
  /* Equal height keeps the identity, action and live-state surfaces on one
     baseline. Without a fixed row, the search control's button made its
     neighbors look shorter on desktop and the difference returned on mobile. */
  box-sizing: border-box; height: 46px; min-height: 46px;
  background: var(--bg-panel); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
}
.topline.command-bar > .brand.pane {
  padding: 8px 13px 8px 10px;
}
.topline.command-bar > .cmd.pane {
  flex: 1 1 auto; min-width: 220px; padding-left: 13px; padding-right: 8px;
}
.topline.command-bar > .cluster {
  padding: 8px 10px; margin-left: auto;
}
/* The live state remains in the DOM so app.js can move the one truthful marker
   to the rail. The clock was deliberately removed from the header already;
   leaving this empty third island on desktop made the search look crowded for
   no visitor benefit. */
.topline.command-bar > .cluster { display: none; }

.live-snapshot {
  margin: 8px 12px 10px; padding: 9px 0 0;
  border-top: 1px solid var(--line-soft);
}
.live-snapshot .chips {
  display: grid; grid-template-columns: repeat(6, minmax(80px, 1fr));
  gap: 0; padding: 0; overflow-x: auto; scrollbar-width: thin;
}
.live-snapshot .chip {
  min-width: 0; padding: 6px 5px; align-items: flex-start;
}
.live-snapshot .chip:not(:first-child) { border-left: 1px solid var(--line-soft); }
.live-snapshot .chip + .chip { box-shadow: none; }

.pane { padding: 9px 14px; }

.brand.pane { display: flex; align-items: center; flex: none; }
.brand-home { color: inherit; text-decoration: none; cursor: pointer; }
.brand-home:hover .brand-word { color: var(--accent); }
.brand-home:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
/* Hidden while the rail is a column, because the rail is carrying the mark
   there and two of them on one screen is one too many. The phone rule below
   turns it on at the same breakpoint that turns the rail's copy off. */
.brand-mark-inline { display: none; }
.brand-text { display: flex; flex-direction: column; gap: 3px; line-height: 1.15; }
.brand-text .brand-word { margin: 0; font-size: 14px; font-weight: 700; letter-spacing: 0.15em; }
@supports (mask-image: url("../brand/wordmark.svg?v=3")) or
          (-webkit-mask-image: url("../brand/wordmark.svg?v=3")) {
  /* The wordmark file is 690.84 x 129.82 against a cap height of 100: the y
     descends below the baseline and the round letters overshoot it, so the box
     is half again as tall as the caps inside it. Setting the cap and working
     the box out from it keeps the name the size it looks on the line beside
     it - a box set to the cap height would draw the letters two thirds size. */
  .brand-word {
    --cap: 12px;
    display: block;
    height: calc(var(--cap) * 129.82 / 100);
    width: calc(var(--cap) * 690.84 / 100);
    overflow: hidden; white-space: nowrap; color: transparent;
    background: var(--text);
    -webkit-mask: url("../brand/wordmark.svg?v=3") left center / contain no-repeat;
            mask: url("../brand/wordmark.svg?v=3") left center / contain no-repeat;
  }
}
.brand-line { display: flex; align-items: center; gap: 8px; }
/* Quieter than a status pill: this is a standing note about the software, not
   a state that changes, and it should not compete with the wordmark it sits
   against. It is left readable rather than aria-hidden - "beta" is something
   a visitor is entitled to hear, not decoration. */
.brand-beta {
  flex: none;
  padding: 1px 6px;
  border: 1px solid var(--accent-dim);
  border-radius: 999px;
  font-size: 8.5px; letter-spacing: 0.13em; text-transform: uppercase;
  line-height: 1.6;
  color: var(--accent);
}
/* The only line on the page that says the traffic is invented. It stays at
   every width. */
.brand-text small {
  font-size: 9.5px; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--text-faint);
}

/* The way in to all four things the site models, at the width of a sentence
   rather than a 30px icon. */
.cmd {
  position: relative;
  flex: 1 1 240px; min-width: 0;
  display: flex; align-items: center; gap: 10px;
  /* A floor, not a fixed height, so it grows to match the row it shares
     on a wide screen - the name and the clock there are 51px, and a 44px
     search between them was the one island that did not line up. */
  min-height: 44px; padding: 0 12px 0 14px;
  cursor: text; text-align: left;
  font: inherit;
  transition: border-color 0.15s;
}
.cmd:hover { border-color: var(--accent-dim); }
/* The whole bar reads as focused, because the input inside it has no border
   of its own - it is the bar. */
.cmd:focus-within { border-color: var(--accent); }
.cmd-ic { width: 17px; height: 17px; flex: none; color: var(--brand); }
.cmd-input {
  flex: 1; min-width: 0;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; font-size: 13.5px; color: var(--text);
  outline: none;
}
.cmd-input::placeholder { color: var(--text-faint); opacity: 1; }
.cmd-ph {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13.5px; color: var(--text-faint);
}

/* The results, anchored under the bar rather than floated in an overlay. Only
   this instance: #zones still uses .jump-list inside a real dialog, and that
   one should stay exactly as it was. */
.cmd-drop {
  position: absolute; z-index: 60;
  top: calc(100% + 7px); left: 0; right: 0;
  padding: 7px 10px 4px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  cursor: default;
}
/* The list scrolls inside the panel; the hint underneath it does not, so it
   stays put while the results move. */
.cmd-drop .jump-list {
  margin-top: 0;
  max-height: min(52vh, 420px);
  overscroll-behavior: contain;
}
.jump-guide[hidden] { display: none; }
.jump-intents { display: flex; gap: 5px; margin: 0 0 10px; }
.jump-intents button, .jump-examples button {
  border: 0; border-radius: 999px; cursor: pointer; font: inherit;
}
.jump-intents button {
  padding: 7px 10px; color: var(--text-faint); background: transparent;
  font-size: 12px;
}
.jump-intents button:hover, .jump-intents button.is-active {
  color: var(--accent); background: var(--sel-bg);
}
.jump-examples { display: flex; flex-wrap: wrap; gap: 7px; }
.jump-examples button {
  padding: 7px 10px; color: var(--text-dim); background: var(--bg-raised);
  font-size: 11px; text-align: left;
}
.jump-examples button:hover { color: var(--text); background: var(--bg-hover); }
.jump-answer {
  position: absolute; z-index: 62; top: calc(100% + 7px); left: 0;
  width: min(430px, calc(100vw - 20px)); padding: 14px;
  background: var(--bg-panel); border: 1px solid var(--accent-dim);
  border-radius: var(--radius-lg); box-shadow: var(--shadow); cursor: default;
}
.jump-answer[hidden] { display: none; }
.jump-answer-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
}
.jump-answer-kicker {
  display: block; margin-bottom: 4px; color: var(--text-faint); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase;
}
.jump-answer h2 { margin: 0; font-size: 18px; line-height: 1.2; font-weight: 500; }
.jump-answer h2 .pill { margin-left: 6px; vertical-align: 2px; }
.jump-answer-head p { margin: 5px 0 0; color: var(--text-dim); font-size: 12px; }
.jump-answer-data {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px;
  margin: 14px 0; color: var(--text-faint); font-size: 10px;
}
.jump-answer-data b {
  display: block; margin-top: 4px; color: var(--text); font-family: var(--mono);
  font-size: 11px; font-weight: 500; white-space: nowrap;
}
.jump-answer-actions { display: flex; gap: 8px; }
.jump-answer-actions .btn { flex: 1; min-height: 30px; }
.jump-answer-note { margin: 0; color: var(--text-dim); font-size: 12px; line-height: 1.5; }
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .cmd-drop, .jump-answer {
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  }
}
.cmd-kbd {
  flex: none;
  min-width: 20px; padding: 2px 6px;
  border: 1px solid var(--line); border-radius: 6px;
  font-family: var(--mono); font-size: 11px; color: var(--text-faint);
  text-align: center;
}
.cmd-submit {
  flex: none; min-height: 32px; padding: 0 14px;
  border: 0; border-radius: 8px;
  color: var(--brand-ink); background: var(--brand);
  font-size: 12px; font-weight: 500; cursor: pointer;
}
.cmd-submit:hover { background: var(--focus); }

.chips { display: flex; align-items: stretch; gap: 0; flex: none; padding: 4px; }
.chip {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  padding: 5px 11px;
  background: none; border: 0; border-radius: 10px;
  cursor: pointer; text-align: left;
  transition: background 0.15s;
}
.chip + .chip { box-shadow: inset 1px 0 0 var(--line-soft); }
.chip:hover { background: var(--bg-hover); }
.chip-value {
  font-family: var(--mono); font-size: 15px; font-weight: 500; line-height: 1.1;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.chip-label {
  font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint); white-space: nowrap;
}
.chip[data-metric="delayed"] .chip-value { color: var(--amber); }
.chip[data-metric="ontime"] .chip-value { color: var(--ok); }

.cluster { display: flex; align-items: center; gap: 12px; flex: none; }
.clock { display: flex; flex-direction: column; }
.clock-main {
  font-family: var(--mono); font-size: 18px; line-height: 1.1;
  letter-spacing: 0.03em; color: var(--brand); font-variant-numeric: tabular-nums;
}
.clock-sub { font-size: 9px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint); }

.clocks { display: flex; align-items: center; gap: 6px; }
.zone {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 4px 18px 4px 9px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 8px;
  white-space: nowrap;
}
.zone-time { font-family: var(--mono); font-size: 13px; line-height: 1.1; color: var(--text); }
/* The day offset rides small and high on the time, the way a footnote does. */
.zone-time i {
  font-style: normal; font-size: 9px; vertical-align: super;
  margin-left: 2px; color: var(--amber);
}
.zone-label {
  font-size: 8px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint); margin-top: 1px;
}
.zone-drop {
  position: absolute; top: 2px; right: 2px;
  width: 14px; height: 14px;
  background: none; border: none; border-radius: 4px;
  color: var(--text-faint); cursor: pointer; line-height: 1;
}
.zone-drop:hover { color: var(--danger); }
.zone-add {
  width: 26px; height: 26px; flex: none;
  background: none;
  border: 1px dashed var(--line); border-radius: 8px;
  color: var(--text-faint); cursor: pointer; font-size: 15px; line-height: 1;
}
.zone-add:hover { color: var(--accent); border-color: var(--accent-dim); border-style: solid; }
.zone-add[hidden] { display: none; }

.status-dot { display: flex; align-items: center; gap: 6px; font-size: 9.5px;
              letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint); }
.header-clock { display: none !important; }
.status-dot .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); }
.status-dot.is-live .dot { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.status-dot.is-down .dot { background: var(--danger); box-shadow: 0 0 8px var(--danger); }
/* A status is a glanceable light in the rail, not another labelled header
   control. The title remains available to pointer users and the live region
   continues to announce a stalled feed for assistive technology. */
.rail-foot .status-dot {
  box-sizing: border-box; width: 38px; height: 38px; flex: none;
  justify-content: center; gap: 0; border-radius: 11px;
}
.rail-foot .status-dot span:not(.dot) { display: none; }
/* Desktop already has room to show the map's own last-report age. The rail
   light repeats that state without helping a route decision, so it belongs to
   the compact layout only. */
@media (min-width: 1001px) {
  .rail-foot .status-dot { display: none; }
}

/* ------------------------------------------------------------- result card */

.sidebar {
  position: absolute; z-index: 20;
  left: calc(var(--rail-w) + var(--gap));
  width: var(--sidebar-w);
  top: calc(var(--gap) + var(--top-h) + 10px);
  bottom: calc(var(--gap) + var(--dock-h) + 10px);
  display: flex; flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
.menu-btn { display: none; }

/* Shut by pressing the tab that is already on. Only ever set on the wide
   layout - on a phone this element is the sheet, and display:none would leave
   the tab bar with nothing to open - and app.js clears it on the way down to
   the compact layout so a narrowed window cannot inherit one. */
.sidebar.is-shut { display: none; }

.panel { display: none; flex-direction: column; min-height: 0; flex: 1; }
.panel.is-active { display: flex; }

.search { display: flex; align-items: center; gap: 8px; padding: 12px 12px 8px; }
.search input {
  flex: 1; min-width: 0;
  padding: 9px 12px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color 0.15s;
}
.search input::placeholder { color: var(--text-faint); }
.search input:focus { border-color: var(--accent-dim); }

/* What the box found, as things rather than as narrowed rows.
 *
 * In normal flow, not floating: an overlay would have to guess at the panel's
 * scroll offset across eight tabs and two layouts, and this disappears the
 * moment anything is chosen. The list below is pushed down for a second and
 * that is the whole cost.
 *
 * Every row is a button because every row does something - opens a board,
 * opens a carrier, sets a filter - and a thing that acts when pressed should
 * be the element that acts when pressed, for a keyboard as much as a mouse. */
.finder {
  margin: 0 12px 8px;
  padding: 5px 4px 7px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-height: 46vh;
  overflow-y: auto;
}
.fi-group {
  margin: 7px 0 3px;
  padding: 0 8px;
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.fi-group:first-child { margin-top: 2px; }
.fi {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 9px;
  align-items: center;
  width: 100%;
  padding: 7px 8px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.fi:hover, .fi:focus-visible { background: var(--bg-hover); }
.fi-code {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--brand);
  background: var(--bg-raised);
  border-radius: 5px;
  padding: 3px 6px;
  white-space: nowrap;
}
.fi-name {
  font-size: 12.5px;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fi-name em {
  display: block;
  font-style: normal;
  font-size: 10px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
}
.fi-right {
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--text-faint);
  white-space: nowrap;
}

/* Four filters that are usually unset were costing four rows of the list to
   say so - 183px of a 493px list, showing, most of the time, the fact that
   nothing is filtered. They fold behind one control that names what is on. */
.filters { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; padding: 0 12px 10px; }
.filters[hidden] { display: none; }
.filters .field:nth-child(5) { grid-column: span 2; }
.field select, .field { min-width: 0; }
.field select { width: 100%; text-overflow: ellipsis; }
.field { display: flex; flex-direction: column; gap: 4px; }
/* Direct child only. This used to be `.field span`, which was harmless while a
   field held a label and a select - and started painting the whole multiselect
   in 9px faint uppercase the moment a field contained a widget made of spans. */
.field > span { font-size: 9.5px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint); }
.field select {
  padding: 7px 8px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
}
.field select:focus { border-color: var(--accent-dim); }

.site-footer {
  flex: none;
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  padding: 8px 14px;
  border-top: 1px solid var(--line-soft);
  font-size: 9.5px; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-faint);
}
.site-footer p { margin: 0; }
.site-footer-nav { display: flex; align-items: center; gap: 12px; }
.site-footer-nav a,
.site-footer-nav button {
  background: none; border: 0; padding: 0;
  font: inherit; letter-spacing: inherit; text-transform: inherit;
  color: var(--text-faint); text-decoration: none; cursor: pointer;
}
.site-footer-nav a:hover,
.site-footer-nav button:hover,
.site-footer-nav a:focus-visible,
.site-footer-nav button:focus-visible { color: var(--accent); }

/* ------------------------------------------------------------ detail card */

.detail {
  position: absolute; z-index: 21;
  right: var(--gap);
  width: var(--detail-w);
  top: calc(var(--gap) + var(--top-h) + 10px);
  bottom: calc(var(--gap) + var(--dock-h) + 10px);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.detail[hidden] { display: none; }
.detail-close {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  background: var(--bg-raised); border: 1px solid var(--line); border-radius: 9px;
  color: var(--text-faint); cursor: pointer;
}
.detail-close:hover { color: var(--danger); border-color: var(--danger); }
#detail-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }

/* --------------------------------------------------------------- map dock */

/* Zoom, fit, follow, dice and the layers in one strip in one corner. Four
   clusters in four corners was three corners too many on a phone, where
   together they painted over an eighth of the map and every aircraft under
   them was both invisible and untappable. */
.map-tools {
  position: absolute; z-index: 18;
  right: var(--gap); bottom: var(--gap);
  height: var(--dock-h);
  display: flex; align-items: center; gap: 4px;
  padding: 0 6px;
}
.tool {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  background: none;
  border: 1px solid transparent;
  border-radius: 10px;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 15px;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.tool:hover { color: var(--accent); background: var(--bg-hover); }
.tool.is-on { color: var(--brand-ink); background: var(--accent); border-color: var(--accent); }
#toggle-follow { font-size: 10px; letter-spacing: 0.04em; }
.tools-rule { width: 1px; height: 22px; background: var(--line); margin: 0 3px; }

/* The round tools are a grid with one child in the middle of them; this one
   has three, and a grid lays those out down the button rather than along it. */
.tool-layers {
  display: flex; align-items: center;
  width: auto; gap: 7px; padding: 0 11px; font-size: 12px;
}
.tool-layers svg { width: 16px; height: 16px; }
.tool-word { letter-spacing: 0.02em; }
.tool-count {
  min-width: 18px; padding: 1px 5px;
  border-radius: 999px;
  background: var(--accent); color: var(--brand-ink);
  font-family: var(--mono); font-size: 10px; line-height: 1.5;
}
.tool-layers[aria-expanded="true"] { color: var(--accent); background: var(--bg-hover); }

/* Eight switches loose over the map was eight things to read before the map.
   The popover is anchored to the button that opens it and closes on Escape
   like every other transient surface here. */
.map-layers {
  /* Above the cards, not among them: a popover that opens underneath the panel
     beside it is a popover that did not open. */
  position: absolute; z-index: 32;
  right: var(--gap); bottom: calc(var(--gap) + var(--dock-h) + 8px);
  width: 268px;
  padding: 12px 14px 14px;
  display: flex; flex-direction: column; gap: 8px;
}
.map-layers[hidden] { display: none; }
.layers-head {
  font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 600;
}

.proj { display: flex; gap: 4px; padding: 3px; background: var(--bg-raised);
        border: 1px solid var(--line); border-radius: 10px; }
.proj button {
  flex: 1;
  padding: 5px 8px;
  background: none; border: 0; border-radius: 7px;
  color: var(--text-faint); cursor: pointer;
  font: inherit; font-size: 11.5px; letter-spacing: 0.04em;
  transition: color 0.15s, background 0.15s;
}
.proj button:hover { color: var(--text-dim); }
.proj button[aria-checked="true"] { background: var(--accent); color: var(--brand-ink); }

.layer-set { display: flex; flex-wrap: wrap; gap: 6px; }
/* A layer is on or it is not, and the chip says which by being filled or not -
   the same answer the projection pair gives, in the same colour. These stay
   independent buttons rather than becoming a second radio group: any number of
   them can be on, and usually most are. */
.layer {
  flex: none;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--text-faint);
  cursor: pointer;
  font: inherit; font-size: 11.5px; letter-spacing: 0.02em;
  white-space: nowrap;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.layer:hover { color: var(--accent); border-color: var(--accent-dim); }
.layer[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--brand-ink);
}
.layers-clear {
  align-self: flex-start;
  margin-top: 2px; padding: 4px 0;
  background: none; border: 0;
  color: var(--text-faint); cursor: pointer;
  font: inherit; font-size: 11px; letter-spacing: 0.04em;
}
.layers-clear:hover { color: var(--accent); text-decoration: underline; }
.layers-clear.is-off { color: var(--accent); }

/* ---------------------------------------------------------------- timebar */

/* The clock is the site's one genuinely unusual control, and it sits in the
   middle of the bottom edge, in the clear band between the two cards. */
.timebar {
  position: absolute; z-index: 18;
  bottom: var(--gap);
  left: calc(var(--rail-w) + var(--gap) + var(--sidebar-w) + 14px);
  right: calc(var(--gap) + 470px);
  height: var(--dock-h);
  display: flex; align-items: center; gap: 12px;
  padding: 0 14px;
}
.tb-live {
  flex: none;
  padding: 4px 11px;
  background: none;
  border: 1px solid var(--line); border-radius: 999px;
  color: var(--text-faint); cursor: pointer;
  font: inherit; font-size: 10.5px; letter-spacing: 0.09em; text-transform: uppercase;
}
.tb-live.is-on { border-color: var(--accent); color: var(--brand-ink); background: var(--accent); }
#tb-range { flex: 1; min-width: 0; accent-color: var(--accent); height: 20px; }
.tb-out {
  flex: none; min-width: 62px; text-align: right;
  font-family: var(--mono); font-size: 12px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
body.is-scrubbed .tb-out { color: var(--amber); }

.map-readout {
  position: absolute; z-index: 17;
  left: calc(var(--rail-w) + var(--gap)); bottom: var(--gap);
  height: var(--dock-h);
  display: flex; align-items: center; gap: 9px;
  padding: 0 13px;
  font-family: var(--mono); font-size: 11px; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.map-readout .sep { opacity: 0.4; }

/* The routes overlay names itself and takes itself off, above the clock. */
.routes-clear {
  position: absolute; z-index: 19;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--gap) + var(--dock-h) + 10px);
  display: flex; align-items: center; gap: 9px;
  padding: 7px 13px;
  border-radius: 999px;
  color: var(--accent); cursor: pointer;
  font: inherit; font-size: 11.5px;
}
.routes-clear[hidden] { display: none; }
.routes-clear:hover { color: var(--danger); border-color: var(--danger); }

.tooltip {
  position: absolute; z-index: 26;
  padding: 8px 11px;
  border-radius: 12px;
  font-size: 11.5px; line-height: 1.5;
  pointer-events: none;
  max-width: 260px;
}
.tooltip[hidden] { display: none; }

.toast {
  position: absolute; z-index: 40;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--gap) + var(--dock-h) + 56px);
  padding: 10px 16px;
  background: var(--accent); color: var(--brand-ink);
  border-radius: 999px;
  font-size: 12.5px; font-weight: 500;
  box-shadow: var(--shadow);
}
.toast[hidden] { display: none; }

/* The dialogs belong to the window, not to whatever the map has been left
   over: a carrier profile used to be 546px wide with a flight open beside it
   and 920 without, for no reason a visitor could see. */
.board-overlay { position: absolute; inset: 0; z-index: 44; }

.scrim { display: none; }

/* ------------------------------------------------------------- responsive */

@media (max-width: 1240px) {
  :root { --sidebar-w: 340px; --detail-w: 340px; }
  .timebar { right: calc(var(--gap) + 438px); }
}

/* Below this the cards stop floating beside each other: the list becomes a
   sheet that rises from the bottom edge, the rail becomes the bar under it,
   and the map keeps the whole screen behind both. */
@media (max-width: 1000px) {
  :root { --gap: 10px; --rail-w: 0px; --dock-h: 42px; }

  /* The rail lies down. Same buttons, same state, same handlers. */
  .rail {
    top: auto; left: 0; right: 0; bottom: 0;
    width: auto; height: 62px;
    flex-direction: row; align-items: center; justify-content: space-between;
    gap: 0;
    padding: 0 6px;
    border-right: 0; border-top: 1px solid var(--line);
    border-radius: 0;
    z-index: 30;
  }
  .rail-brand { display: none; }
  /* ...and the topline picks it up, so the phone is not the one layout with
     no logo on it. Smaller than the rail's 26px: it sits on a 14px wordmark
     here rather than alone in a 40px square. */
  .brand-mark-inline {
    display: grid;
    width: 21px; height: 21px;
    margin-right: 9px;
    flex: none;
  }
  .rail .tabs { flex-direction: row; justify-content: space-around; flex: 1; }
  .tab { width: auto; flex: 1; height: 52px; max-width: 76px; }
  .rail-foot { margin-top: 0; flex-direction: row; gap: 0; }
  .rail-btn { width: 34px; height: 44px; border-radius: 10px; }


  .topline { top: var(--gap); left: var(--gap); right: var(--gap); gap: 7px; }
  .topline.command-bar { gap: 0; padding: 6px; }
  .topline.command-bar > .brand.pane {
    order: 1; flex: 1 1 auto; padding: 4px 8px; border-right: 0;
  }
  .topline.command-bar > .cluster {
    order: 2; flex: none; padding: 4px 5px; gap: 8px; border-left: 0;
  }
  .topline.command-bar > .cmd.pane {
    order: 3; flex: 1 1 100%; min-width: 0; min-height: 38px;
    padding: 0 6px 0 9px; border-top: 1px solid var(--line-soft);
  }
  /* The six figures above the search, not below it. The owner asked for the
     bar under the aircraft/airborne row, and it also means the results open
     over the map rather than over those numbers - the note saying how many
     aircraft the search lit was sitting exactly behind the chips. The wide
     layout reads the same way from the markup order, figures then search. */
  .chips { order: 3; flex: 1 1 100%; justify-content: space-between; padding: 3px; }
  .cmd { order: 4; flex: 1 1 100%; min-height: 38px; }
  .cmd-submit { min-height: 30px; padding: 0 12px; }
  .live-snapshot .chips { order: initial; flex: none; justify-content: initial; padding: 0; }
  .jump-answer { right: 0; width: auto; }
  .jump-answer-data { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .chip { padding: 3px 5px; flex: 1; align-items: center; }
  .rail-btn { width: 32px; }
  .chip-value { font-size: 13px; }
  .chip-label { font-size: 8px; letter-spacing: 0.04em; }
  .clocks, .zone-add { display: none; }
  .status-dot span:not(.dot) { display: none; }
  .clock-main { font-size: 15px; }
  /* The date used to be hidden here, so a phone showed a running clock and no
     way to tell which day it was running through - and now that the big line
     is local time, this is also the only thing naming UTC. It is one 8px line
     and the header has room for it. */
  .clock-sub { font-size: 8px; letter-spacing: 0.05em; }

  /* On a narrow screen the old single capsule made the logo, status dot and
     search field look like one long sentence with no starting point. The
     brand is the identity line and the search is the action line, so give
     each one a small, deliberate surface while keeping them in one command
     area. This also leaves the result guide anchored to the field instead of
     making it appear to belong to the map. */
  .topline.command-bar {
    display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content;
    grid-template-areas: "brand search state";
    align-items: center; gap: 6px; padding: 0;
    background: transparent; border: 0; box-shadow: none;
  }
  .topline.command-bar > .brand.pane {
    grid-area: brand; order: initial; flex: none; min-width: 0; padding: 8px 11px;
    background: var(--bg-panel); border: 1px solid var(--line);
    border-radius: var(--radius-lg); box-shadow: var(--shadow);
  }
  .topline.command-bar > .cluster {
    /* The status marker moves into the bottom rail on compact screens. The
       cluster is hidden after the move so an empty header island cannot steal
       the narrow column that belongs to the search field. */
    display: none; grid-area: state; order: initial; flex: none;
    padding: 8px 11px; margin-left: 0;
    background: var(--bg-panel); border: 1px solid var(--line);
    border-radius: var(--radius-lg); box-shadow: var(--shadow);
  }
  .topline.command-bar > .cmd.pane {
    grid-area: search; order: initial; flex: 1 1 auto; min-width: 0; min-height: 46px;
    padding: 0 7px 0 12px; border-top: 0;
    background: var(--bg-panel); border: 1px solid var(--line);
    border-radius: var(--radius-lg); box-shadow: var(--shadow);
  }
  .topline.command-bar > .cmd.pane:focus-within {
    border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-dim), var(--shadow);
  }
  .cmd-submit { border-radius: 999px; }
  .cmd-drop {
    top: calc(100% + 6px); padding: 8px 9px 7px;
    border-radius: var(--radius-lg);
  }
  .jump-intents { gap: 3px; margin-bottom: 8px; }
  .jump-intents button { flex: 1; padding: 8px 7px; text-align: center; white-space: nowrap; }
  .jump-examples { gap: 5px; }
  .jump-examples button { padding: 7px 9px; }

  /* The feed marker uses the same quiet rail treatment on every viewport; the
     phone only changes its dimensions to match the shorter horizontal dock. */
  .rail-foot .status-dot {
    box-sizing: border-box; width: 34px; height: 44px; flex: none;
    justify-content: center; gap: 0; border-radius: 10px;
  }

  /* The scrubber moves to the top on a phone. It used to sit at the bottom
     under both sheets, so opening a flight - the other thing a visitor wants
     open - covered the clock completely, and the site's headline claim became
     unreachable the moment you took it up on it. */
  .timebar {
    top: calc(var(--gap) + var(--top-h) + 8px);
    left: var(--gap); right: var(--gap); bottom: auto;
    height: 40px;
  }
  .map-readout { display: none; }
  .routes-clear { bottom: auto; top: calc(var(--gap) + var(--top-h) + 56px); }

  /* Above the sheet's peek, not under it: the strip is how you get the map
     back to the whole world, which is exactly what you want when a sheet is
     covering the bottom of it. */
  /* 22px is the shut sheet's peek - the handle - and PEEK in app.js. */
  .map-tools { right: var(--gap); bottom: calc(62px + 22px + var(--gap)); height: 40px; }
  .map-layers {
    right: var(--gap); left: var(--gap); width: auto;
    bottom: calc(62px + 22px + var(--gap) + 46px);
  }
  .toast { bottom: calc(62px + 22px + var(--gap) + 52px); }

  /* A sheet with a peek rather than a drawer behind a hamburger. The list was
     the only object in the product with no place at all on a phone. */
  .sidebar {
    left: 0; right: 0; width: auto;
    top: auto; bottom: 62px;
    height: min(72vh, 620px);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: 0;
    transform: translateY(calc(100% - 22px));
    transition: transform 0.26s cubic-bezier(0.32, 0.72, 0, 1);
    z-index: 28;
  }
  .sidebar.is-open { transform: none; }
  /* is-shut belongs to the wide layout, where it hides the card. Here the same
     element is the sheet, and hiding it would leave the tab bar with nothing to
     open. app.js drops the class on the way down to this layout, but a resize
     event is not something to stake a stuck sheet on - a window that never
     fires one, or fires it before the media query has flipped, would strand
     it - so the class is made harmless here instead of merely unlikely. */
  .sidebar.is-shut { display: flex; }

  /* The handle is the grab bar and the toggle at once, and it is what the
     aria-expanded on the sheet is attached to.

     Just the pill now. It used to be 56px with the word under it - CLOSE, or
     the tab's name - and the owner asked for the space back. The word went;
     the pill is the universal "pull me" sign and does the telling on its own,
     and the label still lives in data-label for the screen reader's sake.
     22px keeps it a comfortable thumb target (the whole width is the
     handle) while giving back 34 of the 56. */
  .menu-btn {
    display: block;
    width: 100%; height: 22px;
    background: none; border: 0;
    cursor: pointer;
    flex: none;
  }
  .menu-btn span {
    display: block; width: 42px; height: 4px; margin: 9px auto 0;
    border-radius: 999px; background: var(--line);
  }

  .detail {
    left: 0; right: 0; width: auto;
    top: auto; bottom: 62px;
    height: min(74vh, 640px);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: 0;
    z-index: 29;
  }
}

@media (max-width: 560px) {
  .units-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .units-set:last-child .units-opt { margin-right: 10px; }
  .brand-text small { font-size: 9px; letter-spacing: 0.06em; }
  .chip-value { font-size: 12px; }
  .tool-word { display: none; }
  .tool-layers { padding: 0 9px; }
}

/* Coarse pointers need bigger hit targets and no hover-only affordances. */
@media (pointer: coarse) {
  .tool, .rail-btn { width: 42px; height: 42px; }
  .tool-layers { width: auto; }
  .row { padding: 13px 14px; }
  .ap-row { padding: 13px 14px; }
  .link-btn { min-height: 24px; padding: 5px 0; }
  .layers-clear { min-height: 24px; }
  .layer { padding: 7px 12px; }
  /* Safari zooms the page in on any field whose text is under 16px, and does
     not zoom out again afterwards - one tap on the search box and the map is
     left hanging off the side of the screen. */
  .search input, .field select { font-size: 16px; }
  .tb-live { min-height: 26px; }
  #tb-range { height: 26px; }
  .site-footer-nav a,
  .site-footer-nav button { min-height: 24px; padding: 5px 0; }
  .bar-link { min-height: 24px; }
  .record { min-height: 44px; }
  .ms-clear, .ms-undo { min-height: 24px; padding: 5px 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* The card used to sit in the bottom-left corner of a stage that had a list
   docked beside it. The stage is the whole window now, so that corner is
   underneath the list rather than beside it. It goes in the clear band the
   map keeps between the two cards, and above them, because a first-run note
   that opens behind something is a first-run note nobody reads. */
.welcome {
  left: auto; bottom: calc(var(--gap) + var(--dock-h) + 14px);
  right: calc(var(--gap) + var(--detail-w) + 24px);
  z-index: 33;
  width: min(340px, 32vw);
  border-color: var(--accent-dim);
  border-radius: var(--radius-lg);
}
@media (max-width: 1000px) {
  .welcome {
    left: var(--gap); right: var(--gap);
    bottom: calc(62px + 22px + var(--gap) + 46px);
    width: auto;
  }
}

/* -------------------------------------------------------------- the deck

   The cards used to hang off a measured custom property, which meant that at
   any width where the top row wrapped they spent a frame - and on first paint,
   longer - starting underneath the part that had just wrapped. The row is in
   normal flow now and the cards sit in the grid row below it, so where the row
   ends is where they begin, with nothing to measure and nothing to be late. */
.layout {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-columns: minmax(0, 1fr);
}
.stage { grid-area: 1 / 1 / -1 / -1; }
.topline {
  position: relative; grid-row: 1;
  top: auto; left: auto; right: auto;
  padding: var(--gap) var(--gap) 0 calc(var(--rail-w) + var(--gap));
}
.layout > .topline.command-bar {
  margin-left: calc(var(--rail-w) + var(--gap)); margin-right: var(--gap);
  padding: 7px;
}
.deck { position: relative; grid-row: 2; z-index: 1; }

/* Now measured from the deck rather than from the window, so the top offsets
   are a plain margin off the row above. */
.sidebar { top: 10px; bottom: calc(var(--gap) + var(--dock-h) + 10px); }
.detail  { top: 10px; bottom: calc(var(--gap) + var(--dock-h) + 10px); }

@media (max-width: 1000px) {
  .topline { padding: var(--gap) var(--gap) 0; }
  .layout > .topline.command-bar {
    margin-left: var(--gap); margin-right: var(--gap); padding: 6px;
  }
  /* The scrubber is the first thing under the top row on a phone, so it is the
     top of the deck rather than an offset from a measurement. */
  .timebar { top: 8px; }
  .routes-clear { top: 56px; }
  .sidebar, .detail { top: auto; }
}

/* Glass is the whole idea, but it is also the one expensive thing here: a
   blurred backdrop over a canvas that is redrawing every frame has to be
   re-blurred every frame, and two of these panels are 372 by 750. Anyone who
   has asked their system for less transparency - because it costs them frames,
   or because moving traffic behind text is hard to read - gets solid panels
   and the same layout. */
@media (prefers-reduced-transparency: reduce) {
  .pane, .sidebar, .detail, .map-tools, .map-layers, .timebar, .map-readout,
  .welcome, .routes-clear, .tooltip, .rail {
    background: var(--bg-solid);
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
}

@media (max-width: 1000px) {
  /* Both sheets stop below the scrubber rather than being given a height and
     allowed to land wherever that puts their top edge. A 74vh detail sheet
     covered the clock on a 844px screen, which is the fault this layout set
     out to fix: the two things a visitor wants open at once are a flight and
     the clock that moves it. Bounding them by top and bottom instead of by
     height makes that structural rather than arithmetical. */
  .sidebar, .detail {
    /* Measured by app.js from the bar itself, which is two rows tall now. */
    top: 96px;
    bottom: 62px;         /* clear of the tab bar */
    height: auto;
  }
}

/* ------------------------------------------------- the dock, read properly

   Two things went wrong when the layer row was folded away. The projection
   went with it, and it is not a layer - it is the ground the layers are drawn
   on, and it was the one control on the map that named both of its states.
   And the button that was left looked exactly like the zoom keys beside it,
   so it read as another instant action rather than as something that opens. */

/* Back on the map, in its own enclosure, both states named. */
.map-tools .proj {
  flex: none;
  display: flex; gap: 3px;
  padding: 3px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 9px;
}
.map-tools .proj button {
  padding: 4px 10px;
  background: none; border: 0; border-radius: 6px;
  color: var(--text-faint); cursor: pointer;
  font: inherit; font-size: 11px; letter-spacing: 0.04em;
  transition: color 0.15s, background 0.15s;
}
.map-tools .proj button:hover { color: var(--text-dim); }
.map-tools .proj button[aria-checked="true"] { background: var(--accent); color: var(--brand-ink); }

/* A raised face and a caret, so it reads as a door rather than a switch. */
.tool-layers {
  background: var(--bg-raised);
  border-color: var(--line);
  color: var(--text-dim);
  padding: 0 9px 0 11px;
}
.tool-layers:hover { border-color: var(--accent-dim); background: var(--bg-hover); }
.tool-ic { width: 16px; height: 16px; }
.tool-caret { width: 11px; height: 11px; opacity: 0.7; transition: transform 0.18s; }
.tool-layers[aria-expanded="true"] .tool-caret { transform: rotate(180deg); }
.tool-layers[aria-expanded="true"] {
  color: var(--accent); border-color: var(--accent-dim); background: var(--bg-hover);
}

.map-layers { width: 286px; }
.layers-head { margin-bottom: 2px; }

/* Pinch and double-tap already zoom, and on a phone the two keys were the
   widest thing in a strip that also has to hold the projection pair and the
   layers door. */
@media (pointer: coarse) {
  #zoom-in, #zoom-out { display: none; }
}
@media (max-width: 560px) {
  /* The word goes before the count does: the count is the part that says
     something the icon cannot. */
  .tool-word { display: none; }
  .map-tools .proj button { padding: 4px 8px; font-size: 10.5px; }
  .tool-layers { padding: 0 7px 0 9px; gap: 5px; }
}

/* The strip is pinned to the right, so when it outgrows the screen it grows
   off the LEFT of it - silently, because nothing scrolls and nothing wraps.
   Adding the locate button spent the last of the room: at 360px the strip
   needed 388 and had 336, so it started 40px off-screen and "fit the whole
   world" was three quarters gone. Reported from a phone, which is the only
   place it happens.

   The dice goes, on the same reasoning that already took the zoom keys here:
   when the strip runs out of room the least necessary control leaves, and
   jumping to a random aircraft is the one thing in the strip that is a
   diversion rather than a control. Not the fit button - now that locate can
   take you somewhere far away, one tap back to the whole world matters more
   than it did.

   Then a little off the gaps and the padding, because dropping the dice alone
   left it six pixels over. */
@media (max-width: 420px) {
  #surprise { display: none; }
  .map-tools { gap: 3px; padding: 0 4px; }
}

/* The deck is a full-width layer with nothing in most of it, and an element
   with nothing in it still answers the mouse. It was taking every click, drag
   and pinch meant for the map underneath: no aircraft could be selected, and
   the globe could not be turned. Only the cards on the deck are there to be
   touched; the deck itself is a place to put them.

   The tooltip is excepted rather than included - it follows the pointer, and a
   thing that follows the pointer must never be under it. */
.deck { pointer-events: none; }
.deck > *:not(.tooltip) { pointer-events: auto; }

/* The clock can be run faster than the world. The button says which speed it
   is on rather than only that it is on, because the difference between a
   minute a second and half an hour a second is the difference between watching
   a flight land and watching a day go by. */
.tb-play {
  flex: none;
  display: flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 8px;
  background: none;
  border: 1px solid var(--line); border-radius: 999px;
  color: var(--text-faint); cursor: pointer;
  font: inherit; font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.tb-play-ic { width: 11px; height: 11px; }
.tb-play:hover { color: var(--accent); border-color: var(--accent-dim); }
.tb-play.is-on {
  background: var(--amber); border-color: var(--amber); color: var(--brand-ink);
}

/* The clock runs both ways. Two buttons rather than one with a direction
   switch: which way it is about to go should be readable without pressing
   anything, and the speed rides on whichever one is running. */
.tb-transport { flex: none; display: flex; align-items: center; gap: 4px; }
.tb-back { padding: 4px 8px; }
.tb-back .tb-play-ic { margin: 0; }
.tb-back.has-label { padding: 4px 10px 4px 8px; }
.tb-back.has-label #tb-back-label {
  position: static; width: auto; height: auto; margin: 0;
  clip-path: none; white-space: nowrap;
}

/* The handle owns its gesture. Without this the browser reads a drag down the
   sheet as a scroll of the list inside it, takes the pointer away mid-gesture
   and the sheet never hears that anything happened - which is exactly how a
   swipe-to-close comes to do nothing at all. */
.menu-btn { touch-action: none; }

/* The transport pair was 27px by 21 on a phone: below the floor for a thumb,
   and the rewind is the smaller of the two because it carries no word. Play
   got pressed and rewind got missed, which reads as rewind being broken. */
@media (pointer: coarse) {
  .tb-play, .tb-back { min-height: 36px; padding: 6px 12px; }
  .tb-back { min-width: 44px; justify-content: center; }
  .tb-live { min-height: 32px; }
}

/* --------------------------------------------------------------- day strip

   The clock reaches three days either way now, and the reach could not come
   from the track: six days across a phone's 86 pixels is ninety minutes to
   the pixel. The day is a separate question from the hour, so it gets its own
   row and the scrubber goes back to covering one day. */
.timebar {
  flex-direction: column; align-items: stretch;
  height: auto; gap: 7px;
  padding: 9px 12px 11px;
}
.tb-row { display: flex; align-items: center; gap: 12px; }

.tb-days { display: flex; gap: 3px; }
.tb-day {
  flex: 1; min-width: 0;
  padding: 4px 2px 5px;
  background: none; border: 1px solid transparent; border-radius: 9px;
  color: var(--text-faint); cursor: pointer;
  font: inherit; line-height: 1.15; text-align: center;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.tb-day b {
  display: block;
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em;
}
.tb-day span {
  display: block; margin-top: 1px;
  font-family: var(--mono); font-size: 9.5px; opacity: 0.85;
  white-space: nowrap;
}
.tb-day:hover { color: var(--text-dim); border-color: var(--line); }
.tb-day.is-on { background: var(--accent); border-color: var(--accent); color: var(--brand-ink); }
/* Today is the one day that is not just a date, and it says so without
   needing to be selected to do it. */
.tb-day.is-today b::after { content: ' •'; color: var(--amber); }
.tb-day.is-on.is-today b::after { color: var(--brand-ink); }

@media (max-width: 1000px) {
  /* Initials and a number: seven days across a phone is 52px each, which is a
     day of the week only if you spell it in one letter. */
  .timebar { height: auto; padding: 7px 9px 9px; gap: 5px; }
  .tb-day { padding: 3px 1px 4px; }
  .tb-day b { font-size: 11px; }
  .tb-day span { font-size: 9px; }
}
@media (max-width: 430px) {
  .tb-day b { font-size: 10.5px; }
  .tb-day span { font-size: 8.5px; }
}
@media (pointer: coarse) {
  .tb-day { min-height: 34px; }
}

/* The one layer that is not about the simulation, marked as such in the row.
   It borrows the amber the map draws real traffic in, so the switch and the
   thing it switches on are recognisably the same subject. */
.layer-real[aria-pressed="true"] {
  border-color: var(--amber);
  color: var(--amber);
}
#readout-real { color: var(--amber); }
/* Past the reckoning cap the picture is held rather than live, and the
   readout is the only thing that says so - so it stops looking like the rest
   of the furniture. */
#readout-real.is-stale { color: var(--danger); font-weight: 500; }

/* A number that cannot be known from a position report. Dimmed and inert
   rather than hidden, because a chip that disappears looks like a bug and a
   chip that is visibly unavailable looks like an answer. */
.chip.is-unknown { opacity: 0.45; cursor: default; }
.chip.is-unknown .chip-value { letter-spacing: 0.1em; }

/* A live row carries no route, so it has no progress bar and no arrow pair.
   The pill says why, in the same place the simulated rows put their status. */
.pill.s-live { color: var(--amber); border-color: currentColor; }
.row-real .row-said { opacity: 0.85; }

/* The real-flight panel. Two ends and the distance between them, which is the
   shape a passenger already has in their head from a boarding pass. */
.realflight { padding: 4px 2px 8px; }
.rf-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.rf-top h2 { margin: 0; font-size: 26px; letter-spacing: -0.01em; }
.rf-airline { color: var(--text-faint); }
.rf-legs { display: grid; grid-template-columns: 1fr auto 1fr; gap: 14px; align-items: center; }
.rf-side-head { font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-faint); }
.rf-iata { font-size: 30px; font-weight: 600; letter-spacing: 0.02em; line-height: 1.1; }
.rf-place { color: var(--text-faint); font-size: 14px; margin-bottom: 8px; }
.rf-times { display: flex; align-items: baseline; gap: 8px; font-variant-numeric: tabular-nums; }
.rf-sched { font-size: 20px; }
/* A revised time never replaces the scheduled one: the gap between them is
   the thing somebody came to look at. */
.rf-sched.is-was { text-decoration: line-through; opacity: 0.55; font-size: 16px; }
.rf-rev { font-size: 20px; color: var(--amber); }
.rf-z { font-size: 11px; color: var(--text-faint); }
.rf-gate { display: flex; flex-direction: column; gap: 2px; margin-top: 8px;
           font-size: 13px; color: var(--text-faint); }
.rf-gate i { opacity: 0.7; font-style: italic; }
.rf-mid { color: var(--text-faint); font-size: 13px; text-align: center; white-space: nowrap; }
.rf-meta { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 16px;
           font-size: 13px; color: var(--text-faint); }
.rf-source { margin-top: 14px; font-size: 12px; color: var(--text-faint); max-width: 60ch; }
@media (max-width: 560px) {
  .rf-legs { grid-template-columns: 1fr; }
  .rf-mid { text-align: left; }
}

/* The carrier rows. Same grammar as the airport rows beside them: a mark, a
   name that wraps, and one hard fact right-aligned. */
/* The carrier row is the airport row (.ap-row, above) with a mark where the
   code goes: same padding, same hairline, same two sizes of text, same plain
   figure on the right. Two lists that sit under neighbouring tabs should
   read as one list, and they did not - the carriers were 76px rows with a
   third line and a labelled count while the airports were 44px rows with
   neither. The rules are written out rather than shared with .ap-row so that
   a change to one list is a decision about that list. */
.al-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: stretch;
  gap: 8px; width: 100%; padding: 7px 14px;
}
.al-entry { border-bottom: 1px solid var(--line-soft); }
.al-entry:last-child { border-bottom: 0; }
/* The previous highlight lived on only the name button, leaving the separate
   live count white. Mark the whole entry so the row and its answer read as one. */
.al-entry.is-open { background: var(--bg-raised); box-shadow: inset 3px 0 0 var(--accent); }
.al-entry:not(.is-open) .al-row:hover { background: var(--bg-hover); }
.al-expand {
  display: flex; align-items: center; gap: 10px; min-width: 0; width: 100%; padding: 3px 0;
  border: 0; background: transparent; color: inherit; text-align: left; cursor: pointer; font: inherit;
}
.al-expand:hover, .al-expand[aria-expanded="true"] { background: transparent; }
.al-expand-glyph { flex: none; }
.al-load {
  display: flex; flex-direction: column; align-items: flex-end; justify-content: center;
  min-width: 42px; padding: 3px 0 3px 5px; border: 0; background: transparent;
  color: var(--text-dim); text-align: right; cursor: pointer; font: inherit;
}
.al-load:hover strong { color: var(--accent); }
.al-load strong { color: var(--text); font-family: var(--mono); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.al-load small { color: var(--text-faint); font-size: 10px; }
/* The directory scrolls with a mouse drag on desktop. Keep its buttons as
   buttons: a short press opens a carrier, while a pull moves the list. */
@media (pointer: fine) {
  #airline-list .al-row { cursor: grab; }
  #airline-list.is-dragging { user-select: none; }
  #airline-list.is-dragging .al-row { cursor: grabbing; }
}
/* One line, not two: "American Airlines - United States". The owner's
   call after seeing it stacked. Same sizes as the airport row, just side by
   side, and the dash is drawn by the country so a carrier without one gets
   no dangling dash. */
.al-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.al-text strong { max-width: 100%; font-size: 12.5px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.al-text .al-hub { max-width: 100%; color: var(--text-faint); font-size: 10.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.al-text .al-hub b { color: var(--accent); font-weight: 500; }
/* The old logo-width indent squeezed three actions into tiny columns. Facts
   and actions now use the same full row width as the aircraft answer. */
.al-expanded { padding: 2px 17px 12px; }
.al-expanded[hidden] { display: none; }
.al-fact { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; min-height: 34px; padding: 7px 0; border-bottom: 1px solid var(--line-soft); }
.al-fact > span { flex: none; color: var(--text-faint); font-size: 10.5px; }
.al-fact > button { min-width: 0; border: 0; background: none; color: var(--accent); text-align: right; cursor: pointer; font: inherit; font-size: 11.5px; }
.al-fact > button:hover { text-decoration: underline; }
.al-fact > strong { min-width: 0; color: var(--text); text-align: right; font-size: 11.5px; font-weight: 500; }
.al-no-aircraft { margin: 0; padding: 8px 0; color: var(--text-faint); font-size: 11px; }
.al-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px; padding-top: 9px; }
.al-actions.is-two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.al-actions button { min-height: 34px; padding: 6px 8px; border-radius: 6px; font: inherit; font-size: 10.5px; font-weight: 600; cursor: pointer; }
.al-primary { border: 1px solid var(--accent); background: var(--accent); color: var(--brand-ink); }
.al-primary:hover { background: var(--accent-dim); }
.al-secondary { border: 1px solid var(--line); background: var(--bg-raised); color: var(--text); }
.al-secondary:hover, .al-secondary[aria-expanded="true"] { border-color: var(--accent-dim); color: var(--accent); }
/* Route rows use the same quiet two-line rhythm as Airlines. The pair leads;
   its city names make the codes readable, and only the current feed is counted. */
.route-entry { border-bottom: 1px solid var(--line-soft); }
.route-entry.is-open { background: var(--bg-raised); box-shadow: inset 3px 0 0 var(--accent); }
.route-row {
  display: grid; grid-template-columns: 23px minmax(0, 1fr) auto; align-items: center; gap: 10px;
  width: 100%; min-height: 52px; padding: 7px 14px;
  border: 0; background: transparent; color: var(--text); text-align: left;
  font: inherit; cursor: pointer;
}
.route-row:hover, .route-row:focus-visible { background: var(--bg-hover); }
.route-expand-glyph {
  display: grid; place-items: center; width: 22px; height: 22px;
  border: 1px solid var(--line); border-radius: 5px;
  color: var(--accent); font-size: 15px; line-height: 1;
}
.route-entry.is-open .route-expand-glyph { background: var(--accent); color: var(--brand-ink); border-color: var(--accent); }
.route-identity { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.route-identity strong, .route-identity small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.route-identity strong { font-size: 12.5px; font-weight: 600; }
.route-identity strong span { color: var(--accent); font-weight: 400; }
.route-identity small { color: var(--text-faint); font-size: 10.5px; }
.route-count { display: flex; flex-direction: column; align-items: flex-end; }
.route-count strong { font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums; }
.route-count small { color: var(--text-faint); font-size: 10px; }
.route-inline { padding: 0 16px 12px 47px; }
.route-inline[hidden] { display: none; }
.route-summary { display: flex; justify-content: space-between; gap: 8px; padding: 7px 0;
  border-bottom: 1px solid var(--line-soft); color: var(--text-dim); font-size: 10.5px; }
.route-summary strong { color: var(--text); }
.route-operators h3 { margin: 11px 0 5px; color: var(--text-faint); font-size: 10px;
  font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.route-operator { display: flex; justify-content: space-between; gap: 10px; width: 100%;
  min-height: 33px; align-items: center; padding: 5px 0; border: 0; border-bottom: 1px solid var(--line-soft);
  background: transparent; color: var(--accent); text-align: left; font: inherit; font-size: 11px; cursor: pointer; }
.route-operator:hover span { text-decoration: underline; }
.route-operator strong { color: var(--text-dim); font-family: var(--mono); font-size: 10px; font-weight: 500; }
.route-flights { width: 100%; min-height: 35px; margin-top: 10px; border: 1px solid var(--accent);
  border-radius: 6px; background: var(--accent); color: var(--brand-ink);
  font: inherit; font-size: 11px; font-weight: 600; cursor: pointer; }
.route-flights:hover { background: var(--accent-dim); }
@media (max-width: 1000px) {
  .route-row, .route-operator, .route-flights { min-height: 44px; }
}
/* tabular-nums because these are read down a column and ragged digits make a
   ranked list look unranked. */
.al-load { font-family: var(--mono); font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* A heading over a run of rows. Sticky, because the whole point of the group
   is knowing which one you are reading, and a heading that scrolls away takes
   that with it. */
.al-group {
  position: sticky; top: 0; z-index: 1;
  padding: 7px 14px;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--line);
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint);
}

/* A real logo, laid over the generated tile rather than replacing it.
   It is invisible until it has actually loaded, so a carrier the logo service
   does not have shows the tile and nothing flickers. */
.mark-slot { position: relative; overflow: hidden; }
/* No background of its own. It carried background: #fff - a colour literal,
   which this stylesheet does not otherwise contain - to guarantee contrast for
   a logo with a transparent background. None of them have one: all ten sampled
   are fully opaque. So the white was never protecting anything and was only
   ever visible in the gap the letterboxing left. Anything that does arrive
   transparent now falls through to the generated tile behind it, which is a
   mid-lightness colour chosen for exactly that job. */
.mark-over {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; opacity: 0;
  transition: opacity .18s ease;
}
.mark-over.is-on { opacity: 1; }

/* --------------------------------------------------- the foot of a phone */

/* Eight tabs have to share a narrow phone bar. The icons alone
   fit but leave a new visitor guessing what a route or airport symbol means.
   Shorter glyphs and tighter words keep every destination named without
   pushing the units cog or theme switch off the edge.

   Top level rather than nested inside the 1000px block, which is where this
   started. Nested it parsed as a sibling with half its rules missing, and the
   labels stayed. */
@media (max-width: 430px) {
  .rail { padding: 0 4px; }
  .rail .tab { min-width: 0; height: 46px; max-width: none; }
  .rail .tabs { gap: 0; }
  .rail-ic { width: 16px; height: 16px; }
  .rail .rail-btn { width: 30px; }
  .rail-label { display: block; font-size: 6.5px; letter-spacing: 0; white-space: nowrap; }
}

/* Five board columns need more width than a phone has. Each movement becomes
   a small card instead of asking the visitor to scroll sideways for its gate. */
@media (max-width: 560px) {
  .airport-board-table,
  .airport-board-table tbody { display: block; width: 100%; }
  .airport-board-table thead { display: none; }
  .airport-board-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 7px 12px;
    margin-bottom: 8px;
    padding: 9px 11px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--bg-panel);
  }
  .airport-board-table td,
  .airport-board-table td:nth-child(1),
  .airport-board-table td:nth-child(2),
  .airport-board-table td:nth-child(4) {
    display: block;
    min-width: 0;
    padding: 0;
    border: 0;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .airport-board-table td:nth-child(3),
  .airport-board-table td[colspan] { grid-column: 1 / -1; }
  .airport-board-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 3px;
    color: var(--text-faint);
    font: 9px var(--sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
}

/* ------------------------------------------------------------ front door
 *
 * A sheet over the map, shown once, asking one question. It rides on
 * .board-overlay so it is centred on a desktop and near-full on a phone
 * without a second set of positioning rules, and so it closes by the same
 * gestures every other panel here closes by.
 *
 * Narrower than a board on purpose: .board-inner is min(920px, 100%) because a
 * board is a table of departures, and this is four rows and a question. At 920
 * the rows become long thin bars with the text stranded on the left. */
.start-inner {
  width: min(460px, 100%);
  padding: 14px 16px 18px;
  gap: 0;
  /* Opaque, where a board is translucent glass.
   *
   * .board-inner uses --bg-raised, which is rgba(19,45,52,.72), and that is
   * right for a panel floating in the middle of a moving map. This one meets
   * the bottom edge of a phone, where the app's own icon dock lives - and the
   * dock showed straight through it, icons and all, under the skip link.
   * --bg-solid is the one surface token declared opaque in both themes. */
  background: var(--bg-solid);
}
/* The grab handle from the compact sheet, kept on every width. It is the one
   part of this that says "this moves out of the way", which is the thing a
   first-time visitor most needs to know about it. */
.start-grip {
  width: 38px;
  height: 4px;
  border-radius: 99px;
  background: var(--line);
  margin: 0 auto 14px;
}
.start-ask {
  margin: 4px 0 14px;
  font-size: 21px;
  line-height: 1.2;
  font-weight: 650;
  letter-spacing: -0.022em;
  text-wrap: balance;
}
.start-ask span { color: var(--accent); }

.start-rows { display: flex; flex-direction: column; gap: 7px; }
.start-row {
  display: grid;
  grid-template-columns: 30px 1fr auto;
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--bg-raised);
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.start-row:hover, .start-row:focus-visible {
  border-color: var(--accent-dim);
  background: var(--bg-hover);
}
.start-ic {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: var(--bg-panel);
  font-size: 13px;
  color: var(--accent);
}
.start-tx { font-size: 14px; min-width: 0; }
.start-tx em {
  display: block;
  font-style: normal;
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.start-go { color: var(--text-faint); font-family: var(--mono); font-size: 12px; }

.start-skip { margin: 16px 0 0; text-align: center; }
.start-skip .link-inline { font-size: 12.5px; color: var(--text-dim); }

/* On a phone it is a sheet rather than a card: it meets the bottom edge, where
   a thumb already is, and the rounded top is the only corner that shows. */
@media (max-width: 560px) {
  .start-overlay { place-items: end center; padding: 0; }
  .start-inner {
    width: 100%;
    border-radius: 18px 18px 0 0;
    padding: 12px 14px 22px;
    max-height: 86%;
  }
  .start-ask { font-size: 19px; }
}

/* ------------------------------------------------------ route-led refresh

   The map has always been the strongest part of FlyGamma. A wider, named rail
   gives every section a clear way in; the lists stay beside the map, while a
   selected flight becomes a wide lower sheet so its route remains visible.
   These are placement rules on the existing components, not a second UI with
   new data or a second set of navigation handlers. */

.section-heading {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 21px 18px 7px;
}
.section-heading h2 {
  margin: 0; color: var(--text); font-size: 23px; font-weight: 650;
  letter-spacing: -0.035em; line-height: 1.1;
}
.section-heading span { color: var(--text-faint); font-size: 11px; white-space: nowrap; }
.panel > .search { padding: 9px 16px 12px; }
.panel > .search input { min-height: 43px; padding: 10px 13px; font-size: 13px; }
/* These one-line lists had 13px of air above and below each entry, making a
   six-item panel look full while hiding the next choices. A 44px target still
   leaves room for the 26px airline logo and for a finger to select a row. */
.al-row, .ap-row { padding: 6px 17px; min-height: 44px; }
.al-text strong, .ap-name strong { font-size: 13.5px; }
.al-text span, .ap-name span { font-size: 11px; }
.al-load, .ap-load { font-size: 12px; }
.al-group { padding-left: 17px; }

/* When there are no saved flights, or the supplier cannot answer, hide
   narrowing chips that cannot help. The search stays in its usual place so
   the three directory panels keep the same shape. */
#panel-flights:is(.is-empty-watch, .is-feed-unavailable) > :is(
  .filters, .chip-row, .filter-map-key
) { display: none !important; }
#panel-flights:is(.is-empty-watch, .is-feed-unavailable) .list {
  flex: 0 0 auto; margin: 13px 16px; overflow: visible;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--bg-raised);
}
#panel-flights:is(.is-empty-watch, .is-feed-unavailable) .empty {
  padding: 44px 28px; color: var(--text-dim); font-size: 13px;
}
#panel-flights.is-empty-watch .empty::before {
  content: "☆"; display: block; margin-bottom: 15px;
  color: var(--saved); font-size: 34px; line-height: 1;
}
#panel-flights.is-feed-unavailable:not(.is-empty-watch) .empty::before {
  content: "✈"; display: block; margin-bottom: 15px;
  color: var(--accent); font-size: 30px; line-height: 1;
}

.map-context {
  position: absolute; z-index: 5; top: 18px; right: var(--gap);
  max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 8px 13px; border: 1px solid var(--line);
  border-radius: 999px; background: var(--bg-panel);
  box-shadow: var(--shadow); color: var(--text-dim); font-size: 11px;
  pointer-events: none;
}
/* A collapsed Flights sheet hides its own key. Keep one compact explanation on
   the map then, especially on a phone where the sheet starts closed. */
.filter-map-badge {
  display: none; position: absolute; z-index: 18; top: 12px; left: 12px;
  max-width: calc(100% - 108px); flex-direction: column; gap: 3px;
  padding: 7px 10px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-solid); box-shadow: var(--shadow);
  color: var(--text-dim); font-size: 10px; pointer-events: none;
}
.filter-map-badge > * { display: flex; align-items: center; gap: 5px; }
.filter-map-badge strong { color: var(--text); font-size: 12px; overflow-wrap: anywhere; }
.filter-map-badge > span { white-space: nowrap; }
.filter-map-badge i { width: 8px; height: 8px; flex: none; border-radius: 50%; }
.deck:has(.sidebar.is-shut) .filter-map-badge:not([hidden]) { display: flex; }
.map-near { display: none; }
.file-preview-warning {
  position: fixed; z-index: 1000; left: 50%; top: 13px;
  width: min(720px, calc(100vw - 30px)); transform: translateX(-50%);
  padding: 12px 16px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--bg-solid);
  box-shadow: var(--shadow); color: var(--text); text-align: center;
  font-size: 13px; line-height: 1.45;
}
.layout.has-detail .map-context { display: none; }
@media (max-width: 700px) {
  .filter-map-badge:not([hidden]) { display: flex; }
  /* Location is the useful phone shortcut. It used to be buried in Layers,
     leaving the world fallback looking permanent when permission was missed. */
  .layout .map-context { display: none; }
  .map-near {
    position: absolute; z-index: 18; top: 12px; right: 12px;
    display: inline-flex; align-items: center; min-height: 36px;
    padding: 7px 12px; border: 1px solid var(--line);
    border-radius: 999px; background: var(--bg-solid);
    box-shadow: var(--shadow); color: var(--accent);
    font: inherit; font-size: 12px; cursor: pointer;
  }
  .map-near:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
  .map-near:disabled { opacity: .6; cursor: wait; }
  .layout.has-detail .map-near { display: none; }
}

/* A real route chooser uses only airport directory data. Until a partner
   supplies a quote, the main action is a search, not a fabricated fare. */
.travel-fields {
  display: grid; grid-template-columns: minmax(0, 1fr) 42px minmax(0, 1fr); gap: 5px 10px;
  padding: 10px 16px 18px;
}
.travel-fields label { color: var(--text-faint); font-size: 11px; }
.travel-fields label[for="travel-q"] { grid-column: 3; grid-row: 1; }
.travel-fields input {
  min-width: 0; width: 100%; min-height: 46px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-raised); color: var(--text); font: inherit; font-size: 13px;
}
.travel-fields input::placeholder { color: var(--text-faint); }
.travel-fields input:focus { border-color: var(--accent-dim); }
.travel-fields #travel-from { grid-column: 1; grid-row: 2; }
.travel-fields #travel-q { grid-column: 3; grid-row: 2; }
.travel-swap {
  grid-column: 2; grid-row: 2; min-width: 0; min-height: 46px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-raised); color: var(--accent); font-size: 22px;
  cursor: pointer;
}
.travel-swap:disabled { opacity: .45; cursor: default; }
.travel-swap:not(:disabled):hover { border-color: var(--accent); }
.travel-find {
  grid-column: 1 / -1; display: block; margin-top: 9px; padding: 13px;
  border-radius: var(--radius); background: var(--accent);
  color: var(--brand-ink); text-decoration: none; text-align: center;
  font-weight: 650; font-size: 13px;
}
.travel-find[hidden] { display: none; }
.travel-find:hover { background: var(--accent-dim); }
.travel-empty { margin: 15px 16px; padding: 26px 15px; border: 1px solid var(--line);
  border-radius: var(--radius-lg); background: var(--bg-raised); text-align: center; }
.travel-empty-line { display: flex; align-items: center; justify-content: center; gap: 12px;
  color: var(--accent); font-family: var(--mono); font-size: 17px; }
.travel-empty-line i { width: 65px; border-top: 2px dashed var(--line); }
.travel-empty p { margin: 12px 0 0; color: var(--text-dim); font-size: 12px; }
.travel-intro { margin: 4px 16px 14px; padding: 16px; border: 1px solid var(--line);
  border-radius: var(--radius-lg); background: var(--bg-raised); }
.travel-intro-kicker { color: var(--text-faint); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; }
.travel-intro-route { display: grid; grid-template-columns: 1fr 50px 1fr;
  align-items: center; gap: 10px; margin-top: 12px; }
.travel-intro-route > div { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.travel-intro-route > div:last-child { text-align: right; }
.travel-intro-route b { color: var(--text); font-family: var(--mono); font-size: 24px; }
.travel-intro-route small { color: var(--text-dim); font-size: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.travel-intro-route > span { color: var(--accent); text-align: center; font-size: 23px; }
.travel-intro p { margin: 14px 0 0; padding-top: 11px; border-top: 1px solid var(--line);
  color: var(--text-dim); font-size: 12px; }
.travel-match { padding: 12px 16px; min-height: 54px; }
.travel-match span { font-size: 13px; }
.travel-match small { font-size: 11px; }

/* --------------------------------------------------------------- Signature

   Navigation belongs in the header; flight browsing and the selected flight
   flank the map. Both cards can get out of the way without losing filters or
   a selection. The same elements become sheets on a phone, so there is only
   one search, one set of tabs and one set of handlers to keep working. */
:root {
  --rail-w: 0px;
  /* The 320px rail squeezed the compact route and status together. Half again
     as wide gives those fixed columns room while capping the card at 480px. */
  --sidebar-w: min(480px, 40.5vw);
  /* Match the earlier 50% widening of the flight list. The viewport cap keeps
     the map visible when both desktop panels are open. */
  --detail-w: min(525px, 43.5vw);
  --gap: 20px;
  --dock-h: 50px;
  --map-bottom-h: 64px;
  --footer-h: 42px;
  /* The highlight row wraps on narrower desks, so the list cannot use a fixed
     upward offset to meet the navbar beside it. frame.js measures this row. */
  --highlights-h: 0px;
}
/* Scale the whole desk without shortening the map. The taller body offsets
   zoom so the footer and phone navigation still meet the physical screen edge;
   a plain zoom left an empty strip below them. */
@media (min-width: 1001px) {
  @supports (zoom: .75) {
    html { zoom: .75; }
    body { height: calc(100vh / .75); }
    @supports (height: 100dvh) {
      body { height: calc(100dvh / .75); }
    }
  }
}
@media (max-width: 1000px) {
  @supports (zoom: .8) {
    html { zoom: 1; }
    body { height: 100vh; }
    @supports (height: 100dvh) {
      body { height: 100dvh; }
    }
  }
}
.layout { grid-template-rows: auto auto minmax(0, 1fr) auto; }
.layout > .topline.command-bar {
  margin: 0; padding: 15px 22px; gap: 22px;
  min-height: 78px; background: var(--bg-solid);
  border-bottom: 1px solid var(--line);
}
.topline.command-bar > .brand.pane {
  display: flex; gap: 10px; height: auto; min-height: 0;
  padding: 0; background: none; border: 0; box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.brand-mark-inline { display: block; width: 30px; height: 34px; filter: none; }
.brand-text .brand-word { width: 124px; height: 26px; }
.brand-beta { display: none; }
.topline.command-bar > .cmd.pane {
  flex: 1 1 300px; min-width: 200px; max-width: 390px; height: 44px;
  min-height: 44px; padding: 0 12px; gap: 10px;
  background: var(--bg-raised); border-radius: 10px; box-shadow: none;
}
.cmd-input { font-size: 14px; }
.cmd-submit { font-size: 12px; }
.topline > .rail {
  position: static; width: auto; height: auto; flex: 1 0 auto;
  padding: 0; gap: 15px; flex-direction: row; align-items: center;
  background: none; border: 0;
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.rail-brand { display: none; }
.rail-foot { margin: 0 0 0 auto; flex-direction: row; gap: 3px; }
.rail-foot .rail-btn { width: 33px; height: 36px; font-size: 17px; }
.rail-foot .status-dot { display: none; }
.sidebar > .tabs {
  display: flex; align-items: center; gap: 2px; flex: none;
  width: 100%; height: 46px; padding: 5px 47px 5px 10px;
  border-bottom: 1px solid var(--line-soft);
}
.sidebar > .tabs .tab {
  flex: 1; width: auto; min-width: 0; height: 34px; padding: 0 3px;
  border-radius: 8px;
}
.sidebar > .tabs .rail-ic { display: none; }
/* Eight named sections still need to fit in the 450px desk header. */
.sidebar > .tabs .rail-label { font-size: 11.5px; letter-spacing: 0; color: inherit; }
.sidebar > .tabs .tab.is-active,
.sidebar > .tabs .tab.is-active .rail-label {
  color: var(--accent);
}
.sidebar > .tabs .tab.is-active { background: var(--bg-hover); }
/* Eight destinations share one narrow header; the model name belongs in the
   Aircraft list, not in a widened nav button that would push Saved away. */
.ac-type-row {
  display: grid; grid-template-columns: 26px 49px minmax(0, 1fr) auto; align-items: center; gap: 9px;
  width: 100%; min-height: 44px; padding: 6px 15px;
  border: 0; border-bottom: 1px solid var(--line-soft);
  background: transparent; color: var(--text); text-align: left; cursor: pointer; font: inherit;
}
.ac-type-row:hover, .ac-type-row:focus-visible { background: var(--bg-hover); }
.ac-type-code { color: var(--accent); font-size: 11px; font-weight: 700; }
.ac-type-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; }
.ac-type-count { color: var(--text-dim); font-size: 11px; font-variant-numeric: tabular-nums; }
/* A 14% teal wash covered the whole expanded answer and read as a coloured
   slab on light paper. The edge already marks the chosen type, so let the
   details sit on a neutral raised surface in both themes. */
.ac-type-item.is-open { background: var(--bg-raised); box-shadow: inset 3px 0 0 var(--accent); }
.ac-type-item.is-open .ac-type-row { border-bottom-color: var(--line); }
/* The Aircraft list owns this scroller on both desk and phone. Keeping the
   answer below its row avoids hiding the list behind a second map drawer. */
.ac-type-inline { min-width: 0; padding: 3px 14px 12px; }
.ac-type-status { display: flex; align-items: baseline; gap: 8px; padding: 8px 0 7px; }
.ac-type-status .badge { margin-left: auto; flex: none; }
.ac-type-airborne {
  display: flex; align-items: baseline; gap: 7px; min-width: 0; padding: 0;
  border: 0; background: none; color: var(--text); text-align: left; cursor: pointer;
}
.ac-type-airborne strong { font: 600 25px/1 var(--mono); font-variant-numeric: tabular-nums; }
.ac-type-airborne span { color: var(--text-dim); font-size: 11px; }
.ac-type-airborne:hover strong { color: var(--accent); }
.ac-type-operators h3 {
  margin: 2px 0; color: var(--text-faint); font-size: 10px;
  font-weight: 600; letter-spacing: .09em; text-transform: uppercase;
}
.ac-type-rank {
  display: grid; grid-template-columns: 18px minmax(0, 1fr) auto;
  align-items: center; gap: 6px; width: 100%; min-height: 38px;
  padding: 5px 0; border: 0; border-bottom: 1px solid var(--line-soft);
  background: none; color: var(--accent); font: inherit; font-size: 12px;
  text-align: left; cursor: pointer;
}
.ac-type-rank:hover .ac-type-airline { text-decoration: underline; text-underline-offset: 2px; }
.ac-type-place, .ac-type-rank-count {
  color: var(--text-faint); font: 500 10px var(--mono);
  font-variant-numeric: tabular-nums;
}
.ac-type-airline { min-width: 0; overflow-wrap: anywhere; }
.ac-type-rank-count { color: var(--text-dim); text-align: right; }
.ac-type-actions { margin-top: 10px; }
.ac-type-actions button { width: 100%; min-height: 40px; padding: 6px 9px; border-radius: 6px; font: inherit; font-size: 11px; font-weight: 600; cursor: pointer; }
.ac-type-flights { border: 1px solid var(--accent); background: var(--accent); color: var(--brand-ink); }
.ac-type-flights:hover { background: var(--accent-dim); }
.ac-type-inline button:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (max-width: 1000px) {
  .ac-type-rank, .ac-type-actions button { min-height: 44px; }
}
.sidebar, .detail, .map-tools, .map-zoom, .map-layers {
  background: var(--bg-solid); backdrop-filter: none; -webkit-backdrop-filter: none;
  border: 1px solid var(--line); border-radius: 15px;
}
/* The desk list meets the navbar while the flight cards use the space to its
   right. Keep its bottom above the map readout and leave phone sheets alone. */
@media (min-width: 1001px) {
  .sidebar {
    top: calc(-1 * var(--highlights-h)); bottom: var(--map-bottom-h); left: 0;
    border: 0; border-right: 1px solid var(--line); border-radius: 0;
    box-shadow: none;
  }
}
.detail, .layout.has-detail .detail {
  left: auto; right: var(--gap); width: var(--detail-w);
  top: 20px; bottom: 80px; height: auto;
}
/* Flight readings now share the first answer. The sheet grows to its content
   and caps at the map, leaving overflow to the sheet's own scroll area. */
#detail[data-kind="flight"]:not(.is-collapsed) {
  bottom: auto; height: auto; max-height: calc(100% - 100px);
}
/* A selected type, carrier or airport has a short first answer too. Without
   this the reused sheet stretched to the map's bottom and looked empty. */
#detail[data-kind]:not([data-kind="flight"]):not(.is-collapsed) {
  bottom: auto; height: auto; max-height: calc(100% - 100px);
}
.sidebar-collapse {
  position: absolute; z-index: 2; right: 10px; top: 7px;
  width: 32px; height: 32px; display: grid; place-items: center;
  background: var(--bg-raised); border: 1px solid var(--line);
  color: var(--text-dim); border-radius: 8px; cursor: pointer;
}
.sidebar-collapse svg { width: 19px; height: 19px; }
/* The tabs replace the repeated panel headings on a desk. A closed card keeps
   this one row so its tabs and expand button remain usable. */
@media (min-width: 1001px) {
  .sidebar .section-heading { display: none; }
  .sidebar.is-shut { display: flex; bottom: auto; height: 46px; }
  .sidebar.is-shut .panel { display: none; }
  .sidebar.is-shut .sidebar-collapse svg { transform: rotate(180deg); }
}
.section-heading {
  min-height: 46px; padding: 8px 54px 8px 17px; align-items: center;
}
.section-heading h2 { flex: none; font-size: 19px; letter-spacing: -.035em; }
.panel > .search { padding: 10px 15px; }
.panel > .search input { min-height: 40px; font-size: 13px; padding: 9px 11px; }
/* Shared links and board actions still set hidden filters. Chips expose any
   active choice so the visible flight search never appears to lie. */
#panel-flights > .filters { display: none !important; }
.live-snapshot { margin: 0 17px 4px; padding: 9px 0 3px; }
.layout > .site-footer {
  grid-row: 3; position: relative; z-index: 22;
  padding: 9px 22px; min-height: 42px; gap: 8px 22px;
  background: var(--bg-solid); border-top: 1px solid var(--line);
  letter-spacing: 0; text-transform: none;
  flex-wrap: nowrap; white-space: nowrap; overflow-x: auto; scrollbar-width: none;
}
.layout > .site-footer::-webkit-scrollbar { display: none; }
.site-footer p { margin: 0; font-size: 11px; }
.site-footer-nav { gap: 6px 20px; flex-wrap: nowrap; }
.site-footer-nav a, .site-footer-nav button { font-size: 11px; }
.detail-bar { position: absolute; z-index: 3; top: 10px; left: 10px; right: 10px; display: flex; gap: 8px; justify-content: space-between; pointer-events: none; }
.detail-bar button { pointer-events: auto; }
.detail-collapse, .detail-bar .detail-close {
  position: static; flex: none; display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border: 1px solid var(--line); border-radius: 9px;
  background: var(--bg-solid); color: var(--text-dim); cursor: pointer;
}
.detail-collapse svg { width: 18px; height: 18px; }
#detail-summary { display: none; }
/* The open desk rule also names .layout.has-detail .detail. Match that weight
   here or its bottom edge wins and stretches this empty handle over the map. */
.detail.is-collapsed, .layout.has-detail .detail.is-collapsed {
  top: 20px; bottom: auto; height: 54px;
}
.detail.is-collapsed .detail-bar { position: static; padding: 10px; }
.detail.is-collapsed .detail-collapse { flex: 1; width: auto; justify-content: space-between; border: 0; background: none; padding: 0 7px; }
.detail.is-collapsed #detail-summary { display: block; color: var(--text); font-size: 15px; font-weight: 600; }
.detail.is-collapsed .detail-collapse svg { transform: rotate(180deg); }
#detail-body[hidden] { display: none; }
.fl-row { grid-template-columns: 1fr; gap: 10px; padding: 14px 0; }
.fl-times { gap: 10px; }
.fl-times > div { min-width: 0; }
.fl-times b { font-size: 14px; }
.fl-times span, .fl-stand, .fl-place span { font-size: 11px; }
.map-tools { left: 50%; right: auto; transform: translateX(-50%); bottom: 20px; gap: 4px; padding: 5px 8px; height: auto; min-height: 50px; white-space: nowrap; }
.tool { flex: none; min-height: 36px; border-radius: 8px; }
.tool-labelled { display: inline-flex; align-items: center; justify-content: center; gap: 7px; width: auto; padding: 0 10px; font-size: 12px; }
.tool-ic { width: 18px; height: 18px; }
.tool-layers { font-size: 12px; }
.map-zoom { position: absolute; z-index: 18; right: var(--gap); bottom: 20px; display: grid; padding: 4px; box-shadow: var(--shadow); border-radius: 10px; }
.map-zoom .tool { width: 35px; height: 31px; min-height: 31px; font-size: 22px; }
.map-zoom .tool + .tool { border-top: 1px solid var(--line); border-radius: 0 0 7px 7px; }
.map-layers { left: 50%; right: auto; transform: translateX(-50%); bottom: 80px; width: 300px; }
.map-readout { bottom: 19px; left: var(--gap); font-size: 11px; background: var(--bg-solid); }
.map-context { top: 21px; right: 22px; background: var(--bg-solid); font-size: 12px; }
.layout.has-detail .sidebar:not(.is-shut) { display: flex; }
.tool[aria-expanded="true"] { color: var(--accent); background: var(--bg-hover); }
.mobile-tool-label { display: none; }
.mobile-map-tools[hidden] { display: none; }
.welcome { right: 20px; bottom: 90px; }

@media (min-width: 1001px) and (max-width: 1250px) {
  .layout > .topline.command-bar { gap: 12px; padding-left: 18px; padding-right: 18px; }
  .brand-text .brand-word { width: 108px; height: 24px; }
  .brand-mark-inline { width: 26px; height: 29px; }
  .topline > .rail { gap: 7px; }
  .rail-foot { gap: 0; }
  .rail-foot .rail-btn { width: 29px; }
  .topline.command-bar > .cmd.pane { min-width: 180px; }
  .cmd-kbd { display: none; }
  .map-readout { bottom: 83px; }
}

@media (max-width: 1000px) {
  :root { --gap: 12px; }
  .layout > .topline.command-bar { display: grid; grid-template-columns: 1fr auto; gap: 8px; padding: 10px 14px; min-height: 0; }
  .topline.command-bar > .brand.pane { grid-column: 1; grid-row: 1; padding: 0; min-height: 30px; width: auto; height: auto; }
  .topline.command-bar > .cmd.pane { grid-column: 1 / -1; grid-row: 2; width: 100%; max-width: none; min-width: 0; height: 44px; }
  .cmd-input { font-size: 16px; }
  .topline.command-bar > .cmd.pane:focus-within { width: 100%; }
  .topline > .rail { position: fixed; top: auto; bottom: var(--footer-h); left: 0; right: 0; width: 100%; height: 62px; padding: 3px 8px; z-index: 34; gap: 0; background: var(--bg-solid); border-top: 1px solid var(--line); }
  .rail-foot { margin-left: 0; }
  .rail .tabs { width: 100%; margin: 0; justify-content: space-around; gap: 0; }
  .rail .tab { flex: 1; width: auto; min-width: 0; max-width: 105px; height: 50px; padding: 5px 2px; gap: 5px; border-radius: 8px; }
  .rail .rail-ic { display: block; width: 20px; height: 20px; }
  .rail .rail-label { display: block; font-size: 11px; letter-spacing: 0; }
  /* Utilities stay at the top, leaving all eight destinations readable at the
     bottom. No duplicate buttons means their saved settings stay in step. */
  .rail-foot { position: fixed; right: 14px; top: 11px; gap: 3px; }
  .rail-foot .rail-btn { width: 34px; height: 34px; background: var(--bg-raised); border: 1px solid var(--line); }
  .sidebar, .layout.has-detail .sidebar { left: 0; right: 0; width: auto; top: auto; bottom: 62px; height: min(60dvh, 570px); border-radius: 19px 19px 0 0; }
  /* On short phones the open sheet can reach into the highlight strip. Let
     only that sheet rise above the strip, so its first rows stay tappable. */
  .layout:has(.sidebar.is-open) .deck { z-index: auto; }
  .sidebar.is-open { z-index: 22; }
  .sidebar.is-open:has(.panel[data-panel="travel"].is-active) { top: auto; }
  .sidebar-collapse { display: none; }
  .section-heading { min-height: 46px; padding: 8px 18px; }
  /* The deck is below the highlight strip in the stacking order. A taller
     phone sheet used to extend behind that strip, hiding its own route even
     when its scrollHeight said everything fitted. Release that stacking
     context while the sheet is expanded so only the sheet rises above the
     header; lifting the whole map would cover the bottom navigation too. */
  .layout.has-detail:has(.detail:not(.is-collapsed)) .deck { z-index: auto; }
  .layout.has-detail:has(.detail:not(.is-collapsed)) .sidebar { visibility: hidden; }
  .detail, .layout.has-detail .detail { position: fixed; left: 0; right: 0; width: auto; top: auto; bottom: calc(62px + var(--footer-h)); height: min(74dvh, 620px); border-radius: 19px 19px 0 0; }
  #detail[data-kind="flight"]:not(.is-collapsed) { top: auto; bottom: calc(62px + var(--footer-h)); height: auto; max-height: calc(100dvh - 70px - var(--footer-h)); }
  #detail[data-kind]:not([data-kind="flight"]):not(.is-collapsed) { top: auto; bottom: calc(62px + var(--footer-h)); height: auto; max-height: min(68dvh, 560px); }
  .detail.is-collapsed, .layout.has-detail .detail.is-collapsed { height: 54px; top: auto; bottom: calc(62px + var(--footer-h)); }
  .detail-bar { top: 10px; left: 12px; right: 12px; }
  .detail-collapse, .detail-bar .detail-close { width: 36px; height: 36px; }
  /* On a phone the sheet leaves its bottom controls in view. A shorter card
     lets the route, live readings, weather and actions fit on one screen. */
  .d-quick { padding: 46px 16px 8px; }
  #detail .detail-highlight-card { padding: 10px 12px; gap: 7px; }
  .dq-journey-facts { padding-top: 6px; }
  .dq-progress { margin-top: 9px; }
  .dq-glance { margin-top: 8px; padding-top: 7px; }
  .dq-aircraft { margin-top: 8px; }
  /* Reserve the first screen on phones for flight readings. */
  #detail[data-kind="flight"] .dq-photo { display: none; }
  .dq-actions { margin-top: 8px; }
  .dq-actions button { min-height: 35px; }
  .dq-live-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 5px; }
  .dq-live-grid b { font-size: 13px; }
  .dq-live-grid span { font-size: 8px; }
  /* A flight with gates and planned duration can add two extra rows. On a
     short phone those optional schedule facts belong in Full record, while
     the route, current readings and airport weather stay in the first view. */
  @media (max-height: 720px) {
    .dq-journey-facts:has(span:nth-child(2)) { display: none; }
  }
  @media (max-height: 680px) {
    .dq-journey-facts { display: none; }
  }
  .map-tools { bottom: 97px; left: 12px; right: auto; transform: none; justify-content: center; min-height: 46px; padding: 4px; gap: 3px; border-radius: 11px; }
  .map-tools .tool-labelled { flex: none; gap: 5px; padding: 0 12px; min-height: 38px; }
  .map-tools #locate, .map-tools #surprise, .map-tools #toggle-follow, .map-tools .proj, .map-tools .tools-rule { display: none; }
  .map-tools .tool-word { display: inline; font-size: 12px; }
  .map-tools .tool-count, .map-tools .tool-caret { display: none; }
  .map-zoom { bottom: 96px; right: 12px; }
  .map-zoom .tool { width: 33px; }
  .map-layers { bottom: 155px; left: 12px; right: 12px; transform: none; width: auto; }
  /* Secondary map tools move into the layers panel on phones; hiding them
     outright would remove locate, globe and follow from the redesign. */
  .map-layers .mobile-map-tools { display: flex; flex-wrap: wrap; gap: 7px; border-top: 1px solid var(--line); padding-top: 12px; }
  .map-layers .mobile-map-tools .tool { min-width: 42px; min-height: 42px; }
  .mobile-map-tools .mobile-tool-label { display: inline; font-size: 12px; }
  .map-layers .mobile-map-tools .tool { display: inline-flex; width: auto; gap: 7px; padding: 0 10px; }
  .mobile-map-tools .proj { display: inline-flex; align-items: center; gap: 3px; border: 1px solid var(--line); border-radius: 8px; padding: 3px; }
  .mobile-map-tools .proj button { min-height: 36px; padding: 0 10px; background: none; color: var(--text-dim); border: 0; border-radius: 5px; cursor: pointer; }
  .mobile-map-tools .proj button[aria-checked="true"] { background: var(--accent); color: var(--brand-ink); }
  .map-context { display: block; top: 12px; right: 12px; font-size: 11px; }
  .map-readout { display: none; }
  .layout.has-detail .map-tools, .layout.has-detail .map-zoom { visibility: hidden; }
  .layout.has-detail:has(.detail.is-collapsed) .map-tools,
  .layout.has-detail:has(.detail.is-collapsed) .map-zoom { visibility: visible; bottom: 128px; }
  .layout.has-detail:has(.detail.is-collapsed) .map-layers { bottom: 186px; }
  .layout > .site-footer { padding: 7px 12px; gap: 12px; justify-content: flex-start; }
  .site-footer p { width: auto; text-align: left; font-size: 10px; flex: none; }
  .site-footer-nav { gap: 12px; justify-content: flex-start; flex: none; }
  .site-footer-nav a, .site-footer-nav button { font-size: 11px; }
}
/* At 320 × 568 there is not room to keep the map dock below the flight card.
   Let the detail take the screen while it is open; closing it restores the
   dock. Compact spacing preserves the readings instead of clipping them. */
@media (max-width: 350px) and (max-height: 600px) {
  #detail[data-kind="flight"]:not(.is-collapsed) {
    top: 0; bottom: 0; height: auto; max-height: 100dvh;
    z-index: 35; border-radius: 0;
  }
  #detail .d-quick { padding: 40px 12px 4px; }
  #detail .dq-glance { margin-top: 5px; padding-top: 4px; }
  #detail .dq-glance h3 { margin-bottom: 5px; }
  #detail .dq-aircraft { margin-top: 5px; padding: 8px 10px; }
  #detail .dq-actions { flex-wrap: nowrap; gap: 3px; margin-top: 5px; }
  #detail .dq-actions button { min-height: 30px; padding: 5px; font-size: 9px; white-space: nowrap; }
  #detail .dq-map { flex: 1 1 75px; min-width: 75px; }
  /* The old full-height sheet was needed at 100% scale. At the smaller
     mobile scale, let the card shrink instead of leaving a large empty block
     below the flight facts on a 320px phone. */
  @supports (zoom: .8) {
    #detail[data-kind="flight"]:not(.is-collapsed) {
      top: auto; bottom: calc(62px + var(--footer-h));
      max-height: calc(100dvh - 70px - var(--footer-h));
      z-index: 21; border-radius: 19px 19px 0 0;
    }
    /* Even scaled, a 320x568 card can put the action buttons under the
       dock. Take the needed space from gaps, not readings or button targets. */
    #detail[data-kind="flight"] .d-quick { padding-bottom: 0; }
    #detail[data-kind="flight"] .dq-glance { margin-top: 2px; }
    #detail[data-kind="flight"] .dq-aircraft { margin-top: 1px; }
    #detail[data-kind="flight"] .dq-actions { margin-top: 0; }
  }
}
@media (max-width: 380px) {
  .rail .rail-label { font-size: 10px; }
  .rail-foot .rail-btn { width: 30px; }
  .brand-text .brand-word { width: 115px; height: 24px; }
  .map-tools .tool-labelled { gap: 4px; padding: 0 4px; font-size: 11px; }
  .map-tools .tool-labelled svg { display: none; }
  .map-tools .tool-layers { padding: 0 7px; }
  .map-tools .tool-layers .tool-ic { display: none; }
}

/* The readout and map actions used to float as separate islands on the same
   edge. One solid row ties them to the footer without letting either drift
   over the map or collide when the flight card is closed. */
.map-bottom {
  position: absolute; z-index: 18; inset: auto 0 0;
  min-height: var(--map-bottom-h); padding: 0 20px;
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center; gap: 12px;
  background: var(--bg-solid); border-top: 1px solid var(--line);
}
.map-bottom > .map-readout {
  position: static; grid-column: 1; grid-row: 1; min-width: 0; max-width: 100%;
  height: auto; padding: 0; overflow: hidden; white-space: nowrap;
  background: none; border: 0; border-radius: 0; box-shadow: none;
  font-size: 11px;
}
.map-bottom > .map-tools {
  position: static; grid-column: 2; grid-row: 1; justify-self: center;
  left: auto; right: auto; bottom: auto; transform: none;
  min-height: 48px; height: auto; padding: 4px 0;
  background: none; border: 0; border-radius: 0; box-shadow: none;
}
.map-bottom > .map-zoom {
  position: static; grid-column: 3; grid-row: 1; justify-self: end;
  right: auto; bottom: auto; display: flex;
  padding: 0; background: none; border: 0; border-radius: 0; box-shadow: none;
}
.map-bottom > .map-zoom .tool { width: 36px; height: 36px; min-height: 36px; }
.map-bottom > .map-zoom .tool + .tool {
  border-top: 0; border-left: 1px solid var(--line); border-radius: 0;
}

@media (min-width: 1001px) and (max-width: 1250px) {
  /* The age appears only after four minutes and can add another ten words.
     Keep the complete feed timestamp on its own line instead of clipping it
     just when that age is useful. The full-width bar still occupies one row. */
  .map-bottom > .map-readout {
    flex-wrap: wrap; gap: 1px 9px; line-height: 1.35;
    white-space: normal; max-height: 58px;
  }
  .map-bottom > .map-readout #readout-real-sep { display: none; }
  .map-bottom > .map-readout #readout-real { flex-basis: 100%; }
}

@media (max-width: 1000px) {
  /* The navbar already fills the row beside the footer on phones. These
     controls retain their clear strip above it while the readout stays hidden. */
  .map-bottom { display: contents; }
  .map-bottom > .map-readout { display: none; }
  .map-bottom > .map-tools {
    position: absolute; left: 12px; right: auto; bottom: 97px;
    min-height: 46px; padding: 4px;
    background: var(--bg-solid); border: 1px solid var(--line); border-radius: 11px;
    box-shadow: var(--shadow);
  }
  .map-bottom > .map-zoom {
    position: absolute; right: 12px; bottom: 96px;
    display: grid; padding: 4px;
    background: var(--bg-solid); border: 1px solid var(--line); border-radius: 10px;
    box-shadow: var(--shadow);
  }
  .map-bottom > .map-zoom .tool { width: 33px; height: 31px; min-height: 31px; }
  .map-bottom > .map-zoom .tool + .tool {
    border-left: 0; border-top: 1px solid var(--line); border-radius: 0 0 7px 7px;
  }
}

/* The flight cards keep their own row below the navbar. On a desk they use
   only the space right of the list; on a phone they keep the full row. */
.flight-highlights {
  position: relative; grid-row: 2; z-index: 21;
  min-width: 0; padding: 7px;
  background: var(--bg-solid); border-bottom: 1px solid var(--line);
}
/* A flight detail floats beside the map below this row. Hiding the row when
   that panel opened made every highlight disappear even though none overlap. */
.flight-highlights[hidden] { display: none; }
.flight-highlights:not([hidden]) ~ .deck .map-context { display: none; }
.layout > .deck { grid-row: 3; }
.layout > .site-footer { grid-row: 4; }
@media (min-width: 1001px) {
  .layout > .flight-highlights { margin-left: var(--sidebar-w); }
}
.highlight-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.highlight-head .live-snapshot {
  flex: none; width: 540px; margin: 0 4px 4px auto; padding: 0;
  border: 0;
}
.highlight-head .live-snapshot .chips { padding-top: 4px; }
.highlight-head .live-snapshot .chip { padding: 4px 6px; }
.highlight-tabs {
  display: flex; min-width: 0; width: max-content; max-width: 100%;
  gap: 5px; padding: 1px 1px 7px;
  overflow-x: auto; scrollbar-width: none; white-space: nowrap;
  touch-action: pan-x;
}
.highlight-tabs::-webkit-scrollbar { display: none; }
.highlight-tabs button {
  flex: none; min-height: 31px; padding: 0 11px;
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: 8px; color: var(--text-dim); font: inherit;
  font-size: 12px; cursor: pointer;
}
.highlight-tabs button:hover { border-color: var(--accent-dim); color: var(--text); }
.highlight-tabs button[aria-selected="true"] {
  background: var(--bg-hover); border-color: var(--accent-dim); color: var(--accent);
}
.highlight-body { position: relative; min-width: 0; }
/* A recycled card can be half visible while the carousel wraps. Keep its
   lettering out from behind the navigation circles without hiding the next
   card that peeks beyond the rail. */
.highlight-body::before, .highlight-body::after {
  content: ''; position: absolute; z-index: 1; top: 0; bottom: 0;
  width: 28px; background: var(--bg-solid); pointer-events: none;
}
.highlight-body::before { left: 0; }
.highlight-body::after { right: 0; }
.highlight-cards {
  /* Leave a narrow rail for the carousel buttons. At the old edge position
     their circles sat on top of airport codes, especially on a phone. */
  display: flex; gap: 7px; padding: 3px 28px 4px;
  overflow-x: auto; overscroll-behavior-inline: contain;
  scroll-snap-type: x mandatory; scroll-padding-inline: 28px; scrollbar-width: none;
}
.highlight-cards::-webkit-scrollbar { display: none; }
.highlight-cards.is-dragging { scroll-snap-type: none; user-select: none; }
.highlight-card {
  position: relative; overflow: hidden;
  flex: 0 0 320px; min-width: 0; height: 154px; padding: 13px 14px;
  display: flex; flex-direction: column; gap: 11px;
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: 10px; color: var(--text); font: inherit;
  text-align: left; cursor: grab; scroll-snap-align: start;
  transition: border-color .2s ease, background .2s ease, transform .2s ease, box-shadow .2s ease;
}
.highlight-cards.is-dragging .highlight-card { cursor: grabbing; transform: none; }
.highlight-card::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--brand-glow), transparent);
}
.highlight-card:hover {
  border-color: var(--accent-dim); background: var(--bg-hover);
  transform: translateY(-2px); box-shadow: var(--shadow);
}
.highlight-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.highlight-card-top, .highlight-card-route {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; min-width: 0;
}
.highlight-card-top { font-size: 12px; }
.highlight-operator, .highlight-identity, .highlight-state {
  display: inline-flex; align-items: center; min-width: 0; gap: 5px;
}
.highlight-operator { flex: 1; color: var(--text); }
.highlight-operator .mark { flex: none; }
.highlight-operator > span, .highlight-state {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.highlight-identity { flex: none; color: var(--accent); }
.highlight-identity strong { font-size: 13px; }
.highlight-state { color: var(--text-dim); font-size: 11px; }
.highlight-state i {
  width: 6px; height: 6px; flex: none; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 2px var(--brand-glow);
  animation: highlight-breathe 2.6s ease-in-out infinite;
}
@keyframes highlight-breathe {
  50% { box-shadow: 0 0 0 5px var(--brand-glow); }
}
.highlight-card-route { font-size: 22px; letter-spacing: -.02em; }
.highlight-place { display: flex; flex-direction: column; flex: 0 1 88px; min-width: 0; }
.highlight-place strong, .highlight-place small {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.highlight-place strong { font-weight: 600; }
.highlight-place small { color: var(--text-dim); font-size: 12px; letter-spacing: 0; }
.highlight-destination { text-align: right; }
.highlight-route-direction {
  flex: 1; align-self: flex-start; min-width: 28px;
  color: var(--text-faint); font-size: 38px; line-height: 1;
  text-align: center; letter-spacing: 0;
}
/* These cards only appear when the feed supplies both clocks. Keep the
   departure and arrival row as the card's ending, not an altitude substitute. */
.highlight-card-times {
  display: flex; justify-content: space-between; gap: 8px; margin-top: auto;
  padding-top: 9px; border-top: 1px solid var(--line);
}
.highlight-card-times > span { display: flex; flex-direction: column; min-width: 0; }
.highlight-card-times > span:last-child { text-align: right; }
.highlight-card-times small { color: var(--text-dim); font-size: 11px; white-space: nowrap; }
.highlight-card-times strong { color: var(--text); font-size: 13px; font-weight: 600; }
/* This is the same card inside the detail sheet, not another draggable item.
   Only its width, clock room and interaction change; the strip's visual
   hierarchy stays shared so opening a card feels like a closer look. */
.detail .detail-highlight-card {
  flex: none; width: 100%; height: auto; min-height: 165px;
  padding: 14px; gap: 13px; cursor: default; scroll-snap-align: none;
}
.detail .detail-highlight-card:hover {
  border-color: var(--line); background: var(--bg-raised);
  transform: none; box-shadow: none;
}
.detail-highlight-card .highlight-operator .link-inline {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text); text-decoration: none; font-size: inherit;
}
.detail-highlight-card .highlight-operator .link-inline:hover { color: var(--accent); text-decoration: underline; }
.detail-highlight-card .highlight-place { flex-basis: 120px; }
/* Keep route links as large as the code and city together. Native buttons
   give keyboard and touch users the same airport shortcut as mouse users. */
.detail-airport-link { padding: 0; min-height: 44px; border: 0; border-radius: 4px; background: transparent; color: inherit; font: inherit; letter-spacing: inherit; text-align: left; cursor: pointer; }
.detail-airport-link.highlight-destination { text-align: right; }
.detail-airport-link:hover strong { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.detail-airport-link:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; }

.detail-highlight-card .highlight-card-times { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.detail-highlight-card .highlight-card-times .detail-stand { margin-top: 4px; color: var(--text-dim); font-size: 10px; white-space: normal; }
.detail-highlight-card .highlight-card-times strong { font-size: 16px; font-variant-numeric: tabular-nums; }
.detail-highlight-card .highlight-card-times .detail-clock-note {
  color: var(--text-faint); font-size: 10px; white-space: normal;
}
.detail .detail-highlight-card .dq-progress { margin-top: 0; }
/* A 768px laptop has less height below the highlight strip than a desktop
   monitor. Trim spacing before sacrificing any flight or weather readings. */
@media (min-width: 1001px) and (max-height: 900px) {
  #detail[data-kind="flight"] .d-quick { padding: 40px 16px 6px; }
  #detail .detail-highlight-card { padding: 8px 12px; gap: 6px; }
  #detail .dq-progress-meta { margin-top: 4px; }
  #detail .dq-glance { margin-top: 6px; padding-top: 5px; }
  #detail .dq-glance h3 { margin-bottom: 4px; }
  #detail .dq-aircraft { margin-top: 8px; padding-top: 6px; padding-bottom: 6px; }
  #detail .dq-actions { margin-top: 6px; }
  #detail[data-kind="flight"] .dq-photo { display: none; }
}
.highlight-prev, .highlight-next {
  position: absolute; z-index: 2; top: 50%; transform: translateY(-50%);
  width: 34px; height: 34px; display: grid; place-items: center;
  background: var(--bg-solid); border: 1px solid var(--line);
  border-radius: 50%; box-shadow: var(--shadow);
  color: var(--text); font-size: 24px; cursor: pointer;
}
.highlight-prev { left: 2px; }
.highlight-next { right: 2px; }
.highlight-prev[hidden], .highlight-next[hidden] { display: none; }
.highlight-empty { padding: 25px 12px; color: var(--text-dim); font-size: 12px; }

@media (max-width: 1000px) {
  /* A little more side padding keeps the swipeable cards off the screen edge.
     The shared grid row above already holds them under search on phones. */
  .layout > .flight-highlights {
    padding: 7px 12px 8px;
  }
  .highlight-card { flex-basis: min(270px, 76vw); height: 136px; padding: 10px 11px; gap: 8px; }
  /* A fixed 305px cap cut the last label in half on 946px screens despite
     ample room. All four fit here; narrow screens still scroll naturally. */
  .highlight-card-route { font-size: 20px; }
  .highlight-prev { left: 2px; }
  .highlight-next { right: 2px; }
}

@media (min-width: 1001px) and (max-width: 1400px) {
  /* The left list removes up to 480px from this row. Below this width the
     four tabs and six feed figures cannot fit together without clipping. */
  .highlight-head { flex-wrap: wrap; gap: 0; }
  .highlight-head .highlight-tabs { flex: 0 0 100%; }
  .highlight-head .live-snapshot {
    width: 100%; margin: 0; padding: 3px 0 0;
    border-top: 1px solid var(--line-soft);
  }
}

@media (max-width: 940px) {
  /* At this width the six figures would squeeze the fourth tab offscreen.
     Give the tabs their full swipeable row and the figures the row below. */
  .highlight-head { flex-wrap: wrap; gap: 0; }
  .highlight-head .highlight-tabs { flex: 0 0 100%; }
  .highlight-head .live-snapshot {
    width: 100%; margin: 0; padding: 3px 0 0;
    border-top: 1px solid var(--line-soft);
  }
}

@media (max-width: 600px) {
  /* Six 80px cells hid the last figure on a phone. The shorter labels fit
     six equal cells even at 320px without making the figures scroll away. */
  .live-snapshot .chips { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .live-snapshot .chip { padding: 4px 1px; }
  .live-snapshot .chip-label { font-size: clamp(7px, 2vw, 8px); letter-spacing: 0; }
}

/* The airport opens with the movements around now. The complete two-sided
   board and the photograph still exist, but they do not make a quick airport
   lookup into a long modal before the visitor has asked for more. */
.board-inner:has(.airport-snapshot) {
  width: min(760px, 100%); padding: 0; background: var(--bg-solid);
}
.board-inner:has(.airport-snapshot.is-full) { width: min(920px, 100%); }
#board-content:has(.airport-snapshot) { padding-right: 0; }
.airport-snapshot { font-size: 12px; }
.airport-snapshot-head {
  display: flex; align-items: center; gap: 11px;
  min-height: 70px; padding: 13px 53px 13px 17px;
  border-bottom: 1px solid var(--line);
}
.airport-snapshot-code {
  display: grid; place-items: center; flex: none;
  width: 43px; height: 43px; border-radius: 7px;
  background: var(--accent); color: var(--brand-ink);
  font-family: var(--mono); font-size: 15px; font-weight: 600;
}
.airport-snapshot-head > div { flex: 1; min-width: 0; }
.airport-snapshot-head h2 {
  margin: 0; color: var(--text); font-size: 17px; font-weight: 600;
  line-height: 1.2;
}
.airport-snapshot-head p { margin: 4px 0 0; color: var(--text-faint); font-size: 11px; }
.airport-snapshot-head .badge { flex: none; white-space: nowrap; }
.airport-snapshot-section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; padding: 13px 17px 9px;
}
.airport-snapshot-section-head h3 {
  margin: 0; color: var(--text-dim); font-size: 11px;
  font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
}
.airport-snapshot-section-head > span { color: var(--text-faint); font-size: 10px; }
.airport-movements { border-top: 1px solid var(--line-soft); }
.airport-movement {
  display: grid;
  grid-template-columns: 62px 30px minmax(0, 1fr) 102px 83px;
  align-items: center; gap: 9px; width: 100%;
  min-height: 54px; padding: 7px 17px;
  border: 0; border-bottom: 1px solid var(--line-soft);
  border-radius: 0; background: transparent; color: var(--text);
  font: inherit; text-align: left;
}
button.airport-movement { cursor: pointer; }
button.airport-movement:hover { background: var(--bg-hover); }
button.airport-movement:focus-visible,
.airport-snapshot button:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.airport-movement-time { font-size: 14px; font-weight: 600; white-space: nowrap; }
.airport-movement-time small {
  display: block; margin-top: 2px; color: var(--text-faint);
  font-family: var(--sans); font-size: 9px; font-weight: 400;
}
.airport-movement-direction {
  display: inline-block; padding: 4px 3px; border-radius: 3px;
  background: var(--bg-panel); color: var(--accent);
  font-family: var(--mono); font-size: 9px; text-align: center;
}
.airport-movement-route { display: block; min-width: 0; }
.airport-movement-route strong {
  display: block; overflow: hidden; color: var(--text);
  font-size: 12px; font-weight: 600;
  text-overflow: ellipsis; white-space: nowrap;
}
.airport-movement-number { color: var(--accent); }
.airport-movement-route small {
  display: block; overflow: hidden; margin-top: 3px; color: var(--text-faint);
  font-size: 10px; text-overflow: ellipsis; white-space: nowrap;
}
.airport-movement-status { color: var(--text-dim); text-align: right; }
.airport-movement-status.is-active { color: var(--accent); }
.airport-movement-status.is-delayed { color: var(--amber); }
.airport-movement-status.is-problem { color: var(--danger); }
.airport-movement-stand { color: var(--text-faint); font-size: 10px; text-align: right; }
.airport-feed-warning, .airport-no-movements {
  margin: 0; padding: 13px 17px; color: var(--text-dim); font-size: 11px;
}
.airport-feed-warning { color: var(--amber); }
.airport-snapshot-actions {
  display: flex; gap: 7px; padding: 12px 17px 15px;
}
.airport-snapshot-actions button {
  min-height: 37px; padding: 7px 11px; border-radius: 6px;
  font: inherit; font-size: 11px; font-weight: 600; cursor: pointer;
}
.airport-snapshot-primary {
  flex: 1 1 55%; border: 1px solid var(--accent);
  background: var(--accent); color: var(--brand-ink);
}
.airport-snapshot-primary:hover { background: var(--accent-dim); }
.airport-snapshot-secondary {
  flex: 1 1 45%; border: 1px solid var(--line);
  background: var(--bg-raised); color: var(--text);
}
.airport-snapshot-secondary:hover { border-color: var(--accent-dim); color: var(--accent); }
.airport-view-bar {
  display: flex; align-items: center; gap: 17px;
  min-height: 48px; padding: 9px 17px;
  border-bottom: 1px solid var(--line);
}
.airport-view-bar button {
  padding: 4px 0; border: 0; background: none;
  color: var(--accent); font: inherit; font-size: 11px; cursor: pointer;
}
.airport-view-bar h3 { margin: 0; font-size: 13px; font-weight: 600; }
.airport-full .board-grid { gap: 20px; padding: 14px 17px; }
.airport-full .board-col { min-width: 0; }
.airport-full .board-col h4 {
  margin: 0 0 8px; color: var(--accent);
  font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
}
.airport-full .cell-btn { color: var(--accent); font-weight: 600; }
.airport-full .cell-btn:hover { text-decoration: underline; }
.airport-full .airport-code-link {
  color: var(--text); font-weight: 400;
  text-decoration: underline; text-decoration-color: var(--line);
  text-underline-offset: 2px;
}
.airport-full .airport-code-link:hover { color: var(--accent); }
.airport-full .airport-snapshot-actions {
  justify-content: flex-end; border-top: 1px solid var(--line-soft);
}
.airport-full .airport-snapshot-actions button { flex: none; }
.airport-board-tabs { display: none; }
.airport-more { padding: 0 17px 16px; }
.airport-more .airport-view-bar { margin: 0 -17px 12px; }
.airport-more-location { margin: 0 0 12px; color: var(--text-faint); font-size: 11px; }
.airport-more .board-tools { margin: 0 0 14px; }
.airport-more .airport-board-photo { margin-top: 18px; }
.airport-more .board-extra { margin-top: 18px; }
.airport-board-back {
  margin: 0 0 13px; padding: 2px 0; border: 0; background: none;
  color: var(--accent); font: inherit; font-size: 12px; cursor: pointer;
}
.airport-board-back:hover { text-decoration: underline; }
.airport-board-back:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

/* CSS zoom makes normal text a thumbnail on desktop. The quick card gets the
   same deliberate compensation as the airline snapshot, while still leaving
   ample map around it. */
@media (min-width: 1001px) {
  .board-inner:has(.airport-snapshot) { width: min(840px, 100%); }
  .board-inner:has(.airport-snapshot.is-full) { width: min(1120px, 100%); }
  .airport-snapshot { font-size: 15px; }
  .airport-snapshot-head { min-height: 86px; padding: 16px 62px 16px 21px; gap: 14px; }
  .airport-snapshot-code { width: 53px; height: 53px; font-size: 19px; }
  .airport-snapshot-head h2 { font-size: 21px; }
  .airport-snapshot-head p { font-size: 13px; }
  .airport-snapshot-section-head { padding: 17px 21px 12px; }
  .airport-snapshot-section-head h3 { font-size: 13px; }
  .airport-snapshot-section-head > span { font-size: 12px; }
  .airport-movement {
    grid-template-columns: 78px 37px minmax(0, 1fr) 125px 110px;
    min-height: 66px; gap: 12px; padding: 9px 21px;
  }
  .airport-movement-time { font-size: 17px; }
  .airport-movement-time small { font-size: 11px; }
  .airport-movement-direction { font-size: 11px; }
  .airport-movement-route strong { font-size: 14px; }
  .airport-movement-route small { font-size: 12px; }
  .airport-movement-stand { font-size: 12px; }
  .airport-snapshot-actions { padding: 15px 21px 18px; gap: 10px; }
  .airport-snapshot-actions button { min-height: 44px; font-size: 13px; }
  .airport-view-bar { min-height: 57px; padding: 10px 21px; }
  .airport-view-bar button { font-size: 13px; }
  .airport-view-bar h3 { font-size: 16px; }
  .airport-full .board-grid { padding: 18px 21px; gap: 26px; }
  .airport-full .board-col h4 { font-size: 13px; }
  .airport-full .board-table { font-size: 14px; }
}

/* A two-column board stops being readable before it reaches a phone. At this
   width the same full response becomes two tabs; switching tabs is local and
   never repeats the upstream board request. */
@media (max-width: 900px) {
  .airport-full .board-grid { display: block; }
  .airport-full .board-col h4 { display: none; }
  .airport-board-tabs {
    display: flex; gap: 18px; padding: 0 17px;
    border-bottom: 1px solid var(--line);
  }
  .airport-board-tabs button {
    min-height: 43px; padding: 0 2px; border: 0;
    border-bottom: 2px solid transparent; border-radius: 0;
    background: none; color: var(--text-dim);
    font: inherit; font-size: 12px; cursor: pointer;
  }
  .airport-board-tabs button[aria-selected="true"] {
    border-bottom-color: var(--accent); color: var(--accent);
  }
  .airport-full:not(.is-arrivals) [data-board-side="arrivals"],
  .airport-full.is-arrivals [data-board-side="departures"] { display: none; }
}

@media (max-width: 560px) {
  #board:has(.airport-snapshot) { padding: 10px; }
  .airport-snapshot-head { min-height: 59px; padding: 10px 42px 10px 11px; gap: 8px; }
  .airport-snapshot-code { width: 37px; height: 37px; font-size: 12px; }
  .airport-snapshot-head h2 { font-size: 14px; }
  .airport-snapshot-head p { margin-top: 2px; font-size: 9px; }
  .airport-snapshot-head .badge { display: none; }
  .airport-snapshot-section-head { padding: 9px 11px 7px; }
  .airport-snapshot-section-head > span { display: none; }
  .airport-movement {
    grid-template-columns: 42px 27px minmax(0, 1fr) 71px;
    grid-template-rows: auto auto;
    gap: 2px 6px; min-height: 51px; padding: 7px 11px;
  }
  .airport-movement-time { grid-column: 1; grid-row: 1 / 3; font-size: 11px; }
  .airport-movement-time small { font-size: 8px; white-space: normal; }
  .airport-movement-direction { grid-column: 2; grid-row: 1 / 3; font-size: 8px; }
  .airport-movement-route { grid-column: 3; grid-row: 1 / 3; }
  .airport-movement-route strong { font-size: 10px; }
  .airport-movement-route small { font-size: 9px; }
  .airport-movement-status { grid-column: 4; grid-row: 1; font-size: 9px; }
  .airport-movement-stand { grid-column: 4; grid-row: 2; font-size: 8px; }
  .airport-movement:nth-child(n+6) { display: none; }
  .airport-snapshot-actions { padding: 9px 11px 11px; }
  .airport-snapshot-actions button { min-height: 35px; font-size: 10px; }
  .airport-view-bar { padding: 8px 11px; }
  .airport-full .board-grid { padding: 7px 11px 12px; }
  .airport-board-tabs { padding: 0 11px; }
  .airport-full .airport-board-table tr {
    grid-template-columns: 54px minmax(0, 1fr) 74px;
    gap: 2px 7px; margin: 0; padding: 8px 0;
    border: 0; border-bottom: 1px solid var(--line-soft);
    border-radius: 0; background: none;
  }
  .airport-full .airport-board-table td[data-label]::before { display: none; }
  .airport-full .airport-board-table td { padding: 0; border: 0; min-width: 0; }
  /* A revised clock needs its own line: two clocks exceed the narrow time
     column and otherwise paint over the adjacent flight number. */
  .airport-full .airport-board-table td:first-child > span { display: block; }
  .airport-full .airport-board-table td:nth-child(1) { grid-column: 1; grid-row: 1 / 3; }
  .airport-full .airport-board-table td:nth-child(2) { grid-column: 2; grid-row: 1; }
  .airport-full .airport-board-table td:nth-child(3) { grid-column: 2; grid-row: 2; }
  .airport-full .airport-board-table td:nth-child(4) {
    grid-column: 3; grid-row: 1; text-align: right;
  }
  .airport-full .airport-board-table td:nth-child(5) {
    grid-column: 3; grid-row: 2; text-align: right;
  }
  .airport-full .airport-board-table td[colspan] {
    grid-column: 1 / -1; grid-row: auto; text-align: left;
  }
}
@media (max-width: 560px) and (max-height: 700px) {
  .airport-movement:nth-child(n+5) { display: none; }
}
/* This comes after the general phone nav rules so the eighth destination has
   room for its name even on a narrow screen. */
@media (max-width: 430px) {
  .rail .rail-label { font-size: 9.5px; }
}

/* Search and map selections now share the left list. These are ordinary
   disclosure rows, so scheduled services do not need an overlay to be useful. */
.lookup-heading, .lookup-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 12px 0; }
.lookup-flight { border-bottom: 1px solid var(--line); }
.lookup-flight summary { display: flex; align-items: center; gap: 10px; padding: 14px 0; cursor: pointer; list-style: none; }
.lookup-flight summary::-webkit-details-marker { display: none; }
.lookup-flight summary small { display: block; margin-top: 5px; color: var(--text-dim); }
.lookup-sign { width: 26px; height: 26px; border: 1px solid var(--line); border-radius: 5px; color: var(--accent); display: grid; place-items: center; flex: none; }
.lookup-sign::before { content: '+'; }
.lookup-flight[open] .lookup-sign::before { content: '−'; }
.lookup-body { padding: 0 0 14px 36px; font-size: 14px; }
.lookup-body .board-col { margin: 12px 0; }
.lookup-body .board-col h3 { font-size: 15px; }
.lookup-body .kv-line { gap: 10px; }
.lookup-body .kv-line b { text-align: right; }
.lookup-body .board-note { font-size: 12px; overflow-wrap: anywhere; }
.flight-inline-foot .btn-watch, .lookup-actions .btn-watch { border: 1px solid var(--line); border-radius: 5px; background: var(--bg-panel); color: var(--accent); padding: 8px 14px; cursor: pointer; font: inherit; }
.flight-inline-foot .btn-watch.is-on, .lookup-actions .btn-watch.is-on { color: var(--saved); border-color: var(--saved); }
.mobile-freshness { display: none; }
@media (max-width: 1000px) {
  /* The old 80% page zoom made an 11px city label less than 9px on a phone.
     Keep native scale and let the list scroll instead of shrinking the text. */
  .mobile-freshness { display: block; grid-column: 1 / -1; margin: 0; font-size: 12px; line-height: 1.4; color: var(--text-dim); }
  .rail .rail-label { font-size: 11px; }
  .rail .tab { min-height: 44px; }
  .sidebar input, .cmd input { font-size: 16px; min-height: 44px; }
  .list.is-compact .flight-inline-trigger, .schedule-row { min-height: 62px; }
  .flight-inline-airline, .flight-inline-head-facts b, .flight-inline-place strong { font-size: 13px; }
  .flight-inline-head-facts small, .flight-inline-place small { font-size: 12px; }
  .flight-inline-eta strong { font-size: 13px; }
  .flight-inline-detail { font-size: 13px; }
  .flight-inline-arrival small, .flight-inline-foot, .flight-inline-progress-meta { font-size: 12px; }
  .flight-inline-foot button, .lookup-actions button, .lookup-heading button,
  .schedule-directions button, .ap-action { min-height: 44px; }
  .flight-inline-disclosure { width: 28px; height: 28px; font-size: 18px; }
  .schedule-main > span > strong, .schedule-time > strong { font-size: 14px; }
  .schedule-main small, .schedule-route, .schedule-time small, .schedule-note { font-size: 12px; }
  .schedule-detail, .schedule-detail p, .schedule-facts { font-size: 13px; }
  .highlight-card-times small, .highlight-place small { font-size: 12px; }
  .highlight-operator { font-size: 12px; }
  .highlight-card { min-width: 280px; }
}

@media (max-width: 1000px) {
  /* With the list open, another row of flight cards covered all of the map.
     Return that space to the map; the highlights return when the list closes. */
  /* A translated, closed sheet extends beyond the page. Browser focus can
     scroll that overflow even with overflow:hidden, leaving the fixed tabs
     halfway up the list after rotation. Anchor the app; only its lists scroll. */
  body { position: fixed; inset: 0; width: 100%; }
  .layout:has(.sidebar.is-open) .flight-highlights { display: none; }
  .al-text strong, .ac-type-name, .ap-name strong, .route-identity strong { font-size: 14px; }
  .al-hub, .ap-name > span, .ap-action small { font-size: 12px; }
  .al-actions button, .ac-type-actions button { min-height: 44px; }
}
/* The owner requested uniform 80 percent sizing at normal browser zoom. CSS zoom also scales layout and fixed controls, while a transform would leave their original space behind. */
html{zoom:.8}

/* Classic tools share the rounded search vocabulary with the main site.
   Keep their existing live filtering and dropdown placement intact. */
.cmd{border-radius:999px;padding:6px 6px 6px 18px;background:var(--bg-panel);border:1px solid var(--line);box-shadow:var(--shadow)}
.cmd .cmd-ic,.cmd .cmd-kbd{display:none}
.cmd-submit,.site-search-submit{border:1px solid var(--accent);border-radius:999px;background:var(--accent);color:var(--brand-ink);padding:11px 24px;flex:none;font:inherit;font-size:12px;cursor:pointer}
.search{margin:12px;border:1px solid var(--line);border-radius:999px;padding:6px 6px 6px 18px;background:var(--bg-panel);box-shadow:var(--shadow)}
.search input{background:none;border:0;border-radius:0;padding:10px 0;outline:none}
.search:focus-within{border-color:var(--accent)}
.travel-fields input,.jump-input{border-radius:999px;background:var(--bg-panel)}
@media(max-width:700px){.search{margin:10px;padding-left:12px}.site-search-submit,.cmd-submit{padding:10px 16px}}

/* Restore the floating map console without reviving the simulated feed.
   These positions belong to the restored entry point only; the specialist
   map and the saved journey desk keep their existing layouts. */
/* The shared sheet still divides its height by the former 75% scale.
   Match the current 80% scale so bottom controls stay inside the window. */
body:has(.restored-map) { height: calc(100dvh / .8); }
/* The 744px list took too much of the map on a desk. Keep the same shared
   width across Flights, Routes and the other tabs, at 75% of that size. */
.restored-map { display: block; --rail-w: 68px; --sidebar-w: 558px; --console-top: 88px; }
.restored-map > .site-footer { position: fixed; bottom: 0; left: var(--rail-w); right: 0; }
.restored-map .flight-highlights { display: none !important; }
.restored-map > .topline.command-bar {
  position: absolute; top: 0; left: var(--rail-w); right: 0;
  margin: 0; padding: 16px; min-height: 76px;
  background: var(--bg-panel); border-bottom: 1px solid var(--line);
  display: flex; gap: 16px; align-items: center; flex-wrap: nowrap;
}
.restored-map .topline > .brand.pane,
.restored-map .topline > .cmd.pane,
.restored-map .topline > .cluster {
  background: var(--bg-panel); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow); padding: 12px;
}
.restored-map .topline > .brand.pane { flex: 0 0 auto; }
.restored-map .topline > .cmd.pane { flex: 1; max-width: none; }
.restored-map .topline > .cluster { display: flex; }
.restored-map .topline > .brand.pane,
.restored-map .topline > .cluster,
.restored-map .topline > .live-snapshot {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  backdrop-filter: none; padding: 0;
}
.restored-map .header-clock { display: flex !important; }
.restored-map .topline > .live-snapshot { flex: none; }
.restored-map > .rail { position: absolute; top: 0; bottom: 0; left: 0; width: var(--rail-w); }
.restored-map .rail-brand { display: none; }
.restored-map .rail-brand-name { display: none; }
.restored-map .rail .tabs { flex-direction: column; gap: 4px; }
.restored-map .rail-foot { margin-top: auto; flex-direction: column; }
.restored-map #tab-travel { display: none; }
.restored-map .deck { position: absolute; inset: var(--console-top) 0 0; }
.restored-map .sidebar {
  /* Dock the list between the two console bars. The map no longer shows
     through a gap around the list or through text in its scrolling rows. */
  top: 0; left: var(--rail-w); bottom: calc(var(--footer-h) + 64px);
  border: 0; border-right: 1px solid var(--line); border-radius: 0;
  background: var(--bg-solid); box-shadow: none;
}
.restored-map .sidebar.is-shut { height: 46px; }
/* The homepage's list is permanent on a desk; its close button overlapped
   Search and suggested the main way to find results could vanish. Phones
   still use the separate bottom-sheet controls below. */
.restored-map .sidebar-collapse { display: none; }
.restored-map .map-context { display: none; }
.restored-map .map-bottom {
  /* The console belongs to the viewport, not the deck below the header.
     Header wrapping or an open answer must not move the bottom controls. */
  position: fixed; bottom: var(--footer-h); left: var(--rail-w); right: 0;
  min-height: 64px; padding: 8px 16px;
  background: var(--bg-solid); border-top: 1px solid var(--line);
}
.restored-map .map-bottom > .map-tools,
.restored-map .map-bottom > .map-zoom,
.restored-map .map-bottom > .map-readout { background: var(--bg-panel); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 8px; }
@media (min-width: 1001px) and (max-width: 1350px) {
  /* A laptop keeps all six figures on a second row instead of squeezing
     the search field until typing is uncomfortable. */
  .restored-map > .topline.command-bar { flex-wrap: wrap; }
  .restored-map .topline > .live-snapshot { order: 4; flex-basis: 100%; }
  .restored-map .deck { top: var(--console-top); }
}
@media (max-width: 1000px) {
  html:has(.restored-map) { zoom: 1; }
  body:has(.restored-map) { height: 100dvh; }
  .restored-map { --rail-w: 0px; --sidebar-w: 100%; }
  .restored-map > .topline.command-bar { top: 0; left: 0; right: 0; padding: 10px; display: grid; grid-template-columns: 1fr auto; gap: 8px; }
  .restored-map .topline > .cmd.pane { grid-column: 1 / -1; grid-row: 2; }
  .restored-map .topline > .live-snapshot { display: none; }
  .restored-map .topline > .cluster { display: none; }
  .restored-map > .rail { position: fixed; top: auto; bottom: var(--footer-h); width: 100%; height: 62px; flex-direction: row; padding: 3px 8px; }
  .restored-map .rail-brand { display: none; }
  .restored-map .rail .tabs { flex-direction: row; width: 100%; gap: 0; }
  .restored-map .rail-foot { position: fixed; top: 10px; right: 10px; margin: 0; flex-direction: row; }
  .restored-map .deck { top: var(--console-top); }
  .restored-map .map-bottom { bottom: calc(62px + var(--footer-h)); }
  .restored-map .map-bottom > .map-tools,
  .restored-map .map-bottom > .map-zoom { position: fixed; bottom: calc(72px + var(--footer-h)); }
  .restored-map .sidebar { left: 0; top: auto; bottom: calc(62px + var(--footer-h)); border-radius: 18px 18px 0 0; }
  /* Phone sheets cover most of the map. Opaque paper keeps city labels from
     showing through the flight answer while the uncovered map stays live. */
  .restored-map .sidebar, .restored-map .cmd-drop { background: var(--bg-solid); }
}

/* One brand in the header. Align the desktop navigation with the docked
   list instead of leaving the removed duplicate logo space empty. */
@media (min-width: 1001px) {
  .restored-map > .rail { padding-top: var(--console-top); }
}
