/* One stylesheet for the public pages and the sign-in page. No build step.
   Colours meet WCAG AA against their backgrounds in both schemes. */

:root {
  color-scheme: light dark;
  --bg: #f7f7f4;
  --surface: #ffffff;
  --text: #1a1d21;
  --muted: #4a5158;
  --accent: #0b5d3b;
  --on-accent: #ffffff;
  --border: #c2c6cc;
  --error: #a3001b;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #111417;
    --surface: #1a1e23;
    --text: #eceef0;
    --muted: #aeb6bf;
    --accent: #7fd6a8;
    --on-accent: #0c1a13;
    --border: #3d444d;
    --error: #ff9aa5;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 1rem/1.6 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.skip {
  position: absolute;
  left: 1rem;
  top: -4rem;
  padding: 0.5rem 0.75rem;
  background: var(--accent);
  color: var(--on-accent);
  border-radius: 0.25rem;
}

.skip:focus {
  top: 0.5rem;
}

header,
main,
footer {
  max-width: 44rem;
  margin: 0 auto;
  padding: 0 1rem;
}

header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  padding-top: 1.5rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}

.name {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  font-weight: 700;
  font-size: 1.125rem;
  letter-spacing: 0.01em;
  color: var(--text);
  text-decoration: none;
}

.name img {
  display: block;
}

nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The flex gap spaces the items; the prose list spacing below would drop all but the first. */
nav li + li {
  margin-top: 0;
}

main {
  padding-top: 1rem;
  padding-bottom: 3rem;
}

h1,
h2,
h3 {
  line-height: 1.25;
  text-wrap: balance;
}

h1 {
  font-size: 2rem;
  margin: 1.5rem 0 0.75rem;
}

h2 {
  font-size: 1.375rem;
  margin: 2.5rem 0 0.5rem;
}

h3 {
  font-size: 1.0625rem;
  margin: 1.75rem 0 0.25rem;
}

p,
ul,
ol,
dl,
table {
  margin: 0.75rem 0;
}

li + li {
  margin-top: 0.25rem;
}

.lede {
  font-size: 1.1875rem;
  color: var(--muted);
}

a {
  color: var(--accent);
  text-underline-offset: 0.15em;
}

a:hover {
  text-decoration-thickness: 2px;
}

a[aria-current="page"] {
  color: var(--text);
  font-weight: 600;
}

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 0.125rem;
}

code {
  font: 0.9375em/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  overflow-wrap: anywhere;
}

.copy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
}

.copy code {
  flex: 1 1 14rem;
  font-size: 1.0625rem;
}

/* The embed code is a long line of HTML; the address is short. */
.copy #embed-code {
  font-size: 0.875rem;
}

.copy [role="status"] {
  flex-basis: 100%;
  min-height: 1.5rem;
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
}

.copy [role="status"]:empty {
  display: none;
}

button {
  font: inherit;
  font-weight: 600;
  min-height: 2.75rem;
  padding: 0.5rem 1rem;
  color: var(--on-accent);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 0.375rem;
  cursor: pointer;
}

button.quiet {
  color: var(--accent);
  background: transparent;
}

blockquote {
  margin: 0.75rem 0;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border-left: 0.25rem solid var(--accent);
  border-radius: 0 0.375rem 0.375rem 0;
}

blockquote p {
  margin: 0;
}

/* Homepage: two chat answers, drawn as text so they follow the colour scheme. */

.chat {
  margin: 1.25rem 0;
  padding: 0 1rem 0.25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
}

.chat figcaption {
  margin: 0 -1rem;
  padding: 0.5rem 1rem;
  font-weight: 600;
  border-bottom: 1px solid var(--border);
}

.chat .ask {
  width: fit-content;
  max-width: 85%;
  margin: 1rem 0 1rem auto;
  padding: 0.5rem 0.875rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 1rem;
}

.chat .tool {
  color: var(--muted);
  font-size: 0.875rem;
}

.chat .tool::after {
  content: " ›";
}

.chat table {
  font-size: 0.9375rem;
}

/* Homepage: the departure board app (ui/board.html), with example trains. It
   is dark in both schemes, as the app is. The trains are a table in the
   board's colours; site.js draws them as flaps and leaves the table to screen
   readers. */

.departures {
  margin: 1.5rem 0;
}

.departures .panel {
  --pale: #cfe3d6;
  --well: #0a2a1c;
  --amber: #ffb020;
  --cancelled: #c62828;
  padding: 0.875rem;
  border-radius: 0.75rem;
  background: #0b5d3b;
  color: #ffffff;
  container-type: inline-size;
}

.departures .station {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0 0 0.625rem;
}

.departures .station span,
.departures th,
.departures .heads {
  color: var(--pale);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.departures .trains {
  padding: 0.25rem 0.75rem;
  border-radius: 0.5rem;
  background: var(--well);
}

.departures table {
  margin: 0;
}

.departures tr,
.departures th,
.departures td {
  border-bottom-color: rgb(255 255 255 / 15%);
}

.departures td {
  color: var(--amber);
  font: 600 0.9375rem/1.4 ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  text-transform: uppercase;
}

.departures tbody tr:last-child,
.departures tbody tr:last-child td {
  border-bottom: 0;
}

.departures.drawn .trains {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.departures .flaps {
  --cols: 38;
  /* One column of the grid. Every size below follows from it, so the board
     keeps its proportions at any width. */
  --pitch: calc((100cqw - 1rem) / var(--cols));
  padding: 0.5rem;
  border-radius: 0.5rem;
  background: var(--well);
}

.departures .line {
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
}

.departures .heads {
  margin-bottom: 2px;
}

.departures .heads span {
  overflow: hidden;
  padding-left: 1px;
  white-space: nowrap;
}

.departures .service + .service {
  margin-top: calc(var(--pitch) * 0.45);
}

.departures .cell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(var(--pitch) * 1.6);
  margin: 1px;
  border-radius: 2px;
  background: #113a29;
  color: var(--amber);
  font: 600 calc(var(--pitch) * 1.05) / 1 ui-monospace, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
}

/* A late train's Expected is white, and a cancelled one's is on red flaps
   (white on red, 5.6:1). The words say it too: colour is never all of it. */
.departures .cell.late {
  color: #ffffff;
}

.departures .cell.cancelled {
  background: var(--cancelled);
  color: #ffffff;
}

/* The seam where a flap folds. */
.departures .cell::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto;
  height: 1px;
  background: rgb(0 0 0 / 45%);
}

.departures .source {
  margin: 0.625rem 0 0;
  color: var(--pale);
  font-size: 0.75rem;
}

.departures .source a {
  color: inherit;
}

/* The page's accent is the panel's green. */
.departures .source a:focus-visible {
  outline-color: var(--amber);
}

.departures figcaption {
  margin-top: 0.5rem;
  color: var(--muted);
  font-size: 0.875rem;
}

/* The shareable boards (site/boards.py): the same board with live trains, the
   station's name as the page's heading and a clock like the station's own. */

.departures.live .station {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0 0.75rem;
}

.departures.live .station h1 {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.3;
}

.departures.live .station span {
  grid-column: 1;
}

.departures .clock {
  grid-column: 2;
  grid-row: 1 / span 2;
  padding: 0.25rem 0.5rem;
  border-radius: 0.375rem;
  background: var(--well);
  color: var(--amber);
  font: 600 1.25rem/1.2 ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  font-variant-numeric: tabular-nums;
}

.departures caption {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.departures .empty {
  margin: 0.5rem 0 0;
  padding: 0.75rem;
  border-radius: 0.5rem;
  background: var(--well);
  color: var(--amber);
}

.departures .notes {
  margin: 0.625rem 0 0;
  padding: 0;
  list-style: none;
  color: var(--pale);
  font-size: 0.8125rem;
}

.departures .notes:empty {
  display: none;
}

/* The row of platform boards: one link each, the current one filled. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0;
  list-style: none;
}

.chips li + li {
  margin-top: 0;
}

.chips a {
  display: inline-block;
  min-width: 2.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  text-align: center;
  text-decoration: none;
}

.chips a[aria-current="page"] {
  background: var(--accent);
  color: var(--on-accent);
}

.picker {
  max-width: 26rem;
}

.picker label {
  margin-top: 1rem;
}

.picker .or {
  margin: 1rem 0 0;
  color: var(--muted);
  font-size: 0.875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.optional {
  color: var(--muted);
  font-weight: 400;
}

/* A board in another site's frame: the board alone, on that page's background. */
.embed body {
  background: transparent;
}

.embed main {
  max-width: 760px;
  margin: 0;
  padding: 0;
}

.embed .departures {
  margin: 0;
}

/* The countdown to the next update keeps its width as the digits change. */
.departures .next {
  font-variant-numeric: tabular-nums;
}

/* A board that has gone this long without an update dims, and says so. */
.departures.stale .flaps {
  opacity: 0.45;
}

.departures .stale-note {
  margin: 0.5rem 0 0;
  color: var(--amber);
  font-weight: 600;
}

.departures .fullscreen {
  margin-top: 0.625rem;
  min-height: 2.25rem;
  padding: 0.25rem 0.875rem;
  color: #ffffff;
  border-color: rgb(255 255 255 / 45%);
}

/* A board on a TV (?tv=1, or "Show on TV"): the panel is the whole screen,
   and site.js sizes the flaps so that every train fits it. Everything else
   on the page is put away, so the same page can switch in place. */
.tv,
.tv body {
  height: 100%;
  overflow: hidden;
  background: #0b5d3b;
}

.tv body > header,
.tv body > footer,
.tv .skip,
.tv main > :not(.departures) {
  display: none;
}

.tv main {
  max-width: none;
  margin: 0;
  padding: 0;
}

.tv .departures {
  margin: 0;
}

/* The station's name at the top left, the Full screen button at the top
   right, the flaps below, and the notes and credit at the bottom left beside
   the clock. */
.tv .departures .panel {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto auto minmax(0, 1fr) auto auto auto;
  column-gap: 2.5vw;
  height: 100vh;
  padding: 2.5vh 2.5vw;
  border-radius: 0;
}

.tv .departures .station {
  display: contents;
}

.tv .departures.live .station h1 {
  grid-area: 1 / 1;
}

.tv .departures.live .station span {
  grid-area: 2 / 1;
}

.tv .departures .flaps,
.tv .departures .empty {
  grid-area: 3 / 1 / 4 / -1;
}

.tv .departures .empty {
  align-self: start;
}

.tv .departures .stale-note {
  grid-area: 4 / 1;
}

.tv .departures .notes {
  grid-area: 5 / 1;
}

.tv .departures .source {
  grid-area: 6 / 1;
  align-self: end;
}

.tv .departures.live .station h1 {
  font-size: clamp(1.25rem, 3.4vw, 5rem);
}

.tv .departures.live .station span {
  font-size: clamp(0.75rem, 1.3vw, 2rem);
}

/* Without its flaps (an empty board) the clock is text, at the bottom right. */
.tv .departures .clock {
  grid-area: 4 / 2 / 7 / 3;
  align-self: end;
  font-size: clamp(1.25rem, 3.4vw, 5rem);
}

/* With them, the clock is a line of the board's own flaps (site.js), under
   the Expected column and the same size as the trains, in white. */
.tv .departures.flap-clock .clock {
  display: none;
}

.tv .departures .clock-flaps {
  grid-area: 4 / 1 / 7 / -1;
  align-self: end;
  margin-top: 1.5vh;
  padding: 0 0.5rem;
}

.tv .departures .clock-flaps .cell {
  color: #ffffff;
}

/* The notices and the credit stop short of the clock. */
.tv .departures.flap-clock .stale-note,
.tv .departures.flap-clock .notes,
.tv .departures.flap-clock .source {
  padding-right: var(--clock-clear, 0px);
}

/* The flaps take the space the rest leaves; their lines are as wide as the
   flaps that fit, in the middle. */
.tv .departures .flaps {
  flex: 1 1 0;
  min-height: 0;
  margin-top: 1.5vh;
  overflow: hidden;
}

/* Where the width limits the flaps (a tall screen), the trains sit in the
   middle of the space rather than at the top of it. */
.tv .departures .flaps:not([hidden]) {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.tv .departures .line {
  width: calc(var(--cols) * (var(--pitch) + 2px));
  margin-inline: auto;
}

.tv .departures .heads {
  font-size: calc(var(--pitch) * 0.45);
  line-height: 1.2;
}

.tv .departures .empty {
  font-size: clamp(1rem, 2.5vw, 3rem);
}

.tv .departures .notes,
.tv .departures .source,
.tv .departures .stale-note {
  font-size: clamp(0.75rem, 1.1vw, 1.5rem);
}

.tv .departures .fullscreen {
  grid-area: 1 / 2 / 3 / 3;
  align-self: start;
  justify-self: end;
  margin: 0;
}

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

.tv.idle .departures .fullscreen {
  display: none;
}

dt {
  margin-top: 1rem;
  font-weight: 600;
}

dd {
  margin: 0.125rem 0 0;
}

.scroll {
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  padding: 0.5rem 0.75rem 0.5rem 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--border);
}

footer {
  padding-top: 1.25rem;
  padding-bottom: 2.5rem;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.875rem;
}

footer p {
  margin: 0.5rem 0;
}

/* Sign-in page (oauth.py): one narrow column of forms. */

.sign-in {
  max-width: 26rem;
  padding-top: 2rem;
}

label {
  display: block;
  font-weight: 600;
}

input {
  display: block;
  width: 100%;
  min-height: 2.75rem;
  margin-top: 0.25rem;
  padding: 0.5rem 0.75rem;
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--muted);
  border-radius: 0.375rem;
}

form button {
  width: 100%;
  margin-top: 0.75rem;
}

details,
form + form {
  margin-top: 1.5rem;
}

summary {
  cursor: pointer;
  padding: 0.5rem 0;
}

.hint {
  margin: 0.5rem 0 0;
  color: var(--muted);
  font-size: 0.875rem;
}

.error {
  color: var(--error);
  font-weight: 600;
}

/* The sign-in code as six boxes, one digit each (static/js/code_input.js). */
.code-boxes {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0.5rem;
  margin-top: 0.25rem;
}

input.code-box {
  min-height: 3.5rem;
  margin-top: 0;
  padding: 0;
  font: 600 1.5rem/1 ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  font-variant-numeric: tabular-nums;
  text-align: center;
  caret-color: var(--accent);
}

@media (max-width: 40rem) {
  h1 {
    font-size: 1.625rem;
  }

  h2 {
    font-size: 1.25rem;
  }

  /* Three columns don't fit a phone: each row becomes a labelled block. */
  table,
  tbody,
  tr,
  td {
    display: block;
  }

  thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  tr {
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--border);
  }

  td {
    padding: 0.125rem 0;
    border: 0;
  }

  td::before {
    content: attr(data-label) ": ";
    font-weight: 600;
  }

  td:first-child {
    font-weight: 600;
  }

  td:first-child::before {
    content: none;
  }

  /* In a chat answer, each train is one line that wraps. */
  .chat tr {
    padding: 0.5rem 0;
  }

  .chat td {
    display: inline;
  }

  .chat td::before {
    content: " · ";
    font-weight: 400;
  }

  .chat td:first-child::before {
    content: none;
  }

  .chat td[data-label="Platform"]::before {
    content: " · Platform ";
  }

  /* A train with no platform yet has no platform line. */
  .departures td:empty {
    display: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .skip {
    transition: top 0.15s;
  }
}
