/* header.css — the command header (brand, nav tabs, utility cluster), the
   classification strip and its overflow popover, and the shared motion that
   was authored beside them: the view-enter, LED and drift keyframes and the
   reduced-motion freeze. */

/* =================== HEADER =================== */
header.cmd-header {
    position: relative;
    display: flex;
    align-items: center;
    gap: clamp(10px, 1.6vw, 28px);
    padding: 14px var(--gutter-shell);
    min-width: 0;
    background: var(--header-ground);
    border-bottom: 1px solid var(--surface-border);
    z-index: 30;
    flex-shrink: 0;
}
header.cmd-header::after {
    content: "";
    position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
    background: repeating-linear-gradient(135deg, var(--accent-danger) 0 18px, transparent 18px 34px);
    /* Blur the console until only mass survives and this 2px hazard strip
       was among the five loudest things on screen — a texture outranking
       every proof moment in the feed. DESIGN.md is explicit that red is
       never used for decoration. The motif stays; its pull halves, and
       everything it was competing with gets louder for free. */
    opacity: 0.26;
}

.brand { display: flex; align-items: center; gap: 14px; flex-shrink: 0; }
.brand .wordmark { display: flex; flex-direction: column; line-height: var(--leading-display); margin: 0; }
.brand .wordmark .top { font-family: var(--font-display); font-weight: 700; font-size: var(--type-display); letter-spacing: var(--track-display); text-transform: uppercase; color: var(--text-primary); }
.brand .wordmark .top .ru { color: var(--danger-text); }
.brand .wordmark .sub { font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-seal); color: var(--text-secondary); margin-top: 5px; }

.nav-spacer { flex: 1; }

.tab-container { display: flex; gap: 4px; background: var(--surface-recessed); padding: 4px; border: 1px solid var(--surface-border); border-radius: var(--radius); flex-shrink: 0; }
.tab-btn {
    position: relative;
    font-family: var(--font-display); font-weight: 500; font-size: var(--type-control); letter-spacing: var(--track-tab); text-transform: uppercase;
    background: transparent; color: var(--text-secondary);
    border: none; padding: 9px 18px; cursor: pointer; border-radius: 2px;
    white-space: nowrap;
    transition: color 0.16s ease, background 0.16s ease;
}
/* Navigation is the last thing that yields — it only tightens, never wraps.
   The button's aria-label carries the full name at every width, so the
   abbreviation is purely visual. */
.tab-btn .t-short { display: none; }
@media (max-width: 1600px) { .tab-btn { padding: 9px 13px; letter-spacing: 0.07em; } }
@media (max-width: 1100px) { .tab-btn { padding: 9px 10px; font-size: var(--type-caption); } }
/* 920, not 820: between those two the full labels at 12px are wider than
   the window. The step was unreachable before — the label span outranked
   .tab-btn's font-size (see the inherit rule up by the base type scale),
   so every size here was inert and the tabs rendered at 15px throughout. */
/* 0.04em was 4% on 11px all-caps, below the floor caps need — and caps at the
   smallest size in the system are where tracking matters most. Measured: in the
   830-980px band where the full labels still show, the four tabs occupy 430px of
   a 452px nav, so 0.06em costs ~11px of the 22px of slack and still does not
   fold. Below 830px the labels abbreviate, which is the real mechanism. */
@media (max-width: 980px)  { .tab-btn { padding: 8px 9px; font-size: var(--type-data); letter-spacing: 0.06em; } }
/* Last resort: abbreviate. 830 rather than 700 because full labels at
   11px still need ~810px of window, and navigation tightens before it
   lets anything spill off the edge. */
@media (max-width: 920px)  {
    .tab-btn .t-full  { display: none; }
    .tab-btn .t-short { display: inline; }
    .tab-btn { padding: 8px 10px; letter-spacing: var(--track-control); }
}
.tab-btn:hover { color: var(--text-primary); background: var(--tint-objective); }
.tab-btn.active { color: var(--heading-strong); background: var(--tint-command); }
.tab-btn.active::after {
    content: ""; position: absolute; left: 10px; right: 10px; bottom: -5px; height: 2px; background: var(--accent-danger);
}

/* Utility cluster. Text stays at --text-primary for AA contrast (the old
   red-on-dark measured 4.08:1 at 12px); the red now lives in the border
   and the live dot, where it signals without having to be read. */
.header-utils { display: flex; align-items: center; gap: 8px; flex-shrink: 0; min-width: 0; }
.theater-trigger {
    font-family: var(--font-display); font-weight: 600; font-size: var(--type-caption); letter-spacing: var(--track-data); text-transform: uppercase;
    background: transparent; color: var(--text-primary);
    border: 1px solid var(--danger-border); padding: 9px 14px; cursor: pointer; border-radius: var(--radius);
    display: flex; align-items: center; gap: 9px; white-space: nowrap; flex-shrink: 0;
    transition: color .16s ease, background .16s ease, border-color .16s ease;
}
.theater-trigger .ico { color: var(--accent-danger); }
.theater-trigger:hover { background: var(--tint-command); border-color: var(--accent-danger); }
.theater-trigger:hover .ico { color: var(--heading-strong); }

/* Overflow toggle: only exists once the cluster folds (≤1200px). */
.utils-toggle {
    display: none; align-items: center; justify-content: center;
    background: transparent; color: var(--text-primary);
    border: 1px solid var(--surface-border-strong); border-radius: var(--radius);
    width: 38px; height: 38px; cursor: pointer; flex-shrink: 0;
    transition: color .16s ease, background .16s ease, border-color .16s ease;
}
.utils-toggle:hover, .utils-toggle[aria-expanded="true"] { background: var(--tint-objective); border-color: var(--accent-color); }

/* Every number in these four steps is the header's measured intrinsic
   width in that state, not an estimate — the previous set was short in
   three separate bands and the header overflowed the viewport there.
   Step 1 — drop the labels, keep the icons and their tooltips. With
   labels on the header needs 2067px, so they yield on anything smaller.
   The Pitch button keeps its label below this point; it sits outside the
   cluster and is the one control a presenter cannot afford to hunt for. */
@media (max-width: 2070px) {
    .theater-trigger .lbl { display: none; }
    .theater-trigger.is-labelled .lbl { display: inline; }
    .theater-trigger { padding: 9px 11px; }
    .theme-switch { gap: 2px; padding: 2px; }
    .theme-switch button { padding: 6px 7px; font-size: var(--type-data); letter-spacing: 0.05em; }
}
/* Step 2 — fold the cluster behind the overflow toggle. The icon row needs
   1502px once the tablist has tightened, so it holds down to 1511. Below
   that Theater / Map / Compare / Settings move into the overflow menu and
   Pitch stays on the bar, because losing the demo control to a menu is the
   thing this layout most has to avoid. */
@media (max-width: 1510px) {
    .utils-toggle { display: flex; }
    .header-utils {
        display: none;
        position: absolute; top: calc(100% + 6px); right: clamp(12px, 1.8vw, 26px);
        flex-direction: column; align-items: stretch; gap: 6px;
        background: var(--surface-raised); border: 1px solid var(--surface-border-strong);
        border-radius: var(--radius); padding: 10px; z-index: 40;
        box-shadow: var(--shadow-overlay);
    }
    .header-utils.is-open { display: flex; animation: viewEnter var(--dur-fast) var(--ease-out); }
    .header-utils .theater-trigger { padding: 9px 12px; justify-content: flex-start; }
    .header-utils .theater-trigger .lbl { display: inline; }   /* room again in the menu */
    .header-utils .theme-switch { justify-content: center; }
    .header-utils .theme-switch button { padding: 6px 12px; font-size: var(--type-data); }
    .header-utils .theme-switch .t-full { display: inline; }   /* room again in the menu */
    .header-utils .theme-switch .t-short { display: none; }
}
/* Below the fold the bar is brand + tablist + Pitch + overflow, and Pitch's
   label is the next thing that can go: the button stays put and keeps its
   tooltip and accessible name, which is what a presenter needs from it.
   Phase 13 moved this from 1150px to 960px: at 1024 (a small projector, a
   half-screen share) the presenter's own control had shrunk to a bare chevron
   while the bar still had the room for its word, measured in all three themes. */
@media (max-width: 960px) { #pitch-btn .lbl { display: none; } }
/* Step 3 — the wordmark's tagline is the thing that yields, not a control. */
@media (max-width: 900px) {
    .brand .wordmark .sub { display: none; }
    .brand .wordmark .top { font-size: var(--type-claim); }
}
/* Step 4 — phones: two rows. Brand and overflow share the first, the
   tablist gets the full width of the second and divides it evenly.
   Nothing is laid out past the edge at any width down to 320px. */
@media (max-width: 640px) {
    header.cmd-header { flex-wrap: wrap; row-gap: 10px; padding: 11px 14px; }
    /* Two rows is the intent above, and 44px touch targets cost the first
       one 4px more than it had — which bought a whole third row for the
       overflow button alone. The wordmark takes one more rung down and
       the row fits again with room to spare. */
    .brand .wordmark .top { font-size: var(--type-body); }
    .brand { order: 1; }
    .utils-toggle { order: 2; margin-left: auto; }
    .nav-spacer { display: none; }
    .tab-container { order: 3; width: 100%; }
    .tab-btn { flex: 1; min-width: 0; padding: 8px 4px; }
    .header-utils { top: auto; }
}

/* =================== CLASSIFICATION STRIP =================== */
.class-strip {
    display: flex; align-items: stretch; gap: 0;
    background: var(--strip-ground); border-bottom: 1px solid var(--surface-border);
    font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-title); flex-shrink: 0; z-index: 20;
}
.class-strip .seal { background: var(--accent-red-deep); color: var(--on-danger); padding: 6px 16px; font-weight: 600; letter-spacing: var(--track-seal); display: flex; align-items: center; gap: 8px; }
.class-strip .items { display: flex; align-items: center; gap: 26px; padding: 6px 18px; color: var(--text-secondary); flex: 1; overflow: hidden; white-space: nowrap; }
.class-strip .items b { color: var(--text-primary); font-weight: 500; }
.stat-led { display: inline-flex; align-items: center; gap: 7px; transition: color var(--dur-med) var(--ease-out); }
/* Keep strip items at natural width so overflow fades under the mask
   instead of shrinking and overlapping neighbours (see .items overflow). */
.class-strip .items > * { flex-shrink: 0; }
/* The commander name is the one readout whose length this console does not
   control — it is an entity title, so it can be a 120-character role, a
   string of emoji, or CJK. The strip already clips it; this makes the clip
   read as truncation rather than as a rendering fault, and the full value
   stays available on hover and to assistive tech. */
#commander-led b { display: inline-block; max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
/* The dot inherits the label's state colour via currentColor. It used to
   hardcode the affirmative accent, so a green heartbeat pulsed beside the
   red words ENGINE // OFFLINE. It also stops pulsing when the engine is
   not running: a pulse claims "alive", and that claim has to be true. */
.stat-led::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; box-shadow: 0 0 7px currentColor; animation: ledPulse 2.4s ease-in-out infinite; }
/* Hollow, not just unpulsed. "The engine is fully operational" versus
   "it is not" was carried by hue alone — green against gold against red —
   and that is the exact axis that collapses for the ~8% of men with
   red-green CVD, on a projector, and over compressed video. A filled dot
   against a ring survives all three. */
.stat-led.is-halted::before { animation: none; background: transparent; box-shadow: inset 0 0 0 2px currentColor; }
.class-strip .ticks { padding: 6px 18px; color: var(--text-faint); letter-spacing: var(--track-data); border-left: 1px solid var(--surface-border); }
/* degrade gracefully at narrow widths: drop low-priority items instead of clipping mid-word */
/* Overflowing readouts move into this popover instead of vanishing. */
.class-strip { position: relative; }
.strip-more {
    display: none; align-items: center; flex-shrink: 0;
    font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-control);
    background: transparent; color: var(--text-primary);
    border: none; border-left: 1px solid var(--surface-border);
    padding: 6px 12px; cursor: pointer;
}
.strip-more.is-needed { display: inline-flex; }
.strip-more:hover, .strip-more[aria-expanded="true"] { background: var(--tint-objective); }
.strip-overflow {
    position: absolute; top: 100%; right: 0; z-index: 45;
    display: none; flex-direction: column; gap: 7px;
    background: var(--surface-raised); border: 1px solid var(--surface-border-strong);
    border-radius: 0 0 var(--radius) var(--radius); padding: 11px 14px;
    box-shadow: var(--shadow-overlay);
    font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-tab);
    color: var(--text-secondary); white-space: nowrap;
}
.strip-overflow.is-open { display: flex; }
.strip-overflow b { color: var(--text-primary); font-weight: 500; }
.class-strip .items > .is-folded { display: none; }
.class-strip .seal-short { display: none; }
@media (max-width: 700px) {
    .class-strip .seal-full { display: none; }
    .class-strip .seal-short { display: inline; }
    .class-strip .seal { padding: 6px 10px; letter-spacing: var(--track-title); }
    .class-strip .items { gap: 14px; padding: 6px 10px; }
}
/* =================== RECORDED RUN BANNER (phase 12) =================== */
/* A recording is playing (src/ui/replay.js). Outside the strip's folding, so
   no width can hide it, and full-width so it is the first thing under the
   strip. Fallback's amber as hairline rules above and below; the words carry
   the state (RECORDED, NOT LIVE, Unedited / Edited), never the colour alone. */
.replay-banner {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-snug) var(--space-loose);
    padding: var(--space-snug) var(--space-shell);
    background: var(--surface-raised); color: var(--text-primary);
    border-top: 1px solid var(--status-working); border-bottom: 1px solid var(--status-working);
    font-size: var(--type-control); line-height: var(--leading-label); flex-shrink: 0; z-index: 19;
}
.replay-banner[hidden] { display: none; }
.rb-label { margin: 0; flex: 1 1 36ch; min-width: 0; font-size: var(--type-body); }
.rb-claim { font-family: var(--font-display); font-weight: 600; letter-spacing: var(--track-body); }
.rb-mark { color: var(--status-working); }
.rb-integrity { font-family: var(--font-data); font-size: var(--type-data); letter-spacing: var(--track-data); text-transform: uppercase; color: var(--text-primary); border: 1px solid var(--surface-border-strong); border-radius: var(--radius); padding: var(--space-hair) var(--space-tight); white-space: nowrap; }
.rb-integrity[data-status="unedited"] { border-color: var(--success-text); }
.rb-integrity[data-status="edited"] { border-color: var(--danger-border); color: var(--danger-text); }
.rb-progress { font-size: var(--type-data); letter-spacing: var(--track-data); color: var(--text-secondary); white-space: nowrap; }
.rb-speed { display: inline-flex; align-items: center; gap: var(--space-tight); font-size: var(--type-caption); color: var(--text-secondary); }
.rb-speed select { width: auto; font-size: var(--type-caption); padding-top: var(--space-hair); padding-bottom: var(--space-hair); }

.ticks-inline { display: none; }
@media (max-width: 1280px) { .class-strip .ticks { display: none; } .ticks-inline { display: inline; } }
/* Indices account for the MODEL dropdown at child(2): drop info items
   PROTOCOL -> DOCTRINE -> THEATER as width shrinks, keeping ENGINE + MODEL. */
/* Folding is measured at runtime (see foldStatusStrip) rather than guessed
   at fixed widths — the readouts change length as the engine reports. */

@keyframes ledPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }
@keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* View change: incoming panel rises and settles. Retriggers on every tab
   switch because .active is toggled off/on per navigation. */
@keyframes viewEnter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
/* Gentle opacity-only entrance for reduced-motion (fade, no movement). */
@keyframes fadeOnly { from { opacity: 0; } to { opacity: 1; } }
/* Generation runs as ONE non-streaming call, so there is no percentage to
   report and a progress bar would be inventing one. An indeterminate sweep
   states exactly what is true — still working, duration unknown — and the
   counter beside it is the measured elapsed time. Transform-only, so it
   composites and does not compete with inference on the main thread. */
@keyframes sweep { from { transform: translateX(-110%); } to { transform: translateX(360%); } }
/* The linter catching an out-of-role order is the peak beat of the demo.
   One-shot ring on arrival, bounded to that single entry. */
/* A gigabyte of model, minutes of download, and the moment it finally
   comes up has been arriving as a colour swap nobody in the room catches.
   One bloom off the status dot, fired once, on a transition that actually
   happened. It rides the existing box-shadow so the dot's own glow is
   never lost, and it is bounded — nothing here loops. */
@keyframes ledCameUp {
    0%   { box-shadow: 0 0 7px currentColor, 0 0 0 0 currentColor; }
    70%  { box-shadow: 0 0 7px currentColor, 0 0 0 10px transparent; }
    100% { box-shadow: 0 0 7px currentColor, 0 0 0 0 transparent; }
}
.stat-led.came-up::before { animation: ledPulse 2.4s ease-in-out infinite, ledCameUp 900ms var(--ease-out); }
@keyframes driftLand {
    0%   { box-shadow: 0 0 0 0 var(--loot-gold); }
    60%  { box-shadow: 0 0 0 5px transparent; }
    100% { box-shadow: 0 0 0 0 transparent; }
}

/* Reduced-motion: honor the OS preference. Freeze looping indicators and
   strip movement, but keep a short opacity crossfade so entrances stay
   gentle rather than snapping (WAI: gentler, not zero). */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
    .stat-led::before { animation: none !important; opacity: 1 !important; transform: none !important; }
    /* Sweep freezes into a static bar; the elapsed readout still ticks, so
       "the engine is alive" is still reported, just not with movement. */
    .working-sweep { animation: none !important; width: 100% !important; opacity: 0.45; background: var(--accent-color) !important; }
    .log-entry.drift { animation: fadeOnly 120ms linear !important; }
    /* Entrances keep a fade, drop the transform. */
    .view-panel.active, .log-entry { animation: fadeOnly 120ms linear !important; }
    #theater-sidebar, #nl-designer-container, #clone-modal-container {
        transition: opacity 120ms linear, display 120ms allow-discrete !important; transform: none !important;
    }
}
