/* components.css — the shared controls and overlays: theme switcher, player
   action menu, Settings, Compare Commanders, NSE tactical map, run report.
   Loaded after base.css; every selector here carries a class or id, so it
   never competes with the element-level base rules. */

/* Theme switcher (segmented control) */
.theme-switch { display: flex; gap: var(--space-hair); background: var(--surface-recessed); padding: var(--space-hair); border: 1px solid var(--surface-border); border-radius: var(--radius); flex-shrink: 0; }
.theme-switch button { font-family: var(--font-display); font-weight: 500; font-size: var(--type-data); letter-spacing: var(--track-control); text-transform: uppercase; background: transparent; color: var(--text-secondary); border: none; padding: var(--space-micro) var(--space-snug); border-radius: 2px; cursor: pointer; transition: color 0.16s ease, background 0.16s ease; }
.theme-switch button:hover { color: var(--text-primary); background: var(--hover-tint); }
.theme-switch button.active { color: var(--text-primary); background: var(--tint-objective); box-shadow: inset 0 -2px 0 var(--accent-color); }
/* "Los Angeles" is the one theme name too long for the inline strip —
   it costs the utility cluster ~95px, which is what forces the label
   and fold breakpoints in header.css. It abbreviates in the strip and returns
   to full length inside the overflow menu, where there's room. The
   aria-label carries the full name at every width, so the abbreviation
   is purely visual (same contract as the nav tabs). */
.header-utils .theme-switch .t-full { display: none; }
.header-utils .theme-switch .t-short { display: inline; }

/* ---- Player action menu (compact tabbed picker) ---- */
.action-tabs { display: flex; flex-wrap: wrap; gap: var(--space-tight); }
.action-tab { font-family: var(--font-display); font-size: var(--type-data); font-weight: 500; letter-spacing: var(--track-display); text-transform: uppercase; background: transparent; color: var(--text-secondary); border: 1px solid transparent; border-radius: var(--radius); padding: var(--space-tight) var(--space-snug); cursor: pointer; transition: color .14s ease, background .14s ease, border-color .14s ease; }
.action-tab:hover { color: var(--text-secondary); background: var(--hover-tint-soft); }
.action-tab.active { color: var(--text-primary); border-color: var(--surface-border); background: var(--tint-objective); }
/* A constant reserved area so switching tabs never resizes the menu or
   shifts the input below it. That intent was right; 78px was not. It is
   exactly two chip rows, and Featured has always needed three — so one row
   of orders was permanently clipped on every desktop, and at 420px every
   one of the eight tabs was clipped, showing 2 rows of up to 8.
   The height is stated in ROWS now, and the row count is the measured
   worst case at each width: 3 rows covers every tab down to 1000px, 4
   covers the narrower two-column widths. */
.action-featured {
    --chip-row: 34px;          /* 13px label + 6px padding + 1px border, both sides */
    --chip-rows: 3;
    display: flex; flex-wrap: wrap; align-content: flex-start; gap: var(--space-snug);
    height: calc(var(--chip-rows) * var(--chip-row) + (var(--chip-rows) - 1) * var(--space-snug));
    overflow-y: auto; scrollbar-gutter: stable;
}
@media (max-width: 1000px) { .action-featured { --chip-rows: 4; } }
/* On a phone even four rows clips Featured and would eat the feed to do it,
   so the tray becomes one horizontally-scrolling rail — the reserved area
   drops to a single row and nothing is hidden without an affordance.
   The height condition is the one that matters in landscape: a phone on
   its side is WIDE and short, so it used to miss the width test and take
   the four-row tray, which reserved ~170px of a 390px viewport and left
   the feed a 30px sliver with Transmit Order below the fold. */
@media (max-width: 640px), (max-height: 600px) {
    .action-featured { --chip-rows: 1; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; }
    .action-chip { flex: 0 0 auto; white-space: nowrap; }
    /* The category tabs get the same rail. At 44px touch targets they
       wrapped to three rows and took ~150px of a phone — more than the
       chips they filter. One scrolling row costs 44px and hides nothing
       that the swipe does not reach. */
    .action-tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
    .action-tabs::-webkit-scrollbar { display: none; }
    .action-tab { flex: 0 0 auto; white-space: nowrap; }
}
.action-chip { background: var(--surface-recessed-soft); border: 1px solid var(--surface-border); color: var(--text-secondary); font-family: var(--font-body); font-size: var(--type-control); font-weight: 400; letter-spacing: normal; text-transform: none; padding: var(--space-micro) var(--space-base); border-radius: var(--radius); cursor: pointer; transition: color .14s ease, border-color .14s ease; }
.action-chip:hover:not(:disabled) { color: var(--text-primary); border-color: var(--surface-border-strong); }
.action-chip:disabled { opacity: 0.5; cursor: default; }

/* ---- Settings modal ---- */
.settings-overlay { position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center; background: var(--scrim); padding: var(--space-shell); }
.settings-overlay.is-open { display: flex; }
.settings-panel { width: min(460px, 100%); max-height: 88vh; overflow-y: auto; background: var(--surface-2); border: 1px solid var(--surface-border-strong); border-radius: var(--radius); padding: var(--space-shell) var(--space-shell); box-shadow: var(--shadow-overlay); }
.settings-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-micro); }
.settings-head h2 { font-family: var(--font-display); font-weight: 600; letter-spacing: var(--track-control); text-transform: uppercase; font-size: var(--type-claim); color: var(--text-primary); margin: 0; }
.settings-close { display: inline-grid; place-items: center; padding: 0; background: transparent; border: 1px solid var(--control-border); color: var(--text-secondary); border-radius: var(--radius); width: 32px; height: 32px; cursor: pointer; flex: 0 0 auto; }
/* One close control everywhere (phase 13): the dialogs used a text ✕ that sat
   off-centre in its box while the sheets drew the icon; both draw the icon now,
   and each says what it closes. */
.settings-close .ico { width: 16px; height: 16px; }
.settings-close:hover { color: var(--text-primary); border-color: var(--surface-border-strong); }
.settings-section { padding: var(--space-base) 0; border-top: 1px solid var(--surface-border); }
.settings-section h3 { font-family: var(--font-display); font-weight: 600; text-transform: uppercase; letter-spacing: var(--track-tab); font-size: var(--type-caption); color: var(--text-secondary); margin: 0 0 var(--space-snug); }
.settings-note { font-size: var(--type-caption); color: var(--text-faint); margin: 0 0 var(--space-base); line-height: var(--leading-data); }
.settings-radios { display: flex; flex-direction: column; gap: var(--space-micro); }
.settings-radios label { display: flex; align-items: baseline; gap: var(--space-snug); padding: var(--space-snug) var(--space-snug); border: 1px solid var(--surface-border); border-radius: var(--radius); cursor: pointer; }
.settings-radios label:hover { border-color: var(--surface-border-strong); }
.settings-radios input { margin: 0; accent-color: var(--accent-color); }
.settings-radios .m-label { font-weight: 600; color: var(--text-primary); }
.settings-radios .m-note { font-size: var(--type-data); color: var(--text-faint); margin-left: var(--space-tight); }
.settings-section .theme-switch { display: inline-flex; }
/* Reasoning model: the running model's readouts, then the tiered choices. */
#settings-model-status .status-panel { margin-bottom: var(--space-base); }
#settings-model-status .status-row .v { white-space: normal; text-align: right; overflow-wrap: anywhere; }
.settings-radios .settings-tier { margin: var(--space-snug) 0 0; }
.settings-radios input:disabled + span { opacity: 0.6; }

/* ---- Compare Commanders modal ---- */
.compare-panel { width: min(780px, 100%); }
.compare-controls { display: flex; flex-direction: column; gap: var(--space-base); padding: var(--space-micro) 0 var(--space-shell); border-bottom: 1px solid var(--surface-border); margin-bottom: var(--space-shell); }
.compare-field { display: flex; flex-direction: column; gap: var(--space-tight); font-size: var(--type-data); letter-spacing: var(--track-display); text-transform: uppercase; color: var(--text-secondary); }
.compare-field select { font: inherit; font-size: var(--type-control); text-transform: none; letter-spacing: normal; padding: var(--space-micro) var(--space-section) var(--space-micro) var(--space-snug); background-color: var(--surface-recessed-soft); color: var(--text-primary); border: 1px solid var(--surface-border); border-radius: var(--radius); }
.compare-persona-row { display: flex; gap: var(--space-base); }
.compare-persona-row .compare-field { flex: 1; min-width: 0; }
.compare-results { display: flex; gap: var(--space-base); }
.compare-working { color: var(--text-faint); font-size: var(--type-control); font-style: italic; padding: var(--space-snug) 0; }
.compare-col { flex: 1; min-width: 0; border: 1px solid var(--surface-border); border-radius: var(--radius); padding: var(--space-base) var(--space-base); background: var(--surface-recessed-soft); }
.compare-col h4 { font-family: var(--font-display); font-size: var(--type-control); font-weight: 600; text-transform: uppercase; letter-spacing: var(--track-control); color: var(--accent-color); margin: 0 0 var(--space-snug); line-height: var(--leading-title); }
.compare-col .cmp-obs { font-size: var(--type-caption); color: var(--text-primary); margin-bottom: var(--space-micro); line-height: var(--leading-data); }
.compare-col .cmp-rat { font-size: var(--type-caption); color: var(--text-secondary); font-style: italic; margin-bottom: var(--space-snug); line-height: var(--leading-data); }
/* Said in words, upright, so a missing field never passes for the model's italic prose. */
.compare-col .cmp-none { font-style: normal; color: var(--text-faint); }
.compare-col .cmp-line { display: flex; justify-content: space-between; gap: var(--space-snug); font-size: var(--type-caption); padding: var(--space-tight) 0; border-top: 1px solid var(--surface-border); }
.compare-col .cmp-line span { color: var(--text-faint); text-transform: uppercase; font-size: var(--type-data); letter-spacing: var(--track-control); align-self: center; }
.compare-col .cmp-line b { color: var(--text-primary); text-align: right; font-family: var(--font-data); font-size: var(--type-data); overflow-wrap: anywhere; }
@media (max-width: 620px) { .compare-results, .compare-persona-row { flex-direction: column; } }

/* ---- NSE tactical map ---- */
.map-panel { width: min(640px, 100%); }
.nse-canvas { border: 1px solid var(--surface-border); border-radius: var(--radius); background: var(--bg-color); overflow: hidden; }
.nse-svg { display: block; width: 100%; height: auto; }
.nse-unit { transition: transform 1.1s cubic-bezier(.4,.1,.2,1); }
.nse-unit.rerouted circle { stroke: var(--loot-gold); stroke-width: 0.8; }
.nse-lbl { font-family: var(--font-data); font-size: 4.2px; fill: var(--text-secondary); }
.nse-lbl.unit { fill: var(--oga-accent); }
.nse-lbl.faint { fill: var(--accent-danger); opacity: 0.75; font-size: 3.6px; letter-spacing: 0.4px; }
/* Sectors the order is not for step back; the one it is for keeps full
   strength and says ORDERS HERE (outline weight and the words carry it, not hue). */
.nse-lbl.sector { fill: var(--text-faint); font-size: 3.6px; }
.nse-lbl.order { fill: var(--text-primary); font-size: 3.6px; letter-spacing: 0.4px; font-weight: 600; }
.nse-caption { margin-top: var(--space-snug); font-size: var(--type-control); color: var(--text-secondary); line-height: var(--leading-data); }
.nse-caption b { color: var(--text-primary); font-family: var(--font-data); font-size: var(--type-data); }
.nse-caption .nse-fw { color: var(--loot-gold); }
/* Phase 13: the sectors are printed plates. The order's own is full strength
   and framed in the accent; the rest sit back so the eye goes to it. Every
   label carries a halo in the panel colour, because some sit over a plate and
   words over a picture still have to read at AA. */
.nse-plate { opacity: 0.5; }
.nse-plate.is-target { opacity: 1; }
.nse-lbl { paint-order: stroke; stroke: var(--surface-2); stroke-width: 1.1px; stroke-linejoin: round; }
.nse-caption .nse-exact { font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-data); color: var(--text-secondary); }
.nse-caption .nse-you { color: var(--danger-text); font-weight: 600; }
.nse-controls { display: flex; align-items: center; gap: var(--space-snug); margin-top: var(--space-snug); }
.nse-controls button { padding: var(--space-tight) var(--space-base); font-size: var(--type-caption); }
.nse-controls button:disabled { opacity: 0.4; cursor: default; }
.nse-step { margin-left: auto; font-family: var(--font-data); font-size: var(--type-data); color: var(--text-faint); letter-spacing: var(--track-data); }

/* ---- Run report ---- */
.report-panel { width: min(640px, 100%); }
.report-body h3 { font-family: var(--font-display); font-size: var(--type-caption); letter-spacing: var(--track-tab); text-transform: uppercase; color: var(--text-secondary); margin: var(--space-shell) 0 var(--space-snug); }
.report-body ul { margin: 0; padding-left: var(--space-shell); font-size: var(--type-control); color: var(--text-secondary); line-height: var(--leading-body); }
.report-body ul b, .report-body .rr-row b { color: var(--text-primary); }
.rr-row { display: flex; gap: var(--space-base); padding: var(--space-micro) 0; border-top: 1px solid var(--surface-border); font-size: var(--type-control); color: var(--text-secondary); }
.rr-tag { flex: 0 0 120px; font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-display); color: var(--text-faint); padding-top: 1px; }
.rr-drift .rr-tag, .rr-safety .rr-tag { color: var(--loot-gold); }
.rr-learning .rr-tag { color: var(--oga-accent); }

/* ---- Behavior eval (src/ui/evalview.js) ----
   A measurement table, not a dashboard: one row per measurement, one column
   per model, counts beside every percentage so no rate stands without the
   sample it came from. The plain sentences lead; the table is for whoever
   wants to check them. Wide enough for five models; narrower screens scroll the
   table inside its own frame, never the page. */
.settings-actions { display: flex; flex-wrap: wrap; gap: var(--space-snug); }
/* Live reasoning (phase 10): two labelled selects side by side, stacking on a phone. */
.settings-pair { display: grid; grid-template-columns: max-content minmax(0, 16rem); align-items: center; gap: var(--space-snug) var(--space-base); margin: var(--space-snug) 0; }
@media (max-width: 520px) { .settings-pair { grid-template-columns: 1fr; } }
/* The safety rule table, in words. */
.settings-rules { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-micro); font-size: var(--type-caption); line-height: var(--leading-data); color: var(--text-secondary); }
.settings-rules li { padding: var(--space-snug); border: 1px solid var(--surface-border); border-radius: var(--radius); }
.settings-rules b { color: var(--text-primary); font-weight: 600; }
/* Recorded Replay (phase 12): the shipped recordings, one row each. */
.replay-list { list-style: none; margin: 0 0 var(--space-base); padding: 0; display: flex; flex-direction: column; gap: var(--space-micro); font-size: var(--type-caption); line-height: var(--leading-data); color: var(--text-secondary); }
.replay-list li { display: flex; align-items: center; justify-content: space-between; gap: var(--space-base); padding: var(--space-snug); border: 1px solid var(--surface-border); border-radius: var(--radius); }
.replay-list b { color: var(--text-primary); font-weight: 600; }
/* DESIGN.md's disabled state: faint label, no fill, no hover. The eval holds
   its run buttons disabled for the whole run. */
.settings-actions button:disabled, .settings-actions button:disabled:hover { color: var(--text-faint); background: transparent; border-color: var(--surface-border); cursor: default; box-shadow: none; }
.eval-panel { width: min(980px, 100%); }
.eval-actions { margin-top: var(--space-shell); }
.eval-progress { padding: var(--space-base); margin-bottom: var(--space-base); background: var(--surface-2); border: 1px solid var(--surface-border); border-radius: var(--radius); }
.eval-progress-msg { margin: 0; font-size: var(--type-control); color: var(--text-primary); line-height: var(--leading-data); }
.eval-rank { margin: 0 0 var(--space-snug); font-size: var(--type-body); font-weight: 600; color: var(--text-primary); line-height: var(--leading-body); max-width: 72ch; }
.eval-leads { margin: 0 0 var(--space-base); padding-left: var(--space-shell); font-size: var(--type-control); color: var(--text-secondary); line-height: var(--leading-body); max-width: 80ch; }
.eval-plain { margin-bottom: var(--space-base); }
.eval-plain p { margin: 0 0 var(--space-micro); font-size: var(--type-control); color: var(--text-secondary); line-height: var(--leading-body); max-width: 72ch; }
.eval-table-wrap { overflow-x: auto; border: 1px solid var(--surface-border); border-radius: var(--radius); margin-bottom: var(--space-base); }
.eval-table { width: 100%; border-collapse: collapse; font-size: var(--type-caption); }
.eval-table th, .eval-table td { padding: var(--space-tight) var(--space-snug); border-top: 1px solid var(--surface-border); text-align: left; vertical-align: top; }
.eval-table thead th { border-top: none; background: var(--surface-recessed-soft); }
.eval-table tbody th { font-weight: 400; color: var(--text-secondary); min-width: 15ch; }
.eval-table td { color: var(--text-primary); min-width: 13ch; }
.eval-table .eval-sub th { padding-left: var(--space-shell); }
.eval-group th { font-family: var(--font-display); font-weight: 600; font-size: var(--type-data); letter-spacing: var(--track-label); text-transform: uppercase; color: var(--accent-color); background: var(--surface-recessed-soft); padding-top: var(--space-snug); }
.eval-group .eval-n { text-transform: none; letter-spacing: normal; margin-left: var(--space-tight); }
.eval-model { display: block; font-family: var(--font-display); font-weight: 600; font-size: var(--type-control); letter-spacing: var(--track-control); text-transform: uppercase; color: var(--text-primary); }
.eval-pct { font-family: var(--font-data); font-weight: 400; font-variant-numeric: tabular-nums; color: var(--text-primary); }
.eval-n { font-family: var(--font-data); font-size: var(--type-data); font-variant-numeric: tabular-nums; color: var(--text-faint); }
th .eval-n, td .eval-n { display: inline-block; }
.eval-cases > summary { cursor: pointer; font-family: var(--font-display); font-size: var(--type-control); letter-spacing: var(--track-control); text-transform: uppercase; color: var(--accent-color); padding: var(--space-snug) 0; }
.eval-cases > summary:hover { color: var(--text-primary); }
.eval-cases .eval-table td > span, .eval-cases .eval-table th > span { display: block; }
.eval-action { font-size: var(--type-caption); color: var(--text-faint); font-style: italic; max-width: 32ch; }
/* Within / outside is carried by the word; the colour only repeats it. */
.eval-in, .eval-out { font-family: var(--font-display); font-weight: 600; font-size: var(--type-data); letter-spacing: var(--track-label); text-transform: uppercase; }
.eval-in { color: var(--success-text); }
.eval-out { color: var(--danger-text); }
.eval-why { font-size: var(--type-caption); color: var(--text-secondary); }
.eval-decision { font-family: var(--font-data); font-size: var(--type-data); color: var(--text-primary); }
.eval-cases .eval-table td { min-width: 20ch; }
thead .eval-model { white-space: nowrap; }

/* ---- Printed plates (phase 13, src/ui/plates.js) ----
   One grayscale engraving per subject, printed in the theme's two inks by
   the #plate-duotone filter in index.html. The two flood classes are how the
   filter reads the theme: a flood colour is a CSS property, so it resolves
   through --plate-ink and --plate-paper like any other colour here. The
   frame sits on a wrapper, never on the image, or the filter would re-ink
   the border too. */
.plate-ink-flood { flood-color: var(--plate-ink); }
.plate-paper-flood { flood-color: var(--plate-paper); }
.plate { filter: url(#plate-duotone); display: block; object-fit: cover; }
