/* Station display: a platform departure board ("Zugzielanzeiger"). It always
   uses its own navy palette, independent of the light/dark preference. */

:root {
  color-scheme: dark;
  --navy: #071a52;
  --navy-deep: #031038;
  --ink: #ffffff;
  --muted: #b3c1ec;
  --faint: #7f8fc4;
  --rule: rgb(255 255 255 / .14);
  --yellow: #ffd54a;
  --red: #ff7a6e;
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Display", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /* One unit that scales with the screen, so the board fills any display. */
  --u: min(1vw, 1.6vh);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 0% 0%, rgb(60 100 220 / .35), transparent 60%),
    linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
  color: var(--ink);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  font-variant-numeric: tabular-nums;
}

body.idle, body.idle * { cursor: none; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* The next departure takes the room it needs; the following ones fill the rest. */
.display {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto auto minmax(0, 1fr);
  height: 100%;
  padding: calc(2.4 * var(--u)) calc(3.2 * var(--u)) calc(2.2 * var(--u));
}

/* Header: station and clock */

.head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(3 * var(--u));
  padding-bottom: calc(1.6 * var(--u));
  border-bottom: 2px solid var(--rule);
}

.station { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.place { margin-right: .4em; color: var(--muted); font-size: calc(2.2 * var(--u)); font-weight: 500; }
.name { font-size: calc(2.9 * var(--u)); font-weight: 700; letter-spacing: -.01em; }

.clock { flex: none; font-size: calc(3.4 * var(--u)); font-weight: 700; letter-spacing: -.01em; }
.clock .s { margin-left: .12em; color: var(--faint); font-size: .6em; }

/* Main departure */

.main {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(4 * var(--u));
  padding: calc(3.2 * var(--u)) 0 calc(3 * var(--u));
}

.main.fade-in { animation: fade-in .6s cubic-bezier(.2, .8, .2, 1); }

.m-left {
  display: grid;
  justify-items: start;
  gap: calc(1.4 * var(--u));
  min-width: calc(17 * var(--u));
}

.m-time { font-size: calc(6.4 * var(--u)); font-weight: 750; line-height: 1; letter-spacing: -.02em; }
.m-time .delay { margin-left: .2em; font-size: .5em; }

.delay { color: var(--yellow); font-weight: 700; }
.delay.late { color: var(--red); }

.m-line .badge { height: calc(5 * var(--u)); min-width: calc(9 * var(--u)); padding: 0 calc(1.4 * var(--u)); border-radius: calc(1 * var(--u)); font-size: calc(2.9 * var(--u)); }

.m-in { color: var(--muted); font-size: calc(2.4 * var(--u)); font-weight: 600; }
.m-in.now { color: var(--yellow); animation: pulse 1.6s ease-in-out infinite; }

.m-center { min-width: 0; }

.m-via {
  margin: 0 0 calc(1.2 * var(--u));
  color: var(--muted);
  font-size: calc(2.5 * var(--u));
  font-weight: 500;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

.m-via .dot { margin: 0 .15em; color: var(--faint); }

.m-dest {
  margin: 0;
  font-size: clamp(32px, calc(8.2 * var(--u)), 160px);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -.03em;
  text-wrap: balance;
}

.main.cancelled .m-dest, .main.cancelled .m-time { text-decoration: line-through; text-decoration-thickness: .06em; color: var(--faint); }

.m-plat {
  display: grid;
  justify-items: center;
  align-content: center;
  min-width: calc(14 * var(--u));
  padding: calc(1.4 * var(--u)) calc(2 * var(--u));
  border: 3px solid var(--ink);
  border-radius: calc(1.6 * var(--u));
}

.m-plat-label { color: var(--muted); font-size: calc(1.6 * var(--u)); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.m-plat-num { font-size: calc(8 * var(--u)); font-weight: 800; line-height: 1; letter-spacing: -.03em; white-space: nowrap; }
.m-plat.changed { border-color: var(--yellow); }
.m-plat.changed .m-plat-num { color: var(--yellow); }

.m-empty { grid-column: 1 / -1; display: grid; gap: calc(1 * var(--u)); text-align: center; }
.m-empty b { font-size: calc(4.4 * var(--u)); font-weight: 750; }
.m-empty span { color: var(--muted); font-size: calc(2.2 * var(--u)); }
.m-empty a { color: var(--ink); }

/* Ticker ("Lauftext") */

.ticker {
  overflow: hidden;
  margin-bottom: calc(2 * var(--u));
  padding: calc(1 * var(--u)) 0;
  border-radius: calc(.8 * var(--u));
  background: var(--ink);
  color: var(--navy);
  font-size: calc(2.3 * var(--u));
  font-weight: 650;
  white-space: nowrap;
}

.ticker-text {
  display: inline-block;
  padding-left: 100%;
  animation: ticker var(--duration, 20s) linear infinite;
}

/* Following departures */

.next { min-height: 0; overflow: hidden; border-top: 2px solid var(--rule); }

.next-label {
  margin: calc(1.4 * var(--u)) 0 calc(.4 * var(--u));
  color: var(--faint);
  font-size: calc(1.5 * var(--u));
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* Rows share their columns through subgrid, so times and platforms line up. */
.next-list {
  display: grid;
  grid-template-columns: max-content max-content minmax(0, 1fr) max-content max-content;
  column-gap: calc(2.4 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: calc(2.4 * var(--u));
}

.next-list li {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: center;
  padding: calc(1 * var(--u)) 0;
  border-bottom: 1px solid var(--rule);
}

.next-list li:last-child { border-bottom: 0; }
.next-list li.cancelled .n-dest, .next-list li.cancelled .n-time { color: var(--faint); text-decoration: line-through; }

.n-time { font-weight: 700; white-space: nowrap; }
.n-time .delay { margin-left: .3em; font-size: .75em; }
.n-dest { min-width: 0; overflow: hidden; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.n-dest small { margin-left: .7em; color: var(--muted); font-size: .7em; font-weight: 500; }
.n-plat { min-width: calc(5 * var(--u)); color: var(--muted); font-weight: 600; text-align: center; white-space: nowrap; }
.n-plat.changed { color: var(--yellow); }
.n-in { color: var(--muted); font-weight: 600; text-align: right; white-space: nowrap; }

.next-list .badge { height: calc(3.4 * var(--u)); min-width: calc(7 * var(--u)); padding: 0 calc(1 * var(--u)); border-radius: calc(.7 * var(--u)); font-size: calc(1.9 * var(--u)); justify-self: start; }

/* Each train links to its journey; ::after makes the whole block clickable. */
.main, .next-list li { position: relative; }
.j-link { color: inherit; text-decoration: none; }
.j-link::after { content: ""; position: absolute; inset: 0; }
.j-link:focus-visible { outline: none; }
.main:has(.j-link:focus-visible), .next-list li:has(.j-link:focus-visible) { outline: 2px solid var(--yellow); outline-offset: 4px; border-radius: 8px; }

/* Line badges in the API's colors */

.badge {
  display: inline-grid;
  place-items: center;
  background: var(--bg-c, #1d2f6b);
  color: var(--fg-c, var(--ink));
  box-shadow: inset 0 0 0 2px rgb(255 255 255 / .25);
  font-weight: 800;
  letter-spacing: -.01em;
  white-space: nowrap;
}

.badge.sbahn { border-radius: 999px !important; }

/* Settings, shown while the pointer moves */

.controls {
  position: fixed;
  right: 20px;
  bottom: 20px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border: 1px solid rgb(255 255 255 / .16);
  border-radius: 16px;
  background: rgb(3 12 40 / .82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 20px 50px -10px rgb(0 0 0 / .6);
  font-size: 14px;
  transition: opacity .3s, transform .3s;
}

/* Only keyboard focus keeps them visible: a click shouldn't pin them. */
body.idle .controls:not(:has(:focus-visible)) { opacity: 0; transform: translateY(8px); pointer-events: none; }
/* Announcements waiting for a tap keep the controls up, to be tapped. */
body.idle .controls:has(.blocked) { opacity: 1; transform: none; pointer-events: auto; }

.control, .segmented button, .controls select {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 36px;
  padding: 0 12px;
  border: 0;
  border-radius: 10px;
  background: rgb(255 255 255 / .08);
  color: var(--ink);
  font: 500 14px var(--font);
  text-decoration: none;
  cursor: pointer;
}

.control:hover, .segmented button:hover, .controls select:hover { background: rgb(255 255 255 / .16); }
.control svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.control.icon-only { padding: 0 9px; }
#announce[aria-pressed="true"] { background: var(--ink); color: var(--navy); }
#announce[aria-pressed="false"] .on, #announce[aria-pressed="true"] .off { display: none; }
#volume-control { padding: 0 10px 0 8px; cursor: default; }
#volume { width: 96px; margin: 0; accent-color: var(--ink); cursor: pointer; }
/* A ring fills while the voice downloads. */
#announce.loading { background: conic-gradient(rgb(255 255 255 / .55) calc(var(--progress, 0) * 1turn), rgb(255 255 255 / .12) 0); color: var(--ink); }
#announce.blocked { background: var(--yellow); color: var(--navy); animation: nudge 1.6s ease-in-out infinite; }
@keyframes nudge { 50% { box-shadow: 0 0 0 6px rgb(255 213 74 / .35); } }
@media (prefers-reduced-motion: reduce) { #announce.blocked { animation: none; } }
.control.select { padding: 0; background: none; }
.controls select { appearance: none; padding-right: 12px; }
.controls select option { background: var(--navy-deep); }

.segmented { display: flex; padding: 3px; border-radius: 12px; background: rgb(255 255 255 / .08); }
.segmented button { height: 30px; background: none; }
.segmented button[aria-pressed="true"] { background: var(--ink); color: var(--navy); }
.segmented { flex-wrap: wrap; gap: 2px; }
.segmented .dot { width: 8px; height: 8px; margin-right: 4px; border-radius: 50%; background: var(--c, var(--faint)); box-shadow: 0 0 0 1px rgb(255 255 255 / .35); }

/* Forced colors drop the pressed button's background: mark it in system colors. */
@media (forced-colors: active) {
  .segmented button { border: 1px solid ButtonText; }
  .segmented button[aria-pressed="true"] { forced-color-adjust: none; background: Highlight; border-color: Highlight; color: HighlightText; }
  .segmented .dot { forced-color-adjust: none; }
  #announce[aria-pressed="true"], #announce.blocked { forced-color-adjust: none; background: Highlight; color: HighlightText; }
}

.controls { flex-wrap: wrap; justify-content: flex-end; max-width: calc(100vw - 40px); }

:focus-visible { outline: 2px solid var(--yellow); outline-offset: 2px; }

/* Portrait screens and phones */

@media (max-aspect-ratio: 1/1) {
  :root { --u: min(1.9vw, 1.2vh); }
  .main { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "left plat" "center center"; align-content: center; }
  .m-left { grid-area: left; }
  .m-center { grid-area: center; }
  .m-plat { grid-area: plat; align-self: start; }
  .m-dest { font-size: calc(6.6 * var(--u)); }
  .place { display: none; }
  .next-list { grid-template-columns: max-content max-content minmax(0, 1fr) max-content; column-gap: calc(1.4 * var(--u)); }
  .n-time .delay { font-size: .65em; }
  .n-dest { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal; line-height: 1.15; hyphens: auto; overflow-wrap: anywhere; }
  .n-plat { display: none; }
  .n-dest small { display: none; }
  .controls { left: 8px; right: 8px; width: fit-content; margin-inline: auto; }
  .controls { max-width: calc(100vw - 16px); }
  .control.select { min-width: 0; flex: 0 1 auto; }
  .controls select { min-width: 0; width: 100%; text-overflow: ellipsis; }
}

@keyframes ticker { to { transform: translateX(-100%); } }
@keyframes pulse { 50% { opacity: .45; } }
@keyframes fade-in { from { opacity: 0; transform: translateY(calc(1 * var(--u))); } }

@media (prefers-reduced-motion: reduce) {
  .ticker-text { padding-left: 0; animation: none; white-space: normal; }
  .ticker { white-space: normal; padding-inline: 1em; }
  .main.fade-in, .m-in.now { animation: none; }
}

/* A part of the station, e.g. "Südseite", where a platform would be */
.m-plat.part .m-plat-num { font-size: .55em; line-height: 1.1; overflow-wrap: anywhere; }
