/* STARNET — motion.css : the PREMIUM MOTION + FEEDBACK foundation (Phase 1).
   Additive layer over style.css/app.css. Same skin, same amber, same VT323 —
   the premium feel comes from MATERIAL, DEPTH & RHYTHM, not the aesthetic.

   Rules of this file:
   - Never introduce a hardcoded colour. Only the existing phosphor/role vars.
   - Motion goes through the token layer below (--t-fast/med/slow + shared easings).
   - Animate only transform / opacity / colour / border / box-shadow — NEVER layout
     (width/height/top/left) on hot paths; the canvas game loop runs at 60fps behind.
   - A single prefers-reduced-motion block at the bottom collapses everything.

   Motion tokens are static (no var() refs) so they live safely on :root. Any
   COMPOSITE var that references another var still MUST be declared on `body`
   (the theme swap re-evaluates it there) — see style.css --bezel/--well note. */

:root {
  --t-fast: 120ms;
  --t-med: 220ms;
  --t-slow: 400ms;
  /* one shared ease-out for entrances/settling, one soft ease for state flips */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

/* ============================================================
   2 · INTERACTIVE ELEMENTS — tactile transitions + hover bloom
   Buttons, provider chips, swatches, tab headers, dock items,
   inputs & selects gain a fast transition on the properties that
   actually change on hover/active. No layout props animated.
   ============================================================ */
.btn, .btn-xl, .btn-sm, .prov,
.bb, .bb-grp, .bb.sm,
.lb-tab, .mc-seg-btn, .set-theme,
.phosphor-swatches .swatch,
.term-x,
input[type=text], input[type=password], input:not([type]),
textarea, select {
  transition:
    border-color var(--t-fast) var(--ease-soft),
    background-color var(--t-fast) var(--ease-soft),
    box-shadow var(--t-fast) var(--ease-soft),
    color var(--t-fast) var(--ease-soft);
}
/* FLOOR — every native <button> inherits the tactile transition by default, so new buttons get the premium
   feel for free without being re-listed above. Element-level specificity (0,0,1) on purpose: ANY bespoke
   per-button transition in an earlier sheet (.chat-send, .chat-attach-btn, .mic-btn, .x-btn family, …) still
   wins the cascade — this is a floor that ADDS coverage, never a clobber. Only the safe props are animated. */
button {
  transition:
    border-color var(--t-fast) var(--ease-soft),
    background-color var(--t-fast) var(--ease-soft),
    box-shadow var(--t-fast) var(--ease-soft),
    color var(--t-fast) var(--ease-soft);
}

/* subtle hover bloom — a soft phosphor glow, no layout shift */
.btn:hover, .btn-xl:hover, .btn-sm:hover, .prov:hover,
.lb-tab:hover, .set-theme:hover,
.term-x:hover {
  box-shadow: 0 0 12px var(--ph-glow2);
}
/* the .btn-xl already carries a resting shadow — keep it and add the bloom */
.btn-xl:hover {
  box-shadow: 0 0 0 2px rgba(0,0,0,.85), 0 0 18px var(--ph-glow2), 0 0 12px var(--ph-glow2);
}

/* :active — keep the existing translateY(1px) sink, add a brief brightness dip */
.btn:active, .btn-xl:active, .btn-sm:active, .prov:active,
.bb:active, .bb-grp:active, .lb-tab:active,
.term-x:active {
  filter: brightness(0.86);
  transition-duration: 60ms;
}
/* FLOOR — every native <button> gets the press-sink by default (low specificity so a bespoke :active still
   wins; where a button already sinks via translateY, this just adds the brightness dip). */
button:active {
  filter: brightness(0.86);
  transition-duration: 60ms;
}

/* ============================================================
   3 · UNIFIED FOCUS RING — one keyboard-focus treatment app-wide.
   Kept low-specificity so it applies everywhere but existing
   themed :focus (border/glow) rules still layer their own accent.
   ============================================================ */
:focus-visible {
  outline: 2px solid var(--ph-bright);
  outline-offset: 2px;
}
/* mouse focus never draws the ring (matches native :focus-visible intent) */
:focus:not(:focus-visible) { outline: none; }

/* ============================================================
   4 · THEMED SCROLLBARS — thin phosphor bars app-wide, incl. panel
   bodies and textareas. Firefox via scrollbar-* ; Chromium via
   ::-webkit-scrollbar. Thumb brightens on hover.
   ============================================================ */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--ph-dim) var(--ph-faint);
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: var(--ph-faint); }
::-webkit-scrollbar-thumb {
  background: var(--ph-dim); border-radius: 4px;
  transition: background var(--t-fast) var(--ease-soft);
}
::-webkit-scrollbar-thumb:hover { background: var(--ph); }
::-webkit-scrollbar-corner { background: var(--ph-faint); }

/* ============================================================
   5 · WINDOW CLOSE — reverse CRT power-off before DOM removal.
   toggleTerm/closeTerm add .term-closing; this collapses the
   glass to a bright line then blackout, matching term-power in.
   ============================================================ */
@keyframes term-power-off {
  0%   { transform: translate(-50%, -50%) scale(1, 1); filter: brightness(1); opacity: 1; }
  55%  { transform: translate(-50%, -50%) scale(1.006, 0.06); filter: brightness(2.4); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(0.9, 0.004); filter: brightness(6); opacity: 0; }
}
.term.term-closing {
  animation: term-power-off 190ms var(--ease-soft) forwards;
  pointer-events: none;
}
/* a window that was dragged (transform:none, explicit left/top) closes without
   the translate() so it doesn't jump to centre on the way out. */
.term.term-closing.term-moved {
  animation: term-power-off-moved 190ms var(--ease-soft) forwards;
}
@keyframes term-power-off-moved {
  0%   { transform: scale(1, 1); filter: brightness(1); opacity: 1; }
  55%  { transform: scale(1.006, 0.06); filter: brightness(2.4); opacity: 1; }
  100% { transform: scale(0.9, 0.004); filter: brightness(6); opacity: 0; }
}
.term-scrim.term-closing { animation: scrim-out 180ms var(--ease-soft) forwards; }
@keyframes scrim-out { from { opacity: 1; } to { opacity: 0; } }

/* ============================================================
   6 · TAB / SECTION CROSSFADE — builder-swapped bodies fade in.
   StationUI stamps .swap-in on the injected content root; the
   class is short-lived (removed after the animation) so a repeat
   swap re-triggers it.
   ============================================================ */
@keyframes swap-in {
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: translateY(0); }
}
.swap-in { animation: swap-in var(--t-med) var(--ease-out); }

/* ============================================================
   7 · TOAST / NOTIFICATION MOTION — a transient on-screen stack.
   StationUI.notify() mirrors the stored notification to a toast
   in #toast-stack; each slides+fades in, then fades out.
   ============================================================ */
/* Bottom-LEFT over the stage (clear of the COMMS composer's mic/model cluster on the right),
   and above every overlay tier — toasts fired while RECRUITMENT (.mkt, z 9000) is open used
   to be buried under it at z 960 (audit P0 #13). */
#toast-stack {
  position: fixed; left: 268px; bottom: 128px; z-index: var(--z-toast, 9600);
  display: flex; flex-direction: column-reverse; gap: 8px; align-items: flex-start;
  pointer-events: none; max-width: min(360px, 42vw);
}
@media (max-width: 900px) { #toast-stack { left: 12px; } }
.toast {
  pointer-events: auto;
  border: 1px solid var(--ph-dim); border-left: 3px solid var(--ph);
  background: rgba(5, 3, 1, 0.96);
  color: var(--text); font-size: 14px; letter-spacing: 0.5px; line-height: 1.3;
  padding: 8px 12px; border-radius: var(--r-sm);
  box-shadow: 0 0 14px var(--ph-glow2), 0 6px 18px rgba(0,0,0,0.6), var(--raise);
  text-shadow: 0 0 4px var(--ph-glow2);
  animation: toast-in var(--t-med) var(--ease-out);
}
.toast .toast-ts { color: var(--ph-dim); font-size: 11px; letter-spacing: 1px; margin-right: 6px; }
.toast.good { border-left-color: var(--ok); }
.toast.good .toast-ts { color: var(--ok); }
.toast.gold { border-left-color: var(--gold); }
.toast.warn { border-left-color: var(--warn); }
.toast.bad  { border-left-color: var(--bad); }
.toast.leaving { animation: toast-out var(--t-med) var(--ease-soft) forwards; }
@keyframes toast-in {
  from { opacity: 0; transform: translateX(-24px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes toast-out {
  from { opacity: 1; transform: translateX(0); max-height: 60px; }
  to   { opacity: 0; transform: translateX(-24px); max-height: 0; margin-top: -8px; }
}

/* ============================================================
   8 · TOGGLE SWITCHES — bare Settings checkboxes → CRT pill switch.
   Checkbox stays in the DOM (a11y + label click) but is visually
   replaced by a styled pill with an animated knob; glows when ON.
   Scoped to .set-row so only Settings-style toggles are affected.
   ============================================================ */
.set-row input[type=checkbox], .mkt input[type=checkbox] {
  -webkit-appearance: none; appearance: none;
  position: relative; vertical-align: middle;
  width: 34px; height: 17px; margin: 0 8px 0 0; padding: 0;
  border: 1px solid var(--ph-dim); border-radius: 10px;
  background: rgba(0,0,0,0.55);
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.85);
  cursor: pointer; flex: 0 0 auto;
  transition: border-color var(--t-fast) var(--ease-soft),
              background-color var(--t-fast) var(--ease-soft),
              box-shadow var(--t-fast) var(--ease-soft);
}
.set-row input[type=checkbox]::after, .mkt input[type=checkbox]::after {
  content: ''; position: absolute; top: 1px; left: 1px;
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--ph-dim);
  box-shadow: 0 1px 2px rgba(0,0,0,0.7);
  transition: transform var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-soft),
              box-shadow var(--t-fast) var(--ease-soft);
}
.set-row input[type=checkbox]:checked, .mkt input[type=checkbox]:checked {
  border-color: var(--ph);
  background: var(--ph-faint);
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.6), 0 0 10px var(--ph-glow2);
}
.set-row input[type=checkbox]:checked::after, .mkt input[type=checkbox]:checked::after {
  transform: translateX(17px);
  background: var(--ph);
  box-shadow: 0 0 8px var(--ph-glow);
}
.set-row input[type=checkbox]:disabled, .mkt input[type=checkbox]:disabled {
  opacity: 0.45; cursor: not-allowed;
}
/* keep the label text aligned with the new pill — ONLY on rows that carry a
   checkbox (a text-only .set-row keeps its block flow). :has() is supported in
   the Chromium the desktop app / preview run on. */
.set-row:has(> input[type=checkbox]) { display: flex; align-items: center; }

/* ============================================================
   9 · UNIFIED LOADING + EMPTY STATES.
   .loading  — a CRT block-cursor + pulsing label ("reading…").
   .empty-state — a dim glyph + prose, centred.
   Applied to the model catalog / memory core / crew / task board.
   ============================================================ */
.loading {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--ph-dim); font-size: 14px; letter-spacing: 1px;
  padding: 8px 2px;
}
.loading::before {
  content: '▮'; color: var(--ph);
  animation: load-blink 1s steps(1) infinite;
  text-shadow: 0 0 6px var(--ph-glow);
}
.loading.pulse { animation: load-pulse 1.4s ease-in-out infinite; }
@keyframes load-blink { 50% { opacity: 0; } }
@keyframes load-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } }
.empty-state {
  text-align: center; color: var(--ph-dim);
  padding: 22px 16px; line-height: 1.5; font-size: 13px;
}
.empty-state .es-glyph {
  display: block; font-size: 30px; color: var(--ph-dim);
  opacity: 0.6; margin-bottom: 8px; text-shadow: 0 0 8px var(--ph-glow2);
}
.empty-state b { display: block; color: var(--ph); font-size: 15px; letter-spacing: 1px; margin-bottom: 4px; }
.empty-state span { display: block; font-size: 12px; opacity: 0.85; }
/* compact variant — the console-inline empties (no glyph/CTA, just a dim line) */
.empty-state.sm { padding: 10px 4px; font-size: 12px; line-height: 1.4; }
/* the one-off dim console empties share the empty-state grade through here (declared after the
   panels' own sheets) so they re-tint/re-size in ONE place; each keeps only its padding / italic /
   alignment / border delta in its own file. Distinct-color empties (.fb-empty bright, .mkt-empty
   --text, .key-empty CTA), the structured COMMS .cmsg-empty (starter chips) and .kb-empty-col
   (a wrapper around a real .empty-state) are intentionally not folded in. */
.mkt-dos-empty, .model-dock-empty, .mc-empty, .cd-empty, .proj-empty, .up-empty, .wg-pop-none {
  color: var(--ph-dim); font-size: 12px; line-height: 1.4;
}

/* ============================================================
   10 · PROGRESS / GAUGE EASING — fills glide instead of snapping.
   The context gauge already eases (style.css); this covers the
   generic fills + adds an optional shimmer sweep on active bars.
   ============================================================ */
.crew-prog > div,
.stat-bar > div,
#xpfill {
  transition: width var(--t-slow) var(--ease-out), background var(--t-med) var(--ease-soft);
}
/* opt-in shimmer sweep for an ACTIVE progress bar (add .bar-active).
   transform-only sweep — cheap, no repaint of the bar body. */
.bar-active { position: relative; overflow: hidden; }
.bar-active::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 46px;
  background: linear-gradient(90deg, transparent, var(--ph-glow), transparent);
  animation: bar-shim 1.9s linear infinite;
  pointer-events: none;
}
@keyframes bar-shim {
  0%   { transform: translateX(-46px); }
  100% { transform: translateX(420px); }
}

/* ============================================================
   12 · PREMIUM WINDOW CHROME (Phase 2) — corner brackets, header LED,
   header hairline + top light-grade, footer plate. Generic on the
   shared .term shell so every plain floating window gets it for free.
   Feature windows (.term.feature) keep their molded casing and are
   excluded. Everything here is static / transform-or-opacity only and
   pointer-events:none where it overlays content, so dragging, resize,
   the focus trap and the .term-closing power-off are untouched. Colours
   are phosphor/role vars only, so theme swaps re-tint correctly.
   ============================================================ */
/* status LED at the header's left — "this window is live". Static ok-green
   (a role var, stays green across theme swaps); a slow subtle pulse. */
.term-led {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: var(--ok); box-shadow: 0 0 8px var(--ok);
  animation: term-led-pulse 2.4s ease-in-out infinite;
}
@keyframes term-led-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } }
/* keep the LED + title grouped at the left; the close button stays hard-right.
   (The head is justify-content:space-between with gap — pushing the title's right
   margin to auto collapses the extra gap so led+title read as one unit.) */
.term-head .term-title { margin-right: auto; }
/* hairline gradient rule under the header (layers over the existing 1px border) */
.term:not(.feature):not(.pw) .term-head::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, var(--ph-dim), transparent 92%);
  pointer-events: none;
}
/* corner L-brackets + top light-grade, grouped in one static overlay layer.
   z above the glass (.term::before is z6) so the brackets read on the glass. */
.term-chrome { position: absolute; inset: 0; pointer-events: none; z-index: 7; border-radius: inherit; overflow: hidden; }
.term-brk {
  position: absolute; width: 13px; height: 13px; border: 2px solid var(--ph);
  opacity: 0.5; box-shadow: 0 0 6px var(--ph-glow2);
}
.term-brk.tl { top: 6px; left: 6px; border-right: 0; border-bottom: 0; }
.term-brk.tr { top: 6px; right: 6px; border-left: 0; border-bottom: 0; }
.term-brk.bl { bottom: 6px; left: 6px; border-right: 0; border-top: 0; }
.term-brk.br { bottom: 6px; right: 6px; border-left: 0; border-top: 0; }
/* faint top light-grade for glass depth — a static gradient, no repaint cost */
.term-grade {
  position: absolute; left: 0; right: 0; top: 0; height: 40%;
  background: linear-gradient(180deg, rgba(255, 205, 130, 0.05), transparent 88%);
}
/* footer plate — thin bottom strip: status dot + term key left, grip dots right.
   A real flex child after the body, so it never overlaps scroll content. */
.term-foot {
  flex: 0 0 auto; position: relative; z-index: 7;
  display: flex; align-items: center; gap: var(--s-2);
  padding: 4px 12px 5px; border-top: 1px solid var(--ph-dim);
  background: linear-gradient(0deg, var(--ph-glow2), transparent);
  font-size: var(--fs-0); letter-spacing: var(--ls-3); color: var(--ph-dim);
}
.term-foot-d {
  width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto;
  background: var(--ok); box-shadow: 0 0 6px var(--ok);
}
.term-foot-sp { flex: 1; }
.term-foot-grip { color: var(--ph-dim); letter-spacing: 2px; opacity: 0.7; }
/* tiny windows: the plate can crowd — hidden below a small height via :has (Chromium). */
.term:not(.feature) { }

/* ============================================================
   13 · CARD LANGUAGE (Phase 2) — recruitment-bay entrance + hover lift.
   A shared .cardIn entrance (opacity+translateY, ease-out, backwards) with
   a capped per-index stagger set inline via --ci (index) on the row, and a
   hover lift + border brighten + phosphor glow. Transform/opacity only.
   Applied to the existing row/card classes across the panels — additive,
   no markup rename. The stagger var falls back to 0 when unset.
   ============================================================ */
@keyframes cardIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.crew-row, .ag-item,
.kb-card, .gx-tro, .perk, .mc-row, .sk-card,
.key-row, .prov-card, .notif-row, .cn-row {
  animation: cardIn 0.34s var(--ease-out) backwards;
  animation-delay: calc(min(var(--ci, 0), 8) * 25ms);
  transition:
    border-color var(--t-fast) var(--ease-soft),
    box-shadow var(--t-fast) var(--ease-soft),
    background-color var(--t-fast) var(--ease-soft),
    transform var(--t-fast) var(--ease-out);
}
/* hover lift — transform + border brighten + glow. Scoped to the interactive
   cards (crew/agent/kanban/quest/perk rows); .mc-row etc. inherit the entrance
   but a lift is applied only where the whole row is clickable. */
.crew-row:hover, .ag-item:hover,
.kb-card:hover, .gx-tro:hover, .perk:hover, .prov-card:hover {
  transform: translateY(-1px);
  box-shadow: 0 0 12px var(--ph-glow2);
}

/* ============================================================
   14 · SECTION DIVIDER (Phase 2) — label + diamond node + fading rule.
   Generic .sec swapped in for ad-hoc headers where markup allows. Matches
   the v2 mockup: amber label, a rotated-square node, a gradient hairline
   that fades to the right. Uses phosphor vars only.
   ============================================================ */
.sec {
  display: flex; align-items: center; gap: 9px; margin: 16px 0 10px;
}
.sec:first-child { margin-top: 4px; }
.sec .sec-l {
  color: var(--ph); letter-spacing: var(--ls-3); font-size: var(--fs-1);
  text-shadow: 0 1px 0 #000, 0 0 8px var(--ph-glow2); flex: 0 0 auto;
}
.sec .sec-r {
  flex: 1; height: 4px;
  background:
    linear-gradient(90deg, var(--ph-dim), transparent 92%) top / 100% 1px no-repeat,
    linear-gradient(90deg, var(--ph-faint), transparent 70%) bottom / 100% 1px no-repeat;
}
.sec .sec-nd {
  width: 6px; height: 6px; transform: rotate(45deg); flex: 0 0 auto;
  background: var(--ph); box-shadow: 0 0 6px var(--ph-glow);
}
.sec .sec-tag {
  flex: 0 0 auto; color: var(--ph-dim); font-size: var(--fs-0);
  letter-spacing: var(--ls-2); border: 1px solid var(--ph-dim);
  border-radius: var(--r-sm); padding: 0 6px;
}

/* ============================================================
   14b · BRIEF BLOCK (Phase 2) — a left-border framed note (v2 mockup
   .brief pattern). Used for the ROUTINES intro. Phosphor left rail,
   dim key label, readable body. Vars only.
   ============================================================ */
.brief-block {
  border-left: 2px solid var(--ph); padding: 9px 13px; margin: 4px 0 12px;
  background: rgba(0, 0, 0, 0.25);
  box-shadow: 0 0 12px var(--ph-glow2), inset 0 1px 0 rgba(var(--ph-bright-rgb), 0.04);
}
.brief-block .brief-k {
  font-size: var(--fs-0); color: var(--ph-dim); letter-spacing: var(--ls-3); margin-bottom: 5px;
}
.brief-block .brief-v { font-size: var(--fs-1); color: var(--text); line-height: 1.55; }

/* ============================================================
   15 · EMPTY-STATE CTA (Phase 2) — a small action button inside an
   .empty-state that focuses the relevant existing input. Inherits the
   .btn hover bloom from section 2; just sizing + spacing here.
   ============================================================ */
.empty-state .es-cta {
  margin-top: 10px; display: inline-block;
  background: transparent; color: var(--ph);
  border: 1px solid var(--ph-dim); border-radius: var(--r-sm);
  font-family: inherit; font-size: var(--fs-1); letter-spacing: var(--ls-2);
  padding: 3px 12px; cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-soft),
              background-color var(--t-fast) var(--ease-soft),
              box-shadow var(--t-fast) var(--ease-soft),
              color var(--t-fast) var(--ease-soft);
}
.empty-state .es-cta:hover {
  border-color: var(--ph); color: var(--ph-bright);
  background: var(--ph-faint); box-shadow: 0 0 12px var(--ph-glow2);
}

/* ============================================================
   17 · ACTIVE-WORK SHIMMER (Phase 2 · H) — the crew row's in-flight bar.
   The bar is collapsed until the row carries .working (toggled from the
   real agent.run.start/end state in crewTick). While working it opens to
   a thin filled rail and the .bar-active shimmer sweeps across it, so a
   running agent reads as alive. Indeterminate (full-width fill), not a %.
   ============================================================ */
.crew-row .crew-prog {
  height: 0; margin-top: 0; overflow: hidden;
  transition: height var(--t-med) var(--ease-out), margin-top var(--t-med) var(--ease-out);
}
.crew-row.working .crew-prog { height: 3px; margin-top: 4px; }
.crew-row.working .crew-prog > div {
  width: 100%; background: var(--ph); box-shadow: 0 0 6px var(--ph-glow);
}
/* the shimmer sweep only animates while working (the ::after is present always via
   .bar-active, but with a collapsed 0-height parent it's clipped and invisible). */

/* ============================================================
   16 · HIERARCHY & DENSITY (Phase 2) — targeted breathing room.
   Quest-log only (scoped by .gx-quests / .q-grid so the GROWTH and
   TROPHY grids that share .gx-tros are untouched). OPEN cards get more
   padding + a 2-up grid so they read clearly; DONE cards dim so the eye
   goes to what's still open. All colour/opacity/spacing — no logic.
   ============================================================ */
.gx-quests .q-grid { grid-template-columns: repeat(2, 1fr); gap: 9px; }
.gx-quests .q-grid .gx-tro { padding: 11px 12px; }
.gx-quests .q-grid .gx-tro .nm { font-size: 12px; margin-top: 6px; }
.gx-quests .q-grid .gx-tro .sub { font-size: 11px; margin-top: 5px; line-height: 1.4; }
/* DONE column reads as settled history — dimmer, so OPEN stays the focus.
   (Keeps the gold "earned" accent; just drops overall emphasis.) */
.gx-quests .q-done .gx-tro { opacity: 0.72; }
.gx-quests .q-done .gx-tro:hover { opacity: 1; }
/* give the OPEN/DONE dividers a touch more air in the log */
.gx-quests .gx-sec { margin-top: 15px; }

/* ============================================================
   18 · MINIMIZE-TO-STRIP — a header minimize control + a dock strip of
   minimized-window chips. Built by StationUI (stationui.js): a "–" .term-min
   button sits left of the ✕; minimizing collapses the window toward the strip
   (a compressed power-off), hides it (kept alive), and drops a chip into
   #term-strip in the bottom bar. Chip click restores. Phosphor / VT323 only,
   theme vars only, transform/opacity motion only.
   ============================================================ */

/* header minimize button — mirrors .term-x chrome so the two controls read as a pair */
.term-min {
  background: rgba(0,0,0,0.35); border: 1px solid var(--ph-dim); color: var(--ph);
  font-family: inherit; cursor: pointer; font-size: var(--fs-1); line-height: 1;
  padding: 2px 8px; border-radius: var(--r-sm); text-shadow: none;
  transition:
    border-color var(--t-fast) var(--ease-soft),
    background-color var(--t-fast) var(--ease-soft),
    box-shadow var(--t-fast) var(--ease-soft),
    color var(--t-fast) var(--ease-soft);
}
.term-min:hover { background: var(--ph-faint); color: var(--ph-bright); border-color: var(--ph); box-shadow: 0 0 12px var(--ph-glow2); }
.term-min:active { filter: brightness(0.86); transition-duration: 60ms; }

/* hidden (minimized) window: fully removed from layout + interaction, element kept alive */
.term.term-min-hidden { display: none !important; }

/* collapse animation — a compressed variant of the CRT power-off, toward the bottom (the strip lives in
   the bottom bar). transform/opacity only. Two variants mirror the close ones: centered vs dragged. */
.term.term-minimizing {
  animation: term-minimize 200ms var(--ease-soft) forwards;
  pointer-events: none;
}
.term.term-minimizing.term-moved { animation: term-minimize-moved 200ms var(--ease-soft) forwards; }
@keyframes term-minimize {
  0%   { transform: translate(-50%, -50%) scale(1, 1); opacity: 1; }
  100% { transform: translate(-50%, calc(-50% + 40px)) scale(0.7, 0.05); opacity: 0; }
}
@keyframes term-minimize-moved {
  0%   { transform: scale(1, 1) translateY(0); opacity: 1; }
  100% { transform: scale(0.7, 0.05) translateY(40px); opacity: 0; }
}
/* restore: replay a CRT power-on. A centered (never-dragged) window keeps the translate()-based
   keyframes; a .term-moved window carries no centering transform, so it gets a plain variant. Both
   are stamped as an explicit class-scoped animation so it re-triggers even though the base .term-power
   already ran once on the original mount. */
.term.term-restoring { animation: term-power-on 0.42s var(--ease-out); }
@keyframes term-power-on {
  0%   { transform: translate(-50%, -50%) scale(1, 0.012); filter: brightness(6); }
  9%   { transform: translate(-50%, -50%) scale(1, 0.04); }
  46%  { transform: translate(-50%, -50%) scale(1.004, 1.03); filter: brightness(2.2); }
  100% { transform: translate(-50%, -50%) scale(1, 1); filter: brightness(1); }
}
.term.term-restoring.term-moved { animation: term-power-on-moved 0.42s var(--ease-out); }
@keyframes term-power-on-moved {
  0%   { transform: scale(1, 0.012); filter: brightness(6); }
  9%   { transform: scale(1, 0.04); }
  46%  { transform: scale(1.004, 1.03); filter: brightness(2.2); }
  100% { transform: scale(1, 1); filter: brightness(1); }
}

/* THE STRIP — docked in #bottombar before .bb-right. Empty → collapsed to nothing. */
#term-strip {
  display: flex; align-items: center; gap: var(--s-2);
  min-width: 0; max-width: 46vw;
  margin: 0 var(--s-2);
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: thin; scrollbar-color: var(--ph-dim) transparent;
}
#term-strip:not(.has-chips) { display: none; }
#term-strip::-webkit-scrollbar { height: 6px; }
#term-strip::-webkit-scrollbar-track { background: transparent; }
#term-strip::-webkit-scrollbar-thumb { background: var(--ph-dim); border-radius: 3px; }
#term-strip::-webkit-scrollbar-thumb:hover { background: var(--ph); }

/* a chip — tiny LED + VT323 title, phosphor border, hover bloom (premium-chrome language). */
.term-chip {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 1 auto;
  min-width: 54px; max-width: 148px;
  padding: 3px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--ph-dim); background: rgba(0,0,0,0.35);
  color: var(--ph); font-family: inherit; font-size: var(--fs-1); letter-spacing: var(--ls-2);
  cursor: pointer; text-shadow: 0 0 6px var(--ph-glow2); white-space: nowrap;
  /* enter/leave: transform + opacity + a width/margin collapse so neighbours slide over on removal */
  opacity: 0; transform: translateY(6px) scale(0.96);
  transition:
    opacity var(--t-med) var(--ease-out),
    transform var(--t-med) var(--ease-out),
    border-color var(--t-fast) var(--ease-soft),
    box-shadow var(--t-fast) var(--ease-soft),
    background-color var(--t-fast) var(--ease-soft),
    color var(--t-fast) var(--ease-soft);
}
.term-chip.in { opacity: 1; transform: translateY(0) scale(1); }
.term-chip.out { opacity: 0; transform: translateY(6px) scale(0.96); pointer-events: none; }
.term-chip:hover { border-color: var(--ph); color: var(--ph-bright); background: var(--ph-faint); box-shadow: 0 0 12px var(--ph-glow2); }
.term-chip:active { filter: brightness(0.86); transition-duration: 60ms; }
.term-chip-led {
  width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
  background: var(--ok); box-shadow: 0 0 6px var(--ok);
  animation: term-led-pulse 2.4s ease-in-out infinite;
}
.term-chip-t { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* ============================================================
   11 · REDUCED MOTION — collapse everything added above to near-0.
   Respects the user's OS setting. (The idle looping animations here
   — toast/loading/shimmer — are transform/opacity only and cheap, but
   still honoured.)
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .term.term-closing, .term.term-closing.term-moved,
  .term.term-minimizing, .term.term-minimizing.term-moved,
  .term.term-restoring, .term.term-restoring.term-moved,
  .term-scrim.term-closing,
  .swap-in,
  .toast, .toast.leaving,
  .bar-active::after,
  .term-led, .ag-psweep, .term-chip-led,
  .crew-row, .ag-item, .kb-card, .gx-tro, .perk, .mc-row, .sk-card,
  .key-row, .prov-card, .notif-row, .cn-row,
  .loading, .loading.pulse, .loading::before {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  button, [role="button"],
  .btn, .btn-xl, .btn-sm, .prov, .bb, .bb-grp, .lb-tab,
  .mc-seg-btn, .set-theme, .phosphor-swatches .swatch, .term-x, .term-min, .term-chip,
  .empty-state .es-cta,
  input, textarea, select,
  .set-row input[type=checkbox], .set-row input[type=checkbox]::after,
  .crew-row:hover, .ag-item:hover, .kb-card:hover, .gx-tro:hover, .perk:hover, .prov-card:hover,
  .gx-quests .q-done .gx-tro:hover,
  .crew-prog > div, .stat-bar > div, #xpfill,
  ::-webkit-scrollbar-thumb {
    transition-duration: 0.01ms !important;
  }
  /* ui-irritants: retire the first-run pulse under reduced-motion (rule appended below) */
  .model-dock-toggle.first-run { animation: none !important; }
  .mc-rec { animation-duration: 0.01ms !important; }
}

/* ============================================================
   ui-irritants lane — appended section (owned by agent/ui-irritants)
   Three targeted UX polish moves:
   (1) model chip first-run pulse — a subtle glow breath so new users
       notice the model/effort selector exists; retired after one
       interaction (JS clears .first-run + persists a localStorage guard).
   (2) memory-core record cards join the shared .cardIn entrance
       (the .mc-rec class was missing from §13's list).
   ============================================================ */
@keyframes modeldock-firstrun {
  0%, 100% { box-shadow: 0 0 0 0 transparent; border-color: var(--ph-dim); }
  50%      { box-shadow: 0 0 12px var(--ph-glow); border-color: var(--ph); }
}
.model-dock-toggle.first-run {
  animation: modeldock-firstrun 2.2s var(--ease-soft) 3;
}
/* memory-core belief cards — the entrance the shared card language already grants siblings.
   Stagger via --ci when set (renderMemoryList can add it); falls back to 0. */
.mc-rec {
  animation: cardIn 0.34s var(--ease-out) backwards;
  animation-delay: calc(min(var(--ci, 0), 8) * 25ms);
}

/* (3) NOTIFICATION SEVERITY — a whisper, not a traffic light. A lead glyph + a left edge that
   colours to the severity. The good/gold/warn/bad toast edges already exist above (§7); here we
   add the glyph slot, the info edge, and the bad edge for the normalized 'error' case. */
.toast { display: flex; align-items: baseline; gap: 6px; }
.toast-sev { flex: 0 0 auto; font-size: 12px; line-height: 1; opacity: 0.9; }
.toast.sev-bad  { border-left-color: var(--bad); }
.toast.sev-bad  .toast-sev { color: var(--bad); }
.toast.sev-warn .toast-sev { color: var(--warn); }
.toast.sev-good .toast-sev { color: var(--ok); }
.toast.sev-gold .toast-sev { color: var(--gold); }
.toast.sev-info { border-left-color: var(--ph-dim); }
.toast.sev-info .toast-sev { color: var(--ph-dim); }

/* ============================================================
   console-windows lane — appended (owned by agent/console-windows)
   The console section-swap reuses the shared .swap-in crossfade (already
   collapsed under reduced-motion above). The rail items animate colour/
   background/border on hover+select; retire those transitions too under
   reduced-motion so a motion-averse user gets an instant, static rail.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .con-rail-item { transition-duration: 0.01ms !important; }
}

/* ============================================================
   settings-truth lane — armed REMOVE pulse (owned by agent/settings-truth)
   The two-step key REMOVE arms on first click; the armed CONFIRM button
   breathes so the destructive state is unmistakable (the calm→armed jump
   was being misread as "nothing happened"). Transform/box-shadow only.
   Static colour/fill lives in app.css; retired under reduced-motion.
   ============================================================ */
@keyframes rm-arm-pulse {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50%      { box-shadow: 0 0 10px 1px var(--bad); }
}
.bb.danger.armed { animation: rm-arm-pulse 1.1s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .bb.danger.armed { animation: none !important; }
}
