/* Shared flight-table vocabulary for /zboruri/ and its route pages. This sheet
   loads after site.css; the board's inline styles load after it and own its
   reflow and day-toggle padding. Route-only rules stay under .route-page so
   their mobile reflow cannot catch the board between its breakpoints — the two
   reflows hand-mirror one two-line row anatomy, detailed at each block. The
   complete tone set is needed because live rows surface states absent from a
   freshly seeded route page. */

/* ── shared: topbar ─────────────────────────────────────────────────────── */

/* Override site.css's auto margin and trim the 1rem topbar gap to 0.6rem. */
.topbar-meta {
  margin-left: auto;
  margin-right: -0.4rem;
}

.resource-nav {
  margin-left: 0;
}

/* ── shared: table shell ────────────────────────────────────────────────── */

.table-wrap {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel), var(--shadow-edge);
  overflow: hidden;
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
}

/* Shared columns; each page owns its extra columns and width deviations. */
.col-time {
  width: 8rem;
}

.col-flight {
  width: 7rem;
}

.col-status {
  width: 10rem;
}

th.col-status-cell {
  text-align: center;
  padding-right: calc(var(--space-4) + 3.2rem);
}

td.col-status-cell {
  text-align: center;
}

thead th {
  font-size: var(--fs-micro);
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 500;
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  background: var(--surface-muted);
}

tbody td {
  padding: 0.78rem var(--space-4);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-body);
}

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

/* Flex spacing and middot offset for both mobile reflows. Declared here, unread
   on desktop, so the two hand-mirrored blocks can't drift. */
tbody tr {
  --cell-gap: 0.35rem;
}

/* ── shared: times and flight numbers ───────────────────────────────────── */

.flight-num {
  font-family: var(--font-mono);
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}

.time {
  font-family: var(--font-mono);
  font-size: 1.02rem;
  font-weight: 600;
  white-space: nowrap;
}

/* Inline everywhere — both mobile reflows keep the struck pair on the scan
   line rather than restacking it. */
.time-pair {
  display: inline-flex;
  align-items: baseline;
  gap: 0.34rem;
  white-space: nowrap;
}

.time.superseded {
  font-weight: 500;
  font-size: 0.82rem;
  color: var(--text-faint);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

/* Mango only for a late completion — the row writers gate this on the
   status-completed-late pill, so the two can't disagree. */
.time.is-late {
  color: var(--badge-mango-text);
}

/* A predicted touchdown for a flight still airborne, gated on the en-route
   pill (IasiFlights.timeCell). Mango because it means what every other mango
   here means — this row is running late — but never the .time weight or size:
   a forecast must not read as heavily as the measured time beside it. The ~ the
   writer prefixes carries the "approximately", and survives where colour can't.

   NO underline or bottom rule. A border-bottom stair-steps ~3px off the
   .place-link beside it on the mobile reflow, where time and city share a line;
   text-decoration lands them flush, which is worse — here an underline IS the
   link affordance, so a flush-underlined ~18:37 reads as a sibling link to
   ROMA. */
.time.is-estimate {
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--badge-mango-text);
}

/* ── shared: status pills, tones, delta chip ────────────────────────────── */

/* One chip anatomy for the status pill and the delta beside it. Every writer
   emits .flight-status and .status-text on the same span, so the pill's half is
   keyed on the former; uppercase stays off the delta, its content a number. */
.flight-status,
.flight-delta {
  display: inline-flex;
  align-items: center;
  min-height: 1.35rem;
  padding: 0.12rem 0.42rem;
  border: 1px solid transparent;
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1;
  color: var(--text-muted);
  white-space: nowrap;
}

.flight-status {
  text-transform: uppercase;
}

/* Boxed tones share the ATERIZAT width; min-width still lets longer labels
   grow. Scheduled and Neconfirmat remain borderless and content-sized. */
.status-text:not(.status-scheduled) {
  min-width: 4.8rem;
  justify-content: center;
}

.status-landed,
.status-departed {
  border-color: var(--badge-green-text);
  background: var(--badge-green-bg);
  color: var(--badge-green-text);
}

.status-completed-late {
  border-color: var(--badge-mango-text);
  background: var(--badge-mango-bg);
  color: var(--badge-mango-text);
}

.status-enroute {
  border-color: var(--badge-cool-text);
  background: var(--badge-cool-bg);
  color: var(--badge-cool-text);
}

.status-disrupted {
  border-color: var(--badge-red-text);
  background: var(--badge-red-bg);
  color: var(--badge-red-text);
}

/* A diverted flight operated elsewhere, so violet distinguishes it from a
   red cancellation and avoids making mass diversions read as cancellations. */
.status-diverted {
  border-color: var(--badge-violet-text);
  background: var(--badge-violet-bg);
  color: var(--badge-violet-text);
}

/* Owns the pill↔delta gap for every placement: the reflows below re-point the
   display, never this rhythm. */
.status-block {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

/* These tracks plus that gap exactly fill the status column's 8rem content box
   (4.8 + 0.3 + 2.9). Borderless labels may overflow the first track
   symmetrically while staying on the pills' centre axis. */
td.col-status-cell .status-block {
  display: inline-grid;
  grid-template-columns: 4.8rem 2.9rem;
  justify-items: center;
  align-items: center;
}

.flight-delta {
  border-color: var(--border-strong);
  /* The three-digit track sits on the chip, not per placement: a delta is only
     ever emitted inside a .status-block, so every context wants it. */
  justify-content: center;
  min-width: 2.9rem;
}

/* Recede past rows with background only; their real data keeps full contrast.
   A whisper, because the 1px divider is all that separates rows: at full
   --surface-muted it fell from 1.31:1 to 1.15:1. On the row, not its cells —
   both mobile reflows stop the cells filling the row. */
.past-row {
  background: color-mix(in srgb, var(--surface-muted) 42%, var(--surface));
}

/* Pages own day-band padding: the board pads .day-toggle; routes pad the cell. */
.day-separator td {
  background: var(--surface-muted);
  color: var(--text-faint);
  font-size: var(--fs-micro);
  font-weight: 700;
  text-transform: uppercase;
}

/* Closing edge for a foldable day group. On the PRECEDING row's border, not a
   border-top on the band: under border-collapse a shared edge resolves in
   favour of the cell above. Gated on .day-toggle so it lands only where a day
   can fold — route pages, always open, separate days by the band's tone. */
tbody tr:has(+ .day-separator .day-toggle) td {
  border-bottom-color: var(--border-strong);
}

/* The same edge for the board's mobile reflow, where the row carries the
   border. Inert on desktop (no row border) and on route pages (no .day-toggle). */
tbody tr:has(+ .day-separator .day-toggle) {
  border-bottom-color: var(--border-strong);
}

.empty-state {
  padding: var(--space-6);
}

/* ── shared: notes, a11y ────────────────────────────────────────────────── */

.tz-note {
  margin: var(--space-3) 0 0;
  padding: 0 var(--space-1);
  color: var(--text-faint);
  font-size: var(--fs-meta);
}

.tz-note-icon {
  margin-right: 0.25em;
  font-size: 0.9em;
  opacity: 0.75;
}

/* Visually hidden, exposed to assistive technology. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── shared: route links ────────────────────────────────────────────────── */

/* Both flight surfaces carry one: /zboruri/ lists every route page, a route
   page lists its siblings. Prerendered from the discovered set on both sides
   (PRERENDER:flights-route-links / PRERENDER:route-siblings), so it is one
   component with two headings rather than two lists — hence the unscoped tier.
   It exists because the board's other link to a route page, the .place-link in
   a table row, renders only while that route has a flight in the five-day
   window: a seasonal pause left the page with no crawlable path in at all. */
.route-links {
  margin: var(--space-6) 0 0;
}

/* The quiet section-label pair, shared with the board's five .stats-head blocks
   rather than copied from them — a nav to other pages must not outrank the data
   sections around it, and one rule is what keeps that true. Not the .display-h
   the .about/.faq headings take. The board's inline block keeps only its own
   ≤560px .stats-sub override. */
.route-links-title,
.stats-head h2 {
  color: var(--text-muted);
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.2;
}

.route-links-sub,
.stats-sub {
  margin-top: 2px;
  color: var(--text-faint);
  font-size: 0.78rem;
}

/* Equal columns rather than chips that hug their labels: content-width left a
   ragged right edge and, at six routes, one chip stranded on its own row.
   auto-fit, not a fixed count, so the board (6 routes) and a route page (5) each
   fill their row without a number here going stale as routes are added. 8rem
   lands 6 columns in the 848px page, ~12px clear of today's widest chip; a
   destination longer than "București" needs 8.5rem, dropping it to 5. */
.route-links ul {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

/* Destination and code pushed to opposite edges: equal columns leave slack inside
   the chip, and spending it between the two makes a second alignment column down
   the grid instead of dead space trailing the label. The padding is the hit area:
   at this size a text-only link would be a small target on a page otherwise made
   of rows. --radius-md, not a full pill — the Sosiri/Plecări
   control above is the real one. */
.route-links a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  height: 100%;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-body);
  font-weight: 600;
  text-decoration: none;
  transition: border-color var(--motion-fast), background-color var(--motion-fast), color var(--motion-fast);
}

.route-links a:hover,
.route-links a:focus-visible {
  border-color: var(--pill-active-border);
  background: var(--pill-active-bg);
  color: var(--accent);
}

/* The tone and mono face the board gives its .airport-code chips, so the same
   three letters read as the same kind of thing in both places. Deliberately not
   its size at every width: the board shrinks those chips under its mobile
   breakpoint because they ride a table row reflowing to the two-line ledger. */
.route-links .code {
  flex: none;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 400;
}

/* Phones: the columns go 1-up and spend a row per route, so the block would grow
   with every route page added. Here it becomes a two-row rail scrolling sideways
   — one height at any route count — bled past the page gutter so a cut chip, not
   a scrollbar, is the scroll cue. The bleed cancels .page's --space-5 by hand: if
   that gutter ever varies by width, this overflows the document instead.
   Its own tier, shared with neither host — the board reflows at 760px and a route
   page at 50rem; between there and here the columns simply re-fit. */
@media (max-width: 560px) {
  .route-links ul {
    /* Release the desktop tracks: explicit columns would be filled before the
       auto ones and the two-row flow would never take effect. */
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-template-rows: repeat(2, auto);
    grid-auto-columns: max-content;
    overflow-x: auto;
    /* overflow-x forces overflow-y to auto, which clips the focus ring off both
       rows — the rail carries the 2px outline + 2px offset itself. */
    padding-block: 4px;
    padding-inline: var(--space-5);
    margin-block: calc(var(--space-3) - 4px) -4px;
    margin-inline: calc(-1 * var(--space-5));
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .route-links ul::-webkit-scrollbar { display: none; }
}

/* ═══ route pages (.route-page) ═══════════════════════════════════════════ */

/* ── breadcrumb ─────────────────────────────────────────────────────────── */

.route-page .crumbs {
  margin-top: var(--space-4);
  font-size: var(--fs-meta);
  color: var(--text-faint);
}

.route-page .crumbs a { color: var(--text-muted); }

.route-page .crumbs .sep {
  margin: 0 0.45rem;
  color: var(--border-strong);
}

.route-page .crumbs [aria-current] { color: var(--text-faint); }

/* ── outage / staleness banner ──────────────────────────────────────────── */

/* site.css owns the .alert look; the board spaces it in its inline block,
   route pages here. */
.route-page .alert {
  margin-top: var(--space-6);
  margin-bottom: var(--space-4);
}

/* ── endpoint lockup ────────────────────────────────────────────────────── */

/* The route-wide endpoint view; tables use Iași time because that is all the
   feed provides. */
.route-page .lockup {
  display: grid;
  grid-template-columns: auto minmax(4rem, 1fr) auto;
  align-items: center;
  gap: var(--space-4);
  margin: var(--space-5) 0;
  padding: var(--space-4) var(--space-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel), var(--shadow-edge);
}

.route-page .endpoint .iata {
  display: block;
  font-family: var(--font-mono);
  font-size: 1.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--text);
}

.route-page .endpoint .city {
  display: block;
  margin-top: 0.3rem;
  font-size: var(--fs-meta);
  color: var(--text-muted);
}

.route-page .endpoint.to { text-align: right; }

.route-page .path {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
}

.route-page .path .block-time {
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.route-page .path-line {
  position: relative;
  width: 100%;
  height: 9px;
}

.route-page .path-line::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 50%;
  height: 1px;
  background: repeating-linear-gradient(
    to right,
    var(--border-strong) 0 4px,
    transparent 4px 8px
  );
}

.route-page .path-line .dot {
  position: absolute;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  border-radius: 50%;
  background: var(--surface);
  border: 1.5px solid var(--accent);
}

.route-page .path-line .dot.start { left: 0; }
.route-page .path-line .dot.end { right: 0; }

.route-page .path-line .plane {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  padding: 0 0.35rem;
  background: var(--surface);
  color: var(--accent);
  line-height: 0;
}

/* ── fact strip ─────────────────────────────────────────────────────────── */

/* Only facts supported by the five-day window. Terminal stays on each table
   heading because it differs by direction: T4 outbound, T3 inbound. */
.route-page .facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px;
  margin: 0 0 var(--space-5);
  padding: 0;
  list-style: none;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.route-page .facts li {
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
}

.route-page .facts .k {
  display: block;
  margin-bottom: 0.25rem;
  font-size: var(--fs-micro);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.route-page .facts .v {
  display: block;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text);
}

/* Hand-written prose — nothing renders this — and the only durable text on a
   page whose tables turn over daily. Take it from the live window rather than
   from a schedule file, and on a route whose window shows no repeatable
   pattern, drop the paragraph rather than guess. */
.route-page .pattern {
  margin: 0 0 var(--space-6);
  padding: var(--space-4) var(--space-5);
  border-left: 2px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 3.5%, var(--surface));
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  color: var(--text-muted);
  font-size: var(--fs-lead);
  line-height: 1.55;
}

.route-page .pattern strong { color: var(--text); }

/* ── direction sections ─────────────────────────────────────────────────── */

/* Space only adjacent directions so the last one does not push the .tz-note;
   .pattern supplies the gap above the first. */
.route-page .dir + .dir {
  margin-top: var(--space-6);
}

.route-page .dir-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-3);
}

/* Typography comes from site.css's h2.section-heading; only margin is local. */
.route-page .dir h2 {
  margin: 0;
}

.route-page .dir h2 .arrow {
  font-style: normal;
  margin: 0 0.15em;
  color: var(--text-faint);
}

.route-page .dir-meta {
  flex: 0 0 auto;
  font-size: var(--fs-meta);
  color: var(--text-faint);
}

.route-page .term {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--text-muted);
}

/* ── route table deviations ─────────────────────────────────────────────── */

/* Wide enough for the longest carrier name the feed publishes, uppercase and
   on one line — AUSTRIAN AIRLINES needs ~10rem including cell padding. The
   slack comes out of the aircraft column below, which runs far wider than its
   content. */
.route-page .col-airline { width: 11rem; }

/* Exactly one auto column absorbs slack under table-layout: fixed; without it,
   fixed widths scale proportionally and the shared Oră/Zbor/Stare anchors
   drift. Aircraft is the longest, most variable field and the route reflows
   before this column becomes too narrow. */
.route-page .col-craft { width: auto; }

/* Baseline-align textual cells, including a two-size .time-pair. Status stays
   middle-aligned because it contains pills rather than text. */
.route-page tbody td {
  vertical-align: baseline;
}

.route-page td.col-status-cell { vertical-align: middle; }

.route-page .day-separator td {
  padding: var(--space-3) var(--space-4);
}

/* Carrier is repetitive on a route page, while aircraft varies per row, so
   mute only the carrier. Scope to tbody to preserve the header's shared tone. */
.route-page tbody .col-airline-cell { color: var(--text-muted); }

/* A hyphenated registration is one token and must not split on mobile. */
.route-page .craft .reg {
  margin-left: 0.45rem;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-faint);
  white-space: nowrap;
}

.route-page .craft.none { color: var(--text-faint); }

/* ── route mobile ───────────────────────────────────────────────────────── */

/* At 50rem the aircraft field starts wrapping while the other columns remain
   single-line. Reflow for readability; the auto aircraft column means this is
   no longer an overflow boundary. */
@media (max-width: 50rem) {
  /* Keep the horizontal flight path between its endpoints. */
  .route-page .lockup {
    gap: var(--space-3);
    padding: var(--space-4);
  }

  .route-page .endpoint .iata { font-size: 1.4rem; }
  .route-page .endpoint .city { font-size: var(--fs-micro); }
  .route-page .path .block-time { font-size: var(--fs-nano); }

  .route-page .dir-head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
  }

  /* Release fixed widths so reflowed rows fill the panel instead of scrolling. */
  .route-page table { table-layout: auto; }

  .route-page .col-time,
  .route-page .col-flight,
  .route-page .col-airline,
  .route-page .col-craft,
  .route-page .col-status { width: auto; }

  .route-page thead { display: none; }

  .route-page tbody,
  .route-page tbody td { display: block; }

  /* Force a stable scan line (time, flight number, status) above a middot meta
     sentence — MIRROR: the board's inline block keeps this two-line anatomy in
     step by hand. The status block takes whichever line has room: the scan line
     here, since the long token (the airframe) sits in the sentence; the board
     pins it to the sentence, its long token (the destination) being on the scan
     line. The board holds its two lines by ellipsizing the airline; this
     sentence stays free to wrap as prose, its block already safe on the scan
     line. Neither reflow may overflow. */
  .route-page tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--cell-gap);
    row-gap: 0.2rem;
    padding: 0.7rem var(--space-4);
    border-bottom: 1px solid var(--border);
  }

  .route-page tbody tr:last-child { border-bottom: 0; }

  /* Rows own the divider — zero every cell's, or a day band's cell stacks a
     second edge under the row's. */
  .route-page tbody td {
    border-bottom: 0;
  }

  /* Flight cells hand padding to their shared row; single-cell utility rows
     retain their own padding. */
  .route-page tbody tr:not(.day-separator):not(.empty-row) td {
    padding: 0;
  }

  /* Reorder visually so renderRow, its prerender mirror and desktop DOM order
     stay unchanged. Flex keeps long identity tokens intact instead of wrapping
     inside grid tracks. These positional selectors assume exactly five cells;
     a changed row schema needs an explicit ordering hook. */
  .route-page tbody td:first-child { order: 1; }
  .route-page tbody td:nth-child(2) { order: 2; }
  .route-page td.col-status-cell {
    order: 3;
    /* The content-sized cell has no internal slack for text-align. */
    margin-left: auto;
  }
  .route-page .col-airline-cell { order: 5; }
  .route-page tbody .craft { order: 6; }

  /* A full-basis pseudo-element forces the chosen line break. Single-cell rows
     have nothing to split and must be excluded. */
  .route-page tbody tr:not(.day-separator):not(.empty-row)::after {
    content: "";
    order: 4;
    flex-basis: 100%;
    height: 0;
  }

  /* Style the middot-separated meta line as one secondary sentence. Only this
     line steps down — the flight number keeps its shared desktop treatment
     (mono 500, muted), which sets it apart from the sentence's sans 400 and
     leaves the time the row's only anchor. */
  .route-page .col-airline-cell,
  .route-page tbody .craft { font-size: var(--fs-meta); }

  /* Without columns, a stronger aircraft token would read as stray emphasis. */
  .route-page tbody .craft { color: var(--text-muted); }

  /* Trail the separator so a wrapped line never begins with a detached middot.
     The board leads its dots instead — its line can't wrap, and a trailing one
     would be clipped away with the ellipsized carrier. Declared twice: the alt
     form hides the dot from assistive tech, and browsers lacking that syntax
     keep the plain one. */
  .route-page .col-airline-cell::after {
    content: "·";
    content: "·" / "";
    margin-left: var(--cell-gap);
    color: var(--text-faint);
  }

  /* Remove the carrier's separator when the aircraft is hidden. Browsers
     without :has() degrade to a harmless trailing middot. */
  .route-page tbody tr:has(.craft.none) .col-airline-cell::after {
    content: none;
  }

  /* Single-cell rows need neither reordering nor shared row padding. */
  .route-page .day-separator,
  .route-page .empty-row { display: block; padding: 0; }

  /* Replace the desktop status grid with the chip's own inline pair. */
  .route-page td.col-status-cell .status-block {
    display: inline-flex;
  }

  /* Match the board's size step-down; the struck pair stays inline on both
     reflows — the scan line carries only the time and one identity token. The
     two are tuned against each other, so neither takes a scale token, however
     exactly 0.8rem matches --fs-meta. */
  .route-page .time { font-size: 0.98rem; }
  .route-page .time-pair .time.superseded,
  .route-page .time-pair .time.is-estimate { font-size: 0.8rem; }

  /* Hide the mobile aircraft dash; the :has() rule also removes its separator. */
  .route-page .craft.none { display: none; }
}
