@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Courier+Prime:ital@0;1&family=Inter+Tight:wght@400;500;600;700&display=swap');

/* BLACKBOX — one job per colour.
   amber  = structure and interaction
   red    = lands THIS cycle, or critical server
   gold   = lands next cycle
   teal   = you (your command, your log lines)
   violet = your daemons acting for you
   orchid = an exception: a part your program leaves to you
   gray   = broken / unavailable */
:root {
  color-scheme: dark;
  --bg: #090603;
  --panel: #100b05;
  --panel-2: #171006;
  --inset: #070503;
  --text: #f0e2b6;
  --bright: #fff2c8;
  --muted: #b99d61;
  --dim: #8f7748; /* 4.6:1 on the panel: it carries real information (senders, timers, hints) */
  --amber: #f1b92f;
  --amber-soft: #d69a22;
  --amber-deep: #7e5311;
  --line: rgba(241, 185, 47, 0.2);
  --line-strong: rgba(241, 185, 47, 0.45);
  --hot: #ff5b3d;
  --hot-soft: rgba(255, 91, 61, 0.14);
  --next: #ffd85c;
  --you: #7fd1c7;
  --daemon: #c3a6ff;
  --exception: #e07bff; /* a part your program leaves to you (routines.mjs): not red (a threat), teal (you), amber or violet (daemons) */
  --exception-soft: rgba(224, 123, 255, 0.14);
  --steel: #86b6c6; /* what protects a virus part: a lock, a ward, the tethers between parts (docs/ui.md) */
  --steel-glow: rgba(134, 182, 198, 0.6);
  --gray: #7d7362;
  --backup: #e9e2cf; /* the Backup objective's process (objectives.mjs): yours to keep, not you (teal) */
  --ready: #8fd46b; /* done and waiting on you: a contract to turn in (docs/ui.md) */
  --sans: 'Inter Tight', 'IBM Plex Sans', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', 'Cascadia Mono', ui-monospace, monospace;
  /* The UI system (docs/ui.md). Spacing: one scale, nothing between the steps. */
  --s1: 2px; --s2: 4px; --s3: 6px; --s4: 8px; --s5: 12px; --s6: 16px; --s7: 24px;
  /* Corners: square-ish. Tags 2px, buttons and chips 3px, cards 4px. Nothing rounder (pills are the one exception). */
  --r-tag: 2px; --r-btn: 3px; --r-card: 4px;
  /* Type roles: the kicker (mono caps over a block), a row label (mono caps beside a value), small print. */
  --kicker: 600 11px/1.3 var(--mono); --kicker-track: 1.5px;
  --label: 600 10px/1.3 var(--mono); --label-track: 1px;
  /* Control heights: every button in a row is one of these. */
  --h-btn: 32px; --h-btn-sm: 26px; --h-chip: 20px;
  --amber-wash: rgba(241, 185, 47, 0.1);
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg) url('ui/textures/grime-overlay-subtle.png');
  background-blend-mode: normal;
  color: var(--text);
  font: 14px/1.45 var(--sans);
}
button, input { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 1px solid transparent; padding: 6px 10px; border-radius: 3px; }
button:hover:not(:disabled) { border-color: var(--line-strong); }
button:disabled { opacity: 0.45; cursor: default; }
:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
[hidden] { display: none !important; }
h1, h2, h3, p { margin: 0; }
code { font-family: var(--mono); color: var(--amber); }

/* UI scale (uiscale.mjs): the screen drawn --ui times as large; its height divides by it so it still fits. */
.app { zoom: var(--ui, 1); height: calc(100dvh / var(--ui, 1)); display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto auto; max-width: 1800px; margin: 0 auto; }

/* ---------- top bar ---------- */
.topbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 20px; padding: 8px 20px; border-bottom: 1px solid var(--line); }
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--bright); font-weight: 700; letter-spacing: 3px; }
/* The mark: a black square eclipsing an amber light, its corona showing round the edges (the favicon is the same). */
.brand-mark, .bb-logo { --lg: 18px; position: relative; flex: none; width: var(--lg); height: var(--lg); isolation: isolate; }
.brand-mark { margin: 0 3px; }
.brand-mark::before, .bb-logo::before { content: ''; position: absolute; inset: -45%; z-index: 0; border-radius: 50%; pointer-events: none; background: conic-gradient(from 12deg, transparent 0 6%, rgba(255, 220, 130, 0.2) 7.5%, transparent 9%, transparent 22%, rgba(255, 220, 130, 0.14) 23.2%, transparent 24.5%, transparent 39%, rgba(255, 220, 130, 0.22) 40.5%, transparent 42%, transparent 58%, rgba(255, 220, 130, 0.12) 59.2%, transparent 60.5%, transparent 74%, rgba(255, 220, 130, 0.18) 75.5%, transparent 77%, transparent 91%, rgba(255, 220, 130, 0.14) 92.2%, transparent 93.5%), radial-gradient(circle closest-side, rgba(255, 226, 150, 0.3) 40%, rgba(241, 185, 47, 0.1) 62%, transparent 100%); -webkit-mask: radial-gradient(circle closest-side, #000 50%, transparent 92%); mask: radial-gradient(circle closest-side, #000 50%, transparent 92%); animation: bb-corona 9s ease-in-out infinite; }
.brand-mark::after, .bb-logo::after { content: ''; position: absolute; inset: 0; z-index: 1; background: #030201; box-shadow: 0 0 0 1px rgba(255, 238, 196, 0.5), 0 0 3px 0.5px rgba(255, 226, 150, 0.7), 0 0 10px 1px rgba(241, 185, 47, 0.28); }
@keyframes bb-corona { 0%, 100% { opacity: 0.8; transform: rotate(0deg) scale(1); } 50% { opacity: 1; transform: rotate(6deg) scale(1.03); } }
@media (prefers-reduced-motion: reduce) { .brand-mark::before, .bb-logo::before { animation: none; } }
.modules { display: flex; gap: 2px; }
.modules button { color: var(--muted); position: relative; }
.modules button[aria-current='page'] { color: var(--bright); border-bottom: 2px solid var(--amber); border-radius: 0; }
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--hot); margin-left: 6px; vertical-align: middle; }
.meters { display: flex; gap: 22px; margin-left: auto; align-items: center; }
.meter { display: flex; align-items: baseline; gap: 8px; font-variant-numeric: tabular-nums; }
.meter-label { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 1px; }
.meter strong { font-size: 16px; color: var(--bright); }
.meter strong, .meter-label, .modules button { white-space: nowrap; }
.meter small { color: var(--muted); }
.meter-integrity { align-items: center; }
.meter-bar { width: 120px; height: 8px; background: var(--inset); border: 1px solid var(--line); display: block; }
.meter-bar span { display: block; height: 100%; background: var(--amber); transition: width 0.3s; }
.meter-integrity.critical strong { color: var(--hot); }
.toggles { display: flex; gap: 4px; color: var(--dim); font-size: 12px; white-space: nowrap; }
.toggles button[aria-pressed='true'] { color: var(--text); }
.toggles button[aria-pressed='false'] { color: var(--dim); text-decoration: line-through; }
#speed { color: var(--amber); }

/* ---------- panels ---------- */
.workspace { min-height: 0; padding: 12px 20px; }
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 4px; min-height: 0; }
.panel-head { display: flex; align-items: baseline; justify-content: space-between; padding: 10px 14px 6px; }
.panel-head h2 { font-size: 12px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--muted); font-weight: 600; }
.panel-note { font-size: 12px; color: var(--dim); }

/* ---------- combat layout ----------
   Eye path: HUD (virus vs you) -> board (parts x cycles) -> prompt.
   The art and log sit to the side and below; nothing needed is there. */
.combat { height: 100%; display: grid; gap: 12px; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr); grid-template-areas: 'hud hud' 'board stage' 'log stage'; }
.hud { grid-area: hud; display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr); gap: 24px; padding: 12px 16px; align-items: start; }
.board { grid-area: board; padding: 4px 0 8px; overflow-y: auto; }
.stage { grid-area: stage; display: flex; flex-direction: column; gap: 8px; padding: 8px; min-height: 0; }
.lesson-slot:empty { display: none; }
.lesson-slot .card { padding: 12px 14px; gap: 8px; }
.lesson-slot .card h1 { font-size: 20px; }
.log-lines { padding-top: 8px; }
.stage .virus-stage { flex: 1; min-height: 90px; }
.log { grid-area: log; display: flex; flex-direction: column; min-height: 0; }

.hud-id { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; min-width: 0; }
.hud-id h1 { font-size: 24px; letter-spacing: 2px; color: var(--bright); font-weight: 700; }
.hud-id .meta { color: var(--muted); }
.mutation-rule { flex-basis: 100%; color: var(--muted); font-size: 13px; }
.hud-bar .bar-top { display: flex; justify-content: space-between; align-items: baseline; font-variant-numeric: tabular-nums; }
.hud-bar .bar-top strong { font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.hud-bar .bar-top span { font: 600 24px var(--mono); color: var(--bright); line-height: 1; }
.hud-bar .bar-top small { font-size: 13px; color: var(--muted); }
.hud-bar .bar-top .bar-ico { width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; color: var(--you); }
.hud-bar.mine.mid .bar-ico { color: var(--next); } .hud-bar.mine.low .bar-ico { color: var(--hot); }
.bigbar { height: 14px; background: var(--inset); border: 1px solid var(--hot); margin-top: 6px; }
.bigbar span { display: block; height: 100%; background: linear-gradient(90deg, #a82f20, var(--hot)); transition: width 0.25s; }
.hud-bar.mine .bigbar { border-color: var(--you); }
.hud-bar.mine .bigbar span { background: var(--you); }
.hud-bar.mine .bar-top span { color: var(--you); }
.hud-bar.mine.mid .bigbar { border-color: var(--next); } .hud-bar.mine.mid .bigbar span { background: var(--next); } .hud-bar.mine.mid .bar-top span { color: var(--next); }
.hud-bar.mine.low .bigbar { border-color: var(--hot); } .hud-bar.mine.low .bigbar span { background: var(--hot); } .hud-bar.mine.low .bar-top span { color: var(--hot); }
.clock-line { margin-top: 6px; font-size: 12px; color: var(--muted); }

.virus-stage { position: relative; min-height: 0; background: var(--inset) url('ui/textures/terminal-grid-fine.png'); border: 1px solid var(--line); border-radius: 3px; overflow: hidden; }
.virus-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.stage-flash { position: absolute; left: 0; right: 0; top: 10px; text-align: center; font: 600 13px var(--mono); color: var(--bright); letter-spacing: 1px; pointer-events: none; }

.brow { display: grid; grid-template-columns: minmax(170px, 1.5fr) repeat(4, minmax(0, 1fr)); width: 100%; text-align: left; border: 0; border-top: 1px solid var(--line); border-radius: 0; padding: 0 12px; background: none; align-items: stretch; }
.bhead { border-top: 0; font-size: 12px; color: var(--muted); letter-spacing: 1px; text-transform: uppercase; }
.bcell { padding: 8px 6px; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 4px; }
.bcell + .bcell { border-left: 1px solid var(--line); }
.bhead .bcell { padding: 6px; }
.bname small { font-size: 11px; color: var(--dim); text-transform: none; letter-spacing: 0; }
.bnow { display: grid !important; grid-template-columns: 1fr auto; align-items: baseline; }
.bnow .cyclebar { grid-column: 1 / -1; }
.bhead .bnow span:first-child { color: var(--bright); font-weight: 600; }
.span3 { grid-column: span 3; } .span4 { grid-column: span 4; } .span5 { grid-column: 1 / -1; }
.bpart { cursor: pointer; }
.bpart:hover:not(:disabled) { background: rgba(241, 185, 47, 0.05); }
.bpart.selected { box-shadow: inset 3px 0 0 var(--amber); background: rgba(241, 185, 47, 0.07); }
.bpart.now { box-shadow: inset 3px 0 0 var(--hot); }
.bpart.now.selected { box-shadow: inset 3px 0 0 var(--hot), inset 0 0 0 1px var(--amber); }
.bpart.now .part-bar span { background: var(--hot); }
.byou .bcell { padding-top: 6px; padding-bottom: 6px; }
.bbroken { color: var(--dim); font-size: 12px; }
.part-top { display: flex; flex-wrap: wrap; justify-content: space-between; column-gap: 8px; row-gap: 0; align-items: baseline; min-width: 0; } /* a long ◆ row wraps the Integrity under it, never into the Now column */
.part-name { font-weight: 600; color: var(--bright); }
.part-hp { font: 500 13px var(--mono); color: var(--text); white-space: nowrap; margin-left: auto; }
.part-bar { height: 5px; background: var(--inset); display: block; }
.part-bar span { display: block; height: 100%; background: var(--amber); }
.part-tags { display: flex; gap: 4px; flex-wrap: wrap; }
.tag { display: inline-block; font-size: 11px; letter-spacing: 1px; text-transform: uppercase; padding: 1px 6px; border: 1px solid var(--line-strong); border-radius: 2px; color: var(--amber); white-space: nowrap; }
.tag.hot { border-color: var(--hot); color: var(--hot); }
.death-mark { margin-left: 6px; font-variant-numeric: tabular-nums; cursor: help; }
.tag.you { border-color: var(--you); color: var(--you); }
.tag.dim { border-color: var(--line); color: var(--muted); }
.part-tags:empty { display: none; }

/* ---------- timeline ---------- */
.timeline-grid { display: grid; grid-template-columns: 1.15fr 1fr 1fr 1fr; padding: 0 14px 14px; }
.tcol { border-left: 1px solid var(--line); padding: 4px 8px 0; display: flex; flex-direction: column; gap: 6px; min-height: 120px; }
.tcol:first-child { border-left: 0; padding-left: 0; }
.tcol-head { display: flex; justify-content: space-between; align-items: baseline; font-size: 12px; color: var(--muted); letter-spacing: 1px; text-transform: uppercase; }
.tcol:first-child .tcol-head { color: var(--bright); font-weight: 600; }
.countdown { font: 600 22px var(--mono); color: var(--bright); line-height: 1; }
.cyclebar { position: relative; height: 7px; background: var(--inset); border: 1px solid var(--line); }
.cyclebar span { position: relative; display: block; height: 100%; background: var(--you); }
.intent { display: flex; align-items: center; gap: 6px; padding: 5px 7px; border: 1px solid var(--line-strong); border-radius: 3px; font-size: 13px; background: var(--panel-2); }
.intent .ico { width: 14px; height: 14px; flex: none; background: currentColor; -webkit-mask: var(--icon) center/contain no-repeat; mask: var(--icon) center/contain no-repeat; }
.intent b { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: clip; min-width: 0; }
.intent .code { display: none; font: 700 12px var(--mono); font-style: normal; letter-spacing: 0.5px; }
@container (max-width: 200px) { .intent b.long { display: none; } .intent .code.long { display: inline; } } /* short names (Surge) always fit */
.bcell { container-type: inline-size; }
.intent small { margin-left: auto; font-family: var(--mono); color: var(--muted); white-space: nowrap; }
.intent.now { border-color: var(--hot); color: var(--hot); background: var(--hot-soft); }
.intent.now small { color: var(--hot); }
.intent.next { border-color: var(--next); color: var(--next); }
.intent.hidden { border-style: dashed; color: var(--muted); }
.intent.mine { border-color: var(--you); color: var(--you); }
.intent.mine.plan { border-style: dashed; opacity: 0.85; }
.intent.mine.auto { opacity: 0.8; }
/* an attack already delayed once: a teal pause mark (you did it), and no other delay moves it */
.intent.held { box-shadow: inset 2px 0 0 var(--you); }
.intent .held { display: inline-grid; flex: none; color: var(--you); }
.intent .held .glyph { width: 11px; height: 11px; margin: 0; }
.intent.daemon { border-color: var(--daemon); color: var(--daemon); }
.intent.patch { margin-top: 4px; padding: 2px 7px; font: 600 11px var(--mono); letter-spacing: 1px; border-style: dashed; border-color: var(--line-strong); color: var(--amber-soft); background: transparent; }
/* Encryption: the damage you take every cycle until the Encryptor breaks. On the Encryptor's row, in every column. */
.intent.crypt { margin-bottom: 4px; padding: 2px 7px; font: 600 11px var(--mono); letter-spacing: 1px; border-color: var(--hot); color: var(--hot); background: repeating-linear-gradient(135deg, var(--hot-soft) 0 6px, transparent 6px 12px); }
.intent.crypt small { color: var(--hot); opacity: 0.8; }
/* A Ratchet (a rolled fight's ramp on its basic): the same drain, amber, growing column by column. */
.intent.crypt.esc { border-color: var(--amber); color: var(--amber); background: repeating-linear-gradient(45deg, var(--amber-wash) 0 6px, transparent 6px 12px); }
.intent.crypt.esc small { color: var(--amber); }
.crypt-line.esc { background: repeating-linear-gradient(45deg, var(--amber) 0 4px, transparent 4px 8px); }
.crypt-line.esc::after { border-color: var(--amber); color: var(--amber); background: repeating-linear-gradient(45deg, var(--amber-wash) 0 6px, transparent 6px 12px), var(--panel); }
.tag.esc { color: var(--amber); border-color: var(--amber-soft); }
/* A Priority's mark (objectives.mjs): its target and cycles left, amber like the bonus it pays. */
.tag.prio { display: inline-flex; align-items: center; gap: 3px; color: var(--next); border-color: var(--next); font-weight: 700; }
.tag.prio .glyph { width: 11px; height: 11px; }
.tag.prio.met { color: var(--muted); border-color: var(--line); }
/* A crew boss's mechanics (raid.mjs): their own row on the board, each chip on the cycle it lands. */
.braid .bname small { display: block; font-size: 11px; }
.intent.raid { border-color: var(--hot); color: var(--hot); display: flex; flex-direction: column; gap: 1px; }
.intent.raid b { font: 600 11px var(--mono); letter-spacing: 1px; text-transform: uppercase; }
.intent.raid small { color: var(--text-dim, inherit); opacity: 0.85; }
.intent.raid.now { background: var(--hot-soft); }
.intent.raid.cast { border-style: dashed; }
.intent.raid .compiling { color: var(--hot); font-style: italic; opacity: 1; }
.intent.raid.fuse { border-color: var(--amber); color: var(--amber); }
.bescape .esc-left { color: var(--next); font-weight: 600; }
.intent.raid.fuse.escape.now { background: rgba(255, 216, 92, 0.12); border-color: var(--next); color: var(--next); }
/* A solo tell (tells.mjs): an attack chip, charged. A kicker strip (what kind, when), then the name and what it does,
   with a small SIGINT mark when SIGINT stops it. Charges and casts are hot; seals and the Mimic are amber. */
.intent.tell { --tc: var(--hot); --tc-soft: var(--hot-soft); display: grid; gap: 0; padding: 0; border: 1px solid var(--tc); color: var(--text); overflow: hidden; }
.intent.tell.t-seal, .intent.tell.t-mimic { --tc: var(--amber); --tc-soft: rgba(241, 185, 47, 0.12); }
.intent.tell.t-cast { border-style: dashed; }
.intent.tell .tl-kick { display: flex; align-items: center; gap: 5px; padding: 2px 7px; background: var(--tc-soft); color: var(--tc); font: 600 10px var(--mono); letter-spacing: 1px; text-transform: uppercase; white-space: nowrap; }
.intent.tell .tl-kick .ico { width: 11px; height: 11px; }
.intent.tell .tl-when { margin-left: auto; letter-spacing: 0.5px; }
.intent.tell .tl-main { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; padding: 4px 7px 2px; min-width: 0; }
.intent.tell .tl-main b { font-weight: 600; color: var(--tc); }
.intent.tell .tl-what { margin-left: 0; color: var(--muted); }
.intent.tell .tl-what.tl-price { color: var(--hot); font-weight: 600; } /* what it costs you (tells.mjs tellPrice): threat */
.intent.tell .tl-what.tl-armor { color: var(--steel); font-weight: 600; } /* the ◆ a seal would hand out */
.intent.tell .tl-main { padding-bottom: 5px; }
.intent.tell .tl-kick .tl-sig { width: 10px; height: 10px; margin-left: auto; background: var(--amber); } /* SIGINT stops it: your key, in amber, before the timing */
.intent.tell .tl-sig + .tl-when, .intent.tell .tl-sig + .tl-win { margin-left: 0; }
.intent.tell.now .tl-kick .tl-sig { background: var(--panel-2); }
.intent.tell.now { background: var(--tc-soft); }
.intent.tell.now .tl-kick { background: var(--tc); color: var(--panel-2); }
/* ---- Tell windows (tells.mjs, view.mjs tellChip and tellSpan) ----
   A tell can only be answered in its window: the cycle it lands, or its last few. While the window is open the chip
   wears the Sync Window's yellow (a NOW badge, a glow, the SIGINT mark in yellow). A window longer than a cycle marks the
   cells before the chip with a slim WINDOW strip, lit in the cycle you're in. */
.intent.tell { grid-template-columns: minmax(0, 1fr); }
.intent.tell .tl-win { margin-left: auto; padding: 0 3px; border-radius: 2px; background: var(--next); color: var(--panel-2); font: 700 9px var(--mono); letter-spacing: 0.5px; }
.intent.tell.win { border-color: var(--next); box-shadow: 0 0 0 1px var(--next), 0 0 10px rgba(255, 216, 92, 0.45); }
.tl-window { margin: 0 0 4px; padding: 1px 6px; border: 1px dashed rgba(255, 216, 92, 0.55); border-radius: 2px; background: rgba(255, 216, 92, 0.1); color: var(--next); font: 600 9px var(--mono); letter-spacing: 1px; text-transform: uppercase; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: help; }
.tl-window.live { border-style: solid; border-color: var(--next); background: rgba(255, 216, 92, 0.42); color: var(--panel-2); box-shadow: 0 0 10px rgba(255, 216, 92, 0.6); }
@media (max-width: 900px) {
  .intent.tell .tl-win { padding: 0 3px; font-size: 9px; }
  .intent.tell.win .tl-kind { display: none; } /* a narrow cell: the icon says the kind, NOW says the window */
  .tl-window { padding: 1px 2px; letter-spacing: 0; }
  .tl-window.live .tw-word { display: none; }
}
/* ---- end tell windows ---- */
/* ---- Themed chips (chipfx.mjs): a part's theme plays faint inside its own chips at +1 and in Now, under the text, in
   the chip's colour and white; its light adds up (screen). The box sits behind the chip's text (z-index -1 in the chip's
   own stacking context); chipfx sets its opacity. Nothing leaves the chip. ---- */
.brow[data-th] .intent[data-k] { position: relative; isolation: isolate; }
.intent > .fxin { position: absolute; inset: 0; z-index: -1; overflow: hidden; border-radius: inherit; pointer-events: none; mix-blend-mode: screen; opacity: 0; }
.intent.tell > .fxin { color: var(--tc); }
.fxin > * { position: absolute; left: 0; top: 0; pointer-events: none; }
.fxin .cfx-svg { width: 100%; height: 100%; overflow: visible; }
.cfx-arc .halo { fill: none; stroke: currentColor; stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; filter: url(#cfx-bloom); }
.cfx-arc .mid { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.cfx-arc .core { fill: none; stroke: var(--bright); stroke-width: 0.8; stroke-linecap: round; stroke-linejoin: round; }
.cfx-arc .twig { fill: none; stroke: currentColor; stroke-width: 0.8; stroke-linecap: round; opacity: 0.8; }
.cfx-hot, .cfx-glow { border-radius: 50%; background: radial-gradient(circle, var(--bright) 0, currentColor 30%, transparent 70%); }
.cfx-hot { width: 14px; height: 14px; margin: -7px 0 0 -7px; }
.cfx-glow { width: 22px; height: 22px; margin: -11px 0 0 -11px; }
.cfx-lk { will-change: transform, opacity; }
.cfx-lk svg { display: block; width: 100%; height: 100%; overflow: visible; }
.cfx-lk .sh { transition: transform 90ms cubic-bezier(.5, 0, .9, .4); transform: translateY(-2.6px); }
.cfx-lk.shut .sh { transform: none; }
.cfx-lk.near { filter: drop-shadow(0 0 2.5px currentColor); }
.cfx-lk.far, .cfx-stream.far { filter: blur(0.6px); }
.cfx-stream { display: grid; font-family: var(--mono); font-weight: 600; line-height: 1; will-change: transform; }
.cfx-stream i { font-style: normal; }
.cfx-stream .head { color: var(--bright); text-shadow: 0 0 4px currentColor, 0 0 8px var(--hot); }
.cfx-rg { fill: none; stroke: currentColor; filter: url(#cfx-soft); }
.cfx-br { fill: none; stroke: var(--bright); stroke-linecap: round; stroke-dasharray: 1 1; stroke-dashoffset: 1; opacity: 0.7; }
.cfx-rime { opacity: 0; }
.cfx-glint { width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; filter: drop-shadow(0 0 2px var(--bright)); }
.cfx-glint svg { display: block; width: 100%; height: 100%; }
.cfx-dith { width: 100%; height: 100%; background: repeating-conic-gradient(currentColor 0 25%, transparent 0 50%) 0 0 / 4px 4px; -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.55), #000 50%, rgba(0, 0, 0, 0.55)); mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.55), #000 50%, rgba(0, 0, 0, 0.55)); }
.cfx-edge { height: 100%; width: 2px; margin-left: -1px; background: var(--bright); box-shadow: 0 0 6px var(--bright), 0 0 12px currentColor; }
.cfx-flake { background: currentColor; box-shadow: 0 0 3px currentColor; }
.cfx-fly.cfx-stream { left: 0; top: 0; }
.cfx-fly.cfx-flake { left: 0; top: 0; }
.cfx-fly.cfx-edge { margin-left: 0; }
.cfx-bracket { border: 0 solid currentColor; filter: drop-shadow(0 0 3px currentColor); }
.cfx-flash { background: currentColor; }
.no-motion .fxin { display: none; }
/* Its strike when it goes off (chipfx.mjs chipStrike), in the threat's red: a bolt, flying padlocks, frost shards. */
.cfx-fly { position: fixed; z-index: 56; pointer-events: none; color: var(--hot); }
svg.cfx-bolt { left: 0; top: 0; width: 100vw; height: 100vh; overflow: visible; mix-blend-mode: screen; }
.cfx-burst { border-radius: 50%; background: radial-gradient(circle, var(--bright) 0, currentColor 25%, transparent 65%); mix-blend-mode: screen; }
.cfx-clamp { border: 1.5px solid currentColor; border-radius: 50%; mix-blend-mode: screen; }
.cfx-shard { background: var(--bright); box-shadow: 0 0 3px var(--bright); }
/* the shared themes: heat */
.cfx-heat { width: 100%; height: 100%; background: radial-gradient(130% 80% at 50% 135%, var(--bright) 0, currentColor 38%, transparent 78%); opacity: 0; }
.cfx-fl-back { fill: currentColor; opacity: 0.4; filter: url(#cfx-bloom); }
.cfx-fl-halo { fill: currentColor; opacity: 0.5; filter: url(#cfx-bloom); }
.cfx-fl-body { fill: currentColor; opacity: 0.32; }
.cfx-fl-core { fill: var(--bright); opacity: 0.6; filter: url(#cfx-soft); }
.cfx-em { border-radius: 50%; background: var(--bright); box-shadow: 0 0 2px var(--bright), 0 0 5px currentColor, 0 0 9px currentColor; transition: background 0.3s, box-shadow 0.3s; }
.cfx-em.cool { background: currentColor; box-shadow: 0 0 4px currentColor; }
.cfx-em.far { filter: blur(0.5px); box-shadow: 0 0 3px currentColor; }
.cfx-spark { width: 1.5px; height: 1.5px; border-radius: 50%; background: var(--bright); box-shadow: 0 0 3px currentColor; }
.cfx-sparkln { border-radius: 1px; background: linear-gradient(90deg, transparent, var(--bright)); box-shadow: 0 0 3px currentColor; }
.cfx-fb-halo circle { fill: currentColor; opacity: 0.55; filter: url(#cfx-bloom); }
.cfx-fb-body circle { fill: currentColor; opacity: 0.8; }
.cfx-fb-core circle { fill: var(--bright); }
.cfx-fb-core { filter: url(#cfx-soft); }
.cfx-scorch { fill: currentColor; filter: url(#cfx-bloom); }
/* crumble */
.cfx-cr-halo, .cfx-cr-core { fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 1; stroke-dashoffset: 1; }
.cfx-cr-halo { stroke: currentColor; opacity: 0.75; filter: url(#cfx-bloom); }
.cfx-cr-core { stroke: var(--bright); }
.cfx-tip { width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%; background: radial-gradient(circle, var(--bright) 0, currentColor 35%, transparent 70%); opacity: 0; }
.cfx-chip { background: var(--bright); filter: drop-shadow(0 0 2px currentColor); }
.cfx-dust1 { width: 1px; height: 1px; background: currentColor; filter: blur(0.4px); }
.cfx-px { width: 3px; height: 3px; background: var(--bright); box-shadow: 0 0 3px currentColor; opacity: 0; }
.cfx-grit { width: 2px; height: 2px; background: var(--bright); box-shadow: 0 0 2px currentColor; }
.cfx-puff { border-radius: 50%; background: radial-gradient(circle, currentColor 0, transparent 70%); filter: blur(1.5px); }
.cfx-sh-halo { fill: currentColor; opacity: 0.35; filter: url(#cfx-bloom); }
.cfx-sh-body { fill: currentColor; fill-opacity: 0.16; stroke: var(--bright); stroke-width: 0.7; stroke-opacity: 0.85; stroke-linejoin: round; }
/* scramble */
.cfx-sc-back, .cfx-sc-tail, .cfx-sc-head { font: 500 9px/9px var(--mono); white-space: pre; letter-spacing: 0; }
.cfx-sc-back { color: currentColor; opacity: 0.3; filter: blur(0.35px); }
.cfx-sc-tail { color: currentColor; text-shadow: 0 0 4px currentColor; }
.cfx-sc-head { color: var(--bright); text-shadow: 0 0 3px var(--bright), 0 0 7px currentColor; }
.cfx-sc-pop { font: 600 12px/12px var(--mono); color: var(--bright); text-shadow: 0 0 4px currentColor, 0 0 9px currentColor; }
.cfx-sc-pop.set { color: currentColor; text-shadow: 0 0 4px currentColor; }
.cfx-tear { height: 1px; background: var(--bright); box-shadow: 0 0 4px var(--bright), 0 0 8px currentColor; opacity: 0; }
.cfx-bolt text { font: 600 12px var(--mono); }
.cfx-sc-halo { fill: currentColor; filter: url(#cfx-bloom); }
.cfx-sc-core { fill: var(--bright); }
.cfx-sc-set { fill: currentColor; }
.cfx-sc-g1 { fill: currentColor; opacity: 0.45; }
.cfx-sc-g2 { fill: currentColor; opacity: 0.2; filter: url(#cfx-soft); }
.cfx-sc-flash { fill: var(--bright); opacity: 0.8; filter: url(#cfx-bloom); }
.cfx-sc-tearln { fill: var(--bright); }
/* thorn */
.cfx-vine path { fill: none; stroke-linecap: round; }
.cfx-vine .halo { stroke: currentColor; stroke-width: 2.4; opacity: 0.6; filter: url(#cfx-bloom); }
.cfx-vine .core { stroke: currentColor; stroke-width: 0.8; }
.cfx-th-halo { fill: currentColor; opacity: 0.55; filter: url(#cfx-bloom); }
.cfx-th-body { fill: currentColor; }
.cfx-th-core { fill: var(--bright); opacity: 0.9; }
.far .cfx-th-body { opacity: 0.5; filter: url(#cfx-soft); }
.cfx-th-streak { fill: currentColor; opacity: 0.55; filter: url(#cfx-bloom); }
.cfx-th-streakc { fill: var(--bright); opacity: 0.6; }
.glint .cfx-sh-body { fill: var(--bright); fill-opacity: 0.6; stroke-width: 1.2; }
.glint .cfx-sh-halo { opacity: 0.7; }
/* clock */
.cfx-ck-ruler line { stroke: currentColor; stroke-width: 1; opacity: 0.35; }
.cfx-ck-ruler line.on { stroke: var(--bright); opacity: 0.8; }
.cfx-ck-ruler line.head { stroke: var(--bright); stroke-width: 1.6; opacity: 1; filter: drop-shadow(0 0 2px currentColor); }
.cfx-ck-face { fill: none; stroke: currentColor; stroke-width: 1; filter: url(#cfx-soft); }
.cfx-ck-fan { fill: currentColor; opacity: 0.3; filter: url(#cfx-soft); }
.cfx-ck-ticks line { stroke: currentColor; stroke-width: 1.1; stroke-linecap: round; }
.cfx-ck-ticks line.on, .cfx-ck-ticks.lit line { stroke: var(--bright); }
.cfx-ck-halo, .cfx-ck-body, .cfx-ck-core { stroke-linecap: round; }
.cfx-ck-halo { stroke: currentColor; opacity: 0.6; filter: url(#cfx-bloom); }
.cfx-ck-body { stroke: currentColor; }
.cfx-ck-core { stroke: var(--bright); }
.cfx-ck-hub { fill: var(--bright); }
.cfx-ck-stop { fill: var(--bright); filter: url(#cfx-bloom); }
/* strobe */
.cfx-sb { top: 0; height: 100%; background: linear-gradient(90deg, transparent, currentColor 30%, var(--bright) 50%, currentColor 70%, transparent); box-shadow: 0 0 8px currentColor; opacity: 0; }
.cfx-sb.far { filter: blur(1px); box-shadow: none; }
.cfx-sb-streak { top: calc(50% - 4px); width: 100%; height: 8px; background: linear-gradient(transparent, currentColor 40%, var(--bright) 50%, currentColor 60%, transparent); filter: blur(0.6px); opacity: 0; }
.cfx-sb-chip { fill: var(--bright); opacity: 0.35; }
.cfx-sb-cone { fill: currentColor; opacity: 0.45; filter: url(#cfx-bloom); }
.cfx-sb-core { stroke: var(--bright); stroke-linecap: round; filter: drop-shadow(0 0 3px currentColor); }
.cfx-sb-hit { fill: var(--bright); opacity: 0.85; }
.cfx-sb-flare { fill: var(--bright); filter: drop-shadow(0 0 4px currentColor) drop-shadow(0 0 8px currentColor); }
.cfx-sb-glow { fill: currentColor; opacity: 0.6; filter: url(#cfx-bloom); }
/* copy */
span.cfx-cp-wake { --x: 0px; width: 100%; height: 100%; background: radial-gradient(circle, currentColor 0.7px, transparent 1.1px) 0 0 / 4px 4px; opacity: 0; -webkit-mask-image: linear-gradient(90deg, transparent calc(var(--x) - 70px), #000 var(--x), transparent var(--x)); mask-image: linear-gradient(90deg, transparent calc(var(--x) - 70px), #000 var(--x), transparent var(--x)); }
rect.cfx-cp-wake { fill: currentColor; filter: url(#cfx-soft); }
.cfx-cp-lamp { top: 0; height: 100%; width: 24px; margin-left: -12px; background: linear-gradient(90deg, transparent, currentColor 38%, var(--bright) 49%, var(--bright) 51%, currentColor 62%, transparent); filter: blur(0.4px); }
.cfx-cp-copy { border: 1px solid var(--bright); border-radius: 3px; box-shadow: 0 0 4px currentColor, inset 0 0 6px currentColor; opacity: 0; transform-origin: 50% 50%; }
.cfx-cp-copy.far { border-color: currentColor; box-shadow: none; filter: blur(0.6px); }
.cfx-cp-lampr { fill: var(--bright); filter: url(#cfx-bloom); }
.cfx-cp-ghost { fill: none; stroke: currentColor; stroke-width: 1; }
.cfx-cp-halo { fill: currentColor; fill-opacity: 0.12; stroke: currentColor; stroke-width: 3; stroke-opacity: 0.5; filter: url(#cfx-bloom); }
.cfx-cp-edge { fill: none; stroke: var(--bright); stroke-width: 1; }
.cfx-cp-edge.hot { stroke-width: 2; filter: drop-shadow(0 0 3px var(--bright)); }
/* scan */
.cfx-sn-dots circle { fill: var(--bright); }
.cfx-sn-beam { top: 0; height: 100%; width: 1.5px; margin-left: -0.75px; background: var(--bright); box-shadow: 0 0 4px var(--bright), 0 0 9px currentColor; transform-origin: 0.75px 50%; }
.cfx-sn-beam i { position: absolute; top: 0; right: 1px; width: 26px; height: 100%; background: linear-gradient(90deg, transparent, currentColor); opacity: 0.55; }
.cfx-sn-tgt { width: 10px; height: 10px; --c: var(--bright); --a: 3px; --t: 1px; filter: drop-shadow(0 0 2px currentColor);
  background: linear-gradient(var(--c), var(--c)) 0 0 / var(--a) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 0 0 / var(--t) var(--a) no-repeat,
    linear-gradient(var(--c), var(--c)) 100% 0 / var(--a) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 100% 0 / var(--t) var(--a) no-repeat,
    linear-gradient(var(--c), var(--c)) 0 100% / var(--a) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 0 100% / var(--t) var(--a) no-repeat,
    linear-gradient(var(--c), var(--c)) 100% 100% / var(--a) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 100% 100% / var(--t) var(--a) no-repeat; }
.cfx-sn-tgt.big { --a: 5px; --t: 1.5px; }
.cfx-sn-emit { fill: var(--bright); filter: drop-shadow(0 0 3px currentColor) drop-shadow(0 0 6px currentColor); }
.cfx-sn-cone { fill: currentColor; opacity: 0.4; filter: url(#cfx-bloom); }
.cfx-sn-edge { stroke: var(--bright); stroke-width: 0.6; opacity: 0.6; }
.cfx-sn-core { stroke: var(--bright); stroke-width: 1.2; filter: drop-shadow(0 0 2px currentColor); }
.cfx-sn-rake { filter: drop-shadow(0 0 3px currentColor); }
/* plate */
.cfx-pl-mesh polygon { fill: none; stroke: currentColor; stroke-width: 0.7; opacity: 0; }
.cfx-pl-halo { fill: currentColor; opacity: 0.2; filter: url(#cfx-bloom); }
.cfx-pl-body { fill: currentColor; fill-opacity: 0.1; stroke: currentColor; stroke-width: 0.8; }
.cfx-pl-bevel { fill: none; stroke: var(--bright); stroke-width: 1.2; stroke-linejoin: round; filter: drop-shadow(0 0 2px currentColor); }
.cfx-pl-rim { stroke: var(--bright); stroke-width: 0.6; opacity: 0.6; }
.cfx-pl-rivet { fill: var(--bright); opacity: 0.85; }
.cfx-seam { top: 0; height: 100%; width: 2px; background: var(--bright); box-shadow: 0 0 6px var(--bright), 0 0 12px currentColor; opacity: 0; }
/* ledger */
.cfx-lg-lines { width: 100%; height: 100%; background: repeating-linear-gradient(transparent 0 5px, currentColor 5px 6px); opacity: 0; -webkit-mask-image: linear-gradient(90deg, transparent, #000 20%, #000 80%, transparent); mask-image: linear-gradient(90deg, transparent, #000 20%, #000 80%, transparent); filter: opacity(0.35); }
.cfx-lg-reel { top: 0; height: 100%; width: 8px; overflow: hidden; -webkit-mask-image: linear-gradient(transparent, #000 35%, #000 65%, transparent); mask-image: linear-gradient(transparent, #000 35%, #000 65%, transparent); }
.cfx-lg-reel b { display: grid; font: 600 9px/10px var(--mono); text-align: center; color: var(--bright); text-shadow: 0 0 3px currentColor, 0 0 7px currentColor; will-change: transform; }
.cfx-lg-reel i { font-style: normal; }
.cfx-lg-reel.far b { font-size: 7px; color: currentColor; text-shadow: none; filter: blur(0.4px); }
.cfx-lg-reel.spin b { filter: blur(0.9px); }
.cfx-lg-win { width: 10px; height: 12px; border-top: 1px solid var(--bright); border-bottom: 1px solid var(--bright); box-shadow: 0 0 4px currentColor; opacity: 0; }
/* mask */
.cfx-mk-halo, .cfx-mk-body, .cfx-mk-core { fill: none; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.cfx-mk-halo { stroke: currentColor; stroke-width: 3; opacity: 0.55; filter: url(#cfx-bloom); }
.cfx-mk-body { stroke: currentColor; stroke-width: 1.2; }
.cfx-mk-core { stroke: var(--bright); stroke-width: 0.5; }
.cfx-mk-ghost { opacity: 0.3; filter: url(#cfx-soft); }
.hot .cfx-mk-core { stroke-width: 1; }
.hot .cfx-mk-halo { opacity: 0.9; }
.cfx-mk-edge { stroke: var(--bright); stroke-width: 1.4; filter: drop-shadow(0 0 3px currentColor); }
.cfx-mk-star { fill: var(--bright); filter: drop-shadow(0 0 2px currentColor); }
/* byte (a fragment's Gnaw): the torn chunk and its 1s and 0s are your bar's, so teal */
.cfx-by-cell { fill: currentColor; }
.cfx-by-cell.gone { fill: none; stroke: currentColor; stroke-width: 0.6; stroke-opacity: 0.5; }
.cfx-by-nib { fill: var(--bright); }
.cfx-by-bit1 { fill: var(--bright); stroke: currentColor; stroke-width: 0.8; }
.cfx-by-bit0 { fill: none; stroke: currentColor; stroke-width: 1; }
.cfx-by-brk { fill: none; stroke: var(--bright); stroke-width: 1.4; filter: drop-shadow(0 0 3px currentColor); }
.cfx-by-hole { background: var(--inset); }
.cfx-by-chunk { background: var(--you); box-shadow: 0 0 6px var(--you); }
.cfx-by-glyph { font: 700 9px/8px var(--mono); color: var(--you); text-shadow: 0 0 4px var(--you); text-align: center; }
@media (prefers-reduced-motion: reduce) { .fxin { display: none; } }
.crypt-line { position: relative; height: 4px; margin: 0 0 6px; border-radius: 2px; background: repeating-linear-gradient(135deg, var(--hot) 0 4px, transparent 4px 8px); opacity: 0.7; cursor: help; }
/* Hover: it opens up into the full chip for a moment (over the cell, nothing moves). */
.crypt-line::after { content: attr(data-label); position: absolute; left: 0; top: 50%; transform: translateY(-50%) scaleY(0.2); transform-origin: left center; opacity: 0; padding: 3px 8px; border: 1px solid var(--hot); border-radius: 3px; background: repeating-linear-gradient(135deg, var(--hot-soft) 0 6px, transparent 6px 12px), var(--panel); color: var(--hot); font: 600 11px var(--mono); letter-spacing: 0.5px; white-space: nowrap; pointer-events: none; z-index: 4; transition: transform 0.15s ease-out, opacity 0.15s ease-out; }
.crypt-line:hover { opacity: 1; }
.crypt-line:hover::after { transform: translateY(-50%) scaleY(1); opacity: 1; }
.hud-extra.hot { color: var(--hot); font-weight: 600; }
/* armor chits: filled = there, hollow = broken */
.chits { font: 15px/1 var(--mono); color: var(--amber); letter-spacing: 2px; text-shadow: 0 0 6px rgba(241, 185, 47, 0.45); margin-left: 6px; margin-right: auto; white-space: nowrap; }
.chits i { font-style: normal; color: var(--dim); }
/* armor broken: the part's cell cracks (it patches back, and the cracks go with it) */
.brow.cracked .bname { background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='240'%20height='64'%20viewBox='0%200%20240%2064'%20fill='none'%20stroke-linejoin='round'%3E%3Cpath%20d='M238%2060%20L222%2052%20L206%2055%20L190%2044%20L176%2046%20L160%2036'%20stroke='%23000'%20stroke-opacity='.5'%20stroke-width='1.6'%20transform='translate(0.6%200.8)'/%3E%3Cpath%20d='M238%2060%20L226%2044%20L229%2032%20L218%2020%20L221%2010'%20stroke='%23000'%20stroke-opacity='.5'%20stroke-width='1.6'%20transform='translate(0.6%200.8)'/%3E%3Cpath%20d='M238%2060%20L214%2062'%20stroke='%23000'%20stroke-opacity='.5'%20stroke-width='1.6'%20transform='translate(0.6%200.8)'/%3E%3Cpath%20d='M206%2055%20L200%2064'%20stroke='%23000'%20stroke-opacity='.5'%20stroke-width='1.6'%20transform='translate(0.6%200.8)'/%3E%3Cpath%20d='M190%2044%20L186%2034%20L174%2030'%20stroke='%23000'%20stroke-opacity='.5'%20stroke-width='1.6'%20transform='translate(0.6%200.8)'/%3E%3Cpath%20d='M226%2044%20L212%2038%20L204%2026'%20stroke='%23000'%20stroke-opacity='.5'%20stroke-width='1.6'%20transform='translate(0.6%200.8)'/%3E%3Cpath%20d='M238%2060%20L240%2040'%20stroke='%23000'%20stroke-opacity='.5'%20stroke-width='1.6'%20transform='translate(0.6%200.8)'/%3E%3Cpath%20d='M238%2060%20L222%2052%20L206%2055%20L190%2044%20L176%2046%20L160%2036'%20stroke='%23fff2c8'%20stroke-opacity='.26'%20stroke-width='.8'/%3E%3Cpath%20d='M238%2060%20L226%2044%20L229%2032%20L218%2020%20L221%2010'%20stroke='%23fff2c8'%20stroke-opacity='.26'%20stroke-width='.8'/%3E%3Cpath%20d='M238%2060%20L214%2062'%20stroke='%23fff2c8'%20stroke-opacity='.26'%20stroke-width='.8'/%3E%3Cpath%20d='M206%2055%20L200%2064'%20stroke='%23fff2c8'%20stroke-opacity='.26'%20stroke-width='.8'/%3E%3Cpath%20d='M190%2044%20L186%2034%20L174%2030'%20stroke='%23fff2c8'%20stroke-opacity='.26'%20stroke-width='.8'/%3E%3Cpath%20d='M226%2044%20L212%2038%20L204%2026'%20stroke='%23fff2c8'%20stroke-opacity='.26'%20stroke-width='.8'/%3E%3Cpath%20d='M238%2060%20L240%2040'%20stroke='%23fff2c8'%20stroke-opacity='.26'%20stroke-width='.8'/%3E%3C/svg%3E") right bottom / 380px 100px no-repeat; }
.brow.cracked.fx-hit .bname, .brow.cracked.fx-break .bname { background-color: transparent; }
.log-lines .daemon { color: var(--daemon); }
.bname small { display: block; }
.quiet { font-size: 12px; color: var(--dim); font-style: italic; }
.hidden-row { grid-column: 1 / -1; margin-top: 8px; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; font-size: 12px; color: var(--muted); }

/* ---------- log ---------- */
.log-lines { list-style: none; margin: 0; padding: 0 14px 10px; overflow-y: auto; flex: 1; font: 13px/1.55 var(--mono); color: var(--muted); }
.log-lines li { display: grid; grid-template-columns: 34px 1fr; gap: 6px; }
.log-lines .c { color: var(--dim); }
.log-lines .you { color: var(--you); }
.log-lines .bad { color: var(--hot); }
.log-lines .exc { color: var(--exception); }
.log-lines .loss { color: var(--next); }
.log-lines .good { color: var(--bright); }
.log-lines .note { color: var(--text); }
.log-lines .warn { color: var(--amber); }

/* ---------- command dock ---------- */
.command-dock { position: relative; z-index: 10; padding: 0 20px 12px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.prompt-row, #command-form { min-width: 0; }
.prompt-row { position: relative; }
#command-form { display: flex; align-items: center; gap: 10px; background: var(--inset); border: 1px solid var(--amber); border-radius: 4px; padding: 0 12px; box-shadow: 0 0 14px rgba(241, 185, 47, 0.12); }
#command-form:focus-within { box-shadow: 0 0 0 1px var(--amber), 0 0 18px rgba(241, 185, 47, 0.22); }
.prompt { font: 600 15px var(--mono); color: var(--amber); white-space: nowrap; }
#command-input { flex: 1; min-width: 0; width: 100%; background: none; border: 0; outline: 0; padding: 11px 0; font: 500 16px var(--mono); color: var(--bright); caret-color: var(--amber); }
#command-input::placeholder { color: var(--dim); }
.hints { font-size: 12px; color: var(--dim); white-space: nowrap; }
.suggestions { position: absolute; bottom: calc(100% + 4px); left: 0; right: 0; display: flex; gap: 6px; flex-wrap: wrap; padding: 6px; background: var(--panel-2); border: 1px solid var(--line-strong); border-radius: 4px; z-index: 5; }
.suggestions button { font: 13px var(--mono); border-color: var(--line); }
.suggestions button[aria-selected='true'] { border-color: var(--amber); color: var(--bright); }
.notice { position: absolute; bottom: calc(100% + 4px); right: 0; max-width: 60%; padding: 6px 10px; background: var(--panel-2); border: 1px solid var(--amber); border-radius: 4px; font-size: 13px; z-index: 6; }
.notice.bad { border-color: var(--hot); color: var(--bright); }

.tray { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 6px; } /* one row: Spike · 7 to 9 skills · SIGINT · next unlock */
.tray:has(> :nth-child(11 of .ability)) .ability { column-gap: 8px; padding: 0 8px 3px; } /* eleven keys or more (an eighth slot at 22, a ninth at 30): a size down */
.tray:has(> :nth-child(11 of .ability)) .ability .name { font-size: 13px; }
.tray:has(> :nth-child(11 of .ability)) .ability .cd { left: 8px; }
/* The Toolkit's button (view.mjs trayMarkup): small and quiet past the last key, out of the grid, so no key moves. */
.tray:has(> .tk-open) { position: relative; padding-right: 32px; }
.tk-open { position: absolute; right: 0; top: 50%; transform: translateY(-50%); display: grid; place-items: center; width: 26px; height: 26px; padding: 0; background: none; border: 1px solid var(--line); border-radius: var(--r-btn); cursor: pointer; }
.tk-open .ico { width: 14px; height: 14px; background: var(--muted); -webkit-mask: var(--icon) center/contain no-repeat; mask: var(--icon) center/contain no-repeat; }
.tk-open:hover, .tk-open:focus-visible { border-color: var(--line-strong); }
.tk-open:hover .ico, .tk-open:focus-visible .ico { background: var(--amber); }
.ability.cantrip { background: var(--inset); }
.tag.daemon { color: var(--daemon); border-color: var(--daemon); }
/* A tray key: its icon and its name, one height and one padding everywhere (view.mjs keyFace). The name takes two lines
   at most; what the key does and what holds now are its tooltip. */
.ability { position: relative; overflow: hidden; display: grid; grid-template-columns: 20px minmax(0, 1fr); align-items: center; column-gap: 10px; height: 48px; padding: 0 12px 3px; text-align: left; background: var(--panel); border: 1px solid var(--line); border-radius: 4px; }
.ability .ico { width: 20px; height: 20px; background: var(--amber); -webkit-mask: var(--icon) center/contain no-repeat; mask: var(--icon) center/contain no-repeat; }
.ability .name { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; overflow-wrap: break-word; font-weight: 600; font-size: 14px; line-height: 1.2; color: var(--bright); }
/* Ready or recharging, at a glance: a charge bar along the bottom (full amber = ready), and while it
   recharges striped and dimmed, the cycles to go over its icon. */
.ability .charge { position: absolute; left: 0; bottom: 0; height: 3px; background: var(--amber); transition: width 0.4s ease; }
.ability.cooling { background: repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.025) 0 6px, transparent 6px 12px), var(--inset); border-color: var(--line); }
.ability.cooling .ico { background: var(--gray); opacity: 0.6; }
.ability.cooling .name { color: var(--muted); }
.ability.cooling .charge { background: var(--gray); opacity: 0.8; }
/* The cycles to go, over the dimmed icon, like WoW's cooldown count. */
.ability .cd { position: absolute; left: 12px; top: calc(50% - 1.5px); width: 20px; transform: translateY(-50%); text-align: center; font: 700 17px/1 var(--mono); color: var(--bright); }
.ability:has(.cd) .ico { opacity: 0.22; }
.ability.ready .ico { filter: drop-shadow(0 0 4px rgba(241, 185, 47, 0.45)); }
.ability.just-ready { animation: just-ready 0.7s ease-out; }
@keyframes just-ready { 0% { box-shadow: 0 0 0 2px var(--amber), 0 0 18px rgba(241, 185, 47, 0.6); } 100% { box-shadow: none; } }
.no-motion .ability.just-ready { animation: none; }
.ability.queued { border-color: var(--you); box-shadow: 0 0 0 1px var(--you) inset; }
/* Armor takes this hit: a key's icon turns steel (view.mjs trayMarkup), and your Now chip wears a small steel ◆
   (armorBadge). Steel is what protects a part (docs/ui.md). */
.ability.armd .ico { background: var(--steel); opacity: 1; filter: drop-shadow(0 0 4px var(--steel-glow)); }
.intent .armd { position: absolute; top: 2px; right: 4px; font: 700 11px/1 var(--mono); color: var(--steel); text-shadow: 0 0 4px var(--steel-glow); cursor: help; }
.intent .armd { top: -6px; right: -4px; padding: 0 2px; background: var(--panel); border: 1px solid var(--steel); border-radius: var(--r-tag); font-size: 9px; line-height: 11px; }
.pips { letter-spacing: 2px; color: var(--amber); font-family: var(--mono); }
.ability.emergency { border-style: dashed; border-color: var(--line-strong); }
.ability.emergency .ico { background: var(--next); }

/* ---------- pages ---------- */
.page { height: 100%; overflow-y: auto; }
.page-grid { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 12px; align-items: start; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 4px; padding: 16px 18px; display: grid; gap: 10px; }
.card h2 { font-size: 12px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--muted); font-weight: 600; }
.card h1 { font-size: 24px; color: var(--bright); letter-spacing: 1px; }
.card p { color: var(--muted); max-width: 70ch; }
.card.alert { border-color: var(--hot); }
.card.alert h2 { color: var(--hot); }
.row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.btn { border: 1px solid var(--line-strong); padding: 7px 14px; color: var(--bright); }
.btn.primary { border-color: var(--amber); background: rgba(241, 185, 47, 0.1); }
.btn[aria-pressed='true'] { border-color: var(--amber); color: var(--amber); }
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.stat { background: var(--inset); border: 1px solid var(--line); padding: 8px 10px; border-radius: 3px; }
.stat span { display: block; font-size: 12px; color: var(--muted); }
.stat strong { font-size: 18px; color: var(--bright); font-variant-numeric: tabular-nums; }
.list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.list li { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.list li span { color: var(--muted); }
.ticker { font: 12px var(--mono); color: var(--dim); white-space: nowrap; overflow: hidden; }
.ticker span { display: inline-block; animation: tick 60s linear infinite; }
.no-motion .ticker span { animation: none; padding-left: 0; }
@keyframes tick { to { transform: translateX(-50%); } }
.lesson { border-color: var(--you); }
.lesson h2 { color: var(--you); }
.lesson .expect { font: 600 15px var(--mono); color: var(--you); }
.fulllog { font: 13px/1.6 var(--mono); color: var(--muted); max-height: 60vh; overflow: auto; margin: 0; padding: 0; list-style: none; }
details summary { cursor: pointer; color: var(--muted); }
pre { font: 12px var(--mono); color: var(--muted); white-space: pre-wrap; max-height: 300px; overflow: auto; }
/* Art (every decorative pre is aria-hidden) never scrolls: only text that may run long does. */
pre[aria-hidden="true"] { max-height: none; overflow: visible; }

/* ---------- the net ---------- */
.net-one { position: relative; height: 100%; display: flex; flex-direction: column; max-width: 1100px; margin: 0 auto; }
.net-head { display: flex; align-items: center; gap: 24px; padding: 12px 18px; border-bottom: 1px solid var(--line); }
.net-where { display: flex; flex-direction: column; min-width: 0; }
.net-where b { color: var(--bright); letter-spacing: 1.5px; }
.net-where span { font: 13px var(--mono); color: var(--muted); }
.net-signal { display: flex; align-items: center; gap: 10px; margin-left: auto; font-variant-numeric: tabular-nums; }
.net-signal .lbl { font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--muted); }
.sigbar { width: 220px; height: 12px; border: 1px solid var(--you); background: var(--inset); }
.sigbar span { display: block; height: 100%; background: var(--you); transition: width 0.3s; }
.net-signal strong { font: 600 26px var(--mono); color: var(--you); line-height: 1; }
.net-signal small { color: var(--muted); font-family: var(--mono); }
.net-signal.mid .sigbar { border-color: var(--next); } .net-signal.mid .sigbar span { background: var(--next); } .net-signal.mid strong { color: var(--next); }
.net-signal.low .sigbar { border-color: var(--hot); } .net-signal.low .sigbar span { background: var(--hot); } .net-signal.low strong { color: var(--hot); }
.net-pack { font: 13px var(--mono); color: var(--muted); border-color: var(--line); }
.net-pack b { color: var(--bright); }
.term { list-style: none; margin: 0; padding: 8px 18px 16px; overflow-y: auto; flex: 1; font: 15px/1.6 var(--mono); color: var(--muted); white-space: pre-wrap; }
.term li { margin-bottom: 2px; }
.term li.you { color: var(--you); margin-top: 12px; }
.term li.note, .term li.file { color: var(--text); }
.term li.file { border-left: 2px solid var(--line-strong); padding-left: 10px; }
.term li.good { color: var(--bright); }
.term li.warn { color: var(--amber); }
.term li.bad { color: var(--hot); }
.ls { display: grid; gap: 2px; white-space: normal; }
.ls-row { display: flex; align-items: center; gap: 10px; }
.ls-kind { color: var(--dim); width: 10px; }
.ls-size { color: var(--dim); font-size: 12px; min-width: 28px; }
.tok { font: 15px var(--mono); padding: 0 6px; border: 1px solid transparent; border-radius: 2px; color: var(--text); text-align: left; }
.tok.dir { color: var(--amber); }
.tok:hover { border-color: var(--amber); background: rgba(241, 185, 47, 0.08); }
.tok.act { font-size: 12px; color: var(--you); border-color: var(--you); padding: 0 8px; }
.prompt.run { color: var(--you); }
.prompt.run.mid { color: var(--next); }
.prompt.run.low { color: var(--hot); }
.tray.net-tray { display: block; }
.next { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.next-label { font-size: 12px; color: var(--dim); text-transform: uppercase; letter-spacing: 1px; }
.nextbtn { font: 14px var(--mono); border: 1px solid var(--line-strong); background: var(--panel); color: var(--bright); padding: 7px 12px; display: inline-flex; gap: 8px; align-items: baseline; }
.nextbtn small { font: 11px var(--sans); color: var(--muted); }
.nextbtn.hot { border-color: var(--you); color: var(--you); }
.nextbtn.quiet { color: var(--muted); border-color: var(--line); margin-left: auto; }

/* ---------- map ---------- */
.modules .ctx { color: var(--you); }
.map-page { height: 100%; display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); gap: 12px; }
.map-canvas { display: flex; flex-direction: column; min-height: 0; background: var(--inset) url('ui/textures/terminal-grid-fine.png'); }
.map-svg { flex: 1; width: 100%; min-height: 0; font-family: var(--mono); }
/* The map's ground, the Chart (view.mjs mapMarkup): crosshairs and hairlines in the map's own units, so it moves with it. */
.mchart { pointer-events: none; }
.mchart-line, .mchart-tick { fill: none; stroke-width: 1; vector-effect: non-scaling-stroke; }
.mchart-line { stroke: color-mix(in srgb, var(--amber) 4%, transparent); }
.mchart-tick { stroke: color-mix(in srgb, var(--amber) 12%, transparent); }
@media (min-width: 901px) { .mchart-line { stroke: color-mix(in srgb, var(--amber) 2.5%, transparent); } .mchart-tick { stroke: color-mix(in srgb, var(--amber) 5%, transparent); } } /* dimmer on a desktop's big map */
.map-legend { padding: 6px 14px 10px; font-size: 12px; color: var(--dim); display: flex; gap: 6px 14px; flex-wrap: wrap; align-items: center; }
.lg { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: -8px; border: 1.5px solid var(--amber); }
.lg.partial { background: var(--amber); }
.lg.done { border-color: var(--gray); background: var(--gray); }
.lg.ghost { border-style: dashed; border-color: var(--muted); }
.map-side { display: flex; flex-direction: column; gap: 12px; overflow-y: auto; min-height: 0; }
/* The map: a quiet network scope. Hairlines, small nodes, small type. */
.map-canvas { background: radial-gradient(60% 70% at 50% 50%, rgba(241, 185, 47, 0.035), transparent 70%), var(--inset); }
.mscope .mring-range { fill: none; stroke: rgba(241, 185, 47, 0.09); stroke-width: 1; }
.mscope .mring-range.wall { stroke: rgba(127, 209, 199, 0.16); stroke-dasharray: 2 5; }
.mscope .maxis { stroke: rgba(241, 185, 47, 0.05); stroke-width: 1; }
.mring-label { fill: rgba(241, 185, 47, 0.4); font-size: calc(10px / var(--z, 1)); letter-spacing: 2px; text-transform: uppercase; }
.mlink { stroke: rgba(241, 185, 47, 0.26); stroke-width: 1; }
.mlink.hot { stroke: rgba(255, 91, 61, 0.75); stroke-dasharray: 3 5; animation: mflow 1.2s linear infinite; }
.mlink.ghost { stroke: rgba(241, 185, 47, 0.2); stroke-dasharray: 1 5; }
@keyframes mflow { to { stroke-dashoffset: -16; } }
.mnode { cursor: pointer; outline: none; }
.mlabel { fill: #e6dcc4; font-size: calc(13px / var(--z, 1)); font-weight: 600; letter-spacing: 1.2px; transition: fill 0.15s; }
.mlabel.home { fill: var(--you); letter-spacing: 2.5px; }
.mlabel.hot { fill: var(--hot); }
.mlabel.dim { fill: var(--muted); }
.msub { fill: var(--muted); font-size: calc(11px / var(--z, 1)); letter-spacing: 0.5px; }
.mnode:hover .mlabel, .mnode.selected .mlabel { fill: var(--bright); }
.mnode:hover .mlabel.hot, .mnode.selected .mlabel.hot { fill: #ff8a70; }
.mreticle { fill: none; stroke: var(--bright); stroke-width: 1.2; opacity: 0.85; }
.mnode.server .halo { fill: rgba(127, 209, 199, 0.05); stroke: rgba(127, 209, 199, 0.25); stroke-width: 1; }
.mnode.server rect { fill: rgba(127, 209, 199, 0.1); stroke: var(--you); stroke-width: 1.2; }
.mnode.server rect.inner { fill: var(--you); stroke: none; }
.mnode.intrusion path { fill: var(--hot); }
.mnode.intrusion .pulse { fill: none; stroke: var(--hot); stroke-width: 1; animation: mpulse 2s ease-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes mpulse { 0% { opacity: 0.8; transform: scale(0.8); } 100% { opacity: 0; transform: scale(2.6); } }
.no-motion .mnode .pulse, .no-motion .mnode .ring, .no-motion .mlink.hot { animation: none; }
.mnode.loc .ring { fill: none; stroke: rgba(241, 185, 47, 0.5); stroke-width: 1.2; animation: svpulse 3s ease-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes svpulse { 0% { opacity: 0.9; transform: scale(1); } 100% { opacity: 0; transform: scale(1.7); } }
.no-motion .mnode.loc .ring { animation: none; opacity: 0; } /* Motion off stills a new server's pulse too: its steady ring stays */
.marc-bg { fill: none; stroke: rgba(241, 185, 47, 0.14); stroke-width: 1.5; }
.marc { fill: none; stroke: var(--amber); stroke-width: 1.5; stroke-linecap: round; }
.mnode.loc.done .mlabel { fill: var(--muted); }
/* An invasion: a spiked virus. Amber on its way, red once it's at your wall; a breach pulses rings. */
.mnode.invader .vbody { fill: var(--hot); stroke: #ffb3a3; stroke-width: 0.6; }
.mnode.invader .vcore { fill: #1a0a06; }
.mnode.invader.travel .vbody { fill: rgba(241, 185, 47, 0.25); stroke: var(--amber); stroke-width: 1.2; }
.mnode.invader.travel .vcore { fill: var(--amber); }
.mnode.invader .vring { fill: none; stroke: none; }
.mnode.invader.breach .vring { stroke: var(--hot); stroke-width: 1.5; transform-box: fill-box; transform-origin: center; animation: vring 1.6s ease-out infinite; }
.mnode.invader.breach .vbody { animation: vthrob 1.6s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes vring { 0% { transform: scale(0.6); opacity: 0.9; } 100% { transform: scale(2.4); opacity: 0; } }
@keyframes vthrob { 50% { transform: scale(1.15); } }
@media (prefers-reduced-motion: reduce) { .mnode.invader.breach .vring, .mnode.invader.breach .vbody { animation: none; } .mnode.invader.breach .vring { opacity: 0.6; } }
/* The pager's lamp on a breach: one ring fires out of it (app.js). */
.led-ring { position: fixed; width: 12px; height: 12px; margin: -6px 0 0 -6px; border: 2px solid var(--hot); border-radius: 50%; pointer-events: none; z-index: 60; animation: led-ring 0.9s ease-out forwards; }
@keyframes led-ring { from { transform: scale(1); opacity: 1; } to { transform: scale(5); opacity: 0; } }
.marc-bg.lead { stroke: rgba(241, 185, 47, 0.14); stroke-dasharray: 1 3; }
.marc.lead { stroke: var(--muted); }
.mnode:not(.loc):focus-visible rect:first-of-type { stroke: var(--bright); }
details summary { font-size: 13px; }

/* ---------- feedback (see feel.mjs) ---------- */
.fx-float { --size: 1; --dx: 0px; position: fixed; z-index: 50; pointer-events: none; font: 700 calc(18px * var(--size)) var(--mono); animation: fx-rise 1s ease-out forwards; text-shadow: 0 0 8px rgba(0, 0, 0, 0.9); }
.fx-float.still { animation: fx-fade 1s ease-out forwards; }
.fx-float.amber { color: var(--next); } .fx-float.hot { color: var(--hot); } .fx-float.you { color: var(--you); } .fx-float.bright { color: var(--bright); }
/* WoW-style level colors: red far above you, orange above, yellow about even, green below, grey too low to matter. */
.con-red { color: #ff5b3d; } .con-orange { color: #ff9a3d; } .con-yellow { color: #f1d02f; } .con-green { color: #7fd67a; } .con-gray { color: #8a8174; }
.fx-float.dim { color: var(--muted); font-size: 16px; letter-spacing: 2px; }
.fx-float.crit { color: #ffe27a; font-size: calc(24px * var(--size)); letter-spacing: 1px; text-shadow: 0 0 12px rgba(255, 216, 92, 0.7), 0 0 8px rgba(0, 0, 0, 0.9); }
.fx-float.big { font-size: calc(22px * var(--size)); }
@keyframes fx-rise { 0% { opacity: 1; transform: translate(0, 0) scale(1.7); } 14% { transform: translate(calc(var(--dx) * 0.4), -8px) scale(0.92); } 24% { transform: translate(calc(var(--dx) * 0.5), -12px) scale(1); } 70% { opacity: 1; } 100% { opacity: 0; transform: translate(var(--dx), -44px) scale(0.95); } }
@keyframes fx-fade { from { opacity: 1; } to { opacity: 0; } }
#fx-edge { position: fixed; inset: 0; pointer-events: none; z-index: 40; box-shadow: inset 0 0 0 0 rgba(255, 91, 61, 0); }
#fx-edge.on { animation: fx-edge 0.6s ease-out; }
@keyframes fx-edge { 0% { box-shadow: inset 0 0 60px 12px rgba(255, 91, 61, 0.45); } 100% { box-shadow: inset 0 0 0 0 rgba(255, 91, 61, 0); } }
.fx-hit { animation: fx-hit 0.35s ease-out; }
@keyframes fx-hit { 0% { background: rgba(255, 216, 92, 0.28); } 100% { background: transparent; } }
.fx-break { animation: fx-break 0.6s ease-out; }
@keyframes fx-break { 0% { background: rgba(255, 242, 200, 0.35); } 100% { background: transparent; } }
.fx-hurt { animation: fx-hurt 0.45s ease-out; }
@keyframes fx-hurt { 0% { background: rgba(255, 91, 61, 0.3); } 100% { background: transparent; } } /* a flash, never a shake (docs/ui.md, Screen effects) */
.fx-still { animation: fx-still 0.45s ease-out; }
@keyframes fx-still { 0% { background: rgba(255, 91, 61, 0.3); } 100% { background: transparent; } }
.fx-tick .bigbar { animation: fx-tick 0.3s ease-out; }
@keyframes fx-tick { 0% { filter: brightness(1.8); } 100% { filter: none; } }
.fx-shove { animation: fx-shove 0.45s ease-out; }
@keyframes fx-shove { 0% { background: rgba(127, 209, 199, 0.25); } 100% { background: transparent; } }
.fx-enrage { animation: fx-enrage 0.6s ease-out; }
@keyframes fx-enrage { 0% { box-shadow: inset 4px 0 0 var(--hot), inset 0 0 24px rgba(255, 91, 61, 0.25); } 100% { box-shadow: none; } }
.fx-nope { animation: fx-nope 0.3s ease-out; }
@keyframes fx-nope { 25%, 75% { border-color: var(--hot); box-shadow: 0 0 0 1px var(--hot); } }
.fx-urgent { animation: fx-urgent 0.5s ease-in-out 3; }
@keyframes fx-urgent { 50% { background: rgba(255, 91, 61, 0.35); color: var(--bright); } }
.fx-cycle .cyclebar { animation: fx-tick 0.25s ease-out; }
.fx-strike { animation: fx-strike 0.5s ease-out; }
@keyframes fx-strike { 0% { box-shadow: inset 3px 0 0 var(--hot), inset 0 0 26px rgba(255, 91, 61, 0.35); } 100% { box-shadow: inset 0 0 0 transparent, inset 0 0 0 transparent; } }
.fx-float.atk { color: var(--hot); font-size: calc(12px * var(--size)); letter-spacing: 2px; opacity: 0.9; }
.fx-mark { animation: fx-mark 0.55s ease-out; }
@keyframes fx-mark { 0% { background: rgba(127, 209, 199, 0.3); box-shadow: inset 0 0 0 1px rgba(127, 209, 199, 0.8); } 100% { background: transparent; box-shadow: inset 0 0 0 1px transparent; } }
.fx-burn { animation: fx-burn 0.55s ease-out; }
@keyframes fx-burn { 0% { background: rgba(255, 140, 61, 0.3); } 100% { background: transparent; } }
.fx-float.mark { color: var(--you); font-size: calc(14px * var(--size)); letter-spacing: 2px; }
.fx-float.burn { color: #ff8c3d; font-size: calc(14px * var(--size)); letter-spacing: 2px; }
.fx-float.helper { color: var(--daemon); font-size: calc(14px * var(--size)); letter-spacing: 2px; }
/* Damage numbers, one per source (dmgfx.mjs): the kind's icon beside the number, in the kind's colour.
   On a part: your hit and Spike amber, a crit gold and bigger (.crit above), a burn orange, a helper or daemon
   violet, damage turned back teal; on you (.at-you): the virus's red, a shield or a heal teal. */
.fx-float.src { display: inline-flex; align-items: center; gap: 0.18em; white-space: nowrap; }
.fx-float .fx-ico { width: 0.82em; height: 0.82em; margin: 0; stroke-width: 1.9; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.95)); }
.fx-float.k-crit .fx-ico { width: 0.95em; height: 0.95em; stroke-width: 1.6; }
.fx-float.k-hit, .fx-float.k-spike { color: var(--next); }
.fx-float.k-spike .fx-ico { color: var(--bright); }
.fx-float.k-burn { color: #ff8c3d; text-shadow: 0 0 8px rgba(255, 140, 61, 0.55), 0 0 8px rgba(0, 0, 0, 0.9); }
.fx-float.k-helper { color: var(--daemon); }
.fx-float.k-reflect, .fx-float.k-interrupt, .fx-float.k-shield, .fx-float.k-heal { color: var(--you); }
.fx-float.k-interrupt { font-size: calc(15px * var(--size)); letter-spacing: 2px; }
.fx-float.at-you { color: var(--hot); }
.fx-float.at-you.k-shield, .fx-float.at-you.k-heal { color: var(--you); }
.fx-float.at-you.k-crit { color: #ff7a52; font-size: calc(24px * var(--size)); text-shadow: 0 0 12px rgba(255, 91, 61, 0.75), 0 0 8px rgba(0, 0, 0, 0.9); }
.fx-float.at-you.k-spike .fx-ico, .fx-float.at-you.k-crit .fx-ico { color: #fff2c8; }
.fx-float.hostile { color: var(--hot); }
/* A virus attack lashing at your screen (lash.mjs): its characters whip into your Signal bar, 1s and 0s burst
   off it and fall, the screen glitches. Above the board, under the numbers; never takes input. */
#lash { position: fixed; inset: 0; z-index: 46; pointer-events: none; overflow: hidden; }
.lash-ch, .lash-bit, .lash-lock { position: absolute; opacity: 0; transform: translate(-50%, -50%); pointer-events: none; font: 700 14px/1 var(--mono); }
.lash-ch { color: color-mix(in srgb, var(--hot) calc(var(--t) * 100%), var(--amber)); text-shadow: 0 0 6px rgba(255, 91, 61, 0.8), 0 0 2px rgba(0, 0, 0, 0.9); animation: lash-ch var(--life, 380ms) cubic-bezier(.2, .7, .3, 1) forwards; }
.lash-ch.lash-head { color: var(--bright); font-size: 16px; text-shadow: 0 0 8px var(--hot), 0 0 3px #fff; }
.lash-ch.heavy { font-size: 17px; color: color-mix(in srgb, #fff2c8 calc(var(--t) * 100%), var(--hot)); text-shadow: 0 0 10px rgba(255, 91, 61, 1), 0 0 2px rgba(0, 0, 0, 0.9); }
.lash-ch.enc { color: color-mix(in srgb, var(--hot) calc(var(--t) * 100%), var(--next)); font-size: 12px; letter-spacing: 1px; }
@keyframes lash-ch { 0% { opacity: 0; transform: translate(-50%, -50%) scale(1.7); } 10% { opacity: 1; transform: translate(-50%, -50%) scale(1.15); } 55% { opacity: 0.9; } 100% { opacity: 0; transform: translate(calc(-50% + var(--jx)), calc(-50% + var(--jy))) scale(0.8); } }
.lash-bit { color: var(--hot); text-shadow: 0 0 6px rgba(255, 91, 61, 0.9); animation: lash-bit var(--d, 600ms) cubic-bezier(.2, .6, .4, 1) forwards; }
.lash-bit.heavy { color: var(--bright); font-size: 16px; text-shadow: 0 0 8px var(--hot), 0 0 2px #fff; }
@keyframes lash-bit { 0% { opacity: 1; transform: translate(-50%, -50%) scale(1.5); } 40% { opacity: 1; transform: translate(calc(-50% + var(--tx) * 0.7), calc(-50% + var(--ty))) scale(1); } 100% { opacity: 0; transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty) + var(--fall))) scale(0.8); } }
.lash-rain { position: absolute; opacity: 0; font: 600 12px/1.05 var(--mono); color: var(--hot); text-align: center; text-shadow: 0 0 4px rgba(255, 91, 61, 0.7); animation: lash-rain 600ms linear forwards; }
@keyframes lash-rain { 0% { opacity: 0; transform: translateY(-16px); } 15% { opacity: 0.7; } 100% { opacity: 0; transform: translateY(var(--fall)); } }
.lash-glitch { position: absolute; inset: 0; opacity: 0; background: repeating-linear-gradient(to bottom, rgba(255, 91, 61, 0.08) 0 1px, transparent 1px 3px); animation: lash-glitch var(--g, 300ms) steps(5) forwards; }
.lash-glitch.heavy { background: repeating-linear-gradient(to bottom, rgba(255, 91, 61, 0.13) 0 1px, transparent 1px 3px), radial-gradient(ellipse 80% 70% at 50% 50%, transparent 55%, rgba(255, 91, 61, 0.22)); }
.lash-glitch i { position: absolute; left: 0; right: 0; background: linear-gradient(90deg, transparent, rgba(255, 91, 61, 0.32) 18%, rgba(127, 209, 199, 0.2) 50%, rgba(255, 91, 61, 0.32) 82%, transparent); mix-blend-mode: screen; transform: translateX(var(--tx)); }
@keyframes lash-glitch { 0% { opacity: 1; transform: translateX(-3px); } 20% { transform: translateX(4px); } 40% { opacity: 0.85; transform: translateX(-2px); } 70% { opacity: 0.5; transform: none; } 100% { opacity: 0; } }
.lash-lock { color: var(--next); font-size: 12px; letter-spacing: 1px; text-shadow: 0 0 6px rgba(255, 216, 92, 0.7), 0 0 2px rgba(0, 0, 0, 0.9); animation: lash-lock var(--life, 520ms) ease-out forwards; }
.lash-lock.shut { color: var(--hot); text-shadow: 0 0 8px rgba(255, 91, 61, 0.9); }
.lash-lock .glyph { width: 18px; height: 18px; margin: 0; stroke-width: 2; }
@keyframes lash-lock { 0% { opacity: 0; transform: translate(-50%, -110%); } 15% { opacity: 1; transform: translate(-50%, -50%); } 75% { opacity: 1; } 100% { opacity: 0; transform: translate(-50%, -30%); } }
/* Where it lands: your bar splits its colours and jitters; encryption hatches it for a moment. */
.hud-bar.mine .bigbar.fx-lashed { animation: fx-lashed 0.42s steps(6) forwards; }
@keyframes fx-lashed { 0% { box-shadow: -4px 0 0 rgba(255, 91, 61, 0.85), 4px 0 0 rgba(127, 209, 199, 0.6); filter: brightness(1.9); } 35% { box-shadow: 3px 0 0 rgba(255, 91, 61, 0.7), -3px 0 0 rgba(127, 209, 199, 0.5); } 70% { filter: brightness(1.2); } 100% { box-shadow: none; filter: none; } }
.hud-bar.mine .bigbar.fx-locked { animation: fx-locked 0.42s ease-out forwards; }
@keyframes fx-locked { 0% { box-shadow: inset 0 0 0 1px var(--hot); background-image: repeating-linear-gradient(-45deg, rgba(255, 91, 61, 0.35) 0 2px, transparent 2px 5px); } 100% { box-shadow: none; background-image: none; } }
/* Effects minimal or Motion off: no lash, a soft edge. */
#fx-edge.soft.on { animation: fx-edge-soft 0.5s ease-out; }
@keyframes fx-edge-soft { 0% { box-shadow: inset 0 0 28px 3px rgba(255, 91, 61, 0.24); } 100% { box-shadow: inset 0 0 0 0 rgba(255, 91, 61, 0); } }
.no-motion #lash { display: none; }
/* Marks on a part: an icon each by its name; Exposed hatches the bar (it's open). */
.pmarks { display: inline-flex; gap: 3px; margin-left: 6px; vertical-align: middle; }
.pmark { display: inline-grid; place-items: center; width: 16px; height: 16px; border: 1px solid rgba(127, 209, 199, 0.55); border-radius: 3px; color: var(--you); background: rgba(127, 209, 199, 0.1); animation: pmark-in 0.35s ease-out; }
.pmark .glyph { width: 11px; height: 11px; margin: 0; }
.pmark.m-burn { color: #ff8c3d; border-color: rgba(255, 140, 61, 0.55); background: rgba(255, 140, 61, 0.1); }
.pmark.m-helper { color: var(--daemon); border-color: rgba(195, 166, 255, 0.5); background: rgba(195, 166, 255, 0.1); }
.pmark.m-exposed { animation: pmark-in 0.35s ease-out, pmark-pulse 1.6s ease-in-out 0.35s infinite; }
@keyframes pmark-in { from { transform: scale(1.8); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes pmark-pulse { 50% { box-shadow: 0 0 6px rgba(127, 209, 199, 0.7); } }
.bpart.m-exposed .part-bar > span:first-child { background-image: repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.28) 0 3px, transparent 3px 7px); }
.bpart.m-exposed .part-bar { box-shadow: 0 0 0 1px rgba(127, 209, 199, 0.6); }
@media (prefers-reduced-motion: reduce) { .pmark, .pmark.m-exposed { animation: none; } }
body.no-motion .pmark, body.no-motion .pmark.m-exposed { animation: none; }
.fx-daemon { animation: fx-daemon 0.5s ease-out; }
@keyframes fx-daemon { 0% { background: rgba(195, 166, 255, 0.22); } 100% { background: transparent; } }
.fx-good { animation: fx-good 0.6s ease-out; }
@keyframes fx-good { 0% { background: rgba(127, 209, 199, 0.22); } 100% { background: transparent; } }
.fx-win { animation: fx-win 0.9s ease-out; }
@keyframes fx-win { 0% { box-shadow: 0 0 0 2px var(--bright), 0 0 40px rgba(255, 242, 200, 0.35); } 100% { box-shadow: none; } }

/* ---------- smaller screens ---------- */
@media (max-width: 1560px) {
  .toggles button:not(#speed) { display: none; }
}
@media (max-width: 1360px) {
  .hints { display: none; }
  .topbar { gap: 14px; }
  .meters { gap: 14px; }
  .meter-bar { width: 80px; }
  .modules button { padding: 6px 8px; }
  .virus-head h1 { font-size: 22px; }
}
@media (max-width: 1240px) and (min-width: 901px) {
  .brand-name { display: none; }
}
@media (max-width: 1440px) and (min-width: 901px) {
  .meter-integrity.noted .meter-label { display: none; }
  .topbar { gap: 10px; }
  .meters { gap: 10px; }
  .meter-bar { width: 56px; }
  .modules button { padding: 6px 6px; }
}
@media (max-height: 760px) and (min-width: 901px) {
  .workspace { padding: 8px 16px; }
  .bcell { padding: 5px 6px; }
  .mutation-rule { display: none; }
  .ability { height: 42px; }
}
@media (max-width: 900px) {
  .app { height: auto; min-height: calc(100dvh / var(--ui, 1)); }
  .topbar { flex-wrap: wrap; gap: 8px 14px; padding: 8px 12px; }
  .modules { order: 3; width: 100%; overflow-x: auto; }
  .meters { gap: 6px 14px; margin-left: 0; flex-wrap: wrap; width: 100%; }
  .meter strong { font-size: 14px; }
  .meter-bar { width: 70px; }
  .toggles { display: none; }
  .workspace { padding: 8px 12px; }
  .combat { display: flex; flex-direction: column; height: auto; }
  .combat > * { min-width: 0; }
  .hud { grid-template-columns: 1fr 1fr; gap: 12px; }
  .hud-id { grid-column: 1 / -1; }
  .brow { grid-template-columns: minmax(96px, 1.2fr) repeat(4, minmax(0, 1fr)); padding: 0 6px; }
  #board .brow { padding-left: var(--gut, 32px); }
  .bname small { display: none; }
  .intent:has(.code) b { display: none; } /* the code stands in for the name; a chip with no code (a cut) keeps its name */
  .intent .code { display: inline; }
  .intent.mine small { display: none; }
  .intent.raid b { display: block; white-space: normal; font-size: 10px; letter-spacing: 0.5px; } /* a tell or a crew boss's mechanic keeps its name: it's what you answer */
  .intent.tell .tl-what, .intent.tell .tl-when { display: none; }
  .intent.tell b { display: block; white-space: normal; font-size: 11px; }
  .bnow { grid-template-columns: 1fr !important; gap: 2px; }
  .bhead .countdown { font-size: 15px; }
  .hud-bar .bar-top { flex-wrap: wrap; }
  .stage { height: 160px; order: 5; }
  .log-lines { max-height: 220px; }
  .timeline-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); padding: 0 10px 10px; }
  .tcol { padding: 4px 4px 0; min-height: 90px; }
  .page-grid { grid-template-columns: minmax(0, 1fr); }
  .map-page { display: flex; flex-direction: column; height: auto; }
  .map-canvas { height: 440px; }
  .mlabel { font-size: calc(15px / var(--z, 1)); }
  .msub { font-size: calc(13px / var(--z, 1)); }
  .map-legend { font-size: 11px; }
  .net-head { flex-wrap: wrap; gap: 8px 14px; padding: 10px 12px; }
  .net-signal { margin-left: 0; }
  .sigbar { width: 120px; }
  .term { max-height: 60vh; font-size: 14px; padding: 6px 12px 12px; }
  .nextbtn.quiet { margin-left: 0; }
  .command-dock { position: sticky; bottom: 0; background: var(--bg); padding: 8px 12px; }
  .prompt:not(.run) span { display: none; }
  .prompt .p-loc { display: none; }
  .prompt.run { font-size: 12px; }
  .prompt:not(.run)::before { content: '$'; }
  .tray { grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ability { height: 44px; column-gap: 8px; padding: 0 8px 3px; }
  .ability .name { font-size: 13px; }
  .ability .cd { left: 8px; }
  .notice { max-width: 100%; left: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ticker span { animation: none; padding-left: 0; }
  * { transition: none !important; }
}

/* ---------- loadout: the class cards (the Skills and talents page is skills-view.mjs: the sk- block at the end) ---------- */
.loadout { display: grid; gap: 12px; }
.arch-tabs { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center; }
.arch { display: inline-flex; align-items: baseline; gap: var(--s4); min-width: 0; padding: 6px 12px; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--panel); color: var(--muted); cursor: pointer; }
.arch b { font: 600 12px var(--mono); letter-spacing: 1px; color: var(--text); }
.arch span { font: 500 11px var(--mono); }
.arch:hover { border-color: var(--line-strong); }
.arch.on { border-color: var(--amber); background: var(--panel-2); }
.arch.on b { color: var(--bright); }
.arch-inuse { align-self: center; width: 6px; height: 6px; border-radius: 50%; background: var(--you); box-shadow: 0 0 6px var(--you); }
.arch-use { margin-left: auto; }
.tag.you { color: var(--you); border-color: var(--you); }

.thead { display: flex; justify-content: space-between; align-items: end; gap: 12px; flex-wrap: wrap; }
.pips { display: flex; gap: 6px; }
.pip { width: 12px; height: 12px; border-radius: 50%; border: 1px solid var(--gray); }
.pip.free { border-color: var(--amber); box-shadow: 0 0 6px rgba(241, 185, 47, 0.5); }
.pip.spent { background: var(--you); border-color: var(--you); }

.kit { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.kit li { display: grid; grid-template-columns: 26px 1fr; gap: 10px; align-items: start; }
.kit kbd { font: 12px var(--mono); border: 1px solid var(--amber); color: var(--amber); border-radius: 3px; text-align: center; padding: 2px 0; }
.kit li.shared kbd { border-color: var(--line-strong); color: var(--muted); }
.kit b { color: var(--bright); }
.kit small { color: var(--muted); }
.preview-note { font-size: 12px; border-top: 1px solid var(--line); padding-top: 8px; }

/* small tags on rules */
.roles { display: flex; gap: 18px; flex-wrap: wrap; font-size: 13px; }
.roles b { color: var(--bright); font-weight: 600; margin-right: 4px; }
.tag.stag.spec { color: var(--amber); border-color: rgba(241, 185, 47, 0.5); }
.tag.stag { font-size: 10px; padding: 0 5px; }
.tag.stag.crew { color: var(--you); border-color: rgba(127, 209, 199, 0.5); }
.tag.stag.payoff { color: var(--next); border-color: rgba(255, 216, 92, 0.5); }
.tag.stag.status { color: var(--bright); border-color: var(--amber); background: rgba(241, 185, 47, 0.12); }
.tag.stag.run { color: var(--muted); border-color: var(--line-strong); }

/* a thin bar (the breach's Trace) */
.tbar { display: block; width: 160px; height: 6px; border: 1px solid var(--line-strong); border-radius: 3px; overflow: hidden; }
.tbar span { display: block; height: 100%; background: var(--you); }

/* ---------- the Now band ----------
   Each row's Now cell is one slice of a band down the whole board. The band is
   a faint tint (so text stays readable) with a thin playhead line that sweeps
   left to right as the cycle runs; the line and edges turn red in the last 1.5s
   when an attack is about to land. Span cells (armor notes, "type engage") only
   mark their first quarter, which is the Now column. */
.board { --elapsed: 0%; --band: rgba(240, 226, 182, 0.035); --band-line: var(--you); --band-edge: rgba(127, 209, 199, 0.35); }
.board.closing { --band-line: var(--hot); --band-edge: rgba(255, 91, 61, 0.55); }
.brow > .bcell:nth-child(2):not(.span5) {
  position: relative;
  background-color: var(--band);
  background-image: linear-gradient(var(--band-line), var(--band-line));
  background-repeat: no-repeat;
  background-size: 2px 100%;
  background-position: var(--elapsed) 0;
  box-shadow: inset 1px 0 0 var(--band-edge), inset -1px 0 0 var(--band-edge);
}
.brow > .bcell.span4:nth-child(2) { background-color: transparent; background-image: linear-gradient(var(--band), var(--band)), linear-gradient(var(--band-line), var(--band-line)); background-size: 25% 100%, 2px 100%; background-position: 0 0, calc(var(--elapsed) * 0.25) 0; box-shadow: inset 1px 0 0 var(--band-edge); }
.bhead .bnow .cyc { font: 500 11px var(--mono); color: var(--muted); letter-spacing: 0; text-transform: none; margin-left: 4px; }

/* cycle change: attacks slide in from the column to their right; the band flashes */
@keyframes slide-left { from { transform: translateX(var(--shift, 120px)); opacity: 0.35; } to { transform: none; opacity: 1; } }
@keyframes band-flash { from { opacity: 1; } to { opacity: 0; } } /* brief, then fully clear so it never sits on text */
.brow > .bcell:nth-child(2):not(.span5)::after { content: ''; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: rgba(127, 209, 199, 0.18); opacity: 0; pointer-events: none; }
.brow > .bcell.span4:nth-child(2)::after { right: 75%; }
/* Chips move with FLIP from app.js (turnTimeline); a resolved chip leaves a ghost that fires. */
.fx-ghost { position: fixed; z-index: 55; pointer-events: none; }
.fx-ghost > .intent { width: 100%; height: 100%; box-sizing: border-box; }
.board.shifted .brow > .bcell:nth-child(2):not(.span5)::after { animation: band-flash 0.45s ease-out; }
.no-motion .board.shifted .intent, .no-motion .board.shifted .bcell::after { animation: none !important; }
@media (prefers-reduced-motion: reduce) { .board.shifted .intent, .board.shifted .bcell::after { animation: none !important; } }
/* the header has its own countdown and bar: no playhead over the digits */
.brow.bhead > .bcell:nth-child(2):not(.span5) { background-image: none; }

/* ---------- levels ---------- */
.meter-level { min-width: 150px; }
.meter-level strong { font-size: 14px; }
.meter-level .meter-bar { width: 60px; }
.meter-level .meter-bar span { background: var(--you); }
.lvl-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lvl-badge { font: 600 13px var(--mono); color: var(--bright); border: 1px solid var(--you); color: var(--you); padding: 2px 8px; border-radius: 3px; }
.lvl-bar { flex: 1; min-width: 80px; max-width: 220px; height: 6px; border: 1px solid var(--line-strong); border-radius: 3px; overflow: hidden; }
.lvl-bar span { display: block; height: 100%; background: var(--you); }
.lvl-row small { font: 12px var(--mono); color: var(--muted); }
.lvl-note { font-size: 13px; }
.gate { color: var(--amber); font-weight: 500; }
.ability.ghost { border-style: dashed; opacity: 0.55; background: transparent; cursor: default; }
.ability.ghost .ico { background: var(--gray); }
.ability.ghost .name { color: var(--muted); font-weight: 400; }
.tag.stag.verb-hit { color: var(--amber); }
.tag.stag.verb-burn { color: var(--hot); border-color: rgba(255, 91, 61, 0.5); }
.tag.stag.verb-stun, .tag.stag.verb-debuff { color: var(--next); border-color: rgba(255, 216, 92, 0.5); }
.tag.stag.verb-shield, .tag.stag.verb-heal, .tag.stag.verb-buff { color: var(--you); border-color: rgba(127, 209, 199, 0.5); }
.tag.stag.verb-util, .tag.stag.verb-run { color: var(--muted); }
/* Gear. Rarity colors: Stock grey, Tuned green, Custom blue, Zero-day violet. */
:root { --r-scrap: #7d766a; --r-stock: #e8e0cc; --r-tuned: #6c9cff; --r-custom: #ffe14d; --r-zeroday: #d4a64a; --r-indemnified: #ff8a3d; --r-set: #b6cf55; } /* D2 colours: grey, white, blue, yellow, gold, orange; and D2's set green, warmed to the amber screen: a set's name, its lit pieces and its bonuses once on (docs/ui.md) */
.iname.r-scrap { color: var(--r-scrap); } .iname.r-stock { color: var(--r-stock); } .iname.r-tuned { color: var(--r-tuned); } .iname.r-custom { color: var(--r-custom); } .iname.r-zeroday { color: var(--r-zeroday); }
.iname.r-set { color: var(--r-set); } /* a set piece, whatever its rarity (gear.mjs shownRarity) */
.ptile small .neg { color: var(--hot); }
.gear-page .gnote { margin: 0 0 8px; color: var(--muted); font-size: 13px; }
.gslots, .gstash { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.gslot { display: grid; grid-template-columns: 84px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 7px 10px; border: 1px solid var(--line-strong); border-radius: 4px; background: var(--inset); }
.gslot-name { font: 600 12px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.gslot-item { display: grid; gap: 2px; min-width: 0; }
.gslot-item small, .gitem small { color: var(--text); font-size: 12px; }
.gslot-item.empty { color: var(--dim); font: 13px var(--mono); }
.gslot-item.empty small { color: var(--dim); }
.gtotals { margin: 8px 0 0; font: 12px var(--mono); color: var(--you); }
.gitem { display: flex; gap: 10px; align-items: center; justify-content: space-between; padding: 8px 10px; border: 1px solid var(--line-strong); border-left-width: 3px; border-radius: 4px; background: var(--inset); }
.gitem.r-scrap { border-left-color: var(--r-scrap); } .gitem.r-stock { border-left-color: var(--r-stock); } .gitem.r-tuned { border-left-color: var(--r-tuned); } .gitem.r-custom { border-left-color: var(--r-custom); } .gitem.r-zeroday { border-left-color: var(--r-zeroday); box-shadow: inset 0 0 18px rgba(212, 166, 74, 0.1); }
.gitem.r-set { border-left-color: var(--r-set); box-shadow: inset 0 0 18px rgba(182, 207, 85, 0.1); }
.gitem-main { display: grid; gap: 3px; min-width: 0; }
.gitem-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.gitem-actions { display: flex; gap: 6px; flex: none; }
.gitem .zd, .gslot .zd { color: var(--r-zeroday); }
.delta { font: 12px var(--mono); color: var(--muted) !important; }
.delta .up { color: var(--r-tuned); } .delta .down { color: var(--hot); }
.btn.small { padding: 4px 9px; font-size: 12px; }
/* Stat sheet: every stat a side can have, grouped; zeros dimmed. */
.sheet { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px 22px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.sheet-group h3 { margin: 0 0 6px; font: 600 12px var(--sans); letter-spacing: 1.5px; text-transform: uppercase; color: var(--amber); }
.sheet dl { margin: 0; display: grid; gap: 0; }
.sheet dl > div { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 4px 2px; font: 14px var(--sans); border-bottom: 1px dotted rgba(241, 185, 47, 0.12); cursor: help; }
.sheet dt { color: var(--bright); display: flex; align-items: center; gap: 6px; } .sheet dd { margin: 0; color: var(--you); font: 600 14px var(--mono); }
.sheet dl > div.zero dt, .sheet dl > div.zero dd { color: var(--muted); opacity: 0.7; }
.intent.cron { margin-top: 4px; padding: 2px 7px; font: 600 11px var(--mono); letter-spacing: 1px; }
.gslot.locked { opacity: 0.55; border-style: dashed; background: transparent; }
/* The wall (invasions) and Degraded mode. */
.wall-bar { height: 6px; border: 1px solid var(--line-strong); border-radius: 3px; background: var(--bg); overflow: hidden; }
.wall-bar span { display: block; height: 100%; background: var(--amber); transition: width 0.9s linear; }
.wall-bar.breach span { background: var(--hot); }
/* An invasion's warning line, what it pays, your streak (invasion.mjs). */
.inv-tell { margin: 4px 0; color: var(--text); font-size: 13px; line-height: 1.4; }
.inv-pay { margin: 4px 0; }
.inv-pay .rw b { font: 600 12px var(--mono); }
.wall-bar.watch span { background: var(--hot); }
.mnode.invader.watch .vbody { fill: rgba(255, 91, 61, 0.25); stroke: var(--hot); stroke-width: 1.2; }
.gstash .svc.off { opacity: 0.7; border-style: dashed; }
.degraded { display: flex; justify-content: space-between; align-items: center; margin: 8px 0; padding: 6px 10px; border: 1px solid var(--hot); border-radius: 4px; background: rgba(255, 91, 61, 0.08); font: 600 12px var(--mono); letter-spacing: 1px; cursor: help; }
.degraded b { color: var(--hot); }
.degraded span { color: var(--text); }
.degraded em { margin-left: auto; margin-right: 10px; font-style: normal; color: var(--hot); }
/* The wall's three bands: what it blocks, holds at a siege, and what breaks through. */
.bands { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin: 8px 0 4px; }
.band { padding: 5px 8px; border: 1px solid var(--line-strong); border-radius: 3px; font: 600 12px var(--mono); text-align: center; cursor: help; }
.band.blocked { color: var(--you); border-color: rgba(127, 209, 199, 0.45); }
.band.siege { color: var(--amber); border-color: rgba(241, 185, 47, 0.45); }
.band.breach { color: var(--hot); border-color: rgba(255, 91, 61, 0.45); }
.invader-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 8px; margin: 8px 0 4px; font-size: 13px; }
.invader-line span { font: 12px var(--mono); color: var(--amber); }
.invader-line.breach span { color: var(--hot); }
.syntax { cursor: help; }
.intent.mine.idle { color: var(--dim); border-style: dashed; justify-content: center; }
.meter-note { font: 600 10px var(--mono); letter-spacing: 1px; padding: 1px 5px; border-radius: 3px; border: 1px solid currentColor; white-space: nowrap; }
.meter-note.siege { color: var(--amber); }
.meter-note.breach, .meter-note.degraded { color: var(--hot); }
/* Services: one row per service; the install queue's progress bar. */
.svc { display: flex; gap: 10px; align-items: center; justify-content: space-between; padding: 8px 10px; border: 1px solid var(--line-strong); border-left-width: 3px; border-left-color: var(--line-strong); border-radius: 4px; background: var(--inset); }
.svc.on { border-left-color: var(--you); }
.svc.locked { opacity: 0.6; border-style: dashed; }
.svc-main { display: grid; gap: 3px; min-width: 0; flex: 1; }
.svc-main small { color: var(--text); font-size: 12px; }
.svc-name { color: var(--bright); }
.svc-next { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; justify-content: space-between; margin-top: 2px; }
.svc-next small { color: var(--muted); flex: 1 1 220px; }
.svc-next .btn { margin-left: auto; }
.install { display: grid; gap: 8px; }
.install-top { display: flex; justify-content: space-between; gap: 10px; font: 13px var(--mono); }
.install-top span { color: var(--amber); }
.install-bar { height: 8px; border: 1px solid var(--line-strong); border-radius: 4px; background: var(--inset); overflow: hidden; }
.install-bar span { display: block; height: 100%; background: var(--you); box-shadow: 0 0 10px rgba(127, 209, 199, 0.5); transition: width 0.9s linear; }
.svc-line { margin: 8px 0 0; font: 12px var(--mono); color: var(--muted); }
.svc-line .svc-prog { color: var(--dim); font-size: 11px; }
.op-hint { margin: 6px 0 0; font-size: 12px; line-height: 1.4; color: var(--muted); }
@media (max-width: 640px) { .svc { flex-direction: column; align-items: stretch; } .gslot { grid-template-columns: 70px minmax(0, 1fr); } .gslot .btn { grid-column: 2; justify-self: start; } .gitem { flex-direction: column; align-items: stretch; } }
/* First-time tips: one coach mark at a time, pointing at the thing it explains. */
.tip { position: fixed; z-index: 58; zoom: var(--ui, 1); width: min(320px, calc((100vw - 24px) / var(--ui, 1))); padding: 12px 14px 10px; background: var(--panel-2); border: 1px solid var(--you); border-radius: 6px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.55), 0 0 24px rgba(127, 209, 199, 0.14); font-size: 14px; color: var(--bright); }
.tip[hidden] { display: none; }
.tip p { margin: 0 0 10px; line-height: 1.45; }
.tip-step { color: var(--dim); font-size: 12px; margin-right: auto; font-variant-numeric: tabular-nums; }
.tip::before { content: ''; position: absolute; left: var(--arrow, 50%); top: -7px; width: 12px; height: 12px; background: var(--panel-2); border-left: 1px solid var(--you); border-top: 1px solid var(--you); transform: translateX(-50%) rotate(45deg); }
.tip.above::before { top: auto; bottom: -7px; transform: translateX(-50%) rotate(225deg); }
.tip-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 10px; }
.tip-off[hidden] { display: none; }
.tip-off { background: none; border: 0; color: var(--muted); font: 12px var(--mono); cursor: pointer; padding: 0; }
.tip-off:hover { color: var(--text); }
.tip.show { animation: tip-in 0.25s ease-out both; }
@keyframes tip-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.tip-target { outline: 2px solid var(--you); outline-offset: 3px; box-shadow: 0 0 18px rgba(127, 209, 199, 0.3); }
.mnode.tip-target, .fp-room.tip-target { outline: none; box-shadow: none; filter: drop-shadow(0 0 7px rgba(127, 209, 199, 0.9)); }
.no-motion .tip.show { animation: none; }
/* Victory: the fight's gains, until you close it. Under the CRT glass (z 70), over everything else. */
@media (max-width: 1440px) { .meter-level { min-width: 0; } .meter-level .meter-bar { width: 40px; } }

/* ---------- immersive shell (shell.mjs; body.shell-on) ----------
   A phosphor CRT around the same layout. Colour jobs don't change:
   the screen only warms toward red when YOUR health is low. */
.input-wrap { position: relative; flex: 1; min-width: 0; display: flex; overflow: hidden; }
.caret { display: none; position: absolute; left: 0; top: 50%; transform: translateY(-50%); pointer-events: none; font: 500 16px var(--mono); white-space: pre; line-height: 1; }
#caret-pad { visibility: hidden; }
.caret i { display: inline-block; width: 0.6em; height: 1.1em; vertical-align: -0.22em; background: var(--amber); opacity: 0.85; box-shadow: 0 0 8px rgba(241, 185, 47, 0.55); animation: caret-blink 1.06s steps(1) infinite; }
.caret.typing i { animation: none; }
@keyframes caret-blink { 50% { opacity: 0; } }
.shell-on #command-input { caret-color: transparent; }
.shell-on #command-form:focus-within .caret { display: block; }

/* the CRT itself: scanlines + vignette, a slow refresh band, faint moving grain */
#crt { position: fixed; inset: 0; pointer-events: none; z-index: 70; display: none; }
.shell-on #crt {
  display: block;
  background:
    repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.16) 0 1px, transparent 1px 3px),
    radial-gradient(ellipse 85% 80% at 50% 45%, transparent 62%, rgba(0, 0, 0, 0.5) 100%);
  transition: box-shadow 1.2s;
}
.shell-on #crt::before { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 22vh; background: linear-gradient(to bottom, transparent, rgba(255, 230, 160, 0.03) 60%, transparent); animation: crt-roll 11s linear infinite; }
.shell-on #crt::after {
  content: ''; position: absolute; inset: -50%; opacity: 0.045;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: crt-grain 0.5s steps(3) infinite;
}
@keyframes crt-roll { from { transform: translateY(-25vh); } to { transform: translateY(105vh); } }
@keyframes crt-grain { 0% { transform: translate(0, 0); } 33% { transform: translate(-7%, 4%); } 66% { transform: translate(5%, -6%); } 100% { transform: translate(0, 0); } }
/* your health, felt: screenfx.css (#crt-bezel.warn, .low), at the screen's very edge only. */

/* the tube: rounded corners and darker edges */
#crt-bezel { position: absolute; inset: 0; border-radius: 18px; box-shadow: 0 0 0 80px #020100, inset 0 0 40px rgba(0, 0, 0, 0.55); }
/* ---------- the monitor casing (desktop, immersive shell) ----------
   The screen sits in a dark plastic monitor. The bottom bezel carries a badge, two knobs (sound,
   speed) and labelled lamps that show real state: power, the gate, the wall, a run, an install,
   daemons. Lamps glow steady; nothing blinks. */
#casing { display: none; }
/* The window behind the monitor (window.mjs): always out of the page flow; only shown when the monitor is. */
.window-out { position: fixed; inset: 0; width: 100vw; height: 100dvh; z-index: -1; pointer-events: none; display: none; }
@media (min-width: 1100px) and (min-height: 720px) {
  /* The monitor is as wide as the screen inside it (at most 1800px of picture) and sits centered on
     the desk, so on a wide display the frame hugs the picture instead of the window edges. */
  body.cased { --side: max(26px, 1.2vw); --top: 22px; --chin: 52px; --desk: 0px; box-sizing: border-box; height: 100dvh; overflow: hidden; padding: var(--top) var(--side) calc(var(--chin) + var(--desk)); background: radial-gradient(120% 90% at 50% 40%, var(--case-hi, #2a2724), var(--case-mid, #181614) 70%, var(--case-lo, #0e0d0c)); } /* the plastic: casing.css colourways set these */
  body.cased::before { content: ''; position: fixed; top: calc(var(--top) - 14px); bottom: calc(var(--desk) + 8px); left: calc(var(--side) - 18px); right: calc(var(--side) - 18px); border-radius: 26px; pointer-events: none; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), inset 0 -2px 0 rgba(0, 0, 0, 0.6), 0 0 0 8px var(--case-rim, #0b0a09); }
  body.cased .app { height: calc((100dvh - var(--top) - var(--chin) - var(--desk)) / var(--ui, 1)); max-width: none; position: relative; overflow: hidden; border-radius: 18px; background: var(--bg) url('ui/textures/grime-overlay-subtle.png'); box-shadow: 0 0 0 2px #000, 0 0 30px 6px rgba(241, 185, 47, 0.08); }
  body.cased #crt, body.cased .boot, body.cased #fx-edge, body.cased .poweron, body.cased .class-pick { inset: var(--top) var(--side) calc(var(--chin) + var(--desk)); border-radius: 18px; overflow: hidden; }
  body.cased .class-pick { overflow-y: auto; } /* it scrolls on a short screen, inside the glass */
  body.cased .class-pick::after { display: none; } /* the tube's own scanlines (#crt) cover it now */
  body.cased #crt-bezel { border-radius: 18px; box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.65), inset 0 0 6px rgba(0, 0, 0, 0.9); }
  body.cased #casing { display: flex; position: fixed; left: calc(var(--side) + 20px); right: calc(var(--side) + 20px); bottom: var(--desk); height: var(--chin); align-items: center; justify-content: space-between; z-index: 57; pointer-events: none; font: 600 9px var(--mono); letter-spacing: 2px; color: var(--case-ink, #5b554d); }
  body.cased #casing .knob, body.cased #casing .lamp { pointer-events: auto; }
  /* The knobs are the sound and speed controls here; the header keeps only what the casing lacks. */
  body.cased .toggles #sound, body.cased .toggles #speed { display: none; }
  /* The window: the monitor sits a little further in so the slum shows either side (window.mjs). */
  .window-out { display: block; }
}
#casing .badge { position: absolute; left: 50%; transform: translateX(-50%); font: 700 11px var(--mono); letter-spacing: 6px; color: var(--case-badge, #6b655c); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.07), 0 -1px 0 rgba(0, 0, 0, 0.8); pointer-events: none; }
#casing .knobs { display: flex; gap: 10px; }
.knob { width: 18px; height: 18px; padding: 0; border-radius: 50%; border: 0; background: radial-gradient(circle at 35% 35%, var(--case-knob-hi, #3a3632), var(--case-knob-lo, #151312)); box-shadow: 0 1px 2px #000, inset 0 0 0 1px rgba(255, 255, 255, 0.04); position: relative; transition: transform 0.25s ease-out; }
.knob i { position: absolute; left: 50%; top: 2px; width: 2px; height: 6px; margin-left: -1px; border-radius: 1px; background: #6b655c; }
.knob.on i { background: var(--amber); box-shadow: 0 0 4px rgba(241, 185, 47, 0.7); }
.knob:hover { border: 0; filter: brightness(1.2); }
#casing .lamps { display: flex; gap: 14px; align-items: center; }
.lamp { display: flex; align-items: center; gap: 5px; }
.lamp i { width: 8px; height: 8px; border-radius: 50%; background: radial-gradient(circle at 40% 35%, #4a4540, #1a1816); box-shadow: inset 0 0 0 1px #0c0b0a; transition: background 0.4s, box-shadow 0.4s; }
.lamp.on i { background: radial-gradient(circle at 40% 35%, #ffe7a0, #f1b92f 45%, #7e5311); box-shadow: 0 0 8px 2px rgba(241, 185, 47, 0.55); }
.lamp.low i { background: radial-gradient(circle at 40% 35%, #b98d2a, #6e5214 60%, #3a2c0c); box-shadow: 0 0 4px 1px rgba(241, 185, 47, 0.25); }
.lamp.hot i { background: radial-gradient(circle at 40% 35%, #ffc2b0, #ff5b3d 45%, #7a1d0d); box-shadow: 0 0 8px 2px rgba(255, 91, 61, 0.55); }
.lamp.you i { background: radial-gradient(circle at 40% 35%, #d8fff9, #7fd1c7 45%, #245f58); box-shadow: 0 0 8px 2px rgba(127, 209, 199, 0.45); }
.lamp.on, .lamp.hot, .lamp.you { color: var(--case-ink-on, #8a8378); }
/* new terminal lines type themselves in */
.shell-on li.typed { animation: type-in 0.3s steps(16, end) both; }
@keyframes type-in { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
/* on a run the net pane sits at the top of the page: leave room for its title */
.shell-on .page:has(> .net-one) { padding-top: 8px; }

/* module change: one bright line sweeps down, the page comes up */
#crt-sweep { position: absolute; left: 0; right: 0; top: 0; height: 2px; background: rgba(255, 242, 200, 0.55); box-shadow: 0 0 18px 4px rgba(241, 185, 47, 0.25); opacity: 0; }
#crt-sweep.go { animation: crt-sweep 0.32s ease-in; }
@keyframes crt-sweep { 0% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(100vh); } }
.shell-on .workspace.refresh { animation: crt-refresh 0.32s ease-out; }
@keyframes crt-refresh { 0% { opacity: 0.25; filter: brightness(1.8) blur(1px); } 100% { opacity: 1; filter: none; } }

/* power-on after the boot: the picture opens from a line */
.shell-on .app.power-on { animation: crt-on 0.42s cubic-bezier(0.2, 0.7, 0.2, 1); transform-origin: 50% 50%; }
@keyframes crt-on { 0% { transform: scale(1, 0.004); filter: brightness(4); } 55% { transform: scale(1, 1.02); filter: brightness(1.6); } 100% { transform: none; filter: none; } }

/* hits: a tear across the backdrop (screenfx.css), never the screen itself */

/* phosphor: bright text glows a little in its own colour */
.shell-on .brand-name, .shell-on .meter strong, .shell-on .prompt, .shell-on #command-input, .shell-on .card h1, .shell-on .hud-id h1,
.shell-on .hud-num, .shell-on .net-signal strong, .shell-on .term, .shell-on .log-lines, .shell-on .ability .name, .shell-on .modules button[aria-current='page'] {
  text-shadow: 0 0 7px color-mix(in srgb, currentColor 38%, transparent);
}

/* glass: panels catch a little light from the top, and wear corner brackets */
.shell-on .panel, .shell-on .card { position: relative; background-image: radial-gradient(130% 70% at 50% 0%, rgba(241, 185, 47, 0.04), transparent 65%); }
.shell-on .panel::after, .shell-on .card::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; border-radius: inherit; opacity: 0.6;
  --c: var(--amber-soft);
  background:
    linear-gradient(var(--c), var(--c)) top left / 9px 1px no-repeat, linear-gradient(var(--c), var(--c)) top left / 1px 9px no-repeat,
    linear-gradient(var(--c), var(--c)) top right / 9px 1px no-repeat, linear-gradient(var(--c), var(--c)) top right / 1px 9px no-repeat,
    linear-gradient(var(--c), var(--c)) bottom left / 9px 1px no-repeat, linear-gradient(var(--c), var(--c)) bottom left / 1px 9px no-repeat,
    linear-gradient(var(--c), var(--c)) bottom right / 9px 1px no-repeat, linear-gradient(var(--c), var(--c)) bottom right / 1px 9px no-repeat;
}
/* window titles on the panes */
.shell-on .panel[data-pane]::before { content: '[ ' attr(data-pane) ' ]'; position: absolute; top: -7px; right: 14px; z-index: 2; padding: 0 6px; font: 500 10px/13px var(--mono); letter-spacing: 1px; color: var(--dim); background: var(--bg); pointer-events: none; }
.shell-on.in-fight .hud[data-pane]::before { color: var(--amber-soft); }
.shell-on .net-one[data-pane]::before { color: var(--you); opacity: 0.8; }

/* the dock reads as a terminal line */
.shell-on #command-form { background: linear-gradient(to bottom, rgba(241, 185, 47, 0.05), transparent 70%), var(--inset); }

/* status line (tmux-ish), desktop only */
.statusline { display: flex; align-items: center; gap: 14px; padding: 3px 20px 5px; font: 11px/16px var(--mono); color: var(--dim); white-space: nowrap; overflow: hidden; border-top: 1px solid var(--line); }
.statusline .sl-host { color: var(--amber); letter-spacing: 1px; }
.statusline .sl-where { overflow: hidden; text-overflow: ellipsis; color: var(--muted); }
.statusline .sl-alert { color: var(--next); font-weight: 600; animation: sl-pulse 1.6s ease-in-out infinite; }
.statusline .sl-you { color: var(--you); font-weight: 600; }
.statusline .sl-right { margin-left: auto; display: flex; gap: 14px; }
.statusline .sl-spark { color: var(--amber-deep); letter-spacing: -1px; }
.shell-on.in-fight .statusline .sl-spark { color: var(--amber-soft); }
.statusline .sl-clock { color: var(--muted); }
@keyframes sl-pulse { 50% { opacity: 0.55; } }

/* boot screen */
.boot { position: fixed; inset: 0; z-index: 65; background: #050302; display: flex; flex-direction: column; justify-content: center; padding: 8vh 10vw; transition: opacity 0.35s; }
.boot.out { opacity: 0; }
.boot pre { margin: 0; max-height: none; overflow: visible; font: 15px/1.7 var(--mono); color: var(--muted); text-shadow: 0 0 8px rgba(241, 185, 47, 0.35); white-space: pre-wrap; }
.boot pre .b { color: var(--bright); letter-spacing: 2px; margin-bottom: 8px; }
.boot pre .h { color: var(--hot); }
.boot pre .y { color: var(--you); }
.boot pre div:last-child::after { content: '█'; color: var(--amber); margin-left: 4px; animation: caret-blink 1.06s steps(1) infinite; }
.boot small { position: absolute; right: 24px; bottom: 18px; font: 11px var(--mono); color: var(--dim); }

/* stillness: Motion off (or the OS asks for less motion) keeps the CRT but stops everything moving */
.no-motion #crt::before, .no-motion #crt::after, .no-motion .statusline .sl-alert, .no-motion .caret i, .no-motion li.typed { animation: none !important; }
@media (prefers-reduced-motion: reduce) { #crt::before, #crt::after, .statusline .sl-alert, .caret i, .workspace.refresh, li.typed { animation: none !important; } }
@media (max-width: 900px) {
  .statusline { display: none !important; }
  .shell-on .panel[data-pane]::before { display: none; }
  .shell-on #crt { background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.12) 0 1px, transparent 1px 3px), radial-gradient(ellipse 90% 85% at 50% 45%, transparent 65%, rgba(0, 0, 0, 0.45) 100%); }
  .boot { padding: 6vh 6vw; }
  #crt-bezel { border-radius: 12px; }
  .boot pre { font-size: 12px; }
}
/* The Now header: "Now" over "cycle N" on the left, the seconds on the right, never wrapping. */
.bhead .bnow > span:first-child { display: flex; flex-direction: column; gap: 1px; white-space: nowrap; line-height: 1.15; }
.bhead .bnow .cyc { margin-left: 0; }
.bhead .bnow .countdown { white-space: nowrap; align-self: center; }
/* A hit's burst in the part's Now cell. */
/* Protocols as compact tiles: slots in a grid, the stash in a grid, no full-width bars. */
.ptiles { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 8px; }
.ptiles.stash { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.ptile { position: relative; display: grid; gap: 3px; align-content: start; min-height: 64px; padding: 8px 10px; background: var(--inset); border: 1px solid var(--line-strong); border-radius: 4px; }
.ptile small { color: var(--muted); font-size: 12px; line-height: 1.35; }
.ptile.empty, .ptile.locked { border-style: dashed; background: none; }
/* A hub's Shop (view.mjs shopMarkup): the shelf, the chase line on its tier rail, tools and codebases, one shape everywhere. */
.shop { display: grid; gap: 10px; }
.shop-h { display: flex; justify-content: space-between; align-items: center; margin: 6px 0 0; padding-bottom: 5px; border-bottom: 1px solid var(--line); font: 600 11px var(--mono); letter-spacing: 1.5px; text-transform: uppercase; color: var(--muted); }
.shop-h:first-child { margin-top: 0; }
.shop-clock { display: inline-flex; gap: 4px; align-items: center; font: 500 11px var(--mono); letter-spacing: 0; text-transform: none; }
.shop .glyph { flex: none; }
.shop .price { display: inline-flex; gap: 3px; align-items: center; }
.shop .price .glyph, .shop-clock .glyph, .shop-imp .glyph { width: 12px; height: 12px; }
.shop-shelf { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.shop-imp { display: inline-flex; gap: 3px; align-items: center; color: var(--fc); font-size: 12px; }
.ptile.sold { opacity: 0.45; border-style: dashed; background: none; }
.shop-rail { display: grid; gap: 10px; }
.shop-rail .ptiles { grid-template-columns: repeat(var(--n, 1), minmax(0, 1fr)); }
.shop-tier { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.shop-tier small { font: 500 11px var(--mono); color: var(--muted); letter-spacing: 1px; text-transform: uppercase; }
.shop-col.shut .shop-tier small { color: var(--dim); }
.shop-tools { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.shop-tool { display: grid; grid-template-columns: auto 1fr auto; grid-template-areas: 'g n n' 'g p b'; gap: 2px 8px; align-items: center; padding: 6px 8px; background: var(--inset); border: 1px solid var(--line-strong); border-radius: 4px; font-size: 12px; }
.shop-tool > .glyph { grid-area: g; }
.shop-tool > b { grid-area: n; font-weight: 500; }
.shop-tool > .price { grid-area: p; }
.shop-tool > .btn, .shop-tool > .rpips { grid-area: b; justify-self: end; }
.shop-tool .price { color: var(--muted); }
@media (max-width: 720px) { .shop-shelf { grid-template-columns: repeat(2, minmax(0, 1fr)); } .shop-rail { grid-template-columns: 1fr !important; } }
.ptile.locked { opacity: 0.5; }
.ptile-slot { font: 600 10px var(--mono); color: var(--dim); letter-spacing: 1px; }
.ptile-empty { font: 12px var(--mono); color: var(--dim); }
.ptile.r-scrap { opacity: 0.85; }
.ptile.r-tuned { border-color: rgba(108, 156, 255, 0.5); }
.ptile.r-custom { border-color: rgba(255, 225, 77, 0.6); }
.ptile.r-zeroday { border-color: rgba(212, 166, 74, 0.75); box-shadow: inset 0 0 18px rgba(212, 166, 74, 0.1); }
.ptile.r-set { border-color: rgba(182, 207, 85, 0.75); box-shadow: inset 0 0 18px rgba(182, 207, 85, 0.1); }
.ptile.r-indemnified { border-color: rgba(255, 138, 61, 0.65); }
.ptile-x { position: absolute; top: 4px; right: 4px; width: 22px; height: 22px; padding: 0; border: 0; background: none; color: var(--muted); font-size: 16px; line-height: 1; cursor: pointer; }
.ptile-x:hover { color: var(--bright); }
.ptile-acts { display: flex; gap: 6px; margin-top: 4px; flex-wrap: wrap; }
.ptile .tag { justify-self: start; }
.ptile.on { border-color: rgba(78, 222, 200, 0.45); }
/* The fight's name line stays one line: name, level, family, then any tags, clipped if tight. */
.hud-id { flex-wrap: nowrap; white-space: nowrap; overflow: hidden; }
.hud-id > * { flex-shrink: 0; }
.hud-id .tag { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* A lit proc key: it glows while its window is open. */
.ability.lit { border-color: var(--gold, #ffd85c); box-shadow: 0 0 0 1px rgba(255, 216, 92, 0.6), 0 0 16px rgba(255, 216, 92, 0.45); animation: lit-pulse 1.2s ease-in-out infinite; }
@keyframes lit-pulse { 50% { box-shadow: 0 0 0 1px rgba(255, 216, 92, 0.9), 0 0 24px rgba(255, 216, 92, 0.65); } }
.no-motion .ability.lit { animation: none; }
/* A situational key whose moment is on the board (situations.mjs): an amber edge; the moment is in its tooltip. */
.ability.moment { border-color: rgba(241, 185, 47, 0.75); box-shadow: inset 0 0 0 1px rgba(241, 185, 47, 0.35); }
/* A key a landed tell knocked offline (tells.mjs). */
.ability.offline { border-color: rgba(255, 92, 92, 0.6); }
/* A part left Open by a tell you read: +50% from everyone. */
.pmark.m-open { color: #ffd85c; border-color: rgba(255, 216, 92, 0.6); background: rgba(255, 216, 92, 0.12); }
.mhit { fill: transparent; stroke: none; pointer-events: all; }
.mnode text { pointer-events: all; }
/* The rogue server on the map, and live viruses in its folders. */
.mnode.zone path { fill: rgba(241, 185, 47, 0.08); stroke: var(--amber); stroke-width: 1.3; }
.mnode.zone .zdot { fill: var(--hot); animation: zblink 1.6s ease-in-out infinite; }
.mnode.zone.here path { stroke: var(--you); fill: rgba(127, 209, 199, 0.15); }
@keyframes zblink { 50% { opacity: 0.25; } }
.no-motion .mnode.zone .zdot { animation: none; }
.tok.virus { color: var(--hot); font-weight: 600; }

/* ---------- mail ---------- */
.mnode.loc.job .msub { fill: var(--next); }
.mail-page { grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); }
.standing { display: flex; align-items: center; gap: 8px; }
.standing .st-name { font: 600 13px var(--mono); color: var(--bright); letter-spacing: 0.5px; }
.standing .lvl-bar { max-width: none; }
.standing .lvl-bar span { background: var(--amber); }
.standing b { font: 600 13px var(--mono); color: var(--bright); font-variant-numeric: tabular-nums; }
.mlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.mrow { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto; column-gap: 8px; text-align: left; padding: 8px 10px; background: var(--inset); border: 1px solid transparent; border-radius: 3px; color: var(--muted); font: 13px var(--sans); cursor: pointer; }
.mrow:hover { border-color: var(--line); }
.mrow.open { border-color: var(--line-strong); background: rgba(241, 185, 47, 0.06); }
.mrow .mfrom { font: 11px var(--mono); letter-spacing: 0.5px; color: var(--dim); }
.mrow .msubj { grid-column: 1; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mrow .tag { grid-column: 2; grid-row: 1 / 3; align-self: center; }
.mrow.unread .msubj { color: var(--bright); font-weight: 600; }
.mrow.unread .mfrom::before { content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--amber); margin-right: 6px; vertical-align: middle; }
.mread .mbody { display: grid; gap: 8px; max-width: 62ch; }
.mread .mbody p { margin: 0; line-height: 1.5; color: var(--text); }
.contract { display: grid; gap: 8px; padding: 12px 14px; border: 1px solid var(--line-strong); border-left: 3px solid var(--amber); border-radius: 3px; background: var(--inset); }
.contract.ready { border-left-color: var(--you); }
.contract.done { border-left-color: var(--gray); opacity: 0.75; }
.contract .c-head { display: flex; align-items: center; gap: 8px; color: var(--bright); }
.contract .lvl-row { display: flex; align-items: center; gap: 10px; }
.contract .lvl-row small { color: var(--muted); font-size: 12px; }
.contract.ready .lvl-bar span { background: var(--you); }
@media (max-width: 900px) { .mail-page { grid-template-columns: 1fr; } }
.modules .count.new { background: var(--you); }
.modules .count { display: inline-block; min-width: 16px; padding: 0 4px; margin-left: 6px; border-radius: 8px; background: var(--amber); color: var(--bg); font: 600 10px/16px var(--mono); text-align: center; vertical-align: middle; }
.mnode.hidden .qmark { fill: var(--muted); font: 600 13px var(--mono); }
.mnode.hidden .marc-bg.lead { stroke: rgba(241, 185, 47, 0.3); }
.mnode.hidden .mhit + * { opacity: 0.7; }
.mnode.hidden.job .qmark { fill: var(--next); }
.mnode.hidden.job .mlabel { fill: var(--next); }
.sigbars { font-family: var(--mono); color: var(--amber); letter-spacing: 1px; }
.mlist.mboard .mexp, .c-exp { margin-left: auto; font: 11px var(--mono); color: var(--dim); grid-column: 2; grid-row: 1 / 3; align-self: center; }
.c-exp { grid-column: auto; }
.mail-page .inbox h2 { margin-top: 4px; }
.contract.offer { border-left-color: var(--line-strong); }
.store-page { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.store-page .stack { display: grid; gap: 12px; align-content: start; }
.store-page .ptile .price { font: 600 12px var(--mono); color: var(--bright); margin-right: auto; }
.store-page .ptile .price i { font-style: normal; font-size: 10px; }
.store-page .ptile .price i.up { color: var(--hot); }
.store-page .ptile .price i.down { color: var(--you); }
.store-page .ptile .qty { font: 11px var(--mono); color: var(--dim); margin-right: 8px; }
.store-page .ptile .agency { font: 10px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--dim); }
.store-page .ptile.locked { opacity: 0.55; }
.store-page .ptile.chase { border-color: rgba(195, 166, 255, 0.35); }
.iname.r-indemnified, .r-indemnified { color: var(--r-indemnified); }
@media (max-width: 900px) { .store-page { grid-template-columns: 1fr; } }

/* ---------- the pager and Comms ---------- */
/* The pager itself (the tray: a lamp and one icon per page) is in pager.css. */
.pager { margin-left: auto; }
.pager + .meters { margin-left: -6px; }
.pager.fx-pager { animation: pagerbuzz 0.4s linear; }
@keyframes pagerblink { 50% { opacity: 0.25; } }
@keyframes pagerbuzz { 15%, 55% { box-shadow: 0 0 10px rgba(241, 185, 47, 0.55); } 35%, 75% { box-shadow: none; } }
.no-motion .pager.fx-pager { animation: none; }
.comms { position: absolute; top: 52px; right: 20px; z-index: 60; width: 360px; max-width: calc(100% - 24px); max-height: min(70vh, 560px); display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--line-strong); border-radius: 4px; box-shadow: 0 14px 34px rgba(0, 0, 0, 0.65); }
.app { position: relative; }
.comms-head { display: flex; justify-content: space-between; align-items: center; padding: 10px 12px; border-bottom: 1px solid var(--line); font: 600 11px var(--sans); letter-spacing: 1.5px; text-transform: uppercase; color: var(--muted); }
.comms-filters { display: flex; flex-wrap: wrap; gap: 4px; padding: 7px 12px; border-bottom: 1px solid var(--line); }
.comms-filters button { font: 11px var(--mono); background: none; color: var(--dim); border: 1px solid var(--line); border-radius: 2px; padding: 1px 7px; cursor: pointer; }
.comms-filters button[aria-pressed='true'] { color: var(--amber); border-color: var(--amber); }
.comms-list { list-style: none; margin: 0; padding: 0; overflow: auto; }
.comms .k { font: 600 9px var(--mono); letter-spacing: 1.2px; text-transform: uppercase; padding: 1px 5px; border: 1px solid currentColor; border-radius: 2px; white-space: nowrap; }
.comms .k.offer { color: var(--amber); } .comms .k.mail { color: var(--bright); } .comms .k.ready { color: var(--you); } .comms .k.paid { color: var(--next); }
.comms .k .glyph, .sb-alerts .k .glyph { width: 10px; height: 10px; margin: 0 4px 0 0; vertical-align: -1px; } /* an event's card icon (event-cards.mjs) */
.comms .k.net { color: var(--daemon); } .comms .k.alert { color: var(--hot); } .comms .k.store { color: var(--muted); } .comms .k.standing { color: var(--you); }
.comms .act { font: 600 11px var(--mono); color: var(--amber); background: none; border: 0; padding: 0; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.comms .quiet { padding: 12px; }
@media (max-width: 1300px) and (min-width: 901px) { .modules button { padding: 6px 4px; } }
@media (max-width: 900px) { .comms { top: 96px; right: 12px; } }


/* Outposts */
.mnode.loc.locked .ring { stroke-dasharray: 2 3; }
.mnode.cutoff { opacity: .45; }
@keyframes opblink { 50% { opacity: .2; } }
.outpost, .rack { border-top: 1px dashed var(--line); margin-top: 8px; padding-top: 6px; }
.outpost.besieged, .outpost.lost { border-top-color: var(--hot); }
@media (prefers-reduced-motion: reduce) { .mnode.besieged .sv-kind { animation: none; } }

/* Spoils: what a won fight gave you, over the virus picture */
.spoils { position: absolute; inset: 0; display: grid; place-items: center; padding: 14px; background: radial-gradient(ellipse at center, rgba(9, 6, 3, 0.55), rgba(9, 6, 3, 0.9)); pointer-events: none; animation: sp-fade 0.3s ease-out both; overflow: hidden; }
.spoils::after { content: ''; position: absolute; inset: 0; background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.18) 0 1px, transparent 1px 3px); pointer-events: none; }
.sp-card { position: relative; width: min(340px, 100%); max-height: 100%; overflow: hidden; padding: 14px 16px 12px; background: linear-gradient(180deg, rgba(20, 14, 6, 0.96), rgba(12, 8, 4, 0.96)); border: 1px solid var(--line-strong); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), 0 0 36px rgba(241, 185, 47, 0.12), inset 0 0 24px rgba(241, 185, 47, 0.05); font: 500 12px var(--mono); color: var(--text); animation: sp-boot 0.42s cubic-bezier(.2, .9, .3, 1.2) both; }
.sp-card::before { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 40%; background: linear-gradient(180deg, rgba(241, 185, 47, 0.07), transparent); pointer-events: none; }
.sp-corner { position: absolute; width: 9px; height: 9px; border: 2px solid var(--amber); }
.sp-corner.tl { left: -1px; top: -1px; border-right: 0; border-bottom: 0; } .sp-corner.tr { right: -1px; top: -1px; border-left: 0; border-bottom: 0; }
.sp-corner.bl { left: -1px; bottom: -1px; border-right: 0; border-top: 0; } .sp-corner.br { right: -1px; bottom: -1px; border-left: 0; border-top: 0; }
.sp-head { display: grid; gap: 2px; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px dashed var(--line); }
.sp-kicker { font-size: 10px; letter-spacing: 3px; text-transform: uppercase; color: var(--amber); }
.sp-name { font: 700 20px var(--mono); letter-spacing: 1px; color: var(--bright); text-shadow: 0 0 12px rgba(255, 216, 92, 0.35); }
.sp-meta { font-size: 11px; color: var(--muted); }
.sp-clean { font-style: normal; color: var(--you); }
.sp-ico { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linejoin: round; stroke-linecap: round; }
.sp-xp, .sp-level, .sp-row { display: flex; align-items: center; gap: 9px; opacity: 0; animation: sp-line 0.34s ease-out forwards; animation-delay: calc(var(--i) * 110ms + 260ms); }
.sp-xp { color: var(--next); margin-bottom: 8px; }
.sp-xp .sp-lbl { min-width: 38px; color: var(--muted); }
.sp-bar { position: relative; flex: 1; height: 6px; background: rgba(241, 185, 47, 0.08); border: 1px solid var(--line); overflow: hidden; }
.sp-bar .sp-was { position: absolute; inset: 0 auto 0 0; background: rgba(255, 216, 92, 0.35); }
.sp-bar .sp-now { position: absolute; inset: 0 auto 0 0; width: var(--to); background: var(--next); box-shadow: 0 0 8px var(--next); animation: sp-fill 0.9s cubic-bezier(.3, .7, .2, 1) both; animation-delay: 0.55s; }
.sp-bar.up .sp-now { background: var(--you); box-shadow: 0 0 8px var(--you); }
.sp-bar.lead { flex: none; display: block; width: 100%; height: 3px; margin-top: 3px; }
.sp-bar.lead .sp-now { background: var(--you); box-shadow: none; animation-delay: calc(var(--i, 1) * 110ms + 400ms); }
.sp-level { margin: 0 0 8px; padding: 6px 8px; border: 1px solid rgba(127, 209, 199, 0.4); background: rgba(127, 209, 199, 0.07); color: var(--you); font-weight: 700; letter-spacing: 1px; text-transform: uppercase; }
.sp-level small { margin-left: auto; font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--muted); }
.sp-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.sp-row { padding: 5px 8px 5px 6px; border-left: 2px solid var(--line); background: rgba(241, 185, 47, 0.03); }
.sp-row .sp-ico { color: var(--muted); }
.sp-row .sp-lbl { flex: 1; min-width: 0; display: grid; }
.sp-row .sp-t { overflow-wrap: anywhere; }
.sp-row small { font-size: 10px; color: var(--dim); line-height: 1.35; }
.sp-qty { font: 700 13px var(--mono); color: var(--bright); font-variant-numeric: tabular-nums; }
.sp-pack { font-size: 9px; letter-spacing: 1px; text-transform: uppercase; padding: 1px 4px; border: 1px solid var(--line-strong); color: var(--muted); }
.sp-row.k-code .sp-ico, .sp-row.k-loot .sp-ico { color: var(--amber-soft); }
.sp-row.k-exploit { border-left-color: var(--hot); } .sp-row.k-exploit .sp-ico { color: var(--hot); }
.sp-row.k-lead .sp-ico, .sp-row.k-found .sp-ico { color: var(--you); } .sp-row.k-found { color: var(--you); }
.sp-row.k-blueprint .sp-ico { color: var(--r-custom); } .sp-row.k-daemon .sp-ico { color: var(--daemon); }
.sp-row.k-item { background: rgba(241, 185, 47, 0.06); }
.sp-row.r-stock { border-left-color: var(--r-stock); } .sp-row.r-stock .sp-ico, .sp-row.r-stock .sp-t { color: var(--r-stock); }
.sp-row.r-tuned { border-left-color: var(--r-tuned); } .sp-row.r-tuned .sp-ico, .sp-row.r-tuned .sp-t { color: var(--r-tuned); }
.sp-row.r-custom { border-left-color: var(--r-custom); } .sp-row.r-custom .sp-ico, .sp-row.r-custom .sp-t { color: var(--r-custom); }
.sp-row.r-zeroday, .sp-row.r-indemnified { border-left-color: var(--r-zeroday); box-shadow: inset 0 0 14px rgba(196, 155, 255, 0.12); } .sp-row.r-zeroday .sp-ico, .sp-row.r-zeroday .sp-t, .sp-row.r-indemnified .sp-ico, .sp-row.r-indemnified .sp-t { color: var(--r-zeroday); }
.sp-row.r-set { border-left-color: var(--r-set); } .sp-row.r-set .sp-ico, .sp-row.r-set .sp-t { color: var(--r-set); }
@keyframes sp-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sp-boot { 0% { opacity: 0; transform: scaleY(0.02) scaleX(0.6); filter: brightness(3); } 45% { opacity: 1; transform: scaleY(0.02) scaleX(1); } 100% { transform: none; filter: none; } }
@keyframes sp-line { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: none; } }
@keyframes sp-fill { from { width: var(--from); } to { width: var(--to); } }
@media (prefers-reduced-motion: reduce) { .spoils, .sp-card, .sp-xp, .sp-level, .sp-row, .sp-bar .sp-now { animation: none; opacity: 1; } }
body.no-motion .spoils, body.no-motion .sp-card, body.no-motion .sp-xp, body.no-motion .sp-level, body.no-motion .sp-row, body.no-motion .sp-bar .sp-now { animation: none; opacity: 1; }
/* Run and Fight tabs add width: tighten the tabs. */
@media (min-width: 1301px) { .ctx-tabs .modules button { padding-left: 7px; padding-right: 7px; } }

/* ---------- juice: hits, shattered shields, hurts ---------- */
/* The chunk of health that just went: white, then it drains away. */
.fx-trail { position: fixed; z-index: 45; pointer-events: none; background: #fff2c8; box-shadow: 0 0 10px rgba(255, 242, 200, 0.8); transform-origin: left center; animation: fx-trail 0.8s cubic-bezier(.5, 0, .3, 1) forwards; }
.fx-trail.mine { background: #ffd0c4; box-shadow: 0 0 12px rgba(255, 91, 61, 0.9); }
@keyframes fx-trail { 0%, 30% { opacity: 1; transform: scaleX(1); } 100% { opacity: 0.6; transform: scaleX(0); } }
/* A punch on the virus picture. */
.virus-stage.fx-punch canvas { animation: fx-punch 0.22s cubic-bezier(.3, 1.6, .5, 1); } /* the picture, not its frame or the words over it */
.virus-stage.fx-punch::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: radial-gradient(circle at 50% 50%, rgba(255, 242, 200, calc(0.22 * var(--punch, 1))), transparent 60%); animation: fx-fade 0.25s ease-out forwards; }
@keyframes fx-punch { 0% { transform: scale(calc(1 - 0.018 * var(--punch, 1))) translateX(calc(3px * var(--punch, 1))); } 45% { transform: scale(calc(1 + 0.01 * var(--punch, 1))) translateX(calc(-2px * var(--punch, 1))); } 100% { transform: none; } }
/* Sparks off the part you hit. */
.fx-spark { position: fixed; z-index: 53; width: 3px; height: 3px; margin: -1.5px 0 0 -1.5px; background: var(--next); box-shadow: 0 0 6px var(--next); pointer-events: none; animation: fx-spark 0.55s cubic-bezier(.1, .7, .3, 1) forwards; }
.fx-spark.crit { background: #fff2c8; box-shadow: 0 0 8px #ffe27a; width: 4px; height: 4px; }
@keyframes fx-spark { 0% { transform: translate(0, 0); opacity: 1; } 100% { transform: translate(var(--tx), var(--ty)); opacity: 0; } }
/* A shield chit shatters. */
.fx-shard { position: fixed; z-index: 55; pointer-events: none; font: 700 13px var(--mono); color: #fff2c8; text-shadow: 0 0 6px var(--amber), 0 0 2px #fff; transform: translate(-50%, -50%); animation: fx-shard 0.75s cubic-bezier(.15, .6, .4, 1) forwards; }
@keyframes fx-shard { 0% { opacity: 1; transform: translate(-50%, -50%) scale(1.3); } 100% { opacity: 0; transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) rotate(var(--rot)) scale(0.6); } }
.fx-crackring { position: fixed; z-index: 54; width: 8px; height: 8px; margin: -4px 0 0 -4px; pointer-events: none; transform: rotate(45deg); border: 2px solid #fff2c8; box-shadow: 0 0 14px var(--amber); animation: fx-crackring 0.45s ease-out forwards; }
@keyframes fx-crackring { 0% { opacity: 1; transform: rotate(45deg) scale(0.6); } 100% { opacity: 0; transform: rotate(45deg) scale(5); } }
.brow.fx-crack { position: relative; }
.brow.fx-crack::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(100deg, transparent 30%, rgba(255, 242, 200, 0.55) 48%, rgba(255, 242, 200, 0.9) 50%, rgba(255, 242, 200, 0.55) 52%, transparent 70%); background-size: 250% 100%; animation: fx-crack 0.4s ease-out forwards; }
@keyframes fx-crack { from { background-position: 120% 0; opacity: 1; } to { background-position: -40% 0; opacity: 0; } }
.no-motion .fx-trail, .no-motion .fx-spark, .no-motion .fx-shard, .no-motion .fx-crackring { display: none; }


.sp-card { pointer-events: auto; }
.sp-go { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; margin-top: 10px; padding: 6px 10px; font: 500 11px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); background: transparent; border: 1px solid var(--line); border-radius: 2px; cursor: pointer; opacity: 0; animation: sp-line 0.34s ease-out forwards; animation-delay: calc(var(--i) * 110ms + 360ms); transition: color 0.15s, border-color 0.15s; }
.sp-go:hover, .sp-go:focus-visible { color: var(--amber); border-color: var(--line-strong); outline: none; }
.sp-go kbd { font: 500 9px var(--mono); letter-spacing: 0; padding: 0 4px; color: var(--dim); border: 1px solid var(--line); border-radius: 2px; }
@media (prefers-reduced-motion: reduce) { .sp-go { animation: none; opacity: 1; } }
body.no-motion .sp-go { animation: none; opacity: 1; }
.btn.buyout { color: var(--amber); border-color: rgba(241, 185, 47, 0.5); } .btn.buyout .glyph { margin-right: 4px; }
.install.mini .btn.buyout { margin-top: 6px; }
.mnode.detached { opacity: 0.38; } .mnode.detached .ring { stroke-dasharray: 2 2; }
.btn.mem-x { margin-left: auto; color: var(--muted); }
/* Factions: their colour (--fc) on their hub, their servers, their icons */
.fmark-i { display: inline-flex; color: var(--fc); vertical-align: -2px; } .fmark-i .glyph { margin: 0 3px 0 0; }
.fmark-i.big .glyph { width: 22px; height: 22px; margin-right: 8px; vertical-align: -3px; }
.mnode.hub .hub-frame { fill: rgba(9, 6, 3, 0.85); stroke: var(--fc); stroke-width: 1.6; }
.mnode.hub .hub-mark { color: var(--fc); fill: none; stroke: var(--fc); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.mnode.hub .mlabel { fill: var(--fc); }
.mnode.hub.hostile { opacity: 0.55; } .mnode.hub.hostile .hub-frame { stroke-dasharray: 3 2; }
.mnode.loc.fowned .ring { stroke: var(--fc); }
.mnode .fmark { fill: none; stroke: var(--fc); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.fcard { border-top: 2px solid var(--fc); } .fcard h1 { color: var(--fc); display: flex; align-items: center; }
.repbar { display: flex; align-items: center; gap: 3px; margin: 8px 0; }
/* Rep: four pips, one a tier (factions.mjs), lit to where you stand. */
.rpips { display: inline-flex; gap: 3px; vertical-align: middle; }
.rpips i { width: 10px; height: 7px; border: 1px solid color-mix(in srgb, var(--fc) 55%, transparent); background: rgba(0, 0, 0, 0.3); }
.rpips i.on { background: var(--fc); box-shadow: 0 0 5px color-mix(in srgb, var(--fc) 45%, transparent); }
.rep-chip .rpips i { width: 6px; height: 6px; }
.standing .rpips { margin-left: auto; }
.frel { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; font-size: 11px; color: var(--muted); }
.frel-k { text-transform: uppercase; letter-spacing: 1px; font-size: 10px; color: var(--dim); margin-left: 6px; } .frel-k:first-child { margin-left: 0; }
.fline .fmark-i { margin-right: 2px; } .fline b { color: var(--fc); margin-right: 4px; }
.fline { display: flex; align-items: center; gap: 4px; cursor: help; } .fl-reps { display: inline-flex; gap: 4px; margin-left: auto; } .fl-rep { cursor: help; padding: 1px 6px; } /* a server's owner and the standing taking it moves (view.mjs ownerLine) */
.reps { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 10px; }
.rep-chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border: 1px solid color-mix(in srgb, var(--fc) 50%, transparent); border-radius: 3px; background: transparent; color: var(--fc); font: 500 11px var(--mono); cursor: pointer; }
.rep-chip .glyph { margin: 0; }
.hub-page .craft-list li.locked { opacity: 0.55; }
.mrow .fmark-i { margin-left: auto; }
/* A contract row: whose job it is, as a mark down the left edge; the rest moves over one column. */
.mrow.has-f { grid-template-columns: auto minmax(0, 1fr) auto; }
.mrow.has-f .mrow-f { grid-column: 1; grid-row: 1 / 3; align-self: center; margin: 0 2px 0 0; }
.mrow .mrow-none { display: inline-block; width: 17px; }
.mrow.has-f .mfrom, .mrow.has-f .msubj { grid-column: 2; }
.mrow.has-f .tag, .mrow.has-f .mexp { grid-column: 3; }
/* The codex: ??? until broken */
.part-name { position: relative; }
.part-name .unk { margin-left: 3px; font-size: 10px; color: var(--dim); }
/* A part researched to 100% (research.mjs): a small amber star by its name, never teal (teal is you). */
.pmast { display: inline-flex; vertical-align: -1px; margin-left: 4px; color: var(--amber-soft); cursor: help; }
.pmast .glyph { width: 11px; height: 11px; margin: 0; }
.pexe { color: var(--hot); cursor: help; }
.codex { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.cx-group b { display: block; font: 600 12px var(--mono); letter-spacing: 1px; color: var(--muted); margin-bottom: 4px; text-transform: uppercase; }
.cx-group ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.cx-group li { display: grid; font-size: 12px; } .cx-group li span { color: var(--dim); } .cx-group li small { color: var(--dim); }
.cx-group li.on span { color: var(--bright); } .cx-group li.on small { color: var(--muted); }
/* The sidebar: on every page, fights included */
body.with-sidebar .workspace { display: grid; grid-template-columns: 270px minmax(0, 1fr); gap: 12px; }
body.with-sidebar .workspace > .combat, body.with-sidebar .workspace > .page { grid-column: 2; grid-row: 1; min-height: 0; }
.sidebar { grid-column: 1; grid-row: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.sb-block { padding: 12px 14px; border: 1px solid var(--line); background: var(--panel); display: grid; gap: 8px; }
.sb-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.sb-head b { font: 600 13px var(--mono); letter-spacing: 1px; color: var(--bright); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sb-head small { color: var(--muted); font-size: 11px; white-space: nowrap; }
.sb-bar { display: flex; align-items: center; gap: 6px; color: var(--you); font-variant-numeric: tabular-nums; }
.sb-bar .glyph { margin: 0; width: 14px; height: 14px; }
.sb-track { flex: 1; height: 7px; border: 1px solid currentColor; background: rgba(0, 0, 0, 0.3); } .sb-track span { display: block; height: 100%; background: currentColor; }
.sb-bar b { font: 600 13px var(--mono); } .sb-bar small { color: var(--muted); font-size: 11px; }
.sb-bar.mid { color: var(--next); } .sb-bar.low { color: var(--hot); }
.sb-bar.vir { color: var(--hot); }
.sidebar .sb-crew .party { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; }
.sidebar .sb-crew .pmate { border-left: 0; padding-left: 0; margin: 0; }
.sb-crew .pmate { display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; padding: 6px 0 0; border-top: 1px solid var(--line); }
.sb-crew .pmate:first-child { border-top: 0; padding-top: 0; }
.sb-crew .pmate .pbar { grid-column: 1 / -1; }
.sb-crew .pm-cls { color: var(--muted); font-size: 11px; }
.sb-crew .pm-tag { grid-column: 1 / -1; justify-self: start; }
.pm-intent { grid-column: 1 / -1; display: flex; align-items: center; gap: 5px; margin-top: 2px; padding: 4px 6px; border: 1px dashed var(--line); font: 500 12px var(--mono); color: var(--amber); }
.pm-intent .glyph { margin: 0; width: 13px; height: 13px; }
.pm-intent b { font-weight: 600; } .pm-intent .pm-at { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .pm-intent small { margin-left: auto; color: var(--dim); }
.pm-intent.verb-burn { color: #ff8c3d; } .pm-intent.verb-debuff, .pm-intent.verb-stun { color: var(--you); } .pm-intent.verb-heal, .pm-intent.verb-shield, .pm-intent.verb-buff { color: var(--next); } .pm-intent.verb-util { color: var(--daemon); }
.pm-intent.dim { color: var(--dim); }
.sb-crew .pmate.acting .pm-intent { border-style: solid; border-color: currentColor; background: rgba(241, 185, 47, 0.08); }
.sb-crew.solo button { justify-self: start; }
.sb-note { color: var(--muted); font: 11px var(--mono); }
.sb-select { display: grid; gap: 10px; }
.sb-select .card { margin: 0; }
.sb-select .card h1 { font-size: 18px; overflow-wrap: anywhere; }
.sb-select .stats { grid-template-columns: 1fr 1fr; }
.sb-alerts ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.sb-alerts button { display: block; width: 100%; text-align: left; white-space: normal; font-size: 12px; line-height: 1.35; }
.sb-alerts .k { margin-right: 6px; }
.map-page.no-side { grid-template-columns: minmax(0, 1fr); }
/* the crew column shows at every width */
/* Slots as pips; the wall as a level ruler; the map's server card */
.slots { display: inline-flex; align-items: center; gap: 3px; font: 500 11px var(--mono); color: var(--muted); vertical-align: middle; }
.slots .glyph { width: 14px; height: 14px; margin-right: 4px; color: var(--amber); }
.slots i { width: 9px; height: 9px; border: 1px solid var(--line-strong); border-radius: 2px; }
.slots i.on { background: var(--amber); border-color: var(--amber); box-shadow: 0 0 5px rgba(241, 185, 47, 0.4); }
.slots small { margin-left: 5px; font-size: 11px; }
h1 .slots { font-size: 13px; } h1 .slots i { width: 13px; height: 13px; } h1 .slots .glyph { width: 18px; height: 18px; }
.wall-ruler { position: relative; margin: 10px 0 6px; padding-bottom: 30px; }
.wall-ruler.compact { flex: 1; margin: 0; padding-bottom: 0; }
.wr-track { position: relative; height: 22px; border: 1px solid var(--line); background: rgba(0, 0, 0, 0.3); overflow: hidden; }
.wall-ruler.compact .wr-track { height: 8px; }
.wr-seg { position: absolute; top: 0; bottom: 0; display: grid; place-items: center; }
.wr-seg .glyph { width: 13px; height: 13px; margin: 0; }
.wr-seg.blocked { background: rgba(127, 209, 199, 0.28); color: var(--you); }
.wr-seg.siege { background: rgba(241, 185, 47, 0.25); color: var(--amber); }
.wr-seg.breach { background: repeating-linear-gradient(-45deg, rgba(255, 91, 61, 0.28) 0 4px, rgba(255, 91, 61, 0.14) 4px 8px); color: var(--hot); }
.wr-marks { position: absolute; left: 0; right: 0; top: 0; height: 22px; pointer-events: none; }
.wall-ruler.compact .wr-marks { height: 8px; }
.wr-mark { position: absolute; top: -3px; bottom: -3px; width: 0; }
.wr-mark i { position: absolute; left: -1px; top: 0; bottom: 0; width: 2px; background: var(--bright); }
.wr-mark small { position: absolute; top: calc(100% + 2px); left: 0; transform: translateX(-50%); white-space: nowrap; font: 500 10px var(--mono); color: var(--bright); }
.wall-ruler.compact .wr-mark small { display: none; }
.wr-mark.inv i { background: var(--hot); box-shadow: 0 0 6px var(--hot); } .wr-mark.inv small { color: var(--hot); top: calc(100% + 14px); }
.wr-scale { position: absolute; left: 0; right: 0; top: 24px; height: 12px; font: 10px var(--mono); color: var(--dim); }
.wr-scale span { position: absolute; transform: translateX(-50%); }
.wall-ruler.down { padding: 6px 10px; border: 1px dashed var(--hot); color: var(--hot); font: 11px var(--mono); }
.srv-card .lvl-row { margin-bottom: 10px; }
.srv-hp { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; color: var(--you); }
.srv-hp .glyph { margin: 0; width: 16px; height: 16px; }
.srv-bar { flex: 1; height: 10px; border: 1px solid var(--you); background: rgba(0, 0, 0, 0.3); } .srv-bar span { display: block; height: 100%; background: var(--you); }
.srv-hp b { font: 600 18px var(--mono); } .srv-hp small { color: var(--muted); }
.srv-hp.mid { color: var(--next); } .srv-hp.mid .srv-bar { border-color: var(--next); } .srv-hp.mid .srv-bar span { background: var(--next); }
.srv-hp.low { color: var(--hot); } .srv-hp.low .srv-bar { border-color: var(--hot); } .srv-hp.low .srv-bar span { background: var(--hot); }
.srv-chips { display: flex; gap: 18px; margin-bottom: 12px; }
.srv-chips span { display: inline-flex; align-items: center; gap: 2px; color: var(--muted); } .srv-chips .glyph { color: var(--amber); } .srv-chips b { font: 600 15px var(--mono); color: var(--bright); }
.srv-wall { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.srv-k { display: inline-flex; align-items: center; font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); min-width: 62px; }
.srv-slots { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 12px; }
.install.mini { margin-bottom: 10px; }
/* Have/need chips (a hub's donation and payloads) */
.craft-sub { font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--muted); margin: 14px 0 6px; }
.needs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.need { display: inline-flex; align-items: center; gap: 2px; padding: 1px 6px; border: 1px solid var(--line); border-radius: 3px; font: 500 11px var(--mono); color: var(--muted); font-variant-numeric: tabular-nums; }
.need .glyph { margin-right: 3px; }
.need b { color: var(--text); font-weight: 600; }
.need.ok { border-color: rgba(127, 209, 199, 0.35); } .need.ok .glyph { color: var(--you); }
.need.short { border-color: rgba(255, 91, 61, 0.5); color: var(--hot); } .need.short b { color: var(--hot); }
/* Consortium: members on one grid, the dividend as a table */
.con-members { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 10px auto auto auto auto auto minmax(0, 1fr) auto auto; column-gap: 12px; row-gap: 2px; }
.con-member { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: center; padding: 7px 8px; border-left: 2px solid transparent; background: rgba(241, 185, 47, 0.03); }
.con-member.crew { border-left-color: var(--you); background: rgba(127, 209, 199, 0.06); }
.con-member.off { opacity: 0.7; }
.cm-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--gray); } .cm-dot.on { background: var(--you); box-shadow: 0 0 6px var(--you); }
.cm-name { display: flex; align-items: center; gap: 6px; min-width: 0; } .cm-name b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .cm-name small { color: var(--amber); }
.cm-crew { color: var(--you); display: inline-flex; } .cm-crew .glyph { margin: 0; }
.cm-cls { color: var(--muted); font-size: 12px; white-space: nowrap; } .cm-cls b { color: var(--text); }
.cm-n { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cm-where { justify-self: start; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
.con-member .p-acts { justify-self: end; }
@media (max-width: 900px) { .con-members { grid-template-columns: 10px 1fr auto; } .con-member { grid-template-columns: subgrid; } .cm-cls, .cm-n, .cm-state { display: none; } .cm-where, .cm-net { grid-column: 2 / -1; } .con-member .p-acts { grid-column: 3; grid-row: 1; } }
.div-table { width: 100%; border-collapse: collapse; font-size: 12px; margin: 4px 0 10px; }
.div-table th { text-align: left; font-weight: 500; color: var(--dim); text-transform: uppercase; letter-spacing: 1px; font-size: 10px; padding: 0 6px 4px; border-bottom: 1px solid var(--line); }
.div-table td { padding: 5px 6px; border-bottom: 1px dashed rgba(241, 185, 47, 0.1); white-space: nowrap; }
.div-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.div-table tr.stopped td { color: var(--dim); }
.div-fill { display: inline-block; vertical-align: middle; width: 54px; height: 5px; margin-right: 6px; background: rgba(241, 185, 47, 0.1); border: 1px solid var(--line); } .div-fill span { display: block; height: 100%; background: var(--you); }
/* Gain card: Pulled (a toast that fades) and Banked (waits for Enter), the spoils card's look */
.gain { position: absolute; inset: 0; z-index: 40; display: grid; place-items: center; padding: 14px; background: radial-gradient(ellipse at center, rgba(9, 6, 3, 0.5), rgba(9, 6, 3, 0.85)); animation: sp-fade 0.3s ease-out both; }
.gain .sp-card { width: min(320px, 100%); max-height: calc(100% - 28px); overflow: auto; }
.gain.toast { inset: 64px 20px auto auto; padding: 0; background: none; pointer-events: none; transition: opacity 0.4s, transform 0.4s; }
.gain.toast .sp-card { width: 250px; max-height: none; overflow: hidden; padding: 10px 12px 8px; }
.gain.toast .sp-head { padding-bottom: 6px; margin-bottom: 6px; }
.gain.toast.out { opacity: 0; transform: translateY(-6px); }
.sp-row.k-fast { border-left-color: var(--bright); background: linear-gradient(90deg, rgba(255, 216, 92, 0.14), rgba(255, 216, 92, 0.02)); } .sp-row.k-fast .sp-ico, .sp-row.k-fast .sp-t { color: var(--bright); }
.sp-row.k-credits .sp-ico { color: var(--amber); } .sp-row.k-credits .sp-qty { color: var(--amber); }
@media (max-width: 640px) { .gain.toast { inset: 56px 16px auto 16px; } .gain.toast .sp-card { width: 100%; } }

/* The fight is won: the timeline and the ability bar step aside for the spoils. */
body.fight-over #board, body.fight-over #tray { display: none; }
body.fight-over .combat { grid-template-rows: auto minmax(0, 1fr); grid-template-areas: 'hud hud' 'log stage'; }

/* The run's backdrop: faint falling binary in the margins beside the terminal (the panel is opaque). */
#page-view { position: relative; }
#page-view > .net-one { z-index: 1; }

/* ---------- first launch: login, then Halcyon's transmission ---------- */
/* The cold open (coldopen.mjs): KESSLER's clearing house, between the start screen and the login */
.coldopen { position: fixed; inset: 0; z-index: 70; background: #050302; padding: 8vh 5vw; box-sizing: border-box; overflow: hidden; transition: opacity 0.35s; }
.coldopen.out { opacity: 0; }
.co-screen { display: flex; gap: 32px; height: 100%; }
.co-log { flex: 1; min-width: 0; height: 100%; overflow: hidden; }
.co-log pre { margin: 0; max-height: none; overflow: visible; font: 15px/1.7 var(--mono); color: var(--muted); text-shadow: 0 0 8px rgba(241, 185, 47, 0.35); white-space: pre-wrap; }
.co-log pre div { padding-left: 6.5ch; text-indent: -6.5ch; } /* a wrapped line lines up with the text, not the year */
.co-log pre .b { color: var(--bright); letter-spacing: 2px; margin-bottom: 8px; }
.co-log pre .h { color: var(--hot); }
.co-log pre .gl { color: var(--dim); text-shadow: none; }
.co-log pre div:last-child::after { content: '█'; color: var(--amber); margin-left: 4px; animation: caret-blink 1.06s steps(1) infinite; }
.co-log pre.hung div:last-child::after { animation: none; }
.co-ts { display: inline-block; width: 4ch; margin-right: 2.5ch; text-align: right; text-indent: 0; color: var(--dim); text-shadow: none; letter-spacing: 0; }
.co-art { flex: none; max-width: 48%; max-height: none; overflow: hidden; height: 100%; box-sizing: border-box; display: flex; flex-direction: column; justify-content: flex-end; margin: 0; font: 1.65vh/1.25 var(--mono); color: var(--muted); text-shadow: 0 0 8px rgba(241, 185, 47, 0.3); white-space: pre; }
.co-art:empty { display: none; }
.co-art.gl, .co-art.dark { color: var(--dim); text-shadow: none; }
.co-art.dark { transition: color 0.6s; }
.co-band { position: absolute; inset: 0; padding: inherit; box-sizing: border-box; pointer-events: none; }
.co-band > .co-screen { visibility: visible !important; }
.co-band.egged > .co-screen { visibility: hidden !important; }
.co-egg { position: absolute; inset: 0; padding: inherit; box-sizing: border-box; display: flex; align-items: center; font: 15px/1.7 var(--mono); color: var(--muted); text-shadow: 0 0 8px rgba(241, 185, 47, 0.35); }
.co-egg span { padding-left: 6.5ch; }
.co-offline { position: absolute; inset: 0; display: grid; place-items: center; font: 500 15px/1 var(--mono); letter-spacing: 0.35em; color: var(--gray); white-space: nowrap; }
.co-offline.off { visibility: hidden; }
.coldopen.cold .co-log pre { color: var(--gray); text-shadow: none; font-size: 14px; }
.coldopen.cold .co-log pre .h { color: var(--hot); }
.coldopen.cold .co-ts { color: #5f584b; }
.coldopen.cold .co-log pre div:last-child::after { color: var(--gray); }
.co-skip { position: absolute; right: 24px; bottom: 18px; font: 11px var(--mono); color: var(--dim); }
@media (max-width: 900px) { .coldopen { padding: 6vh 6vw; } .co-log pre, .co-egg { font-size: 12px; } .co-art { display: none; } }
.boot.intro { z-index: 70; justify-content: flex-start; padding-top: 12vh; }
.intro-tty { margin: 0; font: 15px/1.7 var(--mono); color: var(--muted); text-shadow: 0 0 8px rgba(241, 185, 47, 0.35); white-space: pre-wrap; }
.intro-tty .b { color: var(--bright); letter-spacing: 2px; margin-bottom: 8px; }
.intro-tty .h { color: var(--hot); }
.intro-tty .y { color: var(--you); }
.intro-tty .dim { color: var(--dim); }
.intro-ask { display: flex; gap: 10px; align-items: baseline; }
.intro-ask label { color: var(--amber); }
.intro-field { position: relative; display: inline-flex; align-items: baseline; color: var(--bright); }
.intro-field input.intro-secret { -webkit-text-security: disc; text-security: disc; letter-spacing: 2px; } /* dots, without being a password field a browser offers to save */
.intro-field input { width: 22ch; padding: 0; background: transparent; border: 0; outline: none; font: inherit; color: var(--bright); caret-color: var(--amber); text-shadow: inherit; }
.intro-field input:focus { caret-color: var(--amber); }
/* The transmission */
.boot.intro.rx .intro-tty { opacity: 0.25; filter: blur(0.5px); transition: opacity 0.6s, filter 0.6s; }
.intro-rx { position: absolute; inset: 0; display: grid; place-items: center; padding: 16px; }
.rx-static { position: absolute; inset: 0; pointer-events: none; background: repeating-linear-gradient(0deg, rgba(241, 185, 47, 0.05) 0 1px, transparent 1px 3px); animation: rx-static 0.9s steps(6) both; }
@keyframes rx-static { 0% { opacity: 1; background-position: 0 0; filter: brightness(2.5); } 60% { opacity: 0.8; background-position: 0 40px; } 100% { opacity: 0.35; background-position: 0 90px; filter: none; } }
.rx-card { position: relative; width: min(620px, 100%); padding: 18px 22px 16px; background: linear-gradient(180deg, rgba(22, 15, 6, 0.97), rgba(12, 8, 4, 0.97)); border: 1px solid var(--line-strong); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), 0 0 50px rgba(241, 185, 47, 0.12), inset 0 0 30px rgba(241, 185, 47, 0.04); font: 14px/1.65 var(--mono); color: var(--text); animation: sp-boot 0.5s cubic-bezier(.2, .9, .3, 1.2) both; }
.rx-card header { display: flex; align-items: center; gap: 14px; padding-bottom: 10px; border-bottom: 1px dashed var(--line); }
.rx-kicker { font-size: 11px; letter-spacing: 3px; text-transform: uppercase; color: var(--hot); animation: pagerblink 0.8s steps(1) infinite; }
.rx-bar.done ~ *, .rx-card header:has(.rx-bar.done) .rx-kicker { animation: none; color: var(--amber); }
.rx-bar { flex: 1; height: 4px; background: rgba(241, 185, 47, 0.1); overflow: hidden; }
.rx-bar i { display: block; height: 100%; width: 0; background: var(--amber); box-shadow: 0 0 8px var(--amber); animation: rx-bar 1.5s cubic-bezier(.4, 0, .2, 1) forwards; }
@keyframes rx-bar { 0% { width: 0; } 40% { width: 34%; } 55% { width: 38%; } 100% { width: 100%; } }
.rx-meta { display: grid; gap: 2px; padding: 10px 0; border-bottom: 1px dashed var(--line); font-size: 12px; color: var(--muted); }
.rx-meta b { display: inline-block; width: 44px; color: var(--dim); font-weight: 500; text-transform: uppercase; font-size: 10px; letter-spacing: 1.5px; }
.rx-body { padding-top: 10px; min-height: 180px; }
.rx-body p { margin: 0 0 10px; }
.rx-body p:first-child { color: var(--bright); }
.rx-card footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 12px; border-top: 1px dashed var(--line); }
.rx-sig { color: var(--muted); font-style: italic; }
.no-motion .rx-static, .no-motion .rx-card, .no-motion .rx-kicker { animation: none; }
.boot.intro pre div:last-child::after { content: none; }

/* A meter you can pay to fill (top up, repair): a + chip beside its number. */
.meter-buy { display: none; align-items: center; justify-content: center; width: 18px; height: 18px; border: 1px solid var(--amber); border-radius: 3px; color: var(--amber); font: 700 14px/1 var(--mono, monospace); align-self: center; }
.meter[data-command] { cursor: pointer; }
.meter[data-command] .meter-buy { display: inline-flex; }
.meter[data-command]:hover .meter-buy, .meter[data-command]:focus-visible .meter-buy { background: var(--amber); color: var(--bg); }
/* Signal in the top bar: five ascending bars, like reception. */
.meter-signal { align-items: center; }
.meter-signal[hidden] { display: none; }
.sig-bars { display: inline-flex; align-items: flex-end; gap: 2px; height: 16px; }
.sig-bars i { width: 5px; background: rgba(127, 209, 199, 0.14); border-radius: 1px; transition: background 0.3s; }
.sig-bars i:nth-child(1) { height: 4px; } .sig-bars i:nth-child(2) { height: 7px; } .sig-bars i:nth-child(3) { height: 10px; } .sig-bars i:nth-child(4) { height: 13px; } .sig-bars i:nth-child(5) { height: 16px; }
.sig-bars i.on { background: var(--you); box-shadow: 0 0 5px rgba(127, 209, 199, 0.5); }
.meter-signal strong { color: var(--you); min-width: 3ch; }
.meter-signal.weak .sig-bars i.on { background: var(--hot); box-shadow: 0 0 5px rgba(255, 91, 61, 0.5); }
.meter-signal.weak strong { color: var(--hot); }
/* Integrity: a server tower that drains from the top, two rack lines across it. */
.srv-tower { position: relative; flex: none; box-sizing: border-box; width: 12px; height: 16px; padding: 1px; display: flex; align-items: flex-end; border: 1.5px solid var(--amber); border-radius: 2px; box-shadow: 0 0 5px rgba(241, 185, 47, 0.35); }
.srv-tower b { display: block; width: 100%; background: var(--amber); border-radius: 0.5px; transition: height 0.3s; }
.srv-tower::before, .srv-tower::after { content: ''; position: absolute; left: 2px; right: 2px; height: 1px; background: var(--inset); }
.srv-tower::before { top: 3px; } .srv-tower::after { top: 6px; }
.meter-integrity.critical .srv-tower { border-color: var(--hot); box-shadow: 0 0 5px rgba(255, 91, 61, 0.4); }
.meter-integrity.critical .srv-tower b { background: var(--hot); }
.meter-integrity strong { min-width: 3ch; }
/* Resting: the next bar up breathes while it refills. */
.meter-signal.resting .sig-bars i.on + i:not(.on), .meter-signal.resting .sig-bars i:first-child:not(.on) { animation: sig-rest 1.2s ease-in-out infinite; }
@keyframes sig-rest { 50% { background: rgba(127, 209, 199, 0.5); } }
.no-motion .meter-signal .sig-bars i { animation: none; }
@media (max-width: 1700px) and (min-width: 901px) { .meters { gap: 14px; } }
@media (max-width: 1440px) and (min-width: 901px) { .meter-signal .meter-label { display: none; } .meters { gap: 10px; } }
@media (max-width: 1300px) and (min-width: 901px) { .meter-level .meter-bar { display: none; } }
@media (max-width: 1700px) and (min-width: 901px) { .meter-level { min-width: 0; } .meter-level .meter-bar { width: 40px; } .topbar { gap: 6px 14px; } }
@media (max-width: 1560px) and (min-width: 901px) { .meter-signal .meter-label, .meter-integrity .meter-label { display: none; } }
@media (max-width: 1320px) and (min-width: 901px) { .ctx-tabs .brand-name { display: none; } }
/* Lists of rows (a hub's work and payloads); protocols on the Loadout page */
.craft-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.craft-list li { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 10px; background: var(--inset); border: 1px solid var(--line); border-radius: 3px; }
.craft-list li > span { display: grid; gap: 2px; min-width: 0; }
.craft-list small { color: var(--muted); font-size: 12px; }
.craft-list small.cost { color: var(--amber-soft); font-family: var(--mono); }
.loadout-protocols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; align-items: start; }
.loadout-protocols.one { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 900px) { .loadout-protocols { grid-template-columns: minmax(0, 1fr); } }

.ltabs { display: flex; gap: 4px; margin: 10px 0 12px; border-bottom: 1px solid var(--line); }
.ltabs button { font: 600 12px var(--sans); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); background: none; border: 0; border-bottom: 2px solid transparent; padding: 8px 12px; margin-bottom: -1px; cursor: pointer; }
.ltabs button[aria-selected='true'] { color: var(--amber); border-bottom-color: var(--amber); }
.ltabs button:hover { color: var(--text); }

/* The Sync Window: a slice of the cycle bar; it lights while the bar is inside it. */
.sync-win { position: absolute; top: -3px; bottom: -3px; z-index: 1; pointer-events: auto; border: 1px solid rgba(255, 216, 92, 0.55); background: rgba(255, 216, 92, 0.12); border-radius: 1px; transition: background 0.1s, box-shadow 0.1s; }
.sync-win.live { background: rgba(255, 216, 92, 0.45); border-color: var(--next); box-shadow: 0 0 10px rgba(255, 216, 92, 0.7); }
.fx-float.sync { margin-top: -26px; color: var(--next); letter-spacing: 2px; font-size: calc(15px * var(--size)); text-shadow: 0 0 10px rgba(255, 216, 92, 0.8), 0 0 8px rgba(0, 0, 0, 0.9); }
.fx-sync { animation: fx-sync 0.4s ease-out; }
@keyframes fx-sync { 0% { box-shadow: inset 0 0 0 2px rgba(255, 216, 92, 0.9); background: rgba(255, 216, 92, 0.15); } 100% { box-shadow: inset 0 0 0 0 rgba(255, 216, 92, 0); background: transparent; } }

/* Service configs on the Server page */
.cfg-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 6px; }
.cfg-label { font: 600 10px var(--mono); letter-spacing: 1.5px; text-transform: uppercase; color: var(--dim); margin-right: 4px; }
.cfg { font: 12px var(--mono); padding: 2px 8px; color: var(--muted); background: var(--inset); border: 1px solid var(--line); border-radius: 2px; cursor: pointer; }
.cfg:hover:not(:disabled) { color: var(--text); border-color: var(--line-strong); }
.cfg.on { color: var(--you); border-color: var(--you); background: rgba(127, 209, 199, 0.08); }
.cfg:disabled { cursor: default; opacity: 0.6; }
.cfg-missing { font: 11px var(--mono); color: var(--dim); margin-left: 4px; }

/* Fleets on the map */
.mnode.fleet path { fill: var(--hot); stroke: none; }
.mnode.fleet path.gone { fill: none; stroke: var(--dim); stroke-width: 1; }
.mnode.fleet.travel path:not(.gone) { fill: var(--next); }
.mnode.fleet.siege { animation: opblink 1.2s steps(2) infinite; }
.no-motion .mnode.fleet.siege { animation: none; }

/* Outpost modules and server architecture */
.mods { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 8px; }
.mod { display: inline-flex; align-items: center; gap: 4px; font: 12px var(--mono); padding: 2px 8px; border: 1px solid var(--line); border-radius: 2px; color: var(--muted); background: var(--inset); }
.mod.on { color: var(--you); border-color: rgba(127, 209, 199, 0.5); }
.mod.add { cursor: pointer; border-style: dashed; }
.mod.add:hover:not(:disabled) { color: var(--text); border-color: var(--line-strong); }
.mod.add:disabled { opacity: 0.5; cursor: default; }
.mod-x { background: none; border: 0; color: var(--dim); cursor: pointer; padding: 0 0 0 2px; font: inherit; }
.mod-x:hover:not(:disabled) { color: var(--hot); }

/* ---------- glyphs: the game's line-drawn icons (see glyphs.mjs) ---------- */
.glyph { display: inline-block; flex: none; width: 1.05em; height: 1.05em; margin-right: 0.45em; vertical-align: -0.16em; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.iname .glyph, .svc-name .glyph { width: 1.15em; height: 1.15em; vertical-align: -0.2em; opacity: 0.95; }
.glyph.verb-hit { color: var(--amber); }
.glyph.verb-burn { color: var(--hot); }
.glyph.verb-stun, .glyph.verb-debuff { color: var(--next); }
.glyph.verb-shield, .glyph.verb-heal, .glyph.verb-buff { color: var(--you); }
.glyph.verb-util, .glyph.verb-run { color: var(--muted); }
.sheet dt .glyph { color: var(--muted); width: 0.95em; height: 0.95em; }
.stat > span .glyph { color: var(--amber-soft); }
.c-head .glyph { color: var(--amber); }
.mod .glyph, .cfg .glyph { width: 0.95em; height: 0.95em; margin-right: 0.3em; }

/* A glyph as a badge: a small framed tile in front of a name (items, skills, services, daemons). */
.glyph.badge { box-sizing: border-box; width: 26px; height: 26px; padding: 5px; margin-right: 9px; vertical-align: middle; stroke-width: 1.3; border: 1px solid currentColor; border-radius: 4px; background: rgba(241, 185, 47, 0.06); box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5); }
.iname:has(.glyph.badge), .svc-name:has(.glyph.badge), .c-head b:has(.glyph.badge) { display: inline-flex; align-items: center; }
.iname .glyph.badge, .svc-name .glyph.badge { width: 26px; height: 26px; vertical-align: middle; }
.r-stock .glyph.badge, .iname.r-stock .glyph.badge { background: rgba(185, 173, 151, 0.07); }
.r-tuned .glyph.badge { background: rgba(127, 214, 122, 0.08); box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5), 0 0 8px rgba(127, 214, 122, 0.15); }
.r-custom .glyph.badge { background: rgba(108, 180, 255, 0.08); box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5), 0 0 8px rgba(108, 180, 255, 0.18); }
.r-zeroday .glyph.badge, .r-indemnified .glyph.badge { background: rgba(196, 155, 255, 0.1); box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5), 0 0 10px rgba(196, 155, 255, 0.25); }
.svc-name .glyph.badge, .c-head .glyph.badge { color: var(--amber); }
.svc.locked .glyph.badge { color: var(--dim); }
.glyph.badge.verb-shield, .glyph.badge.verb-heal, .glyph.badge.verb-buff { background: rgba(127, 209, 199, 0.07); }
.glyph.badge.verb-burn { background: rgba(255, 91, 61, 0.07); }

/* The window beside the monitor needs the room: only on wide screens (window.mjs). */
@media (min-width: 1700px) and (min-height: 720px) {
  body.cased.window-on { --side: max(48px, 3.5vw); background: var(--case-win, #0b0a09); } /* the monitor fills the window, with a strip of the city either side */
  /* Tall enough: window above the monitor too, and the desk it stands on below. */
  @media (min-height: 860px) { body.cased.window-on { --top: 46px; --desk: 30px; } }
  @media (min-height: 1000px) { body.cased.window-on { --top: 56px; --desk: 34px; } }
  body.cased.window-on .toggles { display: none; } /* all on the System page; the bar is narrower here */
}

/* Ability slots: the key sits in the bottom-right corner so the icon and name center in the slot. */
/* Skill library: a small badge that sits in the line with the name. */

/* Skill library, compact: name row, then the rule with its button on the same line. */

/* ---------- Log sweep (forensics.mjs) ---------- */
.term li.sweep-li { list-style: none; }
.sweep { margin: 6px 0 8px; border: 1px solid var(--line-strong); border-radius: 4px; background: rgba(0, 0, 0, 0.35); font: 12.5px var(--mono); }
.sweep.past { border: 0; background: none; margin: 0; color: var(--muted); }
.sw-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 7px 10px; border-bottom: 1px solid var(--line); }
.sw-head b { display: inline-flex; align-items: center; gap: 6px; color: var(--bright); letter-spacing: 1px; }
.sw-q { color: var(--amber); }
.sw-filters { margin-left: auto; display: flex; gap: 4px; }
.sw-filter { font: 11px var(--mono); padding: 2px 8px; border: 1px solid var(--line-strong); border-radius: 3px; background: none; color: var(--muted); cursor: pointer; }
.sw-filter.on { color: var(--bright); border-color: var(--amber); }
.sw-note { padding: 4px 10px; color: var(--you); border-bottom: 1px dashed var(--line); }
.sw-log { padding: 4px 0; max-height: 300px; overflow-y: auto; }
.sw-line { display: grid; gap: 14px; width: 100%; text-align: left; padding: 1px 10px; border: 0; background: none; color: var(--text); font: inherit; cursor: pointer; }
.sw-line:hover { background: rgba(241, 185, 47, 0.07); }
.sw-line.quiet { color: var(--dim); cursor: default; }
.sw-c:first-child { color: var(--muted); }
.sw-c.bad { color: var(--hot); }
.sw-c.good { color: var(--you); }
.sw-line.dimmed { color: var(--muted); }
.sw-cols { cursor: default; color: var(--dim); padding-top: 5px; border-bottom: 1px dashed var(--line); }
.sw-cols:hover { background: none; }
.sw-line.flag0, .sw-suspect.flag0 { background: rgba(241, 185, 47, 0.16); box-shadow: inset 3px 0 0 var(--amber); }
.sw-line.flag1, .sw-suspect.flag1 { background: rgba(127, 209, 199, 0.14); box-shadow: inset 3px 0 0 var(--you); }
.sw-line.flag2, .sw-suspect.flag2 { background: rgba(196, 155, 255, 0.14); box-shadow: inset 3px 0 0 #c49bff; }
.sw-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 7px 10px; border-top: 1px solid var(--line); }
.sw-label { color: var(--muted); letter-spacing: 1px; text-transform: uppercase; font-size: 10.5px; margin-right: 4px; }
.sw-suspect { font: 12px var(--mono); padding: 3px 10px; border: 1px solid var(--line-strong); border-radius: 3px; background: none; color: var(--bright); cursor: pointer; }
.sw-suspect:hover { border-color: var(--amber); }
.sw-suspect.guilty { border-color: var(--hot); color: var(--hot); }
.sw-suspect.cleared { color: var(--dim); text-decoration: line-through; }
.sw-tries { color: var(--dim); }
.sweep .glyph { width: 13px; height: 13px; }
.sweep, .sweep * { white-space: normal; }
.sw-line > span { white-space: pre; overflow: hidden; text-overflow: ellipsis; }

.hud-id .tag-strain, .hud-id .tag-strain ~ .tag { flex-shrink: 0; overflow: visible; }
.tag-strain { border-color: var(--amber); color: var(--amber); }

/* ---------- volume sliders (System page) ---------- */
.vol-card .vol-row { display: grid; grid-template-columns: 90px 1fr 36px; align-items: center; gap: 12px; padding: 4px 0; cursor: pointer; }
.vol-name { color: var(--muted); font-size: 13px; }
.vol-val { font: 600 12px var(--mono); color: var(--bright); text-align: right; }
.vol-row input[type='range'] { -webkit-appearance: none; appearance: none; width: 100%; height: 4px; background: var(--line-strong); border-radius: 2px; outline: none; accent-color: var(--amber); }
.vol-row input[type='range']::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; border-radius: 3px; background: var(--amber); border: 0; box-shadow: 0 0 8px rgba(241, 185, 47, 0.4); cursor: pointer; }
.vol-row input[type='range']::-moz-range-thumb { width: 14px; height: 14px; border-radius: 3px; background: var(--amber); border: 0; cursor: pointer; }
.vol-row input[type='range']:focus-visible { box-shadow: 0 0 0 2px var(--amber); }

/* ---------- rogue servers on the map (rogue.mjs) ---------- */
.mnode.rogue path { fill: rgba(255, 91, 61, 0.08); stroke: var(--hot); stroke-width: 1.3; }
.mnode.rogue path.rx { fill: none; stroke: var(--hot); stroke-width: 1.4; opacity: 0.8; }
.mnode.rogue.here path { stroke: var(--you); fill: rgba(127, 209, 199, 0.15); }
.tag-rogue { border-color: var(--hot); color: var(--hot); }
.tag.tag-special { color: #1a1206; background: var(--amber); border-color: var(--amber); font-weight: 700; letter-spacing: 0.5px; cursor: help; } /* a server special (specials.mjs): the one filled amber tag */

/* A meter that isn't full: click to pay for the rest (top up Signal, repair the server). */
.meter[data-command] { cursor: pointer; border-radius: 4px; padding: 2px 6px; margin: -2px -6px; }
.meter[data-command]:hover, .meter[data-command]:focus-visible { background: var(--panel-2); outline: 1px solid var(--line-strong); }

/* Infiltrator Surprise: the first cycle's window glows blue, not yellow. */
.sync-win.surprise { border-color: rgba(108, 156, 255, 0.6); background: rgba(108, 156, 255, 0.14); }
.sync-win.surprise.live { background: rgba(108, 156, 255, 0.5); border-color: #6c9cff; box-shadow: 0 0 12px rgba(108, 156, 255, 0.8); }
.fx-float.surprise { margin-top: -26px; color: #8fb4ff; letter-spacing: 2px; font-size: calc(15px * var(--size)); text-shadow: 0 0 10px rgba(108, 156, 255, 0.85), 0 0 8px rgba(0, 0, 0, 0.9); }
.fx-surprise { animation: fx-surprise 0.45s ease-out; }
@keyframes fx-surprise { 0% { box-shadow: inset 0 0 0 2px rgba(108, 156, 255, 0.9); background: rgba(108, 156, 255, 0.15); } 100% { box-shadow: inset 0 0 0 0 rgba(108, 156, 255, 0); background: transparent; } }

/* An event on a server (events.mjs): an antenna on the map node, what's happening on its card. */
.mnode .dropmark path { fill: none; stroke: var(--daemon, #c3a6ff); stroke-width: 1.4; stroke-linecap: round; }
.motion .mnode.drop .dropmark, .mnode.drop .dropmark { animation: drop-ping 1.8s ease-in-out infinite; }
.no-motion .mnode.drop .dropmark { animation: none; }
@keyframes drop-ping { 50% { opacity: 0.35; } }
/* A blip (events.mjs): a small spark in the director's violet, on a map node or a room's chip. */
.blipmark { cursor: help; pointer-events: auto; }
.blipmark path { fill: var(--daemon, #c3a6ff); filter: drop-shadow(0 0 3px rgba(195, 166, 255, 0.8)); }
.motion .blipmark path { animation: drop-ping 2.4s ease-in-out infinite; }
.tag-drop { color: var(--daemon, #c3a6ff); border-color: currentColor; }
.drop-line code { color: var(--daemon, #c3a6ff); letter-spacing: 1px; }

/* Loadout: the class's level and XP sit under its name. */

/* Status row under You: each timed effect is a bar over the cycles it lasts (Now first). */
.bstatus .bcell { padding-top: 4px; padding-bottom: 4px; }
.sgrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 3px 0; align-content: center; }
.sbar { display: flex; align-items: baseline; gap: 6px; min-width: 0; overflow: hidden; white-space: nowrap; padding: 2px 8px; margin-right: 6px; border-radius: 2px; font: 12px var(--mono); cursor: help; }
.sbar b { font-weight: 600; } .sbar span { opacity: 0.85; }
.sbar.you { color: var(--you); background: rgba(127, 209, 199, 0.12); border: 1px solid rgba(127, 209, 199, 0.45); }
.sbar.hot { color: var(--hot); background: rgba(255, 91, 61, 0.1); border: 1px solid rgba(255, 91, 61, 0.45); }

/* ---------- protocol glyphs (protocol-glyphs.mjs) ----------
   An item's ASCII picture in its rarity colour. White dims; yellow, gold and orange get corner marks; a Zero-day's
   bright scanline and a unique's flicker are app.js's (glyphMotion), and stop with motion off. */
.pglyph { --pg-c: var(--r-stock); position: relative; display: block; flex: none; width: max-content; margin: 0; padding: 0.5em 0.7em; white-space: pre; font: 600 var(--pg-size, 7px)/1.08 var(--mono); letter-spacing: 0; color: var(--pg-c); text-shadow: 0 0 0.45em color-mix(in srgb, var(--pg-c) 45%, transparent); }
.pglyph.pg-sm { --pg-size: 3.1px; } .pglyph.pg-md { --pg-size: 4.1px; } .pglyph.pg-tip { --pg-size: 6px; } .pglyph.pg-lg { --pg-size: 6.4px; } /* small marks beside a name */
.pglyph.r-scrap { --pg-c: var(--r-scrap); } .pglyph.r-tuned { --pg-c: var(--r-tuned); } .pglyph.r-custom { --pg-c: var(--r-custom); }
.pglyph.r-zeroday { --pg-c: var(--r-zeroday); } .pglyph.r-indemnified { --pg-c: var(--r-indemnified); }
.pglyph.r-set { --pg-c: var(--r-set); }
.pglyph.r-stock, .pglyph.r-scrap { opacity: 0.72; }
.pglyph.pg-framed::before, .pglyph.pg-framed::after { content: ''; position: absolute; width: 1.6em; height: 1.6em; border: 0 solid var(--pg-c); opacity: 0.85; }
.pglyph.pg-framed::before { top: 0; left: 0; border-width: 1px 0 0 1px; }
.pglyph.pg-framed::after { right: 0; bottom: 0; border-width: 0 1px 1px 0; }
.pglyph .pg-scan { font-weight: inherit; color: #fff3c4; text-shadow: 0 0 0.6em var(--pg-c); }
.ptip-glyph { justify-self: start; display: grid; place-items: center; }

/* ---------- the protocol board (Loadout → Protocols; view.mjs silkBoard) ----------
   A silkscreened board: the rig in the middle, its slots as labelled footprints three a side, a trace from each to the
   rig. The columns (36% · 6% · 16% · 6% · 36%) match the traces' percent coordinates, inside the board's padding. Wide:
   the board and the stats down the left; the stash, a list of every item that fits, down the right, on the first screen.
   One column (900px and under): board, stash, stats. A phone, and a narrow screen with the board beside the stash
   (901–1100px), fold the board to one column of slots under the rig, traces gone. An item's datasheet is a popover (.pg-pop, app.js), never a card in the layout. */
.loadout-protocols.silk { grid-template-columns: minmax(0, 1.3fr) minmax(380px, 1fr); grid-template-rows: auto auto 1fr; grid-template-areas: 'board stash' 'stats stash' '. stash'; }
.silk > .silk-card { grid-area: board; } .silk > .silk-stash { grid-area: stash; align-self: start; } .silk > .silk-statcard { grid-area: stats; }
@media (max-width: 900px) { .loadout-protocols.silk { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; grid-template-areas: 'board' 'stash' 'stats'; } }
.silk-card { padding: 20px 22px 22px; }
.silk-board { --bx: 18px; --by: 16px; position: relative; display: grid; grid-template-columns: 36% 6% 16% 6% 36%; grid-template-rows: repeat(3, 1fr); padding: var(--by) var(--bx); border-radius: 8px; background: #0c0905; border: 1px solid var(--line); }
.silk-traces { position: absolute; top: var(--by); left: var(--bx); width: calc(100% - 2 * var(--bx)); height: calc(100% - 2 * var(--by)); overflow: visible; pointer-events: none; }
.silk-trace { fill: none; stroke: #5a3f15; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }
.silk-trace.live { stroke: var(--amber); stroke-dasharray: 8 10; animation: silk-flow 1s linear infinite; }
.silk-trace.off { opacity: 0.35; }
@keyframes silk-flow { to { stroke-dashoffset: -18; } }
.silk-rig { position: relative; z-index: 1; grid-column: 3; grid-row: 1 / 4; align-self: center; display: grid; place-content: center; gap: 4px; height: 50%; min-height: 120px; padding: 10px 6px; text-align: center; background: #15100a; border: 1.5px solid rgba(127, 209, 199, 0.6); border-radius: 10px; }
.silk-rig b { font: 600 17px var(--mono); color: var(--you); overflow-wrap: anywhere; }
.silk-rig small { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--muted); }
.silk-pin1 { position: absolute; left: 10px; top: 10px; width: 7px; height: 7px; border-radius: 50%; background: var(--you); opacity: 0.6; }
.silk-fp { --edge: #2a2012; position: relative; z-index: 1; display: grid; min-width: 0; padding: 7px 0; }
.silk-fp.at-l0 { grid-area: 1 / 1; } .silk-fp.at-l1 { grid-area: 2 / 1; } .silk-fp.at-l2 { grid-area: 3 / 1; }
.silk-fp.at-r0 { grid-area: 1 / 5; } .silk-fp.at-r1 { grid-area: 2 / 5; } .silk-fp.at-r2 { grid-area: 3 / 5; }
.silk-fp.r-stock { --edge: var(--r-stock); } .silk-fp.r-tuned { --edge: var(--r-tuned); } .silk-fp.r-custom { --edge: var(--r-custom); }
.silk-fp.r-zeroday { --edge: var(--r-zeroday); } .silk-fp.r-indemnified { --edge: var(--r-indemnified); }
.silk-fp.r-set { --edge: var(--r-set); }
/* A footprint's row: the glyph and the text block (name, set, label) centred on one line. */
.silk-fp .silk-pick { position: relative; display: flex; align-items: center; gap: 10px; width: 100%; min-height: 78px; margin: 0; padding: 10px 34px 10px 12px; text-align: left; color: var(--text); background: #16110a; border: 1px solid var(--line-strong); border-radius: 8px; transition: border-color 0.12s, box-shadow 0.12s; }
.silk-fp .silk-pick::before { content: ''; position: absolute; left: 6px; top: 6px; width: 4px; height: 4px; border-radius: 50%; background: var(--dim); } /* pin 1 */
.silk-text { display: grid; gap: 3px; align-content: center; min-width: 0; }
.silk-hole { display: block; flex: none; width: 58px; height: 52px; border: 1px dashed rgba(143, 119, 72, 0.6); border-radius: 4px; }
.silk-fp .iname { font: 600 13px/1.3 var(--mono); overflow-wrap: break-word; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.silk-set { font: 600 11px var(--mono); color: var(--r-set); }
.silk-none { font: 600 13px var(--mono); color: var(--dim); }
.silk-count { display: inline-grid; place-items: center; min-width: 18px; height: 18px; margin-left: 4px; padding: 0 5px; border-radius: 9px; background: var(--amber); color: var(--bg); font: 700 11px var(--mono); vertical-align: 1px; }
.silk-ref { display: flex; align-items: center; gap: 6px; min-width: 0; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--muted); }
.silk-ref b { color: var(--amber); font-weight: 600; letter-spacing: 1.5px; }
.silk-led { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--edge); box-shadow: 0 0 6px color-mix(in srgb, var(--edge) 50%, transparent); }
.silk-fp.empty .silk-led, .silk-fp.locked .silk-led { box-shadow: none; }
.silk-fp.empty .silk-pick, .silk-fp.locked .silk-pick { background: none; border-style: dashed; border-color: rgba(143, 119, 72, 0.7); }
.silk-fp.locked { opacity: 0.45; }
.silk-fp.locked .silk-pick { cursor: default; }
.silk-fp button.silk-pick:hover { border-color: var(--amber-soft); }
.silk-fp.sel .silk-pick { border-color: var(--amber); box-shadow: 0 0 0 1px var(--amber), 0 0 14px rgba(241, 185, 47, 0.18); }
.silk-fp.target .silk-pick { border-color: var(--amber); outline: 1px dashed var(--amber); outline-offset: 4px; }
.silk-out { position: absolute; top: 14px; right: 6px; z-index: 2; min-width: 24px; height: 22px; padding: 0 6px; }
/* Hovering a stash tile lights the footprint it goes in (data-kind on both). */
body:has(.silk-stash .silk-tile[data-kind="exploit"]:hover) .silk-fp[data-kind="exploit"]:not(.locked) .silk-pick,
body:has(.silk-stash .silk-tile[data-kind="proxy"]:hover) .silk-fp[data-kind="proxy"]:not(.locked) .silk-pick,
body:has(.silk-stash .silk-tile[data-kind="shell"]:hover) .silk-fp[data-kind="shell"]:not(.locked) .silk-pick,
body:has(.silk-stash .silk-tile[data-kind="script"]:hover) .silk-fp[data-kind="script"]:not(.locked) .silk-pick,
body:has(.silk-stash .silk-tile[data-kind="implant"]:hover) .silk-fp[data-kind="implant"]:not(.locked) .silk-pick { border-color: var(--amber); background: #1d160b; box-shadow: 0 0 10px rgba(241, 185, 47, 0.25); }
@media (max-width: 640px), (min-width: 901px) and (max-width: 1100px) { /* a phone, and the board beside the stash on a narrow screen: one column of slots */
  .silk-card { padding: 16px 14px 18px; }
  .silk-board { --bx: 12px; --by: 12px; grid-template-columns: minmax(0, 1fr); grid-template-rows: none; gap: 8px; }
  .silk-traces { display: none; }
  .silk-rig { grid-area: auto; display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center; gap: 4px 12px; height: auto; min-height: 0; padding: 10px 12px 10px 24px; }
  .silk-pin1 { top: 50%; margin-top: -3px; }
  .silk-board .silk-fp { grid-area: auto; order: var(--i); padding: 0; }
  .silk-out { top: 50%; margin-top: -11px; }
}

/* An item's datasheet (view.mjs protocolDetailMarkup), in its popover: a rarity edge down its left, the name first and
   the glyph beside it. Beside a row or slot on hover or focus it only reads (the buttons are on the row); after a tap
   (.tap) its buttons are in it, and a tap outside closes it. On a phone it is in the one sheet (phone.css). */
.pg-pop { position: fixed; z-index: 80; zoom: var(--ui, 1); width: 340px; max-width: calc((100vw - 16px) / var(--ui, 1)); max-height: calc((100vh - 16px) / var(--ui, 1)); overflow: auto; pointer-events: none; animation: ptip-in 0.14s ease-out; }
.pg-pop[hidden] { display: none; }
.pg-detail { --edge: var(--line-strong); display: grid; gap: 8px; padding: 14px 16px; background: #0a0805; border: 1px solid var(--line-strong); border-left: 3px solid var(--edge); border-radius: 4px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6); color: var(--text); }
.pg-detail.r-stock { --edge: var(--r-stock); } .pg-detail.r-tuned { --edge: var(--r-tuned); } .pg-detail.r-custom { --edge: var(--r-custom); }
.pg-detail.r-zeroday { --edge: var(--r-zeroday); } .pg-detail.r-indemnified { --edge: var(--r-indemnified); }
.pg-detail.r-set { --edge: var(--r-set); }
.pg-detail .silk-title { font-size: 16px; }
.pg-pop:not(.tap) .pg-acts { display: none; }
.pg-scrim { position: fixed; inset: 0; z-index: 79; background: rgba(0, 0, 0, 0.45); }
.pg-scrim[hidden] { display: none; }
.pg-pop.tap { pointer-events: auto; }
.no-motion .pg-pop { animation: none; }
@media (prefers-reduced-motion: reduce) { .pg-pop { animation: none; } }
.silk-head { display: flex; align-items: flex-start; gap: 14px; } /* the title and its line sit at the top left, beside the art */
.silk-headtext { display: grid; align-content: start; gap: 6px; flex: 1; min-width: 0; }
.silk-plate { flex: none; display: grid; place-items: center; padding: 4px; background: #0c0905; border: 1px solid var(--line); border-radius: 3px; }
.silk-title { margin: 0; font: 600 18px/1.25 var(--mono); overflow-wrap: break-word; text-wrap: balance; }
.silk-sub { margin: 0; font: 12px var(--mono); color: var(--muted); }
.silk-sub .tag { margin-left: 4px; }
.silk-req { color: var(--hot); font-weight: normal; }
.silk-kicker { margin: 6px 0 0; font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; color: var(--dim); }
.silk-stats { display: grid; margin: 0; }
.silk-stats > div { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 10px; padding: 3px 2px; border-bottom: 1px dotted rgba(241, 185, 47, 0.12); font-size: 13px; }
.silk-stats.vs > div { grid-template-columns: minmax(0, 1fr) auto 64px; }
.silk-stats dt { display: flex; align-items: center; gap: 6px; color: var(--text); }
.silk-stats dt .glyph { color: var(--muted); width: 0.95em; height: 0.95em; }
.silk-stats dd { margin: 0; font: 600 13px var(--mono); color: var(--bright); text-align: right; }
.silk-stats .neg dd { color: var(--hot); } .silk-stats .zero dd { color: var(--dim); font-weight: 500; }
.silk-stats .silk-d { font: 12px var(--mono); color: var(--dim); } .silk-stats .silk-d.up { color: var(--you); } .silk-stats .silk-d.down { color: var(--hot); }
.silk-lost { margin: 0; font: 12px var(--mono); color: var(--hot); }
.silk-fx { margin: 0; font-size: 13px; color: var(--text); max-width: none; }
.silk-fx b { color: var(--r-zeroday); font-weight: 600; }
.silk-flavour { color: var(--muted); font-size: 12px; }
.pg-detail .set-lines { margin-top: 2px; }
.silk-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.silk-acts .btn .glyph { margin: 0; }

/* The stash: a row a protocol, to scan down: its small glyph, its name and level, its three biggest stats with ▲ ▼ in a
   column of their own, then Load or Swap and Deconstruct. A click on the row loads it. */
.pg-bar { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0 12px; }
.pg-bar .inv-filters { flex: 1 1 auto; }
.pg-bar .pg-sort { flex: 0 0 auto; }
.silk-tiles { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 4px; }
.silk-tile { --edge: var(--line-strong); position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; min-width: 0; background: var(--inset); border: 1px solid var(--line); border-left: 3px solid var(--edge); border-radius: var(--r-card); }
.silk-tile.r-stock { --edge: var(--r-stock); } .silk-tile.r-tuned { --edge: var(--r-tuned); } .silk-tile.r-custom { --edge: var(--r-custom); }
.silk-tile.r-zeroday { --edge: var(--r-zeroday); } .silk-tile.r-indemnified { --edge: var(--r-indemnified); }
.silk-tile.r-set { --edge: var(--r-set); }
.silk-tile:hover, .silk-tile.pd-on { background: rgba(241, 185, 47, 0.06); border-color: var(--line-strong); border-left-color: var(--edge); }
.silk-tile.fit { border-color: rgba(241, 185, 47, 0.45); border-left-color: var(--edge); }
.silk-tile .silk-pick { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 8px; min-width: 0; margin: 0; padding: 5px 6px 5px 4px; text-align: left; color: var(--text); background: none; border: 0; border-radius: var(--r-card) 0 0 var(--r-card); cursor: pointer; }
.silk-tile .silk-pick[aria-disabled='true'] { cursor: default; }
.silk-tile .silk-pick:hover { border: 0; }
.silk-tile .silk-pick:focus-visible { outline: 1px solid var(--amber); outline-offset: -1px; }
.silk-tile .silk-text { gap: 2px; }
.silk-tile .pglyph.pg-sm { --pg-size: 2.6px; }
.silk-tile .iname { font: 600 13px/1.25 var(--mono); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.silk-tile .iname .tag { margin-left: 4px; vertical-align: 1px; }
.pg-lv { display: grid; justify-items: end; gap: 1px; min-width: 52px; }
.pg-lv b { font: 600 12px var(--mono); color: var(--text); white-space: nowrap; }
.pg-lv small { font: 10px var(--mono); letter-spacing: 0.5px; text-transform: uppercase; color: var(--dim); }
.silk-sts { display: flex; flex-wrap: wrap; gap: 0 12px; }
.silk-st { display: flex; align-items: center; gap: 3px; font-size: 12px; color: var(--muted); }
.silk-st .glyph { width: 0.95em; height: 0.95em; margin: 0; color: var(--muted); }
.silk-st b { font: 600 12px var(--mono); color: var(--text); }
.silk-st.neg b { color: var(--hot); }
.silk-st i { font: normal 10px var(--mono); } .silk-st i.up { color: var(--you); } .silk-st i.down { color: var(--hot); }
.silk-tile .inv-acts { padding: 0 6px 0 0; }
@media (max-width: 640px) { .silk-tile .inv-acts .inv-btn:not(.load) { display: none; } .pg-lv { min-width: 0; } } /* a phone: Deconstruct is in the tap's sheet */
.no-motion .silk-trace.live { animation: none; }
@media (prefers-reduced-motion: reduce) { .silk-trace.live { animation: none; } }

/* What a stash tile and the hover card share: stats one a line, the effect, the tile's small buttons. */
.inv-stats { display: grid; gap: 1px; font-size: 12px; color: var(--muted); } /* one stat a line */
.inv-stats b { color: var(--text); font: 600 12px var(--mono); }
.inv-stats .neg, .inv-stats .neg b { color: var(--hot); }
.inv-fx { font-size: 12px; color: var(--r-zeroday); }
.inv-acts { display: flex; gap: 4px; align-items: center; }
.inv-btn { display: inline-grid; place-items: center; min-width: 28px; height: 26px; padding: 0 8px; background: none; border: 1px solid var(--line); border-radius: 3px; color: var(--muted); font: 600 11px var(--mono); letter-spacing: 1px; text-transform: uppercase; cursor: pointer; }
.inv-btn .glyph { margin: 0; }
.inv-btn:hover:not(:disabled) { color: var(--bright); border-color: var(--line-strong); }
.inv-btn.load { color: var(--amber); border-color: rgba(241, 185, 47, 0.45); }
.inv-btn.load:hover:not(:disabled) { background: var(--amber); color: var(--bg); }
.inv-btn:disabled { opacity: 0.35; cursor: default; }
.inv-filters { display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 8px; }
.inv-filters button { background: none; border: 1px solid var(--line); border-radius: 2px; padding: 3px 8px; color: var(--muted); font: 11px var(--mono); letter-spacing: 1px; text-transform: uppercase; cursor: pointer; }
.inv-filters button span { color: var(--dim); margin-left: 4px; }
.inv-filters button[aria-pressed='true'] { color: var(--amber); border-color: var(--amber); }
.inv-filters button:disabled { opacity: 0.35; cursor: default; }

/* Simulated crew (crew.mjs): their rows under yours, who an attack is going at, names in the log. */
.intent.mine.mate { border-color: rgba(195, 166, 255, 0.5); color: var(--daemon); }
.intent { position: relative; }
.intent .at { position: absolute; top: -8px; right: 4px; padding: 0 4px; font: 600 9px var(--mono); letter-spacing: 0.5px; color: var(--bright); background: var(--panel); border: 1px solid var(--line-strong); border-radius: 2px; }
#log li.crew .who, .log li.crew .who { color: var(--daemon); font-weight: 600; }
.you-top { display: flex; align-items: center; gap: 14px; }
/* Your crew under your Signal in the HUD (view.mjs partyMarkup): name, bar, number, a line each. */
/* Your side (Signal, crew under it) over the board, the virus's bar over its picture: the same columns
   as the page below. The gap makes up for the HUD's own padding, so the virus bar starts where the picture does. */
.hud { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); column-gap: 21px; }
.hud-left { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.55fr); gap: 20px; min-width: 0; } /* your side (as wide as the virus's bar), then your statuses */
.hud-you { display: grid; gap: 8px; min-width: 0; }
/* Your statuses (view.mjs statusPanel): a chip each, timed ones say how long. */
.hud-status { min-width: 0; }
.hud-status .bar-top strong { font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.st-list { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.st { position: relative; display: inline-block; padding: 2px 8px; border: 1px solid var(--line); border-radius: 3px; font: 600 11px/16px var(--sans); background: var(--inset); white-space: nowrap; cursor: help; }
.st.you { color: var(--you); border-color: rgba(127, 209, 199, 0.5); }
.st.hot { color: var(--hot); border-color: rgba(255, 91, 61, 0.55); }
.st.daemon { color: var(--daemon); border-color: rgba(195, 166, 255, 0.5); }
/* The quick tooltip: shows almost at once (the browser's own takes a second). */
.st[data-tip]::after { content: attr(data-tip); position: absolute; left: 0; top: calc(100% + 6px); z-index: 20; width: max-content; max-width: 260px; padding: 6px 9px; border: 1px solid var(--line-strong, rgba(241, 185, 47, 0.35)); border-radius: 4px; background: var(--panel); color: var(--text); font: 400 12px/1.4 var(--sans); white-space: pre-line; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5); opacity: 0; visibility: hidden; transform: translateY(-2px); transition: opacity 0.08s ease-out, transform 0.08s ease-out, visibility 0s linear 0.08s; pointer-events: none; }
.st[data-tip]:hover::after, .st[data-tip]:focus::after { opacity: 1; visibility: visible; transform: none; transition-delay: 0.05s, 0.05s, 0s; }

/* The virus's name on its bar (no separate title). */
.hud-bar.enemy .bar-top { align-items: baseline; }
.hud-bar .bar-top .vname { display: flex; align-items: baseline; gap: 10px; min-width: 0; overflow: hidden; white-space: nowrap; font: inherit; line-height: 1.2; color: inherit; }
.hud-bar .bar-top .vname strong { font: 700 16px var(--sans); letter-spacing: 1.5px; text-transform: none; color: var(--bright); }
.hud-bar .bar-top .vname .meta { font: 12px var(--sans); color: var(--muted); letter-spacing: 0; line-height: 1.2; }
.hud-bar .bar-top .vname .meta * { font: inherit; } /* the level keeps its colour (how it compares to yours) */
.hud-bar .bar-top .vname .meta .lvl, .hud-bar .bar-top .vname .meta b { font-weight: 600; }
.hud-bar.enemy .clock-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
/* The crew: a little window under your Signal, side by side. */
.hud-crew { border: 1px solid var(--line); border-radius: 4px; background: var(--inset); padding: 6px 10px; display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 12px; }
.hud-crew .bar-top { display: block; }
.hud-crew .bar-top strong { font-size: 11px; }
.party { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 4px 0; margin-top: 2px; }
/* A divider between crewmates, so it's clear whose bar is whose. */
.party .pmate { padding: 0 10px; } .party .pmate:first-child { padding-left: 0; } .party .pmate + .pmate { border-left: 1px solid var(--line-strong, rgba(241, 185, 47, 0.25)); }
.pmate { display: grid; grid-template-columns: auto auto 1fr auto; align-items: center; gap: 8px; font-size: 12px; }
.pmate b { color: var(--daemon); font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.pmate .tag { font-size: 9px; padding: 0 4px; }
.pmate:not(:has(.tag)) { grid-template-columns: auto 1fr auto; }
.pmate small { color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
.pbar { position: relative; height: 5px; background: var(--inset); border: 1px solid var(--line); overflow: hidden; }
.pbar > span:first-child { display: block; height: 100%; background: var(--daemon); }
.pmate.down { opacity: 0.4; } .pmate.down b { text-decoration: line-through; }
.pmate.acting b { color: var(--bright); }
.byou.acting { background: rgba(127, 209, 199, 0.08); box-shadow: inset 3px 0 0 var(--you); }

/* The hit effects layer (hitfx.mjs) sits over the board, positioned against this. */
.combat { position: relative; }

/* The forecast (view.mjs forecast): what this cycle is about to cost, as a blinking white slice
   at the end of each bar (parts, the virus, you, the crew). */
.bigbar, .part-bar { position: relative; overflow: hidden; }
.bigbar .loss, .part-bar .loss { position: absolute; top: 0; bottom: 0; display: block; background: #fff8e6; box-shadow: 0 0 6px rgba(255, 248, 230, 0.8); animation: loss-blink 0.9s ease-in-out infinite; }
@keyframes loss-blink { 50% { opacity: 0.25; } }
.no-motion .bigbar .loss, .no-motion .part-bar .loss { animation: none; opacity: 0.7; }
/* A chit about to break this cycle (the forecast): it blinks white like the slices on the bars. */
.chits .going { font-weight: inherit; color: #fff8e6; text-shadow: 0 0 6px rgba(255, 248, 230, 0.8); animation: loss-blink 0.9s ease-in-out infinite; }
.no-motion .chits .going { animation: none; opacity: 0.7; }

/* People (presence.mjs): the top-bar button, its panel, and who's in a SPRAWL-00 folder. */
.people-btn { display: flex; align-items: center; gap: 6px; background: #1b1409; border: 1px solid #3a2c14; border-radius: 6px; padding: 4px 9px; color: var(--muted); font: 600 12px var(--mono); cursor: pointer; }
.people-btn[hidden] { display: none; }
.people-btn:hover, .people-btn[aria-expanded='true'] { border-color: var(--amber); color: var(--text); }
.p-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--you); box-shadow: 0 0 5px var(--you); flex: none; }
.p-dot.fighting { background: var(--hot); box-shadow: 0 0 5px var(--hot); }
.p-dot.off { background: var(--dim); box-shadow: none; }
.people-btn.friends-on .p-dot { background: var(--daemon); box-shadow: 0 0 6px var(--daemon); }
.comms.people { right: 150px; width: 380px; }
.people-list .person { display: grid; grid-template-columns: auto auto 1fr; grid-template-areas: 'dot name class' 'dot where where' 'dot acts acts'; align-items: center; gap: 2px 8px; padding: 8px 12px; border-bottom: 1px solid rgba(241, 185, 47, 0.08); list-style: none; }
.people-list .person .p-dot { grid-area: dot; align-self: start; margin-top: 5px; }
.people-list .person b { grid-area: name; color: var(--bright); font: 600 13px var(--mono); }
.people-list .person.friend b { color: var(--daemon); }
.people-list .person small { grid-area: class; color: var(--dim); font: 11px var(--mono); }
.people-list .person .p-where { grid-area: where; color: var(--muted); font-size: 12px; }
.people-list .person .p-acts { grid-area: acts; display: flex; gap: 10px; align-items: center; }
.people-list .person.off { opacity: 0.55; }
.act.dim { color: var(--dim); }
.ls-people { display: inline-flex; gap: 4px; margin-left: 8px; }
.ls-people .who { font: 11px var(--mono); color: var(--you); border: 1px solid rgba(127, 209, 199, 0.35); border-radius: 8px; padding: 0 6px; }
.ls-people .who::before { content: '● '; font-size: 8px; vertical-align: 1px; }
.ls-people .who.friend { color: var(--daemon); border-color: rgba(195, 166, 255, 0.5); }
.ls-people .who.fighting::before { color: var(--hot); }
.ls-people .who.more { color: var(--muted); border-color: var(--line); }
.ls-people .who.more::before { content: none; }
.ls-here { display: flex; align-items: center; gap: 4px; margin: 0 0 4px; font: 11px var(--mono); color: var(--dim); letter-spacing: 1px; text-transform: uppercase; }
.ls-here .ls-people { margin-left: 4px; }

/* The crew strip (run screen): you and each crewmate, where they are, linked or not. */
.crew-strip { display: flex; gap: 8px; padding: 8px 14px; border-bottom: 1px solid var(--line); overflow-x: auto; }
.cs-card { flex: 0 0 168px; display: grid; gap: 3px; padding: 7px 9px; background: var(--inset); border: 1px solid var(--line); border-left: 3px solid var(--daemon); border-radius: 3px; }
.cs-card.you { border-left-color: var(--you); }
.cs-card.linked { box-shadow: inset 0 0 0 1px rgba(195, 166, 255, 0.25); }
.cs-card.here:not(.you) { background: rgba(195, 166, 255, 0.06); }
.cs-top { display: flex; align-items: baseline; gap: 6px; } .cs-top b { font: 600 13px var(--mono); color: var(--bright); } .cs-top small { font: 10px var(--mono); color: var(--dim); text-transform: uppercase; letter-spacing: 1px; }
.cs-card:not(.you) .cs-top b { color: var(--daemon); }
.cs-sig { display: block; height: 3px; background: rgba(255, 255, 255, 0.06); } .cs-sig span { display: block; height: 100%; background: var(--you); }
.cs-card:not(.you) .cs-sig span { background: var(--daemon); }
.cs-where { font: 12px var(--mono); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-state { font: 10px var(--mono); letter-spacing: 0.5px; } .cs-link { color: var(--daemon); } .cs-link.lead { color: var(--you); } .cs-off { color: var(--dim); }
.cs-acts { display: flex; gap: 10px; }
.ls-people .who.crew { color: var(--daemon); border-color: rgba(195, 166, 255, 0.6); background: rgba(195, 166, 255, 0.08); }
.ls-people .who.member { color: var(--next); border-color: rgba(255, 216, 92, 0.4); }
.people-list .person.member b { color: var(--next); }
.people-list .con-head { list-style: none; padding: 10px 12px; border-bottom: 1px solid var(--line); display: grid; gap: 4px; }
.people-list .con-head b { color: var(--next); font: 600 14px var(--sans); } .people-list .con-head small { color: var(--muted); font-size: 12px; }
.people-list .con-head.invite { border: 1px solid rgba(255, 216, 92, 0.4); background: rgba(255, 216, 92, 0.05); }
.people-list .con-alert { list-style: none; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--line); border-left: 2px solid var(--hot); font-size: 12px; color: var(--text); } .con-alert b { color: var(--hot); }
.con-div { display: flex; align-items: center; justify-content: space-between; gap: 8px; } .con-div b { color: var(--text); }
.con-tiers { display: flex; flex-wrap: wrap; gap: 4px; }
.tag-con { color: var(--next); border-color: rgba(255, 216, 92, 0.5); }
/* The consortium's map: trunk lines out to members' home servers. */
.map-canvas { position: relative; }
.map-tools { position: absolute; top: 8px; left: 8px; right: 8px; z-index: 2; display: flex; justify-content: space-between; align-items: center; pointer-events: none; }
.map-tools > * { pointer-events: auto; }
.map-ctl { margin-left: auto; }
.map-svg.zoomed { cursor: grab; } .map-svg.zoomed:active { cursor: grabbing; }
/* Levels first: the level big, in WoW colours; the layer a small tag; names can hide until hover. */
.msub .mlv { font-size: calc(14px / var(--z, 1)); font-weight: 700; }
.mlv.con-red { fill: #ff5b3d; } .mlv.con-orange { fill: #ff9a3d; } .mlv.con-yellow { fill: #f1d02f; } .mlv.con-green { fill: #7fd67a; } .mlv.con-gray { fill: #8a8174; }
.msub .mlayer { fill: var(--you); font-weight: 600; letter-spacing: 1px; }
.names-hover .mnode:not(.server):not(:hover):not(:focus-visible):not(.selected) .mlabel { opacity: 0; }
.names-hover .mnode .mlabel { transition: opacity 0.15s; }
.mscope .mring-range.trunk { stroke: rgba(255, 216, 92, 0.14); stroke-dasharray: 4 6; }
.mlink.trunk { stroke: rgba(255, 216, 92, 0.55); stroke-width: 1.6; stroke-dasharray: 6 4; animation: mflow 2.4s linear infinite; }
.no-motion .mlink.trunk { animation: none; }
.mnode.member rect { fill: rgba(255, 216, 92, 0.06); stroke: rgba(255, 216, 92, 0.7); stroke-width: 1.3; }
.mnode.member.online rect { fill: rgba(255, 216, 92, 0.16); }
.mnode.member .zdot { fill: var(--next); }
.mnode.member.besieged rect { stroke: var(--hot); }

/* The Consortium page: alerts as cards (what, how long, what it pays, one button), members, the
   consortium's size ladder, the dividend. */
.con-col { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; align-content: start; min-width: 0; }
.con-alarms { display: grid; gap: 10px; }
.con-alarm { border: 1px solid rgba(255, 91, 61, 0.35); border-left: 3px solid var(--hot); background: rgba(255, 91, 61, 0.05); border-radius: 4px; padding: 12px 14px; display: grid; gap: 6px; }
.con-alarm.k-lockdown, .con-alarm.k-crash { border-color: rgba(255, 216, 92, 0.3); border-left-color: var(--next); background: rgba(255, 216, 92, 0.04); }
.con-alarm.mine { box-shadow: inset 0 0 0 1px rgba(127, 209, 199, 0.25); }
.ca-top { display: flex; justify-content: space-between; gap: 8px; font: 600 11px var(--mono); letter-spacing: 1.2px; text-transform: uppercase; }
.ca-kind { color: var(--hot); } .k-lockdown .ca-kind, .k-crash .ca-kind { color: var(--next); }
.ca-time { color: var(--text); }
.ca-title { font: 600 16px var(--sans); color: var(--bright); }
.ca-detail { color: var(--muted); font-size: 13px; margin: 0; }
.ca-bar { height: 4px; background: rgba(255, 255, 255, 0.07); border-radius: 2px; overflow: hidden; }
.ca-bar span { display: block; height: 100%; background: var(--hot); transition: width 0.9s linear; }
.k-lockdown .ca-bar span, .k-crash .ca-bar span { background: var(--next); }
.ca-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ca-meta { color: var(--muted); font-size: 13px; } .ca-meta b { color: var(--text); }
.con-members, .con-ladder { padding: 0; margin: 0; }
.con-member > div { display: grid; gap: 3px; justify-items: start; } .con-member .con-name { display: flex; align-items: center; gap: 8px; } .con-member b { color: var(--next); } .con-member small { color: var(--muted); font-size: 12px; }
.con-member.off b { color: var(--muted); }
.con-ladder { list-style: none; display: grid; gap: 4px; }
.con-ladder li { display: grid; grid-template-columns: 28px 90px 1fr; align-items: baseline; gap: 8px; color: var(--dim); font-size: 13px; }
.con-ladder li.on { color: var(--text); } .con-ladder li.on b { color: var(--next); }
.tier-at { font: 600 12px var(--mono); text-align: right; }
.con-waiting { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.con-waiting span { display: grid; gap: 2px; } .con-waiting small { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 1px; } .con-waiting b { color: var(--bright); font-size: 15px; }
.con-leave { justify-content: flex-end; }
.people-list .con-head .btn { justify-self: start; margin-top: 4px; } .people-list .con-head .hot { color: var(--hot); }
@media (max-width: 900px) { .con-page { grid-template-columns: minmax(0, 1fr); } }

/* The top bar keeps to one line: app.js fitTopbar() steps these on while it would wrap. */
.topbar.fit-1 .brand-name { display: none; }
.topbar.fit-2 { gap: 6px 10px; } .topbar.fit-2 .meters { gap: 10px; } .topbar.fit-2 .meter-bar { width: 56px; } .topbar.fit-2 .modules button { padding: 6px 6px; }
.topbar.fit-3 .meter-bar { display: none; }
.topbar.fit-4 .meter-label { display: none; }

/* Who's aiming at a part this cycle: round initials stacked in a rail down the row's left edge
   (you teal, crew violet). Every board row keeps the rail's width, so names line up. */
#board { --gut: 38px; } /* the left gutter: the aim pips, and the tethers when parts protect each other */
#board .brow { padding-left: var(--gut); }
.bpart .bname { position: relative; }
.aim-pips { position: absolute; left: -32px; top: 50%; transform: translateY(-50%); display: flex; flex-direction: column;  }
.aim { cursor: help; } /* hover: the command (a click still goes to the part's row) */
.aim { width: 24px; height: 24px; border-radius: 50%; border: 2px solid var(--panel); font: 700 9px/20px var(--mono); letter-spacing: 0.3px; text-align: center; }
.aim + .aim { margin-top: -7px; }
.aim.you { color: var(--you); background: #1d3532; box-shadow: inset 0 0 0 1px rgba(127, 209, 199, 0.55); }
.aim.crew { color: var(--daemon); background: #2c2440; box-shadow: inset 0 0 0 1px rgba(195, 166, 255, 0.5); }
/* Your avatar previewing the command you're typing: dashed, breathing; red if it wouldn't go through. */
.aim.you.preview { box-shadow: 0 0 0 1px var(--you), 0 0 10px rgba(127, 209, 199, 0.5); outline: 1px dashed var(--you); outline-offset: 2px; animation: aim-preview 1.1s ease-in-out infinite; }
.aim.you.preview.bad { color: var(--hot); background: rgba(255, 91, 61, 0.12); box-shadow: 0 0 0 1px var(--hot); outline-color: var(--hot); animation: none; }
@keyframes aim-preview { 50% { box-shadow: 0 0 0 1px var(--you), 0 0 16px rgba(127, 209, 199, 0.8); } }
.no-motion .aim.you.preview { animation: none; }
/* Hit effects (hitfx.mjs), on a layer over the board: the strike lands on the part's own cell in
   the shooter's colour (flash, slash, jolt); a crit slashes twice; a chit flashes white; a miss shakes. */
#hitfx { position: absolute; pointer-events: none; z-index: 3; overflow: visible; }
.fx-smash { position: absolute; overflow: hidden; border-radius: 3px; animation: fx-smash 0.35s ease-out forwards; }
.fx-smash.crit { animation: fx-smash-crit 0.5s ease-out forwards; }
.fx-smash.chit { animation: fx-smash-chit 0.3s ease-out forwards; }
.fx-smash.miss { animation: none; }
@keyframes fx-smash { 0% { background: rgba(255, 236, 190, 0.32); } 100% { background: rgba(255, 236, 190, 0); } }
@keyframes fx-smash-crit { 0% { background: rgba(255, 240, 200, 0.6); box-shadow: inset 0 0 0 2px #fff2c8, 0 0 22px rgba(255, 216, 92, 0.8); } 100% { background: rgba(241, 185, 47, 0); box-shadow: none; } }
@keyframes fx-smash-chit { 0% { background: rgba(255, 255, 255, 0.45); } 100% { background: rgba(255, 255, 255, 0); } }
/* The burst: 1s and 0s fly out of the part's centre and fade (crit: more, bigger, gold-white). */
.fx-bit { position: absolute; z-index: 2; font: 700 16px/1 var(--mono); color: var(--amber); text-shadow: 0 0 6px rgba(241, 185, 47, 0.9); transform: translate(-50%, -50%); animation: fx-bit var(--d, 0.6s) cubic-bezier(0.15, 0.7, 0.3, 1) forwards; }
.fx-bit.crew { color: var(--daemon); text-shadow: 0 0 6px rgba(195, 166, 255, 0.85); }
.fx-bit.crit { color: #fff2c8; font-size: 20px; text-shadow: 0 0 8px rgba(255, 216, 92, 1); }
.fx-bit.chit { color: #fff; font-size: 13px; text-shadow: 0 0 5px rgba(255, 255, 255, 0.8); }
@keyframes fx-bit { 0% { transform: translate(-50%, -50%) scale(0.6); opacity: 1; } 60% { opacity: 1; } 100% { transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) scale(var(--s, 1)) rotate(var(--r, 0deg)); opacity: 0; } }
.bname.fx-jolt { animation: fx-jolt 0.32s ease-out; }
.bname.fx-jolt.crit { animation: fx-jolt-crit 0.45s ease-out; }
.bname.fx-jolt.miss { animation: fx-jolt-miss 0.4s ease-out; }
@keyframes fx-jolt { 0% { filter: brightness(1.9); text-shadow: 0 0 8px currentColor; } 100% { filter: none; text-shadow: none; } } /* light, never movement */
@keyframes fx-jolt-crit { 0%, 30% { filter: brightness(2.3); text-shadow: 0 0 12px rgba(255, 216, 92, 0.9); } 100% { filter: none; text-shadow: none; } }
@keyframes fx-jolt-miss { 0%, 100% { opacity: 1; } 40% { opacity: 0.6; } }
/* Ability effects (abilityfx.mjs), on one layer over the whole page, fixed like #lash and placed at the board's corner
   and scaled with it (so its pixels are the board's): ASCII pieces and characters that travel from the ability's key in
   the tray (your bar when it isn't on screen) to a part's name cell (for a moment: each is gone within about a second) or play on your
   own bar. Text only, no background, no input. Teal: you; a crit gold-white; a hit on ◆ steel; a crewmate's violet
   (as .fx-bit.crew). Each piece is placed and moved by its own animation (layout() in abilityfx.mjs), so its box is
   exact: line-height and character width are the module's CW and LH. */
#abilityfx { position: fixed; left: 0; top: 0; width: 0; height: 0; z-index: 46; pointer-events: none; overflow: visible; transform-origin: 0 0; }
.afx { position: absolute; display: block; left: 0; top: 0; margin: 0; padding: 0; opacity: 0; pointer-events: none; user-select: none; white-space: pre; font-family: var(--mono); font-weight: 700; line-height: 1.05; letter-spacing: 0; color: var(--you); text-shadow: 0 0 6px rgba(127, 209, 199, 0.75); will-change: transform, opacity; }
.afx > i { position: absolute; left: 0; top: 0; font-style: normal; }
.afx.art { text-shadow: 0 0 8px rgba(127, 209, 199, 0.85), 0 0 2px rgba(0, 0, 0, 0.9), 0 0 16px rgba(127, 209, 199, 0.35); }
.afx.echo, .afx.ghost { color: rgba(127, 209, 199, 0.8); }
.afx.flame.hot, .afx.flash { color: #e4fffb; text-shadow: 0 0 8px rgba(127, 209, 199, 1); }
.afx.ember { font-weight: 600; }
.afx.cut, .afx.streak:not(.echo) { color: #e4fffb; text-shadow: 0 0 2px rgba(0, 0, 0, 0.9), 0 0 8px rgba(127, 209, 199, 1); }
.afx.wall { color: #e4fffb; text-shadow: 0 0 2px rgba(0, 0, 0, 0.95), 0 0 6px rgba(127, 209, 199, 0.9); } /* Firewall's bricks: they read over your bar's teal fill */
/* Mastery tiers (mastery.mjs): tier 3's particles brighter, its marks (a scar, a glint) and cinders white-hot. A crit, a crewmate's and ◆ still win below. */
.afx.bright { color: #c9fff6; text-shadow: 0 0 8px rgba(127, 209, 199, 1); }
.afx.scar, .afx.glint, .afx.cinder { color: #e4fffb; text-shadow: 0 0 2px rgba(0, 0, 0, 0.9), 0 0 10px rgba(127, 209, 199, 1); }
.afx.crit { color: #fff2c8; text-shadow: 0 0 8px rgba(255, 216, 92, 1); }
.afx.chit { color: var(--steel); text-shadow: 0 0 6px var(--steel-glow); }
.afx.crew { color: var(--daemon); text-shadow: 0 0 6px rgba(195, 166, 255, 0.85); }
/* Look C (abilityfx.mjs, abilitylight.mjs): a piece burns white-hot where it makes contact and cools (.hot, a copy of it
   that shows from its contact on); what it does there is drawn in light on an SVG of its own in the layer (.alight). */
.afx.hot { color: #e4fffb; text-shadow: 0 0 6px rgba(228, 255, 251, 0.9), 0 0 14px rgba(127, 209, 199, 0.9); }
.afx.hot.crit { color: #fff6dc; text-shadow: 0 0 6px rgba(255, 246, 220, 0.9), 0 0 14px rgba(255, 216, 92, 0.9); }
.afx.hot.crew { color: #f4efff; text-shadow: 0 0 6px rgba(244, 239, 255, 0.9), 0 0 14px rgba(195, 166, 255, 0.9); }
#abilityfx .alight { position: absolute; left: 0; top: 0; width: 1px; height: 1px; overflow: visible; pointer-events: none; mix-blend-mode: screen; }
.no-motion #abilityfx { display: none; }
/* The ability effects playtest's panel (?playtest=fx, abilityfx-playtest.mjs): developer only, beside the board. */
#fx-playtest { position: fixed; right: 16px; bottom: 16px; z-index: 60; width: min(380px, calc(100vw - 32px)); max-height: calc(100vh - 32px); overflow: auto; padding: 12px; background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--r-card); font: 12px/1.3 var(--mono); color: var(--text); }
#fx-playtest h2 { margin: 0 0 8px; font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; color: var(--amber); }
#fx-playtest h2 small { color: var(--dim); text-transform: none; letter-spacing: 0; margin-left: 6px; }
#fx-playtest .fxp-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-bottom: 6px; }
#fx-playtest .fxp-k { width: 100%; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--muted); }
#fx-playtest button { font: inherit; color: var(--text); background: var(--inset); border: 1px solid var(--line); border-radius: var(--r-btn); padding: 3px 8px; cursor: pointer; }
#fx-playtest button.on { border-color: var(--amber); color: var(--bright); }
#fx-playtest .fxp-fx { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; margin-top: 8px; }
#fx-playtest .fxp-fx button { display: flex; flex-direction: column; align-items: flex-start; text-align: left; }
#fx-playtest .fxp-fx small { color: var(--dim); }
#fx-playtest .fxp-said { margin: 8px 0; min-height: 1.3em; color: var(--muted); }
#fx-playtest h3 { margin: 12px 0 4px; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--amber-soft); }
#fx-playtest > button.all { width: 100%; display: flex; gap: 8px; align-items: baseline; }

/* A crewmate's number: smaller and dimmer than yours (Effects: calm). */
.fx-float.quiet { opacity: 0.7; filter: saturate(0.6); }

/* The people panel's Crew tab. */
.people-list .crewmate b { color: var(--daemon); }
.people-list .crew-slot { opacity: 0.55; border-style: dashed; }
.people-list .crew-slot b { color: var(--muted); font-weight: 500; }

.comms-head .p-acts { display: flex; gap: 10px; }

/* A breach: the Integrity meter flashes red and its BREACH badge pulses (app.js pings every 15 s). */
.meter-integrity.breaching { outline: 2px solid var(--hot); outline-offset: 3px; border-radius: 3px; animation: breach-flash 1s ease-in-out infinite; }
.meter-integrity.breaching .meter-note { background: var(--hot); color: #fff; font-weight: 700; animation: breach-badge 1s steps(1) infinite; }
@keyframes breach-flash { 50% { outline-color: rgba(255, 91, 61, 0.25); box-shadow: 0 0 14px rgba(255, 91, 61, 0.5); } }
@keyframes breach-badge { 50% { opacity: 0.55; } }
.no-motion .meter-integrity.breaching, .no-motion .meter-integrity.breaching .meter-note { animation: none; }

/* A skill's cooldown badge (Skills & Talents). */
.stag.cd { color: var(--text); border-color: var(--line-strong, rgba(241, 185, 47, 0.3)); font-variant-numeric: tabular-nums; }
.stag.cd.none { color: var(--muted); }

/* A bounty on the kill card: gold, with a sheen running across it. */
.sp-row.k-bounty { position: relative; overflow: hidden; border: 1px solid rgba(255, 216, 92, 0.6); border-radius: 3px; background: linear-gradient(90deg, rgba(255, 216, 92, 0.14), rgba(255, 216, 92, 0.04)); }
.sp-row.k-bounty .sp-t, .sp-row.k-bounty .sp-qty, .sp-row.k-bounty .sp-ico { color: var(--next); stroke: var(--next); }
.sp-row.k-bounty::after { content: ''; position: absolute; inset: 0; background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, 0.18) 50%, transparent 70%); transform: translateX(-100%); animation: bounty-sheen 2.4s ease-in-out 0.6s infinite; pointer-events: none; }
@keyframes bounty-sheen { 0% { transform: translateX(-100%); } 45%, 100% { transform: translateX(100%); } }
.no-motion .sp-row.k-bounty::after { animation: none; }

/* Threats on an outpost (swarm, siege, infestation): a box each, with a bar for time left. */
.op-box { border: 1px solid var(--line); border-left: 3px solid var(--hot); border-radius: 3px; background: var(--inset); padding: 8px 10px; display: grid; gap: 6px; margin: 6px 0; }
.op-box.infest { border-left-color: var(--next); }
.op-top { display: flex; align-items: baseline; gap: 8px; } .op-top small { color: var(--muted); }
.op-bar { height: 3px; background: rgba(255, 255, 255, 0.07); border-radius: 2px; overflow: hidden; }
.op-bar span { display: block; height: 100%; background: var(--hot); } .op-box.infest .op-bar span { background: var(--next); }
.op-box .row { margin: 0; }
.mk-up { color: #8fd46b; font-size: 0.8em; margin-left: 0.4em; cursor: help; }
.mk-down { color: #ff6f91; font-size: 0.8em; margin-left: 0.4em; cursor: help; }
.mk-flat { color: var(--dim, #777); font-size: 0.8em; margin-left: 0.4em; cursor: help; }
.mk-tags { gap: 0.4em; margin-bottom: 0.5em; flex-wrap: wrap; }
.mk-tags .tag { cursor: help; }
.craft-list li > span.mk-btns { display: flex; gap: 0.3em; flex-wrap: nowrap; align-items: center; }
.mnode.fleet[data-faction] path { fill: var(--fc); stroke: var(--fc); }
.craft-list .btn { white-space: nowrap; }
.craft-list li.mk-row, .craft-list li.mk-xfer { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 10px; }
.craft-list li > span.mk-ware { display: flex; align-items: center; gap: 8px; }
.mk-have { font: 12px var(--mono); color: var(--dim, #8a8170); }
.mk-have.zero { opacity: 0.45; }
.craft-list li > span.mk-val { display: flex; align-items: center; gap: 5px; font-family: var(--mono); }
.mk-val b { font-size: 15px; }
.mk-val.in b { color: #8fd46b; }
.mk-d { font: 600 11px var(--mono); padding: 1px 5px; border-radius: 3px; cursor: help; border: 1px solid currentColor; }
.mk-d.up { color: #8fd46b; }
.mk-d.down { color: #ff6f91; }
.mk-d.flat { color: var(--dim, #8a8170); }
.xfer-bar { display: block; width: 90px; height: 6px; border: 1px solid var(--line); background: rgba(0,0,0,0.3); }
.xfer-bar i { display: block; height: 100%; background: var(--you, #7fd1c7); }
.xfer-bar.hot i { background: var(--hot); }
.pips { font-size: 11px; letter-spacing: 1px; color: var(--hot); }
.mk-ware .iname { white-space: nowrap; }
/* Hub sessions: a terminal like any server's; a menu choice opens its window beside it. */
.hub-session { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; height: 100%; }
.hub-session.with-win { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); }
.hub-session .hub-term { height: 100%; min-height: 420px; }
.hub-session .hub-win { max-height: 100%; overflow: auto; }
.hub-term .net-head { display: flex; align-items: center; gap: 12px; }
.hub-term .net-head .net-where { display: flex; align-items: center; gap: 8px; color: var(--fc); }
.hub-term .net-head .repbar { flex: 1; margin: 0; }
.term li.hub-banner { display: flex; align-items: center; gap: 16px; margin: 8px 0; }
.hub-ascii { margin: 0; font: 12px/1.15 var(--mono); color: var(--fc); }
.hub-motd { display: flex; align-items: center; gap: 8px; }
.hub-motd b { color: var(--fc); letter-spacing: 0.08em; }
.term li.hub-say { margin: 6px 0 10px; }
.term li.hub-say b { color: var(--fc); }
.term li.hub-menu { display: grid; gap: 2px; margin: 4px 0 6px; max-width: 420px; }
.hub-row { display: grid; grid-template-columns: 2.4em 1fr auto; align-items: center; gap: 10px; padding: 5px 10px; background: none; border: 1px solid transparent; border-radius: 3px; color: var(--text); font: 15px var(--mono); text-align: left; cursor: pointer; }
.hub-row:hover, .hub-row:focus-visible, .hub-row.on { border-color: var(--fc); background: color-mix(in srgb, var(--fc) 10%, transparent); color: var(--bright); }
.hub-row .hn { color: var(--fc); }
.hub-row .hn::before { content: '['; opacity: 0.6; }
.hub-row .hn::after { content: ']'; opacity: 0.6; }
.hub-row .hm { color: var(--muted); font-size: 13px; display: inline-flex; align-items: center; gap: 3px; }
.hub-win h2 { display: flex; justify-content: space-between; align-items: center; }
.hub-win h2 .x { margin-left: auto; }
.hub-term .net-head .net-where { flex-direction: row; }
.hub-term .net-where b { color: var(--fc); }
/* The Market window: aligned tables. Price is the loudest thing on a row, then the name; the rest is muted. */
.mk-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 14px; }
.mk-sec { margin: 18px 0 6px; font: 600 11px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.mk-table { display: grid; font-variant-numeric: tabular-nums; }
.mk-tr { display: grid; align-items: center; column-gap: 10px; padding: 7px 8px; border-bottom: 1px solid var(--line); min-height: 40px; }
.mk-tr:not(.mk-th):hover { background: color-mix(in srgb, var(--fc, var(--line)) 7%, transparent); }
.mk-wares .mk-tr { grid-template-columns: minmax(90px, 1fr) 36px 44px 58px 44px 44px 52px; }
.mk-goods .mk-tr { grid-template-columns: minmax(0, 1fr) 52px 74px; }
.mk-xfers .mk-tr { grid-template-columns: minmax(90px, 1fr) 58px 140px; }
.mk-th { min-height: 0; padding-top: 0; padding-bottom: 6px; font: 600 10px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); border-bottom-color: var(--line-strong, var(--line)); }
.mk-th .mk-span2 { grid-column: span 2; text-align: center; }
.mk-th span:last-child { text-align: center; }
.mk-name { display: flex; align-items: center; gap: 9px; min-width: 0; color: var(--muted); }
.mk-name b { font: 600 14px var(--sans, inherit); color: var(--bright); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mk-name .mk-sub { font: 12px var(--mono); color: var(--muted); }
.mk-num { text-align: right; font-family: var(--mono); }
.mk-held { font-size: 13px; color: var(--text); }
.mk-held.zero { color: var(--muted); opacity: 0.5; }
.mk-price { font-size: 16px; font-weight: 700; color: var(--bright); }
.mk-price.in { color: #8fd46b; }
.mk-tr .btn.small { width: 100%; justify-content: center; padding-left: 0; padding-right: 0; font-variant-numeric: tabular-nums; }
.mk-tr .mk-lock { justify-self: stretch; text-align: center; }
.mk-tr.locked .mk-name b { color: var(--muted); }
.mk-dir { color: var(--muted); font-family: var(--mono); }
.mk-tr .xfer-bar { width: 100%; }
.mk-d { display: inline-block; min-width: 50px; text-align: center; }
/* The map's pop-up card, beside the node you clicked. */
.map-canvas { position: relative; }
.map-pop { position: absolute; z-index: 5; width: 330px; max-height: calc(100% - 16px); overflow: auto; filter: drop-shadow(0 12px 30px rgba(0, 0, 0, 0.65)); }
.map-pop > .card { margin: 0; background: var(--panel, #120f0a); }
.map-pop > .card + .card { margin-top: 8px; }
.map-pop-x { position: absolute; top: 10px; right: 10px; z-index: 1; }
/* The server card: one line per thing, label | bar | number. */
.srv-card h2 { display: flex; align-items: center; gap: 8px; padding-right: 36px; }
.srv-line { display: grid; grid-template-columns: 104px minmax(0, 1fr) auto; align-items: center; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--line); }
.srv-k { display: flex; align-items: center; gap: 7px; font: 12px var(--mono); letter-spacing: 0.04em; color: var(--muted); }
.srv-v { min-width: 0; }
.srv-n { font: 600 14px var(--mono); color: var(--bright); font-variant-numeric: tabular-nums; text-align: right; min-width: 52px; }
.srv-n small { font-weight: 400; color: var(--muted); font-size: 11px; }
.srv-line .srv-bar { display: block; height: 7px; border: 1px solid var(--line); background: rgba(0, 0, 0, 0.3); }
.srv-line .srv-bar > span { display: block; height: 100%; background: var(--you); }
.srv-line .srv-bar.xp > span { background: var(--amber); }
.srv-line .srv-bar.hp.mid > span { background: var(--amber); }
.srv-line .srv-bar.hp.low > span { background: var(--hot); }
.srv-line .wall-ruler { margin: 0; }
.pip-row { display: flex; gap: 3px; }
.pip-row i { width: 10px; height: 10px; border: 1px solid var(--line-strong, var(--muted)); }
.pip-row i.on { background: var(--you); border-color: var(--you); }
.srv-svc { padding: 10px 0 10px; border-bottom: 1px solid var(--line); }
.srv-svc-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.srv-svc-head span { display: flex; align-items: center; gap: 7px; font: 600 12px var(--mono); letter-spacing: 0.06em; color: var(--text); text-transform: uppercase; }
.srv-svc-head small { font: 600 13px var(--mono); color: var(--bright); }
.svc-strip { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 5px; }
.svc-tile { aspect-ratio: 1; display: grid; place-items: center; align-content: center; gap: 1px; border: 1px solid var(--line-strong, var(--line)); border-radius: 3px; color: var(--you); }
.svc-tile small { font: 10px var(--mono); color: var(--muted); }
.svc-tile.on { background: color-mix(in srgb, var(--you) 10%, transparent); border-color: color-mix(in srgb, var(--you) 55%, transparent); }
.svc-tile.busy { border-style: dashed; color: var(--amber); }
.svc-tile.free { border-style: dashed; opacity: 0.45; }
/* Combat: the timeline is the main event; the log is a short strip under it. */
.combat { grid-template-rows: auto auto minmax(88px, 1fr); } /* the board as tall as its parts (three, four with a boss's add); the log takes the rest */
.combat .board { max-height: calc(100dvh - 300px); }
.combat .board { min-height: 0; }
.combat .board { background-image: radial-gradient(rgba(240, 226, 182, 0.07) 1px, transparent 1.4px); background-size: 12px 12px; background-position: 6px 6px; } /* a faint dot grid behind the timeline */
.combat .brow:not(.bhead) > .bcell { padding-top: 11px; padding-bottom: 11px; }
.combat .intent { padding: 7px 9px; font-size: 14px; }
.combat .intent .ico { width: 16px; height: 16px; }
.combat .log { font-size: 12px; }
body.fight-over .combat { grid-template-rows: auto minmax(0, 1fr); }
/* The side panel (only the party, in a fight with a crew): its own surface, so it always reads as the side. */
#sidebar { background: color-mix(in srgb, var(--inset) 80%, #000); border-right: 1px solid var(--line-strong, var(--line)); box-shadow: inset -12px 0 18px -14px rgba(0, 0, 0, 0.8); padding: 10px; }
#sidebar .sb-block { background: transparent; border-color: var(--line); }
.combat .brow:not(.bhead) { min-height: 68px; }
/* Pop-up cards never show scrollbars: nothing scrolls sideways, and a tall one scrolls without a bar. */
.gain .sp-card, .map-pop, .hub-session .hub-win { overflow-x: hidden; overflow-y: auto; scrollbar-width: none; }
.gain .sp-card::-webkit-scrollbar, .map-pop::-webkit-scrollbar, .hub-session .hub-win::-webkit-scrollbar { display: none; }
/* Top bar: a short rule between each meter. */
.meters { gap: 0; }
.meters > .meter { padding: 0 16px; }
.meters > .meter:not([hidden]) ~ .meter:not([hidden]) { border-left: 1px solid var(--line-strong, var(--line)); }
.meters > .meter { align-self: center; padding-top: 3px; padding-bottom: 3px; }
/* The crew window: a small floating panel, dragged by its title bar. */
.crewwin { position: fixed; z-index: 30; width: 240px; background: color-mix(in srgb, var(--inset) 85%, #000); border: 1px solid var(--line-strong, var(--line)); border-radius: 4px; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6); }
.cw-head { display: flex; align-items: center; gap: 8px; padding: 7px 8px 7px 12px; cursor: grab; user-select: none; touch-action: none; border-bottom: 1px solid var(--line); }
.cw-head:active { cursor: grabbing; }
.cw-head b { font: 600 11px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--text); }
.cw-head small { font: 11px var(--mono); color: var(--muted); }
.cw-btn { margin-left: auto; background: none; border: 1px solid transparent; color: var(--muted); cursor: pointer; font-size: 12px; width: 22px; height: 22px; border-radius: 3px; }
.cw-btn:hover { border-color: var(--line); color: var(--bright); }
.cw-body { padding: 10px 12px 12px; }
.cw-body .party { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; }
.crewwin:has(.cw-body) .cw-head { border-bottom-color: var(--line); }
.crewwin:not(:has(.cw-body)) .cw-head { border-bottom: 0; }
.crewwin .party .pmate, .crewwin .party .pmate + .pmate { border-left: 0; padding-left: 0; margin: 0; }
/* Crew window rows: name left, class + level right, flush with the bar's right end; nothing moves. */
.crewwin .party .pmate { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; row-gap: 3px; padding: 6px 0; border-top: 1px solid var(--line); }
.crewwin .party .pmate:first-child { border-top: 0; padding-top: 0; }
.crewwin .pmate > b { font-size: 13px; }
.crewwin .pmate .pm-cls { justify-self: end; text-align: right; color: var(--muted); font-size: 11px; }
.crewwin .pmate .pm-lv { color: var(--text); margin-left: 4px; }
.crewwin .pmate .pbar, .crewwin .pmate .pm-intent, .crewwin .pmate .pm-tag { grid-column: 1 / -1; }
.crewwin .pmate > small:not(.pm-cls) { grid-column: 1 / -1; color: var(--muted); font-size: 11px; }
.crewwin .pmate, .crewwin .pmate * { animation: none !important; transform: none !important; }
.crewwin .pmate.fx-hurt, .crewwin .pmate.hurt { outline: 1px solid var(--hot); }
.cw-btn { display: grid; place-items: center; padding: 0; line-height: 1; font-size: 11px; }
/* Pinned crew window (top left) and its docked twin in a fight's side column. */
.cw-head { cursor: default; }
body.with-sidebar .workspace { grid-template-columns: 230px minmax(0, 1fr); }
#sidebar .crewwin.docked { position: static; width: auto; box-shadow: none; border: 0; background: none; }
#sidebar .crewwin.docked .cw-btn { display: none; }
/* Costs: one component per line. */
.needs { flex-direction: column; flex-wrap: nowrap; align-items: flex-start; gap: 4px; }
/* The crew column: narrow, on every page while you have a crew. */
body.with-sidebar .workspace { grid-template-columns: 200px minmax(0, 1fr); }
#sidebar { padding: 8px 8px 8px 4px; }
#sidebar .crewwin.docked .cw-head { padding-left: 6px; }
#sidebar .crewwin.docked .cw-body { padding: 8px 6px 10px; }
.p-ico { width: 15px; height: 15px; flex: none; fill: none; stroke: var(--you); stroke-width: 1.5; stroke-linecap: round; filter: drop-shadow(0 0 3px color-mix(in srgb, var(--you) 60%, transparent)); }
.people-btn.friends-on .p-ico { stroke: var(--daemon); }
/* Top bar meters: the class level lives on the Loadout page now; every meter the same box. */
#meter-level { display: none !important; }
.meters > .meter, .meters > .meter[data-command] { padding: 4px 14px; margin: 0; min-height: 28px; align-items: center; border-radius: 0; }
.meter[data-command]:hover, .meter[data-command]:focus-visible { outline: 1px solid var(--line-strong); outline-offset: -2px; border-radius: 4px; }
.meters > .meter:not([hidden]) ~ .meter:not([hidden]) { border-left: 1px solid var(--line-strong, var(--line)); }
.meter strong { font-variant-numeric: tabular-nums; }
/* Your server on the map: the server glyph (two racks), not a square. */
.mnode.server .srv-glyph rect { fill: rgba(127, 209, 199, 0.12); stroke: var(--you); stroke-width: 1; }
.mnode.server .srv-glyph path { stroke: var(--you); stroke-width: 1.6; stroke-linecap: round; }
/* Run controls in the crew column. */
.crewwin .pmate .pm-run { grid-column: 1 / -1; display: flex; justify-content: space-between; align-items: center; gap: 6px; margin-top: 2px; }
.pm-where { display: flex; align-items: center; gap: 5px; min-width: 0; font-size: 11px; color: var(--muted); }
.pm-where code { font: 11px var(--mono); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm-where .cs-link { color: var(--daemon); }
.pm-acts { display: flex; gap: 2px; flex: none; }
.pm-acts .act { padding: 2px 5px; font-size: 11px; }
.cw-foot { display: flex; justify-content: flex-end; margin-top: 8px; padding-top: 6px; border-top: 1px solid var(--line); }
.cw-foot .act { font-size: 11px; }
/* Whose half of the cycle: a strip across the top of the board names it; only the virus's half turns the board red. */
.phase-strip { display: flex; align-items: center; gap: 10px; padding: 6px 14px; margin: -4px 0 4px; font: 600 11px var(--mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--dim); border-bottom: 1px solid var(--line); }
.phase-strip i { font-style: normal; opacity: 0.6; }
/* a runner's countdown (the Exfil's upload): its own board row; on a phone, where rows are dear, on the strip instead */
.phase-strip .ps-esc { display: none; margin-left: auto; color: var(--next); font-weight: 700; letter-spacing: 0.08em; }
@media (max-width: 640px) { .board .bescape { display: none; } .phase-strip .ps-esc { display: inline; } }
.phase-strip .ps-obj { margin-left: 8px; padding: 1px 7px; border: 1px solid currentColor; border-radius: 2px; color: var(--next); font-weight: 700; letter-spacing: 0.08em; }
.phase-strip .ps-obj.met { color: var(--amber); } .phase-strip .ps-obj.failed { color: var(--muted); font-weight: 400; }
.phase-strip .ps-obj.ob-backup:not(.met) { color: var(--backup); } .phase-strip .ps-obj.ob-clean.failed { text-decoration: line-through; }
/* The Backup (objectives.mjs): its own row under yours, ivory, a segmented bar; an attack coming for it wears its stripe and disk. */
.bbackup { background: rgba(233, 226, 207, 0.06); box-shadow: inset 3px 0 0 var(--backup); }
.bbackup .part-name { display: inline-flex; align-items: center; gap: 6px; }
.bbackup .part-name b, .bbackup .part-hp { color: var(--backup); font-weight: 600; }
.bbackup .part-bar span { background: repeating-linear-gradient(90deg, var(--backup) 0 10px, transparent 10px 12px); }
.bbackup.lost { opacity: 0.45; }
.bk-ico { width: 13px; height: 13px; flex: none; color: var(--backup); }
.intent.to-bk { box-shadow: inset 3px 0 0 var(--backup); }
.intent.to-bk .bk-ico { margin-right: 4px; vertical-align: -2px; }
.phase-strip span { padding: 2px 8px; border-radius: 2px; border: 1px solid transparent; }
.phase-strip.ph-wait .ps-you { color: var(--you); border-color: color-mix(in srgb, var(--you) 50%, transparent); }
.phase-strip.ph-you .ps-you { color: var(--bg); background: var(--you); }
.phase-strip.ph-them .ps-them { color: var(--bg); background: var(--hot); }
#board { transition: background-color 0.2s, box-shadow 0.2s; }
body.phase-them #board { background-color: color-mix(in srgb, var(--hot) 7%, var(--panel)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--hot) 55%, transparent); }
body.phase-them .board { --band-line: var(--hot); --band-edge: rgba(255, 91, 61, 0.55); }
body.phase-them .brow.byou { opacity: 0.6; transition: opacity 0.2s; }
/* No surprise scrollbars on the board: it scrolls (wheel) only when parts don't fit, without a bar. */
#board { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; } /* a thin bar, so a part below the fold isn't hidden */
/* The prompt: lit when it's your move, dim while the virus acts. */
.prompt.acting { color: var(--hot); opacity: 0.85; }
body.phase-them #command-input { opacity: 0.5; }
body.phase-wait .cmdline, body.phase-wait #command-input { box-shadow: 0 0 0 1px color-mix(in srgb, var(--you) 40%, transparent); }
/* Who did it to what: the actor's row and the target light in the side's colour. */
.brow.side-them { box-shadow: inset 3px 0 0 var(--hot), inset 0 0 0 1px color-mix(in srgb, var(--hot) 55%, transparent); background: color-mix(in srgb, var(--hot) 10%, transparent); }
.hud-bar.side-them { box-shadow: 0 0 0 1px var(--hot), 0 0 14px color-mix(in srgb, var(--hot) 45%, transparent); }
.hud-bar.side-you { box-shadow: 0 0 0 1px var(--you); }
/* The log by side. */
#log li.side-you, .log li.side-you { border-left: 2px solid var(--you); padding-left: 6px; }
#log li.side-them, .log li.side-them { border-left: 2px solid var(--hot); padding-left: 6px; }
/* Crew on a run: state chip, where they are, actions; remove sits top right. */
.crewwin .pmate, .sidebar .pmate { position: relative; }
.pm-st { font-size: 10px; padding: 0 5px; line-height: 16px; flex: none; }
.pm-kick { position: absolute; top: 2px; right: 2px; width: 18px; height: 18px; display: grid; place-items: center; padding: 0; border: 0; background: none; color: var(--dim); font-size: 14px; line-height: 1; cursor: pointer; border-radius: 3px; }
.pm-kick:hover { color: var(--bad, #e66); background: rgba(255,255,255,0.06); }
/* A found server's Connect: memory now → after (new slots outlined bright; past the cap, red). */
.mem-join i.add { border-color: var(--amber); background: rgba(241, 185, 47, 0.25); animation: memadd 1.2s ease-in-out infinite; }
.mem-join i.x { border-color: var(--bad, #e66); background: rgba(230, 102, 102, 0.35); }
.mem-join.over small b { color: var(--bad, #e66); }
.mem-join small { margin-left: 4px; } .mem-join .mj-to { margin: 0 3px; color: var(--dim); } .mem-join small b { color: var(--text); }
.mem-card.asking .srv-slots { outline: 1px solid rgba(241, 185, 47, 0.35); border-radius: 4px; padding: 4px 6px; }
@keyframes memadd { 50% { background: rgba(241, 185, 47, 0.6); } }
@media (prefers-reduced-motion: reduce) { .mem-join i.add { animation: none; } }
/* A locked row: dimmed. */
.craft-list li.locked > span { opacity: 0.55; }
/* Installing a harvester on an outpost: slots, then one row per harvester in the rack. */
.op-pick { display: grid; gap: 8px; margin-top: 8px; }
.op-rack { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.op-rack li { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: 4px; background: var(--inset); }
.op-h { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; font-size: 13px; }
.op-h b { color: var(--text); font-weight: 600; }
.op-h .glyph { width: 15px; height: 15px; color: var(--amber); }
.op-h .tag { font-size: 10px; line-height: 16px; padding: 0 5px; }
.op-rack .btn { flex: none; padding: 5px 12px; }
.mod.add small { margin-left: 4px; color: var(--muted); font: 10px var(--mono); }
/* Halcyon's plans: one row each. */
.plan-shelf { list-style: none; margin: 0; padding: 0; }
.plan-shelf li { display: grid; grid-template-columns: 1fr auto 56px 52px; align-items: center; gap: 10px; padding: 7px 2px; border-top: 1px solid var(--line); font-size: 13px; }
.plan-shelf li:last-child { border-bottom: 1px solid var(--line); }
.plan-shelf .iname { display: flex; align-items: center; gap: 6px; }
.plan-shelf .iname .glyph { width: 15px; height: 15px; color: var(--amber); }
.plan-shelf .price { font: 600 12px var(--mono); text-align: right; color: var(--text); }
.plan-shelf li.known { opacity: 0.6; }
.plan-shelf li.known .tag.you { grid-column: 3 / 5; justify-self: end; }
.plan-shelf .tag { font-size: 10px; line-height: 16px; padding: 0 5px; }
.craft-list .iname .tag.you { margin-left: 8px; font-size: 10px; line-height: 16px; padding: 0 5px; }
/* A broken part's last moment: its row flickers out and becomes 1s and 0s that rise off (hitfx.mjs). */
.brow.dying { pointer-events: none; animation: part-dissolve 1s steps(10, end) forwards; }
.brow.dying .bname { color: var(--amber); }
.brow.dying .part-top { visibility: hidden; } /* its letters are breaking up on the effects layer (hitfx.mjs) */
.fx-cell { font: 600 11px/1 var(--mono); color: var(--amber); }
.fx-letter { position: absolute; z-index: 2; transform: translate(-50%, -50%); white-space: pre; pointer-events: none; text-shadow: 0 0 6px rgba(241, 185, 47, 0.7); }
@keyframes part-dissolve { /* a flash, a flicker, then gone: its 1s and 0s take its place (hitfx.mjs) */
  0% { opacity: 1; background: rgba(255, 236, 190, 0.25); }
  10% { opacity: 0.5; }
  15% { opacity: 1; }
  25%, 100% { opacity: 0; background: transparent; }
}
.fx-bit.dissolve { opacity: 0; animation-fill-mode: both; color: var(--amber); font-size: 14px; text-shadow: 0 0 6px rgba(241, 185, 47, 0.8); }
@media (prefers-reduced-motion: reduce) { .brow.dying { animation: none; opacity: 0.3; } }
/* The server card's two levels: the server's (amber), your class's under it (your colour). */
.srv-line .srv-bar.xp.you > span { background: var(--you); }
.srv-line .srv-n small { color: var(--dim); font-weight: 500; margin-right: 2px; }
/* HOME's two level bars on the map: the server's (amber), your class's under it (your colour). */
.mbars { transform: scale(calc(1 / var(--z, 1))); }
.mnode.server .mbars rect { stroke-width: 0.6; }
.mnode.server .mbars .srv .hb-track { fill: rgba(241, 185, 47, 0.1); stroke: rgba(241, 185, 47, 0.35); }
.mnode.server .mbars .srv .hb-fill { fill: var(--amber); stroke: none; }
.mnode.server .mbars .you .hb-track { fill: rgba(127, 209, 199, 0.08); stroke: rgba(127, 209, 199, 0.35); }
.mnode.server .mbars .you .hb-fill { fill: var(--you); stroke: none; }
.mbars .hb-n { font: 600 9px var(--mono); }
.mbars .srv .hb-n { fill: var(--amber); } .mbars .you .hb-n { fill: var(--you); }
/* Top centre: who you are. Handle · class · level, the class's XP as a thin bar under it. */
.whoami { margin: 0 auto; display: grid; grid-template-columns: auto auto auto auto auto; align-items: baseline; column-gap: 7px; row-gap: 3px; font: 600 12px var(--mono); letter-spacing: 0.06em; color: var(--muted); }
.whoami #who-handle { color: var(--bright); letter-spacing: 0.08em; }
.whoami #who-class { color: var(--you); text-transform: uppercase; font-size: 11px; letter-spacing: 0.14em; }
.whoami .who-lv { color: var(--muted); font-size: 11px; } .whoami .who-lv b { color: var(--bright); font-size: 13px; }
.whoami .who-dot { color: var(--dim); }
.whoami .who-bar { grid-column: 1 / -1; height: 3px; background: rgba(127, 209, 199, 0.12); border-radius: 2px; overflow: hidden; }
.whoami .who-bar span { display: block; height: 100%; background: var(--you); }
/* The pager sits by the server's meters now, just left of Integrity. */
.topbar .pager { margin-left: 0; }
@media (max-width: 900px) { .whoami { display: none; } }
/* Mail: delivered contracts and LOWLIGHT jobs, greyed, under Completed (newest first). */
.mdone-head { color: var(--dim); }
.mlist.mdone .mrow { opacity: 0.5; filter: grayscale(0.85); }
.mlist.mdone .mrow:hover, .mlist.mdone .mrow.open { opacity: 0.8; }
/* HOME's Integrity bar on the map. */
.mnode.server .mbars .hp .hb-track { fill: rgba(127, 209, 199, 0.08); stroke: rgba(127, 209, 199, 0.35); }
.mnode.server .mbars .hp .hb-fill { fill: var(--you); stroke: none; }
.mnode.server .mbars .hp.mid .hb-fill { fill: var(--amber); }
.mnode.server .mbars .hp.low .hb-fill { fill: var(--hot); }
/* A status landing: its chip flies from the middle of the board into the Status column. */
.st.st-fly { position: fixed; z-index: 60; pointer-events: none; margin: 0; box-sizing: border-box; text-align: center; box-shadow: 0 0 18px currentColor; background: var(--panel); }
.st.st-land { animation: st-land 0.45s ease-out; }
@keyframes st-land { 0% { transform: scale(1.25); filter: brightness(1.8); } 100% { transform: none; filter: none; } }
/* A run listing: a virus or guarded folder that counts for a contract gets a small marker. */
.ls-job { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; margin-left: 6px; color: var(--amber); vertical-align: middle; cursor: help; animation: ls-job 2.4s ease-in-out infinite; filter: drop-shadow(0 0 3px rgba(241, 185, 47, 0.5)); }
.ls-job .glyph { width: 17px; height: 17px; }
.ls-job .glyph * { stroke-width: 1.9; }
@keyframes ls-job { 50% { box-shadow: 0 0 8px rgba(241, 185, 47, 0.55); } }
@media (prefers-reduced-motion: reduce) { .ls-job { animation: none; } }
/* A run's Leads panel: the terminal on the left, every trace in progress on the right. */
.net-body { flex: 1; min-height: 0; display: flex; }
.net-body > .term { flex: 1; min-width: 0; }
.net-leads { flex: none; width: 250px; border-left: 1px solid var(--line); padding: 12px 14px; overflow-y: auto; background: rgba(0, 0, 0, 0.18); }
.net-leads h3 { display: flex; align-items: center; gap: 6px; margin: 0 0 10px; font: 600 11px var(--mono); letter-spacing: 1.5px; text-transform: uppercase; color: var(--amber); }
.net-leads h4 { margin: 14px 0 6px; font: 600 10px var(--mono); letter-spacing: 1.2px; text-transform: uppercase; color: var(--dim); }
.net-leads .glyph { width: 13px; height: 13px; flex: none; }
.ld-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.ld-row { display: grid; grid-template-columns: 14px 1fr auto; grid-template-rows: auto auto; column-gap: 7px; row-gap: 3px; align-items: center; padding: 5px 6px; border-radius: 3px; cursor: pointer; font-size: 12px; }
.ld-row:hover { background: rgba(241, 185, 47, 0.07); }
.ld-row .ld-name { color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ld-row .ld-name small { color: var(--dim); font: 10px var(--mono); }
.ld-row .ld-bar { grid-column: 2 / 3; height: 4px; background: rgba(241, 185, 47, 0.12); border-radius: 2px; overflow: hidden; }
.ld-row .ld-bar span { display: block; height: 100%; background: var(--amber); }
.ld-row .ld-n { grid-column: 3; grid-row: 1 / 3; font: 600 12px var(--mono); color: var(--bright); }
.ld-row .ls-job { grid-column: 3; grid-row: 1; margin: 0; width: 16px; height: 16px; }
.ld-row.wanted .ld-n { grid-row: 2; font-size: 11px; }
.net-leads-btn { display: inline-flex; align-items: center; gap: 5px; }
.net-leads-btn[aria-pressed="true"] { border-color: var(--amber); color: var(--amber); }
@media (max-width: 900px) { .net-body.with-leads { flex-direction: column; } .net-leads { width: auto; border-left: 0; border-top: 1px solid var(--line); max-height: 40%; } }
/* Class cards: Use sits in the corner of any class you aren't playing. */
/* A hub's Compile list: each payload's costs on one line. */
/* The market: each row is ware · held | sell here (price, vs other hubs, Sell 1 / Sell all) | buy here (price, Buy 1). */
.mk-wares .mk-tr { grid-template-columns: minmax(96px, 1fr) 40px 104px 64px 64px 56px 64px; }
.mk-sellp { display: flex; align-items: baseline; justify-content: flex-end; gap: 8px; }
.mk-sellp .mk-price { font: 700 15px var(--mono); color: var(--bright); }
.mk-buyp { font: 600 14px var(--mono); color: var(--text); text-align: right; padding-left: 12px; border-left: 1px solid var(--line-strong, var(--line)); }
.mk-th .mk-sell-h { grid-column: 3 / 6; text-align: left; padding-left: 14px; color: var(--good, #8fd18f); }
.mk-th .mk-buy-h { grid-column: 6 / 8; text-align: left; padding-left: 12px; border-left: 1px solid var(--line-strong, var(--line)); color: var(--amber); }
.mk-th span:last-child { text-align: left; }
.mk-tr .btn.small { white-space: nowrap; }
/* Tight top bar (a breach's chip, a full pager): the pager's icons and who-you-are give way (pager.css has the pager's steps). */
.topbar.fit-3 .whoami .who-dot, .topbar.fit-3 .whoami #who-class { display: none; }
/* A listing with several files to pull: one button takes them all. */
.ls-all { margin: 2px 0 4px; }
.ls-all .tok.act { font-weight: 600; }
/* The market, calmer: one accent. The percent is plain text (amber ▲ when it pays above average,
   grey otherwise), the headers are grey, every button is the same quiet button. */
.mk-wares .mk-d { border: 0; padding: 0; min-width: 0; font: 600 11px var(--mono); background: none; }
.mk-wares .mk-d.up { color: var(--amber); }
.mk-wares .mk-d.down, .mk-wares .mk-d.flat { color: var(--dim); }
.mk-th .mk-sell-h, .mk-th .mk-buy-h { color: var(--muted); }
.mk-wares .btn.small, .mk-goods .btn.small { border-color: var(--line-strong, var(--line)); color: var(--text); background: transparent; box-shadow: none; }
.mk-wares .btn.small:hover:not([disabled]), .mk-goods .btn.small:hover:not([disabled]) { border-color: var(--amber); color: var(--bright); }
.mk-wares .mk-name .glyph, .mk-goods .mk-name .glyph { color: var(--muted); }
.mk-buyp { color: var(--bright); font-weight: 700; }
.mk-goods .mk-tr { grid-template-columns: minmax(0, 1fr) 52px 64px 74px; }
.mk-goods .mk-gprice { border-left: 0; padding-left: 0; }
/* Header labels sit exactly over their columns. */
.mk-wares .mk-th > span { align-self: end; }
.mk-th .mk-buy-h { padding-top: 0; }
/* A button waiting on its second click: the question, highlighted, on one line it can fit. */
.btn.armed { border-color: var(--hot); color: var(--hot); white-space: normal; text-align: left; max-width: 100%; }
.mk-wares .mk-th > span { align-self: center; }
.mk-th .mk-buy-h { border-left: 0; padding-left: 12px; }
/* Wall and Away rows: the same bar as Integrity. */
.srv-line .srv-bar.wall > span { background: var(--you); }
.srv-line .srv-bar.wall.mid > span { background: var(--amber); }
.srv-line .srv-bar.wall.low > span { background: var(--hot); }
.srv-line .srv-n small { font-weight: 500; }
/* Every server-card row: the same label column, the same bar length, the same number column. */
.srv-line { grid-template-columns: 104px minmax(0, 1fr) 96px; }
.srv-line .srv-n { text-align: right; white-space: nowrap; }
.srv-line .srv-v:empty { display: block; }
/* The market: read-only rows you pick (ware · held · sell here · buy here), and one order ticket under the picked row. */
.mk-wares .mk-tr { grid-template-columns: minmax(110px, 1fr) 56px 110px 84px; }
.mk-th .mk-sell-h { grid-column: auto; padding-left: 0; text-align: right; }
.mk-th .mk-buy-h { grid-column: auto; padding-left: 0; text-align: right; border-left: 0; }
.mk-wares .mk-buyp { border-left: 0; padding-left: 0; }
button.mk-row { width: 100%; background: none; border: 0; border-bottom: 1px solid var(--line); text-align: left; cursor: pointer; color: inherit; font: inherit; }
button.mk-row:hover { background: rgba(241, 185, 47, 0.05); }
button.mk-row.open { background: rgba(241, 185, 47, 0.08); border-bottom-color: transparent; }
.mk-ticket { display: grid; gap: 12px; padding: 12px 14px 14px; margin: 0 0 6px; border: 1px solid rgba(241, 185, 47, 0.35); border-top: 0; background: rgba(241, 185, 47, 0.04); }
.mk-sides { display: inline-flex; gap: 0; border: 1px solid var(--line-strong, var(--line)); border-radius: 4px; overflow: hidden; justify-self: start; }
.mk-side { padding: 5px 16px; background: none; border: 0; color: var(--muted); font: 600 12px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; cursor: pointer; }
.mk-side.on { background: var(--amber); color: var(--bg); }
.mk-slide { display: flex; align-items: center; gap: 10px; }
.mk-slide input[type=range] { flex: 1; accent-color: var(--amber); }
.mk-slide .mk-qty { font: 700 18px var(--mono); color: var(--bright); min-width: 2ch; text-align: right; }
.mk-slide small { color: var(--dim); font: 12px var(--mono); }
.mk-prev { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.mk-prev span { display: grid; gap: 2px; }
.mk-prev small { font: 600 10px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--dim); }
.mk-prev b { font: 700 15px var(--mono); color: var(--bright); }
.mk-prev b.up { color: var(--amber); }
.mk-go { justify-self: end; min-width: 120px; }
.mk-none { margin: 0; color: var(--dim); font: 13px var(--mono); }
@media (max-width: 700px) { .mk-prev { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.mk-prev b.mk-plus { color: var(--bright); }
.mk-wares .mk-tr { grid-template-columns: minmax(110px, 1fr) 56px 120px 100px; }
/* Shops in a hub window: one column, tiles in a grid. */
.hub-win .store-page { display: grid; grid-template-columns: 1fr; gap: 12px; }
.hub-win .ptiles.stash { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
/* A crowded map: minor servers (nothing to do there) are small dim dots; their names come back on
   hover, when selected, or zoomed in. Filters dim everything outside their group (home stays). */
.map-svg .mnode.minor { opacity: 0.45; }
.map-svg .mnode.minor text { display: none; }
.map-svg .mnode.minor:hover, .map-svg .mnode.minor.selected { opacity: 1; }
.map-svg .mnode.minor:hover text, .map-svg .mnode.minor.selected text, .map-svg.zoomed .mnode.minor text { display: block; }
.map-svg.zoomed .mnode.minor { opacity: 0.7; }
.map-svg.mf .mnode:not(.server):not(.selected) { opacity: 0.12; transition: opacity 0.2s; }
.map-svg.mf .mnode:not(.server):not(.selected) text { display: none; }
.map-svg.mf-mine .mnode.f-mine, .map-svg.mf-targets .mnode.f-target, .map-svg.mf-threats .mnode.f-threat { opacity: 1; }
.map-svg.mf-mine .mnode.f-mine text, .map-svg.mf-targets .mnode.f-target text, .map-svg.mf-threats .mnode.f-threat text { display: block; }
.map-filters { margin-right: 6px; }
.map-svg.mf-mine .mnode.f-mine:not(.server), .map-svg.mf-targets .mnode.f-target:not(.server), .map-svg.mf-threats .mnode.f-threat:not(.server) { opacity: 1; }
.map-svg.mf-mine .mnode.f-mine:not(.server) text, .map-svg.mf-targets .mnode.f-target:not(.server) text, .map-svg.mf-threats .mnode.f-threat:not(.server) text { display: block; }
/* Map labels, smaller; a label that would overlap a more important one waits for hover/zoom. A halo in the map's own
   ground keeps the links from running through the words. The level is the name's size: the name leads. */
.mlabel { font-size: calc(11px / var(--z, 1)); letter-spacing: 0.6px; }
.msub { font-size: calc(9.5px / var(--z, 1)); }
.map-svg .mlabel, .map-svg .msub { paint-order: stroke; stroke: var(--inset); stroke-width: calc(3px / var(--z, 1)); stroke-linejoin: round; }
.msub .mlv { font-size: calc(11px / var(--z, 1)); }
.msub .mspecial { fill: var(--amber); font-size: calc(11px / var(--z, 1)); font-weight: 700; letter-spacing: 2px; }
/* A server on the map (view.mjs serverIcon): its kind's glyph and the bar of what you've cleared, amber; gray when it's
   done, teal where you are and what's yours, yellow (--next) for a contract's. A plate under the glyph hides the links. */
.mnode.loc .sv-plate { fill: var(--inset); stroke: none; }
.mnode.loc .sv-ring { fill: none; stroke: rgba(241, 185, 47, 0.5); stroke-width: 1.2; }
.mnode.loc .sv-kind { fill: none; stroke: var(--amber); stroke-width: 1.45; stroke-linecap: round; stroke-linejoin: round; }
.mnode.loc .sv-hit { fill: transparent; stroke: none; }
.mnode.loc .sv-track { fill: rgba(241, 185, 47, 0.22); } .mnode.loc .sv-lit { fill: var(--amber); }
.mnode.loc.done .sv-kind { stroke: var(--gray); } .mnode.loc.done .sv-lit { fill: var(--gray); }
.mnode.loc.job .sv-kind { stroke: var(--next); }
.mnode.loc.fowned .sv-lit { fill: var(--fc); }
.mnode.loc.owned .sv-kind, .mnode.loc.outpost .sv-kind, .mnode.loc.here .sv-kind { stroke: var(--you); } .mnode.loc.owned .sv-lit, .mnode.loc.here .sv-lit { fill: var(--you); }
.mnode.loc.fowned .sv-ring { stroke: var(--fc); } .mnode.loc.locked .sv-ring, .mnode.detached .sv-ring { stroke-dasharray: 2 3; }
.mnode.loc.locked .sv-kind { stroke: var(--hot); }
.mnode.loc.besieged .sv-kind { stroke: var(--next); animation: opblink 1s steps(2) infinite; }
.no-motion .mnode.loc.besieged .sv-kind { animation: none; }
.mnode:focus-visible .sv-kind { stroke: var(--bright); }
.map-svg .mnode.crowded text.mlabel, .map-svg .mnode.crowded text.msub { display: none; }
.map-svg .mnode.crowded:hover text.mlabel, .map-svg .mnode.crowded:hover text.msub, .map-svg .mnode.crowded.selected text.mlabel, .map-svg .mnode.crowded.selected text.msub, .map-svg.zoomed .mnode.crowded text.mlabel, .map-svg.zoomed .mnode.crowded text.msub { display: block; }
/* The map's List mode: every server as a sortable row; its card beside. */
.map-list-page { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 12px; height: 100%; }
.map-list { display: flex; flex-direction: column; min-height: 0; padding-top: 52px; }
.server-list { display: flex; flex-direction: column; min-height: 0; padding: 0 14px 12px; }
.sl-head, .sl-row { display: grid; grid-template-columns: minmax(150px, 1.6fr) 120px 44px 52px 120px minmax(120px, 1.4fr); align-items: center; column-gap: 12px; }
.sl-head { padding: 0 8px 6px; border-bottom: 1px solid var(--line-strong, var(--line)); }
.sl-h { background: none; border: 0; padding: 0; text-align: left; font: 600 10px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); cursor: pointer; }
.sl-h.on { color: var(--amber); }
.sl-body { overflow-y: auto; min-height: 0; }
.sl-row { width: 100%; padding: 8px; background: none; border: 0; border-bottom: 1px solid var(--line); color: var(--text); font: 13px var(--sans, inherit); text-align: left; cursor: pointer; }
.sl-row:hover { background: rgba(241, 185, 47, 0.05); }
.sl-row.on { background: rgba(241, 185, 47, 0.1); box-shadow: inset 2px 0 0 var(--amber); }
.sl-row.minor { color: var(--muted); }
.sl-name { display: flex; align-items: center; gap: 6px; min-width: 0; font-family: var(--mono); }
.sl-name b { font-weight: 600; letter-spacing: 0.04em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-fam { display: flex; align-items: center; gap: 6px; color: var(--muted); font-size: 12px; }
.sl-fam .glyph { width: 13px; height: 13px; }
.sl-lv { font: 700 13px var(--mono); }
.sl-num { font: 13px var(--mono); color: var(--muted); }
.sl-exp { display: flex; align-items: center; gap: 6px; }
.sl-exp .ld-bar { flex: 1; height: 4px; background: rgba(241, 185, 47, 0.12); border-radius: 2px; overflow: hidden; }
.sl-exp .ld-bar span { display: block; height: 100%; background: var(--amber); }
.sl-exp small { font: 10px var(--mono); color: var(--dim); }
.sl-status { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.sl-status .tag { font-size: 10px; line-height: 16px; padding: 0 5px; }
.sl-status .ls-job { margin: 0; }
.sl-wall { display: inline-flex; cursor: help; }
.sl-wall .glyph { width: 14px; height: 14px; }
.sl-wall.you { color: var(--you); } .sl-wall.warn { color: var(--amber); } .sl-wall.hot { color: var(--hot); }
@media (max-width: 1100px) { .map-list-page { grid-template-columns: 1fr; } }
/* List mode: section heads, and the locate button at the end of each row. */
.sl-sec { margin: 18px 8px 4px; font: 600 10px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim); }
.sl-loc { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; margin-left: auto; border: 1px solid var(--line-strong, var(--line)); border-radius: 3px; color: var(--muted); cursor: pointer; }
.sl-loc:hover { border-color: var(--amber); color: var(--amber); }
.sl-loc .glyph { width: 13px; height: 13px; }
.sl-status { justify-content: flex-start; }

/* Traffic on the map: the hubs' backbone, and files moving along it and to and from home. */
.mbone { fill: none; stroke: rgba(241, 185, 47, 0.18); stroke-width: 1; stroke-dasharray: 1 3; }
.mroute { fill: none; stroke: none; }
.mpkt { pointer-events: none; }
.mpkt .pk-hit { fill: transparent; }
.mpkt.amb { pointer-events: auto; cursor: help; }
.mpkt.amb .pk-dir { opacity: 0.9; fill: currentColor; }
.mpkt.amb .pk-icon { fill: rgba(0, 0, 0, 0.35); stroke: currentColor; stroke-width: 1; stroke-linejoin: round; }
.mpkt.you, .mpkt.pay { pointer-events: auto; }
.mpkt.you .pk-icon { fill: rgba(127, 209, 199, 0.18); stroke: var(--you); stroke-width: 1; stroke-linejoin: round; filter: drop-shadow(0 0 3px var(--you)); }
.mpkt.you .pk-dir { fill: var(--you); }
.mpkt.pay .pk-icon { fill: rgba(255, 91, 61, 0.25); stroke: var(--hot); stroke-width: 1; stroke-linejoin: round; filter: drop-shadow(0 0 3px var(--hot)); }
.mpkt.pay .pk-dir { fill: var(--hot); }
.map-svg.mf .mbone, .map-svg.mf .mpkt.amb, .map-svg.mf:not(.mf-mine) .mpkt { opacity: 0.12; }

/* The firewall: its level, what it's vulnerable to, and its blocks (firewall.mjs). */
.fw-lv { font: 700 22px var(--mono); color: var(--text); }
.fw-base { color: var(--muted); font: 11px var(--mono); }
.vuln { margin-left: auto; font: 600 11px var(--mono); letter-spacing: 0.06em; text-transform: uppercase; padding: 2px 8px; border: 1px solid currentColor; border-radius: 3px; }
.vuln.ok { color: var(--you); }
.vuln.mid { color: var(--amber); }
.vuln.low { color: var(--hot); }
.tag.warn { color: var(--amber); border-color: var(--amber); }
.fw-mini { display: grid; gap: 6px; margin: 8px 0; padding: 8px; border: 1px solid var(--line); border-radius: 4px; background: var(--inset); }
.fw-mini .fw-tag { display: inline-flex; align-items: center; gap: 4px; font: 600 12px var(--mono); }
/* The map's toolbar: view and Show picker on the left, the zoom tools on the right. */
.map-left { display: flex; align-items: center; gap: 8px; }
.map-pick select { font: 11px var(--mono); color: var(--dim); background: var(--panel, #120f0a); border: 1px solid var(--line); border-radius: 2px; padding: 1px 18px 1px 7px; cursor: pointer; appearance: none; background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%); background-position: calc(100% - 9px) 55%, calc(100% - 5px) 55%; background-size: 4px 4px; background-repeat: no-repeat; }
.map-pick.on select { color: var(--amber); border-color: var(--amber); }
.map-pick select option { background: #120f0a; color: var(--text); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* A missed attack (hitfx.mjs): MISS stamped across the part, struck through, then gone. */
.fx-miss { position: absolute; transform: translate(-50%, -50%) scale(1.8) rotate(-8deg); font: 800 30px var(--mono); letter-spacing: 0.18em; color: #cfc6b4; text-shadow: 0 0 10px rgba(0, 0, 0, 0.9), 0 0 2px #000; pointer-events: none; z-index: 30; opacity: 0; animation: fx-miss 1.05s cubic-bezier(.2,.8,.3,1) forwards; }
.fx-miss::after { content: ''; position: absolute; left: -6%; right: -6%; top: 52%; height: 3px; background: var(--amber); box-shadow: 0 0 6px var(--amber); transform: scaleX(0); transform-origin: left; animation: fx-miss-line 0.25s 0.18s ease-out forwards; }
.fx-miss.crew { color: #c9b8ff; }
@keyframes fx-miss { 0% { opacity: 0; transform: translate(-50%, -50%) scale(1.8) rotate(-8deg); } 18% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(-8deg); } 70% { opacity: 1; transform: translate(-50%, -55%) scale(1) rotate(-8deg); } 100% { opacity: 0; transform: translate(-50%, -75%) scale(0.95) rotate(-8deg); } }
@keyframes fx-miss-line { to { transform: scaleX(1); } }
.mem-join i.take { border-color: var(--amber); background: rgba(241, 185, 47, 0.35); animation: memtake 1.1s ease-in-out infinite; }
@keyframes memtake { 50% { background: transparent; } }
@media (prefers-reduced-motion: reduce) { .mem-join i.take { animation: none; background: transparent; border-style: dashed; } }
.tag.fw-ver { color: var(--you); border-color: var(--you); cursor: help; }

/* A button with a price: the label, a divider, then icon + number for each thing it takes. */
.bcost { display: inline-flex; align-items: center; gap: 8px; margin-left: 10px; padding-left: 10px; border-left: 1px solid currentColor; opacity: 0.85; font: 12px var(--mono); }
.bcost span { display: inline-flex; align-items: center; gap: 3px; }
.bcost .glyph { width: 12px; height: 12px; }
/* The threat rail: the left of the map, everything coming for you, soonest first. */
.threat-rail { display: grid; gap: 5px; }
.tr-row { display: grid; grid-template-columns: 16px 1fr auto; grid-template-rows: auto 3px; gap: 4px 8px; align-items: center; padding: 6px 8px; background: rgba(12, 10, 6, 0.88); border: 1px solid var(--line); border-left: 3px solid var(--line-strong); border-radius: 3px; color: var(--text); text-align: left; cursor: pointer; backdrop-filter: blur(2px); }
.tr-row:hover { border-color: var(--line-strong); }
.tr-row > .glyph { width: 14px; height: 14px; color: var(--muted); }
.tr-txt { display: grid; min-width: 0; }
.tr-txt b { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tr-txt b small { color: var(--muted); font: 10px var(--mono); margin-left: 4px; }
.tr-txt > small { color: var(--muted); font: 10px var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tr-t { font: 600 12px var(--mono); color: var(--text); }
.tr-bar { grid-column: 1 / -1; height: 3px; background: rgba(255, 255, 255, 0.06); border-radius: 2px; overflow: hidden; }
.tr-bar i { display: block; height: 100%; background: var(--muted); }
.tr-row.hot { border-left-color: var(--hot); } .tr-row.hot > .glyph, .tr-row.hot .tr-t { color: var(--hot); } .tr-row.hot .tr-bar i { background: var(--hot); }
.tr-row.warn { border-left-color: var(--amber); } .tr-row.warn > .glyph, .tr-row.warn .tr-t { color: var(--amber); } .tr-row.warn .tr-bar i { background: var(--amber); }
.tr-row.drop { border-left-color: var(--you); } .tr-row.drop > .glyph { color: var(--you); } .tr-row.drop .tr-bar i { background: var(--you); }
.tr-row.dim { opacity: 0.8; }
/* The contract tracker (view.mjs contractTracker): the contracts you hold, each with its name, whose it is and its
   progress in amber (what you use), a count as pips. Never teal: teal is only ever you. */
.ctrack { display: grid; gap: var(--s2); pointer-events: auto; min-width: 0; }
.ct-head { display: flex; align-items: center; gap: var(--s3); margin: 0; padding: 0 2px; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--amber); }
.ct-head .glyph { width: 12px; height: 12px; }
.ct-head small { margin-left: auto; font: inherit; color: var(--muted); }
.ct-row { display: grid; grid-template-columns: 16px minmax(0, 1fr); gap: 4px 8px; align-items: center; padding: 6px 8px; background: rgba(12, 10, 6, 0.88); border: 1px solid var(--line); border-left: 3px solid var(--amber-deep); border-radius: var(--r-btn); color: var(--text); font: inherit; text-align: left; cursor: pointer; backdrop-filter: blur(2px); }
.ct-row:hover, .ct-row:focus-visible { border-color: var(--line-strong); border-left-color: var(--amber); }
.ct-row.on { border-color: var(--amber); background: rgba(40, 30, 10, 0.92); }
/* Pinned (earned.mjs): an earned piece's row, set green's edge for a set piece, amber's for a unique; its cells and n/N. */
.ct-row.pin-row.set { border-left-color: var(--r-set); }
.ct-row.pin-row.set > .glyph { color: var(--r-set); }
.ct-row.pin-row .ct-prog { flex-wrap: wrap; row-gap: 3px; }
.pin-goal { font: 10px var(--mono); color: var(--muted); white-space: normal; line-height: 1.35; font-variant-numeric: tabular-nums; } /* its goal in words: wraps under the cells, never cut */
.ct-row > .glyph { width: 14px; height: 14px; color: var(--amber-soft); align-self: start; margin-top: 2px; }
.ct-txt { display: grid; min-width: 0; }
.ct-txt b { font-size: 12px; font-weight: 600; color: var(--bright); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ct-for { display: flex; align-items: center; min-width: 0; font: 10px var(--mono); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ct-for .glyph { width: 10px; height: 10px; }
.ct-prog { grid-column: 2; display: flex; align-items: center; gap: var(--s3); min-width: 0; min-height: 10px; }
.ct-bar { flex: 1 1 30px; min-width: 24px; height: 3px; background: rgba(255, 255, 255, 0.06); border-radius: 2px; overflow: hidden; }
.ct-bar i { display: block; height: 100%; background: var(--amber); }
.ct-n { flex: 0 1 auto; min-width: 0; font: 600 10px var(--mono); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ct-n.ct-say { white-space: normal; font-weight: 400; color: var(--muted); line-height: 1.35; }
.ct-turn { padding: 2px 7px; border: 1px solid var(--ready); border-radius: 3px; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--ready); white-space: nowrap; }
.ct-row.ready { grid-template-columns: 16px minmax(0, 1fr) auto; border-color: var(--ready); background: rgba(20, 32, 12, 0.92); }
.ct-row.ready .ct-prog { grid-column: 3; grid-row: 1 / span 2; }
.ct-row.ready .ct-txt b { white-space: normal; }
.ct-row.ready:hover .ct-turn, .ct-row.ready:focus-visible .ct-turn { background: var(--ready); color: var(--bg); }
.ct-row.ready > .glyph { color: var(--ready); }
/* The rail and the tracker share the map's left column; the rail keeps its own rows. */
.map-lcol { position: absolute; top: 56px; left: 10px; z-index: 3; width: 230px; display: grid; align-content: start; gap: var(--s5); max-height: calc(100% - 60px); overflow-y: auto; pointer-events: none; }
.map-lcol > * { pointer-events: auto; }
@media (max-width: 900px) { .map-lcol { position: static; width: auto; max-height: none; overflow: visible; margin: 44px 8px 0; gap: var(--s4); } }
/* The Rail (runners-view.mjs): the runners you know, under Contracts. Paper white (--bright): a runner is nobody's
   colour; the one you pick is drawn on the map as a diamond, its route dotted, where it's heading ringed. */
.rrail { display: grid; gap: var(--s2); min-width: 0; }
.rr-head { color: var(--bright); }
.rr-row { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 5px 8px; background: rgba(12, 10, 6, 0.88); border: 1px solid var(--line); border-left: 3px solid rgba(255, 242, 200, 0.35); border-radius: var(--r-btn); color: var(--text); font: inherit; text-align: left; cursor: pointer; backdrop-filter: blur(2px); }
.rr-row:hover, .rr-row:focus-visible { border-color: var(--line-strong); border-left-color: var(--bright); }
.rr-row.on { border-color: var(--bright); border-left-color: var(--bright); }
.rr-row.down { opacity: 0.6; }
.rr-dia { width: 7px; height: 7px; transform: rotate(45deg); border: 1.5px solid var(--bright); }
.rr-row.on .rr-dia { background: var(--bright); }
.rr-txt { display: grid; min-width: 0; white-space: nowrap; }
.rr-txt b { font-size: 12px; font-weight: 600; color: var(--bright); overflow: hidden; text-overflow: ellipsis; }
.rr-txt small, .rr-at { font: 10px var(--mono); color: var(--muted); white-space: nowrap; }
.rr-at { max-width: 120px; overflow: hidden; text-overflow: ellipsis; text-align: right; color: var(--text); }
.rr-head .rr-dia { margin: 0 2px; }
.mrunner { pointer-events: none; }
.mrunner .mr-route { fill: none; stroke: var(--bright); stroke-width: 1.6; stroke-dasharray: 1.5 5; stroke-linecap: round; opacity: 0.8; }
.mrunner .mr-ring { fill: none; stroke: var(--bright); stroke-width: 1.4; stroke-dasharray: 5 4; opacity: 0.85; }
.mrunner .mr-dia { fill: var(--bright); stroke: var(--bg); stroke-width: 1.5; }
.mrunner .mr-name { fill: var(--bright); font-size: calc(12px / var(--z, 1)); font-weight: 600; letter-spacing: 1px; paint-order: stroke; stroke: var(--bg); stroke-width: 3px; }
.mrunner.down .mr-dia { fill: none; stroke: var(--bright); }
/* Item hover card: a spinning ASCII model of the item's kind, in its rarity colour, over its details. */
.ptip { position: fixed; z-index: 80; zoom: var(--ui, 1); pointer-events: none; animation: ptip-in 0.14s ease-out; } /* zooms with the screen (app.js placePtip) */
@keyframes ptip-in { from { opacity: 0; transform: translateY(4px); } }
.ptip-card { width: 290px; display: grid; gap: 8px; padding: 12px 14px; background: rgba(10, 8, 5, 0.97); border: 1px solid var(--line-strong); border-top: 2px solid currentColor; border-radius: 4px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6); color: var(--r-stock); }
.ptip-card.r-scrap { color: var(--r-scrap); } .ptip-card.r-tuned { color: var(--r-tuned); } .ptip-card.r-custom { color: var(--r-custom); } .ptip-card.r-zeroday, .ptip-card.r-indemnified { color: var(--r-zeroday); }
.ptip-card.r-set { color: var(--r-set); }
.ptip-art { margin: 0; max-height: none; overflow: visible; justify-self: start; font: 11px/1 var(--mono); letter-spacing: 0.05em; color: currentColor; text-shadow: 0 0 6px currentColor; opacity: 0.95; background: radial-gradient(ellipse at center, rgba(255, 255, 255, 0.04), transparent 70%); padding: 4px 6px; }
.ptip-body { display: grid; gap: 3px; color: var(--text); }
.ptip-body .iname { font-size: 15px; }
.ptip-body > small { color: var(--muted); font: 11px var(--mono); }
.ptip-stats { display: grid; gap: 2px; margin-top: 4px; font-size: 12px; }
.ptip-stats span { display: block; }
.ptip-body .impl { display: block; } /* its text wraps back to the left edge, under the icon */
.ptip-body .impl .glyph { display: inline-block; vertical-align: -2px; margin-right: 6px; }
.ptip-body em { color: var(--muted); font-size: 11px; margin-top: 4px; }
.inv-card .inv-state { display: flex; align-items: center; gap: 8px; margin: 6px 0 4px; }
.inv-card .inv-state b { font: 600 12px var(--mono); color: var(--text); }
.inv-card.breach { border-color: rgba(255, 91, 61, 0.6); }
/* The hover card's swap comparison: against what that slot runs now. */
.ptip-vs { display: grid; gap: 2px; margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--line); font-size: 12px; }
.ptip-vs small { color: var(--muted); font: 11px var(--mono); }
.ptip-vs .up { color: var(--you); } .ptip-vs .down { color: var(--hot); } .ptip-vs .dim { color: var(--dim); }
.ptip-ans { display: block; margin-top: 6px; color: var(--dim); font: 11px var(--mono); } /* a premium shelf's answer: its price, or why not */
/* A contract's pay: icon chips. */
.rw-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
.rw { display: inline-flex; align-items: center; gap: 5px; padding: 3px 8px; border: 1px solid var(--line); border-radius: 3px; background: var(--inset); }
.rw .glyph { width: 14px; height: 14px; color: var(--amber); }
.rw b { font: 700 13px var(--mono); color: var(--bright); }
.rw.neg b { color: var(--hot); }

/* Hover card for a file moving on the map. */
.pkt-tip { position: fixed; z-index: 80; pointer-events: none; }
.pkt-card { min-width: 190px; display: grid; gap: 6px; padding: 10px 12px; background: rgba(10, 8, 5, 0.97); border: 1px solid var(--line-strong); border-top: 2px solid var(--you); border-radius: 4px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6); font-size: 12px; }
.pkt-card.pkt-pay { border-top-color: var(--hot); }
.pkt-top { display: flex; gap: 8px; align-items: center; }
.pkt-top .glyph { width: 22px; height: 22px; color: var(--amber); }
.pkt-top span { display: grid; }
.pkt-top b { color: var(--bright); font-size: 13px; } .pkt-top b small { color: var(--muted); font: 12px var(--mono); }
.pkt-top code { color: var(--muted); font: 11px var(--mono); }
.pkt-route { display: flex; gap: 6px; font: 11px var(--mono); color: var(--text); text-transform: uppercase; letter-spacing: 0.06em; }
.pkt-route i, .pkt-row i { color: var(--muted); font-style: normal; }
.pkt-row { display: flex; gap: 6px; align-items: center; }
.pkt-row .glyph { width: 13px; height: 13px; color: var(--muted); }
.pkt-row b { font: 700 13px var(--mono); color: var(--bright); } .pkt-row b.up { color: var(--r-tuned); }
.pkt-row small { color: var(--r-tuned); font: 11px var(--mono); }

/* The map's Show picker: a dropdown of checkboxes (any mix; none checked = all). */
details.map-pick { position: relative; }
details.map-pick summary { list-style: none; font: 11px var(--mono); color: var(--dim); background: var(--panel, #120f0a); border: 1px solid var(--line); border-radius: 2px; padding: 1px 20px 1px 7px; cursor: pointer; position: relative; white-space: nowrap; }
details.map-pick summary::-webkit-details-marker { display: none; }
details.map-pick summary::after { content: '▾'; position: absolute; right: 6px; top: 0; }
details.map-pick.on summary { color: var(--amber); border-color: var(--amber); }
.map-pick-menu { position: absolute; z-index: 30; top: calc(100% + 3px); left: 0; min-width: 140px; display: grid; gap: 2px; padding: 6px; background: #120f0a; border: 1px solid var(--line-strong); border-radius: 3px; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5); }
.map-pick-menu label { display: flex; align-items: center; gap: 8px; padding: 3px 4px; font: 12px var(--mono); color: var(--text); cursor: pointer; border-radius: 2px; }
.map-pick-menu label:hover { background: var(--inset); }
.map-pick-menu input { accent-color: var(--amber); margin: 0; }
.map-pick-menu button { margin-top: 4px; font: 11px var(--mono); color: var(--muted); background: none; border: 1px dashed var(--line); border-radius: 2px; padding: 2px 4px; cursor: pointer; }
/* The open Show menu sits above the threat rail. */
.map-tools:has(details.map-pick[open]) { z-index: 5; }
details.map-pick { pointer-events: auto; }
/* An unknown server's card: the ways to trace it, each with its gain; dim when it isn't open to you. */
.trace-ways { list-style: none; margin: 8px 0; padding: 0; display: grid; gap: 3px; }
.trace-ways .tw { display: grid; grid-template-columns: 16px 1fr auto; align-items: center; gap: 8px; padding: 4px 8px; border: 1px solid var(--line); border-radius: 3px; background: var(--inset); font-size: 12px; }
.trace-ways .tw .glyph { width: 14px; height: 14px; color: var(--you); }
.trace-ways .tw span { font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trace-ways .tw b { font: 700 12px var(--mono); color: var(--r-tuned); }
.trace-ways .tw.off { opacity: 0.45; } .trace-ways .tw.off .glyph { color: var(--muted); } .trace-ways .tw.off b { color: var(--muted); }
.trace-ways .tw.done span { text-decoration: line-through; color: var(--muted); } .trace-ways .tw.done b::after { content: ' ✓'; }
.fam-tag .glyph, .svc-line .tag.dim .glyph { width: 12px; height: 12px; margin-right: 4px; vertical-align: -2px; }
.op-pick-t { font: 11px var(--mono); color: var(--muted); margin-right: 8px; }
.bcost.req.short { color: var(--hot); opacity: 1; }
.op-pick-t { display: inline-flex; align-items: center; gap: 6px; font: 600 13px var(--sans, inherit); color: var(--text); }
.op-pick-t .glyph { width: 14px; height: 14px; }
/* A paused fight: the board dims under a banner. Any order (or the Fight tab) resumes it. */
#board.is-paused { position: relative; }
#board.is-paused > :not(.pause-strip) { opacity: 0.45; }
#board .pause-strip { position: absolute; left: 50%; top: 4px; transform: translateX(-50%); padding: 3px 12px; border: 1px solid var(--amber); background: rgba(9, 6, 3, 0.92); color: var(--amber); font: 700 11px var(--mono); letter-spacing: 2px; z-index: 3; pointer-events: none; white-space: nowrap; opacity: 1 !important; }

/* Root access (root.mjs): pips on the server card, a ↻ (or ★ rare) on the map node */
.root-pips { letter-spacing: 1px; color: var(--teal, #6fd3c1); }
.root-pips i { font-style: normal; opacity: 0.35; }
.mnode .rotmark text { font-size: 11px; fill: var(--teal, #6fd3c1); text-anchor: middle; dominant-baseline: central; }
.mnode .rotmark.rare text { fill: var(--amber, #ffb84d); }
.motion .mnode .rotmark { animation: drop-ping 2.4s ease-in-out infinite; }

/* Crew rooms (elites): a gold frame, so nobody walks in solo by accident */
.tag.tag-crew { color: #1a1206; background: var(--gold, #e8b54a); border-color: var(--gold, #e8b54a); font-weight: 700; letter-spacing: 0.06em; box-shadow: 0 0 0 1px rgba(232, 181, 74, 0.35), 0 0 8px rgba(232, 181, 74, 0.25); }

.sig-eta { color: var(--dim); font-size: 11px; font-variant-numeric: tabular-nums; margin-left: 4px; }
/* Reboot sickness: what's off your max Signal while your server reboots. */
.sig-sick, .meter small.sig-sick { color: var(--hot); font: 600 11px var(--mono); font-style: normal; font-variant-numeric: tabular-nums; margin-left: 4px; }
.meter-signal.weak .sig-eta { color: var(--amber); }
.sp-row.k-lost { border-left-color: var(--hot); } .sp-row.k-lost .sp-ico { color: var(--hot); }
.sp-row.k-time .sp-qty { font-variant-numeric: tabular-nums; }
.gain.loss .sp-kicker { color: var(--hot); }

/* Phones: three timeline columns (Now, +1, +2), slimmer chips, skill names that fit, labelled credits. */
@media (max-width: 480px) {
  .brow { grid-template-columns: minmax(84px, 1.1fr) repeat(3, minmax(0, 1fr)); }
  .brow > .bcell:nth-child(5) { display: none; }
  .brow > .bcell.span4 { grid-column: 2 / -1; }
  .intent .ico { display: none; }
  .intent { padding-left: 4px; padding-right: 4px; }
  .tray { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .meter:not(.meter-signal):not(.meter-integrity) .meter-label { display: inline; font-size: 10px; }
}

/* First-class picker: four cards over the screen, right after you log in. */
/* ---------- choosing your first class (view.mjs classPickMarkup, app.js pickClass) ---------- */
.class-pick { position: fixed; inset: 0; z-index: 70; overflow-y: auto; scrollbar-width: none; background: radial-gradient(ellipse at 50% 0%, rgba(241, 185, 47, 0.1), transparent 60%), #040302; }
.class-pick::-webkit-scrollbar { display: none; } /* it still scrolls on a short window, without the bar */
.class-pick::after { content: ''; position: fixed; inset: 0; pointer-events: none; background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.22) 0 1px, transparent 1px 3px); }
.pk-scene { position: relative; z-index: 1; width: min(1180px, 100%); margin: 0 auto; padding: 5vh 16px 24px; display: grid; gap: 22px; }
.pk-head { display: grid; justify-items: center; gap: 10px; text-align: center; animation: pk-in 0.6s ease-out both; }
.pk-logo { --lg: 30px; margin-bottom: 12px; }
.pk-head h2 { margin: 0; font: 600 22px var(--mono); letter-spacing: 8px; margin-right: -8px; text-transform: uppercase; color: var(--bright); text-shadow: 0 0 14px rgba(241, 185, 47, 0.35); }
.pk-head p { margin: 0; font-size: 13px; color: var(--muted); }
.pk-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px 14px; }
/* Each card spans seven rows of the grid and lays its plate, name, roles and four sections on them (subgrid), so a
   section starts at the same height on every card in a row however long the one above it runs. */
.pk-card { grid-row: span 7; grid-template-rows: subgrid; }
.pk-card { position: relative; display: grid; align-content: start; gap: 10px; padding: 14px 14px 16px; text-align: left; color: var(--text); background: linear-gradient(180deg, rgba(255, 216, 110, 0.04), transparent 40%), var(--panel-2); border: 1px solid var(--line); border-radius: 6px; cursor: pointer; transition: transform 0.18s ease, border-color 0.18s, box-shadow 0.18s; animation: pk-in 0.5s calc(0.15s + var(--i) * 0.08s) ease-out both; }
.pk-card:hover, .pk-card:focus-visible { transform: translateY(-4px); border-color: var(--line-strong); outline: none; }
.pk-card[aria-checked='true'] { border-color: var(--amber); box-shadow: 0 0 0 1px var(--amber) inset, 0 10px 40px -12px rgba(241, 185, 47, 0.55); transform: translateY(-4px); }
.pk-num { position: absolute; z-index: 2; top: 18px; left: 20px; font: 600 11px var(--mono); color: var(--dim); letter-spacing: 1px; }
/* The emblem's plate: dark, with the logo's corona rising behind the art when the card is chosen. */
.pk-plate { position: relative; display: grid; place-items: center; height: 116px; margin: -2px -2px 2px; border: 1px solid var(--line); border-radius: 4px; background: #070503; overflow: hidden; isolation: isolate; container-type: inline-size; }
.pk-plate::before { content: ''; position: absolute; left: 50%; top: 50%; width: 120px; height: 120px; margin: -60px 0 0 -60px; z-index: -1; border-radius: 50%; background: radial-gradient(circle closest-side, rgba(255, 216, 110, 0.38), rgba(241, 185, 47, 0.12) 60%, transparent); opacity: 0.25; transform: scale(0.7); transition: opacity 0.3s, transform 0.4s ease-out; }
.pk-card:hover .pk-plate::before { opacity: 0.55; transform: scale(0.9); }
.pk-card[aria-checked='true'] .pk-plate::before { opacity: 1; transform: scale(1.1); }
.pk-art { margin: 0; max-height: none; overflow: hidden; font: 600 min(10px, calc((100cqw - 16px) / 11.5))/1.15 var(--mono); color: var(--amber); white-space: pre; text-shadow: 0 0 6px rgba(241, 185, 47, 0.45); opacity: 0.8; transition: opacity 0.2s, color 0.2s; }
.pk-card:hover .pk-art, .pk-card[aria-checked='true'] .pk-art { opacity: 1; color: #ffd86e; }
.pk-name { font: 600 20px var(--mono); letter-spacing: 3px; text-transform: uppercase; color: var(--bright); }
.pk-role { display: flex; flex-wrap: nowrap; gap: 0 7px; white-space: nowrap; overflow: hidden; font: 600 9.5px var(--mono); letter-spacing: 0.6px; text-transform: uppercase; color: var(--you); }
.pk-role span + span::before { content: '·'; margin-right: 7px; color: var(--dim); }
.pk-sec { display: grid; align-content: start; gap: 2px; padding-top: 8px; border-top: 1px solid var(--line); font-size: 12px; line-height: 1.4; }
.pk-k { font: 600 9.5px var(--mono); letter-spacing: 2px; text-transform: uppercase; color: var(--dim); }
.pk-sec b { color: var(--bright); font-weight: 600; }
.pk-sec small { font-size: 11.5px; color: var(--muted); }
.pk-sec small i { font-style: normal; color: var(--dim); }
.pk-skills { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.pk-skills li { display: grid; gap: 0; }
.pk-skills small { color: var(--dim); }
.pk-foot { display: flex; justify-content: center; align-items: center; gap: 16px; flex-wrap: wrap; animation: pk-in 0.5s 0.5s ease-out both; }
.pk-hint { font-size: 12.5px; color: var(--muted); }
.pk-go { min-width: 220px; justify-content: center; font-size: 13px; letter-spacing: 2px; text-transform: uppercase; padding: 10px 18px; }
@keyframes pk-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (max-width: 960px) { .pk-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .pk-grid { grid-template-columns: 1fr; } .pk-plate { height: 108px; } .pk-head h2 { font-size: 17px; letter-spacing: 5px; margin-right: -5px; } }
@media (prefers-reduced-motion: reduce) { .pk-card, .pk-head, .pk-foot { animation: none; } .pk-card, .pk-card:hover, .pk-card[aria-checked='true'] { transform: none; } }

/* Collection log (System page) */
.coll-card .coll-bar { height: 4px; background: var(--inset); border: 1px solid var(--line); border-radius: 2px; margin: 0 0 10px; overflow: hidden; }
.coll-card .coll-bar i { display: block; height: 100%; background: var(--amber); }
.coll { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 6px 14px; }
.coll li { display: grid; gap: 1px; padding: 4px 0; border-top: 1px solid var(--line); }
.coll li small { font-size: 11px; color: var(--dim); }
.coll .coll-q { color: var(--gray); letter-spacing: 2px; }
.coll .coll-odds { color: var(--amber, #e0b050); }

/* Sets (sets.mjs): under a piece in its tooltip and its stash or slot row, WoW's grammar. The set's name and count, its
   pieces (loaded and held lit, missing dim, ??? until found), each bonus greyed until it's on. Set green is the set's
   own colour, never teal: teal is only ever you. */
.set-lines { display: grid; gap: 1px; margin-top: 6px; font-size: 12px; }
.set-lines .set-name { color: var(--r-set); font: 600 12px var(--mono); letter-spacing: 0.3px; }
.set-tier { display: block; color: var(--dim); font-size: 11px; } /* a class set: its class's tier set, level 50 */
.set-pieces { display: grid; gap: 0; padding-left: 10px; }
.set-pieces .sp.worn { color: var(--r-set); }
.set-pieces .sp.held { color: var(--text); }
.set-pieces .sp.missing { color: var(--dim); }
.set-pieces .sp.unknown { color: var(--gray); letter-spacing: 2px; }
.set-pieces .sp.earned { display: flex; justify-content: space-between; gap: 10px; letter-spacing: 0; } /* earned (earned.mjs): named, its goal and count right */
.sp-goal { font: 10px var(--mono); color: var(--dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
.set-bonuses { display: grid; gap: 1px; margin-top: 3px; }
.sb { color: var(--gray); }
.sb.on { color: var(--r-set); }
.sb.blocked em { font-style: normal; color: var(--dim); }
.sb.sub { padding-left: 10px; } /* a class set's subclass line, under its 4-piece bonus */
.sg { color: var(--gray); } /* a piece's green line: set green once it and another piece of its set are loaded */
.sg.on { color: var(--r-set); }
.set-lines.compact { margin-top: 2px; font-size: 11px; }
.set-lines.compact .set-pieces { display: flex; flex-wrap: wrap; gap: 0 8px; padding-left: 0; }
.set-lines.compact .set-pieces .sp:not(:last-child)::after { content: ' ·'; color: var(--gray); }
.set-bonus-card { margin: 10px 0 2px; padding: 8px 10px; border: 1px solid var(--line); border-left: 2px solid var(--r-set); border-radius: var(--r-card); background: var(--inset); }
.set-bonus-card h3 { margin: 0 0 4px; font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; color: var(--r-set); }
.set-bonus-card ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.set-bonus-card li { display: grid; gap: 1px; font-size: 12px; }
.set-bonus-card .set-name { color: var(--r-set); font: 600 12px var(--mono); }
.coll-sets-h { margin: 14px 0 6px; font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; color: var(--r-set); }
.coll-sets { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.coll-set-row > .set-name { display: block; margin-bottom: 2px; color: var(--r-set); font: 600 12px var(--mono); }
.coll-set-row > .set-name span { color: var(--dim); font-weight: 400; }
.coll-set-row.done > .set-name span { color: var(--r-set); }

/* Trace on a break-in: beside Signal in the run header. */
.net-trace { display: flex; align-items: center; gap: 8px; font-variant-numeric: tabular-nums; }
.net-trace .lbl { font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--muted); }
.net-trace .sigbar span { background: var(--amber); }
.net-trace.low .sigbar span { background: var(--you); }
.net-trace.hot .sigbar span, .net-trace.hunted .sigbar span { background: var(--hot); }
.net-trace strong { font: 600 18px var(--mono); color: var(--amber); }
.net-trace.low strong { color: var(--you); }
.net-trace.hot strong, .net-trace.hunted strong { color: var(--hot); }

/* A contract ready to deliver: a yellow check by Mail. */
.modules .ready-check { display: inline-block; margin-left: 5px; color: var(--amber); font: 700 13px var(--mono); }

/* Event cards (event-cards.mjs, docs/ui.md): one shell for every card, a kicker strip (the card's icon and name, its level or
   mark, a ring of the time left), then the card's own body. Event violet on the strip and frame (the map's antenna); factions
   in their colours; you in teal. The action is the design: a faction's half, a target tile, a price tile. Motion is locked to
   the clock (--ph, so a redraw doesn't restart it) and stops with Motion off or reduced motion. */
@media (min-width: 901px) { .map-pop:has(.evc) { width: 376px; } } /* a phone's pop-up is the screen's width already */
.evc { --ec: var(--daemon); position: relative; display: grid; margin-top: var(--s2); background: var(--inset); border: 1px solid color-mix(in srgb, var(--ec) 34%, transparent); border-radius: var(--r-card); overflow: hidden; }
.evc + .evc { margin-top: var(--s4); }
.evc-head { display: flex; align-items: center; gap: var(--s3); min-height: 26px; padding: 3px 6px 3px 9px; background: color-mix(in srgb, var(--ec) 12%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--ec) 26%, transparent); color: var(--ec); font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; cursor: help; }
.evc-head > .glyph { width: 13px; height: 13px; margin: 0; }
.evc-head > b { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.evc-sub { display: inline-flex; align-items: center; gap: var(--s3); margin-left: auto; font: 600 12px var(--mono); letter-spacing: 0.5px; text-transform: none; }
.evc-ring { display: inline-grid; flex: none; width: 18px; height: 18px; }
.evc-ring svg { width: 18px; height: 18px; }
.evc-ring circle { fill: none; stroke-width: 2.4; }
.evc-ring .bg { stroke: color-mix(in srgb, var(--ec) 22%, transparent); }
.evc-ring .fg { stroke: var(--ec); stroke-linecap: round; }
.evc-ring.low .fg { stroke: var(--amber); }
.evc-body { display: grid; gap: var(--s4); padding: var(--s4); }
/* Rewards: an icon and a number. */
.evc-rw { display: inline-flex; align-items: center; gap: 3px; font: 600 12px var(--mono); color: var(--text); white-space: nowrap; cursor: help; }
.evc-rw > .glyph { width: 13px; height: 13px; margin: 0; color: var(--amber); }
.evc-rw.cl-risk { opacity: 0.45; } /* a defence call's cost: muted until you answer, then a threat */
.evc-rw.cl-risk.on { opacity: 1; color: var(--hot); }
.evc-rw.cl-risk.on > .glyph { color: var(--hot); }
.evc-rw.r-tuned > .glyph { color: var(--r-tuned); } .evc-rw.r-custom > .glyph { color: var(--r-custom); } .evc-rw.r-zeroday > .glyph { color: var(--r-zeroday); }
.evc-fm { display: inline-flex; color: var(--fc); } .evc-fm .glyph { width: 13px; height: 13px; margin: 0; }
.evc-sub .evc-fm .glyph { width: 15px; height: 15px; }
/* A target tile: the virus framed, its name and level, its pay. The whole tile is the button; a reticle closes on hover. */
.evc-target { display: grid; grid-template-columns: 46px minmax(0, 1fr) auto; align-items: center; gap: var(--s5); width: 100%; margin: 0; padding: 7px 10px 7px 7px; text-align: left; color: var(--text); background: linear-gradient(90deg, color-mix(in srgb, var(--ec) 10%, transparent), transparent 70%); border: 1px solid var(--line-strong); border-radius: var(--r-btn); transition: border-color 0.12s, box-shadow 0.12s, background-color 0.12s; }
.evc-target:hover:not(:disabled), .evc-target:focus-visible { border-color: var(--amber); background-color: rgba(241, 185, 47, 0.05); box-shadow: inset 0 0 0 1px var(--amber), 0 0 14px rgba(241, 185, 47, 0.14); outline: none; }
.evc-target:active:not(:disabled) { transform: translateY(1px); box-shadow: inset 0 0 0 1px var(--amber); }
.evc-face { position: relative; display: grid; place-items: center; width: 46px; height: 46px; box-sizing: border-box; color: var(--ec); background: #0c0905; border: 1px solid color-mix(in srgb, var(--ec) 40%, transparent); border-radius: 2px; }
.evc-face > .glyph { width: 26px; height: 26px; margin: 0; stroke-width: 1.25; filter: drop-shadow(0 0 4px color-mix(in srgb, var(--ec) 45%, transparent)); }
/* The reticle: four corners that close in on hover or focus. */
.evc-face::before { content: ''; position: absolute; inset: -4px; opacity: 0; transform: scale(1.18); transition: opacity 0.14s, transform 0.14s; background: linear-gradient(var(--amber), var(--amber)) 0 0 / 9px 2px, linear-gradient(var(--amber), var(--amber)) 0 0 / 2px 9px, linear-gradient(var(--amber), var(--amber)) 100% 0 / 9px 2px, linear-gradient(var(--amber), var(--amber)) 100% 0 / 2px 9px, linear-gradient(var(--amber), var(--amber)) 0 100% / 9px 2px, linear-gradient(var(--amber), var(--amber)) 0 100% / 2px 9px, linear-gradient(var(--amber), var(--amber)) 100% 100% / 9px 2px, linear-gradient(var(--amber), var(--amber)) 100% 100% / 2px 9px; background-repeat: no-repeat; pointer-events: none; }
.evc-target:hover:not(:disabled) .evc-face::before, .evc-target:focus-visible .evc-face::before { opacity: 1; transform: none; }
.evc-who { display: grid; gap: 3px; min-width: 0; }
.evc-who > b { overflow: hidden; font: 600 14px var(--mono); letter-spacing: 0.5px; color: var(--bright); white-space: nowrap; text-overflow: ellipsis; }
.evc-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--s3); min-width: 0; font: 600 12px var(--mono); }
.evc-tags .tag { padding: 0 4px; font-size: 10px; line-height: 15px; }
.evc-tags .iname { overflow: hidden; max-width: 100%; font-size: 12px; white-space: nowrap; text-overflow: ellipsis; }
.evc-at { overflow: hidden; max-width: 100%; color: var(--dim); font: 11px var(--mono); white-space: nowrap; text-overflow: ellipsis; }
.evc-pay { display: grid; justify-items: end; gap: 4px; }
/* Bounty: a pinned poster. Hollow Choir: a boss frame. */
.evc-target.poster .evc-face { color: var(--amber); border-color: var(--line-strong); outline: 1px dashed rgba(241, 185, 47, 0.3); outline-offset: -5px; }
.evc-target.poster .evc-face::after { content: ''; position: absolute; top: -3px; left: 50%; width: 5px; height: 5px; margin-left: -3px; border-radius: 50%; background: var(--amber-soft); box-shadow: 0 0 4px rgba(241, 185, 47, 0.5); }
.evc-target.boss { border-color: color-mix(in srgb, var(--hot) 45%, transparent); }
.evc-target.boss .evc-face { color: var(--hot); border-color: var(--hot); box-shadow: 0 0 0 2px #0c0905, 0 0 0 3px color-mix(in srgb, var(--hot) 55%, transparent), 0 0 14px rgba(255, 91, 61, 0.3); }
.evc-target.boss .evc-face > .glyph { filter: drop-shadow(0 0 5px rgba(255, 91, 61, 0.6)); animation: evc-pulse 2.4s ease-in-out infinite var(--ph, 0s); }
.evc-target.courier .evc-face { color: var(--r-tuned); }
.evc-target.courier.unique .evc-face { overflow: hidden; border-color: color-mix(in srgb, var(--r-zeroday) 50%, transparent); }
.evc-face .pglyph { padding: 0; }

/* Feud: two halves facing off over a stacked bar in the factions' colours. */
.fd-arena { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 7px 6px; }
.fd-half { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: 'mark pct' 'name name' 'foe foe'; align-items: center; gap: 3px var(--s4); min-width: 0; margin: 0; padding: 8px 10px 7px; text-align: left; color: var(--text); background: linear-gradient(180deg, color-mix(in srgb, var(--fc) 13%, transparent), transparent 75%); border: 1px solid color-mix(in srgb, var(--fc) 42%, transparent); border-radius: var(--r-btn); transition: border-color 0.12s, box-shadow 0.12s, background-color 0.12s; }
.fd-half.fd-a { grid-area: 1 / 1; } .fd-half.fd-b { grid-area: 1 / 2; }
.fd-rw.fd-a { grid-area: 3 / 1; } .fd-rw.fd-b { grid-area: 3 / 2; }
.fd-half.fd-b { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: 'pct mark' 'name name' 'foe foe'; text-align: right; }
.fd-half:hover:not(:disabled), .fd-half:focus-visible { border-color: var(--fc); background-color: color-mix(in srgb, var(--fc) 9%, transparent); box-shadow: inset 0 0 0 1px var(--fc), 0 0 16px color-mix(in srgb, var(--fc) 22%, transparent); outline: none; }
.fd-half:active:not(:disabled) { transform: translateY(1px); }
.fd-half.on { border-color: var(--fc); box-shadow: inset 0 0 0 1px var(--fc), 0 0 18px color-mix(in srgb, var(--fc) 24%, transparent); }
.fd-half.off:disabled { opacity: 0.38; filter: saturate(0.35); }
.fd-mark { grid-area: mark; display: grid; color: var(--fc); }
.fd-mark .glyph { width: 26px; height: 26px; margin: 0; stroke-width: 1.3; filter: drop-shadow(0 0 5px color-mix(in srgb, var(--fc) 50%, transparent)); }
.fd-pct { grid-area: pct; justify-self: end; font: 600 24px/1 var(--mono); color: var(--fc); font-variant-numeric: tabular-nums; }
.fd-b .fd-pct { justify-self: start; }
.fd-pct small { margin-left: 1px; font-size: 12px; opacity: 0.7; }
.fd-name { grid-area: name; overflow: hidden; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--fc); white-space: nowrap; text-overflow: ellipsis; }
.fd-foe { grid-area: foe; display: flex; align-items: center; gap: 4px; min-width: 0; font: 11px var(--mono); color: var(--muted); }
.fd-b .fd-foe { flex-direction: row-reverse; }
.fd-foe .glyph { width: 11px; height: 11px; margin: 0; flex: none; }
.fd-foe span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* Your side: a teal lamp, and a tick a runner you've beaten. */
.fd-you { position: absolute; bottom: 9px; display: flex; gap: 2px; align-items: center; }
.fd-a .fd-you { right: 8px; } .fd-b .fd-you { left: 8px; flex-direction: row-reverse; }
.fd-you::before { content: ''; width: 7px; height: 7px; margin: 0 3px; border-radius: 50%; background: var(--you); box-shadow: 0 0 6px var(--you); }
.fd-a .fd-you::before { order: 1; }
.fd-you i { width: 3px; height: 9px; background: var(--you); opacity: 0.85; }
.fd-vs { grid-row: 1; grid-column: 1 / -1; z-index: 1; place-self: center; display: grid; place-items: center; width: 24px; height: 24px; box-sizing: border-box; font: italic 600 10px var(--mono); letter-spacing: 0.5px; text-transform: uppercase; color: var(--bright); background: var(--inset); border: 1px solid var(--line-strong); border-radius: 50%; box-shadow: 0 0 0 3px var(--inset); pointer-events: none; }
.fd-bar { --p: 50%; position: relative; grid-area: 2 / 1 / 3 / -1; height: 12px; margin: 2px 0; background: #0c0905; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6); }
.fd-seg { position: absolute; top: 0; bottom: 0; background-size: 12px 12px; }
.fd-seg.sa { left: 0; width: var(--p); border-radius: 2px 0 0 2px; background-color: var(--ca); background-image: repeating-linear-gradient(-55deg, rgba(0, 0, 0, 0.22) 0 3px, transparent 3px 6px); animation: fd-flow-a 1.2s linear infinite var(--ph, 0s); }
.fd-seg.sb { left: var(--p); right: 0; border-radius: 0 2px 2px 0; background-color: var(--cb); background-image: repeating-linear-gradient(55deg, rgba(0, 0, 0, 0.22) 0 3px, transparent 3px 6px); animation: fd-flow-b 1.2s linear infinite var(--ph, 0s); }
.fd-bar.lead-a .sb, .fd-bar.lead-b .sa { filter: brightness(0.7); }
.fd-mid { position: absolute; left: 50%; top: -4px; bottom: -4px; width: 1px; background: var(--bright); opacity: 0.35; }
.fd-edge { position: absolute; left: var(--p); top: -4px; bottom: -4px; width: 2px; margin-left: -1px; background: #fff3c4; border-radius: 1px; box-shadow: 0 0 6px 2px rgba(255, 243, 196, 0.55); animation: fd-clash 1.2s ease-in-out infinite var(--ph, 0s); }
.fd-edge.up::before, .fd-edge.down::before { content: ''; position: absolute; top: -6px; border: 3px solid transparent; }
.fd-edge.up::before { left: 3px; border-left: 5px solid #fff3c4; border-right-width: 0; }
.fd-edge.down::before { right: 3px; border-right: 5px solid #fff3c4; border-left-width: 0; }
.fd-rw { display: grid; grid-template-columns: auto auto auto; justify-content: start; align-items: center; gap: 5px var(--s4); min-width: 0; }
.fd-rw.fd-b { justify-content: end; }
.fd-rw.off { opacity: 0.35; }
.fd-won { grid-column: 1 / -1; display: inline-flex; align-items: center; gap: 5px; justify-self: start; padding-top: 5px; border-top: 1px dashed var(--line); cursor: help; }
.fd-rw.fd-b .fd-won { justify-self: end; }
.fd-won > .glyph { width: 12px; height: 12px; margin: 0; color: var(--muted); }
@keyframes fd-clash { 0%, 100% { box-shadow: 0 0 4px 1px rgba(255, 243, 196, 0.45); } 50% { box-shadow: 0 0 12px 4px rgba(255, 243, 196, 0.9); } }
@keyframes fd-flow-a { to { background-position: 12px 0; } }
@keyframes fd-flow-b { to { background-position: -12px 0; } }

/* Bounty hunt: its route, a dot a server (past dim, the quarry's ringed, the next dashed), the pay rung and level under each. */
.hn-route { list-style: none; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); margin: 0; padding: 2px 0 0; }
.hn-stop { position: relative; display: grid; justify-items: center; gap: 2px; min-width: 0; font: 11px var(--mono); color: var(--dim); cursor: help; }
.hn-stop::before { content: ''; position: absolute; top: 10px; left: 50%; width: 100%; height: 2px; margin-top: -1px; background: var(--line-strong); }
.hn-stop:last-child::before { display: none; }
.hn-stop.past::before { background: color-mix(in srgb, var(--ec) 45%, transparent); }
.hn-stop.here::before { background: repeating-linear-gradient(90deg, var(--ec) 0 5px, transparent 5px 9px); background-size: 9px 2px; animation: hn-flow 0.8s linear infinite var(--ph, 0s); }
.hn-dot { position: relative; z-index: 1; display: grid; place-items: center; width: 20px; height: 20px; box-sizing: border-box; border: 2px solid var(--line-strong); border-radius: 50%; background: var(--inset); transform: scale(0.6); }
.hn-stop.past .hn-dot { background: color-mix(in srgb, var(--ec) 45%, var(--inset)); border-color: transparent; }
.hn-stop.next .hn-dot { border-style: dashed; border-color: var(--ec); transform: scale(0.75); }
.hn-stop.here .hn-dot { transform: none; color: var(--ec); border-color: var(--ec); box-shadow: 0 0 10px color-mix(in srgb, var(--ec) 55%, transparent); animation: evc-glow 2.4s ease-in-out infinite var(--ph, 0s); }
.hn-dot .glyph { width: 12px; height: 12px; margin: 0; }
.hn-stop b { font-weight: 600; color: var(--muted); }
.hn-stop.past b, .hn-stop.past small { opacity: 0.6; }
.hn-stop.here b { color: var(--bright); font-size: 13px; }
.hn-stop.here small { color: var(--ec); }
.hn-stop small { font-size: 10px; }
@keyframes hn-flow { to { background-position: 9px 0; } }

/* Courier: the packet on its line through your server, as far along as its time is gone. */
.cr-line { --at: 0%; position: relative; height: 26px; margin: 0 4px; cursor: help; }
.cr-track { position: absolute; left: 0; right: 0; top: 12px; height: 2px; background: repeating-linear-gradient(90deg, var(--line-strong) 0 6px, transparent 6px 10px); }
.cr-track::after { content: ''; position: absolute; right: -2px; top: -3px; border: 4px solid transparent; border-left: 6px solid var(--line-strong); border-right-width: 0; }
.cr-line::before { content: ''; position: absolute; left: 0; top: 12px; width: var(--at); height: 2px; background: color-mix(in srgb, var(--ec) 60%, transparent); }
.cr-srv { position: absolute; left: 50%; top: 3px; display: grid; place-items: center; width: 20px; height: 20px; margin-left: -10px; box-sizing: border-box; color: var(--muted); background: var(--inset); border: 1px solid var(--line-strong); border-radius: 2px; }
.cr-srv .glyph, .cr-pkt .glyph { width: 12px; height: 12px; margin: 0; }
.cr-pkt { position: absolute; z-index: 1; top: 2px; left: clamp(0px, calc(var(--at) - 11px), calc(100% - 22px)); display: grid; place-items: center; width: 22px; height: 22px; box-sizing: border-box; color: var(--ec); background: var(--inset); border: 1px solid var(--ec); border-radius: 3px; box-shadow: 0 0 10px color-mix(in srgb, var(--ec) 55%, transparent); animation: evc-glow 2.4s ease-in-out infinite var(--ph, 0s); }

/* Spotter: its tile; the next invasion a silhouette (?) until it's down, then its kind, −2 lv in teal (yours). */
.spt-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s4); align-items: stretch; }
.spt-next { display: grid; justify-items: center; align-content: center; gap: 1px; min-width: 66px; padding: 5px 8px; color: var(--muted); border: 1px dashed var(--line-strong); border-radius: var(--r-btn); cursor: help; }
.spt-next > .glyph { width: 13px; height: 13px; margin: 0; color: var(--you); }
.spt-sil { font: 600 20px/1.1 var(--mono); color: var(--muted); }
.spt-next small { font: 600 11px var(--mono); color: var(--you); }
.spt-next.known { grid-template-columns: auto auto auto; justify-content: start; justify-items: start; align-items: center; gap: 2px var(--s4); border-style: solid; border-color: color-mix(in srgb, var(--you) 45%, transparent); }
.spt-next.known .spt-sil { font-size: 14px; color: var(--bright); }
.spt-next.known .spt-from { grid-column: 1 / -1; color: var(--dim); font-weight: 400; }
.evc-told { --ec: var(--you); }

/* Market shock: the price tile. ▲ sell there, ▼ buy there. */
.evc-shock.up { --sc: #8fd46b; } .evc-shock.down { --sc: #ff6f91; }
.sh-tile { display: grid; grid-template-columns: 40px auto minmax(0, 1fr) auto; grid-template-areas: 'ware mult spark act' 'ware name name act'; align-items: center; gap: 2px var(--s5); width: 100%; margin: 0; padding: 7px 10px 7px 7px; text-align: left; color: var(--text); border: 1px solid color-mix(in srgb, var(--sc) 40%, transparent); border-radius: var(--r-btn); background: linear-gradient(90deg, color-mix(in srgb, var(--sc) 9%, transparent), transparent 70%); transition: border-color 0.12s, box-shadow 0.12s; }
.sh-tile:hover, .sh-tile:focus-visible { border-color: var(--sc); box-shadow: inset 0 0 0 1px var(--sc), 0 0 14px color-mix(in srgb, var(--sc) 20%, transparent); outline: none; }
.sh-tile:active { transform: translateY(1px); }
.sh-ware { grid-area: ware; display: grid; place-items: center; width: 40px; height: 40px; box-sizing: border-box; color: var(--sc); background: #0c0905; border: 1px solid color-mix(in srgb, var(--sc) 40%, transparent); border-radius: 2px; }
.sh-ware .glyph { width: 22px; height: 22px; margin: 0; }
.sh-mult { grid-area: mult; font: 600 24px/1 var(--mono); color: var(--sc); white-space: nowrap; }
.sh-spark { grid-area: spark; width: 46px; height: 16px; }
.sh-spark polyline { fill: none; stroke: var(--sc); stroke-width: 1.5; stroke-linejoin: round; opacity: 0.85; }
.sh-name { grid-area: name; overflow: hidden; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--muted); white-space: nowrap; text-overflow: ellipsis; }
.sh-act { grid-area: act; padding: 3px 8px; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--sc); border: 1px solid color-mix(in srgb, var(--sc) 55%, transparent); border-radius: var(--r-tag); }

/* Outbreak: the family's code, ×2. */
.ob-tile { display: flex; align-items: center; gap: var(--s5); cursor: help; }
.ob-glyph { display: grid; place-items: center; width: 40px; height: 40px; box-sizing: border-box; color: var(--amber); background: #0c0905; border: 1px solid var(--line-strong); border-radius: 2px; }
.ob-glyph .glyph { width: 22px; height: 22px; margin: 0; }
.ob-mult { font: 600 26px/1 var(--mono); color: var(--amber); text-shadow: 0 0 10px rgba(241, 185, 47, 0.35); }
.ob-name { display: grid; gap: 1px; min-width: 0; }
.ob-name b { font: 600 13px var(--mono); color: var(--bright); }
.ob-name small { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); }

/* Darknet listing: the unique's glyph and name, its network, a price tag you buy with. */
.dk-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--s5); }
.dk-glyph { display: grid; place-items: center; width: 46px; height: 46px; box-sizing: border-box; overflow: hidden; background: #0c0905; border: 1px solid color-mix(in srgb, var(--r-zeroday) 45%, transparent); border-radius: 2px; }
.dk-glyph .pglyph { padding: 0; }
.dk-who { display: grid; gap: 3px; min-width: 0; }
.dk-who b { overflow: hidden; font: 600 13px var(--mono); white-space: nowrap; text-overflow: ellipsis; }
.dk-who small { display: flex; align-items: center; gap: 4px; overflow: hidden; font: 11px var(--mono); color: var(--dim); white-space: nowrap; }
.dk-who small .glyph { width: 11px; height: 11px; margin: 0; }
.dk-price { display: grid; justify-items: end; gap: 2px; margin: 0; padding: 5px 9px; font: 600 12px var(--mono); color: var(--text); border: 1px solid var(--line-strong); border-radius: var(--r-btn); background: rgba(241, 185, 47, 0.05); transition: border-color 0.12s, box-shadow 0.12s; }
.dk-price span { display: inline-flex; align-items: center; gap: 4px; }
.dk-price .glyph { width: 12px; height: 12px; margin: 0; color: var(--amber); }
.dk-price small { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--amber); }
.dk-price:hover:not(:disabled), .dk-price:focus-visible { border-color: var(--amber); box-shadow: inset 0 0 0 1px var(--amber); outline: none; }
.dk-price:active:not(:disabled) { transform: translateY(1px); }

/* Leak: the vault key, as a tile, until the vault's open. */
.lk-tile { display: flex; align-items: center; gap: var(--s5); cursor: help; }
.lk-key { display: grid; place-items: center; width: 34px; height: 34px; box-sizing: border-box; color: var(--amber); background: #0c0905; border: 1px solid var(--line-strong); border-radius: 2px; }
.lk-key .glyph { width: 18px; height: 18px; margin: 0; }
.lk-tile code { padding: 3px 8px; font: 600 15px var(--mono); letter-spacing: 1px; border: 1px dashed var(--line-strong); border-radius: var(--r-tag); }
.lk-vault { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; color: var(--you); }
.lk-vault .glyph { width: 13px; height: 13px; margin: 0; }
.lk-vault small { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; }

/* Chains (events.mjs): a follow-up's link mark in the strip, the event that caused it on hover; a button to its server. */
.evc-link { display: inline-grid; place-items: center; flex: none; width: 18px; height: 18px; margin: 0; padding: 0; box-sizing: border-box; color: var(--ec); background: color-mix(in srgb, var(--ec) 10%, transparent); border: 1px solid color-mix(in srgb, var(--ec) 45%, transparent); border-radius: 50%; cursor: help; transition: border-color 0.12s, box-shadow 0.12s, background-color 0.12s; }
.evc-link .glyph { width: 11px; height: 11px; margin: 0; }
button.evc-link { cursor: pointer; }
button.evc-link:hover, button.evc-link:focus-visible { border-color: var(--ec); background-color: color-mix(in srgb, var(--ec) 22%, transparent); box-shadow: 0 0 8px color-mix(in srgb, var(--ec) 45%, transparent); outline: none; }
button.evc-link:active { transform: translateY(1px); }
.comms .cchain { display: inline-flex; margin-left: 4px; vertical-align: -1px; cursor: help; }
.comms .cchain .glyph { width: 11px; height: 11px; margin: 0; }

/* Counter-raid: the blow swings back, an arc from the side you fought onto your server (your side's mark on it). */
.cx-blow { position: relative; display: flex; align-items: flex-end; justify-content: space-between; height: 34px; margin: 0 2px; cursor: help; }
.cx-from, .cx-to { position: relative; z-index: 1; display: grid; place-items: center; width: 26px; height: 26px; box-sizing: border-box; background: var(--inset); border-radius: 2px; }
.cx-from { color: var(--fc); border: 1px solid var(--fc); box-shadow: 0 0 10px color-mix(in srgb, var(--fc) 40%, transparent); }
.cx-from .glyph { width: 17px; height: 17px; margin: 0; }
.cx-to { color: var(--muted); border: 1px solid var(--line-strong); }
.cx-to > .glyph { width: 13px; height: 13px; margin: 0; }
.cx-arc { position: absolute; left: 16px; right: 36px; top: 2px; height: 22px; border: 2px dashed color-mix(in srgb, var(--fc) 70%, transparent); border-bottom: 0; border-radius: 50% 50% 0 0 / 100% 100% 0 0; }
.cx-arc::after { content: ''; position: absolute; right: -6px; bottom: -6px; border: 5px solid transparent; border-top: 7px solid var(--fc); border-bottom-width: 0; }
.cx-hit { position: absolute; inset: -5px; border: 1px solid var(--fc); border-radius: 50%; opacity: 0.7; animation: cx-hit 2.4s ease-out infinite var(--ph, 0s); pointer-events: none; }
.cx-mine { position: absolute; right: -6px; bottom: -6px; display: grid; place-items: center; width: 14px; height: 14px; color: var(--yc); background: var(--inset); border: 1px solid var(--yc); border-radius: 50%; }
.cx-mine .glyph { width: 9px; height: 9px; margin: 0; }
.evc-target.runner .evc-face { color: var(--ec); border-color: color-mix(in srgb, var(--ec) 60%, transparent); }
@keyframes cx-hit { 0% { transform: scale(0.6); opacity: 0.9; } 70%, 100% { transform: scale(1.25); opacity: 0; } }

/* Returning bounty: the wanted tile, back once (its last-chance tag is a hot tag). */

/* LANTERN's offer: the courier's line in LANTERN's colour; its lamp is the packet. */
.evc-target.lantern .evc-face { color: var(--r-custom); }
.evc-tags .tag.r-custom { color: var(--r-custom); border-color: color-mix(in srgb, var(--r-custom) 50%, transparent); }

/* Patient zero: the family's code glyph at an epicentre, rings going out; the outbreak's ×2 struck through. */
.evc-target.zero .evc-face { color: var(--amber); overflow: visible; }
.zr-ring { position: absolute; inset: 6px; border: 1px solid var(--amber); border-radius: 50%; opacity: 0; animation: zr-out 2.4s ease-out infinite var(--ph, 0s); pointer-events: none; }
.zr-ring.r2 { animation-delay: calc(var(--ph, 0s) - 1.2s); }
.zr-end { display: inline-flex; align-items: center; gap: 2px; color: var(--amber); cursor: help; }
.zr-end .glyph { width: 11px; height: 11px; margin: 0; }
.zr-end s { text-decoration-thickness: 2px; text-decoration-color: var(--hot); }
@keyframes zr-out { 0% { transform: scale(0.5); opacity: 0.9; } 100% { transform: scale(1.6); opacity: 0; } }
.no-motion .zr-ring:not(.r2), .no-motion .cx-hit { opacity: 0.35; transform: scale(1.15); }
@media (prefers-reduced-motion: reduce) { .zr-ring:not(.r2), .cx-hit { opacity: 0.35; transform: scale(1.15); } }

@keyframes evc-pulse { 50% { opacity: 0.55; } }
@keyframes evc-glow { 50% { box-shadow: 0 0 2px color-mix(in srgb, var(--ec) 30%, transparent); } }
.no-motion .evc, .no-motion .evc * { animation: none !important; }
@media (prefers-reduced-motion: reduce) { .evc, .evc * { animation: none !important; transition: none !important; } }
/* A feud on the map: its bar, small, under the antenna. */
.feudmark rect { stroke: rgba(9, 6, 3, 0.9); stroke-width: 0.5; }
.tag.shock { cursor: help; }
.tag.shock.up { color: #8fd46b; border-color: currentColor; }
.tag.shock.down { color: #ff6f91; border-color: currentColor; }
.tag.shock .glyph { width: 12px; height: 12px; margin: 0 2px; vertical-align: -2px; }
.mnode .hub-shock rect { fill: rgba(9, 6, 3, 0.9); stroke: currentColor; stroke-width: 1; }
.mnode .hub-shock text { fill: currentColor; font: 600 10px var(--mono); }
.mnode .hub-shock .hs-in { transform: scale(calc(1 / var(--z, 1))); }
.mnode .hub-shock .hs-ware { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.mnode .hub-shock.up { color: #8fd46b; } .mnode .hub-shock.down { color: #ff6f91; }
.mhunt line { stroke: var(--daemon, #c3a6ff); stroke-width: 1.4; stroke-dasharray: 4 4; animation: mflow 1.6s linear infinite; }
.mhunt path { fill: var(--daemon, #c3a6ff); }
.no-motion .mhunt line { animation: none; }

/* Buildings on a held server (outpost.mjs): slots and bandwidth, what's built, the build, the store, the Build list. */
.outpost .op-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin: 8px 0 4px; }
.outpost .op-meta { display: flex; gap: 12px; font: 11px var(--mono); color: var(--muted); }
.outpost .op-meta span { display: inline-flex; align-items: center; gap: 4px; }
.outpost .op-meta .glyph { width: 1em; height: 1em; }
/* One labeled row each for Buildings, Stored and Wall: label on the left, its content on the right. */
.outpost .op-row { display: grid; grid-template-columns: 72px 1fr; gap: 8px; align-items: start; padding: 7px 0; border-top: 1px solid var(--line); }
.outpost .op-label { font: 600 10px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--dim); padding-top: 5px; }
.outpost .op-val { min-width: 0; }
.outpost .op-val .mods { margin-top: 0; gap: 6px; }
.outpost .op-val .fw-mini { margin: 0; padding: 0; border: 0; background: none; }
.outpost .op-store { display: flex; align-items: center; gap: 4px 10px; flex-wrap: wrap; padding-top: 3px; }
.outpost .op-stock { display: inline-flex; align-items: center; gap: 4px; font: 12px var(--mono); color: var(--text); }
.outpost .op-stock .glyph { width: 1em; height: 1em; }
.outpost .op-store small { flex-basis: 100%; color: var(--dim); font-size: 11px; }
.outpost .op-build { margin-top: 8px; }
.op-buildlist { margin-top: 10px; }
.op-buildlist summary { cursor: pointer; font: 600 12px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.op-buildlist .bl { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 6px; }
.op-buildlist .bl li { display: flex; gap: 10px; align-items: flex-start; justify-content: space-between; padding: 6px 8px; border: 1px solid var(--line); border-radius: 4px; }
.op-buildlist .bl li.locked { opacity: 0.6; }
.op-buildlist .bl-main { display: grid; gap: 2px; min-width: 0; }
.op-buildlist .bl-main b { font-size: 13px; }
.op-buildlist .bl-main small { font-size: 11px; color: var(--muted); line-height: 1.35; }
.op-buildlist .bl-cost { color: var(--dim) !important; }
.op-buildlist .bl-why { color: var(--warn, #e0a030) !important; }
.coll-set { margin: 4px 0 8px; color: var(--amber); font-size: 12px; letter-spacing: 1px; }
.coll li.heard { outline: 1px solid var(--hot); }
.coll .coll-listen { float: right; margin-top: -30px; font-size: 11px; padding: 1px 6px; }
/* The subclass row over Skills and talents: the class alone and its two subclasses, to look at; the one on show
   under it (Preview, or yours) with its Pick. */
.sub-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0; min-height: 26px; }
.tag.preview { border-style: dashed; color: var(--next); border-color: var(--next); }
/* Rule text's key facts (ruletext.mjs): the numbers and what they count, in white; the rest keeps its tone. */
b.hi { color: var(--bright); font-weight: 600; letter-spacing: normal; }
/* The Build panel (view.mjs buildPanelMarkup): a wide sheet over the map for one held server. */
.build-panel { position: absolute; inset: 44px 12px 12px; z-index: 6; overflow: auto; background: var(--panel, #120f0a); border: 1px solid var(--amber-deep, #7e5311); border-radius: 4px; padding: 16px 18px; filter: drop-shadow(0 12px 30px rgba(0, 0, 0, 0.65)); }
.build-panel .bp-head { display: flex; align-items: flex-start; gap: 16px; padding-right: 36px; margin-bottom: 8px; }
.build-panel .bp-head h1 { margin: 2px 0 0; }
.build-panel .bp-meta { display: flex; gap: 8px; align-items: center; margin-left: auto; flex-wrap: wrap; }
.build-panel .bp-x { position: absolute; top: 12px; right: 12px; }
.build-panel .bp-now { margin: 4px 0; font-size: 12px; color: var(--muted); display: flex; gap: 6px; align-items: center; }
.build-panel .bp-grid { list-style: none; margin: 10px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
.build-panel .bp-card { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 4px; }
.build-panel .bp-card.locked { opacity: 0.55; }
.build-panel .bp-top { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.build-panel .bp-top b { display: flex; gap: 6px; align-items: center; font-size: 14px; }
.build-panel .bp-card p { margin: 0; font-size: 12px; line-height: 1.4; }
.build-panel .bp-card small { font-size: 11px; color: var(--muted); }
.build-panel .bp-card .bl-why { color: var(--amber-soft, #d69a22); }
.build-panel .bp-card .btn { align-self: flex-start; margin-top: auto; }
.op-build-open small { margin-left: 8px; opacity: 0.75; font-size: 11px; }
@media (max-width: 700px) { .build-panel { inset: 40px 6px 6px; padding: 12px; } .build-panel .bp-grid { grid-template-columns: 1fr; } }
/* A long spoils card: the header and the Continue button stay put, the rewards scroll between them. */
.sp-card { display: flex; flex-direction: column; }
.sp-card > .sp-head, .sp-card > .sp-xp, .sp-card > .sp-level, .sp-card > .sp-go { flex: none; }
.sp-card > .sp-rows { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
/* On a phone the virus panel is a strip: the win card lifts out of it to the whole screen, so its rows (loot, XP, a
   daemon) are never squeezed to nothing. */
@media (max-width: 640px) {
  .spoils { position: fixed; inset: 0; z-index: 70; padding: 16px; }
  .spoils .sp-card { width: 100%; max-height: calc(100dvh - 32px); }
}

/* A page that failed to draw (app.js pageOrError): the error, selectable, and a way back. */
.page-error { max-width: 720px; margin: 24px auto; border-color: var(--hot); }
.page-error pre { white-space: pre-wrap; user-select: text; font: 12px var(--mono); color: var(--text); background: var(--inset); padding: 10px; border-radius: 3px; max-height: 240px; overflow: auto; }

/* Networks (network.mjs): a signature as a card, a member's network as a chip, a native unique's home */
.cm-net { justify-self: start; display: inline-flex; align-items: center; gap: 4px; max-width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 12px; }
.cm-net small { color: var(--dim); }
.net-card h1 { font-size: 20px; }
.lean-bar { display: flex; height: 22px; margin: 8px 0 10px; border: 1px solid var(--line-strong); border-radius: 3px; overflow: hidden; background: var(--inset); }
.net-none { margin: 8px 0 10px; color: var(--muted); font-size: 13px; }
.lean-seg { display: inline-flex; align-items: center; gap: 4px; min-width: 0; padding: 0 6px; overflow: hidden; white-space: nowrap; font: 600 11px var(--mono); letter-spacing: 0.5px; color: var(--bg); }
.lean-seg.l0 { background: var(--amber); } .lean-seg.l1 { background: var(--amber-soft); } .lean-seg.l2 { background: var(--amber-deep); color: var(--text); }
.lean-seg .glyph { flex: none; }
.net-rows { display: grid; gap: 4px; margin: 0 0 10px; }
.net-row { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 8px; align-items: center; }
.net-row dt { font: 600 11px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.net-row dd { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.net-row dd small { color: var(--dim); font-size: 11px; }
.net-sub { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; font: 600 11px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.net-natives { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px 12px; }
.net-native { display: grid; gap: 1px; padding: 4px 0; border-top: 1px solid var(--line); }
.net-native small { font-size: 11px; color: var(--dim); }
.net-native .coll-q { color: var(--gray); letter-spacing: 2px; }
.net-native .act, .net-native .tag { justify-self: start; }
.ptip-body .tag.native { justify-self: start; color: var(--r-zeroday); border-color: rgba(212, 166, 74, 0.5); }
/* Genes (genome.mjs): a virus's byline, its gene chips, the scan card and the codex by gene */
.byline { margin-left: 6px; font: 600 11px var(--mono); letter-spacing: 1px; color: var(--ac, var(--muted)); white-space: nowrap; }
.byline.stray { color: var(--dim); }
h1 .byline { font-size: 13px; vertical-align: middle; }
.hud-bar .bar-top .vname .byline { flex-shrink: 0; margin-left: -4px; font: 600 11px var(--mono); letter-spacing: 1px; line-height: 1.2; color: var(--ac, var(--muted)); }
.gene-line { display: flex; flex-wrap: wrap; gap: 4px; margin: 4px 0 0; }
.gchip { display: inline-flex; align-items: center; gap: 3px; padding: 0 5px; border: 1px solid color-mix(in srgb, var(--ax) 55%, transparent); border-radius: 2px; color: var(--ax); font: 500 10px/16px var(--mono); letter-spacing: 0.5px; white-space: nowrap; cursor: help; }
.gchip .glyph { width: 10px; height: 10px; margin: 0; }
.gchip.g-core { opacity: 0.55; border-style: dashed; }
.gchip.unknown { color: var(--dim); border-color: var(--line); opacity: 1; }
.gchip.g-tell { border-style: dotted; }
.scan-card { display: grid; gap: 4px; margin: 2px 0; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: 4px; background: var(--inset); }
.sc-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; }
.sc-head b { color: var(--bright); letter-spacing: 1px; }
.sc-head small { color: var(--dim); }
.sc-style { margin: 0; color: var(--muted); font-size: 12px; }
.sc-row { display: flex; gap: 8px; align-items: baseline; }
.sc-k { flex: 0 0 42px; color: var(--dim); font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }
.sc-chips { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0; }
.sc-deep { list-style: none; margin: 2px 0 0; padding: 0; display: grid; gap: 2px; font-size: 12px; color: var(--muted); }
.sc-deep b { color: var(--bright); }
.cx-gene span { display: flex; align-items: center; gap: 5px; }
.cx-gene em { font-style: normal; font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--dim); }
.cx-gene .gax { display: inline-flex; color: var(--ax); }
.cx-gene .gax .glyph { width: 11px; height: 11px; margin: 0; }
.cx-gene.seen span { color: var(--muted); }
.cx-gene .cx-tele, .cx-gene .cx-answer { color: var(--dim); }
.cx-gene.on .cx-answer { color: var(--you); }
/* A long genome name (WARDED CRYPTJACK-4821 v2 · TOLLGATE) wraps on a phone instead of losing its byline */
@media (max-width: 900px) {
  .hud-bar .bar-top .vname { flex-wrap: wrap; white-space: normal; row-gap: 2px; }
  .hud-bar .bar-top .vname strong { font-size: 14px; letter-spacing: 1px; overflow-wrap: anywhere; }
  .hud-bar .bar-top .vname .byline { margin-left: 0; }
}
.cx-gene .cx-tele .glyph { width: 10px; height: 10px; margin: 0 4px 0 0; vertical-align: -1px; }

/* Themed hover tips (app.js): every title in the game, in the game's own card. */
.tt { position: fixed; z-index: 90; max-width: calc(300px * var(--ui, 1)); padding: calc(8px * var(--ui, 1)) calc(11px * var(--ui, 1)); background: rgba(10, 8, 5, 0.97); color: var(--text); border: 1px solid var(--line-strong); border-top: 2px solid var(--amber); border-radius: 4px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55); font: calc(13px * var(--ui, 1))/1.45 var(--sans, inherit); pointer-events: none; white-space: pre-line; animation: ptip-in 0.12s ease-out; }
.tt b { display: block; margin-bottom: 3px; color: var(--amber); font: 600 calc(12px * var(--ui, 1)) var(--mono); letter-spacing: 0.5px; }
.tt .tt-state { display: block; margin-bottom: 4px; font-size: calc(12px * var(--ui, 1)); } /* what holds now (a tray key's), coloured by its job */
.tt .tt-state.hot { color: var(--hot); } .tt .tt-state.amber { color: var(--amber); } .tt .tt-state.you { color: var(--you); } .tt .tt-state.steel { color: var(--steel); } .tt .tt-state.muted { color: var(--muted); }
.tt .tt-kind { display: block; margin: -2px 0 4px; color: var(--muted); font-size: calc(12px * var(--ui, 1)); } /* a tray key's verb and cooldown */
.tt .tt-mastery { display: block; margin-top: 4px; color: var(--you); font: 600 11px var(--mono); letter-spacing: 0.3px; } /* an ability's mastery line (mastery.mjs) */
.tt .tt-more { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; white-space: normal; } /* icon chips under the text (a contract's pay) */
.tt .tt-more b { display: inline; margin: 0; color: var(--bright); font: 700 12px var(--mono); letter-spacing: 0; }
.tt .tt-more .rw.neg b { color: var(--hot); } /* a cost (a server special's) */
.tt .tt-more .tt-ct { flex: 1 1 100%; cursor: inherit; backdrop-filter: none; } /* a contract as the map's tracker draws it (floorplan-view.mjs strip) */
.tt .tt-ct .ct-txt b { display: block; margin: 0; color: var(--bright); font: 600 12px var(--sans, inherit); letter-spacing: 0; }
.tt .tt-ans { display: block; margin-top: 5px; padding-top: 4px; border-top: 1px solid var(--line); color: var(--muted); font-size: calc(12px * var(--ui, 1)); } /* the answer line (fightread.mjs answerLine) */
@media (prefers-reduced-motion: reduce) { .tt { animation: none; } }


/* =====================================================================================================
   UI SYSTEM (docs/ui.md). Shared components and the fixes that bring older pieces onto them.
   Tokens live on :root. Later rules here win over the per-feature rules above on purpose.
   ===================================================================================================== */

/* ---- Buttons: two heights, one shape. Content centres; an icon and a label keep a 6px gap. ---- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--s3); min-height: var(--h-btn); padding: 0 14px; line-height: 1.2; border-radius: var(--r-btn); text-align: center; }
.btn.small { min-height: var(--h-btn-sm); padding: 0 9px; font-size: 12px; }
.btn .glyph { flex: none; }
/* A row of actions: one gap, wraps cleanly, never a lone giant button beside a small one. */
.row { gap: var(--s3); }

/* ---- Tag lines: a level, then tags. Flex with a gap, so a tag never butts into the level before it. ---- */
.tagline { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3); }
.tagline > .tag { margin: 0; }

/* ---- Stat tiles: label (mono caps) over value. Tiles share a row and the last row fills, no orphans. ---- */
.stats { display: flex; flex-wrap: wrap; gap: var(--s4); }
.stats > .stat { flex: 1 1 auto; min-width: 80px; }
.sb-select .stats { grid-template-columns: none; }
.stat { display: grid; align-content: start; gap: var(--s1); }
.stat span { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); }
.stat strong { line-height: 1.2; overflow-wrap: anywhere; }

/* ---- Pages never scroll sideways: a column can't be pushed wider than the page by its content. ---- */
.page-grid > * { min-width: 0; }
.page-grid > div:not([class]) { grid-template-columns: minmax(0, 1fr); }

/* ---- Item rows with an action on the right (collection, a network's natives): name over meta, action in its own column. ---- */
.coll li, .net-native { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--s4); row-gap: var(--s1); align-items: center; }
.coll li > :not(.coll-listen), .net-native > :not(.act):not(.tag) { grid-column: 1; }
.coll .coll-listen, .net-native > .act, .net-native > .tag { grid-column: 2; grid-row: 1 / span 2; float: none; margin: 0; justify-self: end; }
/* the small action: a framed mono word, the size of a tag */
.coll .coll-listen, .net-native > .act { display: inline-flex; align-items: center; min-height: var(--h-chip); padding: 0 var(--s3); border: 1px solid var(--line-strong); border-radius: var(--r-btn); font: 500 11px var(--mono); letter-spacing: 0.5px; color: var(--muted); background: none; }
.coll .coll-listen:hover, .net-native > .act:hover { color: var(--amber); border-color: var(--amber); }

/* ---- Pane titles ([ ssh … ]) sit on the panel's top edge: the page leaves room so they're never clipped. ---- */
.shell-on .page:has(.net-one[data-pane]), .shell-on .page:has(> .hub-session) { padding-top: var(--s4); }
/* the fight log scrolls under its title: fade the top so a cut line reads as scrolled, not broken */
.shell-on .log[data-pane] .log-lines { padding-top: var(--s5); -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 18px); mask-image: linear-gradient(to bottom, transparent 0, #000 18px); }

/* ---- Build panel: the card kicker over the name; a long building name pushes its role tag to the next line. ---- */
.build-panel .bp-head h2 { font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; color: var(--muted); }
.build-panel .bp-head h1 { font-size: 24px; letter-spacing: 1px; color: var(--bright); }
.build-panel .bp-grid { grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); }
.build-panel .bp-top { flex-wrap: wrap; row-gap: var(--s2); }
.build-panel .bp-top b { flex: 1 1 auto; }
.build-panel .bp-top .tag { flex: none; }

/* ---- Phone: hub windows stack under their terminal instead of squeezing beside it. ---- */
@media (max-width: 900px) {
  .hub-session.with-win { grid-template-columns: minmax(0, 1fr); }
  .hub-session .hub-term { height: auto; min-height: 0; }
  .hub-session .hub-win { order: -1; max-height: none; }
}
@media (max-width: 700px) {
  .mk-wares .mk-tr { grid-template-columns: minmax(0, 1fr) 36px 84px 52px; column-gap: var(--s4); padding-left: var(--s2); padding-right: var(--s2); }
  .mk-name { gap: var(--s3); }
}

/* ---- Tiles (daemons, protocols, shop wares): the action row sits on the tile's floor, level across a row. ---- */
.ptile { display: flex; flex-direction: column; gap: 3px; }
.ptile > .tag { align-self: flex-start; }
.ptile-acts { margin-top: auto; padding-top: var(--s2); align-items: center; }
.ptile.empty { justify-content: space-between; }

/* ---- Key cells (the Loadout bar): icon over name, the name wraps to two lines instead of clipping. ---- */

/* ---- Settings (System): toggles in an even grid, each with a lamp (lit = on), like the casing's lamps.
   The sound test is its own block under a label, with small keys. ---- */
.settings-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: var(--s3); }
.settings-grid .btn { justify-content: flex-start; padding: 0 var(--s5); color: var(--text); }
.settings-grid .btn[aria-pressed]::before { content: ''; flex: none; width: 7px; height: 7px; border-radius: 50%; background: #3a2f1c; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5); }
.settings-grid .btn[aria-pressed='true'] { border-color: var(--line-strong); color: var(--bright); }
.settings-grid .btn[aria-pressed='true']::before { background: var(--amber); box-shadow: 0 0 6px rgba(241, 185, 47, 0.7); }
.settings-grid .btn[aria-pressed='false'] { color: var(--muted); }
.sound-test { margin-top: var(--s4); padding-top: var(--s5); border-top: 1px solid var(--line); }
.sound-test .next-label { flex-basis: 100%; font: var(--label); letter-spacing: var(--label-track); }
.sound-test .btn { min-height: var(--h-btn-sm); padding: 0 var(--s4); font-size: 12px; color: var(--muted); }

/* ---- Phone layout (≤900px): the top bar in two tidy rows, a map you can read, a fight HUD that stacks. ---- */
@media (max-width: 900px) {
  /* top bar, three rows on a grid: brand · pager · credits, then Integrity and Signal, then the tabs */
  .topbar { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; align-items: center; gap: var(--s4) var(--s5); }
  .topbar > .meters { display: contents; }
  .topbar .brand { grid-area: 1 / 1; }
  .topbar .pager { grid-area: 1 / 2; margin: 0; justify-self: start; }
  .meters > .meter, .meters > .meter[data-command] { padding: 0; min-height: 26px; border-left: 0 !important; }
  .meters > .meter:last-child { grid-area: 1 / 4; justify-self: end; }
  #meter-integrity { grid-area: 2 / 1 / 3 / 3; }
  #meter-signal { grid-area: 2 / 3 / 3 / 5; justify-self: end; }
  .topbar .modules { grid-area: 3 / 1 / 4 / 5; }
  .modules { justify-content: space-between; gap: 0; }
  .modules button { padding: 6px 5px; font-size: 13px; }
  /* map: the threat rail sits above the scope, and the scope keeps a usable height under it */
  .map-canvas { height: auto; }
  .map-svg { flex: none; height: 380px; }
  .threat-rail { gap: var(--s2); }
  .tr-row { padding: 5px 8px; }
  .map-pop { width: auto; left: var(--s3) !important; right: var(--s3); }
  .map-pop .card h1 { font-size: 20px; overflow-wrap: anywhere; }
  /* fight HUD: your side and your statuses on one row, the virus's bar under them */
  .hud { grid-template-columns: minmax(0, 1fr); row-gap: var(--s5); }
  .hud-left { grid-template-columns: minmax(0, 1fr) minmax(0, 0.7fr); gap: var(--s5); }
}

/* ---- The pause banner sits in the phase strip's empty right end, not over "Your move". ---- */
#board .pause-strip { left: auto; right: 12px; top: 3px; transform: none; padding: 2px 10px; }
@media (max-width: 900px) { #board .pause-strip { position: static; transform: none; margin: 4px 12px 8px; text-align: center; white-space: normal; } }

/* ---- Service rows (Server): the action sits top right beside the name, not floating mid-row. ---- */
.gstash .svc { align-items: flex-start; }
.gstash .svc .gitem-actions { padding-top: 2px; }

/* ---- Mail: a row with no faction still fills the icon column, with a quiet neutral mark. ---- */
.mrow .mrow-none { display: inline-grid; place-items: center; width: 17px; height: 17px; }
.mrow .mrow-none::before { content: ''; width: 5px; height: 5px; border: 1px solid var(--dim); transform: rotate(45deg); }

/* ---- Action rows (.row.acts): the buttons share each line edge to edge, so a wrapped row is never ragged. ---- */
.row.acts > .btn { flex: 1 1 auto; }
.srv-card .row.acts { margin-top: var(--s4); }

/* ---- Phone with a crew: the crew column stacks over the page instead of squeezing it to a strip. ---- */
@media (max-width: 900px) {
  body.with-sidebar .workspace { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto; }
  body.with-sidebar .workspace > .combat, body.with-sidebar .workspace > .page { grid-column: 1; grid-row: 2; }
  body.with-sidebar .sidebar { grid-column: 1; grid-row: 1; max-height: none; overflow: visible; border-right: 0; border-bottom: 1px solid var(--line-strong); padding: var(--s4) 0; }
}

/* ---- Nothing scrolls the page sideways: a hit's shake or a stray chip is clipped at the app's edge
   (clip, not hidden: no scroll box, so sticky and fixed children still work). ---- */
.app { overflow-x: clip; }
.intent { min-width: 0; }
.intent small { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ---- Tell chips in a narrow column (a crew's side column takes width): the chip keeps its "→ who" tab
   (no clipping box), and its strips tighten instead of cutting words off at the cell's edge. ---- */
.intent.tell { overflow: visible; }
.intent.tell .tl-kick { border-radius: 2px 2px 0 0; overflow: hidden; }
.intent.tell .tl-main b { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
#board .bcell { container-type: inline-size; }
@container (max-width: 132px) {
  .intent.tell .tl-kick { gap: 3px; padding: 2px 5px; letter-spacing: 0.4px; }
  .intent.tell .tl-kick .ico { display: none; }
  .intent.tell .tl-kick .ico.tl-sig { display: block; } /* the kind is the kick word; the SIGINT mark stays */
  .intent.tell .tl-main { padding: 3px 5px 4px; column-gap: 4px; }
}


/* ---- The error card reads as an alert, like any other hot card: its kicker in red. ---- */
.page-error h2 { color: var(--hot); }
.page-error pre { border-left: 2px solid var(--hot); }
.settings-grid .btn[data-toggle='speed'] { grid-column: span 2; }
.settings-grid .btn { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.net-natives { grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); }
@media (max-width: 420px) { .settings-grid .btn[data-toggle='speed'] { grid-column: 1 / -1; } }

/* ---- Run header: pack and leads are the same small control, one line each, the same height. ---- */
.net-pack { display: inline-flex; align-items: center; gap: var(--s3); min-height: var(--h-btn-sm); padding: 0 10px; white-space: nowrap; }

/* ---- Map list, phone: name and level on the first line, status tags and progress on the second.
   Every row the same shape (before: hidden columns left rows of different heights). ---- */
@media (max-width: 700px) {
  .sl-head, .sl-row { grid-template-columns: minmax(0, 1fr) 96px 36px; row-gap: var(--s2); }
  .sl-head > :nth-child(n+4) { display: none; }
  .sl-row > :nth-child(4) { display: none; }
  .sl-row > :nth-child(5) { grid-column: 1; grid-row: 2; }
  .sl-row > :nth-child(6) { grid-column: 2 / 4; grid-row: 2; justify-content: flex-end; }
  .sl-row > :nth-child(6):empty { display: none; }
}
/* Phone, seven tabs or more (Consortium, Store, Fight or Run up): a size down so every tab stays on screen. */
@media (max-width: 900px) {
  .modules:has(#tab-consortium:not([hidden])) button, .modules:has(#tab-store:not([hidden])) button, .modules:has(#tab-combat:not([hidden])):has(#tab-net:not([hidden])) button, .modules[data-tabs='7'] button { padding: 6px 2px; font-size: 12px; }
  /* Eight or more (the Codex, Consortium and a Run or Fight tab up together): two even rows, so none runs off the screen. */
  .modules[data-tabs='8'], .modules[data-tabs='9'], .modules[data-tabs='10'] { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); overflow: visible; }
  .modules[data-tabs='9'], .modules[data-tabs='10'] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .modules[data-tabs='8'] button, .modules[data-tabs='9'] button, .modules[data-tabs='10'] button { padding: 5px 2px; font-size: 13px; text-align: center; }
  .modules .count { margin-left: 2px; }
}

/* ---- A hub's mark is drawing, not text: it never wraps, and it never shrinks for the name beside it. ---- */
.hub-ascii { white-space: pre; flex: none; overflow: visible; max-height: none; }
@media (max-width: 700px) { .term li.hub-banner { gap: var(--s5); } .hub-ascii { font-size: 10px; } }

/* ---- Board, phone: a part's name gets its own line; armor and HP sit under it. The narrow name
   column can't hold all three on one line (before: the HP overlapped a wrapped name, the chits ran
   into the Now column). ---- */
@media (max-width: 900px) {
  #board .part-top { flex-wrap: wrap; row-gap: 0; column-gap: var(--s2); align-items: center; }
  #board .part-top .part-name { flex-basis: 100%; min-width: 0; font-size: 13px; overflow-wrap: break-word; hyphens: auto; line-height: 1.2; }
  #board .part-top .chits { margin-left: 0; font-size: 11px; letter-spacing: 0; overflow: hidden; min-width: 0; }
  #board .part-top .part-hp { margin-left: auto; font-size: 11px; }
}
@media (max-width: 900px) { #board .bpart .intent:not(.tell) { padding: 4px 5px; gap: 3px; justify-content: space-between; } #board .bpart .intent:not(.tell) small { font-size: 11px; } }

/* ---- A loss card is a hot card all the way round: the frame, corners and glow go red with the kicker. ---- */
.gain.loss .sp-card { border-color: rgba(255, 91, 61, 0.55); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), 0 0 36px rgba(255, 91, 61, 0.14); }
.gain.loss .sp-card::before { background: linear-gradient(180deg, rgba(255, 91, 61, 0.08), transparent); }
.gain.loss .sp-corner { border-color: var(--hot); }
/* ---- The death recap (recap.mjs) over a loss card's rows: your Signal over the last cycles as bars (teal what you
   kept, hot what each cycle took, the last one empty), the hits that did it (the biggest lit, the last tagged, a
   tell's icon on a charge), then what you took, healed and shielded. Numbers and marks; the words are in the tips. */
.recap { display: grid; gap: var(--s4); margin-bottom: var(--s5); padding-bottom: var(--s5); border-bottom: 1px dashed var(--line); animation: sp-line 0.34s ease-out both; animation-delay: 160ms; }
.sp-card > .recap { flex: none; }
.rc-strip { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--s4); }
.rc-k, .rc-tot i { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); font-style: normal; white-space: nowrap; }
.rc-bars { display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: 3px; height: 30px; }
.rc-bar { position: relative; background: rgba(241, 185, 47, 0.06); border-bottom: 1px solid var(--line); }
.rc-bar i { position: absolute; left: 0; right: 0; }
.rc-kept { bottom: 0; background: var(--you); opacity: 0.8; }
.rc-lost { background: var(--hot); box-shadow: 0 0 6px rgba(255, 91, 61, 0.45); }
.rc-bar.end { border-bottom-color: var(--hot); }
.rc-ends { font: 600 11px var(--mono); color: var(--dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
.rc-ends b { color: var(--you); } .rc-ends .rc-zero { color: var(--hot); }
.rc-hits { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.rc-hit { display: flex; align-items: center; gap: var(--s3); min-width: 0; padding: 4px 8px 4px 6px; border-left: 2px solid var(--line); background: rgba(255, 91, 61, 0.04); }
.rc-hit .rc-ico { width: 14px; height: 14px; margin: 0; color: var(--muted); }
.rc-hit.k-crit .rc-ico, .rc-hit.k-spike .rc-ico { color: var(--hot); }
.rc-name { flex: 1; min-width: 0; display: grid; line-height: 1.25; }
.rc-name b, .rc-name small { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rc-name b { font-weight: 600; color: var(--text); }
.rc-name small { font-size: 10px; color: var(--dim); }
.rc-tell { flex: none; width: 12px; height: 12px; background: var(--hot); -webkit-mask: var(--icon) center/contain no-repeat; mask: var(--icon) center/contain no-repeat; }
.rc-tell.t-seal, .rc-tell.t-mimic { background: var(--amber); }
.rc-n { flex: none; font: 500 11px var(--mono); color: var(--muted); }
.rc-last { flex: none; font-size: 9px; padding: 0 4px; }
.rc-dmg { flex: none; min-width: 4ch; text-align: right; font: 700 13px var(--mono); color: var(--bright); font-variant-numeric: tabular-nums; }
.rc-hit.top { border-left-color: var(--hot); background: linear-gradient(90deg, rgba(255, 91, 61, 0.16), rgba(255, 91, 61, 0.03)); }
.rc-hit.top .rc-dmg { color: var(--hot); font-size: 15px; }
.rc-tots { display: flex; gap: var(--s3); }
.rc-tot { flex: 1; min-width: 0; display: grid; gap: 1px; padding: 3px 6px; border: 1px solid var(--line); }
.rc-tot b { font: 700 13px var(--mono); font-variant-numeric: tabular-nums; color: var(--you); }
.rc-tot.k-took b { color: var(--hot); } .rc-tot.none b { color: var(--gray); }
@media (prefers-reduced-motion: reduce) { .recap { animation: none; } }
body.no-motion .recap { animation: none; }

/* Firewall upgrade buttons carry their costs: they keep their padding, and in a narrow column (an outpost's Wall
   row) the costs drop under the label instead of running out of the card. */

/* The fight board takes the whole left column, so every part of the virus shows without scrolling. The log moves
   under the picture on the right. Rows are tighter, and if the parts still don't fit, app.js adds .dense and the
   rows tighten again (sub-lines go, chips go to one line). */
@media (min-width: 901px) {
  .combat { grid-template-rows: auto minmax(0, 1fr) minmax(96px, 32%); grid-template-areas: 'hud hud' 'board stage' 'board log'; }
  .combat .board { max-height: none; min-height: 0; }
  body.fight-over .combat { grid-template-rows: auto minmax(0, 1fr); grid-template-areas: 'hud hud' 'log stage'; }
}
.combat .brow:not(.bhead) > .bcell { padding-top: 7px; padding-bottom: 7px; }
.combat .intent { padding: 5px 8px; font-size: 13px; }
.combat .bhead .bcell { padding-top: 4px; padding-bottom: 4px; }
.combat .board.dense .brow:not(.bhead) > .bcell { padding-top: 3px; padding-bottom: 3px; gap: 2px; }
.combat .board.dense .intent { padding: 3px 7px; font-size: 12px; }
.combat .board.dense .intent small:not(.at), .combat .board.dense .bname small, .combat .board.dense .bcell > .quiet, .combat .board.dense .bcell > small.quiet { display: none; }
.combat .board.dense .intent.tell .tl-main { padding-top: 2px; }
.combat .board.dense .intent.tell .tl-main { padding-bottom: 3px; }
.combat .board.dense .bhead .cyclebar { display: none; }
.combat .board.dense .part-top { flex-wrap: nowrap; }
.combat .board.dense .part-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* A short screen: the HUD gives the board its height back. */
@media (min-width: 901px) and (max-height: 820px) {
  .combat { gap: 8px; }
  .combat .hud { padding-top: 6px; padding-bottom: 6px; row-gap: 4px; }
}
.combat .board.dense .brow:not(.bhead) { min-height: 44px; }
.combat .board.dense .brow { grid-template-columns: minmax(200px, 2.2fr) repeat(4, minmax(0, 1fr)); }

/* A holding's wall in a card row (view.mjs fwRow): a status line, then equal action tiles (name over cost). */
.fw-row { display: grid; gap: var(--s4); min-width: 0; }
.fw-stat { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4); font: 12px var(--mono); }
.fw-stat .fw-lv { display: inline-flex; align-items: center; gap: var(--s2); color: var(--bright); }
.fw-stat .fw-lv .glyph { width: 13px; height: 13px; margin: 0; }
.fw-stat .tag { margin: 0; }
.fw-mod { color: var(--muted); } .fw-mod.warn { color: var(--amber); } .fw-mod.you { color: var(--you); }
.fw-vuln { display: inline-flex; align-items: center; gap: var(--s2); font: 600 11px var(--mono); letter-spacing: 0.5px; text-transform: uppercase; }
.fw-vuln::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.fw-vuln.ok { color: var(--you); } .fw-vuln.mid { color: var(--amber); } .fw-vuln.low { color: var(--hot); }
.fw-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: var(--s3); }
.fw-act { display: grid; align-content: start; gap: 3px; min-height: 46px; padding: 6px 10px; text-align: left; background: var(--inset); color: var(--text); border: 1px solid var(--line-strong); border-radius: var(--r-btn); cursor: pointer; }
.fw-act .fa-name { font: 600 12px var(--mono); letter-spacing: 0.3px; }
.fw-act .fa-cost { font: 11px var(--mono); color: var(--muted); }
.fw-act .fa-cost .bcost { margin: 0; padding: 0; border: 0; gap: 6px; flex-wrap: wrap; font-size: 11px; opacity: 1; }
.fw-act .fa-cost .bcost .glyph { width: 11px; height: 11px; }
.fw-act.primary { border-color: var(--amber); }
.fw-act.primary .fa-name { color: var(--amber); }
.fw-act:hover:not(:disabled), .fw-act:focus-visible { border-color: var(--amber); background: rgba(241, 185, 47, 0.06); outline: none; }
.fw-act:disabled { opacity: 0.5; cursor: default; }
.fw-stat .fw-ver { padding: 0 5px; min-height: 0; font-size: 11px; line-height: 16px; }
.fw-stat .fw-lv b { font: 600 13px var(--mono); }
.fw-tiles { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); }
/* In a narrow row the tiles read best as a short list: the action on the left, its price on the right. */
.fw-tiles { grid-template-columns: 1fr; gap: var(--s2); }
.fw-act { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); min-height: 34px; padding: 5px 10px; }
.fw-act .fa-cost { text-align: right; }
.fw-act { flex-wrap: wrap; row-gap: 2px; }
.fw-act .fa-name { white-space: nowrap; }
.fw-act .fa-cost { margin-left: auto; }

/* Sync bonus: the class's Sync Window extra, in the window's yellow (talent tree root, class picker). */

/* Breach healing cap: the bar past the Signal you came into the fight with is fenced off (hatched, a hard edge). */
.bigbar { position: relative; }
.bigbar .heal-cap { position: absolute; top: 0; bottom: 0; display: block; pointer-events: auto; border-left: 2px solid var(--bright); background: repeating-linear-gradient(135deg, rgba(0, 0, 0, 0.6) 0 3px, rgba(255, 255, 255, 0.16) 3px 6px); }

/* Fight readability (fightread.mjs). Your gear's conditional rules under Status: a chip each, lit (teal, a soft glow)
   while its condition holds, dim while it doesn't, struck through once a once-a-fight rule is spent. The board marks
   the columns a cycle rule is live in (a clock in the header) and the parts a part rule holds on (a chip by the name);
   a decoded part whose rule reaches another row says so under its name (a lock: "locks Encryptor"). */
/* The server's leaning (leanings.mjs): amber, a thing you use. Lit on the cycle it paid; its tag on the part's row. */
.gfx.lean .lean-n { font: 700 11px var(--mono); padding-left: 6px; margin-left: 2px; border-left: 1px solid var(--line); }
.gfx.lean.lit { color: var(--amber); border-color: var(--amber); background: rgba(241, 185, 47, 0.12); box-shadow: 0 0 8px rgba(241, 185, 47, 0.3); }
.gfx.lean.lit .lean-n { border-left-color: rgba(241, 185, 47, 0.5); }
.tag.tag-lean { display: inline-flex; align-items: center; gap: 3px; color: #1a1206; background: var(--amber); border-color: var(--amber); font: 700 11px var(--mono); cursor: help; }
.tag.tag-lean .glyph { width: 11px; height: 11px; margin: 0; }
.srv-tags { display: grid; grid-template-columns: auto auto; justify-content: start; gap: var(--s1) var(--s5); align-items: start; margin: var(--s2) 0 var(--s3); }
.srv-tags > :nth-child(even) { padding-left: var(--s5); border-left: 1px solid var(--line); align-self: stretch; } /* Leaning: a rule between the columns */
.srv-tags .tagline { margin: 0; flex-direction: column; flex-wrap: nowrap; align-items: flex-start; } /* a tag a line, never wrapped */
.srv-tags .tag { white-space: nowrap; }
.hud-gear { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--s3); margin-top: var(--s3); min-width: 0; }
.hg-k { display: inline-flex; align-items: center; gap: var(--s1); flex: none; height: var(--h-chip); font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); }
.hg-k .glyph { width: 11px; height: 11px; margin: 0; }
.gfx-list { display: flex; flex-wrap: wrap; gap: 5px; min-width: 0; }
.gfx { display: inline-flex; align-items: center; gap: 4px; height: var(--h-chip); padding: 0 7px; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--inset); color: var(--dim); font: 600 11px/1 var(--sans); max-width: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: help; transition: color 0.15s, border-color 0.15s, background 0.15s, box-shadow 0.15s; }
.gfx .gfx-ico { flex: none; width: 11px; height: 11px; margin: 0; opacity: 0.7; }
.gfx.lit { color: var(--you); border-color: rgba(127, 209, 199, 0.75); background: rgba(127, 209, 199, 0.12); box-shadow: 0 0 8px rgba(127, 209, 199, 0.3); }
.gfx.lit .gfx-ico { opacity: 1; }
.gfx.spent { text-decoration: line-through; opacity: 0.6; }
.gfx.fx-gear { animation: fx-gear 0.7s ease-out; }
@keyframes fx-gear { 0% { background: rgba(127, 209, 199, 0.45); box-shadow: 0 0 16px rgba(127, 209, 199, 0.8); color: var(--bright); } 100% { } }
.fx-float.gear { color: var(--you); font: 600 calc(12px * var(--size)) var(--mono); letter-spacing: 1.5px; text-transform: uppercase; }
.bhead .gcyc { display: inline-grid; place-items: center; margin-left: 4px; color: var(--you); vertical-align: middle; cursor: help; }
.bhead .gcyc .glyph { width: 11px; height: 11px; margin: 0; }
.bhead .bnow .gcyc { margin: 0; }
.bhead .bcell.gear-cyc { box-shadow: inset 0 -2px 0 rgba(127, 209, 199, 0.55); }
.gpart { display: inline-grid; place-items: center; flex: none; width: 16px; height: 16px; margin-left: 4px; border: 1px solid rgba(127, 209, 199, 0.75); border-radius: var(--r-btn); color: var(--you); background: rgba(127, 209, 199, 0.12); cursor: help; }
.gpart .glyph { width: 11px; height: 11px; margin: 0; }
.pcue { display: inline-flex; align-items: center; gap: 3px; max-width: 100%; min-width: 0; padding: 1px 5px; border: 1px dashed var(--line-strong); border-radius: var(--r-tag); color: var(--amber); font: 600 10px/14px var(--mono); letter-spacing: 0.5px; text-transform: uppercase; overflow-wrap: break-word; min-width: 0; }
.pcue .pcue-ico { width: 10px; height: 10px; margin: 0; flex: none; }
.board .bpart.linked { outline: 1px dashed var(--amber); outline-offset: -1px; }
@media (prefers-reduced-motion: reduce) { .gfx.fx-gear { animation: none; } }

/* ---- What protects what (view.mjs guardMarks, tethers; fightread.mjs partLinks). One look for every rule that reaches
   from one part to another: a steel tether in the board's left gutter, from the part the rule sits on (a square) to
   the part it reaches (an arrow), with a node mid-span carrying the rule's icon (lock, ward, twin, re-arm; ? until
   decoded) and its countdown (↻ N). Glowing while the rule holds, grey while it's down (the countdown then is the node), snapping as its part breaks.
   A Mutex's lock sits on its partner's own bar as an absorb segment (hatched steel, a padlock where hits drain it);
   a Lockbox's ward as a cap line at the most the part can still lose this cycle. ---- */

#board:has(.tether) { --gut: 66px; }
#board:has(.tether.lane1) { --gut: 80px; }
@media (max-width: 480px) { #board:has(.tether) { --gut: 56px; } #board:has(.tether.lane1) { --gut: 70px; } }
.tether { --x: 18px; --tt: var(--steel); position: absolute; top: 0; bottom: 0; left: calc(-1 * var(--gut)); width: var(--gut); pointer-events: none; z-index: 1; color: var(--steel); }
.tether.lane1 { --x: 31px; }
.tt-line { position: absolute; left: calc(var(--x) - 1px); width: 2px; background: var(--tt); pointer-events: auto; }
.tt-line::before { content: ''; position: absolute; inset: 0 -4px; } /* a wider hover target than the line */
.tether.stub .tt-line { top: 22% !important; bottom: 22% !important; }
.tt-arm { position: absolute; top: calc(50% - 1px); left: var(--x); right: 6px; height: 2px; background: var(--tt); }
.tt-arm.src::before { content: ''; position: absolute; left: -3px; top: -2px; width: 6px; height: 6px; background: var(--tt); }
.tt-arm.dst::after { content: ''; position: absolute; right: -5px; top: -3px; border: 4px solid transparent; border-left: 5px solid var(--tt); border-right: 0; }
.tt-node { position: absolute; left: var(--x); top: 50%; transform: translate(-50%, -50%); z-index: 2; display: grid; place-items: center; width: 16px; height: 16px; border: 1px solid var(--tt); border-radius: 50%; background: var(--panel); color: var(--tt); font: 700 10px/1 var(--mono); pointer-events: auto; cursor: help; }
.tt-node.edge { top: 100%; }
.tt-node .tt-ico { width: 10px; height: 10px; margin: 0; }
.tether.up .tt-line, .tether.up .tt-arm { box-shadow: 0 0 5px var(--steel-glow); }
.tether.up .tt-node { box-shadow: 0 0 7px var(--steel-glow); }
.tether.up .tt-line { animation: tt-glow 2.4s ease-in-out infinite alternate; }
@keyframes tt-glow { from { box-shadow: 0 0 3px var(--steel-glow); } to { box-shadow: 0 0 8px var(--steel); } }
/* The rule is down (a broken lock waiting to relock, a re-arm counting): the tether goes grey and solid, and only its
   countdown stays steel, so the one lit thing is how long you have. */
.tether.down { --tt: var(--gray); }
.tether.down .tt-line, .tether.down .tt-arm { opacity: 0.6; }
.tt-node.clock { width: auto; height: auto; gap: 3px; grid-auto-flow: column; padding: 1px 5px 1px 4px; border-radius: var(--r-tag); }
.tt-node.clock .tt-ico { width: 11px; height: 11px; }
.tether:has(.tt-node) { z-index: 2; } /* a node on a row's edge sits over the next row's piece of line */
#board:has(.tether.lane1) .tt-node.clock { left: 25px; } /* two lanes: every chip in one column, over both lines */
.tt-count { color: var(--bright); font: 700 13px/16px var(--mono); }
/* Two arms on one row (view.mjs tethers --arm): one a little above the middle, one below, so neither hides the other. */
.tether .tt-arm.dst { top: calc(50% - 1px + var(--arm, 0px)); }
.tether .tt-line[style*="bottom:50%"] { bottom: calc(50% - var(--arm, 0px)) !important; }
.tether .tt-line[style*="top:50%"] { top: calc(50% + var(--arm, 0px)) !important; }
.tether.unk .tt-node { color: var(--muted); border-color: var(--gray); }
/* The part it hangs from breaks: the line flashes and pulls apart, the node bursts (a dissolving row; --snap picks the
   animation up where it was after a redraw). Effects minimal, Motion off: it's simply gone. */
.tether.snap .tt-line, .tether.snap .tt-arm { animation: tt-snap 0.7s ease-out var(--snap, 0ms) forwards; }
.tether.snap .tt-node { animation: tt-node-snap 0.7s ease-out var(--snap, 0ms) forwards; }
@keyframes tt-snap { 0% { background: #eefaff; box-shadow: 0 0 10px #eefaff; opacity: 1; } 35% { opacity: 1; transform: scale(1, 0.55); } 100% { opacity: 0; transform: scale(1, 0); } }
@keyframes tt-node-snap { 0% { transform: translate(-50%, -50%) scale(1); color: #eefaff; box-shadow: 0 0 12px #eefaff; } 30% { transform: translate(-50%, -50%) scale(1.5) rotate(-20deg); opacity: 1; } 100% { transform: translate(-50%, -50%) scale(0.3) rotate(40deg); opacity: 0; } }
.no-motion .tether.up .tt-line, body[data-fx="minimal"] .tether.up .tt-line { animation: none; }
.no-motion .tether.snap, body[data-fx="minimal"] .tether.snap { display: none; }
@media (prefers-reduced-motion: reduce) { .tether.up .tt-line { animation: none; } .tether.snap { display: none; } }
.part-bar.guarded { overflow: visible; }
.part-bar.guarded .loss { z-index: 2; }
.lockseg { position: absolute; top: -1px; bottom: -1px; z-index: 1; display: block; background: repeating-linear-gradient(-45deg, rgba(196, 232, 242, 0.95) 0 2px, rgba(70, 128, 148, 0.92) 2px 4px); box-shadow: 0 0 0 1px var(--steel), 0 0 6px var(--steel-glow); cursor: help; }
.lockpad { position: absolute; left: -7px; top: 50%; transform: translateY(-50%); display: grid; place-items: center; width: 13px; height: 13px; border: 1px solid var(--steel); border-radius: var(--r-tag); background: var(--panel); color: var(--steel); }
.lockpad .glyph { width: 9px; height: 9px; margin: 0; }
.part-bar .loss.lockloss { top: -2px; bottom: -2px; background: #fff; box-shadow: 0 0 8px rgba(238, 250, 255, 0.95); animation: lockloss-blink 0.9s ease-in-out infinite; } /* white, then the bare bar: the lock this hit takes */
@keyframes lockloss-blink { 50% { background: var(--inset); box-shadow: inset 0 0 0 1px #fff; opacity: 1; } }
.no-motion .part-bar .loss.lockloss { animation: none; opacity: 1; }
.wardcap { position: absolute; top: -3px; bottom: -3px; z-index: 2; width: 2px; margin-left: -1px; background: var(--steel); box-shadow: 0 0 4px var(--steel-glow); cursor: help; }
.wardcap::before, .wardcap::after { content: ''; position: absolute; left: -2px; width: 6px; height: 2px; background: inherit; }
.wardcap::before { top: 0; } .wardcap::after { bottom: 0; }
.wardcap.spent { background: var(--bright); }
.fx-float.k-shield:not(.at-you) { color: var(--steel); }
.fx-trail.lock { background: #eefaff; box-shadow: 0 0 10px var(--steel); }
.fx-shard.steel { color: #eefaff; text-shadow: 0 0 6px var(--steel), 0 0 2px #fff; }
.fx-crackring.steel { border-color: #eefaff; box-shadow: 0 0 14px var(--steel); }
.board .bpart.linked .bname { box-shadow: inset 0 0 0 1px var(--steel); }
.fx-float.steel { color: var(--steel); }

/* ---------- floors (floors.mjs, docs/servers.md 5) ---------- */
/* The floor panel: a lift's buttons down the right of the map. Reached floors lit, the next dim, the rest dark. */
.floor-lift { position: absolute; top: 44px; right: 10px; z-index: 3; display: grid; gap: 3px; width: 168px; pointer-events: auto; }
.floor-lift::before { content: ''; position: absolute; left: 14px; top: 10px; bottom: 10px; width: 1px; background: var(--line); z-index: -1; }
.fl-btn { display: grid; grid-template-columns: 22px 1fr auto; align-items: center; gap: 6px; padding: 4px 8px 4px 4px; background: rgba(12, 10, 6, 0.88); border: 1px solid var(--line); border-radius: 3px; color: var(--text); font: 12px var(--mono); text-align: left; cursor: pointer; position: relative; backdrop-filter: blur(2px); }
.fl-btn .fl-n { display: grid; place-items: center; width: 20px; height: 20px; border: 1px solid var(--line-strong); border-radius: 2px; font: 600 11px var(--mono); color: var(--amber); background: var(--inset); }
.fl-btn .fl-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fl-btn small { font: 10px var(--mono); color: var(--muted); white-space: nowrap; }
.fl-btn small b { font-weight: 600; }
.fl-btn:hover:not(:disabled) { border-color: var(--line-strong); }
.fl-btn.on { border-color: var(--amber); background: rgba(40, 30, 10, 0.92); }
.fl-btn.on .fl-n { background: var(--amber); color: #120f0a; border-color: var(--amber); }
.fl-btn.held { box-shadow: inset 2px 0 0 var(--hc); } /* its holder's colour (floors.mjs) */
.fl-btn.next { opacity: 0.6; cursor: default; }
.fl-btn.next .fl-name { color: var(--muted); }
.fl-btn.dark { opacity: 0.32; cursor: default; padding-top: 2px; padding-bottom: 2px; }
.fl-btn.dark .fl-n { color: var(--muted); border-color: var(--line); height: 16px; }
.fl-btn .fl-you { position: absolute; left: -4px; top: 50%; width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%; background: var(--you); box-shadow: 0 0 6px var(--you); }
@media (max-width: 900px) {
  .floor-lift { position: static; width: auto; margin: 6px 8px 0; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 3px; }
  .floor-lift::before { display: none; }
  .fl-btn { grid-template-columns: 1fr; justify-items: center; padding: 3px 2px; gap: 0; }
  .fl-btn .fl-name, .fl-btn small { display: none; }
  .fl-btn.on { grid-column: span 3; grid-template-columns: auto 1fr; justify-items: start; gap: 6px; padding-right: 6px; }
  .fl-btn.on .fl-name { display: block; font-size: 11px; }
  .fl-btn.dark .fl-n { height: 20px; }
  .fl-btn .fl-you { left: 50%; top: -3px; margin: 0 0 0 -3.5px; }
  /* The tools row flows above the rail and the floor strip instead of floating over them (it wrapped off the right edge). */
  .map-tools { position: static; flex-wrap: wrap; row-gap: 6px; padding: 8px 8px 0; }
  .map-lcol { margin-top: 14px; }
}
/* An exit (▼) and an up-link (▲): lit through the fog. Its label carries the floor's band in WoW colours. */
.mnode.exit .exit-mark, .mnode.entry .exit-mark { fill: rgba(241, 185, 47, 0.12); stroke: var(--amber); stroke-width: 1.4; stroke-linejoin: round; }
.mnode.exit .exit-glow, .mnode.entry .exit-glow { fill: none; stroke: rgba(241, 185, 47, 0.18); stroke-width: 1; stroke-dasharray: 2 4; }
.mnode.exit.open .exit-mark { fill: var(--amber); }
.mnode.exit.open .exit-glow { stroke: rgba(241, 185, 47, 0.45); animation: exit-spin 14s linear infinite; transform-box: fill-box; transform-origin: center; }
.mnode.exit.been .exit-glow { animation: none; }
.mnode.entry .exit-mark { fill: rgba(241, 185, 47, 0.35); }
@keyframes exit-spin { to { transform: rotate(360deg); } }
.no-motion .mnode.exit .exit-glow { animation: none; }
@media (prefers-reduced-motion: reduce) { .mnode.exit .exit-glow { animation: none; } }
.floor-card h1 { letter-spacing: 1px; }
.floor-card .tagline b { font: 600 15px var(--mono); }
.floor-card .fl-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 4px 10px; padding: 8px 0; border-top: 1px solid var(--line); font: 12px var(--mono); }
.floor-card .fl-k { color: var(--muted); text-transform: uppercase; letter-spacing: 1px; font-size: 10px; }
.floor-card .fl-v { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.floor-card .fl-v b { font-weight: 600; }

/* ---- Threads (threads-view.mjs): the Threads list in Mail, a thread read, the reward card, the floor map's marks. ---- */
.mrow .th-f { display: inline-grid; place-items: center; width: 17px; height: 19px; clip-path: polygon(50% 0, 100% 24%, 100% 76%, 50% 100%, 0 76%, 0 24%); background: var(--amber); color: #1a1002; font: 700 11px var(--mono); }
.mrow.th-row.done .th-f { background: var(--gray); }
.mrow.th-row.done { opacity: 0.55; }
.mrow.th-row.done:hover, .mrow.th-row.done.open { opacity: 0.85; }
.tag.th-tag { color: var(--amber); border-color: var(--amber); }
.th-lore { margin: 4px 0 10px; color: var(--bright); font-style: italic; }
/* the reward: pick one of three */
.gain.th-offer { z-index: 41; }
.th-later { opacity: 0.8; }
.th-later small { color: var(--dim); font-size: 11px; margin-left: 6px; }
/* the floor map: a temporary server (an amber ?, gray once dark), its dashed link, a file in transit, a server's mark */
.mnode.temp .tframe { fill: rgba(241, 185, 47, 0.06); stroke: var(--amber); stroke-width: 1.4; stroke-dasharray: 3 2.5; }
.mnode.temp .tq { fill: var(--amber); font: 700 13px var(--mono); }
.mnode.temp.here .tframe { stroke: var(--you); }
.mnode.temp.dark .tframe { fill: rgba(125, 115, 98, 0.08); stroke: var(--gray); stroke-dasharray: none; }
.mnode.temp.dark .tq { fill: var(--gray); }
.mnode.temp .mlabel.th { fill: var(--amber); }
.mnode.temp.dark .mlabel { fill: var(--gray); }
.mlink.tlink { stroke: rgba(241, 185, 47, 0.45); stroke-dasharray: 3 4; }
.mnode.transit { pointer-events: none; }
.mnode.transit .troute { fill: none; stroke: var(--amber); stroke-width: 1.4; stroke-dasharray: 5 6; opacity: 0.65; }
.mnode.transit .tbg { fill: #1a1103; stroke: var(--amber); stroke-width: 1.2; }
.mnode.transit .tfile { fill: none; stroke: var(--amber); stroke-width: 1.2; stroke-linejoin: round; }
@media (prefers-reduced-motion: no-preference) { .mnode.transit .tmover { animation: th-transit 1.6s ease-in-out infinite; } }
@keyframes th-transit { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
.mquest path { fill: var(--amber); stroke: #2a1b04; stroke-width: 1; }
.mquest text { font: 700 9px var(--mono); fill: #1a1002; }
.mquest.m-goal path { fill: #1a1103; stroke: var(--amber); }
.mquest.m-goal text { fill: var(--amber); }
.th-temp .th-line-svc b { color: var(--amber); }
.th-temp.dark h1 { color: var(--gray); }

/* Clock Speed: a ring that fills each cycle (--ck, 0-100) and glows the cycle it pays out (view.mjs clockMeter). */
@property --ck { syntax: '<number>'; inherits: true; initial-value: 0; }
.clock-meter { display: inline-flex; align-items: center; gap: 7px; margin-top: 6px; font: 600 10px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); transition: --ck 0.25s ease; }
.clock-meter .ck-ring { display: block; width: 18px; height: 18px; flex: none; }
.clock-meter .ck-ring i { display: block; width: 100%; height: 100%; border-radius: 50%; background: conic-gradient(var(--you) calc(var(--ck) * 1%), var(--line) 0); -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3.5px)); mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3.5px)); }
.clock-meter.paid .ck-ring { filter: drop-shadow(0 0 4px var(--you)); animation: ck-paid 0.6s ease-out; }
.clock-meter.paid .ck-k { color: var(--you); }
@keyframes ck-paid { 0% { transform: scale(1.25); } 100% { transform: none; } }
@media (prefers-reduced-motion: reduce) { .clock-meter { transition: none; } .clock-meter.paid .ck-ring { animation: none; } }

/* ---------- the power-up (poweron.mjs): the monitor comes on, the mark rises, any key starts ---------- */
.poweron { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; background: #020101; overflow: hidden; cursor: default; }
.poweron::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.28) 0 1px, transparent 1px 3px), radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, 0.75)); }
/* The tube warming up: a line of light across the middle that opens into the screen, then fades. */
.po-flash { position: absolute; left: 0; right: 0; top: 50%; height: 2px; margin-top: -1px; background: #fff6d8; box-shadow: 0 0 24px 6px rgba(255, 216, 110, 0.75); transform: scaleX(0); animation: po-tube 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) forwards; }
@keyframes po-tube { 0% { transform: scaleX(0); opacity: 1; height: 2px; margin-top: -1px; } 35% { transform: scaleX(1); opacity: 1; height: 2px; margin-top: -1px; } 60% { transform: scaleX(1); height: 100vh; margin-top: -50vh; opacity: 0.35; } 100% { transform: scaleX(1); height: 100vh; margin-top: -50vh; opacity: 0; } }
.po-stage { position: relative; z-index: 1; display: grid; justify-items: center; gap: 18px; text-align: center; padding: 16px; }
.po-logo { --lg: clamp(72px, 14vmin, 128px); margin-bottom: 28px; }
.po-logo::before { opacity: 0; transform: scale(0.35); animation: po-rise 1.6s 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) forwards, bb-corona 7s 2.3s ease-in-out infinite; }
.po-logo::after { opacity: 0; animation: po-in 0.5s 0.55s ease-out forwards; }
@keyframes po-rise { to { opacity: 0.9; transform: scale(1); } }
@keyframes po-in { to { opacity: 1; } }
.po-word { margin: 0; font: 600 clamp(28px, 6vmin, 52px) var(--mono); letter-spacing: 0.9em; margin-right: -0.9em; color: var(--bright); text-shadow: 0 0 18px rgba(241, 185, 47, 0.45); opacity: 0; animation: po-word 1s 1.4s ease-out forwards; }
@keyframes po-word { from { opacity: 0; letter-spacing: 1.4em; margin-right: -1.4em; filter: blur(4px); } to { opacity: 1; letter-spacing: 0.9em; margin-right: -0.9em; filter: none; } }
.po-sub { margin: 0; font: 12px var(--mono); letter-spacing: 3px; text-transform: uppercase; color: var(--dim); opacity: 0; animation: po-in 0.6s 1.9s ease-out forwards; }
.po-press { margin: 36px 0 0; font: 600 13px var(--mono); letter-spacing: 4px; text-transform: uppercase; color: var(--amber); opacity: 0; }
.poweron.ready .po-press { animation: po-blink 1.4s steps(1) infinite; }
@keyframes po-blink { 0%, 60% { opacity: 1; } 61%, 100% { opacity: 0.15; } }
/* A key while it's still coming on: everything lands at once. */
.poweron.skip .po-flash { display: none; }
.poweron.skip .po-logo::before { animation: bb-corona 7s ease-in-out infinite; opacity: 0.9; transform: none; }
.poweron.skip .po-logo::after, .poweron.skip .po-word, .poweron.skip .po-sub { animation: none; opacity: 1; filter: none; }
/* Starting: the corona flares and the screen goes. */
.poweron.out { animation: po-out 0.5s ease-in forwards; }
.poweron.out .po-logo::before { animation: po-flare 0.5s ease-out forwards; }
@keyframes po-flare { to { opacity: 1; transform: scale(2.6); } }
@keyframes po-out { 60% { opacity: 1; } to { opacity: 0; } }
.poweron.still .po-flash { display: none; }
.poweron.still .po-logo::before, .poweron.still .po-logo::after, .poweron.still .po-word, .poweron.still .po-sub { animation: none; opacity: 1; transform: none; filter: none; }
.poweron.still.ready .po-press { animation: none; opacity: 1; }
.poweron.still.out { animation: none; }
/* The unknown-server card: the way tracing it now, with pips for what's left, then the other ways (view.mjs traceWays). */
.tw-main { display: grid; grid-template-columns: 16px 1fr auto; gap: 8px; align-items: center; margin: 10px 0 6px; padding: 8px 10px; border: 1px solid var(--line-strong); border-left: 2px solid var(--you); border-radius: 3px; background: var(--inset); }
.tw-main .glyph { width: 14px; height: 14px; color: var(--you); }
.tw-what { display: grid; gap: 5px; min-width: 0; }
.tw-what b { font: 600 12.5px var(--mono); color: var(--bright); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tw-pips { display: flex; align-items: center; gap: 3px; }
.tw-pips i { width: 9px; height: 9px; border: 1px solid var(--you); border-radius: 1px; opacity: 0.85; }
.tw-pips small { font: 600 10px var(--mono); color: var(--you); }
.tw-main em { font: 700 13px var(--mono); font-style: normal; color: var(--r-tuned); }
.tw-main.dim { border-left-color: var(--line-strong); opacity: 0.55; }
/* Faction gear (faction-gear.mjs): an implicit's mark on a glyph and its line in a tooltip, a piece's parts as pips. */
.pglyph .pg-fm { position: absolute; top: 2px; right: 2px; display: block; width: max(9px, 2.6em); height: max(9px, 2.6em); color: var(--fc); filter: drop-shadow(0 0 2px color-mix(in srgb, var(--fc) 60%, transparent)); }
.pglyph .pg-fm .glyph { display: block; width: 100%; height: 100%; margin: 0; stroke-width: 1.6; }
.impl { display: flex; align-items: center; gap: 6px; margin-top: 4px; color: var(--fc); font-size: 12px; cursor: help; }
.impl .glyph { width: 13px; height: 13px; margin: 0; flex: none; }
.impl span { color: color-mix(in srgb, var(--fc) 70%, var(--text)); }
.impl b { color: var(--fc); font-weight: 600; }
p.impl { margin: 6px 0 0; padding: 4px 2px; border-bottom: 1px dotted color-mix(in srgb, var(--fc) 30%, transparent); font-size: 13px; }
.part-pips { display: inline-flex; align-items: center; gap: 3px; vertical-align: middle; cursor: help; }
.part-pips i { flex: none; width: 8px; height: 8px; border: 1px solid var(--fc); transform: rotate(45deg); opacity: 0.55; }
.part-pips i.on { background: var(--fc); opacity: 1; box-shadow: 0 0 5px color-mix(in srgb, var(--fc) 70%, transparent); }
.part-pips i.next { opacity: 1; background: color-mix(in srgb, var(--fc) 30%, transparent); animation: part-next 1.6s ease-in-out infinite; }
.part-pips.sm { gap: 3px; margin-left: 2px; } .part-pips.sm i { width: 6px; height: 6px; }
.part-pips.lg { gap: 6px; margin: 4px 0; } .part-pips.lg i { width: 11px; height: 11px; }
.hub-row .hm .part-pips i { width: 7px; height: 7px; }
.hub-row .hm .part-pips.ready i.on { animation: part-next 1.6s ease-in-out infinite; }
@keyframes part-next { 50% { box-shadow: 0 0 7px var(--fc); } }
@media (prefers-reduced-motion: reduce) { .part-pips i.next, .hub-row .hm .part-pips.ready i.on { animation: none; } }
.fd-part { gap: 4px; } .fd-part > .glyph { color: var(--r-zeroday); }
.fd-drop > .glyph { color: var(--fc); }
.piece-tile { max-width: 520px; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 14px; align-items: center; padding: 10px; border: 1px solid color-mix(in srgb, var(--fc) 35%, var(--line)); border-radius: 4px; background: color-mix(in srgb, var(--fc) 5%, transparent); }
.piece-tile.ready { border-color: var(--fc); }
.piece-tile .pglyph { grid-row: span 2; --pg-size: 9px; }
.piece-tile:not(.on) .pglyph { opacity: 0.7; }
.piece-body { display: grid; gap: 2px; min-width: 0; }
.piece-body .iname { font-size: 15px; } .piece-tile:not(.on) .piece-body .iname { color: var(--muted); }
.piece-body > small { color: var(--muted); font: 11px var(--mono); }
.piece-stats { display: grid; gap: 1px; font-size: 12px; color: var(--text); }
.piece-tile > .btn { grid-column: 2; justify-self: start; }
.coll-pieces .coll-piece .iname { display: inline-flex; align-items: center; gap: 2px; color: var(--muted); }
.coll-pieces .coll-piece.on .iname { color: var(--r-zeroday); }
.coll-pieces .coll-piece .part-pips { justify-self: end; }
.coll-sets-h.coll-pieces-h { color: var(--r-zeroday); }
.coll .coll-piece:not(.on) .iname { color: var(--dim); font-weight: 500; } .coll .coll-piece:not(.on) .fmark-i { opacity: 0.6; }
/* Halcyon's Claims: a payout pending, a striped pip past your Signal. Kestrel's Appraisal: the part's next hit on its row. */
.bigbar .claim { position: absolute; top: 0; bottom: 0; background: repeating-linear-gradient(90deg, color-mix(in srgb, #6fb6ff 70%, transparent) 0 3px, transparent 3px 5px); box-shadow: inset 0 0 0 1px #6fb6ff; cursor: help; }
.tag.appraised { color: #8fd46b; border-color: #8fd46b; display: inline-flex; align-items: center; gap: 3px; }
.tag.appraised .glyph { width: 11px; height: 11px; margin: 0; }

/* ---------- #net, the public channel (channel.mjs) ---------- */
/* Its latest line over the prompt: one line, never more, quiet in colour. Click it for the drawer. */
.net-line { display: flex; align-items: baseline; gap: 8px; width: 100%; min-width: 0; height: 18px; margin: 0 0 -4px; padding: 0 2px; background: none; border: 0; font: 12px/18px var(--mono); color: var(--dim); text-align: left; cursor: pointer; overflow: hidden; }
.net-line[hidden] { display: none; }
.net-line[aria-expanded='true'] { visibility: hidden; } /* the drawer is open over it */
.net-line:hover .nl-line, .net-line[aria-expanded='true'] .nl-line { color: var(--muted); }
.net-line .nl-tag { flex: none; font: 600 10px/18px var(--mono); letter-spacing: 1px; color: var(--amber-soft); }
.net-line .nl-line { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--dim); }
.net-line .nl-line time { display: none; }
.net-line .ch-from, .net-line .ch-title, .net-line .ch-text { opacity: 0.85; }
.channel { position: absolute; left: 20px; bottom: calc(100% - 14px); z-index: 55; width: min(640px, calc(100% - 40px)); height: min(46vh, 420px); display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--r-card); box-shadow: 0 14px 34px rgba(0, 0, 0, 0.65); }
.channel[hidden] { display: none; }
.ch-head { gap: 10px; }
.ch-head .ch-name { color: var(--amber); letter-spacing: 1px; text-transform: none; font: 600 12px var(--mono); }
.ch-head small { flex: 1; font: 11px var(--mono); letter-spacing: 0; text-transform: none; color: var(--dim); }
.ch-head .act { font: 600 11px var(--mono); color: var(--amber); background: none; border: 0; padding: 0; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; letter-spacing: 0; text-transform: none; }
.ch-head .act.dim { color: var(--dim); }
.ch-lines { flex: 1; min-height: 0; overflow: auto; list-style: none; margin: 0; padding: 6px 12px 8px; font: 12.5px/1.5 var(--mono); }
.ch-line { padding: 1px 0; color: var(--text); overflow-wrap: anywhere; }
.ch-line.quiet { color: var(--dim); padding: 8px 0; }
.ch-line time { margin-right: 8px; font-size: 11px; color: var(--dim); }
.ch-from { font: 600 inherit; }
.ch-from.hacker { padding: 0; background: none; border: 0; font: 600 12.5px/1.5 var(--mono); color: var(--you); cursor: pointer; }
.ch-from.hacker:hover { text-decoration: underline; text-underline-offset: 2px; }
.ch-from.hacker.friend { color: var(--daemon); }
.ch-from.hacker.me { color: var(--bright); }
.ch-from.contact { color: var(--fc); }
.ch-from.contact .glyph { width: 11px; height: 11px; margin: 0 4px 0 0; vertical-align: -1px; }
.ch-from.wire { color: var(--amber-soft); font-weight: 600; letter-spacing: 0.5px; }
.ch-title { margin-left: 5px; font-style: normal; font-size: 11px; color: var(--amber-soft); }
.ch-title::before { content: '‹'; opacity: 0.6; } .ch-title::after { content: '›'; opacity: 0.6; }
.ch-text::before { content: ': '; color: var(--dim); }
.k-wire .ch-text { color: var(--muted); }
.k-feat .ch-text::before { content: ' '; }
.k-feat .ch-text, .ch-star { color: var(--next); }
.ch-star { margin-right: 4px; }
.k-you .ch-text { color: var(--bright); }
.ch-item { font-weight: 600; color: var(--r-zeroday); }
.ch-say { display: flex; align-items: center; gap: 8px; padding: 7px 12px; border-top: 1px solid var(--line); }
.ch-say label { font: 600 10px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--dim); }
.ch-say input { flex: 1; min-width: 0; height: var(--h-btn-sm); padding: 0 8px; background: var(--inset); color: var(--bright); border: 1px solid var(--line); border-radius: var(--r-btn); font: 13px var(--mono); }
.ch-say input:focus { outline: none; border-color: var(--amber); }
.people-list .p-handle { cursor: pointer; }
.people-list .p-handle:hover { text-decoration: underline; text-underline-offset: 2px; }
.whoami { cursor: pointer; }
.whoami:hover #who-handle { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- the profile card (profile.mjs): finger, a Unix login with gamertag art ---------- */
.profile-scrim { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; padding: 16px; overflow: auto; background: rgba(4, 3, 1, 0.72); }
.profile-scrim[hidden] { display: none; }
.pf-wrap { display: flex; align-items: flex-start; gap: 12px; max-width: 100%; }
.pf-card, .pf-edit { background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--r-card); box-shadow: 0 18px 44px rgba(0, 0, 0, 0.7); }
/* The card is a net ID badge: an amber strip; a centred identity (the banner framed as the photo, teal corners for the
   person; the handle large in teal, the title, the plan quoted); then sections on one column, each with the same
   small label over it and the same rule above it; a bar code beside the date at the foot. One spacing scale: 4 and 8
   inside a block, 12 between blocks, 16 at the sides. */
.pf-card { width: 372px; max-width: 100%; padding: 0; font: 12px var(--mono); color: var(--text); display: grid; overflow: hidden; background: linear-gradient(155deg, rgba(241, 185, 47, 0.06), transparent 34%), var(--panel); }
.pf-head { display: flex; align-items: center; justify-content: space-between; height: 28px; padding: 0 8px 0 16px; background: var(--amber); color: #120c03; }
.pf-kicker { font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; }
.pf-x { font: 600 18px/1 var(--mono); color: rgba(18, 12, 3, 0.65); background: none; border: 0; cursor: pointer; padding: 0 2px; }
.pf-x:hover { color: #120c03; }
.pf-face { display: grid; justify-items: center; gap: 4px; padding: 16px; text-align: center; min-width: 0; }
.pf-photo { --tk: rgba(127, 209, 199, 0.7); max-width: 100%; padding: 6px; background:
  linear-gradient(var(--tk), var(--tk)) top left / 10px 1px, linear-gradient(var(--tk), var(--tk)) top left / 1px 10px,
  linear-gradient(var(--tk), var(--tk)) top right / 10px 1px, linear-gradient(var(--tk), var(--tk)) top right / 1px 10px,
  linear-gradient(var(--tk), var(--tk)) bottom left / 10px 1px, linear-gradient(var(--tk), var(--tk)) bottom left / 1px 10px,
  linear-gradient(var(--tk), var(--tk)) bottom right / 10px 1px, linear-gradient(var(--tk), var(--tk)) bottom right / 1px 10px; background-repeat: no-repeat; }
.pf-banner { display: block; width: max-content; max-width: 100%; margin: 0; padding: 10px 14px; font: 600 14px/1.15 var(--mono); color: var(--amber); text-shadow: 0 0 0.5em rgba(241, 185, 47, 0.35); background: var(--inset); border: 1px solid var(--line); border-radius: var(--r-card); white-space: pre; overflow: hidden; }
.pf-handle { margin-top: 8px; font: 600 24px/1.1 var(--mono); color: var(--you); letter-spacing: 0.06em; text-shadow: 0 0 0.6em rgba(127, 209, 199, 0.3); overflow-wrap: anywhere; }
.pf-title { color: var(--amber); font: 600 12px var(--mono); }
.pf-plan { max-width: 100%; margin: 4px 0 0; font: italic 12px/1.5 var(--mono); color: var(--muted); overflow-wrap: anywhere; text-wrap: balance; }
.pf-plan.quiet { color: var(--dim); }
.pf-sec { display: grid; gap: 8px; min-width: 0; padding: 12px 16px; border-top: 1px solid var(--line); }
.pf-sec-h { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 16px; }
.pf-sec h3, .pf-group h3 { margin: 0; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); }
.pf-classes { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; }
.pf-class { margin: 0; display: grid; justify-items: center; align-content: start; gap: 8px; padding: 8px 4px 6px; background: var(--inset); border: 1px solid var(--line); border-radius: var(--r-btn); }
.pf-class pre { margin: 0; font: 600 5.4px/1.05 var(--mono); color: var(--you); text-shadow: 0 0 0.6em rgba(127, 209, 199, 0.35); }
.pf-class figcaption { font: 600 10px var(--mono); letter-spacing: 0.5px; text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.pf-class figcaption b { color: var(--bright); }
.pf-groups { display: flex; flex-wrap: wrap; align-items: start; gap: 12px 24px; }
.pf-group { display: grid; align-content: start; gap: 8px; }
.pf-pieces { display: flex; gap: 8px; }
.pf-piece .pglyph { --pg-size: 3.6px; padding: 0.3em; }
.pf-marks { display: flex; gap: 12px; }
.pf-stance { display: inline-flex; align-items: center; gap: 5px; font: 600 11px var(--mono); letter-spacing: 0.5px; color: var(--fc); }
.pf-stance .glyph { width: 12px; height: 12px; margin: 0; }
.pf-mark { display: grid; justify-items: center; gap: 4px; color: var(--fc); }
.pf-mark .glyph { width: 16px; height: 16px; margin: 0; }
.pf-pips { display: flex; gap: 2px; }
.pf-pips i { width: 4px; height: 4px; border: 1px solid currentColor; opacity: 0.45; }
.pf-pips i.on { background: currentColor; opacity: 1; }
.pf-stickers, .pf-sec .pf-achs { display: flex; flex-wrap: wrap; gap: 8px; }
.pf-sticker { display: inline-flex; align-items: center; gap: 4px; padding: 2px 7px 2px 5px; color: var(--sc); background: color-mix(in srgb, var(--sc) 12%, var(--inset)); border: 1px solid color-mix(in srgb, var(--sc) 70%, transparent); border-radius: var(--r-btn); font: 600 10px var(--mono); letter-spacing: 0.6px; text-transform: uppercase; transform: rotate(-1.5deg); }
.pf-sticker:nth-child(3n + 2) { transform: rotate(1.2deg); } .pf-sticker:nth-child(3n) { transform: rotate(-0.4deg); }
.pf-sticker .glyph { width: 11px; height: 11px; margin: 0; }
.pf-stickers .pf-sticker, .pf-sec .pf-ach-chip { height: 22px; box-sizing: border-box; padding: 0 8px 0 6px; line-height: 1; transform: none; }
.pf-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 16px; border-top: 1px solid var(--line); font: 11px/14px var(--mono); color: var(--dim); }
.pf-since { min-width: 0; }
.pf-bars { flex: none; height: 14px; color: var(--muted); opacity: 0.6; }
.pf-foot .act, .pf-foot .tag { margin-left: auto; flex: none; white-space: nowrap; }
.pf-foot .act { font: 600 11px/14px var(--mono); color: var(--amber); background: none; border: 0; padding: 0; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.pf-edit { width: 336px; max-width: 100%; display: grid; gap: 10px; padding: 0 0 12px; }
.pf-edit .comms-filters { padding: 8px 12px; }
.pf-presets { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; padding: 0 12px; }
.pf-preset { display: grid; place-items: center; padding: 6px 2px; background: var(--inset); border: 1px solid var(--line); border-radius: var(--r-btn); cursor: pointer; }
.pf-preset pre { margin: 0; font: 600 5.6px/1.1 var(--mono); color: var(--muted); }
.pf-preset:hover pre { color: var(--text); }
.pf-preset[aria-pressed='true'] { border-color: var(--amber); }
.pf-preset[aria-pressed='true'] pre { color: var(--amber); }
.pf-draw { display: grid; gap: 6px; padding: 0 12px; }
.pf-draw label { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--muted); }
.pf-draw label small { color: var(--dim); margin-left: 4px; }
.pf-draw-box { width: calc(24ch + 18px); max-width: 100%; height: calc(4 * 1.2em + 14px); justify-self: center; padding: 6px 8px; resize: none; overflow: auto; background: var(--inset); color: var(--amber); border: 1px dashed var(--line-strong); border-radius: var(--r-btn); font: 600 14px/1.2 var(--mono); white-space: pre; background-image: linear-gradient(90deg, transparent calc(24ch + 8px), rgba(255, 91, 61, 0.25) calc(24ch + 8px), rgba(255, 91, 61, 0.25) calc(24ch + 9px), transparent calc(24ch + 9px)); }
.pf-draw-box:focus { outline: none; border-color: var(--amber); }
.pf-draw-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pf-err { font: 12px var(--mono); color: var(--hot); }
.pf-titles { list-style: none; margin: 0; padding: 0 12px; display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.pf-tl { display: flex; align-items: center; gap: 5px; width: 100%; min-height: var(--h-btn-sm); padding: 3px 8px; background: var(--inset); color: var(--text); border: 1px solid var(--line); border-radius: var(--r-btn); font: 600 11.5px var(--mono); text-align: left; cursor: pointer; }
.pf-tl[aria-pressed='true'] { border-color: var(--amber); color: var(--amber); }
.pf-tl.none { color: var(--muted); font-weight: 500; }
.pf-tl.locked { color: var(--dim); border-style: dashed; font-weight: 500; cursor: help; }
.pf-tl.locked .glyph { width: 11px; height: 11px; margin: 0; flex: none; }
.pf-planform { display: flex; gap: 8px; padding: 0 12px; }
.pf-planform input { flex: 1; min-width: 0; height: var(--h-btn-sm); padding: 0 8px; background: var(--inset); color: var(--bright); border: 1px solid var(--line); border-radius: var(--r-btn); font: 13px var(--mono); }
.pf-planform input:focus { outline: none; border-color: var(--amber); }
@media (max-width: 760px) {
  .pf-wrap { flex-direction: column; align-items: stretch; width: 100%; }
  .pf-card, .pf-edit { width: 100%; }
  .profile-scrim { place-items: start center; padding: 10px; }
  .channel { left: 10px; width: calc(100% - 20px); height: min(52vh, 420px); }
  .ch-lines { font-size: 12px; }
  .ch-from.hacker { font-size: 12px; }
}

/* The parts plan (docs/parts-plan.md P1), in the board's own vocabulary: an Accumulator's charge bar, a volley's
   bracket, a Backlog's SYN, a Zip Bomb's fuse, a Buffer's shield (the lock's steel segment), a Hotspot's glow, the
   Idle Timer's pips on the signature's row. */
.tag.accum { display: inline-flex; align-items: center; gap: 3px; }
.tag.accum .glyph { width: 10px; height: 10px; margin: 0; }
.acc-bar { position: relative; display: inline-block; width: 34px; height: 5px; border: 1px solid var(--hot); background: transparent; }
.acc-bar b { position: absolute; left: 0; top: 0; bottom: 0; background: var(--hot); }
.intent.tap { position: relative; }
.intent.tap::after { content: ''; position: absolute; bottom: -5px; height: 4px; left: -10px; right: -10px; border-bottom: 1px solid currentColor; opacity: 0.75; pointer-events: none; }
.intent.tap.first::after { left: 50%; border-left: 1px solid currentColor; }
.intent.tap.last::after { right: 50%; border-right: 1px solid currentColor; }
.intent .tapmark, .intent .synmark { font: 700 9px/1 var(--mono); font-style: normal; letter-spacing: 0.5px; opacity: 0.85; margin-left: 3px; }
.intent .synmark { color: #6fb6ff; border: 1px solid #6fb6ff; padding: 0 2px; }
.intent.fuse { border-color: var(--hot); color: var(--hot); background: repeating-linear-gradient(135deg, var(--hot-soft) 0 5px, transparent 5px 10px); animation: fuse-spark 0.9s ease-in-out infinite alternate; }
@keyframes fuse-spark { from { box-shadow: 0 0 2px var(--hot); } to { box-shadow: 0 0 9px var(--hot); } }
.no-motion .intent.fuse, body[data-fx="minimal"] .intent.fuse { animation: none; }
@media (prefers-reduced-motion: reduce) { .intent.fuse { animation: none; } }
/* The order levers (view.mjs, docs/puzzle-levers.md 3.2 to 3.4). A Tripwire your move breaks: the other parts' attacks at
   their loud numbers, a cycle sooner, edged as a preview. A Zip Bomb's blast on each bar: a hatched ghost past this
   cycle's slice. A Lockbox's held damage: your teal, its number on the Lockbox's row and the ghost on its partner's bar. */
.intent.loud { border-style: dashed; border-color: var(--hot); }
.intent.loud small { color: var(--hot); font-weight: 700; }
.part-bar .blastghost, .part-bar .heldghost { position: absolute; top: 0; bottom: 0; display: block; cursor: help; pointer-events: auto; }
.part-bar .blastghost { background: repeating-linear-gradient(90deg, rgba(255, 248, 230, 0.75) 0 2px, rgba(255, 248, 230, 0.18) 2px 4px); }
.part-bar .heldghost { background: repeating-linear-gradient(90deg, var(--you) 0 2px, rgba(127, 209, 199, 0.3) 2px 4px); }
.part-bar .blastghost.breaks, .part-bar .heldghost.breaks { box-shadow: 0 0 6px currentColor; }
.part-bar .heldghost.breaks { color: var(--you); }
.part-bar .blastghost.breaks { color: rgba(255, 248, 230, 0.8); }
.tag.held .glyph { width: 11px; height: 11px; margin-right: 3px; vertical-align: -1px; }
.intent.bufup { border-style: dashed; border-color: var(--steel); color: var(--steel); background: transparent; }
.tag.hotspot { display: inline-flex; align-items: center; gap: 3px; color: var(--amber); border-color: var(--amber); box-shadow: 0 0 6px var(--amber-wash); }
.tag.hotspot .glyph { width: 10px; height: 10px; margin: 0; }
.brow.bpart:has(.tag.hotspot) { box-shadow: inset 3px 0 0 var(--amber-soft); }
.tag.idlepips { display: inline-flex; align-items: center; gap: 2px; letter-spacing: 1px; font-size: 9px; }
.tag.idlepips .glyph { width: 10px; height: 10px; margin: 0 2px 0 0; }
.tag.idlepips i { opacity: 0.4; font-style: normal; }
.tether.k-front .tt-line { border-style: dashed; }
/* Your helpers (docs/puzzle-fights.md 3.2, view.mjs boardMarkup): a teal pip for each hit a helper has left, in the
   column it lands, one row of pips a helper at the foot of its part's cells, so the rows line up across the columns. A
   pip that trips a lever (a hit on the Mimic's beat, a Tripwire broken while others stand) is edged red. The move-on
   tether is a teal dashed line, from a part breaking this cycle to where its helpers go next. */
.bcell .hpips { display: flex; flex-direction: column; gap: 2px; margin-top: auto; padding-top: 2px; }
.hpip { display: block; width: 8px; height: 8px; border-radius: 1px; background: var(--you); cursor: help; }
.hpip.trip { box-shadow: 0 0 0 2px var(--hot), 0 0 6px var(--hot); }
.hpip.none { visibility: hidden; }
.tether.k-moveon { --tt: var(--you); color: var(--you); transform: translateY(5px); } /* a little under the steel ones, so their arms never overlap */
.tether.k-moveon .tt-line { background: repeating-linear-gradient(180deg, var(--tt) 0 4px, transparent 4px 7px); }
.tether.k-moveon .tt-arm { background: repeating-linear-gradient(90deg, var(--tt) 0 4px, transparent 4px 7px); }
.tether.k-moveon.up .tt-line, .tether.k-moveon.up .tt-arm, .tether.k-moveon.up .tt-node { animation: none; box-shadow: none; }

/* The beats (docs/puzzle-levers.md 3.1, 3.8; view.mjs). The Mimic's beat chip says what your selected command would
   copy, red when the copy is dear; this cycle, a red ghost past the forecast slice on your Signal bar, or a red count on
   the ◆ and shield it would strip. The Decoy's Bend chip says where its next beat points, and the pointer is a dashed red
   tether from the Decoy to that part (a stub when it points at itself), drawn like the helpers' move-on tether. */
.intent.tell .tl-what.copy { color: var(--text); }
.intent.tell .tl-what.copy.dear { color: var(--hot); }
.bigbar .copy-ghost { position: absolute; top: 0; bottom: 0; display: block; background: repeating-linear-gradient(135deg, rgba(255, 91, 61, 0.7) 0 4px, rgba(255, 91, 61, 0.35) 4px 8px); box-shadow: 0 0 5px rgba(255, 91, 61, 0.6); pointer-events: auto; }
.st.ghosted { border-color: rgba(255, 91, 61, 0.55); }
.st .st-ghost { margin-left: 5px; color: var(--hot); font: 700 10px var(--mono); }
.intent.bend { border: 1px dashed var(--hot); color: var(--hot); background: transparent; }
.intent.bend b.bend-to { display: inline-block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--text); }
.intent.bend.harm b.bend-to { color: var(--hot); }
.intent.bend.veiled b.bend-to { color: var(--muted); }
.intent.bend.now { background: var(--hot-soft); }
/* A boss's act break (actbreak.mjs): its card over the board's strip, the emote under its bar, the bits off its ♛'s tick. */
.phase-strip.act-on { position: relative; }
.phase-strip.act-on > :not(.act-card) { visibility: hidden; }
.act-card { position: absolute; inset: 0; display: flex; align-items: center; gap: 14px; padding: 0 14px; overflow: hidden; white-space: nowrap; color: var(--hot); border-top: 1px solid var(--hot); pointer-events: none; }
.act-card .ac-n, .act-card .ac-name { font: 800 15px var(--mono); letter-spacing: 0.22em; }
.act-card .ac-of { opacity: 0.75; letter-spacing: 0.12em; }
.act-card .ac-name { color: var(--text); }
.hud-bar.enemy.act-emoting .gene-line { display: none; }
.act-emote { margin: 8px 0 0; padding: 5px 10px; width: max-content; max-width: 100%; border: 1px solid color-mix(in srgb, var(--hot) 55%, transparent); border-radius: 2px; background: color-mix(in srgb, var(--hot) 8%, transparent); font: 13px var(--mono); color: var(--text); }
.act-emote b { margin-right: 8px; color: var(--hot); letter-spacing: 0.12em; }
.act-bit { position: fixed; z-index: 60; pointer-events: none; font: 700 13px var(--mono); color: var(--hot); text-shadow: 0 0 6px var(--hot); }
.ptick.act-flare { box-shadow: 0 0 12px 3px var(--hot); }
/* NIGHT DESK's attacks open trades (view.mjs tradeChip): dashed, like every chip that lands only if you let it. */
.intent.trade { border: 1px dashed var(--hot); background: transparent; }
.intent.trade .tr-ico { width: 14px; height: 14px; flex: none; color: var(--hot); }
.intent.trade.full { border-style: solid; background: var(--hot-soft); }
.intent.trade.full small { color: var(--hot); }
.tether.k-bend { --tt: var(--hot); color: var(--hot); transform: translateY(-5px); } /* a little over the steel ones, so their arms never overlap */
.tether.k-bend .tt-line { background: repeating-linear-gradient(180deg, var(--tt) 0 4px, transparent 4px 7px); }
.tether.k-bend .tt-arm { background: repeating-linear-gradient(90deg, var(--tt) 0 4px, transparent 4px 7px); }
.tether.k-bend.up .tt-line, .tether.k-bend.up .tt-arm, .tether.k-bend.up .tt-node { animation: none; box-shadow: none; }
.tether.k-bend .tt-count { color: var(--hot); }

/* The parts plan's P2 (docs/parts-plan.md): what protects a part in steel (a Limiter's cap line, a Damper's crossed
   kind, a Cold Store's frost and its thaw bar, a sleeping Spare's ◆), what threatens you in red (a Scraper's takes-buffs
   mark, a Bad Block's cracked cells on your bar, a thaw or a boot coming), a Spare asleep dim, a Packer's ??? grey. */
.tag.limcap, .tag.damper, .tag.frost { display: inline-flex; align-items: center; gap: 3px; color: var(--steel); border-color: var(--steel); }
.tag.limcap .glyph, .tag.damper .glyph, .tag.frost .glyph, .tag.standby .glyph, .tag.packed .glyph { width: 10px; height: 10px; margin: 0; }
.tag.damper s { text-decoration-thickness: 1.5px; }
.tag.damper.off { opacity: 0.5; }
.part-bar .capline { position: absolute; top: -2px; bottom: -2px; width: 0; border-left: 2px solid var(--steel); box-shadow: 0 0 4px var(--steel-glow); pointer-events: auto; }
.thaw-bar { position: relative; display: inline-block; width: 30px; height: 5px; border: 1px solid var(--steel); }
.thaw-bar b { position: absolute; left: 0; top: 0; bottom: 0; background: var(--steel); }
.brow.bpart.frozen { background-image: repeating-linear-gradient(45deg, rgba(134, 182, 198, 0.08) 0 6px, transparent 6px 12px); box-shadow: inset 3px 0 0 var(--steel); }
.brow.bpart.frozen .part-bar > span:first-child { background: var(--steel); opacity: 0.6; }
.brow.bpart.standby { opacity: 0.55; }
.brow.bpart.standby:hover, .brow.bpart.standby.selected { opacity: 0.85; }
.tag.standby, .tag.packed { display: inline-flex; align-items: center; gap: 3px; color: var(--gray); border-color: var(--gray); border-style: dashed; }
.gchip.packed { border-style: dashed; color: var(--gray); }
.intent .scrapemark, .intent .badmark { display: inline-flex; margin-left: 3px; font-style: normal; color: var(--hot); }
.intent .scrapemark .glyph { width: 10px; height: 10px; margin: 0; }
.intent.scrape, .intent.bad { border-color: var(--hot); }
.intent.thaw, .intent.boot { border-style: dashed; border-color: var(--hot); color: var(--hot); background: transparent; }
.bigbar .cracked-cells { position: absolute; top: 0; bottom: 0; background: repeating-linear-gradient(135deg, var(--hot-soft) 0 3px, rgba(255, 91, 61, 0.45) 3px 4px, transparent 4px 7px); border-left: 1px solid var(--hot); pointer-events: auto; }

/* ---- The test bench (bench.mjs, ?bench=<name>): its tag in the top bar, and the dev panel in a drawer. ---- */
.bench-tag { flex: none; padding: 2px 7px; border: 1px dashed var(--you); border-radius: var(--r-tag); color: var(--you); font: 600 11px/1.4 var(--mono); letter-spacing: 1.5px; white-space: nowrap; cursor: help; }
.bench-panel { position: fixed; z-index: 50; left: var(--s5); bottom: 84px; max-width: min(560px, calc(100vw - 2 * var(--s5))); display: flex; flex-direction: column; align-items: flex-start; gap: var(--s3); font: 12px/1.3 var(--mono); }
.bp-toggle, .bp-btn { display: inline-flex; align-items: center; gap: var(--s2); min-height: 26px; padding: 0 var(--s4); border: 1px solid var(--line-strong); border-radius: var(--r-btn); background: var(--panel-2); color: var(--text); font: inherit; cursor: pointer; }
.bp-toggle { border-style: dashed; border-color: var(--you); color: var(--you); letter-spacing: 1.5px; text-transform: uppercase; }
.bp-toggle[aria-expanded='true'] { background: var(--inset); }
.bp-btn:hover, .bp-toggle:hover { border-color: var(--amber); color: var(--bright); }
.bp-btn[aria-pressed='false'] { color: var(--gray); border-style: dashed; }
.bp-ico { color: var(--amber); font-size: 13px; }
.bp-body { display: grid; gap: var(--s3); padding: var(--s4); border: 1px dashed var(--you); border-radius: var(--r-card); background: rgba(9, 6, 3, 0.94); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.6); }
.bp-body[hidden] { display: none; }
.bp-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); }
.bp-label { width: 56px; flex: none; color: var(--dim); font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; font-size: 10px; }
.bp-row select, .bp-num { min-height: 26px; padding: 0 var(--s3); border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--inset); color: var(--text); font: inherit; }
.bp-num { width: 58px; }
.bp-body { max-height: calc(100vh - 150px); overflow-y: auto; }
/* The Arena: a search over every fightable thing, grouped by kind; a row is its name, kind and the level it opens. */
.bp-row:has(> .bp-stack) { align-items: flex-start; }
.bp-row:has(> .bp-stack) .bp-label { padding-top: 7px; }
.bp-stack { flex: 1 1 0; display: grid; gap: var(--s2); min-width: 0; }
.bp-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); }
.ar-pick { display: grid; gap: var(--s2); min-width: 0; }
.ar-find { min-height: 26px; padding: 0 var(--s3); border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--inset); color: var(--text); font: inherit; }
.ar-list { max-height: 188px; overflow-y: auto; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--inset); }
.ar-head { display: block; padding: var(--s2) var(--s3) 2px; color: var(--dim); font: var(--kicker); font-size: 10px; letter-spacing: var(--kicker-track); text-transform: uppercase; }
.ar-row { display: grid; grid-template-columns: minmax(0, 1fr) auto 5ch; align-items: baseline; gap: var(--s3); width: 100%; padding: 3px var(--s3); border: 1px solid transparent; background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.ar-row b { overflow: hidden; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.ar-kind { color: var(--muted); font-size: 11px; }
.ar-lv { color: var(--dim); font-size: 11px; text-align: right; }
.ar-row:hover { background: var(--amber-wash); }
.ar-row[aria-selected='true'] { border-color: var(--amber); background: var(--amber-wash); }
.ar-row[aria-selected='true'] b { color: var(--bright); }
.ar-group[hidden], .ar-row[hidden] { display: none; }
.ar-none { margin: 0; padding: var(--s3); color: var(--dim); }
@media (max-width: 900px) {
  .topbar .bench-tag { grid-area: 1 / 3; justify-self: start; }
  .bench-panel { left: var(--s6); right: var(--s6); bottom: 96px; max-width: none; }
  .bp-label { width: 100%; }
  .ar-list { max-height: 150px; }
  .bp-row:has(> .bp-stack) .bp-label { padding-top: 0; }
  .bp-stack { flex-basis: 100%; }
}

/* ---- Loadout → Skills and talents (skills-view.mjs, docs/class-page.md): one card of the whole class, subclass A ·
   the class · subclass B. Names, icons and state on the card; every rule in its tooltip. Teal is yours (your keys,
   ranks, picks, level), amber what you use or can spend on, grey what's closed. ---- */
.sk-ico { display: inline-block; flex: none; width: 18px; height: 18px; background: currentColor; -webkit-mask: var(--icon) center/contain no-repeat; mask: var(--icon) center/contain no-repeat; }
.sk-emblem { margin: 0; max-height: none; overflow: visible; font: 500 11px/1.15 var(--mono); color: var(--amber); white-space: pre; letter-spacing: 0; text-shadow: 0 0 12px rgba(241, 185, 47, 0.35); }
.sk-pips { display: flex; gap: 3px; flex: none; }
.sk-pips i { width: 6px; height: 6px; border: 1px solid var(--line-strong); transform: rotate(45deg); }
.sk-pips i.on { background: var(--you); border-color: var(--you); }
.cls { display: grid; gap: var(--s6); }
.cls-top { display: flex; align-items: center; gap: var(--s6); padding-bottom: var(--s5); border-bottom: 1px solid var(--line); }
.cls-lv { display: flex; align-items: center; gap: 10px; font: 600 12px var(--mono); color: var(--you); }
.cls-lv small { color: var(--dim); }
.cls-xp { width: 160px; height: 3px; background: var(--line); } .cls-xp i { display: block; height: 100%; background: var(--you); }
.cls-sp { flex: 1; }
.cls-pts { font: 600 12px var(--mono); color: var(--muted); } .cls-pts b { color: var(--amber); }
.cls-toolkit { display: inline-flex; align-items: center; gap: 8px; }
.cls-toolkit kbd { font: 600 10px var(--mono); color: var(--dim); border: 1px solid var(--line); border-radius: var(--r-tag); padding: 0 4px; }
.cls-ban { display: flex; align-items: center; gap: 12px; margin: 0; font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; color: var(--amber); }
.cls-ban.dim { color: var(--dim); }
.cls-ban::before, .cls-ban::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, var(--line-strong), transparent); }
.cls-card { display: grid; grid-template-columns: minmax(0, 1fr) 250px minmax(0, 1fr); border: 1px solid var(--line); border-radius: var(--r-card); background: var(--panel); }
.cls-card.reg { grid-template-columns: minmax(0, 1fr) 250px 200px; }
.cls-col { display: grid; gap: 18px; align-content: start; padding: 22px 24px 24px; min-width: 0; }
.cls-col + .cls-col, .cls-fold { border-left: 1px solid var(--line); }
.cls-mid { background: var(--inset); justify-items: center; }
.cls-sub.off > :not(.cls-ch) { opacity: 0.15; filter: grayscale(1); }
.cls-sub.off .cls-mk, .cls-sub.off .cls-ch h2, .cls-sub.off .cls-roles { opacity: 0.3; filter: grayscale(1); }
.cls-ch { display: flex; align-items: center; gap: 14px; }
.cls-ch > :last-child { margin-left: auto; }
.cls-mk { display: grid; place-items: center; flex: none; width: 48px; height: 48px; border: 1px solid var(--amber); border-radius: var(--r-card); color: var(--amber); }
.cls-mk .sk-ico { width: 26px; height: 26px; }
.cls-ch h2, .cls-fold h2 { margin: 0; font: 600 24px var(--sans); color: var(--bright); }
.cls-roles { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 6px; }
.cls-role { padding: 2px 7px; border: 1px solid var(--line-strong); border-radius: var(--r-tag); font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--muted); }
.cls-yours { display: flex; align-items: center; gap: 6px; font: 600 11px var(--mono); letter-spacing: 1px; text-transform: uppercase; color: var(--you); }
.cls-yours::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--you); }
.cls-lv10 { padding: 3px 8px; border: 1px solid var(--line); border-radius: var(--r-tag); font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--muted); }
.cls-root { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--inset); cursor: help; }
.cls-root > svg, .cls-root > .glyph { color: var(--amber); flex: none; }
.cls-root small { display: block; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); }
.cls-root b { font: 500 14px var(--sans); color: var(--text); }
.cls-root.cls-edge b { color: var(--amber); }
.cls-root.locked { border-style: dashed; opacity: 0.5; }
.cls-abil { display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 14px 8px; }
.cls-card.reg .cls-sub .cls-abil { grid-template-columns: repeat(11, minmax(0, 1fr)); }
.cls-abil.core { grid-template-columns: repeat(2, 72px); justify-content: center; gap: 14px 24px; }
.cls-ab { position: relative; display: grid; justify-items: center; gap: 4px; padding: 0; border: 0; background: none; color: var(--amber); font: inherit; cursor: help; }
button.cls-ab { cursor: pointer; }
.cls-fr { position: relative; display: grid; place-items: center; width: 100%; max-width: 64px; aspect-ratio: 1; border: 1px solid var(--line-strong); border-radius: var(--r-btn); background: var(--inset); }
.cls-fr .sk-ico { width: 24px; height: 24px; }
.cls-ab b { font: 500 11px/1.2 var(--sans); color: var(--text); text-align: center; overflow-wrap: anywhere; }
.cls-ab.lock .cls-fr, .cls-ab.peek .cls-fr { border-color: var(--line); }
.cls-ab.lock .cls-fr { border-style: dashed; color: var(--dim); }
.cls-ab.lock b, .cls-ab.peek b { color: var(--muted); }
.cls-at { position: absolute; top: 3px; left: 5px; font: 600 9px var(--mono); color: var(--dim); }
.cls-k { position: absolute; top: -5px; right: max(-5px, calc(50% - 37px)); min-width: 18px; height: 18px; display: grid; place-items: center; padding: 0 4px; border: 1px solid var(--you); border-radius: var(--r-tag); background: var(--inset); font: 600 11px var(--mono); color: var(--you); }
button.cls-ab:hover .cls-fr, button.cls-ab:focus-visible .cls-fr { border-color: var(--amber); }
.cls-roots { display: grid; gap: 8px; width: 100%; }
.cls-id { display: grid; justify-items: center; gap: 8px; text-align: center; }
.cls-id h2 { margin: 0; font: 600 28px var(--sans); color: var(--bright); letter-spacing: 0.5px; }
.cls-id .cls-roles { justify-content: center; margin: 0; }
.cls-tree { display: grid; gap: 8px; }
.cls-row { display: grid; grid-template-columns: minmax(0, 1fr) 22px minmax(0, 1fr); align-items: center; }
.cls-row.t3 { position: relative; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.cls-row.t3 .cls-tn { height: auto; min-height: 36px; padding: 4px 10px; }
.cls-row.t3 .cls-tn b { white-space: normal; line-height: 1.15; }
.cls-tl { position: absolute; right: 100%; margin-right: 6px; font: 600 9px var(--mono); color: var(--dim); }
.cls-or { text-align: center; font: 600 9px var(--mono); color: var(--dim); text-transform: uppercase; }
.cls-tn { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; height: 36px; padding: 0 12px; border: 1px solid var(--line); border-radius: var(--r-btn); background: none; color: var(--muted); font: 500 13px var(--sans); text-align: left; cursor: help; }
.cls-tn b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cls-tn.can { cursor: pointer; color: var(--text); border-color: var(--line-strong); }
.cls-tn.can:hover, .cls-tn.can:focus-visible { border-color: var(--amber); }
.cls-tn.has { border-color: var(--line-strong); color: var(--text); }
.cls-tn.pick { border-color: var(--amber); background: var(--amber-wash); color: var(--bright); }
.cls-tn.locked { border-style: dashed; color: var(--dim); }
.cls-row.cap .cls-tn { height: 40px; }
.cls-fold { display: grid; gap: 14px; align-content: start; justify-items: center; padding: 22px 18px; text-align: center; }
.cls-fold > :not(.btn) { opacity: 0.4; filter: grayscale(1); }
.cls-fold h2 { font-size: 20px; }
.cls-fold .cls-roles { justify-content: center; margin: 0; }
.cls-fedge { margin: 0; font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); cursor: help; }
.cls-icons { display: grid; grid-template-columns: repeat(4, 30px); gap: 6px; color: var(--amber); }
.cls-icons span { display: grid; place-items: center; height: 30px; border: 1px solid var(--line); border-radius: var(--r-btn); }
.cls-icons .sk-ico { width: 16px; height: 16px; }
@media (max-width: 1100px) {
  .cls-card, .cls-card.reg { grid-template-columns: minmax(0, 1fr); }
  .cls-col + .cls-col, .cls-fold { border-left: 0; border-top: 1px solid var(--line); }
  .cls-mid { order: -1; }
  .cls-card.reg .cls-sub .cls-abil { grid-template-columns: repeat(auto-fill, minmax(56px, 1fr)); }
}
@media (max-width: 900px) {
  .arch-tabs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .arch { justify-content: space-between; }
  .arch-use { grid-column: 1 / -1; margin-left: 0; }
  .cls-top { flex-wrap: wrap; gap: var(--s5); }
  .cls-xp { width: 100px; }
  .cls-col { padding: 16px 14px; }
  .cls-ch h2 { font-size: 20px; }
}

/* ---- The Toolkit (skills-view.mjs toolkitMarkup; key T): the class's abilities on the left page, the subclass's on
   the right, the bar along its foot. Drag an ability onto a key, or tap it and then a key. ---- */
.toolkit[hidden] { display: none; }
.tk-scrim { position: fixed; inset: 0; z-index: 80; background: rgba(5, 3, 1, 0.78); }
.tk { position: fixed; z-index: 81; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(1180px, calc(100vw - 32px)); max-height: calc(100vh - 32px); display: grid; grid-template-rows: auto minmax(0, 1fr) auto; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--panel); box-shadow: 0 30px 80px rgba(0, 0, 0, 0.7); }
.tk-h { display: flex; align-items: center; gap: 14px; padding: 14px 22px; border-bottom: 1px solid var(--line); color: var(--amber); }
.tk-h h2 { margin: 0; font: 600 18px var(--sans); color: var(--bright); }
.tk-cls { font: 600 12px var(--mono); color: var(--muted); }
.tk-x { margin-left: auto; width: 30px; height: 30px; border: 1px solid var(--line); border-radius: var(--r-btn); background: none; color: var(--muted); font: 18px var(--sans); cursor: pointer; }
.tk-spread { display: grid; grid-template-columns: 1fr 1fr; overflow-y: auto; }
.tk-pg { display: grid; gap: 14px; align-content: start; padding: 20px 24px 24px; }
.tk-pg + .tk-pg { border-left: 1px solid var(--line); background: linear-gradient(90deg, rgba(0, 0, 0, 0.25), transparent 40px); }
.tk-kick { margin: 0; font: var(--kicker); letter-spacing: var(--kicker-track); text-transform: uppercase; color: var(--dim); }
.tk-none { margin: 0; color: var(--dim); }
.tk-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 18px; }
.tk-i { display: flex; align-items: center; gap: 6px; border-radius: var(--r-btn); }
.tk-b { flex: 1; min-width: 0; display: grid; grid-template-columns: 52px minmax(0, 1fr); gap: 2px 12px; align-items: center; padding: 6px; border: 1px solid transparent; border-radius: var(--r-btn); background: none; color: inherit; font: inherit; text-align: left; cursor: help; }
button.tk-b { cursor: grab; }
button.tk-b:hover, button.tk-b:focus-visible { border-color: var(--line); }
.tk-i.picked .tk-b { border-color: var(--amber); background: var(--amber-wash); }
.tk-fr { position: relative; grid-row: span 2; display: grid; place-items: center; width: 52px; aspect-ratio: 1; border: 1px solid var(--line-strong); border-radius: var(--r-btn); background: var(--inset); color: var(--amber); }
.tk-fr .sk-ico { width: 26px; height: 26px; }
.tk-fr .cls-k { right: -5px; }
.tk-b b { align-self: end; font: 500 15px var(--sans); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tk-b small { align-self: start; font: 500 11px var(--mono); color: var(--dim); }
.tk-i.lock .tk-fr { border-style: dashed; border-color: var(--line); color: var(--dim); }
.tk-i.lock b { color: var(--dim); }
.tk-mt { display: flex; gap: 3px; }
.tk-tier { width: 20px; height: 20px; padding: 0; border: 1px solid var(--line); border-radius: var(--r-tag); background: none; color: var(--muted); font: 600 10px var(--mono); cursor: pointer; }
.tk-tier.on { border-color: var(--you); color: var(--you); cursor: default; }
.tk-tier.locked { border-style: dashed; color: var(--dim); cursor: default; }
.tk-dock { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 18px; padding: 14px 22px; border-top: 1px solid var(--line); background: var(--inset); border-radius: 0 0 6px 6px; }
.tk-slots { display: grid; grid-template-columns: repeat(11, minmax(0, 1fr)); gap: 6px; margin: 0; padding: 0; list-style: none; }
.tk-slot { position: relative; display: grid; place-items: center; height: 54px; border: 1px solid var(--line-strong); border-radius: var(--r-btn); background: var(--panel); color: var(--amber); }
.tk-slot[data-tk-key] { cursor: pointer; }
.tk-slot[draggable="true"] { cursor: grab; }
.tk-slot kbd { position: absolute; top: 3px; left: 5px; font: 600 10px var(--mono); color: var(--dim); }
.tk-slot .sk-ico { width: 24px; height: 24px; }
.tk-slot small { font: 600 10px var(--mono); color: var(--dim); }
.tk-slot.empty { border-style: dashed; }
.tk-slot.closed { border-style: dashed; border-color: var(--line); }
.tk-slot.cant { background: var(--inset); }
.tk-slots.armed .tk-slot[data-tk-key] { border-color: var(--amber-soft); }
.tk-slot.picked, .tk-slot.hover { border-color: var(--amber); box-shadow: 0 0 0 1px var(--amber), 0 0 18px rgba(241, 185, 47, 0.35); }
.tk-presets { display: flex; gap: 6px; }
.tk-chip { padding: 4px 10px; border: 1px solid var(--line); border-radius: var(--r-btn); background: none; color: var(--muted); font: 500 12px var(--sans); cursor: pointer; }
.tk-chip.on { border-color: var(--amber); color: var(--bright); background: var(--amber-wash); cursor: default; }
.tk-chip:disabled:not(.on) { opacity: 0.5; cursor: default; }
.tk-busy { font: var(--label); letter-spacing: var(--label-track); text-transform: uppercase; color: var(--dim); }
@media (max-width: 900px) {
  .tk { top: auto; bottom: 0; transform: translateX(-50%); width: 100vw; max-height: 92vh; border-radius: 6px 6px 0 0; }
  .tk-spread { grid-template-columns: minmax(0, 1fr); }
  .tk-pg + .tk-pg { border-left: 0; border-top: 1px solid var(--line); }
  .tk-list { grid-template-columns: minmax(0, 1fr); }
  .tk-dock { grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 12px; }
  .tk-slots { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .tk-dock > .tk-kick { display: none; }
}
/* An attacking part striking out of the render's window (virus-art.mjs): drawn over the page for half a second, no input. */
#art-out { position: fixed; inset: 0; width: 100vw; height: 100vh; z-index: 45; pointer-events: none; }
.no-motion #art-out { display: none; }

/* The takeover card's receipt (receipts.mjs; the Stamps look): an inset mono block, five square stamps, Later. */
.rc-block { display: grid; gap: 2px; margin: 10px 0 12px; padding: 10px 12px; font: 400 12px/1.45 var(--mono); color: var(--text); background: var(--inset); border: 1px solid var(--line); border-radius: var(--r-tag); }
.rc-block .rc-id { color: var(--muted); letter-spacing: 1px; }
.rc-block .rc-sum { color: var(--amber); font-weight: 600; }
.rc-block .rc-wait { color: var(--dim); }
.rc-stamps { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 5px; }
.gain-card:has(.rc-stamps) { width: min(380px, calc(100vw - 32px)); }
.rc-stamp { display: grid; justify-items: center; align-content: center; gap: 5px; min-width: 0; aspect-ratio: 1; padding: 6px 2px; color: var(--fc); background: color-mix(in srgb, var(--fc) 7%, transparent); border: 1px solid color-mix(in srgb, var(--fc) 45%, transparent); border-radius: var(--r-btn); cursor: pointer; font: 600 9px/1.15 var(--mono); letter-spacing: 0.3px; text-transform: uppercase; text-align: center; }
.rc-stamp:hover, .rc-stamp:focus-visible { background: color-mix(in srgb, var(--fc) 16%, transparent); border-color: var(--fc); outline: none; }
.rc-stamp .glyph { width: 18px; height: 18px; margin: 0; }
.rc-pips { display: flex; gap: 3px; }
.rc-pips i { width: 5px; height: 5px; border: 1px solid currentColor; opacity: 0.5; }
.rc-pips i.on { background: currentColor; opacity: 1; }
.gain-card .rc-later { opacity: 1; animation: none; }
.rc-mono { font: 400 11px/1.4 var(--mono); color: var(--text); }
.comm-line { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; color: var(--fc); }
.comm-line .comm-pay { color: var(--amber); font: 600 12px var(--mono); }
.comm-line .btn, .comm-line .tag { margin-left: auto; }
