/* 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;
  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;
}

/* 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;
}

.tv .departures .panel {
  display: flex;
  flex-direction: column;
  height: 100vh;
  padding: 2.5vh 2.5vw;
  border-radius: 0;
}

.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);
}

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

/* 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 {
  position: fixed;
  right: 2.5vw;
  bottom: 2.5vh;
}

.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;
}

@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;
  }
}
