/*
 * What Board - the three board designs (currency, airport flights, rail/bus).
 *
 * Owned by fe-boards; the shell links this file AFTER css/styles.css.
 *
 * HOW THE SIZING WORKS (read this before changing a number)
 * ---------------------------------------------------------
 * One unit, --u, is 1% of the screen's LONG side (max(1vw, 1vh)). A 1920x1080
 * landscape panel and the same panel turned to 1080x1920 portrait therefore
 * share one --u (19.2px), so type is the same physical size either way; only
 * the layout around it changes.
 *
 * The table's font-size is NOT a fixed number. It is derived from how tall one
 * row is: (body height) / (rows per page + head), capped at --fs-max. So 12 rows
 * on a 720p screen and 12 rows on a 4K screen look the same, 8 rows get roomier
 * but not bigger than the cap, and 30 rows shrink instead of clipping. The body
 * is a size container, which is what makes `cqh` (its own height) available to
 * its children.
 *
 * The table is an inline-size container too, and its columns are written in
 * `em` of that same row font. `@container board-table (max-width: Nem)` therefore
 * asks "is there room for these columns at this type size?" - not "is this a
 * phone?" - and the answer flips to the stacked (two-line row) layout exactly
 * where the wide one would start to ellipsise. Portrait is simply the place
 * where that happens first.
 *
 * Needs Chromium 111+ (any current WebView2 / Android System WebView): container
 * queries and cqh (105), :has() (105) for one thing only - moving the shell's
 * connectivity chip out of the clock's way while a board is up - and color-mix()
 * (111) for the tinted chips and strips. Without color-mix the tokens fall back
 * to plain translucent greys and the tints are simply absent.
 *
 * COLOURS
 * -------
 * Branding supplies only --bg --ink --accent --accent-strong --accent-soft
 * --border (an M3 LIGHT palette: --bg near-white, --ink near-black). The board
 * derives its own tokens from them per theme and never hardcodes a brand
 * colour: dark = --ink as the surface and --bg as the text, light = the other
 * way round, --accent-soft as the highlight. The only literals are neutral
 * greys and the semantic status / transport-mode colours, which have to read
 * the same whatever the brand is.
 */

/* ------------------------------------------------------------------ tokens */

/* Neutral defaults for the six branding variables, so an unbranded board looks
   right on its own whatever the shell's stylesheet says (it publishes similar
   ones). `html:root` outranks a plain `:root` whatever the link order, and still
   loses to branding.js, which writes the real values inline on <html>. */
html:root {
    --bg: #f7f8fa;
    --ink: #15191e;
    --accent: #4a5d73;
    --accent-strong: #2f4054;
    --accent-soft: #d3dce6;
    --border: #c6ccd4;
}

:root {
    /* Geometry the shell needs: it positions #brand-logo from these (refining the
       defaults css/styles.css publishes; this file loads after it). */
    --u: max(1vw, 1vh);
    --board-pad-x: calc(var(--u) * 3.2);
    --board-pad-y: calc(var(--u) * 1.4);
    --board-header-h: calc(var(--u) * 6.6);
    --board-logo-h: calc(var(--board-header-h) * 0.56);
    --board-logo-w: calc(var(--board-header-h) * 2.6);

    --board-font: "Roboto", "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;

    /* Transport mode colours (white text on each): literal on purpose, they
       carry meaning (bus red, rail blue ...) and must not follow the brand. */
    --mode-rail: #1565c0;
    --mode-bus: #c62828;
    --mode-coach: #6a1b9a;
    --mode-tram: #2e7d32;
    --mode-metro: #bf4f00;
    --mode-water: #00838f;
    --mode-air: #455a64;
    --mode-other: #546e7a;

    /* Status colours. Solid chips (warn, bad) carry their own ink so they are
       legible on either surface; ok / info are text colours picked per theme. */
    --board-warn: #ffb81c;
    --board-warn-ink: #1b1400;
    --board-bad: #d93a35;
    --board-bad-ink: #ffffff;
}

/* Dark is the default theme (and what an unset data-theme means). */
:root {
    --board-surface: var(--ink);
    --board-text: var(--bg);
    --board-accent: var(--accent-soft);
    --board-fill: var(--accent);
    --board-fill-ink: var(--bg);
    --board-ok: #62d894;
    --board-info: #7dbcff;
    /* The ink on a SOLID --board-ok fill (the "boarding" chip): dark on the light dark-theme green. */
    --board-go-ink: #04210f;

    /* Fallbacks for engines without color-mix(); replaced just below. */
    --board-text-dim: rgba(255, 255, 255, 0.62);
    --board-line: rgba(255, 255, 255, 0.13);
    --board-band: rgba(255, 255, 255, 0.045);
    --board-raise: rgba(255, 255, 255, 0.075);
    --board-flash: rgba(255, 255, 255, 0.28);
}

:root[data-theme="light"] {
    --board-surface: var(--bg);
    --board-text: var(--ink);
    --board-accent: var(--accent-strong);
    --board-fill: var(--accent);
    --board-fill-ink: var(--bg);
    --board-ok: #1b7a3f;
    --board-info: #135fb5;
    --board-go-ink: #ffffff;

    --board-text-dim: rgba(0, 0, 0, 0.62);
    --board-line: var(--border);
    --board-band: rgba(0, 0, 0, 0.035);
    --board-raise: var(--accent-soft);
    --board-flash: rgba(0, 0, 0, 0.16);
}

@supports (color: color-mix(in srgb, red 50%, blue)) {
    :root {
        --board-text-dim: color-mix(in srgb, var(--bg) 64%, var(--ink));
        --board-line: color-mix(in srgb, var(--bg) 14%, var(--ink));
        --board-band: color-mix(in srgb, var(--bg) 5%, var(--ink));
        --board-raise: color-mix(in srgb, var(--bg) 9%, var(--ink));
        --board-flash: color-mix(in srgb, var(--accent-soft) 34%, transparent);
    }

    :root[data-theme="light"] {
        --board-text-dim: color-mix(in srgb, var(--ink) 64%, var(--bg));
        --board-line: color-mix(in srgb, var(--border) 85%, var(--bg));
        --board-band: color-mix(in srgb, var(--ink) 4%, var(--bg));
        --board-raise: color-mix(in srgb, var(--accent-soft) 62%, var(--bg));
        --board-flash: color-mix(in srgb, var(--accent) 24%, transparent);
    }
}

/* ------------------------------------------------------------------ shell hooks */

/* The shell's connectivity chip ("no network" / "may be out of date") sits top
   right by default - exactly where this header draws the clock. While a board is
   on screen it moves to the bottom centre, over the footer's quiet middle. The
   logo needs no hook: the shell already positions #brand-logo from the layout
   variables above, tints it with its own --stage-ink, and board.js measures it
   to leave room in the header. (:has() keeps this inert on the shell's own
   notice screens.) */
body:has(.board) .status-chip {
    top: auto;
    right: auto;
    bottom: calc(var(--u) * 0.7);
    left: 50%;
    transform: translateX(-50%);
}

/* ------------------------------------------------------------------ board frame */

.board {
    position: absolute;
    inset: 0;
    display: grid;
    /* minmax(0, 1fr), not the implicit auto column: an unbreakable long title
       must be ellipsised inside the screen, never widen the board past it. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: var(--board-header-h) minmax(0, 1fr) auto auto;
    background: var(--board-surface);
    color: var(--board-text);
    font-family: var(--board-font);
    font-size: max(12px, calc(var(--u) * 0.85));
    line-height: 1.25;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
}

.board [hidden] {
    display: none !important;
}

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

.board p,
.board h1,
.board h2 {
    margin: 0;
}

/* ---- header */

.board-header {
    display: flex;
    align-items: center;
    gap: 0;
    height: var(--board-header-h);
    padding: 0 var(--board-pad-x);
    background: var(--board-raise);
    border-bottom: 0.18em solid var(--board-fill);
}

/* board.js measures the shell's logo and writes its width here; with no logo
   the slot (and its gap) is zero, so the title sits on the margin. */
.board-logo-slot {
    flex: none;
    width: var(--board-logo-slot, 0px);
    margin-right: min(1.6em, calc(var(--board-logo-slot, 0px) * 1000));
}

.board-titles {
    flex: 1 1 auto;
    min-width: 0;
    margin-right: 1.6em;
}

/* overflow:hidden (for the ellipsis) clips descenders unless the line box has
   room for them, hence the generous line-height. */
.board-title {
    font-size: 2.35em;
    font-weight: 750;
    line-height: 1.22;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-subtitle {
    margin-top: 0.15em;
    font-size: 1.05em;
    color: var(--board-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-clock {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.05;
}

.board-clock-time {
    font-size: 2.7em;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
}

.board-clock-date {
    margin-top: 0.1em;
    font-size: 0.95em;
    color: var(--board-text-dim);
    white-space: nowrap;
}

.board-chip {
    flex: none;
    padding: 0.3em 0.9em;
    border-radius: 0.5em;
    font-size: 0.95em;
    font-weight: 650;
    white-space: nowrap;
}

.board-chip--stale {
    background: var(--board-warn);
    color: var(--board-warn-ink);
}

/* ---- body */

.board {
    --band-h: 0px;
}

.board-body {
    min-height: 0;
    padding: var(--board-pad-y) var(--board-pad-x);
    container: board-body / size;
}

.board-content {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

/* ---- platform heading ("Track 5"): a station-style sign */

.board-platform {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: calc(var(--u) * 1.4);
    height: calc(var(--band-h) - var(--u) * 1.2);
    margin-bottom: calc(var(--u) * 1.2);
    border-radius: calc(var(--u) * 1.2);
    background: var(--board-fill);
    color: var(--board-fill-ink);
    line-height: 1;
}

.board-platform-label {
    font-size: calc(var(--u) * 2.3);
    font-weight: 650;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    opacity: 0.88;
}

.board-platform-id {
    font-size: calc(var(--u) * 7.2);
    font-weight: 800;
    letter-spacing: -0.02em;
    white-space: nowrap;
}

.board-platform[data-len="4"] .board-platform-id,
.board-platform[data-len="5"] .board-platform-id { font-size: calc(var(--u) * 5.2); }
.board-platform[data-len="6"] .board-platform-id,
.board-platform[data-len="7"] .board-platform-id { font-size: calc(var(--u) * 4.2); }
.board-platform[data-len="8"] .board-platform-id,
.board-platform[data-len="9"] .board-platform-id { font-size: calc(var(--u) * 3.4); }

/* ---- table */

.board-table {
    --rows: 12;
    --head: 0.62;
    --fs-max: calc(var(--u) * 1.55);
    /* The stacked layout needs about 24em of width; never size type past that. */
    --fs-w: calc(100cqw / 24);
    --row-h: calc((100cqh - var(--band-h)) / (var(--rows) + var(--head)));
    flex: 1 1 0;
    min-height: 0;
    min-width: 0;
    font-size: min(var(--fs-max), var(--fs-w), calc(var(--row-h) * 0.4));
    container: board-table / inline-size;
    overflow: hidden;
}

.board-head,
.board-row {
    display: grid;
    grid-template-columns: var(--cols-wide);
    align-items: center;
    column-gap: 0.9em;
    padding: 0 0.7em;
}

.board-head {
    height: calc(var(--row-h) * var(--head));
    border-bottom: 1px solid var(--board-line);
}

/* The label size lives on the cells: the head grid shares the rows' `em`
   column templates, so its own font-size must stay the row font. */
.board-head-cell {
    min-width: 0;
    font-size: max(0.56em, 10px);
    font-weight: 650;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--board-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.board-rows {
    display: grid;
    grid-auto-rows: var(--row-h);
    align-content: start;
}

.board-row {
    height: var(--row-h);
    border-bottom: 1px solid var(--board-line);
}

.board-row:nth-child(even) {
    background: var(--board-band);
}

/* Cells hug their content (start / centre / end by kind) instead of stretching
   over the whole column, so a changed value flashes a box the size of the value. */
.board-cell {
    display: flex;
    flex-direction: column;
    justify-content: center;
    justify-self: start;
    max-width: 100%;
    min-width: 0;
    border-radius: 0.3em;
}

.cell-sub {
    font-size: max(0.64em, 11px);
    line-height: 1.2;
    color: var(--board-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cell-sub:empty {
    display: none;
}

/* time */

.cell-time .time-main {
    display: flex;
    align-items: baseline;
    gap: 0.45em;
    font-size: 1.15em;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.time-old {
    font-size: 0.68em;
    font-weight: 500;
    color: var(--board-text-dim);
    text-decoration: line-through;
}

.time-old:empty {
    display: none;
}

.cell-time.is-revised .time-now {
    color: var(--board-warn);
}

:root[data-theme="light"] .cell-time.is-revised .time-now {
    color: #a35f00;
}

/* flight */

.cell-flight .flight-no {
    font-weight: 750;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.cell-flight .flight-airline {
    font-size: max(0.64em, 11px);
    color: var(--board-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* destination / origin */

.cell-place .place-main {
    display: flex;
    align-items: baseline;
    gap: 0.6em;
    min-width: 0;
}

.place-name {
    flex: 0 1 auto;
    min-width: 0;
    font-size: 1.12em;
    font-weight: 650;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.place-code {
    flex: none;
    padding: 0.08em 0.4em;
    border: 1px solid var(--board-line);
    border-radius: 0.3em;
    font-size: max(0.6em, 10px);
    font-weight: 650;
    letter-spacing: 0.08em;
    color: var(--board-text-dim);
}

.place-code:empty {
    display: none;
}

/* The via text gives way first: the destination is the thing people read. */
.place-via {
    flex: 0 8 auto;
    min-width: 0;
    font-size: max(0.66em, 11px);
    font-weight: 500;
    color: var(--board-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.place-via:empty {
    display: none;
}

.cell-place .place-notice {
    color: var(--board-warn);
}

:root[data-theme="light"] .cell-place .place-notice {
    color: #8a5300;
}

/* gate / belt / check-in / platform */

.cell-value {
    align-items: center;
    justify-self: center;
}

.cell-status {
    align-items: flex-start;
}

.cell-value .value {
    max-width: 100%;
    font-size: 1.12em;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.col-gate,
.col-belt,
.col-checkin,
.col-platform {
    text-align: center;
}

/* status chip */

.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    max-width: 100%;
    padding: 0.22em 0.7em;
    border-radius: 0.45em;
    font-size: max(0.78em, 11px);
    font-weight: 650;
    line-height: 1.15;
    white-space: nowrap;
    overflow: hidden;
}

.chip-text {
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.3;
}

.chip-dot {
    display: none;
    flex: none;
    width: 0.55em;
    height: 0.55em;
    border-radius: 50%;
    background: currentColor;
}

.chip.has-dot .chip-dot {
    display: block;
}

.chip--ok {
    color: var(--board-ok);
    background: color-mix(in srgb, var(--board-ok) 16%, transparent);
}

/* "Boarding": the one chip that asks people to act now, so it is solid. */
.chip--go {
    color: var(--board-go-ink);
    background: var(--board-ok);
}

.chip--info {
    color: var(--board-info);
    background: color-mix(in srgb, var(--board-info) 16%, transparent);
}

.chip--warn {
    color: var(--board-warn-ink);
    background: var(--board-warn);
}

.chip--warn-soft {
    color: var(--board-warn);
    background: color-mix(in srgb, var(--board-warn) 16%, transparent);
}

:root[data-theme="light"] .chip--warn-soft {
    color: #8a5300;
    background: color-mix(in srgb, var(--board-warn) 30%, transparent);
}

.chip--bad {
    color: var(--board-bad-ink);
    background: var(--board-bad);
}

.chip--done {
    color: var(--board-text-dim);
    border: 1px solid var(--board-line);
}

.chip--quiet {
    padding-left: 0;
    color: var(--board-text-dim);
    font-weight: 500;
}

/* line badge */

.cell-line {
    align-items: flex-start;
}

.line-badge {
    --badge: var(--mode-other);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.7em;
    max-width: 100%;
    padding: 0.14em 0.5em;
    border-radius: 0.4em;
    background: var(--badge);
    color: #ffffff;
    font-size: 0.98em;
    font-weight: 800;
    letter-spacing: 0.02em;
    white-space: nowrap;
    overflow: hidden;
}

.line-badge.mode-rail { --badge: var(--mode-rail); }
.line-badge.mode-bus { --badge: var(--mode-bus); }
.line-badge.mode-coach { --badge: var(--mode-coach); }
.line-badge.mode-tram { --badge: var(--mode-tram); }
.line-badge.mode-metro { --badge: var(--mode-metro); }
.line-badge.mode-water { --badge: var(--mode-water); }
.line-badge.mode-air { --badge: var(--mode-air); }

/* currency */

.cell-currency {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 0.8em;
}

.ccy-flag {
    flex: none;
    width: 1.9em;
    height: 1.425em;
    border-radius: 0.2em;
    object-fit: cover;
    /* A hairline keeps white-heavy flags (Japan) from dissolving into a light board. */
    box-shadow: 0 0 0 1px var(--board-line);
}

.ccy-code {
    flex: none;
    min-width: 3.4em;
    padding: 0.14em 0.55em;
    border-radius: 0.4em;
    background: var(--board-fill);
    color: var(--board-fill-ink);
    font-size: 0.98em;
    font-weight: 800;
    letter-spacing: 0.05em;
    text-align: center;
}

.ccy-caption {
    display: flex;
    gap: 0.4em;
    min-width: 0;
    font-weight: 550;
}

.ccy-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ccy-unit {
    display: none;
    flex: none;
    color: var(--board-text-dim);
}

.cell-unit {
    justify-self: end;
    align-items: flex-end;
    color: var(--board-text-dim);
    font-variant-numeric: tabular-nums;
}

.cell-rate {
    justify-self: end;
    align-items: flex-end;
    font-size: 1.22em;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.cell-mid {
    font-weight: 500;
    color: var(--board-text-dim);
}

.col-unit,
.col-buy,
.col-sell,
.col-mid {
    text-align: right;
}

.cell-trend {
    align-items: center;
    justify-self: center;
}

.trend {
    display: block;
    width: 0;
    height: 0;
}

.trend--up {
    border-left: 0.42em solid transparent;
    border-right: 0.42em solid transparent;
    border-bottom: 0.72em solid var(--board-ok);
}

.trend--down {
    border-left: 0.42em solid transparent;
    border-right: 0.42em solid transparent;
    border-top: 0.72em solid var(--board-bad);
}

.trend--flat {
    width: 0.8em;
    height: 0.16em;
    border-radius: 0.1em;
    background: var(--board-text-dim);
}

/* row states */

/* Cancelled: the content fades, the status chip does not - it is the one
   thing on the row that has to stay crisp. */
.board-row.is-cancelled .board-cell:not(.col-status) {
    opacity: 0.55;
}

.board-row.is-cancelled .time-now,
.board-row.is-cancelled .place-name,
.board-row.is-cancelled .flight-no {
    text-decoration: line-through;
}

.board-row.is-done,
.board-row.is-gone {
    color: var(--board-text-dim);
}

.board-row.is-imminent .cell-time .cell-sub {
    color: var(--board-text);
    font-weight: 650;
}

/* changed-value flash: two identical animations under different names, so a
   second change inside the window restarts it (see table.js) */

.is-flash-a {
    animation: board-flash-a 1.8s ease-out;
}

.is-flash-b {
    animation: board-flash-b 1.8s ease-out;
}

@keyframes board-flash-a {
    0% { background-color: var(--board-flash); box-shadow: 0 0 0 0.25em var(--board-flash); }
    100% { background-color: transparent; box-shadow: 0 0 0 0.25em transparent; }
}

@keyframes board-flash-b {
    0% { background-color: var(--board-flash); box-shadow: 0 0 0 0.25em var(--board-flash); }
    100% { background-color: transparent; box-shadow: 0 0 0 0.25em transparent; }
}

/* page change */

.board-rows.enter-a {
    animation: board-page-a 0.55s ease-out;
}

.board-rows.enter-b {
    animation: board-page-b 0.55s ease-out;
}

@keyframes board-page-a {
    from { opacity: 0; transform: translateY(0.6em); }
    to { opacity: 1; transform: none; }
}

@keyframes board-page-b {
    from { opacity: 0; transform: translateY(0.6em); }
    to { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ whole-board states */

.board-state {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    padding-bottom: calc(var(--u) * 3);
    text-align: center;
}

/* Three quiet glyphs, drawn with borders: ! (unavailable), - (empty), dashed ring (not set up). */
.board-state-mark {
    position: relative;
    width: calc(var(--u) * 5.4);
    height: calc(var(--u) * 5.4);
    margin-bottom: calc(var(--u) * 0.8);
    border: calc(var(--u) * 0.4) solid var(--board-text-dim);
    border-radius: 50%;
    opacity: 0.7;
}

.board-state-mark::before,
.board-state-mark::after {
    content: "";
    position: absolute;
    left: 50%;
    background: var(--board-text-dim);
    border-radius: 999px;
    transform: translateX(-50%);
}

.board-state[data-kind="unavailable"] .board-state-mark::before {
    top: 20%;
    width: 9%;
    height: 38%;
}

.board-state[data-kind="unavailable"] .board-state-mark::after {
    top: 66%;
    width: 9%;
    height: 9%;
}

.board-state[data-kind="empty"] .board-state-mark::before {
    top: 46%;
    width: 44%;
    height: 8%;
}

.board-state[data-kind="unconfigured"] .board-state-mark {
    border-style: dashed;
}

.board-state[data-kind="unconfigured"] .board-state-mark::before {
    top: 44%;
    width: 12%;
    height: 12%;
    border-radius: 50%;
}

.board-state-title {
    font-size: calc(var(--u) * 2.5);
    font-weight: 750;
    line-height: 1.15;
}

.board-state-body {
    font-size: calc(var(--u) * 1.5);
    color: var(--board-text-dim);
}

/* ------------------------------------------------------------------ alerts strip */

.board-alerts {
    --alert: var(--board-info);
    display: flex;
    align-items: center;
    gap: 1.1em;
    padding: 0.75em var(--board-pad-x);
    font-size: calc(var(--u) * 1.3);
    background: color-mix(in srgb, var(--alert) 14%, var(--board-surface));
    border-top: 1px solid color-mix(in srgb, var(--alert) 45%, transparent);
}

.board-alerts[data-severity="warning"] { --alert: var(--board-warn); }
.board-alerts[data-severity="severe"] { --alert: var(--board-bad); }

.board-alerts-badge {
    flex: none;
    padding: 0.18em 0.7em;
    border-radius: 0.4em;
    background: var(--alert);
    color: var(--board-warn-ink);
    font-size: 0.75em;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.board-alerts[data-severity="severe"] .board-alerts-badge {
    color: var(--board-bad-ink);
}

.board-alerts-text {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 550;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.board-alerts-count {
    flex: none;
    font-size: 0.8em;
    color: var(--board-text-dim);
    font-variant-numeric: tabular-nums;
}

.board-alerts.enter-a .board-alerts-text { animation: board-alert-a 0.6s ease-out; }
.board-alerts.enter-b .board-alerts-text { animation: board-alert-b 0.6s ease-out; }

@keyframes board-alert-a { from { opacity: 0; } to { opacity: 1; } }
@keyframes board-alert-b { from { opacity: 0; } to { opacity: 1; } }

/* ------------------------------------------------------------------ footer */

.board-footer {
    display: flex;
    align-items: center;
    gap: 2.2em;
    padding: 0.2em var(--board-pad-x) 0.9em;
    font-size: 1em;
    color: var(--board-text-dim);
}

.board-footnote {
    flex: 0 1 auto;
    max-width: 55%;
    min-width: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.board-footer-spacer {
    flex: 1 1 0;
}

.board-note,
.board-attrib {
    flex: none;
    white-space: nowrap;
}

.board-attrib-link {
    margin-left: 0.4em;
    color: inherit;
    text-decoration: none;
    pointer-events: none;
}

.board-pager {
    flex: none;
    display: flex;
    align-items: center;
    gap: 0.8em;
    font-variant-numeric: tabular-nums;
}

.board-dots {
    display: flex;
    gap: 0.45em;
}

.board-dot {
    width: 0.6em;
    height: 0.6em;
    border-radius: 50%;
    background: var(--board-line);
}

.board-dot.is-active {
    background: var(--board-accent);
}

/* ------------------------------------------------------------------ platform view */

/* Few rows, read from far away: big type, no column heads, rows centred in
   the space they have so one departure looks placed, not stranded at the top. */
.board.view-platform {
    --band-h: calc(var(--u) * 10.5);
}

.board.view-platform .board-table {
    --head: 0;
    --fs-max: calc(var(--u) * 5);
    /* Portrait: one column of "cards" - about 11em wide, see the card tier below. */
    --fs-w: calc(100cqw / 11);
}

.board.view-platform .board-head {
    display: none;
}

.board.view-platform .board-rows {
    height: 100%;
    align-content: center;
}

/* Portrait and square: the type follows the height of a row as well as its width. A card (see the
   cards below) is 4.85 lines tall, 5.3 with a weekday or "in 9 min" under the time, 5.6 with a via
   stop or a notice under the destination and 6 with both; the two-line row is 3 lines tall, 3.5
   with a line under the destination. With more rows than the three the view was drawn for, the
   type shrinks to what a row can hold instead of the next row painting over the card (three rows
   or fewer keep the sizes above wherever the card fits). From 28em of width on - what the
   two-line row needs with a gate column - the rows are the two-line ones, and the type is the
   larger of the two. Landscape is not in this block: it keeps the sizes above. */
@container board-body not (min-aspect-ratio: 5/4) {
    .board.view-platform .board-table {
        --card-em: 4.95;
        --row-em: 3;
        font-size: max(
            min(var(--fs-max), var(--fs-w), calc(var(--row-h) / var(--card-em))),
            min(var(--fs-max), calc(100cqw / 28), calc(var(--row-h) / var(--row-em)))
        );
    }

    .board.view-platform .board-table:has(.cell-time .cell-sub:not(:empty)) {
        --card-em: 5.4;
    }

    .board.view-platform .board-table:has(.cell-place .cell-sub:not(:empty)) {
        --card-em: 5.8;
        --row-em: 3.6;
    }

    .board.view-platform .board-table:has(.cell-time .cell-sub:not(:empty)):has(.cell-place .cell-sub:not(:empty)) {
        --card-em: 6.3;
    }
}

/* Landscape (container aspect ratio 5:4 and wider). */
@container board-body (min-aspect-ratio: 5/4) {
    /* Boards with fewer than the default 12 rows get larger type, up to what their
       wide layout still fits in one line per row (see the thresholds under "narrow":
       about 52em for flights, 46em for rail and bus; at 1920x1080 these caps leave
       53em and 49em). Portrait keeps the lower cap: its stacked rows are
       width-limited, and bigger type there would only ellipsise the destinations. */
    .board--flights .board-table { --fs-max: calc(var(--u) * 1.72); }
    .board--transit .board-table { --fs-max: calc(var(--u) * 1.9); }

    /* A platform view: the sign stands beside the rows, full height. */
    .board.view-platform .board-content {
        flex-direction: row;
        gap: calc(var(--u) * 2.6);
    }

    .board.view-platform .board-table {
        --band-h: 0px;
        --fs-max: calc(var(--u) * 3.1);
        /* the sign takes its width and a gap off the row area */
        --fs-w: calc((100cqw - var(--u) * 21.6) / 24);
    }

    /* Flights keep their status in a column of its own even when stacked, so
       they need more width per em than a rail row (whose status sits under the
       destination): a smaller type size keeps "Trondheim" and "TRD" on one line. */
    .board--flights.view-platform .board-table {
        --fs-w: calc((100cqw - var(--u) * 21.6) / 29);
    }

    .board.view-platform .board-platform {
        flex: none;
        flex-direction: column;
        gap: calc(var(--u) * 0.8);
        width: calc(var(--u) * 19);
        height: 100%;
        margin-bottom: 0;
    }

    .board.view-platform .board-platform-id {
        font-size: calc(var(--u) * 11);
    }

    .board.view-platform .board-platform[data-len="2"] .board-platform-id,
    .board.view-platform .board-platform[data-len="3"] .board-platform-id { font-size: calc(var(--u) * 8.4); }
    .board.view-platform .board-platform[data-len="4"] .board-platform-id,
    .board.view-platform .board-platform[data-len="5"] .board-platform-id { font-size: calc(var(--u) * 5.2); }
    .board.view-platform .board-platform[data-len="6"] .board-platform-id,
    .board.view-platform .board-platform[data-len="7"] .board-platform-id { font-size: calc(var(--u) * 3.8); }
    .board.view-platform .board-platform[data-len="8"] .board-platform-id,
    .board.view-platform .board-platform[data-len="9"] .board-platform-id { font-size: calc(var(--u) * 3); }
}

/* ------------------------------------------------------------------ narrow: stacked, two-line rows
   When the wide layout's columns no longer fit at the current type size (each
   kind has its own threshold: its fixed columns plus the room its main text
   needs), a row becomes two lines that stay together, centred in the row:
   destination over flight / status. The grid templates come from the specs
   (--cols-narrow, --areas-narrow ...) because they depend on which columns the
   board has; cells with `hide-narrow` are dropped here. */

/* flights: below 52em */
@container board-table (max-width: 52em) {
    .board--flights .board-head,
    .board--flights .board-row {
        grid-template-columns: var(--cols-narrow);
        grid-template-areas: var(--areas-narrow);
        grid-template-rows: var(--rows-narrow);
    }

    .board--flights .board-row { align-content: center; row-gap: 0.12em; }
    .board--flights .board-head { grid-template-areas: var(--areas-head-narrow); grid-template-rows: auto; }
    .board--flights .hide-narrow,
    .board--flights .board-head .col-flight { display: none; }

    .board--flights .col-time { grid-area: time; }
    .board--flights .col-flight { grid-area: flight; }
    .board--flights .col-place { grid-area: place; }
    .board--flights .col-gate { grid-area: gate; }
    .board--flights .col-belt { grid-area: belt; }
    .board--flights .col-status { grid-area: status; }

    .board--flights .cell-flight { flex-direction: row; justify-content: flex-start; align-items: baseline; gap: 0.6em; }
    .board--flights .cell-flight .flight-airline { font-size: max(0.6em, 11px); }
}

/* rail and bus: below 46em */
@container board-table (max-width: 46em) {
    .board--transit .board-head,
    .board--transit .board-row {
        grid-template-columns: var(--cols-narrow);
        grid-template-areas: var(--areas-narrow);
        grid-template-rows: var(--rows-narrow);
    }

    .board--transit .board-row { align-content: center; row-gap: 0.12em; }
    .board--transit .board-head { grid-template-areas: var(--areas-head-narrow); grid-template-rows: auto; }
    .board--transit .hide-narrow,
    .board--transit .board-head .col-status { display: none; }

    .board--transit .col-time { grid-area: time; }
    .board--transit .col-line { grid-area: line; }
    .board--transit .col-place { grid-area: place; }
    .board--transit .col-platform { grid-area: platform; }
    .board--transit .col-status { grid-area: status; }
}

/* exchange rates: below 40em - the code badge sits over the name, and the unit
   moves in front of the name ("100 Svenske kroner") so it is never lost */
@container board-table (max-width: 40em) {
    .board--rates .board-head,
    .board--rates .board-row {
        grid-template-columns: var(--cols-narrow);
        grid-template-areas: var(--areas-narrow);
        grid-template-rows: var(--rows-narrow);
    }

    .board--rates .board-head { grid-template-areas: var(--areas-head-narrow); grid-template-rows: auto; }
    .board--rates .hide-narrow { display: none; }

    .board--rates .col-currency { grid-area: currency; }
    .board--rates .col-buy { grid-area: buy; }
    .board--rates .col-sell { grid-area: sell; }
    .board--rates .col-mid { grid-area: mid; }
    .board--rates .col-trend { grid-area: trend; }

    /* Narrow: the flag sits left of a column that holds the code badge over the caption. */
    .board--rates .cell-currency { display: grid; grid-template-columns: auto 1fr; grid-template-areas: "flag code" "flag caption"; align-items: center; justify-content: start; column-gap: 0.6em; row-gap: 0.2em; }
    .board--rates .ccy-flag { grid-area: flag; width: 1.6em; height: 1.2em; }
    .board--rates .ccy-code { grid-area: code; justify-self: start; }
    .board--rates .ccy-caption { grid-area: caption; max-width: 100%; font-size: 0.7em; font-weight: 500; color: var(--board-text-dim); }
    .board--rates .ccy-unit { display: inline; }
    .board--rates .ccy-unit:empty { display: none; }
}

/* ------------------------------------------------------------------ cards (platform view, narrow)
   A platform view whose rows are less than ~27.5em wide (portrait panels, and
   square ones where the type size is capped before the width is used up) has no
   room for even the stacked two-line row at its big type size, so each departure
   becomes a three-line card: time + line / destination / status. In portrait
   --fs-w above aims for 11em, and the type shrinks with the row height past
   three rows (the block above) until the rows are the two-line ones, which need
   about 28em: the threshold sits a hair under that, so the two never meet on one
   table. Portrait and square only: a landscape platform view sizes its rows from
   the width the sign leaves (24em for rail and bus, 29em for flights) and keeps
   the two-line rows. */

@container board-body not (min-aspect-ratio: 5/4) {
    @container board-table (max-width: 27.5em) {
        .board--transit.view-platform .board-row,
        .board--flights.view-platform .board-row {
            /* The right column is as wide as its content (a line badge, a flight
               number) but never more than 46%: a bare `auto` track would grow to a
               long airline name's full width and push the time out of the card. */
            grid-template-columns: minmax(0, 1fr) fit-content(46%);
            grid-template-rows: auto auto auto;
            align-content: center;
            row-gap: 0.14em;
            padding: 0 0.4em;
        }

        .board--transit.view-platform .board-row { grid-template-areas: "time line" "place place" "status status"; }
        .board--flights.view-platform .board-row { grid-template-areas: "time flight" "place place" "status status"; }

        .board--transit.view-platform .col-time,
        .board--flights.view-platform .col-time { grid-area: time; }
        .board--transit.view-platform .col-line { grid-area: line; justify-self: end; }
        .board--flights.view-platform .col-flight { grid-area: flight; justify-self: end; max-width: 100%; align-items: flex-end; text-align: right; flex-direction: column; gap: 0; }
        .board--flights.view-platform .col-flight > span { max-width: 100%; }
        .board--transit.view-platform .col-place,
        .board--flights.view-platform .col-place { grid-area: place; }
        .board--transit.view-platform .col-status,
        .board--flights.view-platform .col-status { grid-area: status; }
        .board--flights.view-platform .col-gate,
        .board--flights.view-platform .col-belt { display: none; }

        /* The corner of the card is a label, not the headline: keep it from crowding the time. */
        .board--transit.view-platform .col-line .line-badge { font-size: 0.78em; }
        .board--flights.view-platform .col-flight .flight-no { font-size: 0.84em; }
    }
}

/* ------------------------------------------------------------------ motion */

@media (prefers-reduced-motion: reduce) {
    .board *,
    .board *::before,
    .board *::after {
        animation: none !important;
        transition: none !important;
    }
}
