/*
 * The arrivals list on a stop page.
 *
 * The markup is produced by /js/render-arrivals.js — in the worker for the
 * page's first paint, in the browser as the times tick over — so every class
 * here is written by that module.
 */

.arrivals {
  padding-block: 1rem;
}

.arrivals-none {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-muted);
  font-size: 1.0625rem;
}

/*
 * Shown only once the times on screen are old enough to mislead — offline, or
 * a worker that has stopped writing. /js/arrivals.js decides.
 */
.arrivals-stale {
  margin-bottom: 0.75rem;
  padding: 0.625rem 1rem;
  border: 1px solid color-mix(in srgb, var(--status-warn) 40%, transparent);
  border-radius: var(--r-md);
  background-color: color-mix(in srgb, var(--status-warn) 14%, transparent);
  color: var(--status-warn);
  font-size: 0.875rem;
  font-weight: 600;
}

/*
 * Written before the first arrival on each new day, and sticky so that a rider
 * scrolled deep into tomorrow can still see which day they are reading. That is
 * the whole job, and it is why the day is not repeated on every card.
 */
.arrivals-day {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-block: 1.25rem 0.75rem;
  padding-block: 0.375rem;
  background-color: var(--bg);
  color: var(--text-muted);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;

  /*
   * Out to the edge of the container's gutter and back in again. A card's
   * shadow spills a couple of pixels past its sides, and where that spill met
   * the ends of the rule — one card above, one below — it read as two serifs,
   * making the divider look like a very wide letter H. Bleeding the divider's
   * own background over the gutter hides the spill at this height, including
   * while the divider is pinned and cards are sliding under it, and the extra
   * inline padding keeps the rules clear of the cards' rounded corners.
   *
   * The 1rem is .container's horizontal padding, in app.css.
   */
  margin-inline: -1rem;
  padding-inline: 2rem;
}

/*
 * The staleness notice is always the first thing the renderer emits, so this is
 * the divider that opens the list — late at night, when every row is tomorrow's.
 * There is nothing above it to be separated from.
 */
.arrivals-stale + .arrivals-day {
  margin-top: 0;
}

/* A rule on each side, so the day sits in the middle of the break. */
.arrivals-day::before,
.arrivals-day::after {
  content: "";
  flex: 1;
  height: 1px;
  background-color: var(--border);
}

/*
 * The card is a link — to the trip it is a row of, so a rider can see where
 * this bus goes after here. `display: block` is what makes it still a card: an
 * anchor is inline by default, and an inline box ignores the vertical padding
 * and lets the accent stripe run the height of the whole list.
 */
.arrival {
  display: block;
  position: relative;
  margin-bottom: 0.75rem;
  padding: 0.875rem 1rem 0.875rem 1.25rem;
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  color: inherit;
  text-decoration: none;
}

/* Enough to say it can be pressed, without turning a list into a row of buttons. */
.arrival:hover,
.arrival:focus-visible {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-2);
}

/* The route's color as a stripe down the leading edge of the card */
.arrival::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 6px;
  background-color: var(--route-color);
}

/*
 * A near-white route color is invisible against a light surface, so the stripe
 * is dropped there. In dark mode it reads fine and is kept.
 */
:root[data-theme="light"] .arrival[data-too-light="true"]::before {
  display: none;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .arrival[data-too-light="true"]::before {
    display: none;
  }
}

.arrival-route {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 1.0625rem;
  font-weight: 600;
}

.arrival-route-name {
  color: var(--route-color);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* Too-light route colors are unreadable as text, so fall back to body text */
.arrival[data-too-light="true"] .arrival-route-name {
  color: var(--text);
}

.arrival-headsign {
  font-weight: 500;
}

/* The bus ends its run here; there is no destination to name. */
.arrival-ends {
  font-style: italic;
  color: var(--text-muted);
}

.arrival-times {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.5rem;
  font-variant-numeric: tabular-nums;
}

/*
 * The one icon that is a background rather than an <svg>: the renderer has to
 * run in Node as well as the browser, so it emits no markup it cannot escape,
 * and a decorative arrow belongs in the stylesheet anyway. Material Symbols
 * arrow_right_alt — see NOTICE.
 */
.arrival-arrow {
  width: 20px;
  height: 20px;
  flex: none;
  background-color: var(--text-muted);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='m560-240-56-58 142-142H160v-80h486L504-662l56-58 240 240-240 240Z'/%3E%3C/svg%3E")
    no-repeat center / contain;
}

.arrival-time-superseded {
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  font-style: italic;
  color: var(--text-muted);
}

.arrival-status {
  margin-left: 0.375rem;
  padding: 0.0625rem 0.5rem;
  border: 1px solid;
  border-radius: var(--r-pill);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  white-space: nowrap;

  color: var(--status-color);
  border-color: color-mix(in srgb, var(--status-color) 40%, transparent);
  background-color: color-mix(in srgb, var(--status-color) 14%, transparent);
}

.arrival-status[data-status="ok"] {
  --status-color: var(--status-ok);
}
.arrival-status[data-status="late"] {
  --status-color: var(--status-late);
}
.arrival-status[data-status="early"] {
  --status-color: var(--status-early);
}
.arrival-status[data-status="warn"] {
  --status-color: var(--status-warn);
}
.arrival-status[data-status="idle"] {
  --status-color: var(--status-idle);
}

.arrival-countdown {
  margin-top: 0.25rem;
  color: var(--text-muted);
  font-size: 0.9375rem;
}

/*
 * Enter and exit animations. Only rows the browser adds or removes carry these
 * classes — a row that is merely updated keeps its element, so nothing
 * re-animates when a countdown ticks over.
 */

.arrival.is-entering {
  animation: arrival-expand 0.35s ease;
}

.arrival.is-leaving {
  animation: arrival-collapse 0.4s ease forwards;
  pointer-events: none;
  overflow: hidden;
}

@keyframes arrival-expand {
  from {
    opacity: 0;
    transform: translateY(-0.5rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes arrival-collapse {
  from {
    opacity: 1;
    /* Comfortably taller than any card, so the height animates the whole way */
    max-height: 16rem;
  }
  to {
    opacity: 0;
    max-height: 0;
    transform: translateY(-0.25rem);
  }
}
