@font-face {
  font-family: 'Space Grotesk';
  src: url('/spacegrotesk.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

/*
 * Wellington harbour at dusk: deep water blue through violet to a warm
 * horizon. Panels float over it as frosted glass rather than solid cards, so
 * the gradient stays visible and the board reads as one scene.
 */
:root {
  --night:   #070b1c;
  --deep:    #14103a;
  --violet:  #3b1d5e;
  --ember:   #a5326b;
  --sun:     #ff7a3d;

  --ink:     #f6f2ff;
  --dim:     #a9a2c8;
  --line:    rgba(255, 255, 255, .14);
  --glass:   rgba(12, 10, 34, .52);

  /* Bright, saturated, and distinguishable from across a room. */
  --air:     #5cd6ff;   /* aircraft */
  --sea:     #43e8c0;   /* vessels  */
  --bus:     #ffc44d;   /* bus 14   */
  --signal:  #ff5f7e;   /* imminent */

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* One unit = 1% of the stage width, so 1080p and 4K render identically. */
  --u: calc(min(100vw, 100vh * 16 / 9) / 100);
  --dot: calc(var(--u) * 0.8);
}

* { box-sizing: border-box; }

html { height: 100%; background: var(--night); }

/* The sunset: layered radials, warmest at the horizon. Painted on body
   itself -- a z-index:-1 pseudo-element sits UNDER body's own background,
   so the gradient was being covered by it. */
body {
  height: 100%;
  margin: 0;
  overflow: hidden;                   /* a wall display never scrolls */
  color: var(--ink);
  font-family: 'Space Grotesk', ui-sans-serif, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  background:
    radial-gradient(120% 80% at 78% 108%, rgba(255,122,61,.55), transparent 62%),
    radial-gradient(90% 70% at 92% 96%, rgba(255,95,126,.42), transparent 58%),
    radial-gradient(100% 90% at 12% -10%, rgba(92,45,148,.80), transparent 66%),
    linear-gradient(168deg, var(--night) 0%, var(--deep) 40%, var(--violet) 72%, var(--ember) 100%);
  background-attachment: fixed;
}

/* ----------------------------------------------------------------- stage */
.stage {
  width: min(100vw, calc(100vh * 16 / 9));
  height: min(100vh, calc(100vw * 9 / 16));
  margin: auto;
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: 63fr 37fr;
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  grid-template-areas:
    "bar     bar"
    "map     side"
    "tracked side"
    "ticker  ticker";
  gap: calc(var(--u) * 0.8);
  padding: calc(var(--u) * 1.1);
}

/* ------------------------------------------------------------------- bar */
.bar {
  grid-area: bar;
  display: flex; align-items: baseline; justify-content: space-between;
  gap: calc(var(--u) * 2);
  padding-bottom: calc(var(--u) * 0.6);
  border-bottom: 1px solid var(--line);
}
.bar h1 {
  margin: 0;
  font-size: calc(var(--u) * 2.4);
  font-weight: 600;
  letter-spacing: -0.03em;
  background: linear-gradient(96deg, var(--ink) 20%, var(--bus) 65%, var(--sun) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.bar__right {
  display: flex; align-items: baseline; gap: calc(var(--u) * 1.6);
  color: var(--dim); font-size: calc(var(--u) * 1.25);
}
.bar__wx { color: var(--ink); }
#clock {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: calc(var(--u) * 1.9); color: var(--ink);
}

/* The Frame's browser has no kiosk mode; the Fullscreen API needs a gesture,
   so this is that gesture. Quiet until focused. */
.fsbtn {
  font: inherit;
  font-size: calc(var(--u) * 0.78);
  letter-spacing: .06em; text-transform: uppercase;
  padding: calc(var(--u) * 0.28) calc(var(--u) * 0.7);
  color: var(--dim);
  background: none;
  border: 1px solid var(--line);
  cursor: pointer;
}
.fsbtn:hover { color: var(--ink); border-color: var(--bus); }
:fullscreen .fsbtn { opacity: .25; }
:fullscreen .fsbtn:hover, :fullscreen .fsbtn:focus-visible { opacity: 1; }

/* ------------------------------------------------------- glass surfaces */
.map, .tracked__col, .card {
  background: var(--glass);
  -webkit-backdrop-filter: blur(calc(var(--u) * 0.9)) saturate(130%);
  backdrop-filter: blur(calc(var(--u) * 0.9)) saturate(130%);
  border: 1px solid var(--line);
}

/* ------------------------------------------------------------------- map */
.map { grid-area: map; position: relative; overflow: hidden; }
.map__tiles, .map__pins { position: absolute; inset: 0; }
.map__tiles img { position: absolute; display: block; max-width: none; }

/* The basemap is already dark, so it needs LIFTING to read against the
   gradient, not dimming -- just enough coastline to orient by. */
.map__tiles { filter: saturate(.25) brightness(2.1) contrast(.85); opacity: .5; }

/*
 * A pin is an anchor exactly the size of its dot, so translate(-50%,-50%)
 * centres the DOT on the coordinate. The label is absolutely positioned
 * beside it and takes no part in the centring -- otherwise the flex row
 * (dot + label) gets centred as a whole and the marker drifts west by half
 * the label's width, which is exactly the bug this replaced.
 */
.pin {
  position: absolute;
  width: var(--dot); height: var(--dot);
  transform: translate(-50%, -50%);
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
  cursor: pointer;
}
.pin__dot { position: absolute; inset: 0; }
.pin__label {
  position: absolute;
  left: calc(100% + var(--u) * 0.3);
  top: 50%;
  transform: translateY(calc(-50% + var(--dy, 0px)));
  font-size: calc(var(--u) * 0.82);
  font-weight: 600;
  white-space: nowrap;
  padding: 0 calc(var(--u) * 0.22);
  background: rgba(7, 11, 28, .74);
}

.pin--plane .pin__dot {
  inset: auto; width: 0; height: 0;
  left: 50%; top: 50%;
  margin: calc(var(--u) * -0.52) 0 0 calc(var(--u) * -0.42);
  border-left: calc(var(--u) * 0.42) solid transparent;
  border-right: calc(var(--u) * 0.42) solid transparent;
  border-bottom: calc(var(--u) * 1.05) solid var(--air);
  transform: rotate(var(--deg, 0deg));
  filter: drop-shadow(0 0 calc(var(--u) * 0.25) rgba(92,214,255,.65));
}
.pin--plane .pin__label { color: var(--air); }
.pin--plane.is-ground .pin__dot { border-bottom-color: var(--dim); filter: none; opacity: .6; }
.pin--plane.is-ground .pin__label { color: var(--dim); }

/*
 * Every marker is a CSS-border triangle. The TV's browser doesn't support
 * clip-path, so anything drawn that way silently vanished -- the aircraft
 * only survived because it was already built from borders.
 *
 * The three are told apart by colour and proportion: aircraft narrow and
 * tall, vessels wide and squat, buses in between.
 */
.pin--boat .pin__dot {
  inset: auto; width: 0; height: 0;
  left: 50%; top: 50%;
  margin: calc(var(--u) * -0.42) 0 0 calc(var(--u) * -0.52);
  border-left: calc(var(--u) * 0.52) solid transparent;
  border-right: calc(var(--u) * 0.52) solid transparent;
  border-bottom: calc(var(--u) * 0.84) solid var(--sea);
  transform: rotate(var(--deg, 0deg));
  filter: drop-shadow(0 0 calc(var(--u) * 0.28) rgba(67,232,192,.65));
}
/* No heading and no course: a square, so nothing implies a direction. */
.pin--boat.is-adrift .pin__dot {
  width: calc(var(--u) * 0.6); height: calc(var(--u) * 0.6);
  margin: calc(var(--u) * -0.3) 0 0 calc(var(--u) * -0.3);
  border: 0; background: var(--sea);
  transform: none;
}
.pin--boat .pin__label { color: var(--sea); }
/* Heard, but outside the window's view polygon. */
.pin--boat.is-outside .pin__dot { opacity: .45; box-shadow: none; }
.pin--boat.is-outside .pin__label { opacity: .6; }

.pin--bus .pin__dot {
  inset: auto; width: 0; height: 0;
  left: 50%; top: 50%;
  margin: calc(var(--u) * -0.46) 0 0 calc(var(--u) * -0.46);
  border-left: calc(var(--u) * 0.46) solid transparent;
  border-right: calc(var(--u) * 0.46) solid transparent;
  border-bottom: calc(var(--u) * 0.92) solid var(--bus);
  transform: rotate(var(--deg, 0deg));
  filter: drop-shadow(0 0 calc(var(--u) * 0.28) rgba(255,196,77,.65));
}
/* Metlink doesn't always send a bearing; a square rather than a lie. */
.pin--bus.is-adrift .pin__dot {
  width: calc(var(--u) * 0.6); height: calc(var(--u) * 0.6);
  margin: calc(var(--u) * -0.3) 0 0 calc(var(--u) * -0.3);
  border: 0; background: var(--bus);
  transform: none;
}
.pin--bus .pin__label { color: var(--bus); }

/* Home: a roof triangle sitting on a square body. Two boxes rather than a
   clip-path, so it survives on the TV. */
.pin--home .pin__dot {
  inset: auto; left: 50%; top: 50%;
  width: calc(var(--u) * 0.98); height: calc(var(--u) * 0.98);
  margin: calc(var(--u) * -0.49) 0 0 calc(var(--u) * -0.49);
  background: none; border: 0;
  filter: drop-shadow(0 0 calc(var(--u) * 0.35) rgba(255,95,126,.85));
}
.pin--home .pin__dot::before,
.pin--home .pin__dot::after { content: ""; position: absolute; }
.pin--home .pin__dot::before {          /* roof */
  left: 0; top: 0; width: 0; height: 0;
  border-left: calc(var(--u) * 0.49) solid transparent;
  border-right: calc(var(--u) * 0.49) solid transparent;
  border-bottom: calc(var(--u) * 0.42) solid var(--signal);
}
.pin--home .pin__dot::after {           /* body */
  left: calc(var(--u) * 0.13); top: calc(var(--u) * 0.42);
  width: calc(var(--u) * 0.72); height: calc(var(--u) * 0.56);
  background: var(--signal);
}

.legend {
  position: absolute; left: calc(var(--u) * 0.8); bottom: calc(var(--u) * 0.8);
  margin: 0; padding: calc(var(--u) * 0.45) calc(var(--u) * 0.7);
  list-style: none; display: flex; gap: calc(var(--u) * 1.1);
  background: rgba(7,11,28,.6); border: 1px solid var(--line);
  font-size: calc(var(--u) * 0.78); color: var(--dim);
}
.legend li { display: flex; align-items: center; gap: calc(var(--u) * 0.3); }
.key { width: calc(var(--u) * 0.6); height: calc(var(--u) * 0.6); display: block; }
.key--plane, .key--boat, .key--bus, .key--home {
  width: 0; height: 0; background: none;
  border-left: calc(var(--u) * 0.32) solid transparent;
  border-right: calc(var(--u) * 0.32) solid transparent;
  border-bottom: calc(var(--u) * 0.6) solid currentColor;
}
.key--plane { color: var(--air); }
.key--boat  { color: var(--sea); }
.key--bus   { color: var(--bus); }
.key--home  { color: var(--signal); }

.map__credit {
  position: absolute; right: calc(var(--u) * 0.6); bottom: calc(var(--u) * 0.4);
  margin: 0; font-size: calc(var(--u) * 0.6); color: var(--dim); opacity: .6;
}

/* ------------------------------------------------------------ bus inset */
.inset {
  position: absolute;
  right: calc(var(--u) * 0.8);
  bottom: calc(var(--u) * 0.8);
  width: 27%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: rgba(4, 7, 20, .94);
  border: 1px solid var(--bus);
  box-shadow: 0 calc(var(--u) * 0.4) calc(var(--u) * 1.4) rgba(0,0,0,.55);
}
.inset__tiles, .inset__pins { position: absolute; inset: 0; }
/* Same dark basemap as the main map, pushed harder: at this size the roads
   have to carry the panel on their own, so they're brightened well past the
   main map's setting and left at full opacity. */
.inset__tiles {
  /* brightness lifts the roads, contrast keeps the ground from coming with
     them. Too much brightness and it goes grey; too much contrast and the
     whole tile crushes to black. */
  filter: saturate(.2) brightness(2.5) contrast(1.15);
  opacity: 1;
}
.inset__tiles img { position: absolute; display: block; max-width: none; }
.inset__tag {
  position: absolute;
  left: calc(var(--u) * 0.4); bottom: calc(var(--u) * 0.35);
  display: flex; align-items: center; gap: calc(var(--u) * 0.3);
  font-size: calc(var(--u) * 0.72);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--bus);
  background: rgba(7,11,28,.72);
  padding: 0 calc(var(--u) * 0.3);
}
/* Says so rather than looking broken when no bus is in the box. */
.inset__pins[data-empty]:not([data-empty=""])::after {
  content: attr(data-empty);
  position: absolute; inset: auto 0 calc(var(--u) * 0.5) 0;
  text-align: center;
  font-size: calc(var(--u) * 0.7);
  color: var(--dim);
}

/* --------------------------------------------------------------- tracked */
.tracked {
  grid-area: tracked;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: calc(var(--u) * 0.8);
  min-height: calc(var(--u) * 13);
}
.tracked__col { padding: calc(var(--u) * 0.7) calc(var(--u) * 0.9); overflow: hidden; }

h2 {
  margin: 0 0 calc(var(--u) * 0.5);
  font-size: calc(var(--u) * 0.85);
  font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--dim);
  display: flex; align-items: baseline; gap: calc(var(--u) * 0.5);
}
.tag {
  font-family: var(--mono); font-size: calc(var(--u) * 0.7);
  letter-spacing: 0; text-transform: none; color: var(--air);
}

.rows { list-style: none; margin: 0; padding: 0; }
.rows li { border-bottom: 1px solid var(--line); }
.rows li:last-child { border-bottom: none; }

.rowbtn {
  width: 100%;
  display: grid; grid-template-columns: 1fr auto;
  gap: calc(var(--u) * 0.6); align-items: baseline;
  padding: calc(var(--u) * 0.28) calc(var(--u) * 0.2);
  background: none; border: 0; font: inherit; color: inherit;
  text-align: left; cursor: pointer;
  font-size: calc(var(--u) * 1.02);
}
.rows .who { font-weight: 600; }
.rows .what { color: var(--dim); font-size: calc(var(--u) * 0.82); }
.route {
  font-family: var(--mono);
  font-size: calc(var(--u) * 0.8);
  color: var(--air);
  margin-left: calc(var(--u) * 0.4);
  white-space: nowrap;
}
.route i { font-style: normal; opacity: .6; margin: 0 calc(var(--u) * 0.15); }
.rows .num {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  color: var(--dim); font-size: calc(var(--u) * 0.82); text-align: right;
}
.rows li.is-moving .who { color: var(--signal); }
.rows li.is-ground { opacity: .55; }

.dim { margin: 0; color: var(--dim); font-size: calc(var(--u) * 0.95); }
.err { margin: 0; color: var(--signal); font-size: calc(var(--u) * 0.8); line-height: 1.4; }

/* ------------------------------------------------------------- status */
.lamp {
  width: calc(var(--u) * 0.42);
  height: calc(var(--u) * 0.42);
  flex: none;
  display: inline-block;
  background: var(--dim);
  opacity: .35;
  align-self: center;
}
.lamp[data-state="ok"]    { background: var(--sea);    opacity: .55; box-shadow: none; }
.lamp[data-state="stale"] { background: var(--bus);    opacity: 1;
  box-shadow: 0 0 calc(var(--u) * 0.4) rgba(255,196,77,.8); }
.lamp[data-state="down"]  { background: var(--signal); opacity: 1;
  box-shadow: 0 0 calc(var(--u) * 0.5) rgba(255,95,126,.9);
  animation: lamp-pulse 1.8s ease-in-out infinite; }

@keyframes lamp-pulse { 50% { opacity: .35; } }

/* The ticker has no header to sit in, so it gets a corner. */
.lamp--ticker {
  position: absolute;
  left: calc(var(--u) * 0.45); top: calc(var(--u) * 0.45);
  z-index: 2;
}

/* ------------------------------------------------------- focus (remote) */
/* Must read from across a room, so it's a filled state, not a hairline. */
[data-focus]:focus-visible,
.sheet__close:focus-visible {
  outline: calc(var(--u) * 0.16) solid var(--bus);
  outline-offset: calc(var(--u) * 0.12);
  background: rgba(255, 196, 77, .16);
}
.pin:focus-visible { background: rgba(255, 196, 77, .35); }

/* --------------------------------------------------------------- sidebar */
.side {
  grid-area: side;
  display: grid; grid-template-rows: auto auto 1fr auto;
  gap: calc(var(--u) * 0.8); min-height: 0;
}
.card { padding: calc(var(--u) * 0.7) calc(var(--u) * 0.9); min-height: 0; overflow: hidden; }

.bus-hero { display: flex; align-items: baseline; gap: calc(var(--u) * 0.6); }
.bus-hero__n {
  font-size: calc(var(--u) * 5.4);
  font-weight: 600; line-height: .85; letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums; color: var(--bus);
}
.bus-hero__n.is-imminent { color: var(--signal); }
.bus-hero__u { font-size: calc(var(--u) * 1.1); color: var(--dim); }
.bus-hero__to { font-size: calc(var(--u) * 1.1); margin-left: auto; }
.bus-more {
  list-style: none; margin: calc(var(--u) * 0.5) 0 0; padding: 0;
  display: flex; gap: calc(var(--u) * 1.2);
  font-family: var(--mono); font-size: calc(var(--u) * 0.95);
  color: var(--dim); font-variant-numeric: tabular-nums;
}

.now { display: flex; align-items: center; gap: calc(var(--u) * 0.9); }
.now__t {
  font-size: calc(var(--u) * 3.6); font-weight: 600; line-height: .9;
  letter-spacing: -0.04em; font-variant-numeric: tabular-nums;
}
.now__d { font-size: calc(var(--u) * 1.05); }
.now__w {
  margin-left: auto; text-align: right; color: var(--dim);
  font-size: calc(var(--u) * 0.88); font-family: var(--mono); line-height: 1.35;
}

.card--rain { display: flex; flex-direction: column; min-height: 0; }
.radar {
  position: relative; flex: 1; min-height: calc(var(--u) * 8);
  overflow: hidden; background: rgba(7,11,28,.5); border: 1px solid var(--line);
}
.radar__tiles { position: absolute; inset: 0; overflow: hidden; }
.radar__tiles img { position: absolute; display: block; max-width: none; }
#radar-base { filter: saturate(.25) brightness(2.1) contrast(.85); opacity: .5; }
.radar__tiles--rain { opacity: .9; }
.radar__here {
  position: absolute; left: 50%; top: 50%;
  width: calc(var(--u) * 0.55); height: calc(var(--u) * 0.55);
  transform: translate(-50%, -50%);
  border: calc(var(--u) * 0.16) solid var(--signal);
  border-radius: 50%;
  box-shadow: 0 0 calc(var(--u) * 0.6) rgba(255,95,126,.8);
}

.wx { width: calc(var(--u) * 1.5); height: calc(var(--u) * 1.5); display: block; flex: none; }
.wx--now { width: calc(var(--u) * 3.2); height: calc(var(--u) * 3.2); color: var(--bus); }

.days { list-style: none; margin: 0; padding: 0; display: grid; gap: calc(var(--u) * 0.12); }
.days li {
  display: grid;
  grid-template-columns: calc(var(--u) * 3.2) calc(var(--u) * 1.7) 1fr auto auto;
  gap: calc(var(--u) * 0.6); align-items: center;
  font-size: calc(var(--u) * 0.92);
}
.days .d { font-weight: 600; }
.days .wx { color: var(--air); }
.days .w { color: var(--dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.days .r {
  font-family: var(--mono); color: var(--dim);
  font-variant-numeric: tabular-nums; font-size: calc(var(--u) * 0.78);
}
.days .r b { color: var(--sea); font-weight: 600; font-size: calc(var(--u) * 0.92); }
.days .t {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* "min"/"max" are units, not emphasis -- keep them quiet. */
.days .t i {
  font-style: normal; color: var(--dim);
  font-size: calc(var(--u) * 0.68); letter-spacing: .04em;
}

/* --------------------------------------------------------------- ticker */
.ticker {
  grid-area: ticker;
  position: relative;
  overflow: hidden;
  height: calc(var(--u) * 2.4);
  display: flex; align-items: center;
  background: var(--glass);
  -webkit-backdrop-filter: blur(calc(var(--u) * 0.9));
  backdrop-filter: blur(calc(var(--u) * 0.9));
  border: 1px solid var(--line);
  /* Fade the ends so items appear and leave rather than being clipped. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent);
}
.ticker__track {
  display: flex; align-items: center;
  gap: calc(var(--u) * 2.6);
  white-space: nowrap;
  will-change: transform;
  animation: ticker-scroll var(--dur, 120s) linear infinite;
}
.ticker:hover .ticker__track, .ticker:focus-within .ticker__track { animation-play-state: paused; }
@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }   /* content is duplicated once */
}
.tick {
  display: inline-flex; align-items: baseline; gap: calc(var(--u) * 0.5);
  font-size: calc(var(--u) * 1.0);
  color: inherit;
  text-decoration: none;
}
a.tick:hover .tick__text, a.tick:focus-visible .tick__text {
  text-decoration: underline;
  text-underline-offset: calc(var(--u) * 0.16);
}
a.tick:focus-visible {
  outline: calc(var(--u) * 0.14) solid var(--bus);
  outline-offset: calc(var(--u) * 0.1);
}
.tick__src {
  font-size: calc(var(--u) * 0.68);
  font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  padding: 0 calc(var(--u) * 0.32);
  color: var(--night); background: var(--dim);
}
.tick--media .tick__src { background: var(--sea); }
.tick--news  .tick__src { background: var(--air); }
.tick--media .tick__text { color: var(--sea); }

@media (prefers-reduced-motion: reduce) {
  .ticker__track { animation: none; }
}

/* ---------------------------------------------------------------- modal */
dialog { border: 0; padding: 0; background: none; color: var(--ink); max-width: none; }
dialog::backdrop { background: rgba(4, 6, 18, .74); backdrop-filter: blur(4px); }

.sheet {
  display: grid;
  grid-template-columns: calc(var(--u) * 30) minmax(calc(var(--u) * 22), auto);
  background: rgba(14, 12, 38, .95);
  border: 1px solid var(--line);
  box-shadow: 0 calc(var(--u) * 1.5) calc(var(--u) * 4) rgba(0,0,0,.6);
  overflow: hidden;
}
.sheet__media {
  background: rgba(7,11,28,.7);
  display: grid; place-items: center;
  min-height: calc(var(--u) * 18);
}
.sheet__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sheet__noimg { font-size: calc(var(--u) * 6); font-weight: 600; color: var(--sea); opacity: .45; }
.sheet__loading { color: var(--dim); font-size: calc(var(--u) * 0.9); }

.sheet__body { padding: calc(var(--u) * 1.4) calc(var(--u) * 1.6); }
.sheet__body h2 {
  font-size: calc(var(--u) * 1.7); text-transform: none;
  letter-spacing: -0.02em; color: var(--ink);
  margin-bottom: calc(var(--u) * 0.2);
}
.sheet__sub { margin: 0 0 calc(var(--u) * 1); color: var(--air); font-size: calc(var(--u) * 1); }
.sheet__facts {
  margin: 0; display: grid; grid-template-columns: auto 1fr;
  gap: calc(var(--u) * 0.3) calc(var(--u) * 1);
  font-size: calc(var(--u) * 1);
}
.sheet__facts dt { color: var(--dim); }
.sheet__facts dd { margin: 0; font-variant-numeric: tabular-nums; }
.sheet__foot { margin: calc(var(--u) * 1) 0 0; font-size: calc(var(--u) * 0.78); color: var(--dim); }
.sheet__foot a { color: var(--sea); }
.sheet__close {
  margin-top: calc(var(--u) * 1.2);
  padding: calc(var(--u) * 0.5) calc(var(--u) * 1.4);
  font: inherit; font-size: calc(var(--u) * 0.95); font-weight: 600;
  color: var(--night); background: var(--bus); border: 0; cursor: pointer;
}

/* ----------------------------------------------------------------- phone */
/*
 * The 16:9 stage is for a wall. On a phone it becomes a single scrolling
 * column, ordered by what you actually want when you pull it out of your
 * pocket: when's the bus, then what's it doing outside, then everything else.
 * The unit switches to viewport width so type stays readable rather than
 * shrinking to fit an aspect ratio nothing here has.
 */
@media (max-width: 700px), (orientation: portrait) and (max-width: 900px) {
  :root { --u: calc(100vw / 42); }

  html, body { overflow-x: hidden; overflow-y: auto; height: auto; }
  body { background-attachment: scroll; min-height: 100%; }

  .stage {
    position: static;
    width: 100%; height: auto;
    grid-template-columns: 1fr;
    grid-template-rows: none;
    grid-template-areas:
      "bar"
      "side"
      "map"
      "tracked"
      "ticker";
    gap: calc(var(--u) * 1.2);
    padding: calc(var(--u) * 1.4) calc(var(--u) * 1.2) calc(var(--u) * 3);
    max-width: 100%;
  }
  /* Grid and flex children default to min-content width, which is what lets
     a long headline or a wide row push the whole page sideways. */
  .stage > *, .side > *, .tracked > *, .rowbtn, .days li, .rows li { min-width: 0; }

  /* Same five columns as desktop, just tighter. Giving only .r and .t an
     explicit column while the rest auto-placed made them collide and wrap. */
  .days li {
    grid-template-columns: calc(var(--u) * 3.4) calc(var(--u) * 1.9) 1fr auto auto;
    column-gap: calc(var(--u) * 0.5);
  }
  .days .r { font-size: calc(var(--u) * 0.85); }
  .days .t { font-size: calc(var(--u) * 0.95); }
  .now__w { font-size: calc(var(--u) * 1.05); }

  /* Sidebar order on phone: bus, now, forecast, then radar. */
  .side { grid-template-rows: none; gap: calc(var(--u) * 1.2); }
  .card--bus  { order: 1; }
  .card--now  { order: 2; }
  .card--days { order: 3; }
  .card--rain { order: 4; }

  .map { height: 58vw; min-height: calc(var(--u) * 40); }
  .radar { min-height: calc(var(--u) * 26); }

  /* Inset stays an overlay -- taking it out of flow made it collide with
     the absolutely-positioned tile layers. Just give it more of the frame. */
  .inset { width: 44%; }
  .legend { gap: calc(var(--u) * 0.8); font-size: calc(var(--u) * 0.9); }

  .tracked { grid-template-columns: 1fr; min-height: 0; }

  .bar { flex-wrap: wrap; gap: calc(var(--u) * 0.6); }
  .bar h1 { font-size: calc(var(--u) * 3.2); }
  .bar__right { width: 100%; justify-content: space-between; font-size: calc(var(--u) * 1.5); }
  #clock { font-size: calc(var(--u) * 2.2); }

  .bus-hero__n { font-size: calc(var(--u) * 7); }
  .now__t { font-size: calc(var(--u) * 4.6); }

  /* A scrolling ticker is unreadable on a phone -- wrap it instead. */
  .ticker { height: auto; -webkit-mask-image: none; mask-image: none; }
  .ticker__track {
    animation: none;
    flex-direction: column; align-items: flex-start;
    gap: calc(var(--u) * 0.7);
    white-space: normal;
    padding: calc(var(--u) * 0.8);
  }
  .tick { font-size: calc(var(--u) * 1.15); }
  /* Only the first copy -- the duplicate exists purely for the scroll loop. */
  .ticker__track .tick:nth-child(n + 13) { display: none; }

  .sheet { grid-template-columns: 1fr; max-width: 92vw; }
  .sheet__media { min-height: calc(var(--u) * 26); }
}

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