/* knowledge.css — the Knowledge Base sidebar and reading pane, the cards the
   engine generates into it and the Armory (assets, catalog entries, provenance
   badges, reasoning pairs), boot progress, the Doctrine Field, and the input
   dock. */

/* =================== KNOWLEDGE BASE SIDEBAR ===================
   Entries are real buttons. Opening a doctrine entry is the product's
   central claim and must not require a mouse; these used to be
   <div onclick> with no role or tabindex, which made the whole tab
   unreachable by keyboard. Styling is class-based so the generated
   markup carries no colour or type scale of its own. */
.kb-node {
    display: block; width: 100%; text-align: left;
    font-family: var(--font-body); font-size: var(--type-body); font-weight: 400;
    letter-spacing: normal; text-transform: none;
    padding: var(--space-snug) var(--space-base); margin-bottom: var(--space-micro); cursor: pointer;
    background: var(--surface-2); color: var(--text-primary);
    border: 1px solid var(--surface-border); border-radius: var(--radius);
    transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.kb-node:hover { background: var(--surface-raised); border-color: var(--surface-border-strong); }
.kb-title { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-meta { display: block; font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-control); color: var(--text-secondary); margin-top: var(--space-hair); }
.kb-node.is-oga { border-color: var(--surface-border-strong); }
.kb-node.is-oga .kb-meta { color: var(--oga-accent); }
.kb-group { margin-bottom: var(--space-base); }
.kb-group-head {
    display: flex; width: 100%; justify-content: space-between; align-items: center; gap: var(--space-snug);
    font-family: var(--font-display); font-size: var(--type-data); font-weight: 600; letter-spacing: var(--track-label); line-height: var(--leading-label); text-transform: uppercase;
    padding: var(--space-snug) var(--space-base); margin-bottom: var(--space-snug); cursor: pointer;
    background: var(--group-head); color: var(--accent-color);
    border: 1px solid var(--surface-border); border-radius: var(--radius);
}
.kb-group-head:hover { border-color: var(--surface-border-strong); }
.kb-caret { font-size: var(--type-data); transition: transform var(--dur-fast) var(--ease-out); }
.kb-group-head[aria-expanded="true"] .kb-caret { transform: rotate(90deg); }
.kb-sec { font-family: var(--font-display); font-size: var(--type-data); font-weight: 600; letter-spacing: var(--track-label); line-height: var(--leading-label); text-transform: uppercase; color: var(--accent-color); margin: var(--space-shell) 0 var(--space-snug); }
.kb-src { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-base); padding: var(--space-snug) var(--space-base); margin-bottom: var(--space-micro); background: var(--surface-2); border: 1px solid var(--surface-border); border-radius: var(--radius); }
.kb-src-name { font-size: var(--type-body); color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Destructive: the danger role, not the affirmative accent it used to carry. */
.kb-purge { flex: none; font-size: var(--type-data); letter-spacing: var(--track-tab); padding: var(--space-tight) var(--space-snug); color: var(--danger-text); background: var(--tint-command); border: 1px solid var(--accent-danger); border-radius: var(--radius); cursor: pointer; }
.kb-purge:hover { background: var(--accent-danger); color: var(--on-danger); }

/* Knowledge Base reading pane. These headings used to be 32px and 24px —
   larger than the 21px wordmark, on a scale DESIGN.md fixes at 11-21px —
   and were prefixed with full-colour emoji in a console that ships its own
   stroked SVG sprite. */
.kb-art-h1 { font-family: var(--font-display); font-size: var(--type-claim); font-weight: 600; letter-spacing: var(--track-control); text-transform: uppercase; color: var(--heading-strong); margin-bottom: var(--space-micro); }
.kb-art-sub { color: var(--text-secondary); font-size: var(--type-control); margin-bottom: var(--space-loose); border-bottom: 1px solid var(--surface-border); padding-bottom: var(--space-base); }
.kb-art-h2 { font-family: var(--font-display); font-size: var(--type-body); font-weight: 600; letter-spacing: var(--track-title); text-transform: uppercase; color: var(--terminal-text); margin-bottom: var(--space-base); display: flex; align-items: center; gap: var(--space-base); }
/* Section label. Was six inline spellings of "12px bold uppercase" in
   app.js, none of them on the Label role (Oswald 11px / 0.18em). */
.sec-label { font-family: var(--font-display); font-size: var(--type-data); font-weight: 600; letter-spacing: var(--track-label); line-height: var(--leading-label); text-transform: uppercase; color: var(--accent-color); display: block; margin-bottom: var(--space-micro); }
.sec-label.is-muted { color: var(--text-secondary); }
/* Reading-pane wrapper: the shared frame behind every article, catalog
   and schema view. Entrance now rides the system curve and duration
   instead of a one-off `fadeIn 0.3s ease`. */
.kb-pane { max-width: 900px; margin: 0 auto; width: 100%; display: flex; flex-direction: column; gap: var(--space-shell); animation: fadeIn var(--dur-med) var(--ease-out); }
/* Every card the engine generates — armoury asset, OGA catalogue entry,
   knowledge-base article — was assembled from its own inline style: 24px
   against 32px padding, radius 0 against the system radius, and three
   different bottom margins. One class now. The border colour is the only
   thing that varies, because it is the only thing that means anything. */
.gen-card {
    background: var(--card-panel); border: 1px solid var(--surface-border);
    border-radius: var(--radius); padding: var(--space-loose);
    display: flex; flex-direction: column; gap: var(--space-shell);
}
.gen-card.is-asset { border-color: var(--oga-accent); }
.gen-card.is-article { border-color: var(--accent-color); }
.gen-attrs { display: flex; flex-wrap: wrap; gap: var(--space-micro); }
.gen-attr { padding: var(--space-hair) var(--space-micro); background: var(--surface-recessed-soft); border: 1px solid var(--surface-border); color: var(--text-secondary); font-size: var(--type-data); }
/* Was --type-display. That rung is the wordmark's alone — "nothing else in
   the interface is this size" — and a generated card title is not the
   product's name. It sits at the claim rung with the rest of the headlines. */
.gen-card h2 { font-size: var(--type-claim); color: var(--text-primary); margin: 0; font-weight: normal; }

/* Boot progress. The counter is a readout: data face, fixed advance, and a
   reserved width so the digits climb without dragging the message with them. */
.boot-pct { font-size: var(--type-control); font-variant-numeric: tabular-nums;
            font-family: var(--font-data); color: var(--text-secondary); }
.boot-bar { height: 6px; background: var(--surface-recessed); border-radius: var(--radius);
            margin-top: var(--space-micro); overflow: hidden; }
.boot-bar > i { display: block; height: 100%; width: 0; background: var(--accent-color);
                transition: width var(--dur-med) var(--ease-out); }
@media (prefers-reduced-motion: reduce) { .boot-bar > i { transition: none; } }
.gen-badges { display: flex; flex-wrap: wrap; gap: var(--space-micro); margin-top: var(--space-snug); }
.gen-field { display: flex; flex-direction: column; gap: var(--space-snug); }
.gen-field-row { display: flex; flex-wrap: wrap; gap: var(--space-snug); }
.armory-list { flex: 1; overflow-y: auto; padding: var(--space-loose); display: flex; flex-direction: column; gap: var(--space-shell); }
/* Trailing explanatory note under a block of generated content. */
/* Both of these carry prose the non-technical viewer is meant to actually
   read, and both ran uncapped. .plain-brief is the plain-language Intent
   Packet — the readable half of the whole "inspectable, not a black box"
   claim — and it measured 150ch on a 1920px screen because nothing between
   it and the viewport set a width. That is the same failure DESIGN.md
   records as fixed for .rsn; it was fixed on the reasoning block and missed
   on the briefing sitting directly above it. It also lived as an inline
   style in app.js, which is why no stylesheet review ever caught it. */
.plain-brief {
    margin: 0; padding: var(--space-shell); max-width: 72ch; overflow-x: hidden;
    display: block; color: var(--terminal-fg); font-family: var(--font-body);
    white-space: pre-wrap; line-height: var(--leading-body); text-wrap: pretty;
}
.note { margin-top: var(--space-shell); max-width: 68ch; font-size: var(--type-caption); line-height: var(--leading-data); color: var(--text-secondary); font-style: italic; }
.note.is-accent { color: var(--accent-color); }
.kb-art-p { color: var(--text-secondary); font-size: var(--type-body); line-height: var(--leading-body); margin: 0; max-width: 72ch; overflow-wrap: break-word; }
.kb-art-list { color: var(--text-secondary); font-size: var(--type-body); line-height: var(--leading-body); margin-left: var(--space-shell); max-width: 72ch; overflow-wrap: break-word; }
.kb-art-box { overflow-wrap: anywhere; background: var(--surface-2); border: 1px solid var(--surface-border); border-radius: var(--radius); padding: var(--space-base); margin-bottom: var(--space-base); }

.wla-alt { display: none; }
body[data-theme="wla"] .ru-alt { display: none; }
body[data-theme="wla"] .wla-alt { display: inline; }

#force-drop-btn[aria-pressed="true"] { border-color: var(--text-primary); box-shadow: inset 0 0 0 1px var(--text-primary); }
.armed-tag { font-weight: 700; letter-spacing: var(--track-title); }

/* Provenance badges in the Armory and the catalog. One shape, two roles. */
.badge { display: inline-block; font-family: var(--font-display); font-size: var(--type-data); font-weight: 600; letter-spacing: var(--track-data); line-height: var(--leading-label); text-transform: uppercase; padding: var(--space-tight) var(--space-snug); border-radius: var(--radius); border: 1px solid; margin-right: var(--space-micro); }
.badge-gold { background: var(--tint-gold); border-color: var(--loot-gold); color: var(--loot-gold); }
.badge-oga { background: var(--tint-info); border-color: var(--oga-accent); color: var(--oga-accent); }
/* Recovering an asset is the one thing this console does that is purely
   a reward, and it used to arrive as `[ CRITICAL SUCCESS: NEW OGA
   RECOVERED - Name (Class - Tier) ]` in a flat gold bar: bracket-caps
   log syntax, which is the exact "developer tool only engineers can read"
   register PRODUCT.md rejects. It is a card now, and it arrives once —
   the border ignites from nothing as it settles, then holds. Nothing
   loops; the drop already happened. */
.loot-banner {
    margin-top: var(--space-shell); padding: var(--space-base) var(--space-shell);
    border-radius: var(--radius); background: var(--tint-gold);
    border: 1px solid var(--loot-gold);
    display: flex; flex-direction: column; gap: var(--space-micro);
    animation: lootLand 700ms var(--ease-out);
}
.loot-banner .lb-kicker { font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-data); text-transform: uppercase; color: var(--text-secondary); }
.loot-banner .lb-name { font-family: var(--font-display); font-weight: 600; font-size: var(--type-claim); letter-spacing: var(--track-display); text-transform: uppercase; color: var(--loot-gold); }
.loot-banner .lb-tags { display: flex; flex-wrap: wrap; gap: var(--space-tight); margin-top: var(--space-tight); }
.loot-banner .lb-where { font-size: var(--type-caption); color: var(--text-secondary); }
@keyframes lootLand {
    from { opacity: 0; transform: translateY(6px); border-color: transparent; box-shadow: 0 0 0 0 var(--loot-gold); }
    60%  { opacity: 1; transform: none; box-shadow: 0 0 0 6px transparent; }
    to   { opacity: 1; transform: none; border-color: var(--loot-gold); box-shadow: 0 0 0 0 transparent; }
}

/* Reasoning pair inside a payload entry: observation then doctrine. Tinted
   blocks, not colored side stripes — the stripe is reserved for the log
   channel itself and does not generalize to content inside an entry. */
.rsn { overflow-wrap: break-word; padding: var(--space-snug) var(--space-base); border-radius: var(--radius); border: 1px solid var(--surface-border); margin-top: var(--space-snug); font-size: var(--type-body); line-height: var(--leading-body); }
.rsn-obs { background: var(--surface-recessed-soft); color: var(--text-secondary); font-style: italic; }
.rsn-doc { background: var(--tint-command); color: var(--text-primary); border-color: var(--surface-border-strong); }
.rsn strong { display: block; font-family: var(--font-display); font-size: var(--type-data); letter-spacing: var(--track-label); line-height: var(--leading-label); text-transform: uppercase; margin-bottom: var(--space-tight); font-style: normal; }
.rsn-obs strong { color: var(--text-secondary); }
.rsn-doc strong { color: var(--danger-text); }
/* What the commander saw is context; why it decided is the claim. They
   were the same size, weight and padding, differing only by ground. */
.rsn-doc { padding: var(--space-base) var(--space-shell); }
/* Prose the investor is actually expected to read. DESIGN.md caps measure
   at 65-75ch and the feed had no cap at all: these ran 117ch. */
.rsn, .claim-sub { max-width: 74ch; }
/* When the model wrote no reasoning, the block that would have held it says
   so instead (PCE v2 phase 6: honest failures). It must never read as
   reasoning: no tint, a dashed rule where the others have a solid one, and
   a heading in words — the difference survives greyscale and projection. */
.rsn-missing { background: transparent; border-style: dashed; border-color: var(--surface-border-strong); color: var(--text-secondary); }
.rsn-missing strong { color: var(--text-primary); }

/* Citations under the commander's reasoning (phase 8). A cited order lists the
   passages it relied on, each a link into the Knowledge Base; an order that
   cited none says UNCITED in words, on a dashed edge like the other "nothing
   to show here" blocks, and is never left out because it is bad news. */
.rsn-cite { max-width: 85ch; /* the 74ch the other blocks get, at this block's smaller type */ display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-micro) var(--space-snug); background: var(--surface-recessed-soft); color: var(--text-secondary); font-size: var(--type-control); }
.rsn-cite strong { display: inline; margin-bottom: 0; color: var(--text-primary); }
.rsn-cite.is-cited { border-color: var(--accent-color); box-shadow: inset 0 0 0 1px var(--accent-color); }
.rsn-cite.is-uncited { border-style: dashed; border-color: var(--surface-border-strong); }
.rsn-cite.is-uncited strong { color: var(--danger-text); }
.cite-list { display: inline-flex; flex-wrap: wrap; gap: var(--space-micro); }
.cite-count { margin-left: auto; font-size: var(--type-data); letter-spacing: var(--track-tab); }
.cite-dropped { flex-basis: 100%; font-size: var(--type-caption); }
/* A passage ID in the commander's own words, or in the list: a real button, so
   reaching the passage never needs a mouse. Set in the data face, not the
   uppercase display face every other button wears. */
.cite-link {
    display: inline-flex; align-items: center; min-height: 24px;
    font-family: var(--font-data); font-size: var(--type-data); font-weight: 600; letter-spacing: var(--track-data); text-transform: none;
    color: var(--text-primary); background: var(--tint-objective);   /* the accent as text measured 4.0:1 on Field Briefing; the edge and underline carry the link */
    border: 1px solid var(--accent-color); border-radius: var(--radius); padding: 0 var(--space-tight);
    text-decoration: underline; text-underline-offset: 2px;
}
.cite-link:hover { border-color: var(--accent-color); }
.cite-miss { font-family: var(--font-data); font-size: var(--type-data); border-bottom: 1px dotted var(--text-secondary); }
.cite-miss-note { font-family: var(--font-body); font-size: var(--type-caption); color: var(--text-secondary); }

/* The source rows in the Knowledge Base sidebar open that source's passages. */
.kb-src-open {
    flex: 1; min-width: 0; text-align: left; font: inherit; letter-spacing: normal; text-transform: none; font-weight: 400;
    background: none; border: 0; padding: 0; color: var(--text-primary);
}
.kb-src-open:hover { background: none; }
.kb-src-open:hover .kb-src-name { text-decoration: underline; }
.kb-src-open .kb-src-name { display: block; }

/* One passage in the reading pane, under the ID the commander is handed and
   cites. The one a citation opened has a heavy edge and says so in words. */
.kb-passage { padding: var(--space-snug) var(--space-base); background: var(--surface-2); border: 1px solid var(--surface-border); border-radius: var(--radius); }
.kb-passage.is-target { border-color: var(--accent-color); box-shadow: inset 0 0 0 1px var(--accent-color); background: var(--tint-objective); }
.kb-passage-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-hair) var(--space-snug); margin-bottom: var(--space-micro); }
.kb-pid { font-size: var(--type-data); font-weight: 600; letter-spacing: var(--track-data); color: var(--text-primary); border: 1px solid var(--control-border); border-radius: var(--radius); padding: 0 var(--space-tight); }
.kb-pkind { font-size: var(--type-data); letter-spacing: var(--track-tab); text-transform: uppercase; color: var(--text-secondary); }
.kb-ptarget { margin-left: auto; font-size: var(--type-data); letter-spacing: var(--track-tab); text-transform: uppercase; color: var(--text-primary); }
.kb-back { margin-left: var(--space-snug); }   /* "Back to the order" (phase 13): the walk from order to doctrine goes both ways */
.kb-ptext { margin: 0; font-size: var(--type-body); line-height: var(--leading-body); color: var(--text-primary); max-width: 74ch; overflow-wrap: break-word; }

/* Every change the engine made between the model's reply and the packet the
   game receives: one line each, the kind as a word, before → after. */
.repair-list { margin-top: var(--space-snug); font-size: var(--type-control); line-height: var(--leading-body); max-width: 74ch; }
.repair-list > summary { cursor: pointer; font-family: var(--font-display); letter-spacing: var(--track-control); text-transform: uppercase; color: var(--text-secondary); padding: var(--space-tight) 0; }
.repair-list > summary:hover { color: var(--text-primary); }
.repair-list ul { margin: var(--space-tight) 0 0; padding-left: var(--space-shell); color: var(--text-secondary); }
.repair-list li { overflow-wrap: anywhere; margin-bottom: var(--space-tight); }
.repair-kind { font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-label); text-transform: uppercase; color: var(--text-primary); border: 1px solid var(--surface-border-strong); border-radius: var(--radius); padding: 0 var(--space-tight); margin-right: var(--space-tight); }

/* "engine default" beside an order's headline: the packet went out, but no
   model decided it. A bordered word, so it reads without colour. */
.log-entry .claim-tag { font-family: var(--font-data); font-size: var(--type-data); font-weight: 400; letter-spacing: var(--track-label); color: var(--text-secondary); border: 1px dashed var(--surface-border-strong); border-radius: var(--radius); padding: 0 var(--space-tight); vertical-align: middle; white-space: nowrap; }

/* A recorded order (phase 12): the tag beside the headline, and the
   recording's label under it — both words, dashed like "engine default",
   with fallback's amber edge as the second cue. */
.log-entry .replay-tag { border-color: var(--status-working); color: var(--text-primary); }
.replay-order-note { margin: var(--space-tight) 0 0; font-size: var(--type-caption); line-height: var(--leading-data); color: var(--text-secondary); max-width: 74ch; }
.replay-order-note b { color: var(--text-primary); font-weight: 600; }

/* Static alert badge — solid fill reads as urgent without motion (no infinite
   flash → no photosensitivity/vestibular hazard on an error message). */
.linter-flag-text {
    display: flex; align-items: center; gap: var(--space-snug);
    font-family: var(--font-data); font-weight: 600; font-size: var(--type-caption); letter-spacing: var(--track-display); text-transform: uppercase;
    color: var(--on-danger); background: var(--accent-danger); border: 1px solid var(--accent-red-deep);
    border-radius: var(--radius); padding: var(--space-snug) var(--space-base); margin: var(--space-snug) 0;
}
.linter-flag-text::before { content: "\25B2"; font-size: var(--type-data); line-height: var(--leading-display); }

/* ---- The semantic field ----
   Sits between the feed head and the feed. It is an instrument, so it
   takes the recessed ground the other readouts use and never grows past
   a third of the column; the feed keeps the rest. */
.field-panel { flex-shrink: 0; border-bottom: 1px solid var(--surface-border); background: var(--surface-recessed); }
.field-head {
    display: flex; align-items: center; gap: var(--space-snug); width: 100%;
    padding: var(--space-snug) var(--space-shell); background: transparent; border: 0;
    color: var(--text-primary); cursor: pointer; text-align: left;
    font-family: var(--font-display); font-size: var(--type-data); font-weight: 500;
    letter-spacing: var(--track-control); text-transform: uppercase;
}
.field-head:hover { background: var(--tint-objective); }
.field-head:focus-visible { outline: 2px solid var(--accent-color); outline-offset: -2px; }
.field-head .ico { transition: transform var(--dur-fast) var(--ease-out); flex-shrink: 0; }
.field-head[aria-expanded="true"] .ico { transform: rotate(90deg); }
.field-title { flex-shrink: 0; }
.field-status { margin-left: auto; color: var(--text-secondary); font-size: var(--type-data); letter-spacing: var(--track-data); text-transform: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Map left, readout right. A 2D projection drawn isotropically — which it
   must be, or distance stops meaning similarity — needs a square; across
   a 1000px column that left the whole corpus in a 140px box with the rest
   of the strip empty. The square now owns the height and the prose owns
   the width neither of them was using. */
.field-body { display: flex; align-items: stretch; gap: var(--space-shell); padding: 0 var(--space-shell) var(--space-base); }
.field-head[aria-expanded="false"] + .field-body { display: none; }
/* The frame is the instrument bezel: it bounds the projection so a point
   near the edge reads as near the edge of the corpus, not as floating. */
#semantic-field {
    display: block; flex: 0 0 auto; width: 176px; height: 176px;
    border: 1px solid var(--surface-border); border-radius: var(--radius);
    background: var(--surface-recessed-soft);
}
/* Not greedy. The note is capped at a readable measure, so a flex: 1 side
   column claimed every spare pixel and opened a 400px hole between the
   prose and the key on a wide window. Sized to its content, the three
   blocks pack left and the slack falls at the panel edge, where it reads
   as margin instead of as a gap someone forgot to fill. */
.field-side { flex: 0 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: var(--space-base); }
.field-note { margin: 0; max-width: 62ch; font-size: var(--type-caption); line-height: var(--leading-body); color: var(--text-secondary); text-wrap: pretty; }
/* The map's numerals, spelled out. Right-hand column so the panel reads
   map -> meaning -> key, and the width stops being dead space. */
.field-key {
    flex: 0 0 auto; align-self: center; margin: 0; padding: 0 0 0 var(--space-shell); list-style: none;
    border-left: 1px solid var(--surface-border);
    display: flex; flex-direction: column; gap: var(--space-snug);
    font-size: var(--type-data); letter-spacing: var(--track-data);
}
.field-key li { display: flex; align-items: center; gap: var(--space-snug); }
.fk-rank {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px; flex-shrink: 0; border-radius: 50%;
    border: 1px solid var(--accent-color); color: var(--accent-color); font-weight: 600;
}
.fk-src { color: var(--text-primary); max-width: 18ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fk-score { color: var(--text-secondary); margin-left: auto; font-family: var(--font-data); font-variant-numeric: tabular-nums; }
@media (max-width: 1180px) { .field-key { display: none; } }
.field-legend {
    display: flex; flex-wrap: wrap; gap: var(--space-snug) var(--space-base); margin: 0;
    font-size: var(--type-data); letter-spacing: var(--track-data); color: var(--text-secondary);
}
/* Below the two-column comms width the prose would be squeezed to a
   column of single words, so it steps out and the map takes the width. */
@media (max-width: 720px) {
    .field-body { flex-direction: column; align-items: center; }
    #semantic-field { width: min(100%, 240px); height: min(60vw, 240px); flex: 0 0 auto; }
    .field-side { width: 100%; }
    .field-note { display: none; }
}
.fl { display: inline-flex; align-items: center; gap: var(--space-tight); }
.fl::before { content: ""; width: 8px; height: 8px; flex-shrink: 0; }
/* Each key carries a shape as well as a hue: a dot, a ring, a cross —
   matching the canvas, and readable when the projector eats the colour. */
.fl-corpus::before { border-radius: 50%; background: var(--text-faint); }
.fl-hit::before { border-radius: 50%; border: 1.5px solid var(--accent-color); background: var(--accent-color); box-shadow: 0 0 0 2px var(--tint-objective); }
.fl-query::before {
    background: none; border-radius: 0;
    background-image: linear-gradient(var(--accent-danger), var(--accent-danger)), linear-gradient(var(--accent-danger), var(--accent-danger));
    background-size: 100% 1.5px, 1.5px 100%; background-position: center, center; background-repeat: no-repeat;
}
/* Short viewports already give the feed everything they can spare; the
   field is the first thing to stand down. */
@media (max-height: 600px) { .field-panel { display: none; } }

/* input dock */
.input-area { flex-shrink: 0; border-top: 1px solid var(--surface-border); background: var(--inset-ground); padding: var(--space-shell) var(--space-shell); display: flex; flex-direction: column; gap: var(--space-base); }
#radio-transcript-box { border-radius: var(--radius); }
#player-action { flex: 1; }
/* Why the order box cannot be typed into during a recorded run (phase 12). */
.replay-note { margin: 0; font-size: var(--type-caption); line-height: var(--leading-data); color: var(--text-secondary); max-width: 74ch; }
.replay-note[hidden] { display: none; }
#player-action:read-only:not(:disabled) { border-style: dashed; }
.dock-actions { display: flex; gap: var(--space-base); align-items: center; justify-content: space-between; }
#force-drop-btn { letter-spacing: var(--track-control); }
/* Off during a recorded run (no loot is rolled): DESIGN.md's disabled state. */
#force-drop-btn:disabled, #force-drop-btn:disabled:hover { color: var(--text-faint); background: transparent; border-color: var(--surface-border); box-shadow: none; cursor: default; }
