/* WFSim — build configurator. Theme-aware; dataviz categorical palette.
   =====================================================================
   COMPONENT CONTRACT — build UI out of these; don't invent one-offs:
     .topbar + .brand      sticky header, WF<span>Sim</span> wordmark (gold Sim)
     .footer               shell bottom bar, same content width as .topbar
   CENTERING RULE: pills/chips/tags center via inline-flex + line-height:1
   and an explicit height — never via line-box leading. Fixed-height
   controls match line-height to their inner height.
     .block  > .bh > .bb   section box: header (uppercase h2, .n number) + body
     .wcard                weapon card (image + name), home grid
     .slot                 mod/arcane slot card (rarity via --rar)
     .combo-menu .opt      rich searchable row (img + pol + name + effects)
     .pchip                chip with select state (.sel) — presets etc.
     .ghost-btn (.small)   secondary button; .run-btn primary action
     .popover + .addbar    floating panel with search
     .buff-card            per-buff stacks + lock row
     .kpi / .stat-table    result numbers
   The public site (site/*.html) copies the :root tokens below verbatim. */
:root{
  color-scheme: light;
  --plane:#f5f5f2; --surface:#ffffff; --panel2:#f0efea; --panel3:#f7f7f4;
  --text:#0b0b0b; --text-2:#52514e; --muted:#898781; --line:rgba(11,11,11,0.12);
  --accent:#2a78d6; --good:#0ca30c; --good-text:#006300; --gold:#a9781f; --critical:#d03b3b;
  --s1:#2a78d6;--s2:#eb6834;--s3:#1baf7a;--s4:#eda100;--s5:#e87ba4;--s6:#008300;--s7:#4a3aa7;--s8:#e34948;
}
@media (prefers-color-scheme: dark){:root:where(:not([data-theme="light"])){
  color-scheme: dark;
  --plane:#0e1014; --surface:#171a21; --panel2:#1e222b; --panel3:#12151b;
  --text:#f2f4f8; --text-2:#a6adbb; --muted:#6b7280; --line:rgba(255,255,255,0.09);
  --accent:#4a9eff; --good:#3ddc84; --good-text:#3ddc84; --gold:#e8c37a; --critical:#e05656;
  --s1:#3987e5;--s2:#d95926;--s3:#199e70;--s4:#c98500;--s5:#d55181;--s6:#008300;--s7:#9085e9;--s8:#e66767;
}}
:root[data-theme="dark"]{
  color-scheme: dark;
  --plane:#0e1014; --surface:#171a21; --panel2:#1e222b; --panel3:#12151b;
  --text:#f2f4f8; --text-2:#a6adbb; --muted:#6b7280; --line:rgba(255,255,255,0.09);
  --accent:#4a9eff; --good:#3ddc84; --good-text:#3ddc84; --gold:#e8c37a; --critical:#e05656;
  --s1:#3987e5;--s2:#d95926;--s3:#199e70;--s4:#c98500;--s5:#d55181;--s6:#008300;--s7:#9085e9;--s8:#e66767;
}
*{box-sizing:border-box}
/* `hidden` MUST ACTUALLY HIDE.
   The browser's own `[hidden]{display:none}` lives in the UA stylesheet, and
   ANY author rule beats it regardless of specificity — so every element here
   with a `display:` of its own ignored the attribute completely. The damage
   meter's rows are `display:grid`, so a collapsed source stayed on screen with
   only its caret flipped: the control looked like it worked and never did
. 31 places in app.js set `.hidden`; nothing in this
   sheet made any of them mean anything.
   `!important` is the HTML spec's own recommendation for exactly this, and is
   what keeps the fix from being one `display:` rule behind forever. */
[hidden]{display:none !important}

/* SCROLLBARS, NAMED ONE BY ONE. The browser's own bar is a pale rod on a dark
   panel, and this page scrolls in several places. `.scroll-thin` is the opt-in
   and the list beside it is every container that already scrolls, so nothing
   is restyled that has not been looked at — a `*` rule reaches menus, tables
   and windows nobody checked. The track is invisible; only the thumb shows,
   and it answers the pointer so a reader can tell it is grabbable. */
.scroll-thin,.rec-scroll,.wsearch-panel .combo-menu{scrollbar-width:thin;
  scrollbar-color:color-mix(in srgb,var(--text) 17%,transparent) transparent}
.scroll-thin::-webkit-scrollbar,.rec-scroll::-webkit-scrollbar,
.wsearch-panel .combo-menu::-webkit-scrollbar{width:11px;height:11px}
.scroll-thin::-webkit-scrollbar-track,.rec-scroll::-webkit-scrollbar-track,
.wsearch-panel .combo-menu::-webkit-scrollbar-track{background:transparent}
/* The 3px transparent border plus `content-box` is what gives the thumb its
   own padding, so it never sits flush against the content it scrolls. */
.scroll-thin::-webkit-scrollbar-thumb,.rec-scroll::-webkit-scrollbar-thumb,
.wsearch-panel .combo-menu::-webkit-scrollbar-thumb{border-radius:999px;
  background:color-mix(in srgb,var(--text) 17%,transparent);
  border:3px solid transparent;background-clip:content-box}
.scroll-thin:hover::-webkit-scrollbar-thumb,.rec-scroll:hover::-webkit-scrollbar-thumb,
.wsearch-panel .combo-menu:hover::-webkit-scrollbar-thumb{
  background:color-mix(in srgb,var(--text) 30%,transparent);background-clip:content-box}
.scroll-thin::-webkit-scrollbar-thumb:active,.rec-scroll::-webkit-scrollbar-thumb:active,
.wsearch-panel .combo-menu::-webkit-scrollbar-thumb:active{
  background:var(--accent);background-clip:content-box}
.scroll-thin::-webkit-scrollbar-corner,.rec-scroll::-webkit-scrollbar-corner,
.wsearch-panel .combo-menu::-webkit-scrollbar-corner{background:transparent}
html,body{margin:0}
body{background:var(--plane);color:var(--text);font-family:system-ui,"Segoe UI",sans-serif;font-size:14px;line-height:1.45}

.topbar{border-bottom:1px solid var(--line);background:var(--surface);position:sticky;top:0;z-index:20}
/* The shell shares ONE content width (the widest page, home's 1060px) so
   header content aligns with the page below it. */
.topbar-inner{max-width:1060px;margin:0 auto;display:flex;align-items:center;gap:14px;padding:12px 18px}
.wsearch{position:relative;flex:1 1 auto;max-width:430px}
.wsearch input{width:100%;padding:6px 11px;font:inherit;font-size:13px;background:var(--plane);border:1px solid var(--line);border-radius:8px;color:var(--text)}
.wsearch input:focus{outline:none;border-color:var(--accent)}
.wsearch-panel{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:50;background:var(--surface);border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 28px rgba(0,0,0,.35);overflow:hidden}
.wsearch-panel .picker-tools select{margin-left:auto}
.wsearch-panel .combo-menu{max-height:320px;overflow-y:auto}
.wsearch-panel .opt{cursor:pointer}
.wsearch-panel .opt:hover{background:var(--panel2)}
.brand{font-weight:800;font-size:20px;letter-spacing:-.01em}.brand span{color:var(--gold)}
/* Module tabs under the weapon strip: Builder | Optimizer. The sim is
   NOT a tab — it sits at the bottom of the builder as the build's test
   bench. body.on-simulator / body.on-optimizer swap which module's
   sections show (Builder | Simulator | Optimizer). */
/* FIVE TABS, AND THEY MAY NOT PUSH THE DOCUMENT. `display:flex` with no wrap
   let them overflow in normal flow, so the DOCUMENT grew to their width and
   the browser fitted that into the screen: at 360px the English strip measured
   474px, every page shrank to 76%, and the right quarter — which is where a
   mod card keeps its ⋯ — went off the edge. It reads as "the mod area is too
   big", because the mod cards are the widest thing being cut; the exilus slot
   looks fine beside them only because its right-hand side is empty.
   ONLY ENGLISH SHOWED IT. The Chinese labels are short enough to fit at every
   phone width, which is why eight weapons swept clean in zh and every one of
   them overflowed in en. `wrap` is the GUARANTEE — a sixth tab, a longer
   translation or a narrower phone costs a second row rather than the page —
   and the tighter padding below is what usually keeps it to one. */
.module-tabs{display:flex;flex-wrap:wrap;gap:4px;margin:16px 0 14px;border-bottom:1px solid var(--line)}
.mtab{display:inline-flex;align-items:center;line-height:1;padding:9px 16px;font-size:13.5px;color:var(--muted);text-decoration:none;border:1px solid transparent;border-bottom:none;border-radius:8px 8px 0 0}
.mtab:hover{color:var(--text)}
.mtab.sel{color:var(--text);font-weight:600;border-color:var(--line);background:var(--panel2);position:relative;top:1px}
/* Measured at 360px: 16px of side padding puts the five English labels at
   474px, 9px puts them at 366 — one row on all but the narrowest phone, and
   `wrap` above catches the rest. */
@media(max-width:520px){.mtab{padding:8px 9px;font-size:12.5px}.module-tabs{gap:2px}}

/* EVERY BLOCK DECLARES WHOSE IT IS, and the rules below are DERIVED from that
   declaration rather than from a list of ids.

   A block belongs to exactly one module (`data-module` in the HTML), and a
   module's blocks show only on that module's tab. That is one rule per module
   instead of one selector per block — which is what this was, and the Parts
   block was in none of the lists: it drew on the Simulator and the Optimizer
   tabs, a builder control on two pages that do not own a build. The same shape
   as the Mode block's own bug (check_opt_modes), which is why a
   list is the wrong mechanism.

   The BUILDER is the default tab, so its blocks show whenever no other
   module's tab is on. */
body:not(.on-optimizer) [data-module="optimizer"],
body:not(.on-rivens) [data-module="rivens"],
body:not(.on-enemies) [data-module="enemies"],
body:not(.on-wbench) [data-module="benchmark"],
body:not(.on-simulator) [data-module="simulator"]{display:none}
body.on-optimizer [data-module="builder"],
body.on-simulator [data-module="builder"],
body.on-rivens [data-module="builder"],
body.on-enemies [data-module="builder"],
body.on-wbench [data-module="builder"]{display:none}
/* THE SIMULATOR'S BLOCKS, and `#wfbuff-block` is one of them: a Warframe buff
   is not part of the weapon. It is something done TO this
   weapon for a while, which is the fight's business — the builder answers
   "what is this gun", and a Roar belongs to no gun. The optimizer shows its
   own read-only copy inside `#opt-block`, so it needs no entry here. */
/* (the simulator's own rule is in the derived block above) */
/* A SECTION OF THE FIGHT THAT STILL READS AS ITS OWN THING. Wrapped rather than merely headed: it saves with the scenario,
   travels with it across weapons and is what the optimizer reads off the
   fight, so it belongs INSIDE — and it is a layer nobody else in this panel
   is, so it gets an edge. It needs no hiding rule of
.sim-h-sub{margin-left:8px;color:var(--text-2);font-size:11px;font-weight:400}
/* The simulator's read-only build summary */
.sb-h{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin:8px 0 4px}
.sb-chips{display:flex;flex-wrap:wrap;gap:6px}
.sb-chip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:8px;padding:3px 9px 3px 5px;font-size:12px;background:var(--panel3)}
.sb-chip img{width:24px;height:24px;object-fit:contain}
.sb-chip .rk{color:var(--muted);font-size:11px}
.sb-empty{color:var(--muted);font-size:12px}
.sb-edit{display:inline-flex;margin-top:12px;text-decoration:none}
.sb-wielder{margin-top:6px}
/* THE LIST THE FIGHT RUNS, scanned top down — numbered because the order IS
   the meaning. */
.sb-apl{margin:2px 0 0;padding-left:20px;display:flex;flex-direction:column;gap:2px}
.sb-apl li{font-size:12px;color:var(--text-2)}
.sb-apl code{font-size:12px;color:var(--text);background:var(--panel2);border-radius:4px;padding:0 4px}
.wld-nest,.wld-op{border-left:2px solid var(--line);padding-left:10px}
.wld-op{margin-top:8px}
.wld-title{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:4px}
.hero-tested{color:var(--muted);font-size:11px;margin-top:4px}
/* Sim results: the WoW-style damage-by-source meter */
.meter{display:flex;flex-direction:column;gap:4px}
.mrow{display:grid;grid-template-columns:140px 1fr auto;gap:8px;align-items:center;font-size:12px}
.mrow .mname{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* DE's own damage-type glyph, inline with the label. A 64px source drawn at
   14 so it stays crisp on a 2x screen, and vertical-align rather than flex so
   it does not disturb the grid the row already is. */
.dt-ico{width:14px;height:14px;vertical-align:-2px;margin-right:5px;flex:none;opacity:.95}
.mrow .mbar{height:12px;background:var(--panel2);border-radius:6px;overflow:hidden}
.mrow .mbar i{display:block;height:100%;border-radius:6px}
.mrow .mval{color:var(--text-2);font-variant-numeric:tabular-nums;white-space:nowrap}
/* A weapon-damage row expands into the damage types it was dealt as. */
.mrow.exp{cursor:pointer}
.mrow.exp:hover .mname{color:var(--text)}
.mcaret{display:inline-block;width:14px;font-size:10px;color:var(--text-2)}
.mrow.sub .mname{padding-left:12px;color:var(--text-2)}
.mrow.sub .mbar{height:8px}
/* Sim results: damage-over-time curve */
.tl-wrap{position:relative;margin-top:4px}
.tl-wrap svg{width:100%;height:170px;display:block}
.tl-line{fill:none;stroke:var(--accent);stroke-width:2;vector-effect:non-scaling-stroke}
.tl-grid{stroke:var(--line);stroke-width:1;vector-effect:non-scaling-stroke}
.tl-cross{stroke:var(--muted);stroke-width:1;stroke-dasharray:3 3;vector-effect:non-scaling-stroke}
.tl-x{display:flex;justify-content:space-between;color:var(--muted);font-size:10px;margin-top:2px}
.tl-ymax{position:absolute;top:0;left:4px;color:var(--muted);font-size:10px}
.tl-tip{position:absolute;top:8px;background:var(--surface);border:1px solid var(--line);border-radius:6px;padding:2px 8px;font-size:11px;pointer-events:none;white-space:nowrap}
/* THE BUILD FINDER IS THE BUILDER'S ALONE. The build bar follows a build onto
   the simulator; finding one is a builder question, so every other module
   hides it. */
.on-simulator #build-finder,.on-optimizer #build-finder,.on-rivens #build-finder,.on-enemies #build-finder,
.on-wbench #build-finder{display:none}
.on-simulator #forma-block,.on-optimizer #forma-block,.on-rivens #forma-block,.on-enemies #forma-block,
.on-wbench #forma-block{display:none}
/* The builder's furniture that is not a `.block`: its preset bar and the quick
   calc travel with the blocks the other modules hide. */
.on-optimizer #preset-bar-builder-builds,.on-optimizer #quick-calc{display:none}
/* The RIVENS tab is its own bench: the builder's blocks step aside, the same
   way they do for the other two modules. */
.on-rivens #preset-bar-builder-builds,.on-rivens #quick-calc,.on-rivens #mode-block,.on-rivens #mod-block,.on-rivens #arcane-block,.on-rivens #evo-block,.on-rivens #element-block,.on-rivens #stats-block{display:none}
/* The ENEMIES editor is the same shape as the rivens one: its own bench, the
   builder's blocks step aside. */
.on-enemies #preset-bar-builder-builds,.on-enemies #quick-calc,.on-enemies #mode-block,.on-enemies #mod-block,.on-enemies #arcane-block,.on-enemies #evo-block,.on-enemies #element-block,.on-enemies #stats-block{display:none}
/* THE TARGET EDITOR. A grid of plain fields, a vulnerability column and a
   body-part list — nothing here is a picker, because every value is a number
   the player is stating rather than choosing from what exists. */
.en-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;margin:10px 0}
.en-grid label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--muted)}
.en-grid input[type=number],.en-grid input[type=text]{font:inherit;font-size:13px;padding:4px 6px;background:var(--panel2);border:1px solid var(--line);border-radius:6px;color:var(--fg)}
.en-sect{margin:14px 0 6px;font-size:12px;color:var(--muted);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.en-parts{display:flex;flex-direction:column;gap:6px}
.en-part{display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:var(--panel2);border:1px solid var(--line);border-radius:8px;padding:6px 8px}
.en-part input[type=text]{width:120px}
.en-part input[type=number]{width:70px}
.en-part label{display:inline-flex;align-items:center;gap:4px;font-size:11px;color:var(--muted)}
.en-mods{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:6px}
.en-mods label{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--muted)}
.en-mods input[type=number]{width:62px;font:inherit;font-size:12px}
/* THE ARENA, seen from above — two bodies on a floor, dragged with a finger.
   Drawn at the real 0.25 m body radius, so "as close as they go" is something
   you can see rather than a rule you are told. */
/* A RULE, in fixed slots — behaviour, the base it reads, which parts take it.
   Monospaced so two weapons line up column for column when you flick between
   them; the prose beside it (.srownote) is only for what the slots cannot say. */
.srowrule{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;
  color:var(--fg);opacity:.85;margin:2px 0 0 2px;letter-spacing:-.2px}
/* QUICK SETS, inside the canvas. The scene is the one place a position is set,
   so the shortcuts live in it rather than in a second control that would be a
   second source of truth for the same fact. */
.ar-face{stroke:var(--accent);stroke-width:2;stroke-linecap:round;opacity:.75}
.ar-muzzle{fill:var(--accent)}
/* WHERE THE WEAPON POINTS — a ring rather than a body, because it may be
   standing on bare floor. */
.ar-aim{fill:none;stroke:var(--accent);stroke-width:1.6;stroke-dasharray:3 2;cursor:grab}
/* THE BODY THE BEAM IS ON, which is not always the nearest one to the marker. */
.ar-body.ar-struck{stroke:var(--accent);stroke-width:2}
.ar-crowd{margin-top:4px}
.ar-count{font-size:11px;color:var(--dim);align-self:center;margin-left:2px}
.ar-jumps{display:flex;gap:4px;padding:5px 6px;border-top:1px solid var(--line);flex-wrap:wrap}
.ar-jump{font-size:11px;padding:2px 8px;border:1px solid var(--line);border-radius:999px;
  background:var(--panel);color:var(--muted);cursor:pointer;line-height:1.5}
.ar-jump:hover:not(:disabled){color:var(--fg);border-color:var(--muted)}
.ar-jump.on{background:var(--gold);border-color:var(--gold);color:var(--panel);font-weight:600}
.ar-jump:disabled{opacity:.45;cursor:default}
.arena.ar-ro .ar-jump{opacity:.45;cursor:default;pointer-events:none}
.arena{margin:6px 0;border:1px solid var(--line);border-radius:8px;background:var(--panel2);overflow:hidden}
/* A FINGER SCROLLS unless the reader says otherwise (hard rule), so
   the ban on browser gestures belongs to the SVG scene, which has no drag mode
   of its own. The canvas editor sets its own on the CANVAS and leaves its
   chrome — a scrolling brush panel — alone. */
.arena:has(.ar-svg){touch-action:none}
.arena .ar-svg{display:block;width:100%;height:auto}
.ar-grid{stroke:var(--line);stroke-width:1;opacity:.45}
.ar-link{stroke:var(--muted);stroke-width:1.5;stroke-dasharray:4 3;opacity:.8}
/* PAST THE BODY THE SHOT STOPS AT — where you are POINTING, which is not always
   where the round ends. Fainter than the sight line, because it is the half
   nothing travels. */
.ar-past{stroke:var(--dim);stroke-width:1;stroke-dasharray:2 3;opacity:.5}
/* THE SCENE IS CLICKABLE FLOOR: pointing somewhere is a click, moving a body is
   a drag. */
.ar-svg{cursor:crosshair}
.ar-body{cursor:grab;stroke-width:2}
.arena.ar-ro .ar-body{cursor:default}
.ar-body:active{cursor:grabbing}
.ar-you{fill:var(--gold);fill-opacity:.35;stroke:var(--gold)}
.ar-foe{fill:#e2564d;fill-opacity:.3;stroke:#e2564d}
.ar-tag{font-size:10px;fill:var(--muted);text-anchor:middle;pointer-events:none}
.ar-dist{font-size:12px;font-weight:600;fill:var(--fg);text-anchor:middle;pointer-events:none;paint-order:stroke;stroke:var(--panel2);stroke-width:3px}
.ar-scale{font-size:9px;fill:var(--muted);pointer-events:none}
.en-row{display:flex;align-items:center;gap:8px;background:var(--panel2);border:1px solid var(--line);border-radius:8px;padding:8px 10px;margin-bottom:6px;cursor:pointer}
.en-row .nm{font-weight:600}
.en-row .sm{color:var(--muted);font-size:11px}
/* The simulator tab keeps the build preset bar (sim settings are preset
   content — the auto-saving preset bar must stay reachable) but hides
   builder's editing blocks. */
/* `#mode-block` is on this list because the MODE is part of the build, and the
   simulator does not edit builds — it picks one and measures it. It was the one editing control left on this tab, sitting above
   a read-only Build card that already stated the same fact; two places to read
   one field, one of them writable, is how a build gets edited somewhere that
   is not the builder.
   NOT hidden on the optimizer, which still reads `mode` off this control and
   has no scope axis of its own for it yet. */
.on-simulator #quick-calc{display:none}

/* Preset bar above the Mods block: chips CRUD in place. */
.preset-bar{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin:0 0 12px;padding:8px 12px;background:var(--panel2);border:1px solid var(--line);border-radius:10px}
/* The official SCENARIO bar. A gold left edge and a tighter box, so it reads as
   a header over the bar below rather than as a second collection of your own.
   ONE DROPDOWN rather than chips: one entry per ruler, picked from a list. */
.bench-bar{margin-bottom:6px;padding:6px 12px;border-left:2px solid var(--gold)}
/* Sized to its content, not to the bar: it sits beside a label and a copy
   button, and a full-width control there would read as the bar itself. */
.bench-bar .dd{height:26px;min-width:150px;max-width:min(360px,60vw)}
.bench-bar .dd[disabled]{cursor:default;opacity:.72}
.bench-bar .dd[disabled]:hover{border-color:var(--line)}
.bench-bar .dd[disabled] .dd-c{opacity:.35}
/* THE BUILD FINDER — a table of the board's builds. It holds a QUERY and never a
   selection, so it carries no gold edge and no "selected" chip: what is open is
   the build bar's to say. */
.finder{background:var(--surface);border:1px solid var(--line);border-radius:12px;margin:0 0 12px;--req:var(--s7)}
.finder[hidden]{display:none}
.fd-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 12px;border-bottom:1px solid var(--line)}
.fd-title{margin:0;font-weight:700;font-size:13.5px;white-space:nowrap}
.fd-count{color:var(--muted);margin-left:-4px;font-variant-numeric:tabular-nums;white-space:nowrap}
.fd-q{flex:1 1 320px;display:flex;align-items:center;flex-wrap:wrap;gap:5px;min-height:32px;padding:3px 8px;border:1px solid var(--line);border-radius:9px;background:var(--plane);position:relative}
.fd-q:focus-within{border-color:var(--accent)}
.fd-q input{flex:1;min-width:150px;border:0;outline:0;background:transparent;font:inherit;font-size:12.5px;color:var(--text);height:24px}
.fd-tok{display:inline-flex;align-items:center;gap:4px;height:23px;padding:0 3px 0 8px;border-radius:6px;font-size:12px;background:var(--surface);border:1px solid var(--line);white-space:nowrap}
.fd-tok i{font-style:normal;color:var(--req)}
.fd-tok.exc{border-color:color-mix(in srgb,var(--critical) 45%,var(--line))}
.fd-tok.exc i{color:var(--critical)}
.fd-tok.exc b{text-decoration:line-through;font-weight:400}
.fd-tok.req{border-color:color-mix(in srgb,var(--req) 50%,var(--line))}
.fd-tok b{font-weight:500}
.fd-tok button{border:0;background:transparent;color:var(--muted);cursor:pointer;padding:0 4px;font-size:13px;line-height:1}
.fd-tok button:hover{color:var(--critical)}
.fd-sugg{position:absolute;left:0;right:0;top:calc(100% + 4px);background:var(--surface);border:1px solid var(--line);border-radius:10px;box-shadow:0 10px 26px rgba(0,0,0,.2);z-index:40;overflow:hidden}
.fd-sg{display:flex;align-items:center;gap:8px;padding:6px 10px;font-size:12.5px}
.fd-sg.hi,.fd-sg:hover{background:var(--panel3)}
.fd-sg .k{font-size:10.5px;color:var(--muted);min-width:44px}
.fd-sg .nm{flex:1}
.fd-sg .pc{color:var(--muted);font-variant-numeric:tabular-nums;font-size:11.5px}
.fd-sg button{height:22px;border-radius:6px;border:1px solid var(--line);background:transparent;font-size:11.5px;padding:0 7px;cursor:pointer;color:var(--text)}
.fd-sg button.p{border-color:var(--req);color:var(--req)}
.fd-sg button.n{color:var(--critical)}
.fd-cmp{display:inline-flex;flex-direction:row;align-items:center;gap:5px;font-size:12px;color:var(--text-2);white-space:nowrap;cursor:pointer}
.fd-cmp input{width:auto;margin:0}
.fd-views{display:inline-flex;border:1px solid var(--line);border-radius:8px;overflow:hidden}
.fd-views button{border:0;background:transparent;padding:0 10px;height:28px;font:inherit;font-size:12px;cursor:pointer;color:var(--text-2)}
.fd-views button.on{background:var(--panel2);color:var(--text);font-weight:600}
.fd-scope{display:flex;flex-wrap:wrap;gap:8px 18px;padding:9px 12px;border-bottom:1px solid var(--line);background:var(--panel3)}
.fd-seg{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.fd-seg > span{font-size:11px;color:var(--muted)}
.fd-seg button{height:26px;padding:0 9px;border:1px solid var(--line);border-radius:7px;background:var(--surface);font:inherit;font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;color:var(--text)}
.fd-seg button:hover{border-color:var(--accent)}
.fd-seg button.on{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset;font-weight:600}
.fd-seg button em{font-style:normal;color:var(--muted);font-weight:400;font-variant-numeric:tabular-nums;font-size:11px}
.fd-seg button[disabled]{opacity:.45;cursor:default}
.fd-rail{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,1fr) minmax(0,1.2fr);gap:18px;padding:9px 12px 11px;border-bottom:1px solid var(--line)}
@media (max-width:860px){.fd-rail{grid-template-columns:1fr}}
.fd-rail h4{margin:0 0 5px;font-size:11px;color:var(--muted);font-weight:600;display:flex;justify-content:space-between;gap:8px}
.fd-rail h4 small{font-weight:400}
.fd-use{display:grid;gap:2px}
.fd-use.mods{grid-template-columns:repeat(3,minmax(0,1fr));column-gap:6px}
@media (max-width:640px){.fd-use.mods{grid-template-columns:repeat(2,minmax(0,1fr))}}
.fd-u{display:grid;grid-template-columns:1fr 34px;align-items:center;gap:6px;padding:2px 6px;border-radius:6px;font:inherit;font-size:12px;cursor:pointer;position:relative;border:1px solid transparent;background:transparent;text-align:left;color:var(--text)}
.fd-u:hover{background:var(--panel3)}
.fd-u .ub{position:absolute;left:0;top:0;bottom:0;background:color-mix(in srgb,var(--accent) 12%,transparent);border-radius:6px}
.fd-u span{position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fd-u .pc{text-align:right;color:var(--text-2);font-variant-numeric:tabular-nums;font-size:11.5px}
.fd-u.req{border-color:var(--req)}
.fd-u.exc{border-color:var(--critical);opacity:.8}
.fd-u.exc span:first-of-type{text-decoration:line-through}
.fd-hint{font-size:11px;color:var(--muted);margin:4px 0 0}
.fd-main{overflow-x:auto}
.fd-main table{border-collapse:collapse;width:100%;min-width:640px}
.fd-main th{font-size:10.5px;color:var(--muted);font-weight:600;text-align:left;padding:7px 8px;border-bottom:1px solid var(--line);white-space:nowrap}
.fd-main th .sort{cursor:pointer}
.fd-main th .sort:hover{color:var(--text)}
.fd-main td{padding:6px 8px;border-bottom:1px solid var(--line);font-size:12.5px;vertical-align:middle}
.fd-main tr.fr{cursor:pointer}
.fd-main tr.fr:hover td,.fd-main tr.fr.x td{background:var(--panel3)}
.fd-rank{font-weight:700;font-variant-numeric:tabular-nums;color:var(--text-2)}
.fd-sv{display:flex;align-items:baseline;gap:6px;font-variant-numeric:tabular-nums;white-space:nowrap}
.fd-sd{font-size:11px;color:var(--muted);white-space:nowrap;font-variant-numeric:tabular-nums}
.fd-sbar{height:4px;border-radius:2px;background:color-mix(in srgb,var(--accent) 12%,transparent);margin-top:4px;overflow:hidden;min-width:96px}
.fd-sbar i{display:block;height:100%;background:var(--accent);border-radius:2px}
/* A ROW'S BUILD is the simulator's build card (`.sb-*`), laid out as a table
   of its own: each section's heading on the left, its chips on the right. */
.fd-card{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 10px;align-items:center}
.fd-card .sb-h{margin:0;letter-spacing:.04em}
.fd-card .sb-chips{gap:4px}
.fd-card .sb-chip{padding:1px 7px 1px 3px;gap:4px;font-size:11.5px}
.fd-card .sb-chip img{width:20px;height:20px}
.fd-card .sb-chip.rv{padding-left:7px;border-color:color-mix(in srgb,var(--gold) 50%,var(--line));color:var(--gold)}
.fd-card.cmp .sb-chip.same{opacity:.45}
.fd-card.cmp .sb-chip.diff{border-color:var(--good);background:color-mix(in srgb,var(--good) 12%,var(--panel3))}
.fd-card .sb-chip.hit{box-shadow:inset 0 0 0 1.5px var(--req)}
.fd-main th small{font-weight:400}
.fd-open{height:25px;padding:0 10px;border-radius:7px;border:1px solid var(--accent);background:transparent;color:var(--accent);cursor:pointer;font:inherit;font-size:12px;white-space:nowrap}
.fd-open:hover{background:color-mix(in srgb,var(--accent) 10%,transparent)}
.fd-open.in{border-color:var(--line);color:var(--muted)}
.fd-main tr.fdet td{background:var(--panel3);padding:10px 12px 12px}
.fd-det{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,1fr);gap:18px}
@media (max-width:760px){.fd-det{grid-template-columns:1fr}}

.fd-dt{font-size:11px;color:var(--muted);margin:9px 0 4px;font-weight:600}
.fd-dt:first-child{margin-top:0}
.fd-diff{display:flex;flex-wrap:wrap;gap:4px}
.fd-diff span{font-size:12px;padding:1px 6px;border-radius:5px;background:var(--surface);border:1px solid var(--line)}
.fd-diff .plus{color:var(--good-text)}
.fd-diff .minus{color:var(--critical)}
.fd-more{display:flex;justify-content:center;gap:8px;padding:9px}
.fd-more button{height:28px;border-radius:8px;border:1px dashed var(--line);background:transparent;padding:0 14px;cursor:pointer;color:var(--text-2);font:inherit;font-size:12px}
.fd-empty{padding:22px 14px;text-align:center;color:var(--muted);font-size:13px}
.fd-mx{border-collapse:separate;border-spacing:0}
.fd-main .fd-mx{min-width:0;width:auto}
.fd-mx th.c{writing-mode:vertical-rl;transform:rotate(180deg);font-size:11.5px;color:var(--text-2);height:118px;padding:6px 2px;width:26px;font-weight:500;text-align:left}
.fd-mx td{padding:2px;border-bottom:0}
.fd-mx td.cell i{display:block;width:18px;height:14px;margin:auto;border-radius:3px;background:var(--panel2)}
.fd-mx td.cell.on i{background:var(--accent)}
.fd-mx td.cell.on.hit i{background:var(--req)}
.fd-mx td.lab{white-space:nowrap;font-size:12px;padding:2px 10px 2px 0;font-variant-numeric:tabular-nums}
.fd-mx td.lab .fd-sbar{width:90px;min-width:0;display:inline-block;vertical-align:middle;margin:0 0 0 6px}
/* A BOARD BUILD IN THE BUILD BAR: dashed and locked, the same read-only mark
   the scenario bar's official entries carry; × takes it out of the bar. */
.preset-bar .pgroup{font-size:10.5px;color:var(--muted)}
.preset-bar .psep{width:1px;align-self:stretch;background:var(--line);margin:2px 3px}
.pchip.ro .plock{width:11px;height:11px;color:var(--gold);flex:none}
.pchip.ro .pop.unpin:hover{color:var(--critical)}
/* WHAT WENT TO THE BOARD, above the ranking rather than under it: it is a fact
   about the whole run, and a line under twenty rows is a line nobody scrolls
   to. Quiet by default — uploading is the expected outcome, and only a refusal
   or a failure is news. */
.opt-board{font-size:12px;margin:0 0 6px}
.opt-board .ob-sent{color:var(--muted)}
.opt-board .ob-off,.opt-board .ob-run{color:var(--text-2)}
/* THE ELEMENT AND THE RIVEN are marked rather than merely listed: on an
   adversary weapon the element is the difference between two builds that are
   otherwise identical, and it has to survive a glance. */
.bl-valence,.bl-riven{color:var(--gold)}
.bl-mode{color:var(--accent)}
.preset-bar .plabel{font-size:12px;color:var(--text-2)}
.preset-bar .plabel.bench{color:var(--gold)}
.preset-bar .plabel b{color:var(--gold)}
.preset-bar .pfilter{height:26px;width:130px;padding:0 10px;font:inherit;font-size:12px;border:1px solid var(--line);border-radius:8px;background:var(--panel3);color:var(--text)}
.preset-bar .pfilter:focus{outline:none;border-color:var(--accent)}
.pchip{display:inline-flex;align-items:center;line-height:1;gap:5px;border:1px solid var(--line);border-radius:8px;padding:0 10px;height:26px;font-size:12.5px;cursor:pointer;background:var(--panel3)}
.pchip:hover{border-color:var(--accent)}
.pchip.sel{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset;font-weight:600}
.pchip.add{border-style:dashed;color:var(--muted)}
.pnote{font-size:12px;color:var(--muted)}
.pchip .pby{font-size:10px;color:var(--muted);border:1px solid var(--line);border-radius:6px;padding:0 4px}
.pchip .pop{background:transparent;border:0;color:var(--muted);cursor:pointer;font-size:12px;padding:0 2px;line-height:1}
.pchip .pop:hover{color:var(--text)}
.pchip .pop.del:hover{color:#e05252}
.ghost-btn{background:transparent;border:1px solid var(--line);color:var(--text);border-radius:8px;padding:5px 9px;cursor:pointer;font:inherit}
.ghost-btn:hover{background:var(--plane)}.ghost-btn.small{font-size:11px;padding:2px 7px}
/* Topbar controls share ONE height so the row reads as a single system. */
.topbar-inner .ghost-btn{height:28px;padding:0 8px;display:inline-flex;align-items:center;justify-content:center}
.gh-link{color:var(--text);width:28px;padding:0}
.gh-link svg{display:block}
/* The icon links are 28px of ICON. `.topbar-inner .ghost-btn` sets
   `padding:0 8px` for the TEXT buttons and outranks a single class, so
   it was eating 16 of the 28 and squeezing every mark to a third of its
   size — the override has to match that specificity to win. */
.topbar-inner .qq-link,.topbar-inner .dc-link,.topbar-inner .gh-link,.topbar-inner .sup-link{
  width:28px;padding:0;text-decoration:none;
  display:inline-flex;align-items:center;justify-content:center}
/* …EXCEPT the ask, which carries its name and therefore its own width. It is
   the one entry in this row that is not chrome, and until 2026-08-19 it was
   drawn exactly like the theme toggle — a bare heart, which reads as
   "favourite" as often as it reads as "donate". Tinted rather than filled:
   the topbar is still chrome, so this is the row's emphasis and not a CTA. */
.topbar-inner .sup-link{width:auto;gap:6px;padding:0 10px;color:var(--gold);
  border-color:color-mix(in srgb,var(--gold) 42%,transparent)}
.topbar-inner .sup-link:hover{background:color-mix(in srgb,var(--gold) 12%,transparent)}
.topbar-inner .sup-link .tbl{display:inline;font-size:12px;font-weight:600}
.sup-link svg{display:block}
/* MEASURED, not guessed: at 360px the bar wraps to two rows and the weapon
   search — the site's navigation — is down to 29px wide, so the support link
   is cut on phones and the nav with it. The MENU fixes the geometry instead of
   deleting the content: below 700px the bar is three
   items (wordmark, search, ☰) and everything else is one tap away. */
.dc-link svg{display:block}
.qq-link svg{display:block}
.qq-copy-btn{background:none;border:none;color:var(--muted);cursor:pointer;font:inherit;padding:0 3px}
.qq-copy-btn:hover{color:var(--text)}
.lang-select{margin-left:auto;width:auto;height:28px;padding:0 24px 0 8px;font-size:12px;background-color:var(--surface);color:var(--text);border:1px solid var(--line);border-radius:8px}

.config-page{max-width:760px;margin:0 auto;padding:18px}

.wstrip{display:flex;align-items:center;gap:14px;background:linear-gradient(120deg,var(--panel2),var(--surface));border:1px solid var(--line);border-radius:12px;padding:10px 14px;margin-bottom:14px}
.wstrip img{width:84px;height:52px;object-fit:contain}
.wstrip h1{margin:0;font-size:20px}
.tags{display:flex;gap:6px;margin-top:5px;flex-wrap:wrap}
.tag{display:inline-flex;align-items:center;line-height:1;font-size:11px;color:var(--text-2);border:1px solid var(--line);border-radius:999px;padding:0 8px;height:20px;background:var(--plane)}

/* blocks */
.block{border:1px solid var(--line);border-radius:12px;margin-bottom:12px;overflow:hidden;background:var(--surface)}
.bh{display:flex;align-items:center;gap:9px;padding:9px 13px;border-bottom:1px solid var(--line);background:var(--panel3)}
.bh .n{width:19px;height:19px;border-radius:50%;background:var(--accent);color:#04111f;font-weight:800;display:inline-flex;align-items:center;justify-content:center;font-size:11px}
.bh h2{margin:0;font-size:12px;letter-spacing:.05em;text-transform:uppercase}
.bh .sub{margin-left:auto;color:var(--muted);font-size:12px;display:flex;align-items:center;gap:6px}
.bb{padding:12px 13px}

/* capacity / forma header */
.bh .cap{display:inline-flex;align-items:center;line-height:1;height:20px;font-variant-numeric:tabular-nums;color:var(--text-2);border:1px solid var(--line);border-radius:7px;padding:0 8px}
.bh .cap.over{color:#fff;background:var(--critical);border-color:var(--critical)}
.bh .forma{color:var(--gold);font-weight:600}

/* mod rarity — the in-game card frame colours: bronze / silver / gold / white */
.rar-common{--rar:#a9713d}
.rar-uncommon{--rar:#97a2ad}
.rar-rare{--rar:#c9931c}
.rar-legendary{--rar:#8f95ab}
@media (prefers-color-scheme: dark){:root:where(:not([data-theme="light"])) .rar-common{--rar:#c98a4b}
  :root:where(:not([data-theme="light"])) .rar-uncommon{--rar:#b9c2cc}
  :root:where(:not([data-theme="light"])) .rar-rare{--rar:#e8c34c}
  :root:where(:not([data-theme="light"])) .rar-legendary{--rar:#eef0f7}}
:root[data-theme="dark"] .rar-common{--rar:#c98a4b}
:root[data-theme="dark"] .rar-uncommon{--rar:#b9c2cc}
:root[data-theme="dark"] .rar-rare{--rar:#e8c34c}
:root[data-theme="dark"] .rar-legendary{--rar:#eef0f7}

/* mod slots.

   `minmax(0,1fr)` and NOT `1fr`: a bare `1fr` floors the track at its
   MIN-CONTENT, and a slot's min-content is 198px (a 26px polarity button, a
   34px card, a 24px menu button and the gaps). Two of those plus the gap is
   404px inside a 326px column, so on a phone the right-hand slots — 2, 4, 6,
   8 — hung ~55px past the screen and you had to pan sideways to reach their
   ⋯ button. `minmax(0,1fr)` lets the track shrink below
   its content and the ellipsis do its job. */
.slots{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.slots.one{grid-template-columns:minmax(0,1fr)}
/* ...and on a PHONE, one column. The line above stops the overflow but not
   much else: two columns inside 326px leaves each card 159px, of which the
   mod NAME gets 31px — about three characters before the ellipsis, which is
   not a name. One column gives the card the full 326px and the name 198px,
   and costs only vertical scrolling, which is the one thing a phone is good
   at. Measured, not guessed; see scripts/check_mobile.mjs. */
/* …AND THE PHONE RULE TAKES `minmax(0,…)` TOO. It was a bare `1fr`, which
   re-buried the exact mine the paragraph above was written about: `1fr` floors
   its track at MIN-CONTENT, so ONE column is only as narrow as the widest card
   is willing to be. Two columns had been fixed and one column had not, which
   is why the report was "only the main 8 mods run off the screen — the arcanes
   and the evolutions are fine, and so is the exilus": the
   exilus grid is the SAME class with ONE usually-empty card in it, so its
   min-content is a stub and its track never hits the floor. Eight filled cards
   is the only place on the page where that floor can bind. */
@media(max-width:520px){.slots{grid-template-columns:minmax(0,1fr)}}
/* A GRID ITEM'S AUTOMATIC MINIMUM IS ITS MIN-CONTENT, so a track that CAN
   shrink is only half of it — the card itself has to be willing to. `min-width:0`
   is the same line `.slot .info` already carries one level down, and
   `overflow:hidden` is the backstop: whatever a card comes to hold, it is
   clipped at the card's own edge rather than painted past it. Between the
   three, a mod card cannot leave the screen no matter what is in it. */
.slot{position:relative;display:flex;align-items:center;gap:8px;background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:6px 8px;min-height:48px;min-width:0;overflow:hidden}
/* The slot's own number, matching the picker's "slot N" chip. Absolutely
   placed so it costs the row NO width — the grid is two tracks wide on a
   phone and the mod NAME is what has to keep the room (check_mobile). */
.slot .slotno{position:absolute;right:6px;bottom:3px;font-size:9px;line-height:1;color:var(--muted);opacity:.75;pointer-events:none;font-variant-numeric:tabular-nums}
.slot .pol{width:16px;height:16px}
.pol-btn{flex:none;width:26px;height:26px;display:flex;align-items:center;justify-content:center;background:var(--plane);border:1px solid var(--line);border-radius:6px;cursor:pointer;padding:0}
.pol-btn:hover{border-color:var(--accent)}
.pol-btn .nopol{color:var(--muted);font-size:13px}
/* A polarity we ship no icon for — the Vinquibus's Aura slot. A LETTER,
   because an invisible image reads as an unpolarised slot. */
.pol-txt{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:11px;font-weight:700;line-height:1;color:var(--muted);border:1px solid var(--line);border-radius:3px}
.slot .mod{width:34px;height:34px;border-radius:6px;object-fit:cover;border:1px solid var(--rar,var(--line));flex:none}
.slot.filled{border-left:3px solid var(--rar,var(--line))}
/* Cards grew a description block: icon/polarity/dots align with the TOP
   row (the name), not the vertical center. Empty slots stay centered. */
.slot.filled{align-items:flex-start}
.slot.filled .pol-btn,.slot.filled .mod{margin-top:2px}
.slot.filled .dots{margin-top:4px}
.slot .info{min-width:0;flex:1}
/* THE NAME ROW WRAPS, and what follows the name is why. A card's name line
   carries the wiki link, the warframe.market mark and any chips AFTER the
   name — so `nowrap` + ellipsis did not shorten a long name, it DELETED
   everything standing behind one. A riven is where that bites: its name is the
   preset's plus the generated one, and the mark sat 139 px outside a 240 px
   row. The picker's copy of this card has always wrapped; this is the equipped
   slot catching up to it. */
.slot .mn{font-size:12.5px;font-weight:600;overflow-wrap:anywhere}
.slot .dr{font-size:11px;color:var(--muted)}
/* THE THREE ANSWERS A SLOT'S COLOUR GIVES, in the colours the arsenal uses. */
.slot .dr.matched{color:var(--good-text)}
.slot .dr.mismatched{color:var(--critical)}
.slot .dr .mpol{display:inline-flex;vertical-align:-1px;margin-right:4px}
.slot .dr .mpol .pol{width:12px;height:12px}
.slot .dr .mpol .pol-txt{width:12px;height:12px;font-size:9px}
/* THE DRAIN AND THE RANK ARE ONE LINE. They were two — a block `.dr` above an
   inline-flex `.rank` — which is a whole row per card for two short facts, and
   a card is eight rows deep on a phone before the eighth one is reached: the
   grid measured 763-956px, nearly two screens of nothing but slots. Side by side costs one line each and reads better everywhere,
   so it is not a phone-only rule. It WRAPS, because a lowered rank draws a
   filled pill and a long drain string ("15 drain (base 7)") can want the
   width. */
.slot .drow{display:flex;align-items:center;flex-wrap:wrap;gap:4px 10px;margin-top:2px}
.slot .drow .rank{margin-top:0}
.slot .dots{flex:none;background:transparent;border:0;color:var(--muted);cursor:pointer;font-size:16px;line-height:1;padding:2px 4px;border-radius:5px}
.slot .dots:hover{color:var(--text);background:var(--plane)}
.slot.empty{justify-content:flex-start;border-style:dashed;color:var(--muted);cursor:pointer;gap:8px}
.slot.empty:hover{border-color:var(--accent)}
.slot.empty .pol.ghost{width:26px;text-align:center;opacity:.6}
.slot.empty .plus{font-size:13px}
.slot.exl{cursor:default;justify-content:center}.slot.exl:hover{border-color:var(--line)}
.exlabel{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin:10px 0 6px}
.exhint{font-size:11px;line-height:1.45;color:var(--dim);margin-top:6px;max-width:46ch}
.forma-plan{display:flex;flex-direction:column;gap:8px}
.forma-plan .exlabel{margin-top:4px}
.fp-rules{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:flex-end}
.fp-ticks{display:flex;flex-direction:column;gap:6px}
.forma-plan label.fp-tick{flex-direction:row;align-items:center;gap:7px;color:var(--text)}
.forma-plan label.fp-tick input{width:auto;margin:0}
.fp-pick select{width:auto;min-width:11em}
.fp-pick input{width:7em}
.fp-group{display:flex;flex-wrap:wrap;gap:6px 18px}
.fp-dim{color:var(--dim)}
.fp-foot{display:flex;flex-wrap:wrap;gap:8px 14px;align-items:flex-start}
.fp-result:empty{display:none}
.fp-table{border-collapse:collapse;font-size:12px}
.fp-table th,.fp-table td{padding:2px 12px 2px 0;text-align:left}
.fp-bill{font-size:12px}
.fp-reach{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--line);padding-top:10px;margin-top:4px}
.fp-curve tr.fp-pt{cursor:pointer}
.fp-curve tr.fp-pt.on td{background:var(--panel3)}
.fp-lay .pol,.fp-lay .nopol{width:14px;height:14px;vertical-align:middle}
.fp-ok{color:var(--good,#2fb36d);font-size:11px}

/* floating popovers */
.popover{position:absolute;z-index:50;background:var(--surface);border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 28px rgba(0,0,0,.35);width:340px;max-width:92vw;overflow:hidden}
.popover.menu{width:200px}
.popover .mi{display:flex;align-items:center;gap:8px;padding:8px 12px;cursor:pointer;font-size:13px}
.popover .mi:hover{background:var(--panel2)}
.popover .mi.sel{color:var(--accent)}
.popover .mi.danger{color:var(--critical)}
.popover .mi .pol{width:15px;height:15px}
/* The search affordance is DRAWN, not typed. It was an emoji magnifier, and an
   emoji is the one thing on the page the platform renders in its own colour and
   its own shape — the only colour glyph in a monochrome UI, different on every
   OS. This is a stroked silhouette in the same 1.6 / round-cap line style as the
   select caret, tinted through `mask` so it takes a theme colour like text does.
   ONE definition for all five search bars: it is a rule, not five spans. */
:root{--ic-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='6.8' cy='6.8' r='4.6' fill='none' stroke='%23000' stroke-width='1.6'/%3E%3Cpath d='M10.4 10.4L14 14' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E")}
.addbar{display:flex;align-items:center;gap:8px;padding:9px 11px;border-bottom:1px solid var(--line)}
.addbar::before{content:"";width:14px;height:14px;flex:none;background-color:var(--muted);
  -webkit-mask:var(--ic-search) center/contain no-repeat;mask:var(--ic-search) center/contain no-repeat}
/* NO focus accent. Every search bar on the site focuses its input the moment it
   opens, so the "focused" tint would be the only state anyone ever sees — a
   permanently accent-coloured icon, which is the loudness the emoji was
   replaced for. Muted is the whole point. */
.addbar input{background:transparent;border:0;color:var(--text);font:inherit;flex:1;outline:none}
.combo-menu{max-height:320px;overflow-y:auto}

/* picker sort/filter toolbar */
.picker-tools{display:flex;align-items:center;gap:8px;padding:7px 11px;border-bottom:1px solid var(--line);background:var(--panel3);font-size:12px;color:var(--text-2);flex-wrap:wrap}
.picker-tools select{width:auto;padding:3px 22px 3px 8px;font-size:12px;background-position:right 7px center}
.picker-tools .pk-pols{display:flex;align-items:center;gap:4px;margin-left:auto}
.pk-pol{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:22px;padding:0 5px;border:1px solid var(--line);border-radius:6px;cursor:pointer;font-size:11px}
.pk-pol .pol{width:14px;height:14px}
.pk-pol:hover{border-color:var(--accent)}
.pk-pol.sel{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset}

/* rank stepper (prominent when below max) */
.rank{display:inline-flex;align-items:center;gap:4px;margin-top:3px;font-size:11px;color:var(--muted)}
.rank .rk{width:18px;height:18px;line-height:1;padding:0;border:1px solid var(--line);border-radius:5px;background:var(--plane);color:var(--text);cursor:pointer;font-size:13px}
.rank .rk:hover{border-color:var(--accent)}
.rank b{font-variant-numeric:tabular-nums;min-width:26px;text-align:center}
.rank.lowered{color:#04111f;background:var(--gold);border-radius:6px;padding:1px 4px;font-weight:700}
.rank.lowered .rk{background:rgba(0,0,0,.15);border-color:rgba(0,0,0,.25);color:#04111f}
.combo-menu .opt{display:flex;align-items:flex-start;gap:9px;padding:6px 10px;cursor:pointer;border-left:3px solid var(--rar,transparent)}
.combo-menu .opt .pol,.combo-menu .opt .mod{margin-top:2px}
.combo-menu .opt .dr{margin-top:2px}
.combo-menu .opt:hover{background:var(--panel2)}
.combo-menu .opt.dis{opacity:.4;cursor:not-allowed}
/* A GROUP HEADER inside the one dropdown. Sticky, because the whole point is to
   know which group you are in while scrolling a list long enough to need one. */
.combo-menu .ddgroup{position:sticky;top:0;z-index:1;margin:6px 0 2px;padding:3px 8px;
  background:var(--panel2);color:var(--gold);font-size:11px;letter-spacing:.03em;
  border-bottom:1px solid var(--line)}
.combo-menu .ddgroup:first-child{margin-top:0}
.combo-menu .opt .pol{width:14px;height:14px;flex:none}
.combo-menu .opt .mod{width:28px;height:28px;border-radius:5px;object-fit:cover;border:1px solid var(--rar,var(--line));flex:none}
.combo-menu .opt .mod.none{display:flex;align-items:center;justify-content:center;color:var(--muted);background:var(--panel2)}
/* Target rows: a render, not a card icon — contained, not cropped. */
.combo-menu .opt .en-thumb{width:34px;height:34px;object-fit:contain;flex:none}
.combo-menu .opt .info{flex:1;min-width:0}
.combo-menu .opt .mn{font-size:12.5px;font-weight:600}
.combo-menu .opt .me{font-size:11px;color:var(--text-2)}
.combo-menu .opt .me div{line-height:1.35}
/* Configured slot cards show the current-rank description in the same
   small-text style as the picker cards. */
/* A card's text WRAPS RATHER THAN PUSHES — the NAME row included. One long
   unbreakable token — a translation without spaces, an id, a number with a
   unit — would otherwise set the card's min-content all by itself. */
.slot .me{font-size:11px;color:var(--text-2);overflow-wrap:anywhere}
.slot .me div{line-height:1.35}
/* Item names (mods / arcanes / evolutions) link to their wiki page. */
.wl{color:inherit;text-decoration:none}
.wl:hover{color:var(--accent);text-decoration:underline}
/* The warframe.market mark, beside a tradeable card's name. DIMMER THAN THE
   NAME until hovered: it is an offer, not part of what the card says, and a
   row of them at full strength reads as the list's own content. */
.wm{color:var(--text-2);opacity:.55;margin-left:5px;vertical-align:-1px;display:inline-block}
.wm:hover{color:var(--accent);opacity:1}
.exchip{font-size:9px;letter-spacing:.05em;color:var(--accent);border:1px solid var(--accent);border-radius:4px;padding:0 4px;vertical-align:1px}
.slotchip{font-size:9px;letter-spacing:.05em;color:color-mix(in srgb,var(--accent) 80%,var(--text));border:1px solid color-mix(in srgb,var(--accent) 40%,var(--line));border-radius:4px;padding:0 4px;vertical-align:1px}
.slotchip.cur{color:#fff;background:var(--accent);border-color:var(--accent)}
/* a lower rank of a card on the every-rank list, one picker row each */
.rkchip{font-size:9px;color:var(--muted);border:1px solid var(--line);border-radius:4px;padding:0 4px;vertical-align:1px}
/* placed mods share ONE colour family (accent); the current slot is stronger */
.combo-menu .opt.placed{background:color-mix(in srgb,var(--accent) 8%,transparent)}
.combo-menu .opt.placed:hover{background:color-mix(in srgb,var(--accent) 14%,transparent)}
.combo-menu .opt.cur{background:color-mix(in srgb,var(--accent) 18%,transparent)}
.combo-menu .opt.cur:hover{background:color-mix(in srgb,var(--accent) 24%,transparent)}
.combo-menu .opt .dr{color:var(--muted);font-size:12px}

/* WHAT BECAME OF THIS RUN, under the headline. The states are not the same
   news: `sent` is a fact, `refused` and `failed` are things to act on, `short`
   is a build that is not finished, and `none`/`pending` are neither good nor
   bad. Muted by default, so a run nobody is submitting does not shout. */
/* ITS OWN BLOCK, ABOVE THE RESULT AND OUTSIDE IT. It used
   to sit under the headline inside `.results`, where it read as a footnote to
   the damage number — and it is not about the damage, it is about the RUN. */
.board-outcome{font-size:12px;color:var(--text-2);line-height:1.55;
  margin:0 0 12px;padding:9px 12px;border:1px solid var(--line);
  border-left:3px solid var(--line);border-radius:9px;background:var(--panel2)}
.board-outcome .bo-h{color:var(--text)}
.board-outcome:empty{display:none}
.board-outcome.sent{border-left-color:var(--gold)}
.board-outcome.sent .bo-h{color:var(--gold)}
/* WHERE THE RUN WOULD STAND, in the panel's own accent: it is the answer the
   submitter came for, and the two lines under it are the rules around it. */
.board-outcome .board-place{margin-top:5px;display:block;color:var(--text)}
.board-outcome.sent .board-place{color:var(--gold)}
/* THE RULE THAT DECIDES WHETHER IT WILL BE LISTED, under what happened to the
   run rather than trailing off the end of it: two facts, two lines. */
.board-outcome .board-state{margin-top:5px;display:block}
.board-outcome.refused,.board-outcome.failed{border-left-color:#e0a052}
.board-outcome.refused .bo-h,.board-outcome.failed .bo-h{color:#e0a052}
.board-outcome .board-state{color:var(--muted)}
/* ONE CONTROL FOR EVERY QUANTIFIABLE AXIS: a CARD saying
   what is installed, with a ⋯ that opens the ranked list. It borrows `.slot`
   wholesale — the arcane slot has been this shape all along and is the model —
   and adds only the AXIS LABEL down its left edge, because these cards sit in
   a column of different questions where an arcane's sit in a row of the same
   one. */
.slot.axis{align-items:flex-start;margin-bottom:8px}
.slot.axis .axl{flex:none;width:74px;color:var(--gold);font-weight:700;font-size:12px;
  padding-top:3px;letter-spacing:.02em}
.slot.axis .eicon{width:26px;height:26px;object-fit:contain;flex:none;margin-top:1px;
  filter:invert(0.35) sepia(1) saturate(3) hue-rotate(160deg)}
.slot.axis .mn{white-space:normal}
.slot.axis .ed{font-size:11px;color:var(--text-2);display:block}
.slot.axis .ed div{line-height:1.35}
.slot.axis .bx{color:#e05252;font-size:10px;font-weight:800;font-style:normal}
.slot.axis .ed.warn{color:#e05252;margin-top:3px}
.slot.axis.broken{border-left-color:#8b3a3a}
/* A LOCKED TIER SAYS WHY instead of inviting a click it would refuse. */
.slot.axis.axlocked{cursor:default;color:var(--text-2);opacity:.7}
.slot.axis.axlocked:hover{border-color:var(--line)}
/* A DROPDOWN ROW CARRIES CHIPS TOO — the gain, and whatever the perk admits.
   Same component as the mod list's, so it needs no size of its own. */
#dd-menu .opt .exchip,#dd-menu .opt .bx{margin-left:5px}

/* HOW FAR BEHIND THE STATIC BOARD IS — a footnote, never a headline: the board
   is current almost all the time and a line that shouted would be wrong almost
   all the time. */
.bench-pending{color:var(--gold)}

/* A LIVE BUG IS NOT A SHORTFALL, so it does not wear the shortfall's colour:
   the number is right and the reason is unknown, which is a different thing to
   tell a reader than "this is a floor". */
.livebug-banner .unmod-h{color:var(--gold)}

/* stats panel — merged buckets explained by source */
.srow{padding:7px 0;border-bottom:1px dashed var(--line)}
.srow:last-child{border-bottom:0}
/* One stats CARD per weapon form — visually separate boxes, side by side
   when the panel is wide enough. */
#stats-rows{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:12px;align-items:start}
.fsec{border:1px solid var(--line);border-radius:10px;background:var(--panel2);padding:10px 13px}
.fhead{font-size:13px;font-weight:700;color:var(--gold);border-bottom:1px solid var(--line);padding-bottom:6px;margin-bottom:4px}
.fhead .fmeta{color:var(--text-2);font-weight:400;font-size:11.5px;margin-left:9px;display:block}
/* Per-weapon mechanic caveat on a stat row (e.g. GunCO computes on the
   original base only, excluding evolution flat damage). */
.srownote{font-size:11px;color:var(--gold);line-height:1.4;margin:2px 0 1px}
.shead{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.shead .sk{font-size:13px;font-weight:600}
.shead .sv{font-variant-numeric:tabular-nums;font-size:13px}
.shead .sbase{color:var(--muted)}
.ssrc{font-size:12px;color:var(--text-2);padding:1px 0 0 14px;font-variant-numeric:tabular-nums}
/* A bonus a LOCK is ignoring: struck through, so the row cannot be read as
   "3.3/s, and also -20%". The word is beside it too — a strikethrough alone
   is a style, not a statement. */
.ssrc.sdead{text-decoration:line-through;opacity:.55}
.snote{color:var(--muted);font-size:11px}
/* Projectile blocks inside a form: the gun's rows sit flush, each
   projectile it launches is boxed off with its own heading. */
.fpart{border:1px solid var(--line);border-radius:8px;background:var(--panel);padding:8px 11px;margin-top:12px}
.fparth{font-size:12px;font-weight:700;color:var(--text);border-bottom:1px solid var(--line);padding-bottom:5px;margin-bottom:4px}
.fparth .fmeta{color:var(--text-2);font-weight:400;font-size:11px;margin-left:8px}
.fpart /* Cross-weapon preset import: an inline panel under the bar, one row per
   source weapon. No native dialogs anywhere in this UI. */
.sdmg-title{margin-top:10px}
.sdmg-title{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin:14px 0 4px}
.sdmg{display:flex;justify-content:space-between;gap:10px;padding:3px 0;font-size:13px}
.scond{font-size:12px;color:var(--text-2);padding:3px 0}
/* WHO IS HOLDING IT — four numbers on one line, above the clauses that read
   them. A row rather than a table: it is context for the list below, not a
   panel of its own, and it has to survive a phone (check_mobile). */
.swielder{font-size:12px;color:var(--text-2);padding:3px 0;display:flex;flex-wrap:wrap;gap:4px 16px;font-variant-numeric:tabular-nums}
.swielder b{color:var(--muted);font-weight:600;margin-right:4px}
/* THE WIELDER FLOOR, and the four overrides under it. The floor is context
   rather than a control, so it reads quieter; an override that is OFF greys
   its own number instead of hiding it, because the number is what the fight
   is using. */
.wffloor{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:2px 14px;align-items:baseline;
  font-size:11.5px;color:var(--text-2);font-variant-numeric:tabular-nums;
  padding:4px 0 2px;border-top:1px solid var(--line);margin-top:4px}
.wffloor-h{color:var(--muted);text-transform:uppercase;letter-spacing:.05em;font-size:10px}
.wffloor b{color:var(--muted);font-weight:600;margin-right:3px}
.wfov{display:flex;align-items:center;gap:6px}
.wfov.off{color:var(--muted)}
.wfov.off input[type=number]{opacity:.55}
.wfov input[type=number]{flex:1 1 0;min-width:0}
.scond.off{opacity:.6}

/* fields */
.field-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
@media(max-width:520px){.field-grid{grid-template-columns:1fr 1fr}}
label{display:flex;flex-direction:column;gap:5px;font-size:12px;color:var(--text-2)}
label.check{flex-direction:row;align-items:center;gap:8px;padding-top:18px;color:var(--text)}
select,input[type=number]{background:var(--plane);color:var(--text);border:1px solid var(--line);border-radius:8px;padding:7px 9px;font:inherit;width:100%}
/* All selects share one custom chevron (appearance:none) so the indicator
   is ALWAYS dead-center vertically — the native arrow is UA-drawn and
   uncontrollable (Chrome even ignores line-height on selects). */
select{appearance:none;padding-right:24px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23888e98' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center}
input[type=range]{width:100%;accent-color:var(--accent)}
.hint{font-size:12px;color:var(--muted);margin-top:8px}
.run-btn{margin-top:12px;width:100%;padding:11px;font:inherit;font-weight:700;font-size:15px;background:var(--accent);color:#fff;border:none;border-radius:10px;cursor:pointer}
.run-btn:hover{filter:brightness(1.05)}.run-btn:disabled{opacity:.6;cursor:progress}

/* results */
.placeholder{color:var(--text-2);padding:24px 4px}
.results h3{font-size:12px;margin:18px 0 8px;color:var(--text-2);text-transform:uppercase;letter-spacing:.04em}

/* ---- THE RESULT IS SIX ZONES ------------------------------------------
   A zone answers one question and says which in its own heading, so a reader
   knows what a block is for before reading a number out of it. They do not
   fold: the folds are inside them, and a skeleton that collapses is a page
   with no shape. */
.zone{border:1px solid var(--line);border-radius:12px;background:var(--surface);
  padding:0 16px 16px;margin:0 0 14px}
.zone-h{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin:0 -16px 14px;
  padding:10px 16px;background:var(--panel3);border-bottom:1px solid var(--line);
  border-radius:11px 11px 0 0;font-size:12px}
.zone-n{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;
  flex:none;border-radius:6px;background:var(--gold);color:var(--panel3);font-size:12px;font-weight:800}
.zone-t{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text)}
.zone-q{font-size:12px;font-weight:400;color:var(--muted);text-transform:none;letter-spacing:0}
.zone>.zone-b>.fold:first-child{margin-top:0}
/* THE SEAM. Zone 3 is where the panel stops being an average and becomes one
   engagement, so it and everything under it carry the gold edge the benchmark
   block already used — the reader can see which numbers the playhead moves. */
.zone[data-zone="3"]{border-color:color-mix(in srgb,var(--gold) 34%,var(--line))}
.zone[data-zone="3"]>.zone-h{border-bottom-color:color-mix(in srgb,var(--gold) 34%,var(--line))}
/* WHOSE A ROW OF FIGURES IS, said above it. Two identical KPI rows sat either
   side of the replay bar with nothing saying that one was a mean over a
   hundred fights and the other was one fight — which reads as a panel
   disagreeing with itself. */
.row-label{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-size:11px;color:var(--muted);margin:16px 0 -6px}
.who-tag{display:inline-flex;align-items:center;height:17px;padding:0 6px;border-radius:4px;
  font-size:10px;letter-spacing:.04em;background:var(--panel2);border:1px solid var(--line);color:var(--muted)}
.who-tag.gold{border-color:color-mix(in srgb,var(--gold) 45%,var(--line));color:var(--gold)}
.kpi-row.bench-kpi .kpi{border-color:color-mix(in srgb,var(--gold) 28%,var(--line))}

/* ---- ZONE 2: TWO SIDES AND THE FLOOR BETWEEN THEM ----------------------
   The split is the repo's own rule made visible: a condition about the TARGET
   is simulated, a condition about the TENNO is assumed — so the LAYOUT is that
   claim rather than two headings over two lists. The floor in the middle is
   the fight as it OPENED; the replay's scene is the one that follows a clock.

   THE MIDDLE COLUMN IS THE ONE THAT GIVES. The two sides hold text that has a
   natural width; the picture is happy at any size and shrinks first. */
.fight-three{display:grid;grid-template-columns:minmax(210px,1fr) minmax(220px,1.15fr) minmax(210px,1fr);
  gap:16px;align-items:start}
@media(max-width:900px){.fight-three{grid-template-columns:1fr 1fr}
  .fight-floor{grid-column:1/-1;order:-1}}
@media(max-width:560px){.fight-three{grid-template-columns:1fr}}
.fs-h{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin-bottom:7px}
.fs-h-mid{text-align:center}
.fc-row{display:flex;flex-wrap:wrap;gap:6px;padding:9px 10px}
.fc{display:inline-flex;align-items:center;height:22px;padding:0 9px;border-radius:999px;
  border:1px solid var(--line);background:var(--panel2);color:var(--text-2);font-size:11.5px}
.fs-them .fc{border-color:color-mix(in srgb,var(--accent) 26%,var(--line))}
.fs-n{font-size:11.5px;color:var(--muted);line-height:1.6;margin:8px 0 0}
.fs-mid{text-align:center;margin-top:7px}
.fs-card{background:var(--surface);border:1px solid var(--line);border-radius:10px;
  overflow:hidden;margin-bottom:8px}
/* ONE ROW PER SEAT, and the bar is its share — "who did the work" is the first
   thing a reader of a squad's number asks. A `button` because it opens that
   seat, so the keyboard reaches it like every other control on this panel. */
.fs-seat{display:grid;grid-template-columns:20px minmax(0,1fr) 46px auto;gap:8px;align-items:center;
  width:100%;padding:7px 10px;border:0;border-bottom:1px solid var(--line);
  background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}
.fs-seat:last-child{border-bottom:0}
.fs-seat:hover{background:var(--panel2)}
.fs-n-badge,.fs-seat .fs-n{all:unset}
.fs-seat>.fs-n{display:inline-flex;align-items:center;justify-content:center;width:19px;height:19px;
  border-radius:10px;background:var(--line);color:var(--text-2);font-size:11px;font-weight:700}
.fs-seat.you>.fs-n{background:var(--accent);color:var(--surface)}
.fs-w{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fs-bar{height:6px;border-radius:4px;background:var(--panel2);overflow:hidden}
.fs-bar i{display:block;height:100%;border-radius:4px;background:var(--accent)}
.fs-d{font-size:11px;color:var(--text-2);font-variant-numeric:tabular-nums}
.fs-none{padding:9px 10px;font-size:11.5px;color:var(--muted)}
.fs-who{padding:8px 10px;border-bottom:1px solid var(--line)}
.fs-wn{font-size:12.5px;font-weight:650}
.fs-wb{font-size:11px;color:var(--muted)}
.fs-stat{display:flex;justify-content:space-between;gap:8px;padding:5px 10px;font-size:11.5px;
  border-bottom:1px solid var(--line);color:var(--muted)}
.fs-stat:last-child{border-bottom:0}
.fs-stat b{color:var(--text-2);font-weight:650;font-variant-numeric:tabular-nums}
/* THE SCENE MEASURES THE BOX IT IS HANDED, so the box has to have one before
   `mountArena` runs — a host with no height draws a scene with no height. */
.fight-scene{min-height:190px;background:var(--panel3);border:1px solid var(--line);border-radius:10px}
.fight-foot{margin-top:14px;padding-top:12px;border-top:1px solid var(--line);
  font-size:11.5px;color:var(--text-2)}

/* ---- ZONE 6: THE DOOR OUT --------------------------------------------- */
/* WHAT EACH SEAT READ. Drawn only where there is more than one — with one
   combatant it would be a second copy of the KPI tiles above it. */
.seat-table{margin-top:12px;font-size:11.5px;font-variant-numeric:tabular-nums;overflow-x:auto}
.seat-h,.seat-r{display:grid;grid-template-columns:minmax(120px,1.4fr) repeat(7,minmax(54px,1fr));
  gap:8px;padding:4px 0;align-items:baseline}
.seat-h{color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:.04em;
  border-bottom:1px solid var(--line)}
.seat-r{border-bottom:1px solid var(--line)}
.seat-r .nm{color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.seat-table .fs-n{margin-top:8px}
.bo-consent{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:8px;
  padding-top:8px;border-top:1px solid var(--line);font-size:11.5px;color:var(--muted)}
.bo-consent span{flex:1 1 320px;line-height:1.6}
.exits{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px}
.exits .exit-free{margin-left:auto;font-size:11.5px;color:var(--muted)}
@media(max-width:640px){.exits .exit-free{margin-left:0;flex:1 0 100%}
  .exits .ghost-btn{flex:1 0 auto;text-align:center}}
.hero{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
.hero-label{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.hero-num{font-size:46px;font-weight:800;letter-spacing:-.03em;line-height:1}
.hero-sub{font-size:13px;margin-top:4px}
.forma-badge{font-size:12px;text-align:right;padding:8px 12px;border-radius:10px;border:1px solid var(--line);background:var(--plane)}
.forma-badge.legal{border-color:var(--good)}.forma-badge.illegal{border-color:var(--critical);color:var(--critical)}
.forma-badge b{font-size:17px;display:block}
.kpi-row{display:grid;grid-template-columns:repeat(4,1fr);gap:9px;margin:16px 0 6px}
@media(max-width:520px){.kpi-row{grid-template-columns:1fr 1fr}}
.kpi{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:9px}
.kpi .kv{font-size:19px;font-weight:800}
.kpi .kl{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
.dmg-bar{display:flex;height:24px;border-radius:7px;overflow:hidden;gap:2px}
.dmg-seg{border-radius:3px;min-width:3px}
.legend{display:flex;flex-wrap:wrap;gap:12px;margin-top:8px}
.legend .li{display:flex;align-items:center;gap:6px;font-size:12px}
.legend .dmgic{width:16px;height:16px}
.legend .lv{color:var(--text-2);font-variant-numeric:tabular-nums}
.stat-table{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.stat-table .row{display:flex;justify-content:space-between;gap:8px;padding:7px 11px;background:var(--surface)}
.stat-table .row .k{color:var(--text-2);font-size:12px}
.stat-table .row .v{font-weight:700;font-variant-numeric:tabular-nums}
.error{color:var(--critical);border:1px solid var(--critical);border-radius:10px;padding:12px;margin-top:12px;font-size:13px}

label.check input{width:auto}

/* ---- Sim: section headers + per-buff cards ---- */
.sim-h{font-size:12px;margin:16px 0 8px;color:var(--text-2);text-transform:uppercase;letter-spacing:.04em;font-weight:700}
.sim-h .sim-hint{font-weight:400;text-transform:none;letter-spacing:0;color:var(--muted);margin-left:6px}
.sim-empty{color:var(--muted);font-size:12px;padding:8px 2px}
#sim-buffs,#opt-buffs{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
@media(max-width:520px){#sim-buffs,#opt-buffs{grid-template-columns:1fr}}
.buff-card{display:flex;align-items:center;gap:10px;background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:8px 11px}
.buff-card .bn{flex:1 1 auto;font-size:13px;font-weight:600;color:var(--text);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.buff-card .bctl{flex:0 0 auto;display:flex;align-items:center}
.buff-card .bstep{display:flex;align-items:center;gap:5px}
.buff-card .bstep input{width:54px;padding:4px 6px}
.buff-card .bstep .bmax{font-size:11px;color:var(--muted)}
.buff-card .bchk{flex-direction:row;align-items:center;gap:5px;font-size:12px;color:var(--text-2)}
.buff-card .bchk input{width:auto}
.buff-card .block-lock{flex:0 0 auto;flex-direction:row;align-items:center;gap:5px;font-size:12px;color:var(--text-2);border-left:1px solid var(--line);padding-left:10px}
.buff-card .block-lock input{width:auto;accent-color:var(--gold)}
.buff-card.info{opacity:.75}
/* A CARD THE FIGHT DENIES IS SHOWN, NOT HIDDEN — dropping it would make "this
   weapon has no such buff" and "this fight will not pay it" look the same, and
   telling those apart is the whole reason the switches exist. Dimmer than
   `.off` (not equipped), because this one is a statement about the RUN. */
.buff-card.denied{opacity:.5}
.buff-card.denied .bn{text-decoration:line-through;text-decoration-color:var(--muted)}
.buff-card .bnot.bdenied{color:var(--gold);text-decoration:none}

/* WHICH TRIGGERS FIRE NO BUFF — in LIMITS, beside Infinite ammo, and the grid
   gives it the full row because it is a set rather than a field. NINETEEN of
   them, so they are GROUPED: a header ticks its members and the row indents
   under it. */
.bev-h{font-size:11px;color:var(--muted);margin:6px 0 4px;grid-column:1/-1}
.bevg{grid-column:1/-1;margin-bottom:4px}
.bevg-h{display:flex;flex-direction:row;align-items:center;gap:6px;font-size:12px;
  font-weight:600;color:var(--text-2);cursor:pointer;padding:2px 0}
.bevg-h.on{color:var(--gold)}
.bevg-h input{width:auto;accent-color:var(--gold)}
.bevg-h small{font-weight:400;color:var(--muted)}
.bev-row{display:flex;flex-wrap:wrap;gap:6px;grid-column:1/-1;padding:2px 0 4px 18px}
/* THE SENTENCE THAT STOPS THE MISREADING. A row of ticked kinds reads as a
   fight where those things do not happen; they do, and they still score. */
.bev-why{font-size:11px;color:var(--muted);margin:6px 0 0;grid-column:1/-1;line-height:1.5}
.bev{display:flex;flex-direction:row;align-items:center;gap:5px;font-size:12px;
  color:var(--text-2);border:1px solid var(--line);border-radius:8px;
  padding:4px 9px;background:var(--panel2);cursor:pointer}
.bev input{width:auto;accent-color:var(--gold)}
.bev.on{color:var(--gold);border-color:var(--gold)}

/* ---- Optimizer ---- */
/* The optimizer's starts: each the simulator's own build card, with a fixed
   position outlined in the accent — the one mark the card gains here. */
#opt-starts{margin-top:6px}
.opt-guide{font-size:12.5px;line-height:1.55;color:var(--text-2);margin:0 0 10px;max-width:78ch}
.opt-start{border:1px solid var(--line);border-radius:10px;padding:8px 12px;margin-bottom:8px;background:var(--surface)}
.opt-start-h{display:flex;align-items:center;gap:6px}
.opt-start-add{display:flex;flex-wrap:wrap;gap:8px}
[data-fold="opt-limits"]{margin-top:12px}
#opt-limits{margin-top:6px}
.opt-limit-list{max-height:260px;margin-bottom:8px;border:1px solid var(--line);border-radius:10px;background:var(--panel3)}
.opt-limit-list .opt{cursor:pointer}
.opt-limit-list .opt.opt-out{opacity:.55}
.opt-limit-list .opt.opt-out .mn{text-decoration:line-through}
.opt-limit-fill{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;margin:4px 0 8px;font-size:13px}
.opt-limit-fill label{display:inline-flex;flex-direction:row;align-items:center;gap:6px}
.opt-limit-tier{font-size:11px;color:var(--muted);font-weight:700;margin:6px 0 3px}
#opt-limit-filter{width:100%;margin-bottom:6px}
.opt-start-clash{margin-top:6px;font-size:12px;color:var(--critical)}
.opt-start-swap{margin-top:6px;font-size:12px;color:var(--muted)}
#opt-fight-brief{border:1px solid var(--line);border-radius:10px;padding:8px 12px;margin:8px 0;background:var(--surface)}
.opt-runbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin:8px 0 14px}
.opt-runbar .run-btn{width:auto;margin-top:0;padding:9px 22px}
.opt-runbar .runs-row,.opt-runbar .opt-est{margin:0}
.opt-runbar .opt-est{flex-basis:100%}
.opt-lanes{display:flex;flex-wrap:wrap;gap:4px 10px;font-size:12px;color:var(--muted);margin:4px 0 6px}
.opt-lane{color:var(--text-2)}
.opt-tie{font-size:11px;font-weight:700;padding:1px 7px;border-radius:999px;border:1px solid var(--line);color:var(--text-2)}
.opt-failed{border-color:var(--critical);color:var(--critical)}
.sb-chip.fixed{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
/* Editing a start in the builder: its banner, and the pin on every position. */
.start-edit{border-color:var(--accent)}
.start-edit-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.start-edit-done{border-color:var(--accent);color:var(--accent)}
.start-pin{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:7px;
  border:1px solid var(--line);background:transparent;color:var(--muted);cursor:pointer;flex-shrink:0}
.start-pin.on{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 22%,transparent);color:var(--accent)}
.slot.fixed-pin{box-shadow:inset 0 0 0 1.5px var(--accent)}
.oseg{display:flex;gap:3px;flex:0 0 auto;margin-top:2px}
.oseg .seg.dis{opacity:.4;pointer-events:none}
.oseg .seg{font-size:11px;padding:3px 9px;border-radius:7px;border:1px solid var(--line);cursor:pointer;user-select:none;color:var(--muted);background:var(--panel2)}
.oseg .seg.on{border-color:var(--accent);color:#fff;background:var(--accent)}
.oseg .seg[data-s="fixed"].on{border-color:var(--gold);color:#fff;background:var(--gold)}
.opt-tier{display:flex;align-items:center;gap:8px;margin:4px 0}
.opt-tier .rk{font-size:11px;color:var(--muted);min-width:22px;font-weight:700}
.opt-est{font-size:12px;color:var(--text-2);margin:12px 0 4px}
.opt-est .warn{color:var(--critical)}
/* A control that is on screen but not available to THIS build says why beside
   itself (the Form select under a mod that rules the Incarnon form out). */
span.warn{color:var(--critical);font-size:11px;align-self:center}
.opt-meta{font-size:12px;color:var(--muted);margin:12px 0 8px}
.opt-scn{font-size:11px;color:var(--muted);margin-top:4px}
.preset-bar .pname{font:inherit;font-size:12px;padding:2px 8px;border:1px solid var(--accent);border-radius:999px;background:var(--panel2);color:var(--text);width:150px}
/* ---- home: hero + the weapon list ---- */
.home-page{max-width:1060px;margin:0 auto;padding:28px 18px}
.hero-h{font-size:32px;letter-spacing:-.01em;margin:22px 0 10px}
.hero-h span{color:var(--gold)}
.hero-sub{color:var(--text-2);font-size:15px;max-width:620px;margin:0 0 10px}
/* THE METHOD LINE, a step below what it qualifies. It answers "how does it
   work" where the line above answers "what is it", and at equal weight the two
   read as one paragraph somebody forgot to join. */
.hero-method{color:var(--muted);font-size:13px;max-width:620px;margin:0 0 34px;line-height:1.7}
/* A hero that runs to more than one paragraph: only the last line keeps the
   gap to whatever follows it. */
.hero-lead{margin-bottom:18px}
/* THE STANCE, one size under the heading and in the body's own colour — it is
   read as a second line of the headline, not as a caption of it. */
.hero-stance{font-size:20px;font-weight:600;letter-spacing:-.01em;margin:0 0 8px}
/* THE NUMBERS. A row of figures rather than tiles: the hero states them, the
   support page presents them, and a grid of boxes here would read as the
   product's features instead of its size. Wraps to a second line on a phone. */
.hero-facts{display:flex;flex-wrap:wrap;gap:6px 20px;margin:0 0 12px}
.hero-facts .hf{font-size:13px;color:var(--text-2)}
.hero-facts .hf b{font-size:17px;font-weight:800;color:var(--text);margin-right:5px}
/* THE TERMS, demoted: a footnote to the figures above, the way a chart carries
   its data source. */
.hero-note{font-size:12px;color:var(--muted);max-width:620px;margin:0 0 30px;line-height:1.6}
.hero-note a{color:var(--muted);text-decoration:underline;text-underline-offset:2px;white-space:nowrap}
.hero-note a:hover{color:var(--accent)}
.home-h{font-size:26px;margin:6px 0 18px}
#weapon-grid{display:block}
.wgroup+.wgroup{margin-top:26px}
.wgroup-h{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:700;margin:0 0 10px}
.wgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}
.wcard{display:flex;align-items:center;gap:14px;padding:16px;border:1px solid var(--line);border-radius:14px;background:var(--panel2);text-decoration:none;color:var(--text);transition:border-color .15s}
.wcard:hover{border-color:var(--accent)}
.wcard .wc-img{width:84px;height:84px;object-fit:contain;flex:0 0 auto}
.wc-name{font-size:17px;font-weight:700;margin-bottom:6px}
.wc-tags{display:flex;flex-wrap:wrap;gap:5px}
.wc-tags .tag{font-size:10px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);border:1px solid var(--line);border-radius:999px;padding:2px 8px}
.topbar .brand{text-decoration:none;color:var(--text)}

/* ---- support: the running costs and where to chip in ----
   Same page shell as home (one content width, the same hero type), so the
   footer link does not land somewhere that looks like a different site. */
.support-page{max-width:1060px;margin:0 auto;padding:28px 18px}
.support-page .block{max-width:760px}
/* auto-fit, not a fixed track count: with one channel the card must not
   stretch to the full 1060px, and with three it must still wrap on a phone. */
.sup-channels{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),300px));gap:14px;margin-bottom:26px}
.sup-card{display:block;padding:16px;border:1px solid var(--line);border-radius:14px;background:var(--panel2);text-decoration:none;color:var(--text);transition:border-color .15s}
.sup-card:hover{border-color:var(--accent)}
.sup-name{font-size:17px;font-weight:700}
.sup-what{font-size:12px;color:var(--text-2);margin-top:4px}
.sup-card .run-btn{display:block;text-align:center;font-size:13px;padding:8px}
/* THE FACTS STRIP — what this repository holds, counted rather than claimed.
   auto-fit for the same reason the channel grid uses it: the number of figures
   is decided by what could be counted, not by a layout. */
.sup-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,140px),1fr));
  gap:10px;margin:18px 0 8px}
.sup-fact{border:1px solid var(--line);border-radius:12px;background:var(--panel2);padding:12px 14px}
.sup-fact b{display:block;font-size:22px;font-variant-numeric:tabular-nums;line-height:1.2}
.sup-fact span{display:block;font-size:11px;color:var(--muted);margin-top:2px}
/* What the reader has already run here. Gold, because it is the one line on
   the page that is about them — and set at reading size rather than as a note,
   since it sits immediately above the ask and is the only sentence there that
   the reader cannot dispute. */
.sup-usage{font-size:15px;color:var(--gold);border-left:2px solid var(--gold);
  padding:6px 0 6px 14px;margin:26px 0 0;max-width:760px;line-height:1.6}
/* THE NAMES, AND THEY ARE THE ONLY PEOPLE ON THIS PAGE. A ground of their own:
   the block sat between two bullet lists at the same weight and read as a third
   one, and the single thing it is not is more prose. */
.thx-block{margin:26px 0 0;padding:20px 22px;border-radius:14px;
  background:var(--panel2);border:1px solid var(--line)}
.thx-head{font-size:11px;color:var(--muted);font-weight:600;margin:0 0 16px;
  letter-spacing:.08em;text-transform:uppercase}
/* EVERY NAME IS DRAWN THE SAME. The order carries the ranking and nothing else
   may: a larger or brighter name at the top is a price list drawn rather than
   written, and the page above promises there are no tiers. */
.thx-list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;
  gap:12px 26px}
.thx-one{display:inline-flex;font-size:19px;line-height:1.35}
/* GOLD, the colour this page already gives to the one line that is about a
   PERSON rather than about the software. */
.thx-name{color:var(--gold)}
.thx-more{font-size:12px;margin:16px 0 0}
.sup-costs,.dl-page .sup-costs{list-style:none;margin:0;padding:0;font-size:13px}
.sup-costs li{padding:7px 0;color:var(--text-2)}
.sup-costs li+li{border-top:1px solid var(--line)}
.sup-costs a{color:var(--accent)}
.sup-note{font-size:11px;color:var(--muted);margin:10px 0 0}
.sup-fine{font-size:11px;color:var(--muted);max-width:760px;margin:18px 0 0;line-height:1.7}
/* THE ASK, WHERE THE ANSWER LANDED — drawn once per browser under a finished
   result. Note weight and no button: it sits inside the panel the reader came
   for, so anything louder is in the way of the thing they asked for. */
.sup-nudge{font-size:12px;color:var(--muted);margin:14px 0 0;line-height:1.6;
  border-top:1px solid var(--line);padding-top:12px}
.sup-nudge a{color:var(--accent);white-space:nowrap}

.block-lock.dis{opacity:.45}
.opt-meta .warn{color:var(--critical)}
.opt-progress{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:12px 14px;margin-top:12px}
.opt-prog-head{display:flex;justify-content:space-between;align-items:baseline;font-size:13px;margin-bottom:8px}
.opt-elapsed{font-size:12px;color:var(--muted)}
.opt-bar{height:8px;border-radius:4px;background:var(--plane);overflow:hidden;margin-bottom:6px}
.opt-bar i{display:block;height:100%;background:var(--accent);border-radius:4px;transition:width .4s ease}
.opt-prog-sub{font-size:12px;color:var(--text-2);margin-bottom:6px}
.opt-note{font-size:11px;color:var(--muted);margin:2px 0}
.opt-progress .ghost-btn{margin-top:8px}
#opt-results .opt-row + .opt-resume,
.opt-meta + .opt-resume{margin-top:10px}
.opt-resume{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:11px 13px;font-size:13px;display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.opt-resume>div{flex:1 1 100%;color:var(--text-2)}
.opt-row{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:9px 12px;margin-bottom:7px}
.opt-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.opt-head .opt-rank{font-weight:800;color:var(--text-2)}
.opt-head .opt-kills{font-size:18px;font-weight:800}
.opt-head .opt-kills small{font-size:11px;font-weight:400;color:var(--muted)}
/* WHERE THIS NUMBER CAME FROM. A tick means the simulator was asked to run
   this exact build and answered with the figure beside it; `≠` means it did
   not, which is the one state a reader must never have to discover with a
   stopwatch. Recessive until it is the second one. */
.opt-head .opt-repro{font-size:11px;font-weight:700;margin-left:4px}
.opt-head .opt-repro.pending,.opt-head .opt-repro.stale{color:var(--muted);opacity:.5}
.opt-head .opt-repro.ok{color:var(--good-text)}
.opt-head .opt-repro.off,.opt-head .opt-repro.failed{color:var(--critical)}
.opt-row.opt-unreproduced{outline:1px solid var(--critical);outline-offset:2px;border-radius:6px}
.opt-head .opt-dps{font-size:12px;color:var(--text-2);font-variant-numeric:tabular-nums}
/* The engagement TOTAL, beside the rate — recessive, like a unit suffix. */
.opt-head .opt-total{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums}
.opt-head .opt-load{margin-left:auto}
.opt-detail{font-size:12px;color:var(--text-2);margin-top:5px}
.opt-mods{font-size:12px;color:var(--muted);margin-top:3px}

/* ---- footer: the shell's bottom bar — same content width as .topbar ---- */
.footer{border-top:1px solid var(--line);margin-top:26px}
.footer-inner{max-width:1060px;margin:0 auto;padding:18px 18px 30px;color:var(--muted);font-size:11px;line-height:1.6}
.footer a{color:var(--muted)}

/* ---- Riven constructor ------------------------------------------------
   A row per rolled stat: what it is, where in its 0.9-1.1 band it landed,
   and what that comes to. The slider's ends ARE the band, so an illegal
   roll is not something the control can express. */
.rv-shape,.rv-foot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.rv-lbl{font-size:12px;color:var(--muted);display:inline-flex;align-items:center;gap:6px}
.rv-lbl.dim{opacity:.7;font-variant-numeric:tabular-nums}
.rv-row{display:grid;
  grid-template-columns:64px minmax(150px,1.1fr) minmax(90px,1.2fr) 84px 40px 46px minmax(150px,1.2fr);
  align-items:center;gap:9px;padding:6px 0;border-bottom:1px solid var(--line)}
/* The stat picker opens the SAME searchable popover as the mod and arcane
   slots — one way to pick a thing on this page. */
.rv-pick{background:var(--panel2);border:1px solid var(--line);color:var(--text);border-radius:7px;
  padding:5px 9px;font:inherit;font-size:12px;cursor:pointer;text-align:left;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rv-pick:hover{background:var(--plane)}
/* The value box takes the number printed on a riven, not the roll. */
.rv-num{background:var(--panel2);border:1px solid var(--line);color:var(--text);border-radius:7px;
  padding:4px 6px;font:inherit;font-size:12px;min-width:0;font-variant-numeric:tabular-nums;text-align:right}
.rv-num:disabled{opacity:.4}
/* Where the roll landed in its own band. It sits next to the value because
   it is the same fact read a different way: the value says what you get, the
   percentile says how close to the best that stat gets. */
.rv-pct{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums;text-align:right}
.rv-pct.top{color:var(--gold)}
.rv-pct.low{opacity:.6}
/* The roll itself, beside the percentile: same fact, two readings. Dimmer,
   because the percentile is what you compare cards on — this is what you
   check against the card in your own arsenal. */
.rv-mult{font-size:11px;color:var(--muted);opacity:.75;font-variant-numeric:tabular-nums;text-align:right}
.rv-unit{font-size:12px;color:var(--text-2);font-variant-numeric:tabular-nums}
.rv-unit.neg{color:var(--bad,#e06c75)}
.rv-unit.unmodeled{opacity:.55}
.seg.pol{display:inline-flex;align-items:center;justify-content:center;padding:3px 8px}
.seg.pol img{width:13px;height:13px;display:block}
.rv-row.malus .rv-tag{color:var(--bad,#e06c75)}
.rv-tag{font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
/* A spliced stat's value is unmeasured: the chip and the note say so. */
.rv-spl{display:block;margin-top:2px;color:var(--gold);letter-spacing:0}
.rv-disclaim{margin-top:8px;padding:7px 10px;border:1px dashed var(--gold);border-radius:7px;
  font-size:12px;color:var(--text-2)}
.rv-disclaim b{color:var(--gold);margin-right:4px}
.rv-roll{width:100%}
.rv-card{margin:12px 0}
.rv-name{font-size:22px;font-weight:800;letter-spacing:.01em}
.rv-meta{font-size:12px;color:var(--muted)}

/* A section heading inside a picker list — rivens are a different kind of
   thing from pool mods and read as their own block.
   ONE BOX PER SECTION: a sticky heading is confined to its containing block,
   so headings that are siblings of the rows all stick at top:0 at once and
   pile up on one line. Its own box makes each heading leave with its rows. */
.menu-sect{position:relative}
.menu-head{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);
  padding:8px 10px 4px;border-top:1px solid var(--line);margin-top:4px;position:sticky;top:0;
  z-index:2;background:var(--panel)}
.menu-sect:first-child .menu-head{border-top:none;margin-top:0}

/* Every saved riven, with what it rolls. The bar above chooses; this is what
   you choose between. */
.rv-all{border:1px solid var(--line);border-radius:10px;padding:8px 11px;margin-bottom:7px;cursor:pointer}
.rv-all:hover{background:var(--plane)}
.rv-all.sel{border-color:var(--accent)}
.rv-all-h{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:5px}
.rv-all-h img.pol{width:12px;height:12px}
.rv-all-h b{font-size:14px}
.rv-official{font-size:12px;color:var(--gold)}
.rv-all-s{display:flex;flex-wrap:wrap;gap:6px}
.rv-chip{font-size:11px;background:var(--panel2);border:1px solid var(--line);border-radius:999px;
  padding:2px 8px;font-variant-numeric:tabular-nums}
.rv-chip.neg{color:var(--bad,#e06c75)}
/* The open card as another weapon it fits reads it. */
.rv-kin{margin-top:8px;padding-top:6px;border-top:1px dashed var(--line)}

/* A setting with only one possible value: stated, not offered. Reads like the
   select it replaces so a one-form weapon's panel is not a gap. */
.fixed-val{display:inline-block;padding:4px 8px;border:1px solid var(--line);border-radius:7px;
  background:var(--panel2);color:var(--text-2);font-size:12px}
/* Marginal gain, on a picker row: what this mod would add to the build. */
.gainchip{margin-left:6px;padding:0 6px;border-radius:8px;font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}
.gainchip.up{background:rgba(90,190,120,.16);color:#7fd39a}
.gainchip.down{background:rgba(200,90,90,.14);color:#d98c8c}
/* Below the scan's own resolution: neither green nor red, because the colour is
   the claim people react to and there is no claim to make here. */
.gainchip.flat{background:var(--line);color:var(--text-2);opacity:.85}
.gainchip small{opacity:.7;font-size:10px}
/* TIED WITH THE LEADER. Inside the chip rather than beside it — it qualifies
   the number, and a marker that floats off on its own reads as a second fact.
   Deliberately quiet: it is a caveat on an answer, not an answer. */
.gainchip .gtie{margin-left:5px;padding:0 4px;border-radius:6px;background:var(--line);color:var(--text-2);font-size:10px;text-transform:lowercase}
.picker-tools .pk-note{color:var(--muted);font-size:11px;margin-left:auto}
.picker-tools #pk-gain-scen,.picker-tools #pk-gain-prec{font:inherit;font-size:11px;max-width:120px}
/* The wider buff view: a setting held for a mod the build does not carry. */
.buff-card.off{opacity:.72}
.buff-card .bnot{color:var(--muted);font-size:10px;font-weight:400}
/* QUICK CALC — a page-level bar above the mods: ONE configuration for every
   slot's "what would this be worth as X", so it reads before them all. */
.quick-calc{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 10px;padding:7px 12px;
  border:1px solid var(--line);border-radius:10px;background:var(--panel3)}
.quick-calc .pc-h{font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.quick-calc select{font:inherit;font-size:12px;max-width:150px}
.quick-calc .pc-note{margin-left:auto;color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums}
/* A gain the second pass confirmed reads a touch stronger than a one-run one. */
.gainchip.deep{font-weight:600}
.quick-calc input[type=number]{width:64px;font:inherit;font-size:12px}
/* HOW A WINNING ROW WAS PLAYED, when the search ranged over modes. Gold, like
   every other thing on a row that is a choice the search made rather than a
   number it produced. */
.opt-mode{display:inline-block;margin-right:7px;padding:1px 6px;border:1px solid var(--gold);border-radius:6px;color:var(--gold);font-size:11px}
/* The run count, beside the scenario it runs under. The unit is a word rather
   than a placeholder so the box reads as "10 runs" at a glance, and the pair
   wraps as one on a narrow screen. */
/* WHICH FIGHT the chips were measured in. A STATEMENT, not a control — it
   replaced a dropdown that could disagree with the simulator, so
   it must not look clickable. Truncates rather than wrapping: a scenario name
   is a name the reader chose and can be arbitrarily long. */
/* THE SIM'S PROGRESS. Unbounded wait, so it gets a bar and a COUNT — "412 /
   1000" is a number a reader can act on where a bar alone is only a feeling. */
.simrun{display:flex;flex-direction:column;gap:6px;align-items:stretch}
.simrun-t{color:var(--muted)}
.simrun-bar{height:6px;border-radius:3px;background:var(--line);overflow:hidden}
.simrun-bar span{display:block;height:100%;background:var(--accent);
  transition:width .12s linear}
.simrun button{align-self:flex-start}
.simrun-n{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums}

/* WHERE THE DAMAGE WENT — the RESULT's own copy of the scene, and its roll
   call. Setting up a fight and reading one are two things: this
   block is read-only and lives in the result panel, while the scenario's canvas
   keeps the dragging and the +1/+8. */
.rp-scene{margin:0 0 10px}
.rp-scene .ar-heat{fill:var(--critical)}
.rp-scene .ar-sel{stroke:var(--accent);stroke-width:2.5}
.rp-roll{width:100%;border-collapse:collapse;font-size:12px}
.rp-roll td{padding:2px 6px;vertical-align:middle}
.rp-rollrow{cursor:pointer}
/* A ROW THE REPLAY DID NOT FOLLOW has no series to show, so it does not offer
   a click it cannot honour. */
/* DIMMED BECAUSE ITS SERIES IS NOT IN HAND YET, not because it is dead: a
   click re-runs the fight following it. */
.rp-rollrow.off{opacity:.55}
.rp-rollrow.off:hover{opacity:1}
.rp-rollrow:hover td{background:var(--line)}
.rp-rollrow.sel td{background:var(--line)}
.rp-roll .nm{white-space:nowrap;font-variant-numeric:tabular-nums}
.rp-roll .nm .sm{opacity:.6}
.rp-roll .bar{width:60%}
.rp-roll .bar span{display:block;height:7px;border-radius:3px;background:var(--critical);opacity:.65}
.rp-roll .num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--muted)}

/* WHICH ENEMY the debuff table is about. Chips rather than a dropdown: there
   are at most `REPLAY_TRACKED` of them and they are compared, not searched —
   and the selected one has to be visible without opening anything. */
.rp-foes{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin:0 0 8px}
.rp-foe{font:inherit;font-size:11px;padding:3px 9px;border-radius:999px;cursor:pointer;
  background:var(--panel);color:var(--muted);border:1px solid var(--line)}
.rp-foe:hover{color:var(--fg)}
.rp-foe.sel{background:var(--accent-dim,var(--line));color:var(--fg);border-color:var(--accent,var(--fg))}
.rp-foe .sm{opacity:.6}
/* …AND WHAT WAS LEFT OUT. A cap nobody is told about reads as "that is
   everyone", which is the one thing it must not. */
.rp-foe-more{font-size:11px;color:var(--muted);margin-left:2px}

.quick-calc .pc-scen{color:var(--muted);font-size:11px;max-width:14em;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;border-bottom:1px dotted var(--line);cursor:help}
.quick-calc .pc-runs{display:inline-flex;align-items:center;gap:5px;white-space:nowrap;color:var(--muted);font-size:11px}
.quick-calc .pc-runs input[type=number]{width:58px}
/* The every-rank list, open under the bar: the picker's own card rows, in the
   picker's own frame, so the list reads as the cards it names. */
.quick-calc .pc-ranks{flex-basis:100%;display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.quick-calc .pc-rank-list{flex-basis:100%;max-height:260px;background:var(--surface);
  border:1px solid var(--line);border-radius:10px}
.quick-calc .pc-rank-list .opt{cursor:default}
.combo-menu .rk-x{flex:none;align-self:center;border:0;background:none;color:var(--muted);
  cursor:pointer;font-size:16px;line-height:1;padding:2px 6px;border-radius:5px}
.combo-menu .rk-x:hover{color:var(--critical);background:var(--panel2)}
/* THE RUN COUNT, on its own row and deliberately not in a field grid: it is
   NOT one of the fight's fields, and looking like one is how it came to be
   saved with the fight and pinned by an official ruler. A short input and a
   sentence, the same shape the quick calc's own count has. */
.runs-row{display:flex;align-items:center;gap:10px;margin:10px 0 4px}
.runs-row label{flex-direction:row;align-items:center;gap:8px;color:var(--text)}
.runs-row input[type=number]{width:96px}
.runs-row .sim-hint{margin:0}
@media(max-width:520px){.runs-row{flex-wrap:wrap;gap:6px}}

/* THE OPTIMIZER'S TWO HALVES, MADE VISIBLE. The split has
   been the tab's rule since 2026-08-02 and only headings said so, which cannot
   tell a reader WHICH preset bar owns the thing they are editing. A box says
   it without a sentence: one holds the search, the other holds the fight the
   search is scored under, and anything outside both is in neither preset. */
/* A HALF IS A `.fold.sect` (the box, the fold, the header strip); what is its
   own is the heading's weight — it is the parent of the sections inside it. */
.opt-half{margin:16px 0 4px}
.opt-half-h{font-size:12px;color:var(--text);text-transform:uppercase;letter-spacing:.04em;font-weight:700}
.opt-half-h .sim-hint{font-size:11.5px;font-weight:400;text-transform:none;letter-spacing:0;line-height:1.45;color:var(--muted);margin:3px 0 0;max-width:66ch}


/* Undo/redo feedback — inline, never a native dialog. Theme-aware like
   everything else: the first cut hardcoded a dark palette and became a black
   box on the light theme. */
#toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%) translateY(8px);
  background:var(--surface);color:var(--text);border:1px solid var(--line);border-radius:8px;
  padding:8px 14px;font-size:13px;letter-spacing:.02em;box-shadow:0 6px 24px rgba(0,0,0,.28);
  opacity:0;pointer-events:none;transition:opacity .15s,transform .15s;z-index:120}
#toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

/* ---- CUSTOMS — a thing you MADE, not a saved state, and deliberately not
   the preset bar: no chip row, no "active" pill. A toolbar over a list of
   items, each carrying its own identity. The toolbar says which of the two
   modes you are in — browsing the list, or with one open. */
.cu-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:2px 0 12px;
  padding-bottom:12px;border-bottom:1px solid var(--line)}
.cu-btn{background:var(--panel3);color:var(--text);border:1px solid var(--line);
  border-radius:8px;padding:5px 11px;font:inherit;font-size:12.5px;cursor:pointer}
.cu-btn:hover{border-color:var(--accent)}
/* Creating is the one action the empty state exists to offer. */
.cu-new{color:var(--gold);border-color:var(--gold)}
.cu-new:hover{background:var(--panel2)}
.cu-open{display:flex;align-items:baseline;gap:8px;font-size:14px}
.cu-open .rv-official{color:var(--muted);font-size:12px}
.cu-ops{margin-left:auto;display:flex;gap:6px}
.cu-del:hover{border-color:var(--critical);color:var(--critical)}
.cu-name{background:var(--plane);color:var(--text);border:1px solid var(--accent);
  border-radius:8px;padding:4px 8px;font:inherit;font-size:14px;width:14em}
.rv-none{color:var(--muted);font-size:13px;padding:10px 2px}

/* Undo/redo, where the change happened — the shortcut alone hid the fact
   that there IS a way back. Dimmed to zero when there is nothing to undo,
   so the pair never invites a click that does nothing. */
.pundo{display:inline-flex;gap:2px;margin-left:auto;padding-left:8px}
.pundo .pop{background:transparent;border:1px solid transparent;border-radius:6px;
  color:var(--muted);cursor:pointer;font-size:13px;line-height:1;padding:3px 6px}
.pundo .pop:hover:not([disabled]){color:var(--text);border-color:var(--line)}
.pundo .pop[disabled]{opacity:.3;cursor:default}

/* Share panel — the link and the card, on the build bar. */
.pshare{flex-basis:100%;margin-top:8px}
.sh-row{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.sh-url{flex:1;min-width:240px;background:var(--panel3);color:var(--text);
  border:1px solid var(--line);border-radius:8px;padding:6px 10px;font:inherit;font-size:12px}
.sh-note{color:var(--muted);font-size:12px;margin:8px 0 6px}
.sh-canvas{max-width:100%;height:auto;border:1px solid var(--line);border-radius:10px;display:block}

/* THE FIGHT — a target card over the knobs that shape it. The card is the
   selection; the grid under it is what the same encounter is set to. */
.sub-block{display:flex;flex-direction:column;gap:10px}
/* The card is the PICK; the wiki link beside it is a second, different action
   (read about the unit), which is why it is a sibling and not nested inside
   the button. */
.en-row{display:flex;align-items:center;gap:10px;align-self:flex-start}
.en-card{display:flex;align-items:center;gap:12px;
  background:var(--panel3);border:1px solid var(--line);border-radius:10px;
  padding:9px 14px;font:inherit;color:var(--text);cursor:pointer;text-align:left;
  min-width:240px}
.en-card:hover:not([disabled]){border-color:var(--accent)}
.en-card[disabled]{cursor:default;opacity:.75}
/* Renders are transparent PNGs of varying aspect — contain, never crop. */
.en-card .en-img{width:54px;height:54px;object-fit:contain;flex:none}
.en-card .en-txt{display:flex;flex-direction:column;gap:3px;min-width:0}
.en-card .en-name{font-size:15px;font-weight:600}
.en-card .en-meta{font-size:12px;color:var(--muted)}
/* The faction column. Up and down must read apart at a glance — this is a
   "what do I bring" line, and the two answers are opposite. */
.en-vuln{display:flex;flex-wrap:wrap;gap:4px;margin-top:2px}
.en-vuln span{font-size:11px;padding:0 6px;border-radius:999px;white-space:nowrap;
  border:1px solid currentColor}
.en-vuln .up{color:var(--accent)}
.en-vuln .dn{color:var(--critical)}
/* A known gap in the model, said out loud. Warning-coloured, not error: the
   target works, its number is just optimistic. */
.en-gap{font-size:11px;color:var(--gold)}
.combo-menu .opt .en-gap{display:block;margin-top:1px}
.en-wiki{font-size:12px;color:var(--muted);text-decoration:none;white-space:nowrap}
.en-wiki:hover{color:var(--accent);text-decoration:underline}
/* What one stack count buys, when a buff grants more than one thing. */
.buff-card .bgr{color:var(--muted);font-size:11px;margin-left:6px}
/* A screening number reads as approximate; a refined one reads as measured. */
.gainchip.rough{opacity:.72}

/* ---- REPLAY: the median engagement, scrubbable ------------------------
   One row per buff, deliberately short (28px of curve): five of them have to
   read as a group at a glance, which a stack of full-height charts cannot do
. */
.rp-bar{display:flex;align-items:center;gap:10px;margin:6px 0 10px}
.rp-play{min-width:64px}
/* THE SCRUBBER. The hand wants a wide band and the eye wants a thin line, so
   those are two things: `.scrub` is the 30px target, `.scrub-rail` the 6px
   line inside it. The range input keeps every behaviour it had — drag,
   keyboard, `.value` — and only its paint is taken over, so it lies over the
   rail with a transparent track of its own. */
.scrub{position:relative;flex:1;height:30px;min-width:120px}
.scrub-rail{position:absolute;left:0;right:0;top:12px;height:6px;border-radius:999px;
  background:var(--panel2);overflow:hidden}
.scrub-done{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:999px;
  background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 55%,transparent),var(--accent))}
/* WHAT HAPPENED, ON THE RAIL: a kill is tall and carries the target's colour,
   a reload is short and recessive. Both are derived from the frames already on
   the wire (`risesIn`), so the rail costs no new field. */
.scrub-kill{position:absolute;top:6px;width:2px;height:18px;margin-left:-1px;border-radius:1px;
  background:var(--critical);opacity:.8;pointer-events:none}
.scrub-reload{position:absolute;top:19px;width:2px;height:8px;margin-left:-1px;border-radius:1px;
  background:var(--muted);opacity:.7;pointer-events:none}
.rp-scrub{position:absolute;left:0;right:0;top:0;width:100%;height:30px;margin:0;
  background:transparent;-webkit-appearance:none;appearance:none;cursor:pointer}
.rp-scrub:focus{outline:none}
.rp-scrub:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:8px}
.rp-scrub::-webkit-slider-runnable-track{height:30px;background:transparent;border:0}
.rp-scrub::-moz-range-track{height:30px;background:transparent;border:0}
.rp-scrub::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
  width:16px;height:16px;margin-top:7px;border:0;border-radius:50%;background:var(--accent);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 20%,transparent),0 1px 4px rgba(0,0,0,.55);
  cursor:grab}
.rp-scrub::-moz-range-thumb{width:16px;height:16px;border:0;border-radius:50%;background:var(--accent);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 20%,transparent),0 1px 4px rgba(0,0,0,.55);
  cursor:grab}
.rp-scrub:active::-webkit-slider-thumb{cursor:grabbing;
  box-shadow:0 0 0 7px color-mix(in srgb,var(--accent) 22%,transparent),0 1px 4px rgba(0,0,0,.55)}
.rp-scrub:active::-moz-range-thumb{cursor:grabbing;
  box-shadow:0 0 0 7px color-mix(in srgb,var(--accent) 22%,transparent),0 1px 4px rgba(0,0,0,.55)}
/* A KEY ONLY FOR THE MARKS THIS FIGHT HAS (`scrubLegend`). */
.scrub-legend{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  font-size:10.5px;color:var(--muted);margin:-4px 0 10px}
.scrub-legend .sl{display:inline-flex;align-items:center;gap:5px}
.scrub-legend .sl-kill{width:2px;height:11px;border-radius:1px;background:var(--critical);opacity:.8}
.scrub-legend .sl-reload{width:2px;height:8px;border-radius:1px;background:var(--muted);opacity:.7}
.rp-clock{font-variant-numeric:tabular-nums;color:var(--muted);font-size:12px;min-width:96px;text-align:right}
/* FIXED columns: every figure changes on every frame, and a flowing row
   re-measures itself each time — the labels slide about for the whole
   playback and the page reads as if it were shaking. This also has room for
   a second and third enemy without a re-layout. */
.rp-pools{display:grid;grid-template-columns:repeat(auto-fill,minmax(168px,1fr));gap:2px 16px;font-size:12px;margin-bottom:8px}
.rp-pools-head{font-size:12px;color:var(--muted);margin:0 0 4px}
.rp-cell{display:flex;justify-content:space-between;gap:10px;border-bottom:1px dotted var(--line);padding:2px 0}
.rp-cell i{font-style:normal;color:var(--muted)}
.rp-cell b{font-variant-numeric:tabular-nums;font-weight:600}
.rp-row{border-top:1px solid var(--line);padding:5px 0}
.rp-head{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:12px}
.rp-head .rp-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rp-head .rp-now{font-variant-numeric:tabular-nums;color:var(--accent);font-weight:600}
.rp-head .rp-stat{color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums}
/* A COVERAGE CHART IS READ, NOT GLANCED AT. 28px made every one of these a
   wobble; at 120 the ramp, the dip on a death, the plateau against the ceiling
   and the dead bands are all separate things. A row still collapses to its
   header, which is what keeps a dozen of them scannable. */
.rp-chart{position:relative;height:120px;margin-top:6px;
  border:1px solid var(--line);border-radius:8px;background:var(--panel3);overflow:hidden}
.rp-chart svg{width:100%;height:120px;display:block}
/* THE CLOCK UNDER EACH CHART, so a reader can place a dip without counting
   pixels from the replay bar above. */
.rp-x{display:flex;justify-content:space-between;font-size:10px;color:var(--muted);
  font-variant-numeric:tabular-nums;padding:3px 2px 0}
.rp-area{fill:var(--accent);opacity:.16}
.rp-line{fill:none;stroke:var(--accent);stroke-width:1.5;vector-effect:non-scaling-stroke}
.rp-cur{stroke:var(--text);stroke-width:1;vector-effect:non-scaling-stroke;opacity:.55}
/* Everything past the cursor is greyed, not removed: the shape you are
   walking through has to stay legible while you walk it. */
.tl-ahead,.rp-ahead{fill:var(--bg);opacity:.62}
.tl-now{stroke:var(--text);stroke-width:1;vector-effect:non-scaling-stroke;opacity:.55}
/* The unit labels the figure without competing with it. */
.hero-unit{font-size:14px;font-weight:600;letter-spacing:0;color:var(--muted);margin-left:16px;vertical-align:baseline}
/* THE BENCHMARK FIGHT, set apart from the means above it: one run, which
   replays, where the block above is every run and holds still. */
.bench{border-top:1px solid var(--line);margin-top:14px;padding-top:12px}
.bench-head h3{margin:0 0 4px}
.bench-num{font-size:24px;font-weight:800;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.bench-num .hero-unit{margin-left:8px}
/* A buff at zero is ABSENT, not low — a flat line on the axis says that too
   quietly, and the run that never earned a stack draws the same picture as
   the one that lost them all. */
/* Visible on purpose. A 0.2 s ramp out of sixty seconds is two pixels wide,
   and at a decorative opacity the one thing the band exists to show — that the
   buff was OFF here — could not be seen at all. */
.rp-dead{fill:var(--muted);opacity:.28}
.rp-off{color:var(--muted)}
/* THE AVERAGE, drawn. "avg 17.50/40" is a number you have to hold in your
   head while reading the curve; a line at that height is the same fact you
   can see against it. */
.rp-mean{stroke:var(--accent);stroke-width:1;stroke-dasharray:4 3;opacity:.75;vector-effect:non-scaling-stroke}

/* THE OFFICIAL SCENARIO. A ruler, not a preset: marked on its chip, explained
   above the fight, and visibly inert while it is open. */
/* THE MULTIPLICATIVE BUCKET line under a stat row. Monospace so the terms
   line up and the bracket reads as arithmetic rather than prose; dimmer than
   the answer above it, because it explains that answer rather than competing
   with it. */
.sbucket{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;color:var(--text-2);margin:2px 0 3px;padding-left:2px}
.sbucket b{color:var(--text)}
.bterm{color:var(--gold);cursor:help}
.bhint{margin-left:6px;padding:0 4px;border:1px solid var(--line);border-radius:6px;cursor:help;font-size:10px}
/* "This part is out of scope." Deliberately not styled as an error — the mod
   is real and equippable, it is our model that stops short — but not styled as
   ordinary card text either, or it reads as one more thing the mod does. */
.unmodeled{display:inline-block;margin-top:2px;padding:0 5px;border:1px dashed var(--line);border-radius:6px;color:var(--text-2);font-size:10px;cursor:help}
/* "Outside the sim" is not a defect — dotted rather than dashed, and no
   warning colour, because the mod is fine and so are we. */
.unmodeled.oos{border-style:dotted}
/* A LIVE BUG reads the other way round from the three above: nothing is missing,
   the number is right, and it is right because the game is wrong. SOLID border
   — this is a statement about the game, not an apology about the model — and
   the gold the app reserves for things that are a property of the subject
   rather than of us. */
.livebug{display:inline-block;margin-top:2px;padding:0 5px;border:1px solid var(--gold);border-radius:6px;color:var(--gold);font-size:10px;cursor:help}
/* A CAVEAT, not a warning. The perk works exactly as written — it is the
   interaction that surprises — so it reads as information, in the muted text
   colour, rather than in the ⚠ red the broken-evolution notice uses. */
.ed.caveat{display:block;margin-top:2px;color:var(--text-2);font-size:10px;cursor:help}
/* Not an error — the weapon is fine and the numbers are real, they are just
   incomplete. Muted, dashed, and above the rows it qualifies. */
.unmodeled-banner{margin:0 0 8px;padding:5px 9px;border:1px dashed var(--line);border-radius:8px;color:var(--text-2);font-size:11px}
/* A weapon's passives, in its own strip. Gold bullet because it is a property
   of the WEAPON — the same colour the wordmark and the ◆ official mark use for
   "this is the real thing" — and small, because it is context and not a stat. */
.wpassives{margin-top:5px;display:flex;flex-direction:column;gap:3px}
.wpassives div{font-size:11px;color:var(--text-2);line-height:1.45}
.wpassives div::before{content:"◆ ";color:var(--gold)}
.pchip.ro{border-style:dashed}
.pofficial{color:var(--gold);margin-right:4px;font-size:11px}
.official-note{margin:6px 0 2px;padding:7px 10px;border:1px dashed var(--line);
  border-radius:8px;background:var(--panel2);color:var(--muted);font-size:12px;line-height:1.5}
.official-note b{color:var(--gold)}
.official-def{color:var(--text);font-variant-numeric:tabular-nums}
.locked{opacity:.72}
/* An official BUILD: the editor is click handlers on divs, so the lock has to
   be pointer-events rather than `disabled`. */
/* A LOCKED BLOCK SAYS WHY, instead of just not reacting. `pointer-events` moves
   onto the CHILDREN so the block itself still takes hover and a click: a slot
   you cannot fill is silent otherwise, and silence is what sent a player back
   to the board four times. */
.locked-hard{opacity:.72;cursor:not-allowed}
.locked-hard *{pointer-events:none}
/* The board's consent line: the same quiet card as the official note, with its
   two choices inline — never a dialog. */
#board-consent .ghost-btn{margin-left:6px}
.board-state{color:var(--text)}

/* DAMAGE TYPE COLOURS — DE's own, transcribed from the wiki's
   `Module:DamageTypes/data` (`Color` for light, `DarkModeColor` for dark).
   The wiki names its own variables `--dt-<type>-text-color`; the same names
   are used here so the two can be compared without a translation step.

   THEY BELONG TO THE TYPE, NOT TO THE ROW. Colouring by POSITION
   (`(i % 8) + 1`) makes Heat one colour under a direct hit and another under a
   field, and lets two runs of the same build disagree about what colour Heat
   is. A colour keyed on the type cannot
   do that, and it is the same colour the wiki and the game use. */
:root{
  --dt-impact: #3d5e5e;
  --dt-puncture: #5c5247;
  --dt-slash: #7a5254;
  --dt-cold: #17658c;
  --dt-electricity: #610fb3;
  --dt-heat: #994d00;
  --dt-toxin: #006611;
  --dt-blast: #b32a00;
  --dt-corrosive: #4d6600;
  --dt-gas: #006633;
  --dt-magnetic: #4747d1;
  --dt-radiation: #806000;
  --dt-viral: #b71658;
  --dt-true: #664d00;
  --dt-void: #085e50;
  --dt-tau: #b30000;
}
@media (prefers-color-scheme: dark){:root:where(:not([data-theme="light"])){
  --dt-impact: #80c4c4;
  --dt-puncture: #c6b098;
  --dt-slash: #e69ca0;
  --dt-cold: #5bbcec;
  --dt-electricity: #b37fe7;
  --dt-heat: #fb9733;
  --dt-toxin: #00cc22;
  --dt-blast: #dd704e;
  --dt-corrosive: #93c203;
  --dt-gas: #00cc66;
  --dt-magnetic: #9797e6;
  --dt-radiation: #ceac49;
  --dt-viral: #f093b9;
  --dt-true: #dda700;
  --dt-void: #15c8ab;
  --dt-tau: #f06666;
}}
:root[data-theme="dark"]{
  --dt-impact: #80c4c4;
  --dt-puncture: #c6b098;
  --dt-slash: #e69ca0;
  --dt-cold: #5bbcec;
  --dt-electricity: #b37fe7;
  --dt-heat: #fb9733;
  --dt-toxin: #00cc22;
  --dt-blast: #dd704e;
  --dt-corrosive: #93c203;
  --dt-gas: #00cc66;
  --dt-magnetic: #9797e6;
  --dt-radiation: #ceac49;
  --dt-viral: #f093b9;
  --dt-true: #dda700;
  --dt-void: #15c8ab;
  --dt-tau: #f06666;
}


/* ---- THE dropdown ---------------------------------------------------- */
/* One trigger shape for every choose-one control. It
   deliberately matches the native `select` rule above —
   same border, radius, caret position — so replacing a select moves nothing
   on the page; only what OPENS from it changes. */
.dd{display:inline-flex;align-items:center;gap:6px;background:var(--plane);color:var(--text);
    border:1px solid var(--line);border-radius:8px;padding:7px 9px;font:inherit;cursor:pointer;
    max-width:100%;text-align:left}
.dd:hover{border-color:var(--accent)}
.dd .dd-v{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.dd .dd-c{color:var(--muted);font-size:10px;flex:none}
.dd .dd-i{width:20px;height:20px;border-radius:4px;object-fit:cover;flex:none}
/* Inside a dense tool strip the replacement for a select keeps that strip's
   smaller metrics rather than the page default. */
.picker-tools .dd,.quick-calc .dd{padding:3px 8px;font-size:12px}
.quick-calc .dd{max-width:150px}
.topbar .dd{height:28px;padding:0 8px;font-size:12px;margin-left:auto}

/* WHAT IS NOT MODELLED YET, wherever a perk is chosen. Amber rather than red:
   it is not broken and not an error — the game has it and the sim cannot price
   it yet, which is a different thing from the BROKEN badge beside it. */
.caveat.unmod{color:var(--gold)}
/* The builder's evolution tiles use <i> for their marks (`.bx` BROKEN does),
   so the unmodelled chip has to lose the italic it would otherwise inherit. */
/* The weapon's own "what this does not model" banner: a heading and one line
   per gap, so several gaps read as a list rather than as one long sentence. */
.unmod-h{font-weight:600}
.unmod-l{margin-left:1.1em;opacity:.9}
.unmod-l::before{content:"· "}
.exchip.unmod{background:color-mix(in srgb,var(--gold) 18%,transparent);color:var(--gold);
  border:1px solid color-mix(in srgb,var(--gold) 40%,transparent)}
/* THE OTHER ADMISSION, and it is deliberately NOT gold: gold is a todo, and a
   todo asks to be watched. An EDGE is settled — muted, stated once, no alarm. */
/* A TARGET THAT TAKES YOUR BUFFS AWAY. Loud on purpose: everything below it is
   ticked and not running, and a player reading only the checkboxes would be
   scoring a fight they are not in. */
.wfb-null{margin:6px 0 2px;padding:6px 8px;border-radius:6px;font-size:12px;
  background:rgba(200,90,90,.14);color:#d98c8c;
  border:1px solid color-mix(in srgb,#d98c8c 34%,transparent)}

.exchip.scope{background:color-mix(in srgb,var(--fg) 8%,transparent);color:var(--dim);
  border:1px solid color-mix(in srgb,var(--fg) 16%,transparent)}
.exchip.livebug{background:color-mix(in srgb,var(--bad,#e06c75) 12%,transparent);
  color:var(--bad,#e06c75);
  border:1px solid color-mix(in srgb,var(--bad,#e06c75) 40%,transparent)}
/* A MISPRINT IS NOT A FAULT — the effect works and its card is wrong about it,
   which is the opposite advice to `.livebug` beside it. So it reads as a NOTE
   rather than a warning: the accent colour, not the bad one. */
.exchip.misprint{background:color-mix(in srgb,var(--acc,#c8a165) 12%,transparent);
  color:var(--acc,#c8a165);
  border:1px solid color-mix(in srgb,var(--acc,#c8a165) 40%,transparent)}

/* ---- topbar navigation: the site's OWN pages ---------------------------
   Against the wordmark, before the search — these are destinations, not the
   "this project, elsewhere" links that follow. */
.topnav{display:flex;gap:2px;flex:0 0 auto}
.tnav{padding:4px 9px;border-radius:7px;color:var(--text-2);font-size:12px;text-decoration:none;white-space:nowrap}
.tnav:hover{background:var(--line);color:var(--text)}
.tnav.sel{background:var(--line);color:var(--text);font-weight:600}

/* ---- the topbar menu: one set of controls, two shapes ------------------
   `display:contents` is the whole trick. Above 700px `.topmenu` and
   `.tblinks` are not boxes at all — their children ARE the bar's flex items,
   so the desktop row is the row that existed before the wrapper was added and
   nothing is duplicated. Which means `order:` has to be spelled out, because
   promoted children default to 0 and would otherwise jump the wordmark. */
.topmenu,.topmenu .tblinks{display:contents}
.topbar-inner .brand{order:1}
.topbar-inner .topnav{order:2}
.topbar-inner .wsearch{order:3}
.topbar-inner .tblinks>*{order:4}
/* `.topbar-inner .ghost-btn` sets `display:inline-flex` for every button in
   the bar and outranks a single class, so hiding this one has to match that
   specificity — the same trap the icon links' width fell into above. */
.menu-toggle{order:5;font-size:15px;line-height:1}
.topbar-inner .menu-toggle{display:none}

/* ---- the topbar overflow: `⋯` -----------------------------------------
   The bar carries what a reader ACTS on; everything else is one click away
. Below 700px this whole thing is `display:contents` and
   its children flatten into the phone menu — one copy of every control at both
   widths, which is the same trick `.topmenu` plays one level up. */
.tbmore{position:relative}
.tbmore-panel{display:none;position:absolute;top:calc(100% + 10px);right:0;z-index:60;
  min-width:190px;flex-direction:column;gap:2px;padding:6px;
  background:var(--surface);border:1px solid var(--line);border-radius:10px;
  box-shadow:0 8px 28px rgba(0,0,0,.35)}
.tbmore.open .tbmore-panel{display:flex}
.tbmore-btn{font-size:15px;line-height:1}
/* A MARK WORKS IN A ROW OF MARKS; A PANEL IS A LIST, AND A LIST HAS NAMES.
   The 28px icon rule above is `.topbar-inner .x-link` (0,2,0), so winning it
   back inside the panel takes the same specificity plus one — the same trap
   that rule itself was written to escape. */
.topbar-inner .tbmore-panel .ghost-btn{width:100%;height:30px;gap:9px;padding:0 8px;
  justify-content:flex-start;border-color:transparent}
.topbar-inner .tbmore-panel .ghost-btn:hover{background:var(--plane)}
.tbl{display:none}
.tbmore-panel .tbl{display:inline;font-size:12px;color:var(--text-2)}
/* The language dropdown's `margin-left:auto` is what pushes the right-hand
   group over on the bar; inside the panel there is nothing to push. */
.tbmore-row{display:flex;align-items:center;gap:9px;height:30px;padding:0 8px}
.tbmore-row .tbl{flex:1 1 auto}
.topbar .tbmore-panel .dd{margin-left:0}
/* THE COMMUNITY SLOT IS A HOLE, NOT A BOX: `applyCommunityOrder()` moves a
   mark into it, and it must sit where the mark itself would have. Which means
   the promoted child needs the ORDER — `.topbar-inner .tblinks>*` reaches the
   slot, and a slot that is `display:contents` is not a flex item, so the value
   lands on nothing while its child defaults to 0 and sorts in front of the
   WORDMARK. Caught on a screenshot, not by geometry: the mark was still
   on screen and still inside the viewport, so nothing measuring reachability
   could see it. Same trap this file warns about two rules up. */
.tbcomm{display:contents}
.topbar-inner .tbcomm>*{order:4}

@media (max-width:700px){
  /* Below here the wrapper becomes a real box, hanging off the bar. The
     anchor is the bar itself so the panel tracks the sticky header. */
  .topbar-inner{position:relative}
  .topbar-inner .menu-toggle{display:inline-flex}
  /* `right:18px` is the bar's own side padding, so the panel's right edge
     lines up with the button that opened it instead of with the screen. */
  .topmenu{display:none;position:absolute;top:calc(100% + 8px);right:18px;z-index:60;
    min-width:196px;max-width:calc(100vw - 36px);flex-direction:column;gap:8px;padding:8px;
    background:var(--surface);border:1px solid var(--line);border-radius:10px;
    box-shadow:0 8px 28px rgba(0,0,0,.35)}
  .topbar.menu-open .topmenu{display:flex}
  /* The panel's own order. Inside it the two children are `.topnav` and
     `.tblinks`, and the desktop `order:` values were written for the BAR —
     `.tblinks` itself has none there, so it sorted to 0 and the icons came out
     above the destinations with the divider stranded at the top. */
  .topmenu .topnav{order:1}
  .topmenu .tblinks{order:2}
  /* Destinations read as a list — full-width rows with a tap target, not the
     4px-tall chips they are when they sit against the wordmark. */
  .topmenu .topnav{flex-direction:column;gap:2px}
  .topmenu .tnav{padding:9px 10px;font-size:13px}
  /* ...and "this project, elsewhere" stays a ROW of marks. Six labels down a
     phone menu would be six lines of chrome above nothing; the icons are
     already the vocabulary the desktop bar uses. */
  .topmenu .tblinks{display:flex;flex-wrap:wrap;align-items:center;gap:6px;
    border-top:1px solid var(--line);padding-top:8px}
  /* The language dropdown's `margin-left:auto` is what pushes the right-hand
     group over on a desktop; inside the panel there is nothing to push. */
  .topbar .topmenu .dd{margin-left:0}
  /* The overflow stops being one: its children join the phone menu directly,
     so the `⋯` has nothing left to open and the panel is not a box. */
  .tbmore,.tbmore-panel,.tbmore.open .tbmore-panel{display:contents}
  .topbar-inner .tbmore-btn{display:none}
  /* `.topbar-inner .tblinks>*` sets order:4 on the row's own children; the
     overflow's promoted children default to 0 and would jump ahead of the ask.
     They sort after it instead — the ask is LAST of what the reader came for
     and first of what spilled out of the bar. */
  .topbar-inner .tbmore-panel>*,.topbar-inner .tbmore-panel .tbcomm>*,
  .topbar-inner .tbmore-row>*{order:5}
  /* Back to a ROW of marks, which is what the phone menu has always been:
     names down a narrow panel would be six lines of chrome above nothing. */
  .tbmore-panel .tbl{display:none}
  .topbar-inner .tbmore-panel .ghost-btn{width:28px;height:28px;padding:0;
    justify-content:center;border-color:var(--line)}
  .tbmore-row{display:contents}
}

/* ---- the ask, beneath a finished result -------------------------------
   Muted, static, below the last fold — it states the work in numbers the
   reader can check against the Detail table above it, and only then asks.
   Never a modal, never a banner, and it does not move: the topbar being
   chrome was always the rule, and it still is. */
.sim-ask{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--line);
  color:var(--muted);font-size:12px;line-height:1.6}
.sim-ask a{color:var(--gold);text-decoration:none;white-space:nowrap}
.sim-ask a:hover{text-decoration:underline}

/* ---- the board -------------------------------------------------------- */
.bench-sub{max-width:70ch;margin:0 0 14px;color:var(--text-2);font-size:15px;line-height:1.55}
/* The terms, between the chips and the standard they belong to. */
.bench-note{max-width:70ch;margin:14px 0 0;color:var(--muted);font-size:12px;line-height:1.6}
#bench-picker{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}
/* WHICH BUILDS, under WHICH FIGHT — the second row reads as subordinate to the
   first because it is: a ruler is the standard, this only narrows who is shown
   under it. */
#bench-view{display:flex;flex-wrap:wrap;gap:6px;margin:-6px 0 12px}
#bench-view .bchip{font-size:.86em;padding:3px 9px}
.bchip{padding:5px 11px;border:1px solid var(--line);border-radius:8px;background:transparent;
  color:var(--text-2);font-size:12px;cursor:pointer;font-family:inherit}
.bchip:hover{color:var(--text)}
.bchip.sel{background:var(--line);color:var(--text);font-weight:600}
.brules{margin:0 0 12px;border:1px solid var(--line);border-radius:9px;padding:8px 12px}
.brules summary{cursor:pointer;color:var(--text-2);font-size:12px;list-style:none}
.brules summary::-webkit-details-marker{display:none}
.brules summary::before{content:"▸ ";color:var(--text-2)}
.brules[open] summary::before{content:"▾ "}
.bstd{margin:9px 0 0;color:var(--text);font-size:12.5px;line-height:1.65;max-width:78ch}
.brules ul{margin:8px 0 2px;padding-left:18px}
.brules li{margin:5px 0;color:var(--text-2);font-size:12.5px;line-height:1.6;max-width:78ch}
.bench-meta{margin-bottom:8px;color:var(--text-2);font-size:12px}
.bench-rows{display:flex;flex-direction:column;gap:2px}
.brow{display:flex;align-items:center;gap:10px;padding:6px 10px;border-radius:8px;
  color:var(--text);text-decoration:none}
.brow:hover{background:var(--line)}
.brow .brank{flex:0 0 44px;color:var(--text-2);font-size:12px;font-variant-numeric:tabular-nums}
.brow .bimg{flex:0 0 auto;width:34px;height:34px;object-fit:contain}
.brow .bname{flex:1 1 auto;font-size:13px}
/* ON EVERY ROW, including a weapon with one way to be played. A tag that
   appears on the neighbour and not here reads as "no mode" rather than as
   "one mode", and this is the page where weapons are compared. */
.brow .bmode{margin-left:6px;padding:1px 6px;border:1px solid var(--line);border-radius:6px;
  color:var(--text-2);font-size:11px;white-space:nowrap}
/* A weapon the sim knows it does not fully model, marked where weapons are
   COMPARED. Quiet on purpose — it is a footnote on the number, not a warning
   about the row — and it carries the whole list in its title. */
.brow .bgap{margin-left:5px;color:var(--warn,#c8a24a);font-size:11px;cursor:help}
.brow .bscore{flex:0 0 auto;font-size:13px;font-variant-numeric:tabular-nums}
/* An unmeasured weapon is not a low score — it is the invitation, and it reads
   as one rather than as a zero at the bottom of a ranking. */
.brow.none{opacity:.62}
.brow .bnone{color:var(--text-2);font-size:12px}

/* THE FIRST PAINT. Everything else is hidden until the wasm has answered, so
   without this the page is blank for as long as that takes — and a blank page
   is indistinguishable from a broken one, which is how it got reported. */
.booting{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;gap:2px;
  font-size:22px;letter-spacing:.08em;color:var(--text-2);background:var(--bg);z-index:50}
.booting .bdot{animation:bootdot 1.2s infinite}
.booting .bdot:nth-child(2){animation-delay:.15s}
.booting .bdot:nth-child(3){animation-delay:.3s}
@keyframes bootdot{0%,60%,100%{opacity:.25}30%{opacity:1}}
/* Motion is decoration here; the word alone says the same thing. */
@media (prefers-reduced-motion:reduce){ .booting .bdot{animation:none} }

/* WARFRAME ABILITY BUFFS (scenario section 3). A grid of cards rather than a
   field row: each one carries a name, what it is worth at YOUR strength, how
   long it runs, and a link to the page the number came off — five facts, which
   is more than a label and an input can hold. */
.wfb-head{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:8px}
/* EARLY ACCESS, on screen. The block is honest about being ahead of the frame
   layer it will move into, in the muted voice the other caveats use — this is
   information, not a warning. */
.wfb-early{color:var(--text-2);font-size:11px;flex:1 1 240px}
.wfb-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:8px}
.wfb{padding:7px 9px;border:1px solid var(--line);border-radius:8px;background:var(--bg-2)}
/* A TICKED buff is the one that changes a number, so it is the one that gets
   the accent — the rest of the grid is a catalogue. */
.wfb.on{border-color:var(--accent)}
/* SUPERSEDED: ticked, and something stronger of the same family is running.
   Dimmed rather than hidden, because it is still YOUR selection — the line
   below says why it pays nothing. */
.wfb.dead{opacity:.62;border-color:var(--line)}
.wfb-n{font-weight:600}
.wfb-f{color:var(--text-2);font-size:11px;margin-left:5px}
/* THE NUMBER, on its own line and big enough to read: it is what the block is
   for, and a card that only named the ability would leave the strength multiply
   to the reader. */
.wfb-v{margin-top:4px;font-size:16px;font-weight:650;color:var(--gold);font-variant-numeric:tabular-nums}
.wfb-e{margin-top:2px;color:var(--text-2);font-size:11px;line-height:1.45}
/* The card's ADMISSIONS — the same `⊘ partly modelled` / `⚑ unintended` chips a
   mod and an arcane carry, so an ability that leaves something out looks the
   way every other family does. Empty on every buff that has nothing to admit,
   and the margin comes with the chips rather than with the box. */
.wfb-u{display:flex;flex-wrap:wrap;gap:4px}
.wfb-u:not(:empty){margin-top:5px}
.wfb-dead{margin-top:3px;color:var(--gold);font-size:11px}
.wfb-w{display:inline-block;margin-top:6px;color:var(--text-2);font-size:11px;text-decoration:none}
.wfb-w:hover{color:var(--accent)}
/* A CHOSEN element (Resupply's gear wheel). Small and inline: it is a property
   of the buff you already ticked, not a second decision. */
.wfb-el{display:block;margin-top:4px;color:var(--text-2);font-size:11px}
.wfb-el select{margin-left:5px;font-size:11px}

/* THE ACCOUNT OF ONE HIT — a ledger, so it reads down a column and the
   products line up. Monospace figures on the right, because the whole point is
   that a reader can multiply them. */

/* A BLOCK FOLDS. The caret turns, the body goes; the heading stays so the page
   keeps its shape and you can find the thing you closed. */
.fold>.fold-h{cursor:pointer;user-select:none;display:flex;align-items:center;gap:6px}
.fold>.fold-h .fold-c{display:inline-block;transition:transform .12s;color:var(--muted);font-size:11px}
.fold.shut>.fold-h .fold-c{transform:rotate(-90deg)}
.fold.shut>.fold-b{display:none}

/* A SECTION FOLDS, AND IT IS A BOX SO THAT ITS HEADING READS AS A CONTROL.
   The numbered headings inside a block are where the page's length actually
   is — the simulator's seven, the optimizer's five axes and its two halves —
   and a bare label gives a reader no reason to think it can be shut. A
   bordered header row does, at the cost of one nesting level.
   EVERY CHILD BUT THE HEADING GOES, rather than a `.fold-b` the markup has to
   remember to wrap: a section that gains an element tomorrow folds with it.
   IMPORTANT, because a child's own `#id{display:grid}` outranks any class
   selector and kept the Buffs section's cards on screen while it was shut. */
.fold.sect{border:1px solid var(--line);border-radius:10px;margin:12px 0;
  padding:0 12px 12px;background:var(--surface)}
.fold.sect.shut{padding-bottom:0}
.fold.sect.shut> :not(.fold-h){display:none!important}
.fold.sect>.fold-h .fold-c{font-size:13px;color:var(--text-2)}
.fold.sect>.fold-h{margin:0 -12px 10px;padding:8px 12px;flex-wrap:wrap;align-items:baseline;
  border-bottom:1px solid var(--line);background:var(--panel3);border-radius:9px 9px 0 0}
.fold.sect.shut>.fold-h{margin-bottom:0;border-bottom:0;border-radius:9px}
/* A long hint wraps under the title instead of stretching the row. */
.fold.sect>.fold-h>.sim-hint{margin-left:0;min-width:0}
.fold.sect>.opt-half-h>.sim-hint{flex:1 0 100%}
/* The heading's own controls (the Buffs section's "all") keep their click. */
.fold>.fold-h button{align-self:center}

/* A BLOCK FOLDS FROM THE HEADER IT ALREADY HAS, and the row gains nothing but
   the caret: `.bh` is what a reader reaches for anyway, and the buttons in it
   (auto Forma, clear) keep their own clicks. Only on the weapon page — a
   support or download section is three lines and has nothing to hide. */
.config-page .block>.bh{cursor:pointer;user-select:none}
.bh .fold-c{display:inline-block;transition:transform .12s;color:var(--text-2);font-size:13px}
.block.shut>.bh .fold-c{transform:rotate(-90deg)}
.block.shut>.bh{border-bottom:0}
.block.shut>.bb{display:none}
/* THE BUILD FINDER FOLDS TO ITS TITLE AND COUNT: the query and the view
   switch in its head steer a table that is no longer on screen. */
.finder>.fd-head.fold-h{gap:10px}
.finder>.fd-head.fold-h .fold-c{font-size:13px;color:var(--text-2)}
.finder.shut>.fd-head{border-bottom:0}
.finder.shut> :not(.fd-head),
.finder.shut>.fd-head> :not(.fold-c):not(.fd-title):not(.fd-count){display:none}
/* WHAT EACH MODE IS. A definition list under the Mode control: one entry per
   mode this weapon has, the picked one marked. It sits inside the builder's
   own block, so it takes the block's width and wraps rather than pushing the
   mod grid sideways — a phone reads this too (check_mobile). */
.fold[data-fold="mode-def"]{margin-top:6px}
.fold[data-fold="mode-def"]>.fold-h{font-size:11px;font-weight:600;color:var(--text-2);margin:0}
.modedef{padding:4px 0;border-top:1px solid var(--line)}
.modedef:first-child{border-top:0}
.modedef-n{font-size:11px;font-weight:600;color:var(--text)}
.modedef.on .modedef-n{color:var(--gold)}
.modedef-on{font-size:10px;font-weight:400;color:var(--muted)}
.modedef-l{font-size:11px;line-height:1.45;color:var(--text-2);max-width:60ch}
/* EVERY HIT, SORTED. Tabular figures, because the whole point is comparing a
   column down its length. */
.kpi .ksub{font-size:10px;color:var(--muted)}

/* An option the scan has not reached yet. Muted and non-committal on purpose:
   it is the one state that must not read as a number. */
.gainchip.pend { opacity: .45; letter-spacing: .1em; }

/* A ONE-LINE NOTICE FROM THE PAGE ITSELF — see `noteInline`. Fixed to the top,
   because what it reports (a save that did not happen) is true wherever you
   have scrolled to; click it to dismiss. */
.page-note{position:fixed; left:50%; transform:translateX(-50%); top:10px; z-index:9998;
  max-width:min(92vw,560px); padding:9px 14px; border-radius:9px; cursor:pointer;
  background:color-mix(in srgb,var(--critical) 14%,var(--surface));
  border:1px solid color-mix(in srgb,var(--critical) 45%,transparent);
  color:var(--text); font-size:13px; box-shadow:0 6px 24px rgba(0,0,0,.28)}

/* ---- THE ARENA AS AN EDITOR -------------------------------
   A canvas you pan and zoom, with its chrome floating on it.

   ONE LOGIC LINE: the LEFT column is what you are about to DO (the tools, the
   brush the active tool acts with, the switches that change how it behaves),
   the TOP RIGHT is what you have SELECTED, and the bottom is the read-outs.
   Nothing appears in two places, and neither side does the other's job -- one
   card being both at once is why neither would be findable. */
.arena{container-type:inline-size}
/* THE FLOOR IS NOT PROSE, so it does not live inside the reading column: the
   page caps itself at 760px, which is right for text and wrong for a thing you
   lay a formation out on.
   THE BLOCK BREAKS OUT, NOT THE ARENA. Widening the arena alone put it outside
   its own section, and `.block` is `overflow:hidden` so that its rounded
   corners clip the header's background — so the floor's left and right edges,
   which is exactly where its two panels live, were cut off. Moving the breakout up one level keeps the clip doing its
   job at the section's own, wider bounds.
   `:has()` rather than an id, so a block that gains a floor tomorrow gets the
   room without anybody remembering to grant it. The parent is centred, so 50%
   of it is the viewport's middle and the arithmetic is exact. */
@media (min-width:900px){
  .block:has(.arena){width:min(1220px,94vw); margin-inline:calc(50% - min(610px,47vw))}
}
.arc-wrap{position:relative; width:100%; height:min(66vh,620px); min-height:380px;
  border-radius:10px; overflow:hidden; border:1px solid var(--line);
  background:var(--panel3)}
.arc-wrap:focus-visible{outline:2px solid var(--accent); outline-offset:1px}
.arc-cv{display:block; width:100%; height:100%; touch-action:pan-y}
.arc-cv.arc-select{cursor:default}
.arc-cv.arc-place,.arc-cv.arc-erase,.arc-cv.arc-aim{cursor:crosshair}
.arc-cv.arc-hand{cursor:grab}
.arc-cv.arc-panning{cursor:grabbing}
.arc-cv.arc-moving{cursor:move}

/* ---- LEFT: the verb ---------------------------------------------------- */
.arc-left{position:absolute; left:8px; top:8px; bottom:8px; width:272px;
  display:flex; flex-direction:column; gap:6px; pointer-events:none}
.arc-left > *{pointer-events:auto}

.arc-rail{display:flex; gap:3px; padding:4px; align-self:flex-start;
  background:var(--surface); border:1px solid var(--line); border-radius:9px;
  box-shadow:0 2px 10px rgba(0,0,0,.14)}
.arc-tool{width:32px; height:32px; display:grid; place-items:center; border-radius:6px;
  border:1px solid transparent; background:none; color:var(--text-2); cursor:pointer}
.arc-tool:hover:not(:disabled){background:var(--panel2); color:var(--text)}
.arc-tool[aria-pressed="true"]{color:var(--accent);
  background:color-mix(in srgb,var(--accent) 15%,transparent);
  border-color:color-mix(in srgb,var(--accent) 45%,transparent)}
.arc-tool:disabled{opacity:.4; cursor:default}
.arc-tool:focus-visible{outline:2px solid var(--accent); outline-offset:1px}
.arc-tool svg{width:17px; height:17px; fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round}

/* THE BRUSH: what the place tool acts with. It is the tallest thing here and
   the only one that may scroll, because an enemy card carries a vulnerability
   column, a status-immunity list and a caveat, and all of them are worth
   reading -- the old floating card cut them off. */
/* IT HUGS ITS CONTENT. `flex:1 1 auto` made it fill the column, so a card three
   lines long sat at the top of a panel six hundred pixels tall — and the empty
   white below it read as something failing to load. It grows to what it holds
   and only scrolls past the room there is. */
.arc-brush{flex:0 1 auto; min-height:0; max-height:calc(100% - 104px); overflow:auto;
  background:var(--surface); border:1px solid var(--line); border-radius:9px;
  box-shadow:0 2px 10px rgba(0,0,0,.14)}
.arc-brush:empty{display:none}
/* AND IT WRAPS RATHER THAN SCROLLING SIDEWAYS. Every one of these is a
   `min-width:0`: a flex item's default minimum is its CONTENT, so an enemy's
   stat line — which is one long unbroken sentence — pushed the card wider than
   the column and took the panel's own edges off the screen with it. */
.arc-brush,.arc-side,.arc-side *{min-width:0}
.arc-side{display:flex; flex-direction:column; gap:6px; padding:7px; font-size:12px}
.arc-side .en-row{margin:0; display:block}
.arc-side .en-card{width:100%; padding:5px 6px; gap:7px; align-items:flex-start}
.arc-side .en-img{width:38px; height:38px; flex:0 0 auto}
.arc-side .en-txt{flex:1 1 auto; overflow-wrap:anywhere}
.arc-side .en-name{font-size:13px}
.arc-side .en-meta{font-size:10.5px; line-height:1.4; white-space:normal}
.arc-side .en-wiki{display:inline-block; margin-top:4px; font-size:11px}
.arc-fields{display:flex; flex-wrap:wrap; gap:5px 10px; align-items:center;
  font-size:11.5px}
.arc-fields label{display:flex; align-items:center; gap:4px; margin:0}
.arc-fields input[type=number]{width:70px}
/* WHAT THE CARD ABOVE REACHES. Quiet, because it is a statement of scope
   rather than a warning — nothing is wrong when it is showing. */
.arc-note{margin:0; font-size:10.5px; line-height:1.45; color:var(--muted)}

.arc-opts,.arc-chips{display:flex; gap:4px; padding:4px; align-self:flex-start;
  background:var(--surface); border:1px solid var(--line); border-radius:9px;
  box-shadow:0 2px 10px rgba(0,0,0,.14)}
.arc-chips:empty{display:none}
.arc-opt{padding:4px 9px; border-radius:6px; border:1px solid var(--line);
  background:var(--panel3); color:var(--muted); cursor:pointer; font:inherit;
  font-size:11.5px; line-height:1.2}
.arc-opt:hover:not(:disabled){color:var(--text)}
.arc-opt[aria-pressed="true"],.arc-opt.on{color:var(--accent);
  background:color-mix(in srgb,var(--accent) 14%,transparent);
  border-color:color-mix(in srgb,var(--accent) 42%,transparent)}
.arc-opt:disabled{opacity:.4; cursor:default}
.arc-opt:focus-visible{outline:2px solid var(--accent); outline-offset:1px}

/* ---- RIGHT: the noun --------------------------------------------------- */
.arc-insp{position:absolute; right:8px; top:8px; width:min(34%,238px);
  padding:8px 10px; border-radius:9px; background:var(--surface);
  border:1px solid var(--line); box-shadow:0 2px 10px rgba(0,0,0,.14);
  font-size:12px}
.ai-h{margin:0 0 6px; font-size:10.5px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--muted); font-weight:600}
/* WHO IT IS, above the geometry. The art is small on purpose — it is here to
   be recognised at a glance, not studied; the card in the left column is where
   a unit is read properly. */
.ai-who{display:flex; gap:8px; align-items:flex-start; padding-bottom:7px; margin-bottom:6px;
  border-bottom:1px solid var(--line)}
.ai-who img{width:34px; height:34px; object-fit:contain; flex:0 0 auto}
.ai-who > div{min-width:0}
.ai-who b{display:block; font-size:12.5px; line-height:1.3}
/* THE KEY TO THE FLOOR — the same hue the body is drawn in. Beside the NAME,
   because a colour with nothing to read it against is decoration. */
.ai-sw{display:inline-block; width:8px; height:8px; border-radius:2px;
  margin-right:5px; vertical-align:baseline; flex:0 0 auto}
.ai-who span{display:block; font-size:10.5px; line-height:1.45; color:var(--muted)}
.ai-row{display:flex; justify-content:space-between; gap:12px; padding:1.5px 0}
.ai-row span:first-child{color:var(--text-2)}
.ai-hint{margin:7px 0 0; font-size:11px; color:var(--muted)}

.arc-read{position:absolute; right:8px; bottom:8px; padding:5px 9px; border-radius:8px;
  background:var(--surface); border:1px solid var(--line); font-size:11.5px;
  color:var(--text-2); box-shadow:0 2px 10px rgba(0,0,0,.14)}

/* A NARROW PANEL IS NARROW WHATEVER THE VIEWPORT IS. The simulator's column can
   be a couple of hundred pixels on a wide screen, so the measurement is of the
   CONTAINER: the chrome stops floating and the three groups stack. */
@container (max-width:620px){
  .arc-wrap{height:auto; min-height:0; display:flex; flex-direction:column}
  .arc-left{position:static; width:auto; flex-direction:row; flex-wrap:wrap;
    align-items:flex-start; order:-1; padding:6px; gap:5px}
  .arc-brush{flex:1 1 100%; max-height:190px}
  .arc-insp{position:static; width:auto; order:2; border-radius:0;
    border-width:1px 0 0; box-shadow:none}
  .arc-cv{height:min(50vh,360px); flex:0 0 auto; order:1}
  .arc-read{display:none}
}

@media (max-width:640px){
  .arc-tool{width:29px; height:29px}
}

/* THE BUILD ON SCREEN. Footer weight and then some: it is for a bug report,
   not for a reader. */
.build-stamp{color:var(--dim); font-size:11px; font-variant-numeric:tabular-nums;
  user-select:all; cursor:text}

/* WHAT THE WARFRAME BRINGS — the squad's aura and the frame's archon shards.
   A LIST of rows rather than a field grid, because each row is a control with
   its own count, its own Tauforged flag and its own remove; a `1fr` grid would
   floor every track at min-content and hang the removes off a phone, which is
   `check_mobile.mjs`'s own lesson. */
.sq-h{font-size:12px; letter-spacing:.04em; text-transform:uppercase;
  color:var(--dim); margin-top:4px}
.sq-h .sim-hint{text-transform:none; letter-spacing:0}
.sq-row{display:flex; flex-wrap:wrap; align-items:center; gap:8px}
/* The dropdown is the row: it takes what is left after the small controls, and
   never less than a name's worth. */
.sq-row > .dd{flex:1 1 200px; min-width:0}
.sq-n{display:inline-flex; align-items:center; gap:4px; color:var(--dim);
  font-size:12px; white-space:nowrap}
.sq-n input{width:44px}
.sq-mute{opacity:.55}
.sq-tau{white-space:nowrap}
/* PAYS NOTHING HERE, and it reads that way — dimmed, with the reason beside it.
   Never hidden: a socket that quietly does nothing is worse than one that says
   so, which is docs/UNMODELLED.md's own rule. */
.sq-dead > .dd, .sq-dead .sq-tau{opacity:.55}
.sq-why{font-size:11px; color:var(--dim); flex:1 1 100%}
.sq-none{font-size:12px; color:var(--dim)}
.sq-add{display:flex}
.sq-add > .dd{flex:1 1 auto}

/* THE NUMBERS A FIGHT POPS. A DOM overlay over the result's arena, not paint on
   its canvas: the scene repaints on every resize and every heat change, and a
   number wants a CSS animation rather than a per-frame redraw. It never eats a
   click — the scene underneath still picks a body. */
.rp-pops{position:absolute; inset:0; pointer-events:none; overflow:hidden}
/* THE HALO IS THEMED, and it has to be: a damage-type colour is a mid-tone, so
   it needs an OUTLINE to be legible, and an outline that is dark on a dark page
   is invisible. Four shadows rather than one — a ring, not a drop — because a
   number sits on top of a body and has no side to lean away from. */
:root{--pop-halo:#fff}
:root:not([data-theme="light"]){--pop-halo:#fff}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]){--pop-halo:#000}}
:root[data-theme="dark"]{--pop-halo:#000}
.rp-pop{
  position:absolute; transform:translate(-50%,-50%);
  font-variant-numeric:tabular-nums; font-weight:800; font-size:13px;
  white-space:nowrap; color:var(--pop-dt, var(--fg));
  text-shadow:
    0 0 3px var(--pop-halo), 0 0 3px var(--pop-halo),
    1px 1px 0 var(--pop-halo), -1px 1px 0 var(--pop-halo),
    1px -1px 0 var(--pop-halo), -1px -1px 0 var(--pop-halo);
}
/* PARKED ON A FRAME, A NUMBER STAYS. Scrubbing is READING — you stopped on this
   instant to see what happened in it — so the numbers rise once and hold. Only
   PLAYBACK floats them away, which is the behaviour that makes a fight look
   like a fight. */
.rp-pop{animation:pop-rise .28s ease-out forwards}
.rp-pops.live .rp-pop{animation:pop-float 1.1s ease-out forwards}
@keyframes pop-rise{
  0%{opacity:0; transform:translate(-50%,-50%) scale(.7)}
  70%{opacity:1; transform:translate(-50%,-66%) scale(1.06)}
  100%{opacity:1; transform:translate(-50%,-62%) scale(1)}
}
@keyframes pop-float{
  0%{opacity:0; transform:translate(-50%,-50%) scale(.7)}
  12%{opacity:1; transform:translate(-50%,-60%) scale(1.08)}
  30%{transform:translate(-50%,-72%) scale(1)}
  100%{opacity:0; transform:translate(-50%,-140%) scale(.95)}
}
/* WHAT KIND OF NUMBER, at a glance — the same distinction the game draws with
   size and colour. A crit is bigger, a headcrit bigger again and gold; a status
   tick is small and takes its element's colour; a blast radial is dimmer than
   the detonation that threw it, because it is the same event seen from further
   away. */
.rp-pop.p-crit{font-size:15px}
.rp-pop.p-head{font-size:14px}
.rp-pop.p-headcrit{font-size:19px; color:var(--gold, #e8c46a)}
.rp-pop.p-status{font-size:11px; opacity:.92}
.rp-pop.p-blast{font-size:13px}
.rp-pop.p-area{font-size:11px; opacity:.8}
.rp-pop.p-field,.rp-pop.p-extra,.rp-pop.p-arcane{font-size:11px; opacity:.9}
/* …AND WHAT DID NOT FIT, said rather than swallowed. */
.rp-pop.p-more{font-size:11px; font-weight:600; color:var(--dim); opacity:.85}
/* THE SCENE HAS TO BE A POSITIONING CONTEXT for any of the above to land. */
#rp-scene{position:relative}

/* PROGRESS WHERE THE WORK IS BEING READ. The quick calc counted itself at the
   top of the page and the LIST it was ranking said nothing — and a list that
   does not move for thirty seconds is read as broken, not as busy. Same strip in every list a scan ranks. */
.scan-strip{
  position:sticky; top:0; z-index:3;
  display:flex; align-items:center; gap:8px;
  padding:5px 10px; background:var(--bg2, var(--bg));
  border-bottom:1px solid var(--line);
  font-size:11px; color:var(--dim); white-space:nowrap;
}
.scan-bar{
  flex:1 1 auto; min-width:40px; height:4px; border-radius:2px;
  background:var(--line); overflow:hidden;
}
.scan-bar>i{
  display:block; height:100%; background:var(--gold, #e8c46a);
  /* The width is set per repaint (every 250 ms while scanning), so the
     transition is what makes it read as movement rather than as a jump. */
  transition:width .25s linear;
}
.scan-txt{font-variant-numeric:tabular-nums; flex:0 0 auto}

/* THE DESKTOP UPDATE NOTICE — drawn only by the desktop shell (`mountDesktopUpdater`).
   Bottom-right rather than a full-width bar: an update is not urgent, and a
   strip across the page reads like an error. It sits under `.page-note`
   (z 9998) so a real message is never covered by a housekeeping one. */
.dtup{position:fixed;right:16px;bottom:16px;z-index:70;display:flex;align-items:center;gap:10px;
  padding:9px 10px 9px 13px;border-radius:10px;background:var(--surface);border:1px solid var(--line);
  box-shadow:0 8px 28px rgba(0,0,0,.35);font-size:13px;color:var(--text);
  max-width:min(440px,calc(100vw - 32px))}
.dtup[hidden]{display:none}
.dtup-t{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dtup-e{color:var(--critical);white-space:normal}
.dtup-b{border:1px solid var(--gold);background:transparent;color:var(--gold);border-radius:7px;
  padding:4px 11px;font:inherit;cursor:pointer;white-space:nowrap}
.dtup-b:hover{background:var(--gold);color:var(--surface)}
.dtup-x{border:0;background:transparent;color:var(--muted);font-size:17px;line-height:1;
  padding:2px 4px;cursor:pointer}
.dtup-x:hover{color:var(--text)}

/* THE DESKTOP DOWNLOAD, on its own page. Gold-outlined rather than filled: it
   is an offer, not the thing the site is for. */
.dl-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.dl-btn{border:1px solid var(--gold);color:var(--gold);border-radius:8px;
  padding:7px 16px;text-decoration:none;white-space:nowrap;font-weight:600}
.dl-btn:hover{background:var(--gold);color:var(--surface)}
/* WHERE THE FILE COMES FROM, beside the button rather than under it. This site
   does not host the executable, and a reader about to run a downloaded binary
   is entitled to see whose drive it is on BEFORE they click. Quiet by default
   and it lights up on hover, because it is an identification first and a link
   second. */
.dl-src{display:inline-flex;align-items:center;gap:5px;font-size:13px;
  color:var(--muted);text-decoration:none;white-space:nowrap}
.dl-src:hover{color:var(--text-2)}
.dl-src svg{flex:none;opacity:.85}
.dl-why{color:var(--text-2);font-size:13px;margin-top:6px}

/* /download — a reading page, so it takes the support page's measure and its
   list styling rather than growing a second set. */
.dl-page{max-width:1060px;margin:0 auto;padding:28px 18px}
.dl-page .block{max-width:760px}
.dl-offer{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin:18px 0 8px}

/* THE WHOLE FIGHT — a reading surface first, so it is dense and quiet. Folded
   shut by default; the ordinary reader is not asked to care. */
.whole-fight{grid-column:1/-1;margin-top:8px;border-top:1px solid var(--line);padding-top:6px}
.whole-fight > summary{cursor:pointer;font-size:11.5px;color:var(--muted);list-style:none;padding:2px 0}
.whole-fight > summary::-webkit-details-marker{display:none}
.whole-fight > summary::before{content:"▸ ";color:var(--muted)}
.whole-fight[open] > summary::before{content:"▾ "}
.whole-fight > summary:hover{color:var(--text)}
.wf-group{margin:6px 0 10px}
.wf-g-h{font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin-bottom:3px}
.wf-row{display:grid;grid-template-columns:minmax(0,11em) minmax(0,1fr) auto;gap:4px 10px;
  align-items:center;font-size:11.5px;padding:2px 0;border-bottom:1px solid rgba(128,128,128,.12)}
.wf-row code{color:var(--text-2);font-size:11px;overflow:hidden;text-overflow:ellipsis}
.wf-val{font-variant-numeric:tabular-nums;min-width:0;overflow:hidden;text-overflow:ellipsis}
.wf-row.forced .wf-val b{color:var(--gold)}
.wf-was{color:var(--muted);font-size:10.5px;margin-left:6px}
/* The REASON spans the row: it is a sentence, and squeezing it into a column
   would make the one thing a forced row exists to say the hardest to read. */
.wf-why{grid-column:1/-1;font-size:10.5px;color:var(--muted);line-height:1.35;padding-bottom:2px}
.wf-absent{color:var(--muted)}
.wf-ctl input[type=number]{width:6.5em}
/* THE HOUSE RULES: one column per weapon class, so a reader can see at a glance
   that this fight has an opinion about Arch-Guns while standing on a Burston.
   `auto-fit` rather than a fixed count — a phone gets one column per row and
   the grid still fits, which is `check_mobile`'s rule. */
.wf-hr{grid-template-columns:minmax(0,11em) minmax(0,1fr);align-items:start}
.hr-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,10.5em),1fr));
  gap:6px 10px;min-width:0}
.hr-col{min-width:0}
.hr-h{font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.hr-col.here .hr-h{color:var(--gold)}
.hr-col .check{display:flex;align-items:center;gap:4px;font-size:11px;min-width:0}
.hr-col .check code{font-size:10.5px}
/* A box that is writing a RULE rather than the fight's own field says so
   without a legend: the reader is looking at a control whose scope is the whole
   class, which is not what any other checkbox on this page means. */
.check.ruled{color:var(--gold)}

/* ---- THE COMBAT RECORD -------------------------------------------------
   One row per number the game pops. It is the WIDEST thing on the panel by
   design — every column is a fact a reader checks a number against — so it
   scrolls inside itself and the page never scrolls sideways for it. */
/* THE PEEK: the panel's own narrow view of the record. ONE renderer, two
   widths — the columns a single column has no room for are dropped here rather
   than in a second markup path, which is what keeps the two from drifting. */
.rec-peek{border:1px solid var(--line);border-radius:9px;overflow:hidden;margin:2px 0 6px}
.rec-peek table.rec-t{min-width:0;width:100%}
.rec-peek .rec-proc,.rec-peek .rec-wep,.rec-peek .rec-buff,.rec-peek .rec-dbf,
.rec-peek .rec-state{display:none}
.rec-peek thead th{font-size:10px}
.rec-peek td{padding:5px 8px}
.rec-peek .rec-calc{min-width:0}
.rec-peek .lg-mit,.rec-peek .lg-exact{display:none}
.rec-peek tr:last-child td{border-bottom:0}
.rec-peek-n{font-size:11px;color:var(--muted);margin:0 0 8px}
.rec-idle{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:6px 0}
.rec-tools{display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding:2px 0 8px}
.rec-tools .tlabel{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.rec-tools .pchip .ct{color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums}
.rec-sep{width:1px;height:18px;background:var(--line);margin:0 3px}
.rec-count{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums;margin-bottom:6px}
/* WHICH SCREENFUL — drawn above the table and below it, because a reader who
   has scrolled five hundred rows is the one who wants the next five hundred. */
.rec-pager{display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding:4px 0;
  font-variant-numeric:tabular-nums}
.rec-pager .tlabel{font-size:11px;color:var(--muted);letter-spacing:.03em}
.rec-pager .pchip[disabled]{opacity:.35;cursor:default}
/* THE RECORD IN ITS OWN WINDOW. The child document is this stylesheet over one
   host element, so it needs only the page margin the app's own layout supplies
   here — and the table gets the whole viewport to be long in. */
/* THE RECORD'S OWN WINDOW. It is a page of this site and is dressed like one:
   the topbar's wordmark over a heading that says which fight the rows are
   about, and the table given the whole width — which is the reason the window
   exists. */
.recwin-top{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  padding:12px 16px;border-bottom:1px solid var(--line);background:var(--surface);
  position:sticky;top:0;z-index:20}
.recwin-title{font-size:13px;font-weight:700;letter-spacing:.02em}
.recwin-sub{font-size:12px;color:var(--muted);margin-left:auto;
  font-variant-numeric:tabular-nums}
.recwin-top .ghost-btn{height:28px;padding:0 9px;display:inline-flex;
  align-items:center;justify-content:center;align-self:center}
.recwin{padding:14px 16px;max-width:none}
/* THE TABLE GETS THE REST OF THE WINDOW. Its own header is sticky, so growing
   this does not cost the reader the column names. 250px is the chrome above it
   — the window's heading, the tools row and the count. */
.recwin .rec-scroll{max-height:calc(100vh - 250px)}
/* THE ONE BLOCK THAT NEEDS THE SCREEN.
   The record is a ten-column ledger and the column it exists for — where the
   number comes from — is the widest of them, so inside the page's own reading
   column it is the one always half off the right edge. Every other block on
   this panel is a summary and belongs at reading width; this one is a table
   somebody is auditing, and it gets the window. Below 900px it goes back to
   the column, and below 720px a row becomes a card. */
@media (min-width:900px){
  .rec-scroll{width:calc(100vw - 56px);max-width:calc(100vw - 56px);
    margin-left:calc(50% - 50vw + 28px)}
  .rec-tools,.rec-count{width:calc(100vw - 56px);margin-left:calc(50% - 50vw + 28px)}
}
.rec-scroll{overflow-x:auto;max-height:520px;overflow-y:auto;
  border:1px solid var(--line);border-radius:10px}
table.rec-t{width:100%;min-width:1080px;border-collapse:separate;border-spacing:0;font-size:12px}
.rec-t thead th{position:sticky;top:0;z-index:2;background:var(--panel3);text-align:left;
  font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700;
  padding:6px 8px;border-bottom:1px solid var(--line);white-space:nowrap}
.rec-t thead th.num{text-align:right}
.rec-t td{padding:6px 8px;border-bottom:1px solid var(--line);vertical-align:top}
.rec-t tbody tr:hover td{background:var(--panel2)}
.rec-t td.num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}
.rec-t td.rec-t{width:72px;text-align:right;font-variant-numeric:tabular-nums;
  color:var(--text-2);white-space:nowrap;border-left:3px solid transparent}
.rec-t .z{color:var(--muted)}
/* WHICH POOL THE NUMBER CAME OUT OF, as a stripe — a hit on a shielded body
   pops two rows and the eye has to pair them at a glance. */
tr.rec-shield td.rec-t{border-left-color:var(--s1)}
tr.rec-health td.rec-t{border-left-color:var(--good)}
tr.rec-overguard td.rec-t{border-left-color:var(--gold)}
tr.rec-evt td{background:color-mix(in srgb,var(--accent) 6%,transparent);font-size:11.5px}
tr.rec-evt td.rec-t{border-left-color:var(--accent)}
tr.rec-reload_start td,tr.rec-reload_end td{background:color-mix(in srgb,var(--s1) 8%,transparent)}
tr.rec-transform_start td,tr.rec-transform_end td{background:color-mix(in srgb,var(--gold) 10%,transparent)}
.rec-cause{display:block;font-size:10px;color:var(--muted)}
/* ---- THE RECORD ON A PHONE -------------------------------------------
   A ten-column ledger with a 1080px minimum cannot be READ through a 326px
   window. It was technically there — the block drew, the button worked, the
   table scrolled sideways — and the column the whole panel exists for, the one
   that says where the number came from, sat furthest off the right edge, so a
   reader on a phone could see a damage figure and never its arithmetic.

   So on a narrow screen a ROW BECOMES A CARD: the header row goes away, each
   cell stacks with its own heading (`data-label`, filled by `recordRow`), and
   nothing scrolls sideways. It is taller per row, which is the trade a phone
   forces — and the filter chips above are what a reader shortens the list
   with. */
@media (max-width:720px){
  .rec-scroll{overflow-x:visible;max-height:none}
  table.rec-t{min-width:0;display:block}
  .rec-t thead{display:none}
  .rec-t tbody{display:block}
  .rec-t tr{display:block;padding:6px 0 8px;border-bottom:2px solid var(--line)}
  .rec-t td{display:flex;gap:8px;align-items:baseline;border-bottom:0;
    padding:2px 8px;width:auto !important;min-width:0 !important}
  /* A CELL WITH NOTHING IN IT IS NOT A LINE. On a desktop an empty cell is an
     empty column; stacked, it is a heading followed by a dash on every row. */
  .rec-t td:empty{display:none}
  .rec-t td::before{content:attr(data-label);flex:0 0 5.5em;color:var(--muted);
    font-size:10px;text-transform:uppercase;letter-spacing:.04em;line-height:1.5}
  .rec-t td:not([data-label])::before{content:none}
  /* THE TIME IS THE CARD'S TITLE rather than one more labelled line. */
  .rec-t td.rec-t{width:auto;text-align:left;border-left:4px solid transparent;
    font-weight:700;font-size:12.5px}
  .rec-t td.num{text-align:left}
  .rec-t td.num b{font-size:15px}
  .rec-calc{min-width:0}
  .rec-buff,.rec-dbf,.rec-wep{width:auto}
  .rec-t td.rec-calc{flex-wrap:wrap}
  .rec-t td.rec-calc::before{flex-basis:100%}
  /* An event row spans columns on a desktop; stacked, a colspan is just a
     block and the empty ones are gone by the rule above. */
  tr.rec-evt td[colspan],tr.rec-miss td[colspan]{display:block}
}
tr.rec-miss td{background:color-mix(in srgb,var(--critical) 8%,transparent);font-size:11.5px}
tr.rec-miss td.rec-t{border-left-color:var(--critical)}
.rec-pool{display:block;font-size:10px;color:var(--muted);font-weight:400}
.rec-crit{display:inline-flex;align-items:center;height:15px;padding:0 4px;border-radius:3px;
  font-size:9.5px;font-weight:700;background:color-mix(in srgb,var(--s4) 26%,transparent);color:var(--s4)}
.rec-head{color:var(--s1);font-weight:600}
/* Where the number comes from: base, the factors that MOVED, the two totals. */
.rec-calc{min-width:440px}
/* ---- THE LEDGER, LAYER BY LAYER ------------------------------------------
   Three shapes, and the shape is the information: a BRACKET lists its terms, a
   SNAP shows its grid, and only a MUL gets a multiplication sign. A quotient
   has no shape here, which is what stops `×5.706 Condition Overload` — the
   base bracket divided by itself — from coming back. */
/* TWO COLUMNS, NOT THREE. A lane of its own on the right puts the running
   total at the edge a 1080px table is cut off at — the one number a reader
   checks against the next layer's start, off screen. It rides in the body and
   wraps with it. */
.lg{display:grid;grid-template-columns:6.5em minmax(0,1fr);gap:2px 10px;
  align-items:baseline;padding:3px 0;border-top:1px solid var(--line)}
.lg:first-child{border-top:0}
.lg-lbl{font-size:10.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;
  white-space:nowrap;min-width:6.5em}
.lg-body{display:flex;flex-wrap:wrap;gap:3px 8px;align-items:baseline;min-width:0}
.lg-out{font-variant-numeric:tabular-nums;font-weight:600;color:var(--text-2);
  white-space:nowrap;padding:0 5px;border-radius:4px;
  background:color-mix(in srgb,var(--good) 14%,transparent);color:var(--good-text)}
.lg-b .lg-lbl{color:var(--accent)}
.lg-b{border-left:2px solid color-mix(in srgb,var(--accent) 40%,transparent);padding-left:8px}
/* A SUM OF WHOLE NUMBERS. Marked like a bracket because it is the same kind of
   claim — this number is built from these — and muted, because the part it
   exists to show is a fraction of a point beside a seed in the hundreds. */
.lg-s .lg-lbl{color:var(--accent)}
.lg-s{border-left:2px solid color-mix(in srgb,var(--accent) 25%,transparent);padding-left:8px}
.lg-term{display:inline-flex;align-items:baseline;gap:3px;font-variant-numeric:tabular-nums}
.lg-term .lg-op{font-style:normal;color:var(--muted)}
.lg-term b{font-weight:400;color:var(--muted);font-size:10.5px}
.lg-term em{font-style:normal;color:var(--muted);font-size:10px;opacity:.75}
.lg-sum{font-weight:600;color:var(--accent);font-variant-numeric:tabular-nums}
.lg-x{font-style:normal;color:var(--accent);font-weight:600;margin-right:2px}
.lg-m .lg-lbl{font-size:12px;color:var(--text);text-transform:none;letter-spacing:0;
  font-variant-numeric:tabular-nums;min-width:4.5em}
.lg-m .lg-body b{font-weight:400;color:var(--muted);font-size:10.5px}
.lg-of{color:var(--muted);font-size:10px;font-variant-numeric:tabular-nums}
.lg-scale{color:var(--muted);font-size:10px;white-space:nowrap}
/* THE SNAP SPANS THE WHOLE CELL. It is a seven-column table and it was living
   in the layer's 1fr body lane, which a grid is entitled to squeeze — so the
   before and after columns, which are the mechanic, were the ones clipped. */
.lg-q{display:block}
.lg-q .lg-lbl{display:inline-block;min-width:6.5em}
.lg-q .lg-body{display:block;margin-top:2px}
table.lg-snap{border-collapse:collapse;font-size:10.5px;font-variant-numeric:tabular-nums;
  white-space:nowrap}
table.lg-snap td{padding:0 7px 0 0;color:var(--muted);white-space:nowrap}
table.lg-snap td.num{text-align:right;color:var(--text-2)}
table.lg-snap td.sn{color:var(--accent);font-weight:600}
table.lg-snap td.pc{color:var(--muted);padding-right:8px}
table.lg-snap td.to{color:var(--text)}
table.lg-snap td.ar{color:var(--line);padding:0 2px}
.lg-base .lg-out,.lg-base .lg-lbl{color:var(--text)}
.lg-mit{display:flex;flex-wrap:wrap;gap:3px;padding:4px 0 2px;border-top:1px solid var(--line)}
.lg-end{border-top:1px solid var(--line)}
.lg-end .lg-out{color:var(--good-text);font-size:14px}
.lg-exact{color:var(--muted);font-size:10px;font-variant-numeric:tabular-nums}
.rec-b0,.rec-mid,.rec-eq{display:inline-block;padding:1px 5px;border-radius:4px;margin-right:3px;
  font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap}
.rec-b0{background:color-mix(in srgb,var(--text-2) 15%,transparent)}
.rec-mid{background:color-mix(in srgb,var(--accent) 15%,transparent);color:var(--accent)}
.rec-eq{background:color-mix(in srgb,var(--good) 18%,transparent);color:var(--good-text)}
.rec-f{display:inline-flex;align-items:baseline;gap:3px;padding:1px 5px;border-radius:4px;
  margin-right:3px;background:var(--panel2);border:1px solid var(--line);white-space:nowrap;
  font-variant-numeric:tabular-nums}
.rec-f i{font-style:normal;color:var(--muted);font-size:10px}
.rec-b0.sub{background:transparent;border:1px dashed var(--line);font-weight:600}
.rec-b0 i{font-style:normal;color:var(--muted);font-size:10px;margin-left:4px;font-weight:400}
.rec-f.base{border-style:dashed}
.rec-pel{display:inline-block;font-size:10px;color:var(--muted);margin-left:4px;font-variant-numeric:tabular-nums}
.rec-half{display:block;font-size:10px;color:var(--text-2);font-weight:600}
.rec-stk{display:flex;flex-wrap:wrap;gap:3px}
.rec-s em{font-style:normal;opacity:.62;font-size:9.5px;margin-left:1px}
.rec-s{display:inline-flex;align-items:baseline;gap:2px;padding:0 5px;height:16px;line-height:16px;
  border-radius:3px;font-size:10px;font-weight:600;font-variant-numeric:tabular-nums}
.rec-s.up{background:color-mix(in srgb,var(--gold) 22%,transparent);color:var(--gold)}
.rec-s.on{background:color-mix(in srgb,var(--s7) 20%,transparent);color:var(--s7)}
/* A PROC AND A TRIGGER SHARE A COLUMN AND NOT A COLOUR: one lands on the
   target, one lands on you, and the two state columns they explain are
   coloured the same way. */
.rec-p.on{background:color-mix(in srgb,var(--s7) 20%,transparent);color:var(--s7)}
.rec-p.up{background:color-mix(in srgb,var(--gold) 24%,transparent);color:var(--gold)}
.rec-p{display:inline-flex;align-items:center;height:16px;padding:0 5px;border-radius:3px;
  font-size:10px;font-weight:600;margin:0 2px 2px 0;
  background:color-mix(in srgb,var(--s8) 20%,transparent);color:var(--s8)}
.rec-buff,.rec-dbf{width:140px}
.rec-wep{width:110px}
/* NO COLUMN IS SQUEEZED INTO A STACK OF LETTERS. `.rec-calc` asks for 340px
   inside a 1080px table, and the two narrow columns beside it lost so much
   room that a two-character Chinese label wrapped one character per line —
   "头 部" over two rows and the proc chips turned on their side (seen on the
   Chinese page). A minimum keeps them readable; the table already
   scrolls sideways inside its own container, which is where the extra width
   comes from. */
.rec-t td:nth-child(3){min-width:66px;white-space:nowrap}
.rec-proc{min-width:86px;vertical-align:top}
.rec-p{white-space:nowrap}
.rec-t td.num{min-width:104px}
/* THE WEAPON COLUMN SETS THE ROW HEIGHT, so it decides how much of the ledger
   fits on a screen. Five facts stacked one per line made every row 129px tall
   for 40px of content — a 20,000-row stream is then two million pixels of
   scroll. They are short, so they flow. */
.rec-wep{width:168px}
.rec-mag{display:inline-block;margin:0 6px 0 0}
.rec-gauge{width:56px;vertical-align:middle;display:inline-block;margin:0 6px 1px 0}
.rec-f.mit{border-color:color-mix(in srgb,var(--critical) 40%,transparent);
  background:color-mix(in srgb,var(--critical) 9%,transparent)}
/* THE FACTORS THAT DID NOTHING, as a count you can hover. They are noise on a
   row and their NAMES are a clue — "the Bane is there and it paid ×1.00" is
   why a build is not working. */
.rec-inert{display:inline-block;font-size:10px;color:var(--muted);border-bottom:1px dotted var(--muted);
  cursor:help;margin-left:2px}
.rec-form{display:inline-flex;align-items:center;height:15px;padding:0 5px;border-radius:3px;
  font-size:9.5px;font-weight:700;line-height:1}
.rec-form.base{background:color-mix(in srgb,var(--muted) 22%,transparent);color:var(--text-2)}
.rec-form.inc{background:color-mix(in srgb,var(--gold) 26%,transparent);color:var(--gold)}
.rec-gauge{height:3px;border-radius:2px;background:var(--line);overflow:hidden}
.rec-gauge>i{display:block;height:100%;background:var(--gold);border-radius:2px}
.rec-mag.firing{color:var(--text)}
.rec-mag.idle{opacity:.62}
.rec-mag{display:block;font-size:10px;color:var(--muted);font-variant-numeric:tabular-nums;margin-top:2px}
.rec-state{width:180px}
.rec-state span{display:block;font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}
.rec-state i{font-style:normal;color:var(--muted);font-size:10px;margin-right:4px}
/* `.rec-proc` IS A CELL RULE, not a chip rule: as a chip rule on the `<td>`,
   every row with no proc draws an empty coloured 16px box where its procs
   would have been, and every row with one draws the chip inside a second box
   the same colour. The chip is `.rec-p`; the CELL is this, and it is a width
   and nothing else. */
.rec-org{display:inline-flex;align-items:center;height:17px;padding:0 6px;border-radius:4px;
  font-size:10.5px;font-weight:700;line-height:1;white-space:nowrap;
  background:color-mix(in srgb,var(--text-2) 13%,transparent);color:var(--text-2)}
.rec-o-multishot{background:color-mix(in srgb,var(--s5) 20%,transparent);color:var(--s5)}
.rec-o-punch_through{background:color-mix(in srgb,var(--s1) 18%,transparent);color:var(--s1)}
.rec-o-status{background:color-mix(in srgb,var(--s7) 18%,transparent);color:var(--s7)}
.rec-o-chain,.rec-o-splash,.rec-o-radial{background:color-mix(in srgb,var(--s3) 18%,transparent);color:var(--s3)}
/* The shield-gate window, which nothing this app fires takes — drawn so the
   claim can be checked the day melee lands (MEASUREMENTS M61). */
.rec-gate{color:var(--s1)}

/* THE CALCULATOR'S OWN STATUS, bottom right and out of the way. It is a TAB
   until it is opened: the reader wants it in two moments — while a scan runs
   and after one that failed — and furniture the rest of the time is what makes
   a warning invisible when it finally matters. */
.calc-status{position:fixed;right:12px;bottom:12px;z-index:60;font-size:12px;
  display:flex;flex-direction:column;align-items:flex-end;gap:0}
.calc-status .cs-tab{font:inherit;font-size:12px;padding:5px 10px;cursor:pointer;
  border:1px solid var(--line);border-radius:8px;background:var(--panel2);color:var(--text-2)}
.calc-status .cs-tab:hover{border-color:var(--accent)}
/* A LOSS IS GOLD, NOT RED. It is not an error — the pool rebuilds on the next
   question — it is a fact the reader could not previously see at all. */
.calc-status.bad .cs-tab{border-color:var(--gold);color:var(--gold)}
.calc-status .cs-lost{color:var(--gold);font-variant-numeric:tabular-nums}
.calc-status.open .cs-tab{border-bottom-left-radius:0;border-bottom-right-radius:0}
.calc-status .cs-body{width:min(280px,80vw);padding:8px 10px;background:var(--panel2);
  border:1px solid var(--line);border-top:none;border-radius:0 0 8px 8px;
  display:flex;flex-direction:column;gap:5px}
.calc-status .cs-row{display:flex;justify-content:space-between;gap:10px}
.calc-status .cs-row span{color:var(--text-2)}
.calc-status .cs-row b{color:var(--text);font-weight:600;text-align:right;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:170px}
.calc-status .cs-why{color:var(--gold);line-height:1.35}

/* ---- THE JUMP MENU ---------------------------------------------------
   A floating index of the sections on the page. It is a GRIP until it is
   opened, like the status tab above: the reader wants it when they are looking
   for something, and furniture the rest of the time is what makes a page feel
   crowded. It DRAGS, so whichever corner is free on this window is where it
   can live; `left`/`top` are written by `renderJump` and clamped to the
   viewport on every resize, because a remembered position on a wide monitor is
   off-screen on a laptop. */
/* BELOW THE TOPBAR'S OWN PANELS (z 60): a menu the reader parked must never
   cover the dropdown they just opened. Shut it is a pill naming where you are;
   open it is a card whose whole header is the handle. */
.jump{position:fixed;z-index:55;font-size:12px}
.jump-grip{display:flex;align-items:center;gap:7px;font:inherit;font-size:12px;line-height:1;
  padding:6px 12px 6px 8px;cursor:grab;touch-action:none;max-width:min(230px,calc(100vw - 24px));
  border:1px solid var(--line);border-radius:999px;color:var(--text-2);
  background:color-mix(in srgb,var(--panel2) 88%,transparent);backdrop-filter:blur(8px);
  box-shadow:0 4px 16px rgba(0,0,0,.22)}
.jump-grip:hover{border-color:var(--accent);color:var(--text)}
.jg-h{color:var(--muted);font-size:14px;line-height:1;user-select:none}
.jg-i{font-size:13px}
.jg-n{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}
.jg-n:empty{display:none}
.jump.dragging .jump-grip,.jump.dragging .jump-head{cursor:grabbing}
.jump.open .jump-grip{display:none}
.jump-panel{display:none;flex-direction:column;width:min(260px,calc(100vw - 24px));
  border:1px solid var(--line);border-radius:12px;overflow:hidden;
  background:color-mix(in srgb,var(--panel2) 92%,transparent);backdrop-filter:blur(10px);
  box-shadow:0 12px 36px rgba(0,0,0,.32)}
.jump.open .jump-panel{display:flex}
.jump-head{display:flex;align-items:center;gap:8px;padding:7px 8px 7px 10px;cursor:grab;
  user-select:none;touch-action:none;border-bottom:1px solid var(--line);background:var(--panel3)}
.jh-t{flex:1 1 auto;font-weight:600;color:var(--text)}
.jump-x{font:inherit;font-size:12px;line-height:1;padding:4px 6px;border:0;border-radius:6px;
  background:none;color:var(--muted);cursor:pointer}
.jump-x:hover{background:var(--surface);color:var(--text)}
.jump-body{max-height:min(62vh,520px);overflow-y:auto;padding:8px}
.jump-mods{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px}
.jump-mod{font-size:11px;padding:3px 8px;border-radius:999px;text-decoration:none;
  border:1px solid var(--line);background:var(--surface);color:var(--text-2)}
.jump-mod:hover{border-color:var(--accent);color:var(--text)}
.jump-mod.sel{color:var(--text);border-color:var(--accent)}
/* One row per fold on the page. A BLOCK is the outdented row and its sections
   are indented under it, which is the page's own shape said in one column. */
.jump-row{display:flex;align-items:center;gap:6px;width:100%;font:inherit;font-size:12px;
  text-align:left;padding:4px 6px;border:0;border-radius:6px;background:none;
  color:var(--text-2);cursor:pointer}
.jump-row:hover{background:var(--surface);color:var(--text)}
.jump-row.blk{font-weight:600;color:var(--text);margin-top:3px}
.jump-row.sub{padding-left:18px}
.jump-row.deep{padding-left:30px}
.jump-row .jr-n{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* THE CARET IS THE FOLD CONTROL AND THE ROW IS THE JUMP: a click on the caret
   shuts or opens that section in place and moves nothing. */
.jump-row .jr-c{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:20px;height:20px;margin:-2px -2px -2px 0;font-size:13px;line-height:1;color:var(--text-2);
  border:1px solid var(--line);border-radius:5px;background:var(--surface);cursor:pointer}
.jump-row .jr-c:hover{border-color:var(--accent);color:var(--text)}
.jump-row.is-shut{color:var(--muted)}
.jump-row.here{color:var(--text);background:color-mix(in srgb,var(--accent) 13%,transparent);
  box-shadow:inset 2px 0 0 var(--accent)}
.jump-foot{display:flex;gap:5px;margin-top:7px;padding-top:6px;border-top:1px solid var(--line)}
.jump-foot .ghost-btn{flex:1 1 0;font-size:11px;padding:3px 6px}

/* THE WARFRAME BUILDER. The weapon builder's slots, rows and dropdowns, and only
   what a frame has that a weapon does not: five shard sockets and ability
   cards. The aura sits where a weapon's stance does. */
.wf-caps{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 12px}
.wf-capbox{flex:1 1 180px;min-width:0;border:1px solid var(--line);border-radius:10px;padding:6px 10px;background:var(--surface)}
.wf-capbox.off{opacity:.55}
.wf-capbox .wf-caph{font-size:12px;font-weight:700;display:flex;align-items:center;gap:6px}
.wf-capbox .wf-capsrc{font-size:11px;color:var(--text-2);line-height:1.4}
.wf-cap{display:inline-flex;align-items:center;height:18px;padding:0 6px;border-radius:999px;font-size:10px;font-weight:600;
  border:1px solid var(--line);color:var(--text)}
.wf-cap.invulnerable,.wf-capbox.invulnerable .wf-caph{color:#e8a33d}
.wf-cap.status_cleanse,.wf-capbox.status_cleanse .wf-caph{color:#2fb36d}
.wf-cap.damage_cap,.wf-capbox.damage_cap .wf-caph{color:#3d8bfd}
.wf-cap.status_immunity,.wf-capbox.status_immunity .wf-caph{color:#9b59d0}
.wf-gate{border:1px solid var(--line);border-radius:10px;padding:8px 11px;background:var(--surface);margin:0 0 12px}
.wf-gate .wf-caph{font-size:12px;font-weight:700;margin-bottom:3px}
.wf-gate .wf-capsrc{font-size:11.5px;color:var(--text-2);line-height:1.5}
.wf-gate table{border-collapse:collapse;font-size:11.5px;margin-top:5px;width:100%}
.wf-gate td,.wf-gate th{padding:3px 6px;border-top:1px solid var(--line);text-align:left;font-variant-numeric:tabular-nums}
.wf-gate th{color:var(--muted);font-weight:600}
.wf-gate .ok{color:var(--good-text)}
.wf-gate .warn{color:var(--gold)}
.op-schools{display:flex;flex-wrap:wrap;gap:6px}
.op-school{font:inherit;font-size:13px;padding:5px 12px;border:1px solid var(--line);border-radius:8px;background:var(--panel2);color:var(--text);cursor:pointer}
.op-school.sel{border-color:var(--accent);color:var(--accent);font-weight:700}
.op-nodes{display:flex;flex-direction:column;gap:8px}
.op-node{border:1px solid var(--line);border-radius:10px;padding:7px 10px;background:var(--panel2);opacity:.65}
.op-node.on{opacity:1;border-left:3px solid var(--accent)}
/* A WAYBOUND IS NOT A CHOICE: always on, and no control beside it. */
.op-node.wb{opacity:1;border-left:3px solid var(--line)}
.op-node .mn{font-size:13px;font-weight:600}
.op-node .me,.wf-operator .me{font-size:12px;color:var(--text-2);line-height:1.45}
.op-when{font-size:11px;color:var(--muted);margin-top:4px}
.op-when label{display:inline-flex;align-items:center;gap:5px;cursor:pointer}
.op-when input{margin:0;flex:none}
.wf-operator{display:flex;flex-direction:column;gap:6px}
.wf-operator .wf-op-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.op-artifact{display:flex;flex-direction:column;gap:8px}
.op-artifact-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.op-artifact-head img{width:44px;height:44px;object-fit:contain}
.op-artifact-head .mn{font-size:14px;font-weight:700}
#wf-aura-block{margin-bottom:10px}
#wf-aura-block .exlabel{margin-top:0}
.wf-shards{display:flex;flex-direction:column;gap:6px}
.wf-shard{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.wf-swatch{width:12px;height:12px;border-radius:3px;border:1px solid var(--line);flex:none}
.wielder-detail{margin-top:10px}
.wld-pane{display:flex;flex-direction:column;gap:6px;min-width:0}
.wld-head{display:flex;align-items:center;justify-content:space-between;gap:8px}
iframe.wld-frame{width:100%;height:480px;border:1px solid var(--line);border-radius:8px;background:var(--surface)}
/* A PAGE FRAMED BY A WEAPON'S WIELDER: the shell's chrome is the outer page's. */
.embed .topbar,.embed .footer,.embed .jump,.embed .nona-fab,.embed .nona{display:none!important}
.wf-tau{display:inline-flex;align-items:center;gap:4px;font-size:12px;color:var(--text-2)}
.wf-helminth{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:10px}
.wf-hl{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.wf-abilities{display:flex;flex-direction:column;gap:10px}
.wf-ab{border:1px solid var(--line);border-radius:10px;padding:9px 11px;background:var(--panel2)}
.wf-ab.infused{border-color:color-mix(in srgb,var(--gold) 55%,var(--line))}
.wf-ab-h{display:flex;align-items:center;gap:9px}
.wf-key{width:19px;height:19px;border-radius:50%;background:var(--plane);border:1px solid var(--line);
  font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;flex:none}
.wf-ab-icon{width:34px;height:34px;border-radius:50%;padding:5px;background:#1c2431;flex:none;object-fit:contain}
.wf-ab .mn{font-size:13px;font-weight:600}
.wf-costs{display:flex;gap:10px;flex-wrap:wrap;font-size:12px;color:var(--text-2);margin-top:2px}
.wf-costs .sbase{color:var(--muted);text-decoration:line-through}
.wf-ab-desc{font-size:12px;color:var(--text-2);line-height:1.45;margin:6px 0}
.wf-ab-stats{grid-template-columns:minmax(0,1fr)}
.wf-ab-stats .sbase{color:var(--muted);font-weight:400}
.wf-ab-stats .wf-der .k{color:var(--gold)}
.wf-scale{font-size:9px;letter-spacing:.05em;color:var(--muted);border:1px solid var(--line);border-radius:4px;padding:0 3px}
.wf-ab-none{font-size:11px;color:var(--muted)}
.wf-adm{font-size:11px;color:var(--text-2)}
.wf-adm.inert{color:var(--gold)}

/* NONA (九九), the in-page agent: a button in the corner and a panel beside the
   page, never over the build she is changing — the reader watches both. */
.nona-fab{position:fixed;right:18px;bottom:calc(18px + env(safe-area-inset-bottom,0px));z-index:60;height:44px;min-width:44px;padding:0 16px;border-radius:22px;border:none;background:var(--accent);color:#fff;font:inherit;font-weight:700;font-size:14px;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.18)}
.nona{position:fixed;top:0;right:0;bottom:0;z-index:61;width:min(400px,100vw);display:flex;flex-direction:column;background:var(--surface);border-left:1px solid var(--line);box-shadow:-6px 0 18px rgba(0,0,0,.12);padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}
.nona-head{display:flex;align-items:center;gap:6px;padding:10px 12px;border-bottom:1px solid var(--line)}
.nona-name{font-weight:700;font-size:15px;margin-right:auto}
.nona-chat{flex:1;display:flex;flex-direction:column;min-height:0}
.nona-log{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px}
.nona-msg{font-size:13px;line-height:1.5;max-width:92%;word-wrap:break-word}
.nona-msg.user{align-self:flex-end;background:var(--accent);color:#fff;border-radius:12px 12px 2px 12px;padding:7px 11px;white-space:pre-wrap}
.nona-msg.assistant{align-self:flex-start;background:var(--panel2);border-radius:12px 12px 12px 2px;padding:7px 11px}
.nona-msg.assistant p{margin:0 0 6px}.nona-msg.assistant p:last-child{margin:0}
.nona-msg.assistant ul{margin:0 0 6px;padding-left:18px}
.nona-msg.assistant code{font-size:12px;background:var(--panel3);padding:0 3px;border-radius:3px}
.nona-msg.tool{align-self:flex-start;font-family:ui-monospace,monospace;font-size:11px;color:var(--muted);padding-left:4px}
.nona-msg.tool::before{content:"· "}
.nona-msg.tool.ok::before{content:"✓ ";color:var(--good)}
.nona-msg.tool.no::before{content:"✕ ";color:var(--critical)}
.nona-msg.note{align-self:center;font-size:11px;color:var(--text-2)}
.nona-msg.error{align-self:stretch;font-size:12px;color:var(--critical);border:1px solid var(--critical);border-radius:8px;padding:6px 9px}
.nona-foot{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--line);align-items:flex-end}
.nona-foot textarea{flex:1;resize:none;font:inherit;font-size:13px;padding:8px;border:1px solid var(--line);border-radius:8px;background:var(--plane);color:var(--text)}
.nona-foot .run-btn{margin:0;width:auto;padding:9px 14px;font-size:13px}
.nona-foot .run-btn.busy{background:var(--critical)}
.nona-settings{padding:14px 12px;display:flex;flex-direction:column;gap:10px;overflow-y:auto}
.nona-settings label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--text-2)}
.nona-settings input,.nona-settings select{font:inherit;font-size:13px;padding:7px 8px;border:1px solid var(--line);border-radius:8px;background:var(--plane);color:var(--text)}
.nona-fine{font-size:11px;color:var(--muted);margin:0}
.nona-settings .run-btn{margin-top:4px}
/* The page's own dropdown opens ABOVE the panel it was opened from. */
.nona-open .popover{z-index:62}
.nona-presets{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.nona-lbl{font-size:12px;color:var(--text-2);width:100%}
.nona-detect{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.nona-status{font-size:12px;color:var(--muted)}
.nona-status.good{color:var(--good-text)}
.nona-status.bad{color:var(--critical)}
.nona-settings .dd{width:100%}
.nona-settings .run-btn:disabled{opacity:.5;cursor:not-allowed}
.nona-convs{display:flex;gap:6px;align-items:center;padding:6px 12px;border-bottom:1px solid var(--line)}
.nona-convs .dd{flex:1;min-width:0}
.nona-msg.usage{align-self:flex-start;font-size:10.5px;color:var(--muted);margin-top:-4px;padding-left:4px}
.nona-foot-note{font-size:10.5px;color:var(--muted);padding:0 12px 8px}
.nona-unmeasured{text-decoration:underline dotted var(--gold);text-underline-offset:3px;cursor:help}
.nona-msg.card{align-self:stretch;border:1px solid var(--line);border-radius:10px;padding:8px 10px;background:var(--panel3);font-size:12.5px}
.nona-card-h{margin-bottom:4px;color:var(--text-2)}
.nona-diff{font-size:12px;margin:2px 0}
.nona-diff.add{color:var(--good-text)}
.nona-diff.del{color:var(--critical)}
.nona-card-b{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.nona-suggest{display:flex;flex-wrap:wrap;gap:6px;padding:0 12px 8px}
.nona-suggest .pchip{height:auto;padding:5px 10px;line-height:1.3;white-space:normal}
.nona-msg.memory{align-self:stretch;display:flex;flex-wrap:wrap;align-items:center;gap:6px;font-size:12px;color:var(--text-2);border-left:3px solid var(--gold);padding:4px 8px;background:var(--panel3);border-radius:0 8px 8px 0}
.nona-suggest .pchip.resume{border-color:var(--accent)}
.nona-suggest .pchip.incog{color:var(--muted)}
.nona-memory{border-top:1px solid var(--line);padding-top:10px;display:flex;flex-direction:column;gap:6px}
.nona-mem-row{display:flex;align-items:center;gap:6px}
.nona-mem-k{font-size:11px;color:var(--muted);min-width:64px}
.nona-mem-row input{flex:1;min-width:0}
.nona-mem-b{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.nona-mem-b label.check{padding-top:0}

/* THE WEAPON'S BENCHMARK TAB. The matrix states one cell per line; nothing in
   it compares two lines, because two rulers are two environments. */
.wb-tab{width:100%;border-collapse:collapse;font-size:12.5px}
.wb-tab th{text-align:left;font-weight:600;color:var(--text-2);font-size:11.5px;
  padding:4px 8px;border-bottom:1px solid var(--line)}
.wb-row{cursor:pointer}
.wb-row td{padding:6px 8px;border-bottom:1px solid var(--line);color:var(--text)}
.wb-row:hover td{background:var(--panel3)}
.wb-row.sel td{background:var(--panel2);font-weight:600}
.wb-mode,.wb-rank{color:var(--text-2)}
.wb-score{font-variant-numeric:tabular-nums}
.wb-rank{text-align:right;font-variant-numeric:tabular-nums}
.wb-detail{margin-top:12px}
.wb-terms{margin:0 0 8px;color:var(--text-2);font-size:11.5px}
.wb-cards{display:flex;flex-wrap:wrap;gap:5px}
.wb-card{font-size:11.5px;border:1px solid var(--line);border-radius:6px;
  padding:2.5px 7px;background:var(--panel2);color:var(--text)}
.wb-card.wb-evo{background:transparent;color:var(--text-2)}
.wb-ceiling{margin:10px 0 0;color:var(--text-2);font-size:12px}
.wb-empty{margin:0;color:var(--text-2);font-size:12.5px;max-width:64ch}

/* THE PAGE'S OWN ANSWER, above the modules — A SLOT, NOT A BOX. What goes in
   it is one `.fold.sect`, which draws its own border, padding and ground; a
   frame here too is two frames around one collapsed line, which is what the
   reader who opens this page every day sees of it. */
.doc{margin:0}
.doc a{color:var(--accent)}

/* THE ENTRANT CLASS, its own row under the build filters: two answers that are
   never added together read worse side by side with three that are. */
.bclass{margin-top:6px;display:flex;gap:6px;flex-wrap:wrap}

/* ---- PART VALUE ANALYSIS (#shapley-block) ---- */
.shp-parts{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}
.shp-group{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px}
.shp-group .sb-h{min-width:5em}
.shp-part{display:inline-flex;flex-direction:row;align-items:center;gap:4px;font-size:13px;color:var(--text);cursor:pointer}
.shp-part input{width:auto;margin:0}
.shp-controls{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-bottom:8px}
.shp-controls label{flex-direction:row;align-items:center;gap:8px;color:var(--text)}
.shp-controls input[type=number]{width:5em}
.shp-cost{color:var(--text-2);font-size:12px;font-variant-numeric:tabular-nums}
.shp-over,.shp-note{color:var(--critical);font-size:12px}
.shp-note{margin:6px 0}
.shp-stale{margin:6px 0;padding:4px 8px;border-radius:6px;background:var(--panel2);color:var(--gold);font-size:12px}
.shp-meta{color:var(--text-2);font-size:12px;margin-top:8px}
.shp-scope{color:var(--muted);font-size:12px}
.shp-total{margin:6px 0 8px}
.shp-scroll{overflow-x:auto;max-width:100%}
.shp-table,.shp-matrix{border-collapse:collapse;font-variant-numeric:tabular-nums;font-size:13px}
.shp-table th,.shp-table td,.shp-matrix th,.shp-matrix td{padding:3px 8px;border-bottom:1px solid var(--line);text-align:right;white-space:nowrap}
.shp-table tbody th,.shp-matrix tbody th{text-align:left;font-weight:500}
.shp-table thead th,.shp-matrix thead th{color:var(--text-2);font-weight:500;font-size:12px}
.shp-table td small{color:var(--muted);font-size:10px;margin-left:3px}
.shp-phi{font-weight:600}
.shp-dim{opacity:.45}
.shp-h{margin:14px 0 4px;font-size:13px}
.shp-matrix td{min-width:4.2em}
.shp-i.syn{background:color-mix(in srgb,var(--good) var(--a),transparent)}
.shp-i.dil{background:color-mix(in srgb,var(--critical) var(--a),transparent)}
.shp-diag{background:var(--panel2)}

/* THE WEAPON'S BRIEF — the only part of a weapon page that is about the
   weapon, and it ships in the served HTML so a reader that never runs
   JavaScript still gets every figure. It folds from its own heading like any
   section; the body stays in the document either way, which is what lets it
   be closed by default without hiding anything from a machine. */
.w-brief{margin:0 0 14px}
.w-brief>.fold-h>.w-cn{color:var(--muted);font-size:12px}
.w-brief>.fold-h>.sim-hint{color:var(--text-2)}
.w-tab{border-collapse:collapse;width:100%;font-size:12px;
  font-variant-numeric:tabular-nums;margin:0 0 10px}
.w-tab:last-child{margin-bottom:0}
.w-tab caption{caption-side:top;text-align:left;color:var(--muted);
  font-size:11px;padding:0 0 6px}
.w-tab th,.w-tab td{padding:5px 10px 5px 0;vertical-align:top;
  border-bottom:1px solid var(--line);text-align:left}
.w-tab tr:last-child>*{border-bottom:0}
.w-tab th{color:var(--muted);font-weight:500;white-space:nowrap}
.w-tab td{color:var(--text-2)}
.w-tab .w-num{color:var(--gold);font-weight:600;text-align:right;
  white-space:nowrap;padding-right:14px}
/* THE ANSWER TABLE IS THE WIDE ONE and a build is a long cell, so it scrolls
   in a box of its own rather than pushing the page sideways. */
.w-answers{display:block;overflow-x:auto;white-space:normal}
.w-answers thead th{color:var(--text-2);font-weight:600}
.w-answers tbody td:first-child{color:var(--text);white-space:nowrap}
/* WHAT THE NUMBER DOES NOT ACCOUNT FOR. It is absent on a weapon with nothing
   to admit, so text here is a signal rather than a filled slot. */
.w-notes{margin:10px 0 0;font-size:12px;color:var(--muted)}
.w-notes b{color:var(--text-2);font-weight:600}
.w-notes ul{margin:5px 0 0;padding-left:18px}
.w-notes li{margin:3px 0}

/* WHO ELSE IS FIRING — the roster (`28-fight-roster.js`). A LIST of rows for
   the same reason the squad's shards are one: each seat is a weapon, a preset
   and a remove, and a field grid would floor every track at min-content and
   push the remove off a phone (`check_mobile.mjs`). */
.rs{display:flex; flex-direction:column; gap:8px}
.rs-row{display:flex; flex-wrap:wrap; align-items:center; gap:8px}
/* THE WEAPON IS THE ROW and the preset is half of it: both grow, the weapon
   twice as fast, so a long name is readable before a preset name is squeezed. */
.rs-row > .dd{flex:2 1 180px; min-width:0}
.rs-row > .dd[id^="dd-seat-preset"]{flex:1 1 120px}
/* THE SEAT NUMBER, and it is the ONE thing every row shares with the result
   panel's per-seat table: the same 1, 2, 3 in the same order, so a reader
   comparing the two is comparing the same list. */
.rs-n{display:inline-flex; align-items:center; justify-content:center;
  min-width:20px; height:20px; border-radius:10px; font-size:11px;
  background:var(--line); color:var(--muted)}
.rs-you .rs-n{background:var(--accent); color:var(--surface)}
.rs-me{font-weight:600}
.rs-hint{color:var(--muted); font-size:12px; flex:1 1 100%; min-width:0}
.rs-row .rs-hint{flex:0 1 auto}
.rs-x{padding:2px 8px; line-height:1}
.rs-add{display:flex; flex-wrap:wrap; align-items:center; gap:8px}

/* ---- ONE ACTOR'S SHEET, above the rows it is folded out of -------------
   WCL gives a page per actor and SimC a line per action; this is both, and it
   is made of the record — so it sits ON the record rather than beside it. */
.ac-sheet{border:1px solid var(--line);border-radius:10px;background:var(--surface);
  margin:0 0 12px;overflow:hidden}
.ac-h{display:flex;align-items:baseline;gap:9px;padding:9px 12px;border-bottom:1px solid var(--line);
  background:var(--panel3);flex-wrap:wrap}
.ac-side{font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  padding:1px 7px;border-radius:999px}
.ac-ally{background:color-mix(in srgb,var(--accent) 22%,transparent);color:var(--accent)}
.ac-foe{background:color-mix(in srgb,var(--gold) 22%,transparent);color:var(--gold)}
.ac-name{font-size:13px;font-weight:700}
.ac-sub{font-size:11px;color:var(--muted)}
.ac-tot{margin-left:auto;font-size:14px;font-weight:700;font-variant-numeric:tabular-nums}
.ac-tab{width:100%;border-collapse:collapse;font-size:11.5px;font-variant-numeric:tabular-nums}
.ac-tab th{text-align:left;font-weight:600;color:var(--muted);font-size:10.5px;text-transform:uppercase;
  letter-spacing:.04em;padding:6px 12px;border-bottom:1px solid var(--line)}
.ac-tab td{padding:5px 12px;border-bottom:1px solid var(--line)}
.ac-tab tr:last-child td{border-bottom:0}
.ac-tab .num{text-align:right}
/* THE BAR IS BEHIND THE NAME, not beside it: a share is a property of the row
   it labels, and a column of its own costs the widest column its width. */
.ac-bar{position:relative;min-width:120px}
.ac-bar i{position:absolute;left:12px;top:50%;transform:translateY(-50%);height:15px;
  border-radius:3px;background:var(--accent);opacity:.22}
.ac-bar span{position:relative}
.ac-none{color:var(--muted);text-align:center;padding:12px}
.ac-n{margin:0;padding:8px 12px;border-top:1px solid var(--line);
  font-size:11px;color:var(--muted);line-height:1.6}
