:root {
  --bg: #f6f7f9;
  --panel: #ffffff;
  --line: #e3e6ea;
  --ink: #14171a;
  --muted: #6b7280;
  --accent: #2563eb;
  --shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .04);
  --ok-bg: #dcfce7;
  --ok-ink: #15803d;
  --warn-bg: #fee2e2;
  --warn-ink: #b91c1c;
  --idle-bg: #eceef1;
  --idle-ink: #6b7280;
  --caution-bg: #fce9ab;
  --caution-ink: #7c4a03;
  --caution-line: #dcbc57;
  /* Operating frequency. Aqua because it must not be mistaken for a car type: the
     timeline above is blue for 3-car and red for 4-car. Checked with the
     dataviz palette validator against both, on both surfaces - violet failed in
     dark mode (deltaE 1.9 under protanopia against the 3-car blue).
     Lives on :root, not #timeline: the wait chart is a sibling of it. */
  --freq: #15916a;
  --freq-soft: rgba(21, 145, 106, .18);
  --freq-grid: rgba(20, 23, 26, .10);
  --car3: #2a78d6;
  --car4: #e34948;
  --now: #e5484d;
  --flash: #e3edfd;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0e1116;
    --panel: #161b22;
    --line: #262c36;
    --ink: #e6edf3;
    --muted: #8b949e;
    --accent: #58a6ff;
    --shadow: none;
    --ok-bg: #14301f;
    --ok-ink: #4ade80;
    --warn-bg: #3d1a1a;
    --warn-ink: #f87171;
    --idle-bg: #21262d;
    --idle-ink: #8b949e;
    --caution-bg: #3a2f13;
    --caution-ink: #f0c765;
    --caution-line: #6d5518;
    --freq: #199e70;
    --freq-soft: rgba(25, 158, 112, .22);
    --freq-grid: rgba(230, 237, 243, .11);
    --car3: #3987e5;
    --car4: #e66767;
    --now: #ff6369;
    --flash: #17293f;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0 auto;
  padding: 24px 16px 64px;
  max-width: 900px;
  background: var(--bg);
  color: var(--ink);
  /* Thai fonts first for Thai glyphs; Latin falls through to the system UI face.
     1.65 rather than 1.5 because Thai stacks vowels and tone marks above and
     below the baseline, and they collide at Latin line spacing. */
  font: 15px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Noto Sans Thai", "IBM Plex Sans Thai", Thonburi, Tahoma, sans-serif;
  -webkit-font-smoothing: antialiased;
}

section + section { margin-top: 32px; }

/* --- header --------------------------------------------------------------- */

header { margin-bottom: 24px; }

.titlebar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}

header h1 {
  margin: 0;
  font-size: 21px;
  font-weight: 650;
  letter-spacing: -.01em;
}

.langs {
  display: inline-flex;
  flex: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 2px;
}

.lang {
  border: 0;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  line-height: 1.4;
  padding: 3px 10px;
  border-radius: 6px;
  cursor: pointer;
}

.lang.is-active {
  background: var(--accent);
  color: #fff;
  font-weight: 550;
}

header .meta {
  display: flex;
  align-items: center;
  gap: 8px 14px;
  flex-wrap: wrap;
  margin: 0;
  font-size: 13px;
  color: var(--muted);
}

#system-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 550;
}

#system-status .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--muted);
}

#system-status.is-online { color: var(--ok-ink); }
#system-status.is-online .dot { background: var(--ok-ink); }
#system-status.is-offline { color: var(--warn-ink); }
#system-status.is-offline .dot { background: var(--warn-ink); }

header .disclaimer {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 12px 0 0;
  padding: 10px 13px;
  border: 1px solid var(--caution-line);
  border-radius: 9px;
  background: var(--caution-bg);
  color: var(--caution-ink);
  font-size: 12px;
  line-height: 1.45;
}

header .disclaimer p { margin: 0; }

/* block-level so the lead sentence owns its own line without a <br> */
header .disclaimer strong {
  display: block;
  font-weight: 650;
}

header .disclaimer svg {
  width: 15px;
  height: 15px;
  flex: none;
  margin-top: 2px;      /* optical alignment with the first line of text */
}

/* --- section 1: last 60 minutes ------------------------------------------ */

.cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

@media (max-width: 640px) {
  .cards { grid-template-columns: 1fr; }
}

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 20px;
  box-shadow: var(--shadow);
}

.card p { margin: 0; }

.card .dir {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--muted);
}

.card .unit {
  margin-bottom: 6px;
  color: var(--muted);
  font-size: 13px;
}

.card .count {
  display: flex;
  align-items: baseline;
  gap: 7px;
  line-height: 1;
}

.card .count .value {
  font-size: 48px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.card .count .suffix {
  font-size: 15px;
  font-weight: 500;
  color: var(--muted);
}

.card .headway {
  margin-top: 8px;
  color: var(--muted);
  font-size: 13px;
}

.card .last {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 13px;
}

.card .last b { font-variant-numeric: tabular-nums; font-weight: 600; }

/* Service status for THIS direction. Never dim the figures to signal it - the
   counts are real regardless, and a faded number is just a harder-to-read one. */
.card .badge {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  vertical-align: 2px;
  background: var(--idle-bg);
  color: var(--idle-ink);
}

/* a pass just landed on this card - a short wash that decays back to the
   panel colour, so it reads as "something arrived" without demanding action */
@keyframes pass-flash {
  0%   { background: var(--flash); border-color: var(--accent); }
  100% { background: var(--panel); border-color: var(--line); }
}

.card.is-new { animation: pass-flash 1.6s ease-out; }

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

.card .badge.is-normal   { background: var(--ok-bg);   color: var(--ok-ink); }
.card .badge.is-abnormal { background: var(--warn-bg); color: var(--warn-ink); }

/* --- section 2: history --------------------------------------------------- */

/* hairline above the row, so the rule reads as the boundary between the live
   panel and the historical one rather than as decoration under a heading */
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}

.section-title {
  margin: 0;
  font-size: 15px;
  font-weight: 650;
  letter-spacing: -.005em;
}

.controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  /* clear of the frequency legend directly above: the toggle belongs to the
     table below it, and butted against the legend it reads as part of the
     chart. Same 22px the other section breaks use. */
  margin-top: 22px;
  margin-bottom: 12px;
}

.tabs {
  display: inline-flex;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 3px;
}

.tab {
  border: 0;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  padding: 6px 16px;
  border-radius: 7px;
  cursor: pointer;
}

.tab.is-active {
  background: var(--accent);
  color: #fff;
  font-weight: 550;
}

.daynav {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.daynav button {
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  font-size: 16px;
  line-height: 1;
  width: 30px;
  height: 30px;
  border-radius: 7px;
  cursor: pointer;
}

.daynav button:disabled { opacity: .35; cursor: default; }

#day-label {
  min-width: 130px;
  text-align: center;
  font-size: 14px;
  color: var(--muted);
}

/* keep the title and the stepper on one line on a phone rather than wrapping */
@media (max-width: 430px) {
  #day-label { min-width: 92px; }
}

/* --- timeline (service-uptime style status map) --------------------------- */

/* An empty 6-minute bin is NORMAL service at a ~10-minute headway, so empty is
   recessive gray, never a red "outage". Occupied bins take steps from one blue
   sequential ramp because the encoded quantity is a COUNT, not a state.
   Validated ordinal in both modes with the dataviz validator. */
#timeline {
  --tl-empty: #eceef1;
  --tl-1: #5598e7;
  --tl-2: #256abf;
  --tl-3: #0d366b;
  /* the marks lane: a white track with a 15-minute ruler. Separate tokens from
     --tl-empty because on the dark theme "white" has to become a recessed
     surface or the lane disappears into the card behind it. */
  --tl-track: #ffffff;
  --tl-track-edge: #e3e6ea;
  --tl-rule15: rgba(20, 23, 26, .14);
  --tl-rule60: rgba(20, 23, 26, .30);
  position: relative;
  margin-bottom: 18px;
}

@media (prefers-color-scheme: dark) {
  #timeline {
    --tl-empty: #21262d;
    --tl-track: #0d1218;
    --tl-track-edge: #262c36;
    --tl-rule15: rgba(230, 237, 243, .13);
    --tl-rule60: rgba(230, 237, 243, .28);
    /* on a dark surface "more" must read as brighter, so the ramp inverts */
    --tl-1: #1c5cab;
    --tl-2: #2a78d6;
    --tl-3: #6da7ec;
  }
}

.tl-rows { display: flex; align-items: flex-start; gap: 10px; }

/* labels live OUTSIDE the scroll container so they stay put while it scrolls */
.tl-labels {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 2px;
}

.tl-label {
  height: 30px;
  display: flex;
  align-items: center;
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}

/* one scroll container for both rows AND the axis, so they cannot drift apart */
.tl-scroll {
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  /* overflow-y: hidden clips at the PADDING box, so the marker head needs real
     padding to live in - without it the triangle was cut off by the bin row */
  overflow-y: hidden;
  padding-top: 9px;
  padding-bottom: 4px;
}

/* the labels must drop by the same 9px or they stop lining up with the rows */
.tl-labels { padding-top: 11px; }

.tl-track { display: inline-block; min-width: 100%; position: relative; }

/* the clock hand: a hairline sitting in the 2px gutter between two bins, with a
   downward pointer above it so it reads as "here" rather than as a gridline.
   A real 2px-wide box with a background, NOT border-left on a zero-width box:
   an absolutely positioned ::before resolves against the PADDING box, which on
   a bordered element starts after the border - so the head sat 2px right of its
   own line. With a background the padding box is the line, and 50%/-50% centres. */
#tl-now {
  position: absolute;
  top: -9px;                       /* the 9px the head needs, see .tl-scroll */
  width: 2px;
  /* head + both rows + whatever sits between them. Derived, not hardcoded: the
     gap grows when the links are shown, and a fixed 75px left the hand stopping
     short of the lower row exactly when there was more to point at. */
  height: calc(9px + 30px + var(--tl-gap) + 30px);
  background: var(--now);
  pointer-events: none;
  z-index: 3;
}

#tl-now[hidden] { display: none; }

#tl-now::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 9px solid var(--now);
}

.tl-row {
  display: flex;
  gap: 2px;                 /* the 2px surface gap between adjacent fills */
  height: 30px;
  align-items: flex-end;
  margin-bottom: 6px;
  cursor: crosshair;
}

/* every bin is the same size - occupancy and count are carried by colour depth
   and the printed digit, not by geometry */
.tl-bin {
  flex: none;
  border-radius: 2px;
  background: var(--tl-empty);
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 700;
  color: #fff;
  line-height: 1;
  overflow: hidden;
}

.tl-bin.on    { background: var(--tl-2); }   /* occupied, type not judged */
.tl-bin.on.c3 { background: var(--car3); }
.tl-bin.on.c4 { background: var(--car4); }
.tl-bin.on.cu { background: var(--tl-empty); outline: 1px solid var(--tl-2);
                outline-offset: -1px; }

.tl-bin.is-hit { outline: 2px solid var(--ink); outline-offset: 1px; }

/* --- marks: each pass at its true minute ---------------------------------- */
/* Same lane, same width, same mark size as a bin - only the placement changes,
   so nothing else in the timeline's geometry has to move. */
.tl-row.marks {
  display: block;
  position: relative;
  border-radius: 2px;
  background-color: var(--tl-track);
  /* One hairline per layer; the repeat period and the phase are set in JS from
     the real window and bin_px, because neither is a constant. The window opens
     at 05:30, so an hour layer starting at x=0 would put every "hour" line on a
     half hour - it has to be shifted to the first whole hour. */
  background-image:
    linear-gradient(to right, var(--tl-rule60) 0 1px, transparent 1px),
    linear-gradient(to right, var(--tl-rule15) 0 1px, transparent 1px);
  background-repeat: repeat-x;
  box-shadow: inset 0 0 0 1px var(--tl-track-edge);
}

.tl-mark {
  position: absolute;
  top: 0;
  height: 100%;
  border-radius: 2px;
  background: var(--tl-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 700;
  color: #fff;
  line-height: 1;
  overflow: hidden;
}

.tl-mark.c3 { background: var(--car3); }
.tl-mark.c4 { background: var(--car4); }
/* hollow would be white-on-white here, so it takes the lane's own surface */
.tl-mark.cu { background: var(--tl-track); outline: 1px solid var(--tl-2);
              outline-offset: -1px; color: var(--ink); }
/* .tl-mark sets color:#fff for the digit, so currentColor would be invisible */
.tl-mark.cluster { outline: 1.5px solid var(--ink); outline-offset: 1.5px; }
.tl-mark.is-hit  { outline: 2px solid var(--ink); outline-offset: 1px; }

/* --- linking a train to its return trip ----------------------------------- */
/* Off by default, so the rows sit at their normal 6px. Switching the links on is
   what buys them room: a 23-minute link is only ~44px long, and across a 6px gap
   it would be near-horizontal and unreadable where links cross. */
/* the UA stylesheet's [hidden] rule is namespaced to HTML, so it does not match
   an <svg> - without this the attribute is set and nothing happens */
#tl-links[hidden] { display: none; }
#tl-links { position: absolute; left: 0; overflow: visible; pointer-events: none; }
.tl-link { fill: none; stroke-width: 1.25; opacity: .45; stroke: var(--tl-2); }
.tl-link.c3 { stroke: var(--car3); }
.tl-link.c4 { stroke: var(--car4); }
/* a fast pass is back in half the time, so its link is half as long - dashing it
   says that is the reason, rather than leaving it to look like a drawing error */
.tl-link.fast { stroke-dasharray: 3 2; opacity: .7; }

#timeline { --tl-gap: 6px; }
#timeline.links-on { --tl-gap: 34px; }
.tl-row[data-dir="outbound"] { margin-bottom: var(--tl-gap); }
/* the label column already carries a 6px flex gap, so it needs the remainder */
.tl-label[data-dir="outbound"] { margin-bottom: calc(var(--tl-gap) - 6px); }

/* --- correcting a pairing by hand ----------------------------------------- */
#timeline.can-correct .tl-mark { cursor: pointer; }
.tl-mark.is-sel  { outline: 3px solid var(--accent); outline-offset: 2px; z-index: 4; }
/* the legal partners for whatever is selected: the same shortlist the matcher
   had, so a correction is a choice rather than a guess */
.tl-mark.is-cand { box-shadow: 0 0 0 2px var(--panel), 0 0 0 4px var(--accent); }
#timeline.arming .tl-mark:not(.is-cand):not(.is-sel) { opacity: .35; }
/* a pairing a person made, which the matcher must not undo */
.tl-mark.is-manual::after {
  content: ""; position: absolute; left: 50%; bottom: -7px;
  transform: translateX(-50%); width: 5px; height: 5px;
  border-radius: 50%; background: var(--accent);
}
.tl-link.manual { stroke: var(--accent); opacity: .95; stroke-width: 2; }
.tl-link.manual.odd { stroke-dasharray: 5 3; }
.linkclear {
  font: inherit; font-size: 11px; color: var(--muted); background: none;
  border: 1px solid var(--line); border-radius: 6px; padding: 1px 8px;
  margin-left: 8px; cursor: pointer;
}
.linkclear:hover { color: var(--ink); }

.tl-opt {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; color: var(--muted); cursor: pointer; margin-top: 2px;
}
.tl-opt .note { margin: 0; font-variant-numeric: tabular-nums; }

/* --- operating frequency --------------------------------------------------------- */
/* positioned: the tooltip is absolute and measures against this box, so
   without it the popup lands wherever the nearest positioned ancestor is */
#freq { margin-top: 22px; position: relative; }
#freq.is-empty { display: none; }


/* two side by side when the viewport can hold them, stacked when it cannot.
   auto-fit rather than a breakpoint, so it also works inside a narrow column */
.freq-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px;
  margin-top: 10px;
}

.freq-card { margin: 0; }
.freq-card figcaption {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; font-size: 12px; color: var(--muted); margin-bottom: 5px;
}
.freq-card .wc-name { color: var(--ink); font-weight: 600; }
.freq-card .wc-unit { margin-right: auto; }
.freq-card .wc-stat { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* A gutter down the left for the y-axis numbers. They used to sit ON the plot
   at left:0, painted over the bars with a panel-coloured background to stay
   readable - which meant the first bar or two of every chart was hidden behind
   a number. The plot now starts to the right of them instead. */
.freq-card { --fp-gutter: 24px; }
.freq-plot { position: relative; height: 74px; }
.fp-grid, .fp-mean { position: absolute; left: var(--fp-gutter); right: 0; height: 0; }
/* the average line paints over the bars, so it must not eat the hover */
.fp-mean { pointer-events: none; }
.fp-grid   { border-top: 1px solid var(--freq-grid); }
.fp-grid::before {
  content: attr(data-v);
  /* right:100% hangs it off the left end of its own gridline, so it lands in
     the gutter and stays right-aligned against the axis whatever its width */
  position: absolute; right: 100%; top: -0.5em;
  font-size: 9px; line-height: 1; color: var(--muted);
  padding-right: 4px; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* dashed, in the bars' own colour: this day's average, so it reads as belonging
   to the data rather than being another fixed rule */
.fp-mean   { border-top: 1px dashed var(--freq); opacity: .85; }

/* bars share the row by flex, so the chart reflows with the column and needs no
   pixel maths or resize handler */
.fp-bars { position: absolute; inset: 0; left: var(--fp-gutter);
           display: flex; gap: 1px; align-items: flex-end; }
.fs { position: relative; flex: 1 1 0; height: 100%; min-width: 0; cursor: crosshair; }
.fb {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--freq); border-radius: 2px 2px 0 0;
}
/* a bin after the last train has no answer; a zero-height bar would claim the
   wait was nothing, which is the opposite of true */
.fs-none::after {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(45deg,
    var(--freq-grid) 0 1px, transparent 1px 5px);
}
.fs:hover .fb, .fs.is-hit .fb { outline: 2px solid var(--ink); outline-offset: 1px; }

.fb-lab {
  position: absolute; left: 50%; transform: translateX(-50%);
  margin-bottom: 3px; font-size: 9px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; pointer-events: none;
}

/* the hour ticks are placed by percentage, so the axis must span exactly the
   same width as the bars or every tick drifts left of the bar it names */
.freq-axis { position: relative; height: 14px; margin-top: 2px;
             margin-left: var(--fp-gutter); }
.freq-axis span {
  position: absolute; top: 0; transform: translateX(-50%);
  font-size: 10px; color: var(--muted);
}

.freq-legend {
  display: flex; flex-wrap: wrap; gap: 14px; margin-top: 8px;
  font-size: 11px; color: var(--muted);
}
.freq-legend i { display: inline-block; width: 10px; height: 10px; margin-right: 5px;
  vertical-align: -1px; border-radius: 2px; }
.freq-legend .sw-bar    { background: var(--freq); }
.freq-legend .sw-mean   { height: 0; width: 14px; border-top: 1px dashed var(--freq);
                          border-radius: 0; vertical-align: 3px; }
.freq-legend .sw-none   { background: repeating-linear-gradient(45deg,
                            var(--freq-grid) 0 1px, transparent 1px 4px);
                          box-shadow: inset 0 0 0 1px var(--line); }

#freq-tip {
  position: absolute; z-index: 6; pointer-events: none;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 7px 10px; box-shadow: var(--shadow); font-size: 12px; min-width: 140px;
}
#freq-tip .r { display: flex; justify-content: space-between; gap: 14px;
  color: var(--muted); }
#freq-tip .r span:last-child { color: var(--ink); font-weight: 600;
  font-variant-numeric: tabular-nums; }

.tl-axis { position: relative; height: 16px; }

.tl-tick {
  position: absolute;
  top: 0;
  font-size: 10px;
  color: var(--muted);
  transform: translateX(-50%);
  white-space: nowrap;
}

.tl-tick::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -4px;
  height: 3px;
  border-left: 1px solid var(--line);
}


#tl-note { margin: 6px 0 0; }

#tl-tip {
  position: absolute;
  z-index: 15;
  min-width: 150px;
  padding: 8px 11px;
  border-radius: 8px;
  background: var(--ink);
  color: var(--bg);
  font-size: 12px;
  line-height: 1.5;
  pointer-events: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .3);
}

#tl-tip[hidden] { display: none; }
#tl-tip b { font-weight: 650; }
#tl-tip .tl-tip-row { font-variant-numeric: tabular-nums; white-space: nowrap; }

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
}

th, td {
  text-align: left;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
}

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

th {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--muted);
}

/* No fixed width: "กม./ชม." is materially wider than "km/h", so a px width that
   fits one language wraps the other. width:1% shrink-wraps the column to its
   content and hands the remaining space to the evidence column. */
.c-time, .c-gap, .c-speed, .c-cars { width: 1%; white-space: nowrap; }

td.c-time, td.c-gap, td.c-speed, td.c-cars { font-variant-numeric: tabular-nums; }

td.c-gap { color: var(--muted); }
/* the gap unit shrinks to a short form on narrow screens (see the 600px block) */
td.c-gap .u-short { display: none; }

td.c-ev { padding: 6px 14px; }

.table-wrap { overflow-x: auto; }

/* the ROI is ~5.9:1, so a 220px-wide crop is a ~38px strip - it sits as a row */
td.c-ev img {
  display: block;
  width: 220px;
  border-radius: 4px;
  border: 1px solid var(--line);
  cursor: zoom-in;
  background: var(--bg);
}

td.c-ev .none { color: var(--muted); font-size: 13px; }

/* The thumbnail alone is wider than a phone can spare once time, gap and speed
   have taken their share, so below this width it becomes a button that opens the
   same lightbox. Done in CSS rather than by measuring the viewport in JS, so
   rotating the phone is handled without re-rendering the table. */
td.c-ev .ev-btn { display: none; }

@media (max-width: 600px) {
  td.c-ev img { display: none; }

  td.c-ev .ev-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--bg);
    color: var(--muted);
    cursor: zoom-in;
  }

  td.c-ev .ev-btn svg { width: 17px; height: 17px; }

  th, td { padding: 9px 10px; }
  .c-ev { width: 1%; }

  /* "min" -> "m", "นาที" -> "น." to keep the gap column narrow */
  td.c-gap .u-long { display: none; }
  td.c-gap .u-short { display: inline; }

  /* claw back width from the cars column: tighten the speed->cars gap and slim
     the badge so the whole table fits without horizontal scroll */
  th.c-speed, td.c-speed { padding-right: 4px; }
  th.c-cars, td.c-cars { padding-left: 4px; padding-right: 8px; }
  td.c-cars .cars { min-width: 0; padding: 1px 5px; }
}

#empty {
  margin: 16px 2px;
  color: var(--muted);
  font-size: 14px;
}

/* --- lightbox ------------------------------------------------------------- */

/* an explicit display value beats the UA stylesheet's [hidden] { display: none },
   so the attribute has to be handled here or the overlay never goes away */
#lightbox[hidden] { display: none; }

#lightbox {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, .8);
  cursor: zoom-out;
  z-index: 10;
}

#lightbox img {
  max-width: 100%;
  max-height: 100%;
  border-radius: 6px;
}

/* car count: the colour matches the timeline so the two read as one encoding,
   and the digit means identity never rests on colour alone */
td.c-cars { text-align: center; }
td.c-cars.none { color: var(--muted); }

.cars {
  display: inline-block;
  min-width: 22px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
}

.cars-3 { background: var(--car3); }
.cars-4 { background: var(--car4); }

.legend { display: flex; align-items: center; gap: 12px; font-size: 11px; color: var(--muted); }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 2px;
            margin-right: 5px; vertical-align: -1px; }

/* Site footer. Muted and quiet: it sits below the fold and must not compete with
   the data above. The body already reserves 64px of bottom padding. */
footer {
  margin-top: 32px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  text-align: center;
  font-size: 12px;
  color: var(--muted);
}
