/* ==========================================================================
   DLT — a bout record.
   Tokens live in tokens.css. Nothing here hardcodes a colour or a size.

   Hierarchy comes from scale and weight. Labels are sentence case: tracked-out
   capitals read as chrome and say nothing that size and colour do not.
   ========================================================================== */

@font-face {
  font-family: "Big Shoulders"; font-style: normal; font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/BigShouldersDisplay.woff2") format("woff2-variations");
}
@font-face {
  font-family: "Archivo"; font-style: normal; font-weight: 100 900;
  font-stretch: 62% 125%; font-display: swap;
  src: url("/static/fonts/Archivo-400_700.woff2") format("woff2-variations");
}
@font-face {
  font-family: "Plex Mono"; font-style: normal; font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/IBMPlexMono-400.woff2") format("woff2");
}

*, *::before, *::after { box-sizing: border-box; }

/* A share code, an ingest token and a Windows path are all one long word with
   no break opportunity in it, so on a narrow screen they do not wrap, they push
   the whole page sideways and every other element inherits the overflow. */
.secret, .mono, .diag, .bind-input, code, .path { overflow-wrap: anywhere; }

/* [hidden] is a UA-stylesheet display:none, so any author display rule beats
   it. Without this the client titlebar and close dialog render while hidden. */
[hidden] { display: none !important; }

html { background: var(--ground); color-scheme: dark; -webkit-text-size-adjust: 100%; }

/* The art sits behind the content, fixed, and never intercepts a pointer.
   Both layers hang off body, not html: the root element's background paints the
   canvas, and a z-index:-1 pseudo-element on html goes BEHIND that and is never
   seen. On body it lands above the canvas and below the content.
   Two layers because the skyline and the grain want different weights. */
body::before, body::after {
  content: ""; position: fixed; inset: 0; z-index: -1;
  pointer-events: none;
}
body::before {
  /* Fixed height, tiled horizontally. Sizing by width instead made the skyline
     61px tall on a phone and 404px on an ultrawide, which is what read as it
     not being locked down. */
  background: url("/static/art/skyline.webp") repeat-x bottom left / auto 190px;
  opacity: var(--art-sky);
}
body::after {
  background: url("/static/art/grain.webp") repeat 0 0 / 256px 256px;
  opacity: var(--art-grain);
}

body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--bone);
  background: transparent;         /* html paints the canvas; body::before/after sit above it */
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Data columns must align. Archivo is the only face here with real tnum. */
td, th, .stat-v, .mono, .hero-num { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); font-size: .92em; }

a { color: inherit; text-decoration: none; }

::selection { background: var(--amber); color: var(--on-amber); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--ground); }
::-webkit-scrollbar-thumb {
  background: var(--rule-hi); border: 2px solid var(--ground); border-radius: var(--r-md);
}
::-webkit-scrollbar-thumb:hover { background: var(--faint); }
* { scrollbar-color: var(--rule-hi) var(--ground); scrollbar-width: thin; }
input { caret-color: var(--amber); }

/* :focus-visible is Chromium 86; the Steam overlay runs 85, so :focus carries
   the ring there and the modern rule removes it for mouse users. */
:focus { outline: 2px solid var(--amber); outline-offset: 2px; }
:focus:not(:focus-visible) { outline: none; }
:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* ------------------------------------------------------------------ header */

.top {
  display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5) var(--sp-3);
  border-bottom: 1px solid var(--rule);
  background: var(--card-92);
  background: color-mix(in srgb, var(--card) 92%, transparent);
  backdrop-filter: blur(8px);
  position: sticky; top: 0; z-index: 20;
}

/* The wordmark is an acronym, so capitals are the word, not a label style. */
.brand {
  font-family: var(--display);
  font-size: 27px; font-weight: 800; font-stretch: 84%;
  line-height: 1; color: var(--bone); flex: none;
}
.brand b { color: var(--amber); font-weight: 800; }

.top nav { display: flex; gap: var(--sp-5); min-width: 0; }
.top nav a {
  font-size: var(--fs-small); color: var(--bone-3); white-space: nowrap;
  padding-bottom: 2px; border-bottom: 2px solid transparent;
  transition: color var(--fast) var(--ease);
}
.top nav a:hover { color: var(--bone); }
.top nav a[aria-current="page"] { color: var(--bone); border-bottom-color: var(--amber); }

.spacer { flex: 1; }

/* Header search. The URL swap is the headline feature, so lookup stays reachable
   from every page rather than living on one. */
.hsearch { position: relative; display: flex; align-items: center; min-width: 0; flex: 0 1 260px; }
/* Specificity has to beat the generic input[type=text] rule below, which is
   equally specific and comes later in the file. Height plus a matching
   line-height is what actually centres the text; padding alone does not. */
.hsearch input[type=text] {
  width: 100%; height: 30px; line-height: 28px;
  padding: 0 var(--sp-6) 0 var(--sp-3);
  font-size: var(--fs-small); background: var(--ground);
  border: 1px solid var(--rule); border-radius: var(--r-md); color: var(--bone);
}
.hsearch input[type=text]::placeholder { color: var(--bone-3); }
.hsearch input[type=text]:hover { border-color: var(--rule-hi); }
.hsearch input[type=text]:focus { border-color: var(--faint); outline: none; }
.hsearch-k {
  position: absolute; right: 6px; pointer-events: none;
  font-family: var(--mono); font-size: var(--fs-fine); line-height: 1;
  color: var(--bone-3); border: 1px solid var(--rule-hi); border-radius: var(--r-md);
  padding: 2px 5px;
}
.hsearch input:focus ~ .hsearch-k { opacity: 0; }

/* Identity is one target: avatar and name together, going to your own profile. */
.me-btn {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-small); color: var(--bone-2);
  padding: 3px var(--sp-2) 3px 3px; border-radius: var(--r-pill);
  border: 1px solid transparent; min-width: 0;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.me-btn img { border-radius: 50%; flex: none; }
.me-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.me-btn:hover { background: var(--raised); color: var(--bone); }
.me-btn[aria-current="page"] { border-color: var(--rule-hi); color: var(--bone); }

.wrap { max-width: var(--measure); margin: 0 auto; padding: var(--sp-6) var(--sp-5) var(--sp-8); }

/* ------------------------------------------------------------------ inputs */

input[type=text], input[type=search] {
  font: inherit; color: var(--bone);
  background: var(--card); border: 1px solid var(--rule-hi); border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4); width: 100%;
  transition: border-color var(--fast) var(--ease);
}
input[type=text]:hover { border-color: var(--faint); }
input::placeholder { color: var(--bone-3); }

/* The variants are listed here as well as .btn, because they only ever override
   colour. On a <button> the element selector already supplies the shape, so
   .btn-ghost alone looks right; on an <a> nothing did, and the variant set a
   border-colour with no border-style, so the control rendered as bare text. */
button, .btn, .btn-ghost, .btn-danger {
  /* An <a> is inline, so its vertical padding does not grow the line box and
     the control overlaps its neighbours. <button> is inline-block already. */
  display: inline-block; text-align: center;
  font: inherit; font-size: var(--fs-small); font-weight: 600;
  color: var(--on-amber); background: var(--amber);
  border: 1px solid var(--amber); border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4); cursor: pointer;
  box-shadow: var(--shadow-1);
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
button:hover, .btn:hover, .btn-ghost:hover, .btn-danger:hover {
  background: var(--amber-hi); border-color: var(--amber-hi);
  transform: translateY(-1px); box-shadow: var(--shadow-2);
}
/* Press lands it back on the surface and pushes the highlight inward, so the
   button reads as depressed rather than merely nudged. */
button:active, .btn:active, .btn-ghost:active, .btn-danger:active {
  transform: translateY(0); box-shadow: var(--shadow-in);
}
button:focus-visible, .btn:focus-visible, .btn-ghost:focus-visible, .btn-danger:focus-visible {
  outline: 2px solid var(--amber-hi); outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  button, .btn { transition: background var(--fast) var(--ease); }
  button:hover, .btn:hover { transform: none; }
}

.btn-ghost, a.btn-ghost { color: var(--bone-2); background: transparent; border-color: var(--rule-hi); }
.btn-ghost:hover { color: var(--bone); background: var(--raised); border-color: var(--faint); }
.btn-danger, a.btn-danger { color: var(--lost); background: transparent; border-color: var(--lost-bg); }
.btn-danger:hover { color: var(--on-amber); background: var(--lost); border-color: var(--lost); }

/* Present to assistive technology, absent on screen. Used where a page has a
   clear identity that the design states through layout rather than a title. */
.vh {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* A section heading with an action on the same line. The rule under the
   heading still spans the section, so the button sits above it rather than
   inside it. */
.diag {
  font-family: var(--mono); font-size: var(--fs-fine); color: var(--bone-2);
  background: var(--raised); border: 1px solid var(--rule-hi);
  border-radius: var(--r-md); padding: var(--sp-4);
  margin-bottom: var(--sp-5); white-space: pre-wrap; overflow-x: auto;
}

.clash { border: 1px solid var(--rule-hi); border-radius: var(--r-md);
  background: var(--card); padding: var(--sp-4); margin-bottom: var(--sp-4); }
.clash-head { font-size: var(--fs-small); color: var(--bone-2); margin-bottom: var(--sp-3); }
.clash td.mono { font-family: var(--mono); font-size: var(--fs-fine); color: var(--bone); }
.clash .chip { margin-right: var(--sp-1); }
.clash-actions { margin-top: var(--sp-3); }

.toggle { display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-small); color: var(--bone-2); }
.toggle input { width: 16px; height: 16px; flex: none; accent-color: var(--amber); }

.sec-row { display: flex; align-items: baseline; gap: var(--sp-4); }
.sec-row .sec-h { flex: 1; }

.row { display: flex; gap: var(--sp-3); align-items: center; }
.row-wrap { flex-wrap: wrap; }

/* ---------------------------------------------------------------- masthead */

.masthead {
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-5);
  align-items: center; padding-bottom: var(--sp-5);
}
.avatar {
  width: 92px; height: 92px; border-radius: var(--r-md);
  border: 1px solid var(--rule-hi); background: var(--raised);
}
.masthead h1 {
  margin: 0; font-family: var(--display); font-size: var(--fs-name);
  font-weight: 700; line-height: .95; letter-spacing: -.005em;
  overflow-wrap: anywhere;
}
.sub { color: var(--bone-3); font-size: var(--fs-small); }
.idline { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); align-items: center; }

.rankchip {
  color: var(--amber-hi); font-size: var(--fs-small); font-weight: 600;
  border-bottom: 1px solid var(--amber-dim); padding-bottom: 1px;
}

/* The last twenty results, newest last so it reads with the chart. */
.form { display: flex; gap: var(--sp-1); align-items: flex-end; flex-wrap: wrap; }
.form-g {
  width: 28px; height: 28px; display: grid; place-items: center;
  background: var(--lost-bg); border-bottom: 2px solid var(--lost);
  border-radius: var(--r-sm);
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease);
}
.form-g.w { background: var(--won-bg); border-bottom-color: var(--won); }
.form-g img { display: block; border-radius: var(--r-sm); opacity: .85; }
.form-g:hover { transform: translateY(-1px); }
.form-g:hover img { opacity: 1; }

/* ------------------------------------------------------- the record line */
/* The rating is the one loud thing on the page. The supporting figures sit in a
   quiet row beside it, separated by rules rather than boxed into equal cards. */

.record {
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-6) var(--sp-7);
  align-items: end;
  border-top: 1px solid var(--rule-hi); border-bottom: 1px solid var(--rule-hi);
  padding: var(--sp-5) 0; margin: var(--sp-5) 0 0;
}
.hero-num {
  font-family: var(--display); font-size: var(--fs-hero); font-weight: 700;
  line-height: .85; letter-spacing: -.02em;
}
.hero-label { font-size: var(--fs-small); color: var(--bone-3); }
.hero-note { font-size: var(--fs-small); color: var(--bone-2); margin-top: var(--sp-1); }

.figures {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(96px, 100%), 1fr));
  gap: var(--sp-4) var(--sp-5);
}
.fig { min-width: 0; }
.fig-k {
  font-size: var(--fs-fine); color: var(--bone-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.stat-v {
  font-family: var(--display); font-size: var(--fs-stat); font-weight: 600;
  color: var(--bone); line-height: 1.2; white-space: nowrap;
}
.stat-v small { font-family: var(--sans); font-size: var(--fs-fine); color: var(--bone-3); }
.v-win  { color: var(--won); }
.v-loss { color: var(--lost); }
.v-amber{ color: var(--amber-hi); }

/* --------------------------------------------------------------------- data */

.sec { margin-top: var(--sp-7); }
.sec-h {
  display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap;
  font-family: var(--display); font-size: var(--fs-head); font-weight: 600;
  color: var(--bone); padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--rule-hi);
  /* These are h2 now, so the UA margin has to go. They were divs, which is
     why 56 section titles were invisible to the document outline and to a
     screen reader's heading list. Nothing about how they look changes. */
  margin: 0 0 0;
}
.sec-h .note {
  font-family: var(--sans); font-size: var(--fs-small);
  font-weight: 400; color: var(--bone-3);
}

.scroller-wrap { position: relative; }
.scroller { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
.scroller-wrap::before, .scroller-wrap::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 40px;
  pointer-events: none; opacity: 0; transition: opacity var(--fast) var(--ease); z-index: 2;
}
.scroller-wrap::before { left: 0; background: linear-gradient(90deg, var(--ground), transparent); }
.scroller-wrap::after { right: 0; background: linear-gradient(270deg, var(--ground), transparent); }
.scroller-wrap[data-l="1"]::before { opacity: 1; }
.scroller-wrap[data-r="1"]::after  { opacity: 1; }

table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
/* A table inside a horizontal scroller must be allowed to exceed the scroller,
   or there is nothing to scroll. width:100% pinned every table to its container
   instead, so on a narrow screen the columns squeezed rather than the table
   overflowing, and cell contents were cut mid-character: the Keys input on the
   binds page clipped about a quarter of the way into a letter.
   max-content sizes to the content, min-width keeps it filling a wide screen. */
.scroller > table { width: max-content; min-width: 100%; }
th {
  text-align: left; font-size: var(--fs-fine); font-weight: 600; color: var(--bone-3);
  padding: var(--sp-3); border-bottom: 1px solid var(--rule); white-space: nowrap;
}
td {
  padding: var(--sp-3); border-bottom: 1px solid var(--rule);
  color: var(--bone-2); vertical-align: middle; white-space: nowrap;
}
tbody tr { transition: background var(--fast) var(--ease); }
tbody tr:hover td { background: var(--card); color: var(--bone); }
td.k, th.k { text-align: right; }
td.name { color: var(--bone); font-weight: 600; }
td.wide, th.wide { width: 99%; white-space: normal; }

.hero { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.hero img {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  background: var(--raised); border: 1px solid var(--rule); flex: none;
}
.hero span { overflow: hidden; text-overflow: ellipsis; }

/* Outcome is never colour alone; the letter is the cue. */
.pill {
  display: inline-block; text-align: center;
  font-size: var(--fs-fine); font-weight: 700;
  padding: 2px 0; border: 1px solid;
  /* 2.25ch, not 22px: it has to fit one letter at whatever the font does. */
  min-width: 2.25ch;
  border-radius: var(--r-pill);
}
.pill-w { color: var(--won);  border-color: var(--won-bg);  background: var(--won-bg); }
.pill-l { color: var(--lost); border-color: var(--lost-bg); background: var(--lost-bg); }
.pill-x { color: var(--bone-3); border-color: var(--rule-hi); background: transparent; }
tr.uncounted td { color: var(--bone-3); }

/* A strict CSP forbids inline style, so bar widths are classes (end of file). */
.bar { display: block; height: 4px; background: var(--rule); width: 64px; overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--lost); }
.bar.win > i { background: var(--won); }
td.barcell { width: 64px; padding-left: 0; }

/* ------------------------------------------------------- rating over time */

.spark { margin: var(--sp-4) 0 0; padding: 0; position: relative; }
.spark svg { display: block; overflow: visible; touch-action: pan-y; }
.spark-zero { stroke: var(--rule-hi); stroke-width: 1; stroke-dasharray: 3 3; }
.spark-patch { stroke: var(--sapphire); stroke-width: 1; stroke-dasharray: 2 3; opacity: .7;
  vector-effect: non-scaling-stroke; }
.spark-line {
  fill: none; stroke: var(--amber); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
}
.spark-last { fill: var(--amber-hi); stroke: var(--ground); stroke-width: 2; }
.spark-cross { stroke: var(--faint); stroke-width: 1; }
.spark-dot { fill: var(--amber-hi); stroke: var(--ground); stroke-width: 2; }
/* SVG receives pointer events only where it paints; hover needs a real target. */
.spark-hit { fill: transparent; }
.spark-read { font-size: var(--fs-fine); color: var(--bone-2); margin-top: var(--sp-2); min-height: 1.2em; }

/* -------------------------------------------------------------- breakdown */

.breakdown {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-5); margin-top: var(--sp-4);
}
@media (max-width: 860px) { .breakdown { grid-template-columns: repeat(2, 1fr); } }
.bd-k { font-size: var(--fs-fine); color: var(--bone-3); }
.bd-z { font-family: var(--display); font-size: var(--fs-stat); font-weight: 600; line-height: 1.2; }
.bd-z small { font-family: var(--sans); font-size: var(--fs-fine); color: var(--bone-3); }
/* Deviation reads from a centre line: right is better, left is worse. Each
   half is half the track, so a fill can never be wider than 50%. It used to
   reach 99% at three sigma while still starting at the midpoint, which ran it
   to 149% and out past the end of the track behind it. */
.bd-bar { height: 3px; background: var(--rule); margin-top: var(--sp-2); position: relative; }
.bd-bar > i { position: absolute; top: 0; height: 100%; max-width: 50%; }
.bd-bar > i.up   { left: 50%; background: var(--won); }
.bd-bar > i.down { right: 50%; background: var(--lost); }
.bd-p { font-size: var(--fs-fine); color: var(--bone-3); margin-top: var(--sp-2); }

/* ------------------------------------------------------------- match page */

.matchhead { padding-bottom: var(--sp-4); }
.matchhead h1 {
  margin: 0; font-family: var(--display); font-size: var(--fs-name);
  font-weight: 700; line-height: .95;
}
/* The two corners, from the game's own teams. The heading already carries a
   rule; the corner colours that rather than adding a tab down the side. */
.corner-a { border-bottom-color: var(--amber); }
.corner-b { border-bottom-color: var(--sapphire); }
tr.focus td {
  background: var(--amber-10);
  background: color-mix(in srgb, var(--amber) 10%, transparent);
}
tr.focus td.name a { color: var(--amber-hi); }

.masthead-plain { padding-bottom: var(--sp-5); }
.masthead-plain h1 {
  margin: 0 0 var(--sp-2); font-family: var(--display);
  font-size: var(--fs-name); font-weight: 700; line-height: .95;
}


.settings {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 1fr));
  gap: var(--sp-4) var(--sp-5); margin-top: var(--sp-4);
}
.setting { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.setting-k { font-size: var(--fs-small); color: var(--bone-2); }
.setting input { padding: var(--sp-2) var(--sp-3); }
/* The cvar name is reference, not a label: the human name is above the box. */
.setting-cvar {
  font-family: var(--mono); font-size: var(--fs-fine); color: var(--faint);
  overflow: hidden; text-overflow: ellipsis;
}

/* --------------------------------------------------------------- aux */

.empty {
  border-radius: var(--r-md);
  border: 1px solid var(--rule-hi); padding: var(--sp-7) var(--sp-5);
  text-align: center; color: var(--bone-3);
}
.err { color: var(--lost); font-size: var(--fs-small); }
.muted { color: var(--bone-3); }

.setting-toggle { align-items: center; }
.setting-toggle input[type=checkbox] { justify-self: start; width: 16px; height: 16px; accent-color: var(--amber); }
.titlebar-where { font-size: var(--fs-fine); color: var(--bone-3); margin-left: var(--sp-3); }

/* Item categories. A dot rather than coloured text: the name stays in the
   reading colour and the category sits beside it, so a table of items does not
   turn into three columns of shouting. */
.cat { display: inline-block; width: 7px; height: 7px; border-radius: 50%;
       margin-right: var(--sp-2); vertical-align: 1px; flex: none; }
.cat-weapon   { background: var(--weapon); }
.cat-vitality { background: var(--vitality); }
.cat-spirit   { background: var(--spirit); }
.v-soul { color: var(--soul-dim); }

.keycap {
  display: inline-block; font-family: var(--mono); font-size: var(--fs-fine);
  line-height: 1; color: var(--bone-2); background: var(--raised);
  border: 1px solid var(--rule-hi); border-bottom-width: 2px;
  border-radius: var(--r-sm); padding: 3px 6px; margin-right: var(--sp-1);
}

/* "3d" answers how long ago; the date under it answers which game. The date is
   the quieter of the two because you only look for it deliberately. */
.when { color: var(--bone-2); line-height: 1.25; }
.when-d { display: block; font-size: var(--fs-fine); color: var(--bone-3); }
.tiny { font-size: var(--fs-fine); }

.gate { min-height: 72vh; display: flex; align-items: center; justify-content: center; }
.gate-in { width: 100%; max-width: 360px; }
.gate h1 {
  font-family: var(--display); font-size: var(--fs-name); font-weight: 800;
  line-height: 1; margin: 0 0 var(--sp-6);
}
.gate form { display: flex; flex-direction: column; gap: var(--sp-3); }
.gate .alt { margin-top: var(--sp-5); font-size: var(--fs-small); color: var(--bone-3); }
.gate .alt a { color: var(--amber-hi); border-bottom: 1px solid var(--amber-dim); }

.prompt {
  border-radius: var(--r-md);
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  border: 1px solid var(--amber-dim); background: var(--amber-06);
  background: color-mix(in srgb, var(--amber) 6%, transparent);
  padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-5);
  font-size: var(--fs-small);
}
.prompt form { display: contents; }

.tree-row { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.tree-row .d { color: var(--faint); font-family: var(--mono); white-space: pre; }
.banned { text-decoration: line-through; color: var(--faint); }
.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: var(--sp-5); }
.stack { display: flex; flex-direction: column; gap: var(--sp-4); }
.card { border: 1px solid var(--rule); border-radius: var(--r-md);
  padding: var(--sp-4); background: var(--card); }
form.inline { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
form.inline input[type=text] { width: auto; flex: 1; min-width: 120px; padding: var(--sp-2) var(--sp-3); }
select {
  font: inherit; font-size: var(--fs-small); color: var(--bone);
  background: var(--card); border: 1px solid var(--rule-hi); padding: var(--sp-2) var(--sp-3);
}
input[type=file] {
  font: inherit; font-size: var(--fs-small); color: var(--bone-2);
  background: var(--card); border: 1px solid var(--rule-hi);
  padding: var(--sp-2) var(--sp-3); max-width: 100%;
}
input[type=file]::file-selector-button {
  font: inherit; font-size: var(--fs-fine); font-weight: 600;
  color: var(--bone); background: var(--raised); border: 1px solid var(--rule-hi);
  padding: var(--sp-1) var(--sp-3); margin-right: var(--sp-3); cursor: pointer;
}

/* Flex rather than grid: a grid leaves the trailing row's empty cells showing
   the rule-coloured backdrop, which reads as a broken bottom edge. Centring a
   wrapped flex row keeps every row visually complete. */
.herogrid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 1px; background: var(--rule);
  border: 1px solid var(--rule); margin-top: var(--sp-4);
  border-radius: var(--r-md); overflow: hidden;
}
.herocard {
  display: flex; align-items: center; gap: var(--sp-3);
  flex: 0 1 172px; min-width: 0;
  padding: var(--sp-3); background: var(--card);
  font-size: var(--fs-small); color: var(--bone-2);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.herocard > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.herocard:hover { background: var(--raised); color: var(--bone); }
.herocard img { border-radius: var(--r-sm); flex: none; }

/* ---------------------------------------------------- desktop client chrome */

.titlebar {
  position: fixed; inset: 0 0 auto 0; height: var(--titlebar-h);
  display: flex; align-items: stretch; z-index: 100;
  background: var(--ground); border-bottom: 1px solid var(--rule);
}
.titlebar-drag { flex: 1; display: flex; align-items: center; padding-left: var(--sp-4); -webkit-app-region: drag; }
.titlebar-name { font-family: var(--display); font-size: var(--fs-body); font-weight: 700; color: var(--bone-3); }
.wc {
  width: 46px; padding: 0; border: 0; border-radius: 0; cursor: pointer;
  background: transparent; color: var(--bone-2); display: grid; place-items: center;
  -webkit-app-region: no-drag;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.wc:hover { background: var(--raised); color: var(--bone); }

/* The launch control. A body and a thin strip, divided by a hairline rather
   than a gap, because a gap reads as two buttons and he asked for one. */
.launch { position: relative; display: flex; align-items: stretch; }
.launch-go, .launch-more {
  border: 1px solid var(--rule-hi); background: var(--card); color: var(--bone);
  cursor: pointer; font: inherit; padding: 0;
  margin: calc((var(--titlebar-h) - 24px) / 2) 0;
}
.launch-go {
  padding: 0 var(--sp-4); font-size: var(--fs-fine); font-weight: 600;
  border-radius: var(--r-md) 0 0 var(--r-md); border-right: 0;
}
/* Thin on purpose, and the divider is the body's missing right border showing
   through as this one's left. */
.launch-more {
  width: 18px; display: flex; align-items: center; justify-content: center;
  border-radius: 0 var(--r-md) var(--r-md) 0; border-left: 1px solid var(--rule-hi);
  color: var(--bone-3);
}
.launch-go:hover, .launch-more:hover { background: var(--raised); }
.launch-more:hover { color: var(--bone); }
.launch-go:disabled, .launch-more:disabled { opacity: .5; cursor: default; }
.launch-go:focus-visible, .launch-more:focus-visible {
  outline: 2px solid var(--amber-hi); outline-offset: -2px;
}
.launch-menu {
  position: absolute; top: calc(100% + 2px); right: 0; z-index: 120;
  min-width: 180px; padding: var(--sp-1);
  background: var(--card); border: 1px solid var(--rule-hi);
  border-radius: var(--r-md); box-shadow: var(--shadow-2);
}
.launch-menu[hidden] { display: none; }
.launch-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; color: var(--bone); font: inherit;
  font-size: var(--fs-fine); padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
}
.launch-item:hover, .launch-item:focus-visible { background: var(--raised); }
.launch-item:disabled { opacity: .5; cursor: default; }
.launch-note { display: block; font-size: var(--fs-fine); color: var(--bone-3); }
.launch-error {
  margin: var(--sp-1) 0 0; padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-fine); color: var(--bone-2);
  border-top: 1px solid var(--rule);
}
.launch-error[hidden] { display: none; }
.wc-close:hover { background: var(--lost); color: var(--on-amber); }
/* The content scrolls in its own region below the toolbar, rather than the
   document scrolling behind a fixed toolbar. With the document scrolling, the
   scrollbar track runs the full window height and sits alongside the toolbar,
   which is not something CSS can inset. A separate scroll container is the
   only way to start the bar below it.

   The close sheet and the resize handles stay outside this element: both are
   window furniture and both need the whole window, not the scrolled part. */
[data-client], [data-client] body { height: 100%; overflow: hidden; }
[data-client] .client-view {
  height: calc(100% - var(--titlebar-h));
  margin-top: var(--titlebar-h);
  overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain;
}
/* Sticky now resolves against .client-view, whose top edge already sits below
   the toolbar, so the old titlebar-height offset would double-count it. */
[data-client] .top { top: 0; }

/* Rounded window corners, 2px. Square enough to read as deliberate rather than
   as a default, which is the whole point of drawing our own frame.

   The radius cannot go on body: the titlebar and the resize handles are
   position:fixed, so they are laid out against the viewport and an ancestor's
   overflow does not clip them. Instead the two elements that actually touch
   the window edge carry it, and everything behind them is transparent so the
   corners show through to nothing.

   This needs transparent:true on the window, without which the corners are
   filled by the window's own opaque surface and nothing appears to round. */
[data-client] html, [data-client] body { background: transparent; }
[data-client] body::before, [data-client] body::after { border-radius: var(--r-sm); }
[data-client] .titlebar { border-radius: var(--r-sm) var(--r-sm) 0 0; }
[data-client] .client-view {
  background: var(--ground);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}

/* Resize handles for the frameless window. Thin edges, larger corners, the
   proportions Windows itself uses. Kept clear of the window control buttons
   by sitting only on the outer few pixels. */
.rz { position: fixed; z-index: 300; display: none; }
[data-client] .rz { display: block; }
.rz-n, .rz-s { left: 8px; right: 8px; height: 4px; }
.rz-w, .rz-e { top: 8px; bottom: 8px; width: 4px; }
.rz-n { top: 0; cursor: ns-resize; }
.rz-s { bottom: 0; cursor: ns-resize; }
.rz-w { left: 0; cursor: ew-resize; }
.rz-e { right: 0; cursor: ew-resize; }
.rz-nw, .rz-ne, .rz-sw, .rz-se { width: 10px; height: 10px; }
.rz-nw { top: 0; left: 0; cursor: nwse-resize; }
.rz-ne { top: 0; right: 0; cursor: nesw-resize; }
.rz-sw { bottom: 0; left: 0; cursor: nesw-resize; }
.rz-se { bottom: 0; right: 0; cursor: nwse-resize; }

.sheet { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; background: var(--scrim); }
.sheet-box {
  width: min(360px, calc(100vw - var(--sp-6)));
  background: var(--card); border: 1px solid var(--rule-hi);
  border-radius: var(--r-md); padding: var(--sp-5);
}
.sheet-q { margin: 0 0 var(--sp-2); font-family: var(--display); font-size: var(--fs-head); font-weight: 700; }
.sheet-sub { margin: 0 0 var(--sp-5); font-size: var(--fs-small); color: var(--bone-3); }
.sheet-row { display: flex; gap: var(--sp-3); }
.sheet-row > * { flex: 1; }
.sheet-check { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-4); font-size: var(--fs-small); color: var(--bone-3); }
.sheet-check input { accent-color: var(--amber); }

/* One authored moment: the page settles in once, on load. */
@keyframes settle { from { opacity: .001; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.wrap > * { animation: settle .38s var(--ease) both; }
.wrap > *:nth-child(2) { animation-delay: .04s; }
.wrap > *:nth-child(n+3) { animation-delay: .08s; }

@media (max-width: 860px) {
  .record { grid-template-columns: 1fr; gap: var(--sp-5); }
  .masthead { gap: var(--sp-4); align-items: start; }
  .avatar { width: 64px; height: 64px; }
  .wrap { padding: var(--sp-5) var(--sp-4) var(--sp-7); }
  .hero img { width: 26px; height: 26px; }
  td, th { padding: var(--sp-2) var(--sp-3); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* Bar widths as classes: a strict CSP forbids the inline style attribute. */
.w0{width:0%} .w1{width:1%} .w2{width:2%} .w3{width:3%} .w4{width:4%} .w5{width:5%} .w6{width:6%} .w7{width:7%} .w8{width:8%} .w9{width:9%}
.w10{width:10%} .w11{width:11%} .w12{width:12%} .w13{width:13%} .w14{width:14%} .w15{width:15%} .w16{width:16%} .w17{width:17%} .w18{width:18%} .w19{width:19%}
.w20{width:20%} .w21{width:21%} .w22{width:22%} .w23{width:23%} .w24{width:24%} .w25{width:25%} .w26{width:26%} .w27{width:27%} .w28{width:28%} .w29{width:29%}
.w30{width:30%} .w31{width:31%} .w32{width:32%} .w33{width:33%} .w34{width:34%} .w35{width:35%} .w36{width:36%} .w37{width:37%} .w38{width:38%} .w39{width:39%}
.w40{width:40%} .w41{width:41%} .w42{width:42%} .w43{width:43%} .w44{width:44%} .w45{width:45%} .w46{width:46%} .w47{width:47%} .w48{width:48%} .w49{width:49%}
.w50{width:50%} .w51{width:51%} .w52{width:52%} .w53{width:53%} .w54{width:54%} .w55{width:55%} .w56{width:56%} .w57{width:57%} .w58{width:58%} .w59{width:59%}
.w60{width:60%} .w61{width:61%} .w62{width:62%} .w63{width:63%} .w64{width:64%} .w65{width:65%} .w66{width:66%} .w67{width:67%} .w68{width:68%} .w69{width:69%}
.w70{width:70%} .w71{width:71%} .w72{width:72%} .w73{width:73%} .w74{width:74%} .w75{width:75%} .w76{width:76%} .w77{width:77%} .w78{width:78%} .w79{width:79%}
.w80{width:80%} .w81{width:81%} .w82{width:82%} .w83{width:83%} .w84{width:84%} .w85{width:85%} .w86{width:86%} .w87{width:87%} .w88{width:88%} .w89{width:89%}
.w90{width:90%} .w91{width:91%} .w92{width:92%} .w93{width:93%} .w94{width:94%} .w95{width:95%} .w96{width:96%} .w97{width:97%} .w98{width:98%} .w99{width:99%}
.w100{width:100%} 
/* ----------------------------------------------------------------- home page */
/* Content leads, tools sit beside it. The side column is a fixed, modest width
   so the main column keeps a readable measure on a wide monitor. */

.home { display: grid; grid-template-columns: minmax(0, 1fr) 232px; gap: var(--sp-6); align-items: start; }
.home-main { display: flex; flex-direction: column; gap: var(--sp-5); min-width: 0; }
.home-side { position: sticky; top: calc(var(--header-h) + var(--sp-4)); }

.quick {
  display: flex; flex-direction: column;
  border: 1px solid var(--rule); border-radius: var(--r-md);
  /* Children paint their own background and border, so without clipping their
     square corners sit on top of this one's rounded ones. */
  overflow: hidden;
}
.quick a {
  display: flex; flex-direction: column; gap: 1px;
  padding: var(--sp-3); font-size: var(--fs-small); color: var(--bone-2);
  border-bottom: 1px solid var(--rule);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.quick a:last-child { border-bottom: 0; }
.quick a:hover { background: var(--raised); color: var(--bone); }
.quick .sub { font-size: var(--fs-fine); color: var(--bone-3); }
.quick-act { margin-top: var(--sp-3); }
.quick-act button { width: 100%; }

.ratingline { display: flex; align-items: baseline; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.rating-n { font-family: var(--display); font-size: var(--fs-stat); font-weight: 700; line-height: 1; }
.rating-v { display: flex; flex-direction: column; font-size: var(--fs-small); color: var(--bone-2); }
.rating-v .sub { font-size: var(--fs-fine); color: var(--bone-3); }
.ratingline .spark { color: var(--bone-3); margin-left: auto; flex: none; }

.lastmatch {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-4); border: 1px solid var(--rule); border-radius: var(--r-md);
  border-left: 3px solid var(--rule);
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.lastmatch.won { border-left-color: var(--won); }
.lastmatch.lost { border-left-color: var(--lost); }
.lastmatch:hover { background: var(--raised); }
.lastmatch img { border-radius: var(--r-sm); flex: none; }
.lastmatch-b { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lastmatch-h { font-size: var(--fs-body); color: var(--bone); }
.lastmatch-r { font-size: var(--fs-small); color: var(--bone-2); }
.lastmatch-kda { margin-left: auto; text-align: right; font-size: var(--fs-small); color: var(--bone-2); }
.lastmatch-kda b { font-family: var(--mono); color: var(--bone); font-weight: 400; }
.lastmatch-kda .sub, .lastmatch-r .sub { display: block; font-size: var(--fs-fine); color: var(--bone-3); }

.workon { font-size: var(--fs-small); color: var(--bone-2); margin-bottom: var(--sp-2); }
.workon-k { font-family: var(--display); }

/* ------------------------------------------------------------- narrow screens */

@media (max-width: 900px) {
  /* The nav moves to its own row below 900px, so the header is taller. Every
     header rule lives here and only here: it used to be split across this and
     an 860 block whose values lost to these ones, so the 860 numbers never
     applied and the real threshold was 900 without saying so. */
  :root { --header-h: 118px; }
  .home { grid-template-columns: minmax(0, 1fr); }
  .home-side { position: static; order: -1; }
  .top { flex-wrap: wrap; align-items: center;
    gap: var(--sp-4); padding: var(--sp-3) var(--sp-4); }
  .top nav { order: 3; width: 100%; overflow-x: auto;
    gap: var(--sp-4); scrollbar-width: none; }
  .top nav::-webkit-scrollbar { display: none; }
  .top nav a { padding: var(--sp-3) 0; }
  .hsearch { flex: 1 1 auto; order: 2; }
  .hsearch-k { display: none; }
  .spacer { display: none; }
  .me-btn { order: 1; margin-left: auto; }
}

@media (max-width: 560px) {
  /* Tables carry generous padding for a mouse. On a phone that padding is the
     difference between a readable row and one that scrolls for no reason. */
  th, td { padding: var(--sp-2); }
  /* The action name and its command stack anyway, so let the name wrap rather
     than forcing the widest column in the table to stay on one line. */
  .binds .name { white-space: normal; min-width: 12ch; }
  /* Anything whose whole purpose is reaching a file in a Deadlock install.
     There is no such file on a phone, and a file picker was the widest thing
     on the Builds tab, pushing the page sideways so it scrolled by accident. */
  .desktop-only { display: none; }

  /* Vertical first. A heading with actions beside it becomes a heading with
     actions under it, rather than a row that has to be scrolled to finish. */
  .sec-row { flex-direction: column; align-items: stretch; gap: var(--sp-2); }
  .sec-row form { width: 100%; }
  .sec-row .btn-ghost, .sec-row button { width: 100%; }

  .me-btn span { display: none; }
  .herocard { flex: 1 1 140px; }
  .form-g { width: 24px; height: 24px; }
  .lastmatch { flex-wrap: wrap; }
  .lastmatch-kda { margin-left: 0; text-align: left; width: 100%; }
  .form-g img { width: 18px; height: 18px; }

  /* Two players side by side leaves each about 140px for an avatar and a
     display-size name. */
  .versus { grid-template-columns: 1fr; gap: var(--sp-4); }

  /* The tab strip is pinned and cannot wrap without pushing the page down, so
     it scrolls sideways instead, with the scrollbar hidden as the header nav
     already does. */
  .gp-tabs { gap: var(--sp-4); overflow-x: auto; scrollbar-width: none; }
  .gp-tabs::-webkit-scrollbar { display: none; }
  .gp-tabs a { white-space: nowrap; }

  /* The action bar already wraps; on a phone it only needs the tighter gap. */
  .gp-bar { gap: var(--sp-2); }
}

/* ------------------------------------------------------------ config wizard */
/* A strict CSP forbids inline style, so every swatch colour is a real class.
   They are generated from crosshair.COLOURS and a test fails if they drift. */

.xhair-stage { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: var(--sp-5) 0; }
.xhair-live { width: 320px; height: 320px; max-width: 100%; display: grid;
  place-items: center; background: var(--ground) center / cover no-repeat;
  border: 1px solid var(--rule); border-radius: var(--r-md); overflow: hidden; }
/* Fixed at 320, and CLIPPED by the wrapper rather than scaled down with it.
   The svg's viewBox is 320 units to 320 pixels, so shrinking it shrinks the
   crosshair, and a preview that claims to show game size stops doing so on
   exactly the screens where it is hardest to notice. The wrapper is
   overflow:hidden and centres its content, so a narrow phone sees less of the
   scene at the right size rather than all of it at the wrong one. */
.xhair-live svg { width: 320px; height: 320px; flex: none; }
.xhair-live.scene-street { background-image: url("/static/art/scene-street.webp"); }
.xhair-live.scene-hall { background-image: url("/static/art/scene-hall.webp"); }
.xhair-live.scene-shrine { background-image: url("/static/art/scene-shrine.webp"); }
.xhair-live.scene-font { background-image: url("/static/art/scene-font.webp"); }
.xhair-live.scene-plaza { background-image: url("/static/art/scene-plaza.webp"); }
.xhair-live.scene-none { background-image: none; }
.scene-pick { margin-top: var(--sp-2); justify-content: center; }
.scene-row { display: flex; align-items: center; justify-content: center;
  gap: var(--sp-3); margin-top: var(--sp-3); }
.scene-step { padding: 2px var(--sp-3); font-family: var(--mono); }
.scene-name { font-size: var(--fs-small); color: var(--bone-2); min-width: 90px;
  text-align: center; }

.xhair-grid { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; }
.xhair input { position: absolute; opacity: 0; pointer-events: none; }
.xhair-cell {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: var(--sp-2); border: 1px solid var(--rule); border-radius: var(--r-md);
  background: var(--ground); cursor: pointer;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.xhair-cell:hover { border-color: var(--rule-hi); }
.xhair input:checked + .xhair-cell { border-color: var(--amber); background: var(--card); }
.xhair input:focus-visible + .xhair-cell { outline: 2px solid var(--amber-hi); outline-offset: 2px; }
.xhair-label { font-size: var(--fs-fine); color: var(--bone-3); }
.xhair input:checked + .xhair-cell .xhair-label { color: var(--bone); }

/* Default fills. The live preview overrides these per shape with a fill
   attribute, which is a presentation attribute and not blocked by the CSP. */
.xhair-thumb [data-role="colour"], .xhair-big [data-role="colour"] { fill: var(--bone); }
.xhair-thumb [data-role="outline"], .xhair-big [data-role="outline"] { fill: var(--xh-outline); }
/* An outline is a stroke. Filling it as well would close the middle, which is
   the whole difference between a ring and a blob for a crosshair with no fill. */
.xhair-thumb [data-stroked], .xhair-big [data-stroked] {
  fill: none; stroke: var(--xh-outline);
}

.swatches { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-4) 0; }
.swatch input { position: absolute; opacity: 0; pointer-events: none; }
.swatch-chip {
  display: block; width: 26px; height: 26px; border-radius: var(--r-sm);
  border: 1px solid var(--rule-hi); cursor: pointer;
  transition: transform var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.swatch-chip:hover { transform: translateY(-1px); }
.swatch input:checked + .swatch-chip { border-color: var(--bone); transform: translateY(-1px); }
.swatch input:focus-visible + .swatch-chip { outline: 2px solid var(--amber-hi); outline-offset: 2px; }
.swatch-white { background: var(--xh-white); }
.swatch-red { background: var(--xh-red); }
.swatch-orange { background: var(--xh-orange); }
.swatch-yellow { background: var(--xh-yellow); }
.swatch-lime { background: var(--xh-lime); }
.swatch-green { background: var(--xh-green); }
.swatch-spring { background: var(--xh-spring); }
.swatch-cyan { background: var(--xh-cyan); }
.swatch-blue { background: var(--xh-blue); }
.swatch-violet { background: var(--xh-violet); }
.swatch-magenta { background: var(--xh-magenta); }
.swatch-black { background: var(--xh-black); }
.alpha { display: flex; align-items: center; gap: var(--sp-2); }
.alpha input { width: 72px; }

.chip-btn {
  padding: var(--sp-2) var(--sp-3); font-size: var(--fs-fine);
  color: var(--bone-2); background: transparent; border-color: var(--rule-hi);
  box-shadow: none; transform: none;
  display: inline-flex; align-items: center; gap: var(--sp-2);
}
.chip-btn:hover { color: var(--bone); background: var(--raised);
  box-shadow: none; transform: none; }
.chip-btn[aria-pressed="true"] { color: var(--bone); border-color: var(--amber); }

/* The library is long enough to bury everything under it, so it scrolls in
   place rather than pushing the launch options off the page. */
.lib-scroll { max-height: 420px; overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid var(--rule); border-radius: var(--r-md);
  padding: 0 var(--sp-4); background: var(--ground); }

.opts { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
.opt { display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3) var(--sp-2) var(--sp-2);
  background: var(--card); border: 1px solid var(--rule-hi);
  border-radius: var(--r-md); font-size: var(--fs-small); cursor: grab; }
.opt[data-dragging] { opacity: .4; }
.opt[data-over] { border-color: var(--amber); }
.opt code { font-family: var(--mono); font-size: var(--fs-fine); color: var(--bone); }
.opt-label { color: var(--bone-3); font-size: var(--fs-fine); }
.opt-unknown code { color: var(--bone-2); }
.opt-x { padding: 0 var(--sp-2); font-size: var(--fs-body); line-height: 1;
  color: var(--bone-3); background: transparent; border: 0; box-shadow: none;
  transform: none; cursor: pointer; }
.opt-x:hover { color: var(--lost); background: transparent; box-shadow: none;
  transform: none; }
.launch-actions input { flex: 1; min-width: 200px; }

.lib-controls { margin: var(--sp-4) 0 var(--sp-3); }
.lib-controls input { flex: 1; }
.lib-head { margin-top: var(--sp-5); }
.lib-row { padding: var(--sp-3) 0; border-bottom: 1px solid var(--rule); }
.lib-cmd { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.lib-cmd code { font-family: var(--mono); font-size: var(--fs-small); color: var(--bone); }
.lib-desc { margin: var(--sp-1) 0 var(--sp-2); font-size: var(--fs-small); color: var(--bone-3); }
.lib-add input { width: 120px; }

.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0 var(--sp-5); }
.chip input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.chip > span {
  display: flex; flex-direction: column; gap: 1px;
  padding: var(--sp-2) var(--sp-3); font-size: var(--fs-small); color: var(--bone-2);
  border: 1px solid var(--rule); border-radius: var(--r-md); cursor: pointer;
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.chip > span:hover { border-color: var(--rule-hi); color: var(--bone); }
.chip input:checked + span { border-color: var(--amber); color: var(--bone); background: var(--card); }
.chip .sub { font-size: var(--fs-fine); }
.chip-free { display: flex; align-items: center; }
.chip-free input[type="text"] { width: 72px; padding: var(--sp-2); font-size: var(--fs-small); }

/* --------------------------------------------------------------- bind editor */
/* Key widths are explicit classes, not a custom property: a per-element layout
   number is not a theme token and does not belong in tokens.css. One unit is
   34px plus the 4px gap a multi-unit key swallows, so width = 38u - 4. */

.kb-wrap { display: flex; gap: var(--sp-4); align-items: flex-end; flex-wrap: wrap;
  margin: var(--sp-4) 0; }
/* The board is a fixed-width drawing, so on a narrow screen it scrolls rather
   than shrinking. Scaling it down is exactly what makes the legends
   unreadable, and body carries overflow-x: hidden, so anything wider than the
   viewport was not merely cut off, it was unreachable: on a phone the right
   half of the keyboard could not be brought into view at all. */
.kb { display: flex; flex-direction: column; gap: var(--sp-1);
  min-width: 0; max-width: 100%; overflow-x: auto;
  overscroll-behavior-x: contain; padding-bottom: var(--sp-1); }
.kb-row { width: max-content; }
.kb-side { display: flex; gap: var(--sp-3); align-items: flex-end; }
.kb-cluster { display: flex; flex-direction: column; gap: var(--sp-1); }
.kb-row { display: flex; gap: var(--sp-1); }

.kb-key, .kb-gap { height: 34px; flex: none; }
.kb-key[data-units="1"], .kb-gap[data-units="1"] { width: 34px; }
.kb-key[data-units="1.25"], .kb-gap[data-units="1.25"] { width: 43.5px; }
.kb-key[data-units="1.5"], .kb-gap[data-units="1.5"] { width: 53px; }
.kb-key[data-units="1.75"], .kb-gap[data-units="1.75"] { width: 62.5px; }
.kb-key[data-units="2"], .kb-gap[data-units="2"] { width: 72px; }
.kb-key[data-units="2.25"], .kb-gap[data-units="2.25"] { width: 81.5px; }
.kb-key[data-units="6.25"], .kb-gap[data-units="6.25"] { width: 233.5px; }

.kb-key {
  display: grid; place-items: center; padding: 0;
  font-family: var(--mono); font-size: 10px; line-height: 1;
  color: var(--bone-3); background: var(--card);
  border: 1px solid var(--rule); border-bottom-width: 2px;
  border-radius: var(--r-sm); cursor: pointer; box-shadow: none;
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease),
              border-color var(--fast) var(--ease);
}
.kb-key:hover { color: var(--bone); border-color: var(--rule-hi); transform: none; }
/* A bound key is lit. That is the entire reason for drawing the board. */
.kb-key[data-bound] { color: var(--on-amber); background: var(--amber); border-color: var(--amber); }
.kb-key[data-bound]:hover { background: var(--amber-hi); border-color: var(--amber-hi); }
.kb-key[data-selected] { outline: 2px solid var(--bone); outline-offset: 1px; }
/* Names we have not seen this game write are drawn quieter than ones we have. */
.kb-key[data-confidence="inferred"]:not([data-bound]) { color: var(--faint); }
.kb-gap { visibility: hidden; }

.mouse-wrap { margin: var(--sp-4) 0; }
.mouse-svg { display: block; }
.mouse-svg .ms-body { fill: var(--card); stroke: var(--rule); }
.mouse-svg .ms-btn { fill: var(--card); stroke: var(--rule); cursor: pointer;
  transition: fill var(--fast) var(--ease); }
.mouse-svg .ms-btn:hover { fill: var(--raised); }
.mouse-svg .ms-btn[data-bound] { fill: var(--amber); stroke: var(--amber); }
.mouse-svg .ms-btn[data-selected] { stroke: var(--bone); stroke-width: 2; }

.kb-bubble {
  display: flex; gap: var(--sp-3); align-items: baseline; min-height: 34px;
  padding: var(--sp-2) var(--sp-3); margin-top: var(--sp-3);
  background: var(--raised); border: 1px solid var(--rule-hi);
  border-radius: var(--r-md);
  font-size: var(--fs-fine); color: var(--bone-2);
}
.kb-bubble-key { display: block; font-family: var(--mono); color: var(--bone); }
.kb-bubble-list { display: block; color: var(--bone-3); }

/* Not a narrow-screen problem, which is how it was first misread. The generic
   input[type=text] rule is width:100% with page-sized padding, so in a table
   cell the padding eats the text and a binding is cut mid-character at any
   viewport width. Compact padding for a compact field, and a minimum that
   fits the longest real binding, "MWHEELDOWN, MOUSE5", with box-sizing
   counted in. */
.bind-input {
  font-family: var(--mono); font-size: var(--fs-fine);
  padding: var(--sp-2) var(--sp-3); min-width: 24ch;
}
.binds td { vertical-align: middle; }
.binds .sub { display: block; font-size: var(--fs-fine); }
.bind-input[data-capturing] { border-color: var(--amber); color: var(--amber-hi); }

/* ------------------------------------------------------------------ vignette */
/* Applied where a panel already has a border and a fill of its own. Anything
   that is only a border with the page showing through gets nothing, because
   darkening the page inside a box looks like a smudge rather than depth. */

.prompt, .empty, .sheet-box, .quick, .lastmatch,
.xhair-live, .bw-catalogue, .bw-phase {
  box-shadow: var(--vignette);
}



/* ------------------------------------------------------------- gameplay shell */
/* Tabs and actions are pinned, the middle scrolls. Actions used to be repeated
   once per stored file, which is how a page ends up with twelve of them. */

/* The whole page is one box. The tab strip and the action bar are its lid and
   its floor, so they carry the box's corners and its padding. They used to be
   full width strips with no horizontal padding at all, which put the first tab
   and the first button hard against the edge of a phone with nothing sealing
   the sides. */
.gp {
  display: flex; flex-direction: column; min-height: calc(100vh - 220px);
  border: 1px solid var(--rule); border-radius: var(--r-md);
  background: var(--ground);
}
/* Ground rather than card, so the strips read as part of the box instead of as
   two separate bands, and so the inputs inside keep the card surface they need
   to stand off it. */
.gp-top { position: sticky; top: var(--header-h); z-index: 15;
  padding: var(--sp-3) var(--sp-4) 0; background: var(--ground);
  border-radius: var(--r-md) var(--r-md) 0 0; }
.gp-tabs { display: flex; gap: var(--sp-5); border-bottom: 1px solid var(--rule-hi); }
.gp-tabs a {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) 0; font-size: var(--fs-body); color: var(--bone-3);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--fast) var(--ease);
}
.gp-tabs a:hover { color: var(--bone); }
.gp-tabs a[aria-current="page"] { color: var(--bone); border-bottom-color: var(--amber); }
.gp-count {
  font-family: var(--mono); font-size: var(--fs-fine); color: var(--bone-3);
  border: 1px solid var(--rule-hi); border-radius: var(--r-pill); padding: 0 6px;
}
.gp-body { flex: 1; padding: 0 var(--sp-4) var(--sp-6); }
.steal {
  margin: 0 0 var(--sp-4); padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-fine); color: var(--bone-2);
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--r-md);
}
.steal-won { border-color: var(--amber-dim); color: var(--bone); }

.gp-applied {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin: var(--sp-3) 0 0; padding: 0 var(--sp-4);
  font-size: var(--fs-fine); color: var(--bone-3);
}
.gp-applied .ok { color: var(--bone-2); }
.gp-applied .off { color: var(--amber); }
.gp-applied .wait { color: var(--bone-3); }

/* One action bar for the whole page, pinned to the bottom. */
.gp-bar {
  position: sticky; bottom: 0; z-index: 15;
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--rule-hi); background: var(--ground);
  border-radius: 0 0 var(--r-md) var(--r-md);
}
.gp-bar .spacer { flex: 1; }
.gp-note { font-size: var(--fs-fine); color: var(--bone-3); }

/* --------------------------------------------------------------------- secrets */

.secret { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin-bottom: var(--sp-4); }
.secret-value {
  font-family: var(--mono); font-size: var(--fs-small); color: var(--bone-2);
  padding: var(--sp-2) var(--sp-3); background: var(--card);
  border: 1px solid var(--rule-hi); border-radius: var(--r-md);
  user-select: all; word-break: break-all;
}
.secret-btn { padding: var(--sp-2) var(--sp-3); }

/* ---------------------------------------------------------- crosshair dials */

.dials { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: var(--sp-3) var(--sp-5); margin-top: var(--sp-4); }
/* The label takes its own row at every width, not just on a phone.
   .dials columns are minmax(260px, 1fr), so even on a wide screen a column is
   260px and the fixed 120px slider plus 62px number plus gaps left the label
   about 54px: enough to show that a setting exists and not enough to say
   which. That is a desktop bug that happened to be worse on mobile. */
.dial { display: grid; grid-template-columns: 1fr 62px; gap: var(--sp-2) var(--sp-3);
  align-items: center; }
.dial-k { grid-column: 1 / -1; }
.dial-bool { grid-template-columns: 1fr auto; }
.dial-bool .dial-k { grid-column: auto; }

/* Below the point where the three-column dial stops working. 120px of slider
   and 62px of number are fixed, so on a narrow column the label is squeezed
   into whatever is left, which was about 54px: enough to show that a setting
   exists and not enough to say which. The label takes its own row instead. */
.dial-k { font-size: var(--fs-small); color: var(--bone-2); }
.dial-n { width: 100%; padding: var(--sp-1) 6px; font-family: var(--mono);
  font-size: var(--fs-fine); text-align: right; }
.dial input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--amber); }

/* Track and thumb have to be styled per engine; there is no shared selector. */
.dial input[type="range"] { -webkit-appearance: none; appearance: none;
  width: 100%; height: 18px; background: transparent; cursor: pointer; }
.dial input[type="range"]::-webkit-slider-runnable-track {
  height: 3px; background: var(--rule-hi); border-radius: var(--r-pill); }
.dial input[type="range"]::-moz-range-track {
  height: 3px; background: var(--rule-hi); border-radius: var(--r-pill); }
.dial input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none;
  width: 14px; height: 14px; margin-top: -6px; border-radius: 50%;
  background: var(--amber); border: 0; }
.dial input[type="range"]::-moz-range-thumb { width: 14px; height: 14px;
  border-radius: 50%; background: var(--amber); border: 0; }
.dial input[type="range"]:focus-visible { outline: 2px solid var(--amber-hi);
  outline-offset: 2px; }

.colourline { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  margin-bottom: var(--sp-3); }
.colourline input[type="color"] { width: 44px; height: 30px; padding: 2px;
  background: var(--card); border: 1px solid var(--rule-hi);
  border-radius: var(--r-md); cursor: pointer; }
.swatch-chip { border: 1px solid var(--rule-hi); }

.xhair-grid button.xhair-cell { font: inherit; box-shadow: none; }
.xhair-grid button.xhair-cell:hover { transform: none; }

/* ------------------------------------------------------------- build wizard */

.bw { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--sp-5);
  align-items: start; }
.bw-phases { display: flex; flex-direction: column; gap: var(--sp-4); }
.bw-phase { margin-top: 0; padding: var(--sp-4); border: 1px solid var(--rule);
  border-radius: var(--r-md); cursor: pointer; box-shadow: var(--vignette);
  transition: border-color var(--fast) var(--ease); }
.bw-phase:hover { border-color: var(--rule-hi); }
.bw-phase[data-active] { border-color: var(--amber); }
.bw-list { list-style: none; margin: var(--sp-3) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 2px; min-height: 40px; }
.bw-picked { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3); background: var(--card);
  border-radius: var(--r-sm); font-size: var(--fs-small); color: var(--bone-2); }
.bw-picked .bw-name { flex: 1; }
.bw-remove { padding: 2px var(--sp-2); font-size: var(--fs-fine);
  border-radius: var(--r-sm);
  color: var(--bone-3); background: transparent; border: 1px solid var(--rule-hi);
  box-shadow: none; }
.bw-remove:hover { color: var(--lost); border-color: var(--lost-bg);
  background: transparent; transform: none; }

.bw-shop { position: sticky; top: calc(var(--header-h) + var(--sp-4)); }
.bw-filters { margin: var(--sp-2) 0; }
.bw-catalogue { list-style: none; margin: var(--sp-3) 0 0; padding: 0;
  max-height: 60vh; overflow: hidden auto; border: 1px solid var(--rule);
  border-radius: var(--r-md); }
.bw-item { border-bottom: 1px solid var(--rule); }
.bw-item:last-child { border-bottom: 0; }
.bw-item[data-used] { opacity: .4; }
.bw-add { display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: var(--sp-2) var(--sp-3); font-size: var(--fs-small); text-align: left;
  color: var(--bone-2); background: transparent; border: 0; border-radius: 0;
  box-shadow: none; }
.bw-add:hover { background: var(--raised); color: var(--bone); transform: none;
  box-shadow: none; }
.bw-add .bw-name { flex: 1; }
.bw-cost, .bw-wr { font-family: var(--mono); font-size: var(--fs-fine); }
.bw-wr { min-width: 46px; text-align: right; }

.linkish { padding: 0; background: transparent; border: 0; box-shadow: none;
  color: var(--bone); font: inherit; text-align: left; }
.linkish:hover { color: var(--amber-hi); background: transparent; transform: none;
  box-shadow: none; }

@media (max-width: 900px) {
  .bw { grid-template-columns: minmax(0, 1fr); }
  .bw-shop { position: static; }
}

/* Build sections: the header is editable, so it has to look like a heading and
   behave like a field. */
.bw-head { display: flex; align-items: center; gap: var(--sp-3); }
.bw-title { flex: 1; padding: 2px 6px; font-family: var(--display);
  font-size: var(--fs-head); font-weight: 600; color: var(--bone);
  background: transparent; border: 1px solid transparent; border-radius: var(--r-sm); }
.bw-title:hover { border-color: var(--rule); }
.bw-title:focus { border-color: var(--amber); outline: none; background: var(--card); }
.bw-move {
  padding: 2px var(--sp-2); font-size: var(--fs-fine);
  color: var(--bone-2); background: transparent; border-color: var(--rule-hi);
  box-shadow: none; transform: none; line-height: 1;
}
.bw-move:hover:not(:disabled) { color: var(--bone); background: var(--raised);
  box-shadow: none; transform: none; }
.bw-move:disabled { opacity: .3; cursor: default; }
/* The per-item note takes its own row under the item, so a long one does not
   squeeze the item name it belongs to. */
.bw-inote {
  flex-basis: 100%; margin-top: var(--sp-1);
  padding: 2px var(--sp-2); font-size: var(--fs-fine);
}

.bw-note { width: 100%; margin-top: var(--sp-2); padding: var(--sp-1) 6px;
  font-size: var(--fs-fine); color: var(--bone-3); background: transparent;
  border: 1px solid transparent; border-radius: var(--r-sm); }
.bw-note:hover { border-color: var(--rule); }
.bw-note:focus { border-color: var(--rule-hi); outline: none; background: var(--card); }
.bw-actions { margin-bottom: var(--sp-4); }
#build-note { width: 100%; padding: var(--sp-2) var(--sp-3); font: inherit;
  font-size: var(--fs-small); color: var(--bone); background: var(--card);
  border: 1px solid var(--rule-hi); border-radius: var(--r-md); resize: vertical; }

/* A player's finished build as category dots. Twelve items fit in a table cell
   where twelve names would not, and the colours are the ones the shop uses. */
.buildcell { white-space: nowrap; line-height: 1; }
.buildcell .cat { margin-right: var(--sp-1); }

/* ------------------------------------------------------------------- facets */

.facets { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: var(--sp-4) var(--sp-5); margin-top: var(--sp-4); }
.facet { display: grid; grid-template-columns: 1fr auto; gap: 2px var(--sp-3);
  align-items: baseline; }
.facet-k { font-size: var(--fs-small); color: var(--bone-2); }
.facet-n { font-family: var(--display); font-size: var(--fs-stat); font-weight: 600;
  line-height: 1.1; }
/* Every bar fills from the left and ends in a tick, so all four read the same
   way and the tick is what you compare. The fill used to start at the midpoint
   and run outwards by twice the distance from fifty, which overflowed the
   track: a score of 80 is a 60%-wide fill starting at 50%, ending at 110%. */
.facet-bar { grid-column: 1 / -1; height: 3px; background: var(--rule);
  position: relative; margin-top: var(--sp-2); }
.facet-bar > i { position: absolute; top: 0; left: 0; height: 100%; max-width: 100%; }
.facet-bar > i.up { background: var(--won); color: var(--won); }
.facet-bar > i.down { background: var(--lost); color: var(--lost); }
/* The end tick, in the fill's own colour so it reads as the same object. */
.facet-fill::after {
  content: ""; position: absolute; right: 0; top: -4px; bottom: -4px;
  width: 2px; background: currentColor; border-radius: var(--r-sm);
}
.facet-scale { background: var(--rule); }

/* A scoreboard row that can be opened, without stopping being a scoreboard. */
.rowmore > summary { cursor: pointer; color: var(--bone-3); list-style: none;
  font-family: var(--mono); }
.rowmore > summary::-webkit-details-marker { display: none; }
.rowmore > summary:hover { color: var(--bone); }
.rowmore-body { display: flex; flex-wrap: wrap; gap: var(--sp-2);
  padding: var(--sp-2) 0; }
.chipstat { font-size: var(--fs-fine); font-family: var(--mono);
  padding: 2px var(--sp-2); border: 1px solid var(--rule-hi);
  border-radius: var(--r-sm); white-space: nowrap; }

/* ------------------------------------------------------------- gold lead */
/* One series, one axis. The fill shows the size of a lead; the midline is
   parity, so crossing it is the game changing hands. */

.leadchart { width: 100%; height: 120px; display: block; margin-top: var(--sp-4); }
.lead-mid { stroke: var(--rule-hi); stroke-width: 1; }
.lead-line { fill: none; stroke-width: 2; }
.lead-area { opacity: .16; stroke: none; }
.lead-0 { stroke: var(--amber); fill: var(--amber); }
.lead-1 { stroke: var(--sapphire); fill: var(--sapphire); }

.timeline { list-style: none; margin: var(--sp-4) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.tl-item { display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); background: var(--card);
  border: 1px solid var(--rule); border-radius: var(--r-md);
  font-size: var(--fs-small); color: var(--bone-2); }
.tl-min { font-family: var(--mono); font-size: var(--fs-fine); color: var(--bone-3);
  min-width: 26px; }

.versus { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5);
  padding-bottom: var(--sp-5); }
.vs-side { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.vs-name { font-family: var(--display); font-size: var(--fs-head); font-weight: 600;
  color: var(--bone); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.oddschart { width: 100%; height: 140px; display: block; margin-top: var(--sp-4); }
.odds-line { fill: none; stroke: var(--amber); stroke-width: 2; }

/* Skill facets are coloured because more is better. Style facets are not: a
   passive player is not a worse player, so the number is placed rather than
   judged. Every bar carries a tick at fifty so a score reads against average
   without having to remember where average is, and it sits above the fill so
   a high score does not bury it. */
.facet-scale { position: relative; }
.facet-scale::before {
  content: ""; position: absolute; left: 50%; transform: translateX(-50%);
  top: -3px; bottom: -3px; z-index: 1;
  width: 2px; background: var(--bone); opacity: .6;
}
.facet-style .facet-n { color: var(--bone-2); }
.facet-mark { position: absolute; left: 0; top: 0; height: 100%; }
.facet-mark::after {
  content: ""; position: absolute; right: 0; top: -4px; bottom: -4px;
  width: 2px; background: var(--bone-2); border-radius: var(--r-sm);
}

/* Touch targets, keyed off the pointer rather than the viewport.
   A 14px slider thumb and a 16px checkbox are fine with a mouse and are half
   the size a finger can reliably hit, and these are the crosshair dials, which
   is the page most likely to be used on a phone while comparing against the
   game. Keying on pointer:coarse rather than a width means a touch laptop gets
   it too and a narrow desktop window does not. */
@media (pointer: coarse) {
  .dial input[type="checkbox"] { width: 22px; height: 22px; }
  /* The label already wraps the control, so the whole row is the target and
     this only makes the row tall enough to be one. */
  .dial-bool { min-height: 44px; align-items: center; }

  .dial input[type="range"] { height: 32px; }
  .dial input[type="range"]::-webkit-slider-thumb { width: 22px; height: 22px; }
  .dial input[type="range"]::-moz-range-thumb { width: 22px; height: 22px; }
  /* The track stays thin. It is the THUMB that has to be catchable, and a
     thick track just looks like a progress bar. */
  .dial input[type="range"]::-webkit-slider-runnable-track { height: 4px; }
  .dial input[type="range"]::-moz-range-track { height: 4px; }

  /* The x that removes a launch option, and the category chips. Same problem,
     smaller blast radius. */
  .opt-x { min-width: 32px; min-height: 32px; }
  .chip-btn { min-height: 36px; }
}

/* ------------------------------------------------------------------ hud editor */

.hud-profile { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-4); }
.hud-profile select { min-width: 180px; }
.hud-profile input[type=text] { width: 220px; padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-small); }
.hud-profile button { padding: var(--sp-2) var(--sp-3); }

.hud-work { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: var(--sp-5);
  align-items: start; margin-top: var(--sp-4); }
.hud-screen { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }

/* The thirds are drawn because they are real: an element is anchored to the
   third its centre falls in, which is what keeps it in that corner at another
   resolution. */
.hud-stage {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border: 1px solid var(--rule-hi); border-radius: var(--r-md);
  background-color: var(--card); box-shadow: var(--vignette);
  background-image:
    linear-gradient(to right, transparent calc(100% / 3 - 1px), var(--rule) calc(100% / 3 - 1px),
      var(--rule) calc(100% / 3), transparent calc(100% / 3),
      transparent calc(200% / 3 - 1px), var(--rule) calc(200% / 3 - 1px),
      var(--rule) calc(200% / 3), transparent calc(200% / 3)),
    linear-gradient(to bottom, transparent calc(100% / 3 - 1px), var(--rule) calc(100% / 3 - 1px),
      var(--rule) calc(100% / 3), transparent calc(100% / 3),
      transparent calc(200% / 3 - 1px), var(--rule) calc(200% / 3 - 1px),
      var(--rule) calc(200% / 3), transparent calc(200% / 3));
  touch-action: none; user-select: none; -webkit-user-select: none;
}

.hud .hud-box {
  position: absolute; display: flex; align-items: flex-start; box-sizing: border-box; min-width: 0;
  padding: 3px 5px; overflow: hidden; text-align: left;
  font-size: var(--fs-fine); font-weight: 500; line-height: 1.25; color: var(--bone-2);
  background: var(--amber-06); border: 1px solid var(--rule-hi);
  border-radius: var(--r-sm); box-shadow: none; cursor: grab;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease),
              color var(--fast) var(--ease);
}
.hud .hud-box span { display: block; overflow: hidden; white-space: nowrap;
  text-overflow: ellipsis; }
.hud .hud-box:hover { transform: none; box-shadow: none; color: var(--bone);
  background: var(--amber-10); border-color: var(--amber-dim); }
.hud .hud-box:active { transform: none; box-shadow: none; }
.hud .hud-box.hud-rough { border-style: dashed; }
.hud .hud-box.is-moved { color: var(--bone); }
.hud .hud-box.is-sel { z-index: 2; color: var(--bone); background: var(--amber-10);
  border-color: var(--amber); }
.hud .hud-box.is-drag { cursor: grabbing; transition: none; }
.hud .hud-box.is-off { z-index: 0; opacity: .35; border-style: dotted;
  pointer-events: none; text-decoration: line-through; }

.hud-guide { position: absolute; z-index: 3; background: var(--sapphire);
  pointer-events: none; }
.hud-guide-x { top: 0; bottom: 0; width: 1px; }
.hud-guide-y { left: 0; right: 0; height: 1px; }

.hud-side-h { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); }
.hud-side-h .sec-h { margin: 0; }
.hud .hud-small { padding: var(--sp-1) var(--sp-3); font-size: var(--fs-fine); }
.hud-small:disabled { opacity: .45; cursor: default; }

.hud-list { list-style: none; margin: var(--sp-3) 0 var(--sp-2); padding: 0;
  border-top: 1px solid var(--rule); }
.hud-list li { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center; gap: var(--sp-2); min-height: 34px; padding: 0 var(--sp-2);
  border-bottom: 1px solid var(--rule); font-size: var(--fs-small); color: var(--bone-2);
  cursor: pointer; }
.hud-list li:hover { background: var(--raised); }
.hud-list li.is-sel { background: var(--raised); color: var(--bone);
  box-shadow: inset 2px 0 0 var(--amber); }
.hud-list li.is-off label { color: var(--bone-3); text-decoration: line-through; }
.hud-list input[type=checkbox] { width: 15px; height: 15px; margin: 0;
  accent-color: var(--amber); }
.hud-list label { overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  cursor: pointer; }
.hud-at { font-family: var(--mono); font-size: var(--fs-fine); color: var(--bone-3);
  font-variant-numeric: tabular-nums; }
.hud .hud-reset { padding: 0 var(--sp-1); font-size: var(--fs-fine); font-weight: 500;
  color: var(--amber); background: none; border: 0; box-shadow: none; }
.hud .hud-reset:hover { color: var(--amber-hi); background: none; transform: none;
  box-shadow: none; text-decoration: underline; }

/* Columns rather than a grid: the health card is five times the height of
   most, and a grid row stretches to it and leaves holes beside it. */
.hud-mods { columns: 3 300px; column-gap: var(--sp-4); margin-top: var(--sp-6); }
.hud-mod { break-inside: avoid; margin-bottom: var(--sp-4); padding: var(--sp-4); background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--r-md); box-shadow: var(--vignette);
  transition: border-color var(--fast) var(--ease); }
.hud-mod.is-on { border-color: var(--amber-dim); }
.hud-mod-h { display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); }
.hud-mod-h h3 { margin: 0; font-size: var(--fs-body); font-weight: 600; color: var(--bone); }
.hud-mod > p { margin: var(--sp-1) 0 0; }
.hud-on { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-small);
  color: var(--bone-2); cursor: pointer; }
.hud-on input { width: 16px; height: 16px; margin: 0; accent-color: var(--amber); }
.hud-mod .dials { grid-template-columns: 1fr; gap: var(--sp-3); margin-top: var(--sp-4); }
.hud-mod .dial input[type="color"] { width: 44px; height: 28px; padding: 2px;
  background: var(--card); border: 1px solid var(--rule-hi); border-radius: var(--r-md);
  cursor: pointer; }
.hud-mod .dial select { max-width: 190px; }
.hud-mod .dial input.dial-n { padding: var(--sp-1) 6px; }

.gp-bar button:disabled { opacity: .45; cursor: default; transform: none; box-shadow: none; }
.hud-profile button:disabled { opacity: .45; cursor: default; transform: none; box-shadow: none; }
.hud-result { margin: 0; padding: 0 var(--sp-4) var(--sp-3); }

@media (max-width: 900px) {
  .hud-work { grid-template-columns: 1fr; }
  .hud-profile input[type=text] { flex: 1; min-width: 140px; }
}

/* ------------------------------------------------------------- focus areas */

/* auto-fill keeps the empty track, so a single column stays half width */
.focus { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(420px, 100%), 1fr));
  gap: var(--sp-5); margin-top: var(--sp-4); }
.focus-h { margin: 0 0 var(--sp-3); font-size: var(--fs-small); font-weight: 600;
  color: var(--bone-3); text-transform: uppercase; letter-spacing: .06em; }
.focus-item { padding: var(--sp-3) 0; border-top: 1px solid var(--rule); }
.focus-k { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  font-size: var(--fs-body); font-weight: 600; color: var(--bone); }
.focus-p { font-family: var(--display); font-size: var(--fs-stat); font-weight: 700; line-height: 1; }
.focus-n { margin: var(--sp-1) 0 0; font-size: var(--fs-small); color: var(--bone-2);
  font-variant-numeric: tabular-nums; }
.focus-n b { color: var(--bone); font-weight: 600; }
.focus-tip { margin: var(--sp-2) 0 0; font-size: var(--fs-small); color: var(--bone-3);
  max-width: 62ch; }

/* --------------------------------------------------------------- lane phase */

.lane-me { margin: var(--sp-3) 0 var(--sp-4); font-size: var(--fs-body); color: var(--bone-2);
  font-variant-numeric: tabular-nums; }
.lane-me b { font-weight: 700; }
.lane-heroes { display: inline-flex; gap: var(--sp-1); vertical-align: middle; }
.lane-heroes img { border-radius: var(--r-sm); }

/* ------------------------------------------------- people and hero matchups */

.people { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
  gap: var(--sp-5); margin-top: var(--sp-4); }
.person { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto 3.2em; align-items: center;
  gap: var(--sp-3); padding: var(--sp-2) 0; border-top: 1px solid var(--rule);
  font-size: var(--fs-small); color: var(--bone-2); font-variant-numeric: tabular-nums; }
a.person:hover .person-n { color: var(--amber-hi); }
.person img { border-radius: var(--r-sm); }
.person-n { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--bone); }
.person-g { color: var(--bone-3); }
.person-w { text-align: right; font-weight: 600; }
