/* ============================================================
   CSFloat Seed Collector — sharp light theme
   ============================================================
   Deliberately NOT the soft/rounded/glowing look:
     - Space Grotesk for UI (flat terminals, angular bowls, a real voice)
     - JetBrains Mono for every number, so columns line up and read technical
     - 2px radii, hairline rules, hard 2px offset shadows instead of blur
     - no gradient rims, no glow; hover INVERTS (ink fill, paper text)
     - monochrome by default; colour is reserved for status and data only
   Motion is fast and transform-based (120–180ms), not floaty.
   ============================================================ */

:root {
  --paper:  #f2f2ef;
  --card:   #ffffff;
  --ink:    #111111;
  --ink-2:  #4a4a46;
  --ink-3:  #8a8a83;
  --rule:   #dedcd6;
  --rule-2: #c6c3ba;

  --ok:   #0f7a2a;
  --err:  #c02626;

  /* Freshness ramp for per-skin scan age. NOT --ok/--warn/--err: those three
     measure ΔE 1.6 apart under protanopia (green and amber are the same colour
     to a red-green colourblind reader) and 14.0 between amber and red even
     with full colour vision. These are the validated status steps — 11.3
     protan, 27.6 normal — so the three bands are actually distinguishable.
     Amber is sub-3:1 on this surface by design, which is why every pip also
     carries a SHAPE and the list carries a legend: colour never decides
     anything on its own here. */
  --st-good:  #0ca30c;
  --st-warn:  #fab219;
  --st-crit:  #d03b3b;
  --live: #7b3fe4;
  /* Marking the striking digits inside a float — a highlighter, not a
     status: warm enough to find at a glance, dark enough to read on. */
  --hot:    #8a4b00;
  --hot-bg: #ffe9b8;

  --r: 2px;

  /* Theme plumbing — see the dark block right after :root. */
  --surface: #ffffff;        /* inputs, chips, list rows sitting on a card */
  --on-ink: #ffffff;         /* text/icons on an --ink filled button or chip */
  --grid-rgb: 17,17,17;      /* the faint background grid and hatching */
  --shadow-rgb: 17,17,17;    /* hard offset shadows */
  --inv-track-bg: #2a2a27;   /* a progress track inside an ink-filled hover */
  --inv-track-border: #4a4a46;
  color-scheme: light;

  /* body's own padding, named so full-bleed elements can cancel it
     exactly instead of guessing — see .topbar. */
  --pad-x: 20px;
  --pad-top: 24px;
}

/* ============================================================
   Dark mode — same sharp look, inverted
   ============================================================
   Set by theme.js as <html data-theme="dark"> (saved per browser, and it
   follows the system setting until you pick one). Only tokens change here:
   every rule above reads colours through these variables, so the hover
   "inversion" still works — ink becomes the light fill, paper the dark text. */
:root[data-theme="dark"] {
  --paper:  #0e0f11;
  --card:   #17181b;
  --surface:#1d1e22;
  --ink:    #ecebe6;
  --ink-2:  #b3b2ab;
  --ink-3:  #7e7d77;
  --rule:   #2a2b30;
  --rule-2: #3b3c42;
  --on-ink: #0e0f11;

  --ok:   #45c46a;
  --err:  #f06464;
  --live: #a883ff;
  --hot:    #ffcf73;
  --hot-bg: #3b2c0a;

  --grid-rgb: 255,255,255;
  --shadow-rgb: 0,0,0;
  --inv-track-bg: #cfcec8;
  --inv-track-border: #9d9c96;
  color-scheme: dark;
}
:root[data-theme="dark"] body::before { opacity: .55; }
:root[data-theme="dark"] img { filter: none; }
:root[data-theme="dark"] ::selection { background: var(--ink); color: var(--on-ink); }

/* Rarity-coloured skin names (Consumer grey, Industrial light blue…) are
   Steam's colours for a dark background; on paper they wash out. */
:root:not([data-theme="dark"]) th[style*="color"] { filter: brightness(.72) saturate(1.25); }

/* The theme switch in the top bar. */
.theme-toggle {
  min-width: 34px;
  padding: 6px 9px !important;
  font-size: 14px;
  line-height: 1;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* The browser's own [hidden] rule is just `display:none`, so ANY author
   rule setting display — .build-grid's `display:grid`, a flex row —
   silently outranks it and the element stays on screen. */
[hidden] { display: none !important; }

body {
  font-family: 'Space Grotesk', 'Arial Narrow', Helvetica, sans-serif;
  background: var(--paper);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.5;
  padding: var(--pad-top) var(--pad-x) 60px;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

/* Faint engineering grid — technical, not a soft wash */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(to right,  rgba(var(--grid-rgb),.045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(var(--grid-rgb),.045) 1px, transparent 1px);
  background-size: 34px 34px;
  mask-image: radial-gradient(circle at 50% 34%, #000 0%, transparent 78%);
  -webkit-mask-image: radial-gradient(circle at 50% 34%, #000 0%, transparent 78%);
}

/* ---- Layout ---------------------------------------------------------- */
.layout {
  display: grid;
  grid-template-columns: 262px minmax(0, 1fr) 286px;
  gap: 16px;
  max-width: 1680px;
  margin: 0 auto;
  align-items: start;
}
.main { min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.sidebar { position: sticky; top: 24px; max-height: calc(100vh - 48px); overflow-y: auto; }

/* ---- Header ---------------------------------------------------------- */
header { padding: 0 2px; }

.header-bar {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 20px;
  flex-wrap: wrap;
  padding-bottom: 12px;
  border-bottom: 2px solid var(--ink);
}
.header-text { min-width: 0; }
.header-actions { display: flex; gap: 6px; flex-wrap: wrap; flex: none; }

h1 {
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  line-height: 1.05;
}
.sub {
  font-size: 12px;
  color: var(--ink-2);
  margin-top: 6px;
  max-width: 66ch;
  letter-spacing: -0.005em;
}

/* ---- Cards ----------------------------------------------------------- */
.card {
  background: var(--card);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  padding: 16px 18px;
  box-shadow: 2px 2px 0 rgba(var(--shadow-rgb),.055);
  transition: box-shadow .16s ease, border-color .16s ease;
  animation: cut .28s ease both;
}
.card:hover { border-color: var(--ink); box-shadow: 3px 3px 0 rgba(var(--shadow-rgb),.1); }

.sidebar-left { animation-delay: .01s; }
.main .card:nth-of-type(1) { animation-delay: .05s; }
.main .card:nth-of-type(2) { animation-delay: .09s; }
.main .card:nth-of-type(3) { animation-delay: .13s; }
.sidebar-right { animation-delay: .17s; }

@keyframes cut {
  from { opacity: 0; transform: translateY(-5px); }
  to   { opacity: 1; transform: none; }
}

.card h2 {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .11em;
  color: var(--ink);
  margin-bottom: 11px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--rule);
  display: flex;
  align-items: baseline;
  gap: 7px;
}
.card h3 {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--ink-3);
  margin-bottom: 6px;
}

.hint { font-size: 12px; color: var(--ink-2); margin-bottom: 11px; }
.hint:last-child { margin-bottom: 0; }

code {
  font-family: 'JetBrains Mono', ui-monospace, Consolas, monospace;
  font-size: 11px;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 0;
  padding: 1px 5px;
  color: var(--ink);
}

/* ---- Controls -------------------------------------------------------- */
.row { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; }
.row:last-child { margin-bottom: 0; }

input[type="text"], select {
  font-family: inherit;
  font-size: 12.5px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  padding: 8px 10px;
  outline: none;
  transition: border-color .14s ease, box-shadow .14s ease;
  min-width: 0;
}
input[type="text"] { flex: 1 1 210px; }
select { cursor: pointer; flex: 0 1 auto; }
input[type="text"]::placeholder { color: var(--ink-3); }

input[type="text"]:hover, select:hover { border-color: var(--ink-2); }
input[type="text"]:focus, select:focus {
  border-color: var(--ink);
  box-shadow: 2px 2px 0 rgba(var(--shadow-rgb),.14);
}

/* ---- Buttons: hard invert, no glow ----------------------------------- */
button {
  font-family: inherit;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ink);
  background: var(--surface);
  cursor: pointer;
  border: 1px solid var(--ink);
  border-radius: var(--r);
  padding: 8px 15px;
  transition: background .14s ease, color .14s ease,
              transform .1s ease, box-shadow .14s ease;
}
button:hover:not(:disabled) {
  background: var(--ink);
  color: var(--on-ink);
  box-shadow: 2px 2px 0 rgba(var(--shadow-rgb),.22);
}
button:active:not(:disabled) { transform: translate(2px, 2px); box-shadow: none; }
button:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
button:disabled {
  cursor: not-allowed;
  color: var(--ink-3);
  background: var(--paper);
  border-color: var(--rule-2);
}

/* Primary — already inverted, so it reverses on hover */
#startBtn { background: var(--ink); color: var(--on-ink); }
#startBtn:hover:not(:disabled) { background: var(--surface); color: var(--ink); }
#startBtn:disabled { background: var(--paper); color: var(--ink-3); border-color: var(--rule-2); }

#stopBtn:hover:not(:disabled) { background: var(--err); border-color: var(--err); color: #fff; }

.nav-btn { padding: 7px 13px; }

/* ---- Status pill: squared off ---------------------------------------- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  padding: 7px 12px;
  border-radius: var(--r);
  background: var(--surface);
  border: 1px solid var(--rule-2);
  color: var(--ink-2);
}
.pill::before { content: ''; width: 6px; height: 6px; background: var(--ink-3); flex: none; }
.pill.ok      { border-color: var(--ok);   color: var(--ok);   }
.pill.ok::before      { background: var(--ok);   }
.pill.err     { border-color: var(--err);  color: var(--err);  }
.pill.err::before     { background: var(--err);  }
.pill.info    { border-color: var(--ink);  color: var(--ink);  }
.pill.info::before    { background: var(--ink);  }
.pill.running { border-color: var(--live); color: var(--live); }
.pill.running::before { background: var(--live); animation: blink .9s steps(1,end) infinite; }
@keyframes blink { 0%,60% { opacity: 1; } 61%,100% { opacity: .15; } }

/* ---- Progress: stepped, not a soft bar -------------------------------- */
.progress-wrap {
  height: 8px;
  background: var(--paper);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  overflow: hidden;
  margin: 12px 0 10px;
}
.progress-bar {
  height: 100%;
  width: 0%;
  background-image: repeating-linear-gradient(
    -45deg, var(--ink) 0 5px, var(--ink-2) 5px 10px);
  background-size: 200% 100%;
  transition: width .2s linear;
  animation: march .7s linear infinite;
}
@keyframes march { from { background-position: 0 0; } to { background-position: 28px 0; } }

.stats-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ink-3);
}
.stats-row b {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: var(--ink);
  letter-spacing: 0;
}

/* ---- Empty states ----------------------------------------------------- */
.empty-state {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-3);
  padding: 16px 4px;
  text-align: center;
}

/* ---- Tracked guns ----------------------------------------------------- */
.tracked-list { display: flex; flex-direction: column; gap: 12px; }

.tracked-category-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink);
  padding: 3px 0;
  margin-bottom: 7px;
  border-top: 2px solid var(--ink);
  border-bottom: 1px solid var(--rule);
}
.tracked-category { margin-bottom: 12px; }
.tracked-category:last-child { margin-bottom: 0; }

.tracked-gun-group { margin-bottom: 9px; padding-left: 7px; border-left: 1px solid var(--rule); }
.tracked-gun-group:last-child { margin-bottom: 0; }
.tracked-gun-name {
  font-size: 11.5px; font-weight: 700; color: var(--ink);
  margin-bottom: 5px; letter-spacing: -0.01em;
}

.tracked-skins { display: flex; flex-wrap: wrap; gap: 4px; }
.tracked-skin-btn {
  font-family: inherit;
  font-size: 10.5px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  padding: 3px 8px;
  border-radius: var(--r);
  border: 1px solid var(--rule-2);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.tracked-skin-btn:hover { background: var(--ink); border-color: var(--ink); color: var(--on-ink); box-shadow: none; }
.tracked-skin-btn.active { background: var(--ink); border-color: var(--ink); color: var(--on-ink); }

/* ---- Who's online / suggested next ------------------------------------ */
.online-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 11.5px;
}
.online-row:last-child { border-bottom: none; }
.online-row-self { color: var(--ink); }
.online-name { font-weight: 700; color: var(--ink); flex: 0 0 auto; white-space: nowrap; }
.online-you { font-weight: 500; color: var(--ink-3); text-transform: uppercase; font-size: 9.5px; letter-spacing: .06em; }
.online-doing {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-2);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.suggest-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  text-align: left;
  padding: 7px 9px;
  margin-bottom: 4px;
  border-radius: var(--r);
  border: 1px solid var(--rule-2);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
  font-size: 11px;
  transition: background .12s, color .12s, border-color .12s;
}
.suggest-btn:last-child { margin-bottom: 0; }
.suggest-btn:hover { background: var(--ink); border-color: var(--ink); color: var(--on-ink); box-shadow: none; }
.suggest-btn:hover .suggest-tag-new { color: var(--st-good); }
.suggest-btn:hover .suggest-tag-stale { color: var(--hot); }
.suggest-tag {
  flex: none;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  padding: 2px 6px;
  border-radius: var(--r);
  border: 1px solid currentColor;
}
.suggest-tag-new { color: var(--ok); }
.suggest-tag-stale { color: var(--ink-3); }
.suggest-skin { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- Rarity panel ----------------------------------------------------- */
.rarity-section { margin-bottom: 15px; }
.rarity-section:last-child { margin-bottom: 0; }

.rarity-wear-select { width: 100%; margin-bottom: 6px; font-size: 11.5px; padding: 6px 8px; }
.rarity-expand-btn { width: 100%; padding: 5px 10px; font-size: 9.5px; margin-bottom: 7px; }

.rarity-list { display: flex; flex-direction: column; gap: 0; max-height: 170px; overflow: hidden; }
.rarity-list.expanded { max-height: 460px; overflow-y: auto; }

.rarity-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  padding: 6px 7px;
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
  transition: background .12s, padding-left .12s;
}
.rarity-item:hover { background: var(--paper); padding-left: 11px; }
.rarity-item-name { color: var(--ink); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rarity-item-stat {
  color: var(--ink-3); flex: none; font-size: 9px;
  text-transform: uppercase; letter-spacing: .08em;
}
.rarity-item-value {
  font-family: 'JetBrains Mono', monospace;
  color: var(--ink); font-weight: 700; font-size: 11px;
}
.rarity-list .empty-state { padding: 10px 4px; }

/* ---- Results table ---------------------------------------------------- */
#resultsWrap { overflow-x: auto; }

table { border-collapse: collapse; width: 100%; font-size: 12px; }
th, td { padding: 7px 12px; text-align: left; border-bottom: 1px solid var(--rule); }
th {
  font-size: 9.5px; font-weight: 700; letter-spacing: .11em;
  text-transform: uppercase; color: var(--ink-3);
  background: var(--surface); border-bottom: 2px solid var(--ink);
  position: sticky; top: 0;
}
td.label { font-weight: 700; color: var(--ink); }
td.val { font-family: 'JetBrains Mono', monospace; color: var(--ink); }
tbody tr { transition: background .1s; }
tbody tr:hover { background: var(--paper); }
tbody tr:last-child td { border-bottom: none; }

/* ---- Scrollbars ------------------------------------------------------- */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb { background: var(--rule-2); border: 2px solid var(--paper); }
::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }

/* ---- Responsive ------------------------------------------------------- */
@media (max-width: 1180px) {
  .layout { grid-template-columns: 1fr; }
  .sidebar { position: static; max-height: none; }
  .sidebar-left { order: 2; }
  .main { order: 1; }
  .sidebar-right { order: 3; }
}
@media (max-width: 560px) {
  :root { --pad-x: 12px; --pad-top: 14px; }
  body { padding: var(--pad-top) var(--pad-x) 40px; }
  .card { padding: 13px 13px; }
  .row > input[type="text"], .row > select { flex: 1 1 100%; }
  h1 { font-size: 19px; }
}

/* ---- Motion off ------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ============================================================
   Scan coverage
   ============================================================ */
.cov-stat {
  font-size: 12px;
  color: var(--ink-2);
  margin-bottom: 8px;
  letter-spacing: -0.005em;
}
.cov-stat b {
  font-family: 'JetBrains Mono', monospace;
  font-size: 14px;
  color: var(--ink);
}
.cov-pct {
  float: right;
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  color: var(--ink);
}

.cov-track {
  display: block;
  height: 5px;
  background: var(--paper);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  overflow: hidden;
}
.cov-track-lg { height: 9px; margin-bottom: 14px; }
.cov-fill {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--ink);
  transition: width .35s cubic-bezier(.3,.8,.4,1);
}

/* Segmented filter — the recommendation mode */
.cov-tabs {
  display: flex;
  gap: 0;
  margin-bottom: 12px;
  border: 1px solid var(--ink);
  border-radius: var(--r);
  overflow: hidden;
  width: fit-content;
}
.cov-tab {
  border: none;
  border-right: 1px solid var(--ink);
  border-radius: 0;
  padding: 6px 13px;
  font-size: 9.5px;
  background: var(--surface);
  box-shadow: none;
}
.cov-tab:last-child { border-right: none; }
.cov-tab:hover:not(.active) { background: var(--paper); color: var(--ink); box-shadow: none; }
.cov-tab.active { background: var(--ink); color: var(--on-ink); }

.cov-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  /* Every collection renders now, so this scrolls instead of truncating.
     Sized so the whole open panel fits a laptop screen without the page
     itself having to scroll to reach the controls. */
  max-height: 330px;
  overflow-y: auto;
  border: 1px solid var(--rule);
  border-radius: var(--r);
}
.cov-list .empty-state { padding: 18px 4px; }

.cov-row { border-bottom: 1px solid var(--rule); }
.cov-row:last-child { border-bottom: none; }
.cov-row.open { background: var(--paper); }

.cov-head {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  border: none;
  background: none;
  box-shadow: none;
  padding: 8px 10px;
  text-transform: none;
  letter-spacing: -0.005em;
  font-size: 12px;
  font-weight: 600;
  border-radius: 0;
}
.cov-head:hover { background: var(--ink); color: var(--on-ink); box-shadow: none; }
.cov-head:hover .cov-name { text-decoration: underline; }
/* On the inverted row every child must flip too, or the count and the
   meta line stay dark-on-dark. */
.cov-head:hover .cov-count,
.cov-head:hover .cov-meta,
.cov-head:hover .cov-chevron { color: var(--on-ink); }
.cov-head:hover .cov-track { border-color: var(--inv-track-border); background: var(--inv-track-bg); }
.cov-head:active { transform: none; }

/* Collection image — no frame. These are transparent artwork, and boxing
   each one in a white chip with a rule around it read as a stack of little
   cards competing with the row itself. The fixed box is kept: it is what
   keeps rows aligned whether or not the remote image loads, and it is why
   .cov-img-blank still reserves the same space while showing nothing. */
.cov-img {
  width: 46px;
  height: 34px;
  flex: none;
  object-fit: contain;
}
.cov-img-blank { display: inline-block; }

.cov-body { flex: 1; min-width: 0; display: block; }

.cov-title {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 2px;
}

.cov-chevron {
  font-size: 9px;
  color: var(--ink-3);
  transition: transform .14s ease;
  display: inline-block;
  flex: none;
}
.cov-row.open .cov-chevron { transform: rotate(90deg); }

.cov-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cov-count {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-2);
  flex: none;
}

.cov-meta {
  display: block;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-3);
  margin-bottom: 5px;
}

.cov-missing {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 2px 10px 10px 66px;   /* aligns under the collection title */
  max-height: 340px;
  overflow-y: auto;
}

.cov-skin {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  text-align: left;
  font-family: inherit;
  font-size: 11px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  padding: 5px 7px;
  border: none;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
  background: none;
  color: var(--ink-2);
  box-shadow: none;
}
.cov-skin:last-child { border-bottom: none; }
.cov-skin:hover { background: var(--ink); color: var(--on-ink); box-shadow: none; }
.cov-skin:active { transform: none; }

/* Tick box — an empty square for not-yet-scanned, a tick once captured.
   The skin stays listed either way. */
.cov-check {
  flex: none;
  width: 15px;
  height: 15px;
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  background: var(--surface);
  color: transparent;
  font-size: 10px;
  font-weight: 700;
  line-height: 13px;
  text-align: center;
}
.cov-skin.done .cov-check { background: var(--ok); border-color: var(--ok); color: #fff; }
.cov-skin.done .cov-skin-name { color: var(--ink-3); }
.cov-skin:hover .cov-check { border-color: var(--on-ink); }

.cov-skin-body { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; }
.cov-skin-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Float-range bar: the track is the full 0–1 scale, the fill is this skin's
   slice of it, so two skins are directly comparable. */
.cov-skin-float { display: flex; align-items: center; gap: 7px; flex: none; }
.cov-float {
  position: relative;
  display: block;
  width: 96px;
  height: 5px;
  background: var(--paper);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  overflow: hidden;
}
.cov-float-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  background: var(--ink);
  border-radius: var(--r);
}
.cov-skin.done .cov-float-fill { background: var(--ok); }
.cov-skin:hover .cov-float { border-color: var(--inv-track-border); background: var(--inv-track-bg); }
.cov-skin:hover .cov-float-fill { background: var(--on-ink); }

.cov-float-txt {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  color: var(--ink-3);
  width: 76px;
  flex: none;
  white-space: nowrap;   /* "0.06 – 0.76" was wrapping onto two lines */
  text-align: right;
}
.cov-skin:hover .cov-float-txt { color: var(--on-ink); }

.cov-more {
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-3);
  align-self: center;
  padding-left: 4px;
}

/* ---- Scan activity log ------------------------------------------------ */
.log-heading { margin-top: 14px; padding-top: 11px; border-top: 1px solid var(--rule); }

.scan-log {
  max-height: 190px;
  overflow-y: auto;
  border: 1px solid var(--rule);
  border-radius: var(--r);
  background: var(--paper);
}
.scan-log .empty-state { padding: 14px 4px; }

.log-line {
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 5px 9px;
  font-size: 11px;
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}
.log-line:last-child { border-bottom: none; }

/* The newest line sits on top and is marked, so the current step is
   obvious without reading timestamps. */
.log-line.latest { box-shadow: inset 3px 0 0 var(--ink); }
.log-line.ok.latest  { box-shadow: inset 3px 0 0 var(--ok);  }
.log-line.err.latest { box-shadow: inset 3px 0 0 var(--err); }

.log-time {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--ink-3);
  flex: none;
}
.log-text { flex: 1; color: var(--ink-2); }
.log-line.ok  .log-text { color: var(--ok);  font-weight: 600; }
.log-line.err .log-text { color: var(--err); font-weight: 600; }

.log-count {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 700;
  color: var(--ink-3);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  padding: 0 5px;
  flex: none;
}

/* ---- Skin profile (what this skin can actually have) ------------------ */
.skin-profile { margin-bottom: 4px; }
.skin-profile .empty-state { padding: 12px 4px; text-align: left; }

.sp-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.sp-float {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
  border: 1px solid var(--ink);
  border-radius: var(--r);
  padding: 2px 7px;
}
.sp-notes {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--err);
  font-weight: 700;
}

table.sp-grid { width: auto; border-collapse: collapse; font-size: 11px; }
table.sp-grid th, table.sp-grid td {
  border: 1px solid var(--rule);
  padding: 4px 12px;
  text-align: center;
}
table.sp-grid th {
  font-size: 9px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: var(--paper);
  border-bottom: 1px solid var(--rule-2);
  position: static;
}
table.sp-grid th.sp-off { color: var(--ink-3); text-decoration: line-through; }

td.sp-wear {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  color: var(--ink);
  background: var(--paper);
  text-align: left;
}
td.sp-yes { color: var(--ok); font-size: 13px; line-height: 1; }
td.sp-no  { color: var(--rule-2); cursor: help; }

tr.sp-row-off td.sp-wear { color: var(--ink-3); text-decoration: line-through; }
tr.sp-row-off { background: repeating-linear-gradient(-45deg,
  transparent 0 4px, rgba(var(--grid-rgb),.028) 4px 8px); }

.sp-warn {
  margin-top: 7px;
  font-size: 10px;
  color: var(--warn, #a86a00);
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* ---- Collection run button + queue ------------------------------------ */
.cov-rowtop { display: flex; align-items: stretch; gap: 0; }
.cov-rowtop .cov-head { flex: 1; min-width: 0; }

.cov-run {
  flex: none;
  align-self: center;
  margin-right: 10px;
  padding: 5px 11px;
  font-size: 9.5px;
  white-space: nowrap;
}
.cov-complete {
  flex: none;
  align-self: center;
  margin-right: 10px;
  padding: 5px 11px;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ok);
  border: 1px solid var(--ok);
  border-radius: var(--r);
  white-space: nowrap;
}

.queue-bar {
  margin-top: 12px;
  padding: 9px 11px;
  border: 1px solid var(--ink);
  border-radius: var(--r);
  background: var(--paper);
}
.queue-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 6px;
}
.queue-name {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.queue-count {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  flex: none;
}
.queue-track {
  height: 6px;
  background: var(--surface);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  overflow: hidden;
}
.queue-fill {
  height: 100%;
  width: 0%;
  background: var(--ink);
  transition: width .35s cubic-bezier(.3,.8,.4,1);
}
.queue-meta {
  margin-top: 5px;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- Section nav (DBA / Marketplace) ---------------------------------- */
.section-nav {
  display: flex;
  border: 1px solid var(--ink);
  border-radius: var(--r);
  overflow: hidden;
  flex: none;
}
.section-tab {
  padding: 7px 15px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--ink);
  background: var(--surface);
  text-decoration: none;
  border-right: 1px solid var(--ink);
  transition: background .14s ease, color .14s ease;
  white-space: nowrap;
}
.section-tab:last-child { border-right: none; }
.section-tab:hover { background: var(--paper); }
.section-tab.active { background: var(--ink); color: var(--on-ink); }
.section-tab.active:hover { background: var(--ink); }

h1 strong, .sub strong { font-weight: 700; color: var(--ink); }

/* ---- Top bar ----------------------------------------------------------
   Section nav moved out of each page's header and up to the top-left, so
   the pages themselves carry only their own content. Settings sits at the
   end of the same group: it IS a section, just an infrequent one. */
.topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 0 24px;
  height: 46px;
  background: var(--card);
  border-bottom: 1px solid var(--ink);
  position: sticky;
  top: 0;
  z-index: 20;
  /* The cards sit inboard of body's padding; the bar is meant to touch the
     window edges, so it cancels exactly that padding — read from the token
     rather than hard-coded, since the 560px breakpoint changes it. */
  margin: calc(var(--pad-top) * -1) calc(var(--pad-x) * -1) 20px;
}
.topbar-tabs { display: flex; align-items: stretch; height: 100%; }
.topbar-tab {
  display: flex;
  align-items: center;
  padding: 0 15px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color .12s, border-color .12s, background .12s;
  white-space: nowrap;
}
.topbar-tab:hover { color: var(--ink); background: var(--paper); }
.topbar-tab.active { color: var(--ink); border-bottom-color: var(--ink); }
/* Settings is a utility, not a destination — same row, quieter, set apart. */
.topbar-tab.util { margin-left: 10px; color: var(--ink-3); }
.topbar-tab.util::before {
  content: '';
  width: 1px;
  height: 14px;
  background: var(--rule-2);
  margin-right: 14px;
}
.topbar-tab.util:hover { color: var(--ink); }
.topbar-spacer { flex: 1; }
.topbar-actions { display: flex; gap: 6px; }
.topbar-actions button { margin: 0; }
@media (max-width: 700px) {
  .topbar { height: auto; padding: 6px 14px; margin-bottom: 16px; }
  .topbar-tabs { flex-wrap: wrap; }
  .topbar-tab { padding: 8px 10px; border-bottom-width: 2px; }
}

/* Pages no longer carry their own nav, so the header is title-only. */
.page-head { padding: 0 2px; }

/* ---- "Go set this up" banner ------------------------------------------
   The credential fields left the main pages; what must NOT leave is the
   warning when nothing is saved, because a scan that silently does nothing
   is the worst failure mode this app has. */
.setup-warning {
  border: 1px solid var(--err);
  border-left-width: 3px;
  border-radius: var(--r);
  background: var(--card);
  padding: 10px 13px;
  font-size: 12px;
  color: var(--ink);
}
.setup-warning a { color: var(--err); font-weight: 700; }

/* ---- Marketplace ------------------------------------------------------ */
.mkt-count {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .04em;
  color: var(--ink-3);
  text-transform: none;
}
/* The table is wider than the card on a narrow window; scroll it rather
   than letting the whole page scroll sideways. */
.mkt-results { overflow-x: auto; }
.mkt-results table { min-width: 640px; }

/* Fixed box whether or not the image loads, so rows never jump as Steam's
   CDN fills them in one by one. */
.mkt-img {
  display: block;
  width: 54px;
  height: 40px;
  object-fit: contain;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r);
}
.mkt-img-blank { background: var(--paper); }
.mkt-results td:first-child { width: 54px; padding-right: 0; }

.mkt-link { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--rule-2); }
.mkt-link:hover { border-bottom-color: var(--ink); }

.mkt-price { font-weight: 700; white-space: nowrap; }

/* ---- Rare finds (Marketplace left rail) -------------------------------- */
.rare-tools { display: flex; gap: 6px; margin-bottom: 10px; }
.rare-tools select { flex: 1; font-size: 11px; padding: 6px 8px; }
.rare-list { display: flex; flex-direction: column; max-height: 62vh; overflow-y: auto; }
.rare-item {
  display: block;
  padding: 9px 2px;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
  transition: background .1s, padding-left .1s;
}
.rare-item:last-child { border-bottom: none; }
.rare-item:hover { background: var(--paper); padding-left: 7px; }
.rare-name {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 3px;
}
.rare-float {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--ink);
  letter-spacing: -.02em;
}
/* The whole point of a rare find is WHICH digits are striking, so the
   matched run is marked rather than left for the eye to find. */
.rare-float mark { background: var(--hot-bg); color: var(--hot); padding: 0 1px; }
.rare-meta {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 3px;
  font-size: 10px;
  color: var(--ink-3);
}
.rare-tags { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 4px; }
.rare-tag {
  font-size: 9px;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  padding: 1px 4px;
  color: var(--ink-2);
  white-space: nowrap;
}

/* ---- Trades ------------------------------------------------------------ */
.trade-tools { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 12px; }

.tier-row { border-bottom: 1px solid var(--rule); }
.tier-row:last-child { border-bottom: none; }
.tier-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 4px;
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  text-align: left;
  font-family: inherit;
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}
.tier-head:hover:not(:disabled) {
  background: var(--paper);
  color: var(--ink);
  box-shadow: none;
}
.tier-head:active { transform: none; }
.tier-chevron {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--ink-3);
  transition: transform .14s;
  flex: none;
}
.tier-row.open .tier-chevron { transform: rotate(90deg); }
.tier-name { font-size: 12.5px; font-weight: 700; color: var(--ink); flex: 1; }
.tier-arrow { color: var(--ink-3); font-weight: 400; }
.tier-stat {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-2);
  white-space: nowrap;
}
.tier-stat + .tier-stat {
  padding-left: 11px;
  border-left: 1px solid var(--rule);
  color: var(--ink-3);
}
@media (max-width: 780px) { .tier-stat + .tier-stat { display: none; } }
.tier-body { padding: 0 4px 14px 26px; display: none; }
.tier-row.open .tier-body { display: block; }

.landing {
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  margin-bottom: 9px;
  background: var(--card);
}
.landing:last-child { margin-bottom: 0; }
.landing-head {
  width: 100%;
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 12px;
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  text-align: left;
  font-family: inherit;
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}
.landing-head:hover:not(:disabled) {
  background: var(--paper);
  color: var(--ink);
  box-shadow: none;
}
.landing-head:active { transform: none; }
.landing-target {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
}
.landing-delta { font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--ink-3); }
.landing-cost { font-size: 12px; font-weight: 700; color: var(--ink); margin-left: auto; white-space: nowrap; }
.landing-colls { font-size: 10.5px; color: var(--ink-2); flex-basis: 100%; }
.landing-body { display: none; padding: 0 12px 12px; }
.landing.open .landing-body { display: block; }
.landing-split { display: grid; grid-template-columns: 1.35fr 1fr; gap: 16px; }
/* Grid children default to min-width:auto, so a wide table stretches the
   column and pushes the whole PAGE sideways. Each half scrolls itself. */
.landing-split > div { min-width: 0; overflow-x: auto; }
@media (max-width: 860px) { .landing-split { grid-template-columns: 1fr; } }
.landing-split h4 {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 4px 0 6px;
}
.landing table { font-size: 11px; }
.landing th, .landing td { padding: 5px 8px; }
.landing td:first-child { padding-left: 0; }
.odds-bar {
  display: inline-block;
  height: 6px;
  background: var(--ink);
  border-radius: 1px;
  vertical-align: middle;
  margin-right: 6px;
  min-width: 2px;
}

/* ---- Custom trade builder ---------------------------------------------- */
.build-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 9px 12px;
  margin-bottom: 10px;
}
.build-grid label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--ink-3);
  min-width: 0;
}
/* These inputs sit in a grid cell, not a flex row, so the flex-basis the
   .row selector gives them would blow the column out. */
.build-grid input[type="text"], .build-grid select { flex: none; width: 100%; }

.build-note {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--ink-2);
  border-left: 2px solid var(--rule-2);
  padding-left: 9px;
  margin-bottom: 11px;
}

.build-results { margin-top: 13px; }
.build-results .landing { border-color: var(--ink); }

/* ---- Market scan controls ---------------------------------------------- */
.scan-controls {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  padding: 11px 0 3px;
  margin-bottom: 9px;
  border-bottom: 1px solid var(--rule);
}
.scan-controls label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.scan-controls select { flex: none; font-size: 11.5px; padding: 6px 8px; }
.scan-controls button { margin-left: auto; }

/* The switch reads as the primary control, so it gets the ink-filled
   treatment rather than a default checkbox lost among the dropdowns. */
.scan-toggle {
  flex-direction: row !important;
  align-items: center;
  gap: 7px !important;
  font-size: 10.5px !important;
  color: var(--ink) !important;
  border: 1px solid var(--ink);
  border-radius: var(--r);
  padding: 8px 12px;
  cursor: pointer;
  user-select: none;
}
.scan-toggle:hover { background: var(--paper); }
.scan-toggle input { accent-color: var(--ink); width: 13px; height: 13px; cursor: pointer; }
.scan-toggle:has(input:checked) { background: var(--ink); color: var(--on-ink) !important; }
.scan-toggle:has(input:checked) input { accent-color: var(--on-ink); }

.budget-line {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-2);
  letter-spacing: -.01em;
}

/* The row being swept right now, marked without moving anything. */
/* The collection being swept or scanned right now. The bar down the leading
   edge is what makes it findable in a long list without scanning every row. */
.cov-row.cov-running { background: var(--paper); box-shadow: inset 3px 0 0 var(--live); }
.cov-live {
  color: var(--live);
  border-color: var(--live);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* And the one skin inside it being counted at this moment. */
.cov-skin-live {
  border-color: var(--live) !important;
  color: var(--live) !important;
  font-weight: 700;
}
.cov-skin-live .cov-check { color: var(--live); }

/* ---- Database & quota panel -------------------------------------------- */
.db-projects {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px;
  margin-bottom: 12px;
}
.db-proj {
  border: 1px solid var(--rule-2);
  border-left-width: 3px;
  border-radius: var(--r);
  padding: 10px 12px;
  background: var(--card);
}
/* Status carries a left edge as well as a word — colour alone is never the
   only signal, and the edge is readable at a glance across two cards. */
.db-good       { border-left-color: var(--ok); }
.db-approaching{ border-left-color: var(--hot); }
.db-exceeded   { border-left-color: var(--err); }
.db-target     { box-shadow: 2px 2px 0 rgba(var(--shadow-rgb),.1); border-color: var(--ink); }

.db-proj-top {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.db-proj-name {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
}
.db-badge {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  background: var(--ink);
  color: var(--on-ink);
  padding: 2px 6px;
  border-radius: var(--r);
}
.db-state {
  margin-left: auto;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.db-exceeded .db-state    { color: var(--err); }
.db-approaching .db-state { color: var(--hot); }
.db-good .db-state        { color: var(--ok); }

.db-meter {
  display: grid;
  grid-template-columns: 42px 1fr auto;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}
.db-meter:last-child { margin-bottom: 0; }
.db-meter-label {
  font-size: 9px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.db-meter-val {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--ink-2);
  white-space: nowrap;
}
.db-approaching .cov-fill { background: var(--hot); }
.db-exceeded .cov-fill    { background: var(--err); }

/* The status pill gains an "approaching" step the others don't have. */
.pill.warn { border-color: var(--hot); color: var(--hot); }
.pill.warn::before { background: var(--hot); }

/* ---- Stickers ---------------------------------------------------------- */
.stk-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 9px;
  max-height: 70vh;
  overflow-y: auto;
  padding: 2px;
}
.stk-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  /* Overrides the global button voice — these are catalog tiles, not actions,
     so no uppercase, no letter-spacing, no ink-fill hover. */
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  padding: 9px 7px;
  background: var(--card);
  border: 1px solid var(--rule);
  text-align: center;
}
.stk-card:hover:not(:disabled) {
  background: var(--paper);
  color: var(--ink);
  border-color: var(--ink);
  box-shadow: 2px 2px 0 rgba(var(--shadow-rgb),.1);
}
.stk-card:active:not(:disabled) { transform: translate(1px, 1px); box-shadow: none; }
.stk-card.active { border-color: var(--ink); background: var(--paper); box-shadow: inset 0 0 0 1px var(--ink); }

/* The rarity colour belongs to the sticker, so it rides the image frame
   rather than the text — colour is never the only signal here, the rarity
   is also a filter you chose. */
.stk-img-wrap {
  display: block;
  width: 100%;
  height: 62px;
  border-bottom: 2px solid var(--rar, var(--rule-2));
  display: flex;
  align-items: center;
  justify-content: center;
  padding-bottom: 5px;
}
.stk-img { max-width: 100%; max-height: 56px; object-fit: contain; display: block; }
.stk-name {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.stk-meta {
  font-size: 9px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.stk-badges { display: flex; gap: 3px; flex-wrap: wrap; justify-content: center; }
.stk-badge {
  font-size: 8px;
  letter-spacing: .06em;
  text-transform: uppercase;
  border: 1px solid var(--rule-2);
  padding: 1px 4px;
  color: var(--ink-2);
}
#stkPrices h3 { margin-bottom: 8px; }

/* ---- SPC: sticker-placed crafts ---------------------------------------- */
.spc-results { display: flex; flex-direction: column; gap: 9px; max-height: 76vh; overflow-y: auto; }
.spc-card {
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  background: var(--card);
  padding: 10px 12px;
}
.spc-card:hover { border-color: var(--ink); }
.spc-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.spc-name { font-size: 12.5px; font-weight: 700; }
.spc-tag {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  border: 1px solid var(--rule-2);
  padding: 2px 6px;
  color: var(--ink-2);
}
/* A quad is the thing people are actually hunting, so it gets the one strong
   mark on the card. */
.spc-tag-hot { background: var(--hot-bg); border-color: var(--hot); color: var(--hot); }
.spc-price { margin-left: auto; font-size: 13px; font-weight: 700; white-space: nowrap; }

.spc-body { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.spc-slots { display: flex; gap: 5px; }
.spc-slot {
  position: relative;
  width: 46px;
  height: 36px;
  border: 1px solid var(--rule);
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
}
.spc-slot img { max-width: 100%; max-height: 100%; object-fit: contain; }
/* Empty slots are drawn, not skipped: stickers in slots 1 and 3 is a
   different item from slots 1 and 2, and closing the gap would hide that. */
.spc-slot-empty { border-style: dashed; background: transparent; }
.spc-clean { border-color: var(--ok); }
.spc-wear {
  position: absolute;
  bottom: -1px; right: -1px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 8px;
  background: var(--err);
  color: #fff;
  padding: 0 2px;
}
.spc-noicon { width: 100%; height: 100%; background: var(--rule); }
.spc-facts {
  display: flex;
  gap: 14px;
  align-items: baseline;
  font-size: 11px;
  color: var(--ink-2);
  font-family: 'JetBrains Mono', monospace;
}
.spc-src { color: var(--ink-3); font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase; }

/* Inline action inside the coverage headline — the fix belongs where the
   problem is visible, not three cards further down. */
.cov-inline-btn { padding: 4px 10px; font-size: 9.5px; margin-left: 6px; vertical-align: 1px; }
.cov-age {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 400;
  color: var(--ink-3);
  margin-left: 8px;
}

/* Per-skin dropdown inside a Marketplace coverage row. */
.cov-skin {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 10.5px;
  border: 1px solid var(--rule);
  border-radius: var(--r);
  padding: 3px 7px;
  color: var(--ink-3);
  background: var(--card);
}
/* A skin we actually hold listings for reads as present; one at "—" is the
   gap a sweep left behind, which is the point of opening the row. */
.cov-skin-has { color: var(--ink); border-color: var(--rule-2); }
.cov-skin b { font-family: 'JetBrains Mono', monospace; font-size: 10px; }
.cov-skin-has b { color: var(--ok); }
.cov-skin-loading { font-size: 11px; color: var(--ink-3); }

/* A live hit and a historical one look identical otherwise, and the
   difference decides whether the price is worth trusting. */
.rare-tag-live { border-color: var(--live); color: var(--live); }

/* ---- Connection test readout ------------------------------------------- */
.test-line {
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 6px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 12px;
}
.test-line:last-child { border-bottom: none; }
.test-label {
  flex: 0 0 170px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.test-value { font-family: 'JetBrains Mono', monospace; color: var(--ink); }
.test-good .test-value { color: var(--ok); }
.test-bad  .test-value { color: var(--err); }
.test-info .test-value { color: var(--ink-2); }

/* ---- Three-column Marketplace ------------------------------------------ */
/* 320 + 1fr + 280 plus two 16px gaps needs ~1000px of content before the
   middle column gets uncomfortable, so three columns survive a 1280 laptop —
   the width this page is most often opened at. */
.layout3 { grid-template-columns: 320px minmax(0, 1fr) 280px; }
.mkt-col-left,
.mkt-col-mid { min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.mkt-col-left { position: sticky; top: 24px; max-height: calc(100vh - 48px); overflow-y: auto; }
/* The left column is narrow, so its controls stack instead of wrapping into
   unreadable slivers. */
.mkt-col-left .row > input[type="text"],
.mkt-col-left .row > select { flex: 1 1 100%; }
.mkt-col-left .mkt-results { max-height: 52vh; overflow-y: auto; }

/* Below this the middle column would be too narrow to read a deal card, so
   the rare-finds rail moves under the other two rather than being squeezed. */
@media (max-width: 1120px) {
  .layout3 { grid-template-columns: 300px minmax(0, 1fr); }
  .layout3 .sidebar-right { grid-column: 1 / -1; position: static; max-height: none; }
}
@media (max-width: 900px) {
  .layout3 { grid-template-columns: 1fr; }
  .mkt-col-left { position: static; max-height: none; }
}

/* ---- Scan drawer ------------------------------------------------------- */
/* A control strip, not a section. Collapsed it was 51px of full-width card —
   taller than the nav above it — for one line of text and a status pill, and it
   pushed everything that matters further down the page. */
.scan-drawer {
  padding: 0;
  overflow: hidden;
  box-shadow: none;
  margin-bottom: 10px;
}
.scan-drawer:hover { box-shadow: none; }
.drawer-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 11px;
  min-height: 0;
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  text-align: left;
  font-family: inherit;
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}
.drawer-head:hover:not(:disabled) { background: var(--paper); color: var(--ink); box-shadow: none; }
.drawer-head:active:not(:disabled) { transform: none; }
.drawer-title {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
}
.drawer-summary {
  flex: 1;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The status pill is the tallest thing in the strip, so it sets the height.
   Full size elsewhere; compact in here. */
.drawer-head .pill {
  padding: 2px 8px;
  font-size: 9.5px;
  letter-spacing: .08em;
  gap: 5px;
}
.drawer-head .pill::before { width: 5px; height: 5px; }

/* Scoped to the drawer's OWN chevron, not every chevron inside it. These were
   descendant selectors, which is fine while a drawer holds plain controls and
   wrong the moment it holds a coverage list: every collection row carries a
   .cov-chevron of its own, so an open drawer rotated all of them at once and
   every collapsed row looked expanded. The Marketplace sweep drawer has that
   same list inside it, so it was already happening there. */
.scan-drawer > .drawer-head > .cov-chevron { transition: transform .14s; font-size: 10px; }
.scan-drawer.open > .drawer-head > .cov-chevron { transform: rotate(90deg); }
.drawer-body { display: none; }
.scan-drawer.open .drawer-body { display: block; }
.drawer-inner { padding: 2px 12px 12px; }
/* NO max-height here on purpose. The collection list inside already scrolls at
   420px, and capping the panel too would put a scrollbar inside a scrollbar —
   the list would scroll, then the panel would, and neither would feel like it
   was responding. One scroller: the list. */
.scan-drawer.open .drawer-body { border-top: 1px solid var(--rule-2); }
/* A sweep behind a closed drawer must still announce itself. */
.scan-drawer.drawer-busy { border-color: var(--live); }
.scan-drawer.drawer-busy .drawer-title { color: var(--live); }

/* ---- Best deals -------------------------------------------------------- */
.deals-list { display: flex; flex-direction: column; gap: 9px; max-height: 72vh; overflow-y: auto; }
/* Picture beside the numbers, not above them. A deals list is read downward,
   comparing prices — stacking the image on top would push that comparison off
   the screen after three rows. The left column is wide enough to afford it. */
.deal-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  border: 1px solid var(--rule-2);
  border-left: 3px solid var(--ok);
  border-radius: var(--r);
  background: var(--card);
  padding: 10px 12px;
}
.deal-main { flex: 1; min-width: 0; }

/* Fixed box whether or not the picture loads, so a long list never reflows as
   Steam's CDN fills them in. Background rather than <img>: the URL can arrive
   after the card is painted, and a src-less <img> shows a broken-image glyph
   in the meantime. */
.deal-shot {
  flex: none;
  width: 92px;
  aspect-ratio: 4 / 3;
  max-width: 100%;
  border-radius: var(--r);
  background: var(--paper) center / contain no-repeat;
  border: 1px solid var(--rule);
}
.deal-shot.has-img { background-color: transparent; }
.deal-card:hover .deal-shot { border-color: var(--rule-2); }

/* Below this the middle column is too narrow to carry both, so the picture
   steps aside rather than squeezing the prices. */
@media (max-width: 720px) {
  .deal-shot { width: 64px; }
}
.deal-card:hover { border-color: var(--ink); border-left-color: var(--ok); }
.deal-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 7px; }
.deal-name { font-size: 12.5px; font-weight: 700; }
.deal-off {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ok);
  border: 1px solid var(--ok);
  padding: 1px 6px;
  border-radius: var(--r);
}
.deal-price { margin-left: auto; font-size: 14px; font-weight: 700; white-space: nowrap; }

/* Where this listing sits between the cheapest and dearest sighting. */
.deal-range { margin: 0 0 7px; }
.deal-track {
  position: relative;
  display: block;
  height: 4px;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 1px;
}
.deal-median {
  position: absolute;
  top: -3px; bottom: -3px;
  width: 1px;
  background: var(--ink-3);
}
.deal-dot {
  position: absolute;
  top: -3px;
  width: 8px; height: 8px;
  margin-left: -4px;
  background: var(--ok);
  border-radius: 50%;
}
.deal-facts {
  display: flex;
  gap: 12px;
  align-items: baseline;
  flex-wrap: wrap;
  font-size: 10.5px;
  color: var(--ink-2);
}
.deal-facts b { font-family: 'JetBrains Mono', monospace; color: var(--ink); }
.deal-facts .val { font-family: 'JetBrains Mono', monospace; color: var(--ink-3); }
.deal-age { color: var(--ink-3); }
.deal-chip {
  font-size: 9px;
  letter-spacing: .05em;
  text-transform: uppercase;
  border: 1px solid var(--rule-2);
  padding: 1px 5px;
  border-radius: var(--r);
}
.deal-chip-hot { border-color: var(--hot); color: var(--hot); background: var(--hot-bg); }

/* The activity feed replaced the page blurb in the header: what the scanner is
   doing belongs where a paragraph read once used to sit. */
.mkt-activity {
  margin-top: 8px;
  max-height: 118px;
  max-width: 72ch;
}
.mkt-activity .log-line { font-size: 10.5px; padding: 4px 8px; }
.mkt-activity .log-line.running .log-text { color: var(--live); font-weight: 600; }
.mkt-activity .empty-state { padding: 10px 4px; font-size: 11px; }

/* ---- Results as compact cards ------------------------------------------
   A table needed columns the 320px rail doesn't have. Each listing is one
   short row instead: picture, name, and the two numbers that matter. */
.mkt-results { display: flex; flex-direction: column; }
.mkt-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 4px;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
  transition: background .1s, padding-left .1s;
}
.mkt-item:last-child { border-bottom: none; }
.mkt-item:hover { background: var(--paper); padding-left: 8px; }

/* A fixed box whether or not the picture loads, so rows never jump as Steam's
   CDN fills them in one at a time. Set as a background rather than an <img>:
   the URL arrives after the row is painted, and a src-less <img> shows a
   broken-image glyph in the meantime. */
.mkt-thumb {
  flex: none;
  width: 54px;
  height: 40px;
  border: 1px solid var(--rule);
  border-radius: var(--r);
  background: var(--paper) center / contain no-repeat;
}
.mkt-thumb.has-img { border-color: var(--rule-2); }

.mkt-item-body { flex: 1; min-width: 0; display: block; }
.mkt-item-top { display: flex; align-items: baseline; gap: 8px; }
.mkt-item-name {
  flex: 1;
  min-width: 0;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mkt-item-price {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
}
.mkt-item-meta {
  display: block;
  font-size: 9.5px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mkt-item-float {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--ink-2);
  letter-spacing: -.02em;
}

/* ---- Scan archive import row ---------------------------------------- */
/* Sits under the budget line in the scan drawer. The note carries the whole
   explanation, so it gets room to wrap rather than being clipped. */
.archive-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 10px 0 4px;
}
.archive-row .hint { margin: 0; flex: 1 1 260px; min-width: 0; }
.archive-row .nav-btn { flex: 0 0 auto; min-width: 130px; }

/* ---- Freshness pips --------------------------------------------------- */
/* Shape carries the same message as colour: the disc drains as the 24h
   deadline approaches, exactly like the bar on a collection row. Full = just
   scanned, half = halfway through the window, empty ring = out of time. */
.cov-pip {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: 0 0 auto;
  box-sizing: border-box;
  /* A defined edge whatever the fill — amber on near-white would otherwise
     almost disappear. */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .32);
}
.cov-pip.fresh  { background: var(--st-good); }
.cov-pip.ageing {
  background: linear-gradient(90deg, var(--st-warn) 0 50%, transparent 50%);
}
.cov-pip.stale  { background: transparent; box-shadow: inset 0 0 0 2px var(--st-crit); }
.cov-pip.todo   { background: transparent; box-shadow: inset 0 0 0 1px var(--muted, #9aa0a6); }

.cov-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding: 6px 0 8px;
  font-size: 11px;
  color: var(--muted, #6b7280);
}
.cov-legend span { display: inline-flex; align-items: center; gap: 5px; }

/* ---- Per-skin scan marks --------------------------------------------- */
/* Three states, deliberately distinguishable at a glance: held (has listings),
   empty (asked, nothing listed — a real answer, not a gap), and todo. */
.cov-skin { display: inline-flex; align-items: center; gap: 6px; }
/* A skin that was asked about but had nothing listed is a real answer, not a
   gap — quieter than one holding listings, but only its TEXT is quieter.
   Dimming the whole chip also dimmed the pip, which made an 18h-old weapon the
   faintest thing in the list when it is the most urgent. Urgency never fades. */
.cov-skin:not(.cov-skin-has) { color: var(--muted, #8a8f98); }
.cov-skin.cov-band-todo      { color: #a9adb3; }
.cov-pip                     { opacity: 1; }

.cov-skins-done {
  font-size: 11px;
  letter-spacing: .02em;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--line, #d8dbe0);
  color: var(--muted, #6b7280);
  white-space: nowrap;
}
.cov-skins-done.all {
  color: var(--ok, #2f9e58);
  border-color: currentColor;
}

/* An empty store looks identical to real data loss, so the note that explains
   why gets enough weight to be read rather than skimmed past. */
.origin-note { display: block; margin-top: 4px; color: var(--muted, #6b7280); }
.origin-note a { font-weight: 600; }

/* The page's own name says which database you are looking at; this says what
   kind it is, so DBAT and SDBA are never confused at a glance. */
.page-kind {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  vertical-align: middle;
  margin-left: 10px;
  padding: 2px 8px;
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  color: var(--ink-2);
}

/* ---- Database ranking --------------------------------------------------
   A ladder, not a table. Every row is ONE line: the rank hard left, the item
   in the middle, the count hard right — and the two numeric columns are
   tabular and fixed-width, so they form an unbroken vertical line down the
   panel however long the names get. The dotted leader between them is what
   keeps a short name tied to its number across the gap. */
.rank-list {
  display: flex;
  flex-direction: column;
  max-height: 460px;
  overflow-y: auto;
  border: 1px solid var(--rule);
  border-radius: var(--r);
}
.rank-list .empty-state { padding: 18px 4px; }

.rank-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  width: 100%;
  text-align: left;
  border: none;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
  background: none;
  box-shadow: none;
  padding: 7px 12px;
  font-size: 12px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: -0.005em;
}
.rank-row:last-child { border-bottom: none; }
.rank-row:hover { background: var(--ink); color: var(--on-ink); box-shadow: none; }
.rank-row:hover .rank-n,
.rank-row:hover .rank-wear { color: var(--on-ink); }
.rank-row:hover .rank-lead { border-bottom-color: #4a4a46; }
.rank-row:active { transform: none; }

/* Fixed width + tabular figures: #9 and #1,284 occupy the same column, which
   is the whole reason the left edge reads as a straight line. */
.rank-n {
  flex: none;
  width: 46px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.rank-label {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 7px;
  overflow: hidden;
}
.rank-name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rank-wear { flex: none; font-size: 10.5px; color: var(--ink-3); white-space: nowrap; }

/* The rung. Takes all the slack, so the count never drifts left. */
.rank-lead {
  flex: 1 1 auto;
  min-width: 14px;
  align-self: center;
  border-bottom: 1px dotted var(--rule-2);
}

.rank-qty {
  flex: none;
  width: 72px;
  font-family: 'JetBrains Mono', monospace;
  font-variant-numeric: tabular-nums;
  text-align: right;
  font-weight: 700;
}

@media (max-width: 620px) {
  .rank-n { width: 34px; }
  .rank-qty { width: 58px; }
  .rank-wear { display: none; }
}

/* A set of related ticks under one label, so three variant filters read as one
   control rather than three loose switches competing with the dropdowns. */
.filter-set { display: flex; flex-direction: column; gap: 4px; }
.filter-set-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.filter-set-row { display: flex; gap: 5px; flex-wrap: wrap; }
.filter-set .scan-toggle { padding: 6px 9px; }

/* ---- Coverage freshness -------------------------------------------------
   How long since a collection's counts were taken: under 6h, 6-16h, over 16h.
   The ramp is --st-good/warn/crit, documented at the top of this file as the
   one whose three steps stay apart under red-green colour blindness — and as
   there, colour is not the only channel: the row's meta line states the age
   in words and the button repeats it in its tooltip.

   A collection with no time at all keeps the plain button. That is the honest
   rendering of "counted before times were recorded", which is every row
   captured before the `at` field existed. */
.cov-run-fresh  { border-color: var(--st-good); color: var(--st-good); }
.cov-run-ageing { border-color: var(--st-warn); color: #6b4a04; }
.cov-run-stale  { border-color: var(--st-crit); color: var(--st-crit); }
.cov-run-fresh:hover  { background: var(--st-good); border-color: var(--st-good); color: #fff; }
.cov-run-ageing:hover { background: var(--st-warn); border-color: var(--st-warn); color: #2a1c00; }
.cov-run-stale:hover  { background: var(--st-crit); border-color: var(--st-crit); color: #fff; }

/* Over a day old. Filled rather than outlined, because this is the one band
   that has to be distinguishable from an UNTIMED collection — and an untimed
   one is exactly the plain default button. Two greys differing only in border
   weight would have been unreadable; a filled chip against an outline is not.
   It reads as set aside rather than alarming, which is what a day-old count
   is: still worth redoing, just not today's emergency. */
.cov-run-cold {
  background: var(--ink-2);
  border-color: var(--ink-2);
  color: var(--on-ink);
}
.cov-run-cold:hover { background: var(--ink); border-color: var(--ink); color: var(--on-ink); }


/* ---- Plan and spend ----------------------------------------------------
   Which plan a project is on changes what its meter MEANS: on the free plan a
   full bar is a wall, on pay-as-you-go it is the point where money starts. The
   badge says which, so the bars can't be misread. */
.db-plan {
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  padding: 2px 6px;
  border-radius: var(--r);
  border: 1px solid currentColor;
}
.db-plan-spark { color: var(--ink-3); }
.db-plan-blaze { color: var(--hot); background: var(--hot-bg); border-color: var(--hot-bg); }

/* Past the free allowance. Not an error — the work went through — so it is
   marked in the highlighter colour rather than the failure one. */
.cov-fill-over { background: var(--hot) !important; }
.db-cost {
  margin-top: 6px;
  font-size: 10.5px;
  line-height: 1.45;
  color: var(--ink-2);
}
.db-cost b { color: var(--hot); }
.db-billing { border-color: var(--hot) !important; }

/* ---- Listing cards ------------------------------------------------------
   A listing is something you look at before you read: which skin, how worn,
   whether it carries stickers. A 54px thumbnail beside a line of text answered
   none of that, so the results are a grid of pictures with the numbers under
   them. auto-fill rather than a fixed count, so the same grid works in the
   320px rail it lives in now and in a wider column if it ever moves. */
.mkt-results.mkt-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 8px;
  align-content: start;
}
.mkt-results.mkt-grid .empty-state { grid-column: 1 / -1; }

.mkt-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  border: 1px solid var(--rule);
  border-radius: var(--r);
  background: var(--card);
  text-decoration: none;
  color: inherit;
  transition: border-color .12s, background .12s;
}
.mkt-card:hover { border-color: var(--ink); background: var(--paper); }

/* A fixed box whether or not the picture loads, so the grid never reflows as
   Steam's CDN fills them in one at a time. Background rather than an <img>:
   the URL can arrive after the card is painted, and a src-less <img> shows a
   broken-image glyph in the meantime. */
.mkt-card-shot {
  width: 100%;
  max-width: 100%;
  aspect-ratio: 4 / 3;
  margin-bottom: 3px;
  border-radius: var(--r);
  background: var(--paper) center / contain no-repeat;
}
.mkt-card-shot.has-img { background-color: transparent; }

.mkt-card-name {
  font-size: 11px;
  font-weight: 700;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mkt-card-sub {
  font-size: 9px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mkt-card-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  margin-top: 2px;
}
.mkt-card-float {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.mkt-card-price {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Sticker count sits ON the picture — it is a property of the item shown, and
   the render underneath it is already the stickered one. */
.mkt-card-stickers {
  position: absolute;
  top: 10px;
  right: 10px;
  min-width: 16px;
  padding: 1px 4px;
  border-radius: var(--r);
  background: var(--ink);
  color: var(--on-ink);
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px;
  font-weight: 700;
  text-align: center;
}

/* The fourth freshness step, matching DBAT: past a full day the disc is solid
   and dark rather than a louder red. The shapes still carry the message on
   their own — full, half, empty ring, then gone out. */
.cov-pip.cold { background: var(--ink-2); }


/* ---- Spend over today --------------------------------------------------
   Cumulative operations as a percentage of each daily free allowance, so
   reads (50,000) and writes (20,000) can share ONE axis honestly — measured
   against their own limits rather than plotted raw at different scales.
   The line at 100% is the allowance itself. */
.spend { margin-top: 10px; }

.spend-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  margin-bottom: 4px;
  font-size: 10px;
  color: var(--ink-2);
}
.spend-key { display: inline-flex; align-items: center; gap: 5px; }
/* The swatch carries identity; the words and the number stay in text ink. */
.spend-key i { width: 9px; height: 3px; border-radius: 2px; flex: none; }
.spend-key b { font-family: 'JetBrains Mono', monospace; color: var(--ink); font-variant-numeric: tabular-nums; }
.spend-now { margin-left: auto; color: var(--ink-3); }

.spend-svg { display: block; width: 100%; height: auto; overflow: visible; }

/* Recessive: the data is the only thing drawn at full strength. */
.spend-grid { stroke: var(--rule); stroke-width: 1; }
.spend-axis { stroke: var(--rule-2); stroke-width: 1; }
/* The allowance. Dashed so it reads as a threshold rather than a reading. */
.spend-limit { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 3 3; }
.spend-tick {
  font-family: 'JetBrains Mono', monospace;
  font-size: 8px;
  fill: var(--ink-3);
  text-anchor: end;
}
.spend-tick-x { text-anchor: middle; }
.spend-hit { cursor: crosshair; }
.spend-hit:hover { fill: rgba(var(--grid-rgb), .05); }

.spend-empty {
  margin-top: 8px;
  font-size: 10.5px;
  color: var(--ink-3);
}

/* ---- Sign-in -----------------------------------------------------------
   Injected into the topbar by auth.js rather than written into every page,
   so all twelve gain it at once and none can drift. */
.auth-box { display: flex; align-items: center; gap: 8px; }
/* Your Steam profile, top right — avatar + name, opens the Profile page. */
.auth-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 11px 0 4px;
  border: 1px solid var(--rule-2);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
  transition: border-color .14s ease, background .14s ease;
}
.auth-chip:hover, .auth-chip.active { border-color: var(--ink); }
.auth-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  background: var(--paper);
}
.auth-avatar-blank {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-2);
  border: 1px solid var(--rule);
}
.auth-who {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
  max-width: 16ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.auth-err { font-size: 10px; color: var(--err); }

/* ---- CSDBN -------------------------------------------------------------
   The board people here sell to each other on. A listing is a picture, a
   price and a way to reach the seller — the three things a decision is made
   on — and nothing about payment, because none happens here. */
.csdbn-form { margin-bottom: 12px; }
.csdbn-form .scan-controls { padding-top: 6px; margin-bottom: 0; border-bottom: none; }
.csdbn-form input[type="text"],
.csdbn-form input[type="url"] { flex: 1 1 180px; min-width: 0; }
.csdbn-form input[type="number"] { flex: 0 1 110px; }
.csdbn-form .hint.cb-bad { color: var(--err); }

.csdbn-list { display: flex; flex-direction: column; gap: 8px; }

.csdbn-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--rule-2);
  border-left: 3px solid var(--live);
  border-radius: var(--r);
  background: var(--card);
}
/* Your own listing reads differently from everyone else's, because the only
   thing you can do with it is take it down. */
.csdbn-card.csdbn-mine { border-left-color: var(--ink-3); background: var(--paper); }

.csdbn-shot {
  flex: none;
  width: 88px;
  aspect-ratio: 4 / 3;
  max-width: 100%;
  border-radius: var(--r);
  border: 1px solid var(--rule);
  background: var(--paper) center / contain no-repeat;
}
.csdbn-shot.has-img { background-color: transparent; }

.csdbn-body { flex: 1; min-width: 0; }
.csdbn-top { display: flex; align-items: baseline; gap: 10px; }
.csdbn-name {
  flex: 1;
  min-width: 0;
  font-size: 12.5px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.csdbn-price {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.csdbn-meta {
  font-size: 10px;
  color: var(--ink-3);
  font-family: 'JetBrains Mono', monospace;
  margin-top: 1px;
}
.csdbn-note { font-size: 11.5px; color: var(--ink-2); margin-top: 4px; }
.csdbn-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 7px;
}
.csdbn-seller { flex: 1; min-width: 0; font-size: 10px; color: var(--ink-3); }
.csdbn-trade { text-decoration: none; display: inline-block; }

/* A sign-in failure is almost always a switch in the Firebase console rather
   than anything on the page, so the notice gets room to say which switch —
   full width under the nav, not a code squeezed into the bar itself. */
.auth-trouble {
  margin: 0 0 12px;
  padding: 9px 14px;
  border: 1px solid var(--err);
  border-left-width: 3px;
  border-radius: var(--r);
  background: var(--card);
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-2);
}
.auth-trouble b { color: var(--err); }
.auth-trouble code {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-3);
}

/* Steam is the way in; Google is a fallback while the function is not
   deployed, so it is present but visibly secondary rather than a second
   equal choice. */
.auth-steam { white-space: nowrap; }
.auth-alt {
  border: none;
  background: none;
  box-shadow: none;
  padding: 4px 2px;
  font-size: 9.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.auth-alt:hover { color: var(--ink); background: none; }

/* ---- The shared view ---------------------------------------------------
   Sits between the deals controls and the deals themselves, because it says
   WHICH deals are below it. Quiet by default; it only earns attention when
   the page is showing someone else's numbers rather than your own. */
.digest-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 10px 0 14px;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--panel-2, rgba(255, 255, 255, 0.04));
  border: 1px solid var(--line, rgba(255, 255, 255, 0.08));
}

.digest-state {
  font-size: 13px;
  color: var(--muted, #9aa4b2);
  flex: 1 1 260px;
  min-width: 0;
}

.digest-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

/* Showing published data is a different state of the page, not a setting, so
   it is marked on the page itself rather than only in the button label. */
.digest-bar.digest-on-shared {
  background: rgba(88, 140, 255, 0.10);
  border-color: rgba(88, 140, 255, 0.38);
}

.digest-bar.digest-on-shared .digest-state { color: #9ec1ff; }

@media (max-width: 520px) {
  .digest-bar { flex-direction: column; align-items: stretch; }
  .digest-actions { justify-content: flex-end; }
}

/* ---- Sync bar (DBAT / SDBA) ------------------------------------------- */
.sync-bar { margin-bottom: 12px; }
.sync-head { flex-wrap: wrap; row-gap: 4px; padding: 7px 11px; }
.sync-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ink-3); flex: none;
}
.sync-dot[data-state="up"]       { background: var(--ok); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 22%, transparent); }
.sync-dot[data-state="down"]     { background: var(--err); box-shadow: 0 0 0 3px color-mix(in srgb, var(--err) 22%, transparent); }
.sync-dot[data-state="checking"] { animation: blink .9s steps(1,end) infinite; }
.sync-item {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-2);
  white-space: nowrap;
}
.sync-server { color: var(--ink); font-weight: 700; }
.sync-sep { color: var(--ink-3); font-size: 10px; }
.sync-new {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  font-weight: 700;
  padding: 1px 6px;
  border: 1px solid var(--hot);
  color: var(--hot);
  background: var(--hot-bg);
  border-radius: var(--r);
}
.sync-spacer { flex: 1; }
.sync-now {
  font-size: 10px !important;
  padding: 3px 9px !important;
  cursor: pointer;
  user-select: none;
}
.sync-now.is-busy { opacity: .6; cursor: progress; }
.sync-head:hover .sync-now { border-color: var(--ink); }
.sync-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 8px;
  margin: 4px 0 10px;
}
.sync-tile {
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 11px;
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: var(--r);
}
.sync-label {
  font-size: 9px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.sync-tile b { font-family: 'JetBrains Mono', monospace; font-size: 15px; color: var(--ink); }
.sync-sub { font-size: 10.5px; color: var(--ink-3); }

/* The Update button: only in the DOM's layout when an update exists. */
.update-btn {
  padding: 6px 10px !important;
  font-size: 10.5px !important;
  border-color: var(--ok) !important;
  color: var(--ok) !important;
  animation: update-pulse 2.4s ease-in-out infinite;
}
.update-btn:hover:not(:disabled) { background: var(--ok) !important; color: #fff !important; }
.update-btn:disabled { animation: none; opacity: .75; }
@keyframes update-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 45%, transparent); }
  50%      { box-shadow: 0 0 0 5px color-mix(in srgb, var(--ok) 0%, transparent); }
}

.ext-download-btn { padding: 6px 10px !important; font-size: 10.5px !important; text-decoration: none; }
.ext-help {
  position: fixed; top: 58px; right: 16px; z-index: 10000;
  max-width: 420px; padding: 14px 16px; font-size: 13px; line-height: 1.5;
  box-shadow: 3px 3px 0 rgba(var(--shadow-rgb), .25);
}
.ext-help ol { margin: 8px 0 10px 18px; }
.ext-help li { margin-bottom: 4px; }
.ext-help p { margin: 0 0 10px; color: var(--ink-2); font-size: 12px; }
.ext-help li { margin-bottom: 7px; line-height: 1.5; }
/* The copy button sits on its own line under step 2 — inline it would wrap
   mid-sentence at narrow widths and read as part of the prose. */
.ext-copy-row { display: block; margin: 6px 0 2px; }
.ext-copy { font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 12px; }
.ext-copy.is-ok { border-color: var(--ok); color: var(--ok); }

/* Links that are buttons (the extension download) look like buttons. */
a.nav-btn {
  display: inline-flex; align-items: center;
  font-family: inherit; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .09em;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--ink); border-radius: var(--r);
  text-decoration: none; cursor: pointer;
  transition: background .14s ease, color .14s ease;
}
a.nav-btn:hover { background: var(--ink); color: var(--on-ink); }
a.nav-btn[hidden] { display: none !important; }

/* ---- Profile page -------------------------------------------------------
   Who you are at the top, then three setup steps with a tick each, then (for
   owners) People. Everything saves as you change it — no Save button. */
.profile-page { grid-column: 1 / -1; max-width: 760px; width: 100%; margin: 0 auto; }
.profile-id { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.profile-avatar {
  width: 72px; height: 72px; border-radius: 50%; object-fit: cover; flex: none;
  border: 1px solid var(--rule-2); background: var(--paper);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 28px; font-weight: 700; color: var(--ink-3);
}
.profile-main { flex: 1 1 260px; min-width: 0; }
.profile-name { font-size: 22px; font-weight: 700; line-height: 1.2; overflow-wrap: anywhere; }
.profile-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 6px; font-size: 12px; color: var(--ink-2); }
.profile-meta code { cursor: pointer; }
.profile-meta a { color: var(--ink-2); }
.profile-role { font-size: 12px; color: var(--ink-2); margin-top: 10px; }
.profile-actions { display: flex; gap: 6px; }

.setup-head { display: flex; align-items: center; gap: 10px; margin-bottom: 11px; padding-bottom: 7px; border-bottom: 1px solid var(--rule); }
.card .setup-head h2 { flex: 1; margin: 0; padding: 0; border: none; }
.setup-head .pill { padding: 4px 9px; }
.setup-step { display: flex; gap: 14px; padding: 16px 0; border-top: 1px solid var(--rule); }
.setup-head + .setup-step { border-top: none; padding-top: 4px; }
.step-mark {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  border: 1.5px solid var(--rule-2); color: var(--ink-3); background: var(--surface);
}
.setup-step.done .step-mark { border-color: var(--ok); background: var(--ok); color: var(--on-ink); }
.setup-step.optional:not(.done) .step-mark { border-style: dashed; }
.step-body { flex: 1; min-width: 0; }
.step-title { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 14px; font-weight: 700; margin-bottom: 3px; }
.step-state { font-size: 12px; font-weight: 500; color: var(--ink-3); }
.setup-step.done .step-state { color: var(--ok); }
.step-state.bad { color: var(--err); }
.step-body .hint { margin-bottom: 9px; }
.step-body .row { margin-bottom: 6px; }
.step-check { display: flex; gap: 8px; align-items: flex-start; font-size: 12px; color: var(--ink-2); cursor: pointer; margin: 4px 0 2px; }
.step-check input { margin-top: 2px; }
.step-more { margin-top: 8px; font-size: 12px; color: var(--ink-2); }
.step-more summary { cursor: pointer; color: var(--ink-3); user-select: none; }
.step-more summary:hover { color: var(--ink); }
.step-more[open] summary { margin-bottom: 8px; }
.step-more ol { margin: 0 0 8px 18px; }
.step-more li { margin-bottom: 3px; }
.save-note { font-size: 11.5px; color: var(--ink-3); min-height: 1em; }
.save-note.ok { color: var(--ok); }
.save-note.err { color: var(--err); }
input[type="password"] { font-family: inherit; font-size: 12.5px; color: var(--ink); background: var(--surface);
  border: 1px solid var(--rule-2); border-radius: var(--r); padding: 8px 10px; outline: none; min-width: 0; flex: 1 1 210px; }
input[type="password"]:focus { border-color: var(--ink); }

.people-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid var(--rule); }
.people-row:first-child { border-top: none; }
.people-row .auth-avatar { width: 30px; height: 30px; }
.people-name { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.people-name .hint { font-weight: 400; margin: 0 0 0 6px; font-size: 11.5px; }
.people-tag { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); border: 1px solid var(--rule-2); padding: 2px 6px; border-radius: var(--r); }
.people-tag.on { color: var(--ok); border-color: var(--ok); }

/* ---- Trades: profit finder --------------------------------------------- */
.pf-nums { display: inline-flex; gap: 12px; align-items: baseline; font-weight: 600; }
.pf-nums span { color: var(--ink-2); font-weight: 500; }
.pf-pos { color: var(--ok); }
.pf-neg { color: var(--err); }
.pf-card h4 .nav-btn { margin-left: 8px; padding: 3px 8px; font-size: 9.5px; }
.pf-live { white-space: nowrap; font-size: 10.5px; }

/* ---- Price book on Stickers / SPC ------------------------------------- */
.stk-price { font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700; color: var(--ink); }
.stk-price .hint { font-weight: 400; font-size: 10px; margin: 0 0 0 4px; }
.spc-value { font-size: 11px; color: var(--ink-2); }
.spc-value b { font-family: 'JetBrains Mono', monospace; }

