/*
 * What Board - the design templates (SPEC 10.8, .doc/TEMPLATES.md).
 *
 * The shell links this file AFTER css/boards.css and builds on the tokens that file
 * defines (--board-surface, --board-text, --board-text-dim, --board-fill, --board-fill-ink,
 * --board-line, --board-band, --board-raise, the status colours, --board-font, --u). It
 * declares no branding variable of its own - the six that branding.js writes
 * (--bg --ink --accent --accent-strong --accent-soft --border) are the only colours a device can
 * change, and they reach a template through those tokens, exactly as they reach the
 * standard table. The only literals below are the inks that have to read on a solid
 * status fill (they carry meaning and so must not follow the brand), plus one light-theme
 * amber text colour: the revised time on the hero card.
 *
 * Every rule is scoped by the template's own class (`.tpl-<id>`, put on the file's root by
 * template-body.js), so a template can never restyle another one or the table boards.
 *
 * HOW THE SIZING WORKS. A template is drawn into `.board-body`, a size container, so one
 * file has to be right for 16:9 panels of any resolution, 21:9 strips, 4:3 and portrait.
 * Every length is a multiple of --g, a unit like boards.css's --u whose value is chosen
 * per orientation (a container query on the body) so that the design's height AND width
 * budget fit the box they are given: it is the largest unit the whole design still fits
 * with. Type is therefore the same relative size on a 720p panel and a 4K one, a 21:9
 * panel scales the design down instead of overflowing it, and a portrait one stacks it.
 * Nothing here measures text: names are bucketed by length in js/renderers/airport-gate.js
 * and the bucket arrives as `data-len`.
 *
 * THE HEIGHT BUDGET is drawn for the tallest card the data can make, not for the plain one. A
 * flight that is late and leaves after midnight puts the scheduled time over the new one, a
 * weekday label under it and a countdown pill after the status, and the meta row then needs two
 * lines; a budget that fits only the plain card paints one text over another the first time a
 * flight is late. The numbers below (90g, 62g, 48.5g, 46g) are the ones the tallest ordinary card
 * still fits in at every panel shape (dev/preview.mjs renders them with --odd and --more). The
 * hero's middle rows are `1fr`, so a row never shrinks below what it holds, and a card that is
 * taller than that anyway (four gates, a via stop, a two-line destination, late and after
 * midnight, all at once) spends its bottom padding instead of painting over a neighbour.
 */

/* ------------------------------------------------------------------ airport-gate */

.tpl-airport-gate {
    /* Portrait first (the narrow default): about 54g across and 90g of design height. The sign, the
       later flights and the gaps take 41g of it and the hero the other 49g; the tallest ordinary
       card (late, after midnight, the countdown running) needs 48.6g of that. */
    --g: min(calc(100cqh / 90), calc(100cqw / 54));

    /* The gate phases: a solid fill and the ink that reads on it, per theme (dark = the
       light status colours of boards.css, light = the dark ones). */
    --gate-go: var(--board-ok);
    --gate-go-ink: var(--board-go-ink);
    --gate-info: var(--board-info);
    --gate-info-ink: #04203d;
    --gate-warn: var(--board-warn);
    --gate-warn-ink: var(--board-warn-ink);
    --gate-bad: var(--board-bad);
    --gate-bad-ink: var(--board-bad-ink);
    --phase: var(--board-fill);
    --phase-ink: var(--board-fill-ink);

    /* The destination's size per length bucket (data-len on the hero). */
    --place-1: calc(var(--g) * 7.2);
    --place-2: calc(var(--g) * 6);
    --place-3: calc(var(--g) * 5);
    --place-4: calc(var(--g) * 4.2);
    --time-size: calc(var(--g) * 10.5);

    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    gap: calc(var(--g) * 1.6);
    font-size: calc(var(--g) * 1);
    line-height: 1.15;
}

:root[data-theme="light"] .tpl-airport-gate {
    --gate-info-ink: #ffffff;
}

.tpl-airport-gate h2,
.tpl-airport-gate h3,
.tpl-airport-gate p,
.tpl-airport-gate ol {
    margin: 0;
    padding: 0;
}

/* ---- the sign: "GATE" and the gate, the same sign the standard platform view draws */

.tpl-airport-gate .gate-sign {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: calc(var(--g) * 1.4);
    min-height: calc(var(--g) * 10);
    padding: calc(var(--g) * 1.2) calc(var(--g) * 2);
    border-radius: calc(var(--g) * 1.2);
    background: var(--board-fill);
    color: var(--board-fill-ink);
    line-height: 1;
}

.tpl-airport-gate .gate-sign-label {
    font-size: calc(var(--g) * 2.3);
    font-weight: 650;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    opacity: 0.88;
}

.tpl-airport-gate .gate-sign-id {
    font-size: calc(var(--g) * 7.2);
    font-weight: 800;
    letter-spacing: -0.02em;
    white-space: nowrap;
}

/* Long ids ("A4 · A6 · B12") get smaller buckets and, from 6 characters, may wrap at the dots. */
.tpl-airport-gate .gate-sign[data-len="4"] .gate-sign-id,
.tpl-airport-gate .gate-sign[data-len="5"] .gate-sign-id { font-size: calc(var(--g) * 5.2); }
.tpl-airport-gate .gate-sign[data-len="6"] .gate-sign-id,
.tpl-airport-gate .gate-sign[data-len="7"] .gate-sign-id { font-size: calc(var(--g) * 4.2); }
.tpl-airport-gate .gate-sign[data-len="8"] .gate-sign-id,
.tpl-airport-gate .gate-sign[data-len="9"] .gate-sign-id { font-size: calc(var(--g) * 3.4); }

.tpl-airport-gate .gate-sign[data-len="6"] .gate-sign-id,
.tpl-airport-gate .gate-sign[data-len="7"] .gate-sign-id,
.tpl-airport-gate .gate-sign[data-len="8"] .gate-sign-id,
.tpl-airport-gate .gate-sign[data-len="9"] .gate-sign-id {
    white-space: normal;
    text-align: center;
    line-height: 1.12;
    overflow-wrap: anywhere;
}

/* ---- the column beside / under the sign */

.tpl-airport-gate .gate-main {
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: calc(var(--g) * 1.6);
}

/* ---- the hero: the next flight that has not left */

.tpl-airport-gate .gate-hero {
    /* Portrait: the hero takes the height the rows do not need and centres its content in it. */
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "phase" "when" "where" "meta";
    /* 1fr, not minmax(0, 1fr): the time and the destination never shrink below what they hold. */
    grid-template-rows: auto 1fr 1fr auto;
    row-gap: calc(var(--g) * 1.3);
    padding: calc(var(--g) * 2.2) calc(var(--g) * 2.6);
    border-radius: calc(var(--g) * 1.2);
    background: var(--board-raise);
    overflow: hidden;
}

.tpl-airport-gate .gate-hero[data-phase="go_to_gate"] { --phase: var(--gate-info); --phase-ink: var(--gate-info-ink); }
.tpl-airport-gate .gate-hero[data-phase="boarding"] { --phase: var(--gate-go); --phase-ink: var(--gate-go-ink); }
.tpl-airport-gate .gate-hero[data-phase="gate_closing"] { --phase: var(--gate-warn); --phase-ink: var(--gate-warn-ink); }
.tpl-airport-gate .gate-hero[data-phase="gate_closed"] { --phase: var(--gate-bad); --phase-ink: var(--gate-bad-ink); }

/* A flight in a gate phase gets the phase colour round the whole card, not just in the banner. */
.tpl-airport-gate .gate-hero[data-phase] {
    box-shadow: inset 0 0 0 calc(var(--g) * 0.3) var(--phase);
}

.tpl-airport-gate .gate-eyebrow {
    grid-area: phase;
    min-width: 0;
    font-size: calc(var(--g) * 1.7);
    font-weight: 650;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--board-text-dim);
}

/* One line, whatever the language or the panel: it ends in an ellipsis rather than pushing the card. */
.tpl-airport-gate .gate-eyebrow-text {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The banner: full width of the card, the phase in large type. Words first - the colour only
   backs them up, so it reads the same on a panel with washed-out colours. */
.tpl-airport-gate .gate-phase {
    grid-area: phase;
    display: flex;
    align-items: center;
    gap: calc(var(--g) * 1.2);
    margin: calc(var(--g) * -2.2) calc(var(--g) * -2.6) calc(var(--g) * 0.2);
    padding: calc(var(--g) * 1.1) calc(var(--g) * 2.6);
    background: var(--phase);
    color: var(--phase-ink);
    line-height: 1;
}

.tpl-airport-gate .gate-phase-dot {
    flex: none;
    width: calc(var(--g) * 1.5);
    height: calc(var(--g) * 1.5);
    border-radius: 50%;
    background: currentColor;
}

.tpl-airport-gate .gate-phase-text {
    min-width: 0;
    font-size: calc(var(--g) * 3.6);
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The time: the revised one big, the scheduled one struck through above it. */
.tpl-airport-gate .gate-when {
    grid-area: when;
    align-self: end;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 0;
    line-height: 1;
}

.tpl-airport-gate .gate-time {
    font-size: var(--time-size);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    white-space: nowrap;
}

.tpl-airport-gate .gate-time-old {
    margin-bottom: calc(var(--g) * 0.4);
    font-size: calc(var(--g) * 2.6);
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--board-text-dim);
}

.tpl-airport-gate .gate-time-old:empty,
.tpl-airport-gate .gate-day:empty,
.tpl-airport-gate .gate-via:empty,
.tpl-airport-gate .gate-code:empty,
.tpl-airport-gate .gate-airline:empty {
    display: none;
}

.tpl-airport-gate .gate-when:has(.gate-time-old:not(:empty)) .gate-time {
    color: var(--board-warn);
}

:root[data-theme="light"] .tpl-airport-gate .gate-when:has(.gate-time-old:not(:empty)) .gate-time {
    color: #a35f00;
}

.tpl-airport-gate .gate-day {
    margin-top: calc(var(--g) * 0.5);
    font-size: calc(var(--g) * 2);
    font-weight: 650;
    color: var(--board-text-dim);
    text-transform: capitalize;
}

/* Where it goes: the destination is the thing people read. */
.tpl-airport-gate .gate-where {
    grid-area: where;
    align-self: start;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: calc(var(--g) * 0.9);
}

.tpl-airport-gate .gate-place {
    font-size: var(--place-1);
    font-weight: 750;
    /* overflow:hidden (for the clamp) clips descenders unless the line box has room for them. */
    line-height: 1.16;
    padding-bottom: 0.04em;
    letter-spacing: -0.01em;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: break-word;
}

.tpl-airport-gate .gate-hero[data-len="2"] .gate-place { font-size: var(--place-2); }
.tpl-airport-gate .gate-hero[data-len="3"] .gate-place { font-size: var(--place-3); -webkit-line-clamp: 2; line-height: 1.1; }
.tpl-airport-gate .gate-hero[data-len="4"] .gate-place { font-size: var(--place-4); -webkit-line-clamp: 2; line-height: 1.1; }

.tpl-airport-gate .gate-where-sub {
    display: flex;
    align-items: baseline;
    gap: calc(var(--g) * 1.2);
    min-width: 0;
}

.tpl-airport-gate .gate-code {
    flex: none;
    padding: 0.08em 0.5em;
    border: 0.12em solid var(--board-line);
    border-radius: 0.3em;
    font-size: calc(var(--g) * 2.2);
    font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--board-text-dim);
}

.tpl-airport-gate .gate-via {
    min-width: 0;
    font-size: calc(var(--g) * 2.2);
    font-weight: 500;
    color: var(--board-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The meta row: flight, airline, status, and the countdown pushed to the far edge. It wraps in every
   tier: a status, a second gate or the countdown goes down to a second line rather than squeeze the
   airline's name, and the budgets above leave the height for that line. */
.tpl-airport-gate .gate-meta {
    grid-area: meta;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: calc(var(--g) * 0.8) calc(var(--g) * 1.6);
    min-width: 0;
}

.tpl-airport-gate .gate-flight {
    flex: none;
    font-size: calc(var(--g) * 3);
    font-weight: 800;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/* The airline is the one text in the row that gives way, and only past 11em (about 21 characters,
   more than any name in the Avinor sample): a 50-letter name must not push the row onto a line
   of its own. */
.tpl-airport-gate .gate-airline {
    flex: 0 1 auto;
    min-width: 0;
    max-width: 11em;
    font-size: calc(var(--g) * 2.3);
    color: var(--board-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* A small "which gate" chip, shown only when the board covers more than one gate. */
.tpl-airport-gate .gate-chip {
    flex: none;
    padding: 0.1em 0.55em;
    border-radius: 0.35em;
    background: var(--board-fill);
    color: var(--board-fill-ink);
    font-size: calc(var(--g) * 2);
    font-weight: 800;
    letter-spacing: 0.04em;
    white-space: nowrap;
}

.tpl-airport-gate .gate-status,
.tpl-airport-gate .gate-row-status {
    flex: none;
    max-width: 100%;
    padding: 0.18em 0.7em;
    border-radius: 0.45em;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tpl-airport-gate .gate-status:empty,
.tpl-airport-gate .gate-row-status:empty {
    display: none;
}

.tpl-airport-gate .gate-status { font-size: calc(var(--g) * 2.5); }

.tpl-airport-gate [data-tone="ok"] { color: var(--board-ok); background: color-mix(in srgb, var(--board-ok) 16%, transparent); }
.tpl-airport-gate [data-tone="info"] { color: var(--board-info); background: color-mix(in srgb, var(--board-info) 16%, transparent); }
.tpl-airport-gate [data-tone="go"] { color: var(--gate-go-ink); background: var(--gate-go); }
.tpl-airport-gate [data-tone="warn"] { color: var(--board-warn-ink); background: var(--board-warn); }
.tpl-airport-gate [data-tone="bad"] { color: var(--board-bad-ink); background: var(--board-bad); }
.tpl-airport-gate [data-tone="done"] { color: var(--board-text-dim); border: 1px solid var(--board-line); }
.tpl-airport-gate [data-tone="quiet"] { padding-left: 0; background: none; color: var(--board-text-dim); font-weight: 500; }

.tpl-airport-gate .gate-countdown {
    flex: none;
    margin-left: auto;
    padding: 0.12em 0.7em;
    border-radius: 999px;
    background: var(--board-band);
    box-shadow: inset 0 0 0 0.1em var(--board-line);
    font-size: calc(var(--g) * 3.4);
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* A cancelled flight stays on screen and says so: the content fades and is struck, the status
   chip stays crisp (the one thing on the card that has to be read). The fade is on the big text.
   The small secondary text (the old time, the weekday, the IATA code, the via stops, the airline)
   is the dimmest on the card already and keeps most of its ink: at 0.55 it measured 2.8:1 on the
   dark theme and 2.1:1 on the light one, under the 3:1 large text needs; at 0.85 it is 4.6:1 and 3.4:1. */
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-time,
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-place,
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-flight {
    text-decoration: line-through;
}

.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-time,
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-place {
    opacity: 0.55;
}

.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-time-old,
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-day,
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-code,
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-via,
.tpl-airport-gate .gate-hero[data-status="cancelled"] .gate-airline {
    opacity: 0.85;
}

/* ---- no hero: every flight in the window has left */

.tpl-airport-gate .gate-none {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: calc(var(--g) * 12);
    border-radius: calc(var(--g) * 1.2);
    background: var(--board-raise);
}

.tpl-airport-gate .gate-none-text {
    padding: 0 calc(var(--g) * 2);
    font-size: calc(var(--g) * 3.2);
    font-weight: 700;
    text-align: center;
    color: var(--board-text-dim);
}

/* ---- the flights after the hero */

.tpl-airport-gate .gate-later {
    flex: none;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.tpl-airport-gate .gate-later-title {
    flex: none;
    margin-bottom: calc(var(--g) * 0.7);
    font-size: calc(var(--g) * 1.6);
    font-weight: 650;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--board-text-dim);
}

.tpl-airport-gate .gate-later-list {
    display: flex;
    flex-direction: column;
    list-style: none;
    border-top: 1px solid var(--board-line);
}

/* Portrait: two-line rows (destination over flight), each with room to breathe. */
.tpl-airport-gate .gate-row {
    flex: none;
    min-height: calc(var(--g) * 8.4);
    display: grid;
    grid-template-columns: calc(var(--g) * 7.6) minmax(0, 1fr) auto auto;
    grid-template-areas: "when place gate status" "when flight gate status";
    align-items: center;
    column-gap: calc(var(--g) * 1.6);
    row-gap: 0.1em;
    border-bottom: 1px solid var(--board-line);
    font-size: calc(var(--g) * 2.7);
}

.tpl-airport-gate .gate-row-when {
    grid-area: when;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.tpl-airport-gate .gate-row-time {
    font-weight: 800;
}

.tpl-airport-gate .gate-row-old {
    font-size: 0.6em;
    font-weight: 500;
    color: var(--board-text-dim);
}

.tpl-airport-gate .gate-row-old:empty {
    display: none;
}

.tpl-airport-gate .gate-row-place {
    grid-area: place;
    min-width: 0;
    font-weight: 650;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tpl-airport-gate .gate-row-flight {
    grid-area: flight;
    font-size: 0.78em;
    font-weight: 650;
    letter-spacing: 0.02em;
    color: var(--board-text-dim);
    white-space: nowrap;
}

.tpl-airport-gate .gate-row .gate-chip { grid-area: gate; }

.tpl-airport-gate .gate-row-status {
    grid-area: status;
    font-size: 0.78em;
}

.tpl-airport-gate .gate-row[data-status="cancelled"] .gate-row-time,
.tpl-airport-gate .gate-row[data-status="cancelled"] .gate-row-place {
    text-decoration: line-through;
    opacity: 0.55;
}

/* ---- a lone hero (nothing after it): the room the later flights would take goes to the type.
   Portrait first; the squarish and wide landscape tiers below set their own, narrower sizes. */

.tpl-airport-gate .gate-main[data-rows="0"] .gate-hero {
    --time-size: calc(var(--g) * 12.5);
    --place-1: calc(var(--g) * 8.6);
    --place-2: calc(var(--g) * 7);
    --place-3: calc(var(--g) * 5.6);
    --place-4: calc(var(--g) * 4.6);
}

/* ---- squarish landscape (container aspect 5:4 and wider): the sign stands beside the column, full
   height. The hero stays stacked - time over destination - because a 4:3 panel has the height for it
   and not the width for both side by side. */

@container board-body (min-aspect-ratio: 5/4) {
    .tpl-airport-gate {
        /* about 66g across and 62g of design height: the later flights and the gaps take 17g, the
           hero the other 45g, and the tallest ordinary card (late, after midnight, the countdown
           running) needs 44.3g of that at 5:4, where a late flight's meta row is two lines */
        --g: min(calc(100cqh / 62), calc(100cqw / 66));
        --place-1: calc(var(--g) * 6.8);
        --place-2: calc(var(--g) * 5.6);
        --place-3: calc(var(--g) * 4.8);
        --place-4: calc(var(--g) * 4);
        --time-size: calc(var(--g) * 9);

        grid-template-columns: calc(var(--g) * 19) minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr);
        gap: calc(var(--g) * 2.6);
    }

    .tpl-airport-gate .gate-sign {
        flex-direction: column;
        gap: calc(var(--g) * 0.8);
    }

    .tpl-airport-gate .gate-sign-id { font-size: calc(var(--g) * 11); }
    .tpl-airport-gate .gate-sign[data-len="2"] .gate-sign-id,
    .tpl-airport-gate .gate-sign[data-len="3"] .gate-sign-id { font-size: calc(var(--g) * 8.4); }
    .tpl-airport-gate .gate-sign[data-len="4"] .gate-sign-id,
    .tpl-airport-gate .gate-sign[data-len="5"] .gate-sign-id { font-size: calc(var(--g) * 5.2); }
    .tpl-airport-gate .gate-sign[data-len="6"] .gate-sign-id,
    .tpl-airport-gate .gate-sign[data-len="7"] .gate-sign-id { font-size: calc(var(--g) * 3.8); }
    .tpl-airport-gate .gate-sign[data-len="8"] .gate-sign-id,
    .tpl-airport-gate .gate-sign[data-len="9"] .gate-sign-id { font-size: calc(var(--g) * 3); }

    .tpl-airport-gate .gate-hero {
        row-gap: calc(var(--g) * 0.9);
        padding: calc(var(--g) * 1.8) calc(var(--g) * 2.6);
    }

    .tpl-airport-gate .gate-phase {
        margin: calc(var(--g) * -1.8) calc(var(--g) * -2.6) calc(var(--g) * 0.1);
        padding: calc(var(--g) * 1) calc(var(--g) * 2.6);
    }

    .tpl-airport-gate .gate-phase-text { font-size: calc(var(--g) * 3.4); }
    .tpl-airport-gate .gate-flight { font-size: calc(var(--g) * 2.8); }
    .tpl-airport-gate .gate-countdown { font-size: calc(var(--g) * 3.2); }

    /* One line a row: time, destination, flight, gate chip, status. */
    .tpl-airport-gate .gate-row {
        min-height: 0;
        grid-template-columns: calc(var(--g) * 6.4) minmax(0, 1fr) auto auto auto;
        grid-template-areas: "when place flight gate status";
        padding: calc(var(--g) * 0.55) 0;
        font-size: calc(var(--g) * 2.3);
    }

    /* A lone hero in the stacked layout: the width is the limit, so the type grows less than in portrait. */
    .tpl-airport-gate .gate-main[data-rows="0"] .gate-hero {
        --time-size: calc(var(--g) * 11);
        --place-1: calc(var(--g) * 7.4);
        --place-2: calc(var(--g) * 5.8);
        --place-3: calc(var(--g) * 5);
        --place-4: calc(var(--g) * 4.2);
    }
}

/* ---- wide landscape (16:10 and wider): time and destination side by side */

@container board-body (min-aspect-ratio: 16/10) {
    .tpl-airport-gate {
        /* about 84g across and 46g of design height: the later flights and the gaps take 17g, the
           hero the other 29g. On a 16:9 panel a card needs 23.7g, or 25.3g late after midnight; the
           worst one (four gates, a long airline, a via stop, late) wraps its meta row, needs 30g and
           spends 1.1g of its bottom padding. */
        --g: min(calc(100cqh / 46), calc(100cqw / 84));
        --place-1: calc(var(--g) * 6.4);
        --place-2: calc(var(--g) * 5.2);
        --place-3: calc(var(--g) * 4.4);
        --place-4: calc(var(--g) * 3.8);
        --time-size: calc(var(--g) * 8);
    }

    .tpl-airport-gate .gate-hero {
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-areas: "phase phase" "when where" "meta meta";
        grid-template-rows: auto 1fr auto;
        column-gap: calc(var(--g) * 3.2);
    }

    .tpl-airport-gate .gate-when { align-self: center; }
    .tpl-airport-gate .gate-where { align-self: center; }
}

/* ---- 16:10 up to, not including, 2:1: a 16:10 panel's hero is narrower than a 16:9 panel's (whose
   body is about 2.1:1 and keeps the 46g above, pixel for pixel), so a flight that is late wraps its
   meta row, and the card needs 2.5g more height. The width budget still binds below 1.73:1. */

@container board-body (16/10 <= aspect-ratio < 2) {
    .tpl-airport-gate {
        --g: min(calc(100cqh / 48.5), calc(100cqw / 84));
    }
}

/* ---- 16:9 and wider: a lone hero has the width for somewhat larger type, side by side */

@container board-body (min-aspect-ratio: 16/9) {
    .tpl-airport-gate .gate-main[data-rows="0"] .gate-hero {
        --time-size: calc(var(--g) * 9.4);
        --place-1: calc(var(--g) * 7);
        --place-2: calc(var(--g) * 5.6);
        --place-3: calc(var(--g) * 4.8);
        --place-4: calc(var(--g) * 4.2);
    }

    .tpl-airport-gate .gate-main[data-rows="0"] .gate-flight { font-size: calc(var(--g) * 3.2); }
    .tpl-airport-gate .gate-main[data-rows="0"] .gate-airline { font-size: calc(var(--g) * 2.6); }
    .tpl-airport-gate .gate-main[data-rows="0"] .gate-status { font-size: calc(var(--g) * 2.8); }
    .tpl-airport-gate .gate-main[data-rows="0"] .gate-countdown { font-size: calc(var(--g) * 3.8); }
}

/* ---- motion: one restrained pulse on the phase dot of a flight that is boarding or closing */

@media (prefers-reduced-motion: no-preference) {
    .tpl-airport-gate .gate-hero[data-phase="boarding"] .gate-phase-dot,
    .tpl-airport-gate .gate-hero[data-phase="gate_closing"] .gate-phase-dot {
        animation: gate-pulse 1.6s ease-in-out infinite;
    }
}

@keyframes gate-pulse {
    0%,
    100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.35; transform: scale(0.78); }
}

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