/*
 * The moderation console.
 *
 * A working tool, not a page: three columns (rail, list, detail), everything scrolls in its own
 * pane, nothing reflows when a row is opened. Dense but not cramped - a moderator reads dozens of
 * rows in a sitting, and the queue's job is to make the worst one findable in a glance.
 *
 * Shares the token set with the support site (venta.css) so the two look like one system, but the
 * layout is deliberately the opposite shape: support is a narrow reading column, this is a
 * three-pane workbench.
 */

body { overflow: hidden; }

/* ── Sign-in ────────────────────────────────────────────────────────────── */
.gate {
    position: fixed;
    inset: 0;
    display: grid;
    place-items: center;
    padding: 24px;
    background: var(--bg);
    z-index: 100;
}

.gate-card {
    width: 100%;
    max-width: 380px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: var(--shadow);
    padding: 30px 30px 26px;
}

.gate-head {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 26px;
}
.gate-head [data-icon] { font-size: 34px; }
.gate-head h1 { font-size: 20px; letter-spacing: -.03em; }

.gate-host {
    font-size: 11.5px;
    color: var(--faint);
    letter-spacing: .04em;
    margin-top: 2px;
}

.btn.block { width: 100%; justify-content: center; margin-top: 6px; }

.gate-foot {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border-soft);
}

.code-input {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    letter-spacing: .3em;
    font-size: 16px;
}

/* ── Shell ──────────────────────────────────────────────────────────────── */
#app {
    display: grid;
    grid-template-columns: 216px minmax(0, 1fr);
    height: 100vh;
}

#app:has(.detail:not(.hidden)) {
    grid-template-columns: 216px minmax(0, 1fr) minmax(380px, 460px);
}

@media (max-width: 1180px) {
    #app:has(.detail:not(.hidden)) { grid-template-columns: 216px minmax(0, 1fr); }
    /* Below this width the detail pane covers the list rather than squeezing it - a 300px queue
       column is a queue nobody can read. */
    .detail:not(.hidden) {
        position: fixed;
        inset: 0 0 0 216px;
        z-index: 40;
    }
}

@media (max-width: 720px) {
    #app { grid-template-columns: 60px minmax(0, 1fr); }
    .rail-item span, .rail-brand span, .who { display: none; }
    .rail-item { justify-content: center; }
    .detail:not(.hidden) { inset: 0 0 0 60px; }
}

.scroller { overflow-y: auto; overscroll-behavior: contain; }

/* ── Rail ───────────────────────────────────────────────────────────────── */
.rail {
    display: flex;
    flex-direction: column;
    background: var(--panel);
    border-right: 1px solid var(--border);
    min-height: 0;
}

.rail-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 16px;
    height: 56px;
    flex: 0 0 56px;
    font-weight: 640;
    font-size: 14.5px;
    letter-spacing: -.02em;
    border-bottom: 1px solid var(--border-soft);
}
.rail-brand [data-icon] { font-size: 22px; }

.rail-nav { flex: 1; padding: 10px 8px; display: flex; flex-direction: column; gap: 1px; min-height: 0; }

.rail-item {
    display: flex;
    align-items: center;
    gap: 11px;
    font: inherit;
    font-size: 14px;
    width: 100%;
    padding: 9px 11px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--muted);
    cursor: pointer;
    text-align: left;
    transition: background .12s, color .12s;
}
.rail-item [data-icon] { font-size: 15px; }
.rail-item span { flex: 1; }
.rail-item:hover { background: var(--raised); color: var(--text); }
.rail-item:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

.rail-item[aria-current="page"] {
    background: color-mix(in srgb, var(--brand) 14%, transparent);
    color: var(--brand);
    font-weight: 560;
}

.badge {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11px;
    font-style: normal;
    font-weight: 600;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--raised);
    color: var(--muted);
}
.badge:empty { display: none; }
.badge.hot { background: var(--danger-bg); color: var(--danger); }

.rail-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 12px 14px;
    border-top: 1px solid var(--border-soft);
}
.who { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.who-name { font-size: 13px; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.who-role { font-size: 10.5px; color: var(--faint); letter-spacing: .1em; text-transform: uppercase; }

/* ── Main ───────────────────────────────────────────────────────────────── */
.main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }

.topbar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 18px;
    height: 56px;
    flex: 0 0 56px;
    border-bottom: 1px solid var(--border);
    background: var(--panel);
}
.topbar h2 { font-size: 16px; letter-spacing: -.02em; }
.topbar-tools { flex: 1; display: flex; align-items: center; gap: 8px; justify-content: flex-end; min-width: 0; }
.topbar-tools select, .topbar-tools input {
    width: auto;
    font-size: 13px;
    padding: 6px 10px;
}
.topbar-tools input[type="search"] { min-width: 220px; }

/* ── Lists ──────────────────────────────────────────────────────────────── */
.rows { display: flex; flex-direction: column; }

.rw {
    display: grid;
    grid-template-columns: 4px minmax(0, 1fr) auto;
    gap: 0 14px;
    align-items: center;
    padding: 0;
    border-bottom: 1px solid var(--border-soft);
    background: none;
    border-left: 0; border-right: 0; border-top: 0;
    font: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
    width: 100%;
    transition: background .1s;
}
.rw:hover { background: var(--raised); }
.rw:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.rw[aria-selected="true"] { background: color-mix(in srgb, var(--brand) 9%, transparent); }

/* The priority stripe. Four pixels doing the work a coloured badge would do worse: it is
   readable in peripheral vision while scrolling, which is how a queue is actually scanned. */
.rw-mark { align-self: stretch; background: transparent; }
.rw-mark.critical { background: var(--danger); }
.rw-mark.high { background: var(--warn); }
.rw-mark.normal { background: color-mix(in srgb, var(--muted) 35%, transparent); }

.rw-main { padding: 13px 0; min-width: 0; }
.rw-side { padding: 13px 18px 13px 0; display: flex; align-items: center; gap: 8px; }

.rw-title {
    font-size: 14px;
    font-weight: 550;
    letter-spacing: -.008em;
    margin-bottom: 3px;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.rw-sub {
    font-size: 12.5px;
    color: var(--faint);
    line-height: 1.45;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rw-time {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11.5px;
    color: var(--faint);
    white-space: nowrap;
}

.list-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px 40px;
    font-size: 12.5px;
    color: var(--faint);
}

/* ── Detail ─────────────────────────────────────────────────────────────── */
.detail {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--panel);
    border-left: 1px solid var(--border);
}

.detail-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 14px 0 18px;
    height: 56px;
    flex: 0 0 56px;
    border-bottom: 1px solid var(--border);
}
.detail-head h2 { flex: 1; font-size: 15px; letter-spacing: -.02em; }

/* The heading takes focus when the pane opens, which is a move the mouse user never asked for - so
   the ring is drawn only when the keyboard is what is driving. */
#detail-title:focus { outline: none; }
#detail-title:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 3px;
    border-radius: 4px;
}

.pane { padding: 18px 18px 60px; }

.block {
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    padding: 15px 16px;
    margin-bottom: 14px;
}

.block > h3 {
    font-size: 11.5px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--faint);
    font-weight: 600;
    margin-bottom: 12px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.kv { display: grid; grid-template-columns: 108px minmax(0, 1fr); gap: 7px 12px; font-size: 13px; }
.kv dt { color: var(--faint); }
.kv dd { margin: 0; overflow-wrap: anywhere; }

.quote {
    font-size: 13.5px;
    line-height: 1.6;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    background: var(--raised);
    border-radius: 9px;
    padding: 12px 14px;
}

.evidence {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11.5px;
    line-height: 1.6;
    white-space: pre;
    overflow-x: auto;
    background: var(--raised);
    border-radius: 9px;
    padding: 12px 14px;
    max-height: 320px;
}

.timeline { display: flex; flex-direction: column; gap: 10px; }
.event {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 10px;
    font-size: 13px;
    align-items: start;
}
.event [data-icon] { font-size: 13px; color: var(--faint); margin-top: .25em; }
.event .when {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11px;
    color: var(--faint);
    display: block;
    margin-top: 1px;
}
.event.struck { opacity: .55; }
.event.struck .what { text-decoration: line-through; }

.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }

/* ── Extract upload (product catalog) ───────────────────────────────────── */
/*
 * A determinate bar rather than a spinner. The file is posted in fixed-size pieces, so how far
 * along it is happens to be a number we actually know - and the operator watching a several
 * hundred megabyte grocery extract go up needs to be able to tell "slow" from "stuck".
 */
.progress {
    height: 6px;
    border-radius: 3px;
    background: var(--raised);
    overflow: hidden;
    margin: 4px 0 10px;
}

.progress > span {
    display: block;
    height: 100%;
    width: 0;
    background: var(--brand);
    transition: width .25s ease;
}

@media (prefers-reduced-motion: reduce) {
    .progress > span { transition: none; }
}

.upload-note {
    font-size: 12.5px;
    color: var(--muted);
    line-height: 1.55;
    margin-bottom: 12px;
    font-variant-numeric: tabular-nums;
    min-height: 1.2em;
}

/* The file picker is a browser control the theme cannot reach into; this at least stops it sitting
   flush against a dark surface looking like it belongs to a different page. */
.field input[type="file"] {
    width: 100%;
    font-size: 13px;
    color: var(--muted);
    padding: 9px 11px;
    border: 1px dashed var(--border);
    border-radius: var(--radius);
    background: var(--raised);
}

/* ── Overview tiles ─────────────────────────────────────────────────────── */
.tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
    gap: 12px;
    padding: 18px;
}

.tile {
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    padding: 15px 16px 16px;
}
.tile-label {
    font-size: 11px;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--faint);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    margin-bottom: 7px;
}
.tile-value { font-size: 26px; font-weight: 640; letter-spacing: -.035em; line-height: 1; }
.tile.alert .tile-value { color: var(--danger); }
.tile.warn .tile-value { color: var(--warn); }

.section-head {
    padding: 22px 18px 4px;
    font-size: 11.5px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--faint);
    font-weight: 600;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* ── Billing ────────────────────────────────────────────────────────────── */
/*
 * The one section read as a document rather than scanned as a queue, and the only one whose prose
 * carries the answer, so it is the only one that needs a measure. Uncapped it inherits the width of
 * whatever monitor it is opened on: the intro sets as a single 200-character line and the version
 * count in the plan list ends up a metre from the plan it counts.
 */
.billing { max-width: 1080px; }

.billing .hint {
    max-width: 72ch;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--muted);
}

.billing .lede { max-width: 72ch; font-size: 14px; line-height: 1.55; }

/* Revoke, Make current, Archive: the buttons a timeline entry carries need clearing from the chips
   above them, which otherwise sit hard against the button row. */
.billing .event .btn-row { margin-top: 8px; }

/*
 * The lookup row, and the reason it is a grid.
 *
 * Every field on the site is `width: 100%`, which as a flex item means a flex basis of the whole
 * row. Three of those overflow the container, flex switches from growing to shrinking, and shrinking
 * is weighted by basis - so the `flex: 1` cell holding the id input, basis zero, shrinks to zero and
 * stays there. Grid tracks give each control a width to be 100% of instead.
 */
.lookup {
    display: grid;
    grid-template-columns: 148px minmax(0, 1fr) auto;
    gap: 10px;
    align-items: end;
    margin-top: 14px;
    max-width: 640px;
}

.lookup > * { min-width: 0; }
.lookup label { margin-bottom: 5px; }

/* A wallet is looked up by one field, not two: guilds do not hold balances, so there is no kind to
   pick and the id should have the width the missing dropdown was using. */
.lookup.two { grid-template-columns: minmax(0, 1fr) auto; }

@media (max-width: 720px) {
    .lookup { grid-template-columns: minmax(0, 1fr); }
}

/*
 * The provenance table. Three columns because the screen answers three things at once - what the key
 * is, what it came out as, and who is credited with it - and reading it as prose is what makes a
 * billing ticket answerable.
 */
.prov { display: flex; flex-direction: column; }

/* The negative margin lets the hover band bleed into the card's own padding, so the row an operator
   is tracking across three columns reaches both ends of the table rather than stopping short. */
.prov-head, .prov-row {
    display: grid;
    grid-template-columns: minmax(150px, 1.2fr) minmax(96px, .7fr) minmax(170px, 1.1fr);
    gap: 3px 16px;
    align-items: baseline;
    padding: 9px 10px;
    margin: 0 -10px;
    font-size: 12.5px;
}

.prov-head {
    padding-top: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 10.5px;
    letter-spacing: .09em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--faint);
}

.prov-row { border-bottom: 1px solid var(--border-soft); }
.prov-row:last-child { border-bottom: 0; }
.prov-row:hover { background: var(--raised); }

.prov-key { overflow-wrap: anywhere; }
.prov-val { font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.prov-val strong { font-size: 13px; font-weight: 640; }
.prov-src { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* A key nobody set is dimmed, never dropped. The row missing is what makes an operator conclude the
   screen is broken; the row present and quiet says "this is a floor, not a decision".
   Dimmed by colour rather than by opacity, so the rows that did come from somewhere keep the full
   strength of their source colour instead of the whole table sitting under a haze. */
.prov-row.faint { color: var(--faint); }
.prov-row.faint .prov-val strong { font-weight: 500; }

/* Nobody supplied this, so the source reads as an outline rather than as a filled band. */
.prov-row.faint .tag {
    background: none;
    color: var(--faint);
    box-shadow: inset 0 0 0 1px var(--border);
}

@media (max-width: 900px) {
    .prov-head { display: none; }
    .prov-row { grid-template-columns: minmax(0, 1fr); }
}

/*
 * The plan catalogue, as the table it is.
 *
 * Fixed tracks rather than the queue's title-and-far-right-meta shape: a version count that has
 * drifted a thousand pixels from the plan it counts is not a column, and the price - the thing
 * actually being compared down the list - was set in body text on a second line.
 */
.plans { display: flex; flex-direction: column; }

.plans-intro { padding: 16px 18px 0; margin-bottom: 4px; }

.plans-head, .plan-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 120px 96px minmax(0, 176px);
    gap: 0 18px;
    align-items: center;
    text-align: left;
}

.plans-head {
    padding: 14px 18px 8px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 10.5px;
    letter-spacing: .09em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--faint);
    border-bottom: 1px solid var(--border);
}

.plans-head .end { text-align: right; }

.plan-row {
    padding: 12px 18px;
    border: 0;
    border-bottom: 1px solid var(--border-soft);
    background: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
    width: 100%;
    transition: background .1s;
}

.plan-row:hover { background: var(--raised); }
.plan-row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.plan-row[aria-selected="true"] { background: color-mix(in srgb, var(--brand) 9%, transparent); }

.plan-id { min-width: 0; }

.plan-title {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 8px;
    font-size: 14px;
    font-weight: 550;
    letter-spacing: -.008em;
}

.plan-desc {
    font-size: 12.5px;
    color: var(--faint);
    line-height: 1.45;
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Right-aligned and tabular so a column of prices lines up on the decimal point, which is what makes
   it comparable at a glance rather than readable one row at a time. */
.plan-price {
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}
.plan-price.unsold { font-weight: 450; color: var(--faint); }

.plan-versions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    font-variant-numeric: tabular-nums;
}
.plan-versions b { font-size: 14px; font-weight: 600; line-height: 1.35; }
.plan-versions span { font-size: 11.5px; color: var(--faint); }

.plan-status { display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; }

/* Same 900px the provenance table folds at, and for the same reason: the rail is still 216px wide
   here, so four fixed tracks have already eaten the plan name's column before the shell reflows. */
@media (max-width: 900px) {
    .plans-head { display: none; }

    .plan-row { grid-template-columns: minmax(0, 1fr) auto; gap: 5px 12px; align-items: start; }
    .plan-id { grid-area: 1 / 1; }
    .plan-price { grid-area: 1 / 2; }
    .plan-versions { grid-area: 2 / 1 / auto / -1; flex-direction: row; align-items: baseline; gap: 6px; }
    .plan-status { grid-area: 3 / 1 / auto / -1; justify-content: flex-start; }
}

.chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.chip {
    font-size: 11.5px;
    padding: 2px 7px;
    border-radius: 6px;
    background: var(--raised);
    color: var(--muted);
    overflow-wrap: anywhere;
}

/* The plan and grant value editor: one row per key in the catalogue, so the editor cannot normally
   offer a key the validator does not know. */
.prov-edit { display: flex; flex-direction: column; gap: 9px; }

.prov-edit-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 148px;
    gap: 4px 12px;
    align-items: center;
}
.prov-edit-row input, .prov-edit-row select { font-size: 12.5px; padding: 6px 8px; }

.prov-edit-label { display: flex; flex-direction: column; min-width: 0; font-size: 12px; }
.prov-edit-label .faint { font-size: 11px; }

/* The field a refusal named. The service's 400 says which key it rejected and lists the ones it
   accepts; pointing at the row beats making somebody re-read eleven of them looking for it. */
.prov-edit-row.bad {
    outline: 1px solid var(--danger);
    outline-offset: 4px;
    border-radius: 6px;
}

/*
 * A campaign's budget, issued against total.
 *
 * A bar and the numbers, not one or the other. The bar is what makes a list of campaigns scannable -
 * "which of these is nearly out" is a shape question, answered before any of the figures are read -
 * and the numbers are what somebody puts in a ticket. The fill changes colour at the campaign's own
 * alert threshold rather than at a number chosen here, so what the console shows as warning and what
 * the service actually alerts on are the same line.
 */
.budget { margin-top: 8px; }

.budget-track {
    height: 6px;
    border-radius: 999px;
    background: var(--raised);
    overflow: hidden;
}

.budget-fill {
    height: 100%;
    min-width: 2px;
    border-radius: 999px;
    background: var(--brand);
    transition: width .2s;
}

.budget-fill.warn { background: var(--warn); }
.budget-fill.danger { background: var(--danger); }

.budget-text {
    margin-top: 5px;
    font-size: 11.5px;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
}

/*
 * The eligibility rule list, in the campaign editor and again on a campaign's detail pane.
 *
 * A stack rather than a grid of checkboxes because each rule carries the sentence it refuses people
 * with underneath it, and two of them carry a correction on top of that. Somebody opening a campaign
 * is deciding what to turn applicants away for, and the sentence is the only place that says what
 * that will read like.
 */
.checks { display: flex; flex-direction: column; gap: 14px; }

.check-row { display: flex; flex-direction: column; gap: 4px; }

.check {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 0;
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
}

/* Every other field on the site is width: 100%, which on a checkbox is a stretched grey slab. */
.check input { width: auto; margin: 0; }

/* ── Buttons and fields ─────────────────────────────────────────────────── */
/*
 * The same ring the rail, the rows and the plan table already draw, so a keyboard user tabbing from
 * a row into the buttons beside it sees one indicator and not two. Offset outwards rather than
 * inwards, which is the one difference: a brand ring inset into a brand-filled primary button is a
 * ring nobody can see.
 */
.btn:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

/* A marker, not a colour. Which half of a form is compulsory has to survive a monochrome screenshot
   pasted into a ticket, and it has to be there before the field is filled in and refused. */
.field label .req {
    color: var(--danger);
    font-weight: 600;
    margin-left: 3px;
}

/* The refusal itself, under the control that caused it rather than in a toast four seconds from
   somewhere else on the screen. */
.field-error {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin-top: 6px;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--danger);
}
.field-error [data-icon] { font-size: 13px; margin-top: .12em; flex: none; }

/* ── Modal ──────────────────────────────────────────────────────────────── */
.modal-host { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; padding: 24px; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(9, 12, 18, .58); }

.modal {
    position: relative;
    width: 100%;
    max-width: 480px;
    max-height: 88vh;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: var(--shadow);
    padding: 24px 26px 22px;
}
.modal h2 { font-size: 18px; letter-spacing: -.025em; margin-bottom: 6px; }
.modal .lede { font-size: 13.5px; color: var(--muted); line-height: 1.55; margin-bottom: 20px; }
.modal .actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 22px; }

/*
 * "Discard your changes?", asked where the changes are.
 *
 * Escape and the backdrop are both easy to hit by accident, and this is what stands between that and
 * a half-written suspension note. Drawn as a band across the foot of the dialog rather than as a
 * second dialog on top of the first: stacking one modal over another is how an operator loses track
 * of which question they are answering.
 */
.modal-confirm {
    margin-top: 18px;
    padding: 13px 14px;
    border-radius: 11px;
    border: 1px solid color-mix(in srgb, var(--danger) 34%, transparent);
    background: var(--danger-bg);
}

.modal-confirm p { font-size: 13.5px; font-weight: 550; margin-bottom: 10px; }
.modal-confirm .btn-row { justify-content: flex-end; }

/* ── Toasts ─────────────────────────────────────────────────────────────── */
.toasts {
    position: fixed;
    bottom: 18px;
    right: 18px;
    z-index: 300;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 380px;
}

.toast {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 12px 15px;
    border-radius: 11px;
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    font-size: 13.5px;
    line-height: 1.5;
    animation: rise .16s ease-out;
}
.toast [data-icon] { margin-top: .16em; }
.toast.ok [data-icon] { color: var(--ok); }
.toast.danger [data-icon] { color: var(--danger); }
.toast.info [data-icon] { color: var(--info); }

@keyframes rise { from { opacity: 0; transform: translateY(6px); } }

@media (prefers-reduced-motion: reduce) {
    .toast { animation: none; }
    * { transition-duration: .001ms !important; }
}
