/* The strip board, drawn as the EHAM handoff's mockup (docs/plans/radio-and-runways.md): a 68 pt
   header with the position tabs, a 64 pt identity row, and edge-to-edge columns that share the width
   and scroll on their own. Dark always, and not by preference: it is worked beside a radar scope in a
   room kept dim, and a board that turns white because the iPad decided it is daytime is a board
   nobody can look at. Every colour is a token so a state cannot be spelled two ways.

   Sized for a 13-inch iPad Pro in landscape, 1376 x 1032 pt: nothing tappable is under 44 px. */

:root {
    color-scheme: dark;

    --bg: #0b1013;
    --header: #0f161a;
    --col: #131a1f;
    --col-rwy: #121b22;
    --col-head: #172128;
    --line: #243038;
    --line-soft: #1f2a31;
    --edge: #2b3942;
    --text: #e3eaee;
    --muted: #8fa2ad;
    --muted-2: #9aabb5;
    --dim: #5a6870;

    --good: #3ecf8e;
    --warn: #ffb020;
    --bad: #d9483b;
    --accent: #5cc8ff;

    /* Strips: a departure is blue and an arrival amber, on the band and the body both. */
    --dep: #2f7ac0;
    --dep-body: #1c3347;
    --arr: #e0a33a;
    --arr-body: #362d1b;
    --plain-body: #1d2833;
    --calling: #ffb020;

    /* The old board's names for the same things, still read by the sheet, the keypad and pairing. */
    --bay: var(--col);
    --bar: var(--header);

    --radius: 6px;
    --ui: "IBM Plex Sans Condensed", system-ui, -apple-system, "Segoe UI", sans-serif;
    --mono: "IBM Plex Mono", ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    height: 100%;
    background: var(--bg);
    color: var(--text);
    font: 15px/1.35 var(--ui);

    /* Nothing on this board scrolls the page, and a rubber-band bounce during a drag looks like the
       board coming apart. The columns scroll themselves. */
    overscroll-behavior: none;
    -webkit-user-select: none;
    user-select: none;
}

body {
    display: flex;
    flex-direction: column;
    padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

#app { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

h1, h2 { margin: 0; font-weight: 600; }
h1 { font-size: 1.3rem; }
h2 { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin: 0.9rem 0 0.35rem; }
.muted { color: var(--muted); }
.spacer { flex: 1; }

button {
    font: inherit;
    color: var(--text);
    background: #141c21;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: 0.45rem 0.7rem;
    min-height: 44px;
    cursor: pointer;
    touch-action: manipulation;
}

button:disabled { color: var(--dim); background: #111719; cursor: default; }
button.quiet { background: transparent; }
button.small { min-height: 36px; padding: 0.25rem 0.6rem; font-size: 0.85rem; }

/* --- The board ------------------------------------------------------------------------------ */

.board {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    overflow: hidden;
}

/* Header, 68 pt: the aerodrome and its runways, the mode, the tabs in the middle, the gestures. */
.hdr {
    height: 68px;
    flex: none;
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 0 16px;
    border-bottom: 1px solid var(--line-soft);
    background: var(--header);
}

.hdr-left { display: flex; align-items: baseline; gap: 10px; min-width: 260px; }
/* The weather, right of the tabs: the letter large, QNH and wind beside it, the METAR under them. */
.wxbox { display: flex; align-items: center; gap: 12px; flex: 0 1 auto; min-width: 0; max-width: 34%; font-family: var(--mono); }
.wxbox .info { display: flex; gap: 10px; flex: none; }
.wxbox .letter { display: flex; flex-direction: column; align-items: center; line-height: 1; }
.wxbox .letter b { font-size: 34px; font-weight: 700; color: var(--text); }
.wxbox .letter i { font-style: normal; font-size: 10px; color: var(--muted); margin-top: 2px; letter-spacing: 0.06em; }
.wxbox .wxr { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.wxbox .wxtop { display: flex; align-items: baseline; gap: 14px; white-space: nowrap; }
.wxbox .wxtop i { font-style: normal; font-size: 11px; color: var(--muted); }
.wxbox .wxtop b { font-size: 15px; color: var(--text); }
.wxbox .metar { font-size: 11px; color: #9fb0b9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hdr-right { display: flex; align-items: center; gap: 14px; min-width: 260px; justify-content: flex-end; }
.apt { font-family: var(--mono); font-weight: 600; font-size: 22px; letter-spacing: 0.06em; }

.rcfg { font-family: var(--mono); font-size: 14px; font-weight: 600; display: flex; align-items: baseline; gap: 6px; white-space: nowrap; }
.rcfg .rl { font-size: 11px; color: var(--muted); font-weight: 500; margin-left: 6px; }
.rcfg .shut { text-decoration: line-through; color: #ffb4ab; }
.rcfg .none { font-size: 12px; font-weight: 500; color: var(--muted); }

.tabs { display: flex; gap: 8px; flex-grow: 1; justify-content: center; }

.tab {
    min-height: 44px;
    min-width: 128px;
    padding: 0 18px;
    border: 1px solid var(--edge);
    background: #141c21;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-weight: 600;
    font-size: 16px;
    letter-spacing: 0.04em;
}

.tab.on { background: var(--text); color: var(--bg); border-color: var(--text); }
.tab:disabled { cursor: not-allowed; opacity: 0.5; background: #141c21; color: var(--text); }

.badge {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 600;
    background: var(--calling);
    color: #1a1204;
    border-radius: 4px;
    padding: 2px 5px;
    animation: blink 1s steps(2, start) infinite;
}

.ghost-btn { min-height: 44px; padding: 0 16px; border-radius: 8px; border: 1px solid var(--warn); background: #2a1f08; color: #ffd27a; font-weight: 600; }
.menu-btn { min-width: 44px; padding: 0 12px; font-size: 20px; line-height: 1; }

.warn {
    background: #4a1612;
    color: #ffd6d1;
    border: 1px solid var(--bad);
    border-radius: 6px;
    padding: 6px 10px;
    font-weight: 600;
    font-size: 13px;
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 38%;
}

.fault { flex: none; margin: 0; padding: 6px 16px; font-size: 13px; color: #ffd6d1; background: #2a1512; border-bottom: 1px solid var(--line-soft); }
.waiting { margin: auto; color: var(--muted); }

/* The columns: edge to edge, one pixel between them, sharing the width. No sideways scroll at all:
   every column of a tab is on screen, and each scrolls down on its own. */
.cols { flex-grow: 1; min-height: 0; display: flex; }

.col {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background: var(--col);
    border-right: 1px solid var(--line);
    overflow: hidden;
}

.col:last-child { border-right: 0; }
.col.rwy { background: var(--col-rwy); }
.col.closed { box-shadow: inset 0 0 0 2px var(--bad); border-color: var(--bad); }

.colhead { flex: none; display: flex; align-items: baseline; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--line); background: var(--col-head); }
.col.closed .colhead { background: #4a1612; }
.colhead .ct { font-weight: 700; font-size: 16px; letter-spacing: 0.03em; white-space: nowrap; }
/* The frequency a transfer lane sends the pilot to: said with every transfer, so it reads at a glance. */
.colhead .fq { font-family: var(--mono); font-size: 14px; font-weight: 600; color: var(--accent); white-space: nowrap; }
.colhead .cs { font-size: 12px; color: var(--muted-2); flex-grow: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.col.closed .colhead .cs { color: #ffb4ab; }
.colhead .cn { font-family: var(--mono); font-size: 12px; color: var(--muted-2); }

.closedbar { flex: none; background: var(--bad); color: #fff; font-size: 12px; font-weight: 600; padding: 6px 12px; letter-spacing: 0.03em; }

/* A lane that only passes a strip to another tab of this board: marked, so it is not read as a handover. */
.colhead .fwd { font-family: var(--mono); font-size: 10px; font-weight: 700; letter-spacing: 0.08em; color: var(--muted); border: 1px solid var(--line); border-radius: 3px; padding: 1px 4px; }

/* A column is a stack of lanes; a lane is a heading over one or more parts, each a bay. */
.lane { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }

.sec { display: flex; flex-direction: column; min-height: 0; }
.sec.slot { flex: none; min-height: 96px; border-bottom: 1px dashed #33444f; background: #101a20; }
/* Sized from nothing, not from its strips: the room a drag makes at the foot of a list (board.js)
   must scroll inside the part, not grow it and push the parts beside it out of place. */
.sec.list { flex: 1 1 0; }

/* A runway slot holds one, and an empty sub-lane is a row: neither opens a hole under a held strip,
   because either would grow and move every part below it. A drop there needs no gap to aim at. */
.sec.slot .strips.making-room::after,
.sec.sub.empty .strips.making-room::after { display: none; }
.sec.slot .strips .make-room { transform: none; }

/* A split column: its lanes share it in equal parts, each under a heading of its own, the next
   heading drawn as the division. Each part scrolls on its own, like any column. */
.col.split .lane { flex: 1 1 0; }
.lane + .lane .colhead { border-top: 1px solid var(--line); }
.sectitle { flex: none; font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); padding: 8px 10px 0; }
.sectitle .fq { margin-left: 8px; font-family: var(--mono); font-size: 12px; letter-spacing: 0; color: var(--accent); }

/* A sub-lane: one per runway in a way out, under a row naming who gets what is dropped in it. An
   empty one collapses to that row, which is still a drop target -- 44 pt, a finger's width. */
.sec.sub + .sec.sub { border-top: 1px dashed #33444f; }
.sec.sub.empty { flex: none; min-height: 44px; }
.sec.sub.empty .strips { flex: none; padding: 0; min-height: 0; }
.subhead { flex: none; display: flex; align-items: baseline; gap: 6px; padding: 8px 10px 0; font-size: 12px; white-space: nowrap; min-height: 28px; }
.subhead .sl { font-weight: 700; letter-spacing: 0.04em; }
.subhead .to { color: var(--muted-2); overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; min-width: 0; }
.subhead .fq { font-family: var(--mono); font-weight: 600; color: var(--accent); }
.subhead .cn { margin-left: auto; font-family: var(--mono); color: var(--muted-2); }

/* Positioned so its strips' offsetTop is measured from it, which is what board.js's orderAt reads. */
.strips { --strip-gap: 6px; position: relative; flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: var(--strip-gap); }
.sec.slot .strips { overflow: visible; }

/* The drag's hole: the strips from the landing place down move by the held strip's height. See board.js. */
.strips .make-room { transform: translateY(calc(var(--room, 0px) + var(--strip-gap))); transition: transform 0.12s ease; }
.strips.making-room::after { content: ""; flex: none; height: var(--room, 0px); }

/* --- One strip: ~60 pt, a band for the direction, the callsign and two lines ----------------- */

.strip {
    display: flex;
    width: 100%;
    min-height: 60px;
    text-align: left;
    border: 0;
    border-radius: 6px;
    padding: 0;
    overflow: hidden;
    flex: none;
    background: var(--plain-body);
    color: var(--text);
    touch-action: none;
}

.strip.dep { background: var(--dep-body); }
.strip.arr { background: var(--arr-body); }

.strip .k {
    width: 30px;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 600;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    letter-spacing: 0.1em;
    background: #33465a;
}

.strip.dep .k { background: var(--dep); color: #fff; }
.strip.arr .k { background: var(--arr); color: #1a1204; }

.strip .b { flex: 1 1 auto; min-width: 0; padding: 7px 9px; display: flex; flex-direction: column; gap: 3px; }
.strip .r1 { display: flex; justify-content: space-between; gap: 6px; align-items: baseline; }
.strip .cs { font-family: var(--mono); font-weight: 600; font-size: 16px; }
/* The holding point or exit given: a small outlined chip, so it reads as a fact about the strip and not a flag. */
.strip .pt { margin-left: 5px; font-family: var(--mono); font-size: 11px; font-weight: 700; padding: 0 4px; border: 1px solid currentColor; border-radius: 3px; }
.strip .tel { flex: 1 1 auto; min-width: 0; font-size: 11px; letter-spacing: .04em; color: #9fb0b9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.strip .ty { font-family: var(--mono); font-size: 12px; color: #b9c7cf; white-space: nowrap; }
.strip .ty .sq { margin-left: 8px; font-weight: 600; color: #e6eef2; }
.strip .ty .sq.off { color: #f2c96b; }
.sheet .sqoff { color: #f2c96b; }
/* IFR is most of the board, so it stays quiet; VFR is the one that changes what is said. */
.strip .ty .fr { margin-left: 6px; padding: 0 3px; font-size: 10px; border: 1px solid #5b6b74; border-radius: 3px; color: #8fa1ab; }
.strip .ty .fr.vfr { border-color: #e0b04a; color: #f2c96b; font-weight: 600; }
.strip .r2 { font-family: var(--mono); font-size: 12px; color: #c5d2d9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.strip .r2 .who { color: var(--accent); }
/* Spaced by margin, not by the text: Razor drops the spaces after the climb's @if, and the destination must not run into it. */
.strip .r2 .dest { margin-left: 8px; font-weight: 600; color: #e6eef2; }
.strip .r2 .climb { margin-left: 6px; font-weight: 600; color: #e6eef2; }
.strip .r2 .climb.expected { font-weight: 400; color: var(--muted); }
.strip .r2 .place { margin-left: 6px; color: #9fb0b9; }
.strip .cs .flag { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: 3px; background: var(--bad); color: #fff; font-size: 12px; line-height: 16px; vertical-align: middle; }
.strip .r2 .bad { color: #ff8a80; font-weight: 600; text-decoration: underline wavy var(--bad); }
.strip .cs .heard { display: inline-block; width: 8px; height: 8px; margin-left: 6px; border-radius: 50%; background: var(--calling); vertical-align: middle; }

.strip.calling { box-shadow: 0 0 0 3px var(--calling); animation: pulse 1.1s ease-in-out infinite; }
.strip.cocked .k { box-shadow: inset -4px 0 0 var(--warn); }
.strip.theirs, .strip.offered { opacity: 0.72; }
.strip.working .cs::after { content: " ·"; color: var(--accent); }

.strip.lifted { display: none; }

.strip.ghost {
    position: fixed;
    z-index: 50;
    pointer-events: none;
    opacity: 0.92;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
}

@keyframes pulse { 0%, 100% { box-shadow: 0 0 0 3px var(--calling); } 50% { box-shadow: 0 0 0 3px var(--calling), 0 0 16px 4px rgba(255, 176, 32, 0.55); } }
@keyframes blink { 50% { opacity: 0.35; } }
@keyframes unsettled { 50% { opacity: 0.45; } }

/* --- The overflow: what the mockup has no room for and the board cannot do without ---------- */

.writes { display: flex; }
.writes button { border-radius: 0; border-right-width: 0; min-height: 40px; font-size: 0.85rem; }
.writes button:first-child { border-radius: var(--radius) 0 0 var(--radius); }
.writes button:last-child { border-radius: 0 var(--radius) var(--radius) 0; border-right-width: 1px; }
.writes button.on { background: var(--accent); border-color: var(--accent); color: #06121e; font-weight: 600; }
.writes button.on.armed { background: var(--bad); border-color: var(--bad); color: #1a0806; }


.position-pick { font: inherit; color: var(--text); background: #141c21; border: 1px solid var(--edge); border-radius: var(--radius); min-height: 44px; padding: 0 0.6rem; }

/* --- Sheets: the pad and the actions ------------------------------------------------------ */

.sheet {
    position: fixed;
    inset: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.55);
}

.pad, .actions {
    width: min(420px, 92vw);
    max-height: 92vh;
    overflow-y: auto;
    padding: 0.8rem;
    background: var(--bay);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6);
}

.actions { width: min(520px, 94vw); }

.pad > header, .actions > header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.pad .what, .actions .what { font-family: var(--mono); font-size: 1.1rem; font-weight: 700; }

.entry {
    font-family: var(--mono);
    font-size: 1.8rem;
    text-align: center;
    padding: 0.4rem;
    background: #10161c;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    min-height: 3rem;
}

.entry.empty { color: var(--dim); font-size: 1.1rem; line-height: 2.7rem; }

.chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0.5rem 0; }
.chips button { min-height: 40px; font-family: var(--mono); }

.keys { display: grid; gap: 0.35rem; margin-top: 0.4rem; }
.keys.digits { grid-template-columns: repeat(3, 1fr); }
.keys.alnum { grid-template-columns: repeat(6, 1fr); }
.keys button { font-family: var(--mono); font-size: 1.15rem; min-height: 48px; padding: 0; }
.keys .wide { grid-column: span 1; font-family: inherit; font-size: 0.9rem; }
.keys.digits .wide { grid-column: span 1; }
.keys .go { background: var(--accent); border-color: var(--accent); color: #06121e; font-weight: 700; }

.actions .row { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.actions .row button { flex: 1 1 auto; }
.actions .row button.on { background: var(--accent); border-color: var(--accent); color: #06121e; font-weight: 600; }
.actions .row button.preferred { border-color: var(--accent); }
.actions .findings { list-style: none; margin: 0 0 0.5rem; padding: 0; }
.actions .findings li { color: #ffd6d1; border-left: 3px solid var(--bad); padding: 0.2rem 0.6rem; margin-bottom: 0.25rem; font-family: var(--mono); font-size: 0.85rem; }
.actions .bad { color: #ff8a80; box-shadow: inset 0 0 0 1px var(--bad); }
.actions .route { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); word-break: break-all; }

.notes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.35rem; }
.notes .note { display: flex; flex-direction: column; align-items: flex-start; min-height: 48px; }
.notes .note .lbl { font-size: 0.6rem; color: var(--dim); }
.notes .note .val { font-family: var(--mono); font-size: 0.9rem; }
.notes .note.empty { color: var(--dim); }

/* --- Pairing, faults and the banner ------------------------------------------------------- */

.pair {
    margin: auto;
    padding: 1.5rem;
    max-width: 30rem;
    text-align: center;
}

.pair form { display: flex; gap: 0.5rem; justify-content: center; margin-top: 1rem; }

.pair .code {
    font: 700 2rem/1 var(--mono);
    letter-spacing: 0.2em;
    text-align: center;
    width: 9rem;
    padding: 0.5rem;
    color: var(--text);
    background: #10161c;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    text-transform: uppercase;
}

.pair .error { color: var(--bad); }

/* The hosts online on a hub, to watch one without a code. */
.pair .hosts { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; margin-top: 0.5rem; }
.pair .host { font: 600 0.95rem/1 var(--mono); padding: 0.6rem 0.9rem; }

/* The status bar: every link's state and one message, along the bottom of the board. It sits in
   the board's column rather than over it, so it never covers a strip. */
/* The tapped strip written out in full, EuroScope's F6 strip: three rows of columns, the route and
   remarks taking whatever width is left and cut short when they must -- the sheet has them whole. */
.fbar {
    flex: none;
    display: flex;
    align-items: stretch;
    min-height: 62px;
    border-top: 1px solid var(--line);
    border-left: 6px solid var(--dim);
    background: var(--plain-body);
    font-family: var(--mono);
    font-size: 12px;
    line-height: 18px;
    color: var(--text);
    cursor: pointer;
}
.fbar.dep { border-left-color: var(--dep); background: var(--dep-body); }
.fbar.arr { border-left-color: var(--arr); background: var(--arr-body); }
.fbar .fc { display: flex; flex-direction: column; justify-content: center; flex: none; min-width: 52px; padding: 2px 10px; border-right: 1px solid color-mix(in srgb, var(--text) 14%, transparent); white-space: nowrap; }
.fbar .fc > span { min-height: 18px; }
.fbar .id .cs { font-size: 15px; font-weight: 700; letter-spacing: 0.03em; }
.fbar .lv { text-align: right; }
.fbar .wide { flex: 1 1 auto; min-width: 0; }
.fbar .txt { overflow: hidden; text-overflow: ellipsis; }
.fbar .dim { color: var(--muted); overflow: hidden; text-overflow: ellipsis; }
.fbar .vfr { color: #f2c96b; font-weight: 600; }
.fbar .sq { font-weight: 600; text-align: right; }
.fbar .sq .off { color: #f2c96b; }
.fbar .x { flex: none; width: 40px; border: 0; background: transparent; color: var(--muted); font-size: 20px; cursor: pointer; }

.statusbar {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 32px;
    padding: 4px 12px calc(4px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--line-soft);
    background: var(--header);
    font-size: 12px;
    white-space: nowrap;
}
.statusbar .st { font-family: var(--mono); padding: 3px 8px; border-radius: 4px; color: var(--muted); box-shadow: inset 0 0 0 1px var(--edge); }
.statusbar .st.good { color: var(--good); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--good) 45%, transparent); }
.statusbar .st.warn { color: var(--warn); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 45%, transparent); }
.statusbar .st.bad { color: #ff8a80; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bad) 55%, transparent); }
/* Fine, in training: blue where green would be, so the bar says which world the board is in. */
.statusbar .st.train { color: var(--accent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 50%, transparent); }
.statusbar .msg {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 26px;
    margin-left: 8px;
    padding: 0 10px;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: left;
    font: inherit;
    color: var(--muted);
    background: none;
    border: none;
    border-radius: 4px;
}
.statusbar .msg.bad { color: #ffd6d1; background: #2a1512; box-shadow: inset 0 0 0 1px var(--bad); }
.statusbar .msg.note { color: #cfe4f4; background: #10222e; box-shadow: inset 0 0 0 1px var(--accent); }
.statusbar .at, .messages .at { font-family: var(--mono); color: var(--dim); margin-right: 8px; }

.messages { list-style: none; margin: 0; padding: 0; font-size: 0.85rem; }
.messages li { padding: 0.3rem 0; border-bottom: 1px solid var(--line-soft); }
.actions .fault-line { color: #ffd6d1; border-left: 3px solid var(--bad); padding: 0.2rem 0.6rem; }

/* The last thing the host said about a command, before there is a board to have a status bar.
   Tapped to dismiss; it is a message, not a dialog, and must never stand between a finger and a strip. */
.banner {
    position: fixed;
    left: 50%;
    bottom: calc(0.8rem + env(safe-area-inset-bottom));
    transform: translateX(-50%);
    z-index: 45;
    max-width: 80vw;
    padding: 0.55rem 0.9rem;
    background: #2a1b1b;
    color: #f0c5c1;
    border: 1px solid var(--bad);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}

/* News rather than a refusal -- a band taken, a rung given back. Drawn apart from a failed write,
   because a board that says "Now covering DEL." in the colour of a rejected command teaches the
   controller to stop reading the banner. */
.banner.note {
    background: #10222e;
    color: #cfe4f4;
    border-color: var(--accent);
}

/* --- What Blazor draws before the app is up ----------------------------------------------- */

.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem;
}

.loading-progress circle {
    fill: none;
    stroke: #1e2833;
    stroke-width: 0.6rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: var(--accent);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8) 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
    text-align: center;
    color: var(--muted);
}

.loading-progress-text:after {
    content: var(--blazor-load-percentage-text, "Loading");
}

#blazor-error-ui {
    display: none;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    padding: 0.7rem 1.2rem;
    background: #2a1b1b;
    color: #f0c5c1;
    border-top: 1px solid var(--bad);
}

#blazor-error-ui .dismiss {
    position: absolute;
    right: 0.75rem;
    top: 0.6rem;
    cursor: pointer;
}
