/* ============================================================================
   Relay Auto Sell — admin dashboard
   ============================================================================

   THE IDEA
   A money tool, read at speed, often on a phone, sometimes at 2am. So the
   interface is almost entirely greyscale and colour is reserved for meaning:
   green is money arriving, amber is waiting on someone, red is danger or
   failure. Nothing else is allowed to be colourful, because if everything is
   accented then an alert reads the same as a heading.

   The emphasis colour is MINT. It sits far enough from the semantic green
   (which is yellower) to never be mistaken for "this is good", and it gives
   the interface one recognisable signature instead of the anonymous white it
   used to have.

   The ground is NEUTRAL near-black. An earlier pass tinted the surfaces mint
   as well, on the theory that the accent should be echoed in the ground; the
   result was that every card, input and hairline read faintly green and the
   whole screen looked colour-cast rather than themed. The accent earns its
   effect precisely by being the only place the hue appears.

   STRUCTURE
   Hairlines do the work that shadows usually do. Elevation is reserved for
   things that genuinely float (menus, modals, toasts), so a raised surface
   always means "this is on top of the page", never "this is a box".
   ========================================================================= */

:root {
  /* ── ground and surfaces ─────────────────────────────────────────────── */
  --bg:          #0A0A0B;   /* page */
  --surface:     #121214;   /* cards */
  --surface-2:   #17181A;   /* inset: inputs, logs, table headers */
  --surface-3:   #202124;   /* hover */
  --line:        #26272A;   /* hairline */
  --line-soft:   #1A1B1E;   /* quieter divider inside a card */

  /* ── type ────────────────────────────────────────────────────────────── */
  --text:        #E9EDEB;
  --text-2:      #9A9DA3;   /* secondary, labels */
  --text-3:      #7A7D83;   /* captions, disabled -- lifted for legibility on the chart axes */

  /* ── emphasis: mint ──────────────────────────────────────────────────── */
  --accent:      #3ECFB8;
  --accent-ink:  #04140F;   /* text ON the accent */
  --accent-dim:  rgba(62,207,184,.13);
  --accent-line: rgba(62,207,184,.28);

  /* ── semantic: the only colour in the interface ──────────────────────── */
  --good:        #52DE7F;
  --good-dim:    rgba(82,222,127,.13);
  --warn:        #E8B341;
  --warn-dim:    rgba(232,179,65,.12);
  --bad:         #FF5C5C;
  --bad-dim:     rgba(255,92,92,.12);
  --info:        #8B93FF;   /* rare: giveaways, non-money highlights */
  --info-dim:    rgba(139,147,255,.12);

  /* coins keep their own identity, used only as small marks */
  --ltc:         #A6A9AA;
  --sol:         #9945FF;
  --dsmp:        #5FD3A6;

  /* ── scale ───────────────────────────────────────────────────────────── */
  --r-sm: 8px; --r: 12px; --r-lg: 16px; --r-pill: 999px;
  --s-1: 4px; --s-2: 6px; --s-3: 10px; --s-4: 13px; --s-5: 18px; --s-6: 24px; --s-7: 36px;

  /* Inter is already preconnected and fetched in index.html; the stack never
     actually named it, so every screen fell back to Segoe UI. */
  --sans: Inter, ui-sans-serif, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --lift-1: 0 1px 2px rgba(0,0,0,.4);
  --lift-2: 0 8px 24px -8px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.4);
  --lift-3: 0 24px 60px -12px rgba(0,0,0,.75);


  /* ── Names app.js draws with ──────────────────────────────────────────
     The chart, the sparklines, the meters and the status dots are painted in
     JavaScript, which reads these custom properties by name. Renaming the
     palette without providing them left every lookup resolving to an empty
     string, so canvas and SVG fell back to black-on-black and the activity
     chart became invisible. They are aliases, not a second palette: change
     the tokens above and these follow. */
  --panel:       var(--surface);
  --border:      var(--line);
  --faint:       #82858B;   /* chart AXIS TEXT -- app.js uses it only for labels,
                               never for lines, so it has to be legible rather
                               than hairline-subtle. Set to a gridline grey it
                               made the dates and counts invisible. */
  --green:       var(--good);
  --red:         var(--bad);
  --amber:       var(--warn);
  --accent-2:    #7C89FF;   /* second series, distinct from green and mint */
  --cyan-bright: #46D6C4;   /* third series */

  --sidebar-w: 216px;
  --topbar-h: 68px;
}

/* A light theme exists because this gets opened outdoors on a phone, where a
   dark UI in sunlight is genuinely hard to read. It is a real design, not an
   inversion: surfaces lighten, but the semantic hues darken so they keep their
   contrast against a pale ground. */
:root[data-theme="light"] {
  --bg:        #F6F7F8;
  --surface:   #FFFFFF;
  --surface-2: #F1F3F5;
  --surface-3: #E7EAEC;
  --line:      #DFE3E6;
  --line-soft: #EDEFF1;
  --text:      #14171A;
  --text-2:    #565D65;
  --text-3:    #7C848C;
  --accent:      #0E9C88;
  --accent-ink:  #FFFFFF;
  --accent-dim:  rgba(14,156,136,.12);
  --accent-line: rgba(14,156,136,.30);
  --good: #17914F; --good-dim: rgba(23,145,79,.12);
  --warn: #A9760B; --warn-dim: rgba(169,118,11,.12);
  --bad:  #D23B3B; --bad-dim:  rgba(210,59,59,.10);
  --info: #5A62D6; --info-dim: rgba(90,98,214,.12);
  --faint: #5C646D;
  --accent-2: #4C5BD4;
  --cyan-bright: #0E9C90;
  --lift-1: 0 1px 2px rgba(16,24,40,.06);
  --lift-2: 0 8px 24px -8px rgba(16,24,40,.16), 0 2px 6px rgba(16,24,40,.06);
  --lift-3: 0 24px 60px -12px rgba(16,24,40,.24);
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 13.5px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
  letter-spacing: -0.006em;
}
::selection { background: rgba(255,255,255,.16); }

/* Numbers line up in columns everywhere in this app, so tabular figures are
   the default rather than something remembered case by case. */
.num, .figure-value, .kpi, .liq-value, td, th, .mono, code, .pay-value { font-variant-numeric: tabular-nums; }
.mono, code, .kbd { font-family: var(--mono); }

a { color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm); }
.hidden { display: none !important; }

/* Fail closed: anything money-shaped stays hidden until the session has
   positively confirmed an admin. */
body:not([data-role="admin"]) .admin-only { display: none !important; }

/* ── app shell ───────────────────────────────────────────────────────────── */
.app { display: flex; min-height: 100vh; position: relative; }
.ambient { display: none; }         /* the old glow; the grey ground carries itself */

.sidebar {
  width: var(--sidebar-w); flex: none;
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
  z-index: 40;
}
.brand { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-4) var(--s-4) var(--s-5); }
.brand-mark {
  width: 32px; height: 32px; border-radius: 9px; flex: none;
  background: var(--accent-dim); display: grid; place-items: center;
  overflow: hidden; border: 1px solid var(--accent-line);
}
.brand-mark img { width: 100%; height: 100%; object-fit: cover; }
.brand-text { min-width: 0; }
.brand-name { font-weight: 620; font-size: 14px; letter-spacing: -0.015em; }
.brand-sub { font-size: 11.5px; color: var(--text-3); }

.nav-list { display: flex; flex-direction: column; gap: 2px; padding: 0 var(--s-3); }
.nav {
  display: flex; align-items: center; gap: var(--s-3);
  width: 100%; padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-2);
  font: 500 13.5px/1 var(--sans); text-align: left; cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.nav svg { width: 17px; height: 17px; flex: none; opacity: .75; }
.nav:hover { background: var(--surface-2); color: var(--text); }
.nav.active {
  background: var(--accent-dim); color: var(--accent);
  box-shadow: inset 2px 0 0 var(--accent);
}
.nav.active svg { opacity: 1; }
.nav-count {
  margin-left: auto; min-width: 19px; height: 19px; padding: 0 6px;
  border-radius: var(--r-pill); background: var(--bad); color: #fff;
  font: 600 11px/19px var(--sans); text-align: center;
}
.nav-count.hidden { display: none; }

.sidebar-bottom { margin-top: auto; padding: var(--s-3); display: grid; gap: var(--s-3); }

/* System widget: a status line, not a decoration. Dot + label + sparkline. */
.sys-widget {
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface-2); padding: 10px 12px;
}
.sys-head { display: flex; align-items: center; gap: 8px; }
.sys-label { font-size: 12px; color: var(--text-2); }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-3); flex: none; }
.dot.ok { background: var(--good); box-shadow: 0 0 0 3px var(--good-dim); }
.dot.warn { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-dim); }
.dot.bad, .dot.failed { background: var(--bad); box-shadow: 0 0 0 3px var(--bad-dim); }
.sys-spark { width: 100%; height: 22px; margin-top: 6px; }
.sys-foot { font-size: 11px; color: var(--text-3); margin-top: 4px; }

.profile { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--r-sm); }
.profile:hover { background: var(--surface-2); }
.avatar {
  width: 28px; height: 28px; border-radius: 50%; flex: none;
  background: var(--accent-dim); color: var(--accent);
  display: grid; place-items: center; font: 600 12px/1 var(--sans);
}
.profile-text { min-width: 0; flex: 1; }
.profile-name { font-size: 13px; font-weight: 550; }
.profile-role { font-size: 11px; color: var(--text-3); }

/* ── main column ─────────────────────────────────────────────────────────── */
.main-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; }
#main-scroll { flex: 1; min-width: 0; }

.topbar {
  position: sticky; top: 0; z-index: 30;
  height: var(--topbar-h); flex: none;
  display: flex; align-items: center; gap: var(--s-4);
  padding: 0 var(--s-6);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.topbar-title { min-width: 0; display: grid; gap: 3px; }
.topbar-title h1, .topbar-title p { margin: 0; }
#page-title { font: 600 15.5px/1.25 var(--sans); letter-spacing: -0.02em; }
#page-subtitle { font-size: 12.5px; line-height: 1.3; color: var(--text-3); }
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: var(--s-2); }
.head-tools { display: flex; align-items: center; gap: var(--s-2); }

.icon-btn {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text-2); cursor: pointer;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
  position: relative;
}
.icon-btn svg { width: 17px; height: 17px; }
.icon-btn:hover { background: var(--surface-3); color: var(--text); }
.menu-btn, .sidebar-close { display: none; }

.badge-dot {
  position: absolute; top: -5px; right: -5px; min-width: 17px; height: 17px;
  padding: 0 5px; border-radius: var(--r-pill);
  background: var(--bad); color: #fff;
  font: 600 10.5px/17px var(--sans); text-align: center;
  border: 2px solid var(--bg);
}

/* search */
/* One element, not two: the markup is <div class="search" id="search-wrap">.
   Styling ".search-wrap" as a child matched nothing, which is why the search
   field had no frame and its placeholder ran out of the box. */
.search, .search-wrap {
  position: relative;
  display: flex; align-items: center; gap: 8px;
  height: 30px; padding: 0 10px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  transition: border-color .12s ease, background .12s ease;
}
.search.focused, .search-wrap.focused { border-color: var(--text-3); background: var(--surface-2); }
.search-icon { width: 15px; height: 15px; color: var(--text-3); flex: none; }
.search input, .search-wrap input {
  border: 0; background: transparent; color: var(--text);
  font: 400 13.5px/1 var(--sans); width: 190px; outline: none;
}
.search input::placeholder, .search-wrap input::placeholder { color: var(--text-3); }
.kbd {
  font-size: 10.5px; color: var(--text-3);
  border: 1px solid var(--line); border-radius: 4px; padding: 2px 5px; background: var(--surface-2);
}
.search-results {
  position: absolute; top: calc(100% + 6px); right: 0; width: 340px; max-height: 380px;
  overflow-y: auto; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--lift-2); padding: 6px; z-index: 60;
}
.search-item {
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 10px; border-radius: var(--r-sm); cursor: pointer;
}
.search-item:hover, .search-item.sel { background: var(--surface-3); }
.si-main { font-size: 13px; }
.si-sub { font-size: 11.5px; color: var(--text-3); }
.search-empty { padding: 14px; color: var(--text-3); font-size: 13px; text-align: center; }

/* notifications */
.notif-panel {
  position: absolute; top: calc(100% + 6px); right: var(--s-5); width: 350px; max-height: 440px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--lift-2); z-index: 60; display: flex; flex-direction: column;
}
.notif-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--line-soft);
  font-size: 13px; font-weight: 600;
}
.notif-list { overflow-y: auto; padding: 6px; }
.notif-item { display: flex; gap: 10px; padding: 10px; border-radius: var(--r-sm); }
.notif-item:hover { background: var(--surface-2); }
.ni-title { font-size: 13px; font-weight: 550; }
.ni-sub { font-size: 12px; color: var(--text-2); }
.ni-time { font-size: 11px; color: var(--text-3); margin-left: auto; white-space: nowrap; }
.notif-empty { padding: 28px 14px; text-align: center; color: var(--text-3); font-size: 13px; }
.link-btn { background: 0; border: 0; color: var(--text-2); font: 500 12px var(--sans); cursor: pointer; }
.link-btn:hover { color: var(--text); }

/* ── views and sections ──────────────────────────────────────────────────── */
.view { display: none; padding: var(--s-6) var(--s-6) var(--s-7); max-width: 1360px; }
.view.active { display: block; }
.view.narrow, .section.narrow { max-width: 720px; }

.section { margin-bottom: var(--s-7); }
.section-head {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-5);
}
.section-head h2 {
  margin: 0; font: 600 15px/1.25 var(--sans);
  letter-spacing: -0.012em; color: var(--text);
}
.section-meta { font-size: 12px; color: var(--text-3); margin-left: auto; }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s-5);
}
.card-title {
  display: flex; align-items: center; gap: 8px;
  font: 600 14px/1.3 var(--sans); letter-spacing: -0.01em; margin-bottom: 6px;
}
.card-title svg { width: 16px; height: 16px; color: var(--text-3); }
.card-sub { font-size: 12.5px; color: var(--text-3); margin: 0 0 var(--s-4); line-height: 1.45; }
.hint { font-size: 12px; color: var(--text-3); margin: var(--s-2) 0 0; }

.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--s-3); }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--s-3); }
.grid-2 > *, .grid-4 > *, .liq-grid > * { min-width: 0; }   /* or a wide chart forces page scroll */
.wide-left { grid-template-columns: 1.6fr 1fr; }

/* ── KPI tiles ───────────────────────────────────────────────────────────── */
/* .kpi is the TILE, .kpi-value is the number. Putting the display size on
   .kpi made the label and footer inherit 26px, which is what made these tiles
   look enormous and shoved everything else out of place. */
.kpi {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: var(--s-4);
}
.kpi-label {
  display: flex; align-items: center; gap: 9px;
  font-size: 12.5px; font-weight: 500; color: var(--text-2);
}
/* The icon chip IS the svg -- background and padding on a replaced element --
   so no wrapper had to be threaded through the JS that builds these tiles. */
.kpi-label svg {
  width: 15px; height: 15px; flex: none; box-sizing: content-box;
  padding: 7px; border-radius: 9px;
  background: var(--accent-dim); color: var(--accent);
}
.kpi-value { font: 600 25px/1.15 var(--sans); letter-spacing: -0.025em; margin-top: 12px; }
.kpi-value.sm { font-size: 18px; }
.kpi-foot { display: flex; align-items: center; gap: 5px; margin-top: 6px; font-size: 11.5px; color: var(--text-3); }
.delta { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; }
.delta.up { color: var(--good); }
.delta.down { color: var(--bad); }
.delta.flat { color: var(--text-3); }
.delta-note { color: var(--text-3); font-weight: 400; }

/* ── money row ───────────────────────────────────────────────────────────── */
.figure-row { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 0; padding: 0; }
.figure { padding: var(--s-4); border-right: 1px solid var(--line-soft); min-width: 0; }
.figure:last-child { border-right: 0; }
.figure-label { font-size: 12px; font-weight: 500; color: var(--text-2); }
.figure-value { font: 600 20px/1.2 var(--sans); letter-spacing: -0.025em; margin: 7px 0 9px; }
.spark { display: block; width: 100%; height: 30px; }
.spark-pt { fill: currentColor; }

/* ── liquidity ───────────────────────────────────────────────────────────── */
.liq-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px,1fr)); gap: var(--s-3); }
.liq-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: var(--s-4); }
.liq-top { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.liq-name { font-size: 12px; color: var(--text-2); }
.coin {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font: 700 11px/1 var(--sans); color: #0D0E10;
}
/* LTC and SOL are the real marks, drawn from the published brand geometry --
   Litecoin's blue (#345D9D), not the silver the icon packs still ship, and
   Solana's actual green-to-purple gradient rather than a flat swatch. */
svg.coin { display: block; background: none; }
.coin.dsmp { background: var(--dsmp); }
.liq-value { font: 600 16px/1.2 var(--sans); letter-spacing: -0.02em; }
.liq-value.blue { color: var(--text); }
.liq-value.purple { color: var(--sol); }
.liq-value.cyan { color: var(--dsmp); }
.liq-usd { font-size: 12px; color: var(--text-3); margin-top: 3px; }
.meter { height: 5px; border-radius: 3px; background: var(--surface-3); margin-top: 10px; overflow: hidden; }
.meter > i { display: block; height: 100%; background: var(--accent); border-radius: 2px; }
.meter-legend { font-size: 11px; color: var(--text-3); margin-top: 5px; }

/* ── market switches ─────────────────────────────────────────────────────── */
.mkt { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); }
.mkt-text { flex: 1; min-width: 0; }
.mkt-name { font-weight: 600; font-size: 12.5px; }
.mkt-state { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.mkt-state.closed { color: var(--bad); font-weight: 550; }

.sw { position: relative; flex: none; width: 42px; height: 24px; }
.sw input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.sw-track {
  position: absolute; inset: 0; border-radius: var(--r-pill);
  background: var(--surface-3); border: 1px solid var(--line);
  transition: background .15s ease, border-color .15s ease; pointer-events: none;
}
.sw-thumb {
  position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--text-2); transition: transform .15s ease, background .15s ease;
  pointer-events: none;
}
.sw input:checked ~ .sw-track { background: var(--good); border-color: transparent; }
.sw input:checked ~ .sw-thumb { transform: translateX(18px); background: #08120D; }
.sw input:disabled { cursor: progress; }
.sw input:focus-visible ~ .sw-track { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 30px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text);
  font: 550 13px/1 var(--sans); cursor: pointer; white-space: nowrap;
  transition: background .12s ease, border-color .12s ease, opacity .12s ease;
}
.btn svg { width: 15px; height: 15px; }
.btn:hover { background: var(--surface-3); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.primary {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
  font-weight: 600; box-shadow: 0 1px 12px -4px var(--accent-line);
}
.btn.primary:hover { opacity: .88; background: var(--accent); }
.btn.danger { background: transparent; color: var(--bad); border-color: color-mix(in srgb, var(--bad) 40%, var(--line)); }
.btn.danger:hover { background: var(--bad-dim); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn.ghost:hover { background: var(--surface-2); color: var(--text); }
.btn.resume { color: var(--good); border-color: color-mix(in srgb, var(--good) 40%, var(--line)); background: transparent; }
.btn.resume:hover { background: var(--good-dim); }
.btn.lg { height: 36px; padding: 0 16px; font-size: 13px; }
.btn.sm { height: 26px; padding: 0 9px; font-size: 11.5px; }
.btn.loading { opacity: .7; pointer-events: none; }
.card-actions { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.back-btn { margin-bottom: var(--s-3); }

/* ── inputs ──────────────────────────────────────────────────────────────── */
/* A settings field is written as <input data-setting="..."> with NO type
   attribute. [type="text"] does not match an absent attribute, so every input
   on the Settings screen fell straight through to the raw browser control --
   21px tall, square corners, mid-grey. That is the "it still looks like
   Chrome" complaint, and it was never about the dropdowns.
   :where() holds this at element specificity so .search input, .mc-row input
   and the rest still override it. */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="submit"]):not([type="button"])),
textarea, select, .select {
  height: 30px; padding: 0 9px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font: 400 13.5px/1 var(--sans); outline: none;
  transition: border-color .12s ease, background .12s ease;
}
textarea { height: auto; padding: 10px; line-height: 1.5; resize: vertical; }
input:focus, textarea:focus, select:focus { border-color: var(--text-3); background: var(--surface); }
input::placeholder, textarea::placeholder { color: var(--text-3); }
input:disabled { opacity: .55; }

/* Native select styled to match, so it never looks like a browser default
   dropped into the page. */
select {
  appearance: none;
  padding-right: 30px;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-3) 50%),
                    linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 15px) 12px, calc(100% - 10px) 12px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.input-money { display: flex; align-items: center; position: relative; flex: 1; min-width: 0; }
.input-money .prefix { position: absolute; left: 10px; color: var(--text-3); font-size: 13.5px; pointer-events: none; }
.input-money input { padding-left: 22px; width: 100%; }

.field { display: grid; gap: 6px; margin-bottom: var(--s-3); }
.field > label, .field > span { font-size: 12px; color: var(--text-2); }

.restock-card { display: flex; flex-direction: column; }
.restock-row { display: flex; gap: var(--s-2); align-items: center; }
#restock-result, #wd-result { margin-top: 10px; font-size: 12.5px; }
#restock-result.ok, #wd-result.ok { color: var(--good); }
#restock-result.err, #wd-result.err { color: var(--bad); }

/* ── withdraw: available + presets ────────────────────────────────────────
   The note only appears when the free float is smaller than the balance, so
   a Max that is lower than you expected always explains itself on the spot. */
.avail-row {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-bottom: var(--s-3); padding: 9px 11px;
  background: var(--surface-2); border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
}
.avail-label { font-size: 11.5px; color: var(--text-3); }
.avail-value { margin-left: auto; font: 600 14px/1 var(--sans); letter-spacing: -0.015em; }
.avail-note { flex: 0 0 100%; font-size: 11px; color: var(--warn); }
.avail-row:not(.has-hold) .avail-note { display: none; }

.chip-row { display: flex; gap: 6px; margin-top: var(--s-2); }
.chip {
  height: 27px; padding: 0 12px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--line);
  color: var(--text-2); font: 500 11.5px/1 var(--sans); cursor: pointer;
}
.chip:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }
.chip.on { background: var(--accent-dim); border-color: var(--accent-line); color: var(--accent); }
.chip:disabled { opacity: .45; cursor: not-allowed; }

/* ── payout routing rows ──────────────────────────────────────────────── */
.route-row {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  padding: 9px 0; border-top: 1px solid var(--line-soft);
}
.route-row:first-of-type { border-top: 0; }
.route-coin {
  font: 600 11px/1 var(--sans); letter-spacing: .06em; color: var(--text-3);
  min-width: 34px;
}
.route-ign { font-family: var(--mono); font-size: 12.5px; }
.route-owner { font-size: 12px; color: var(--text-3); }
.route-row .badge { margin-left: auto; }
.route-row.bad .route-ign { color: var(--bad); }

.pay-network {
  font-size: 11.5px; color: var(--warn); margin: 2px 0 8px; line-height: 1.4;
}

/* ── tables ──────────────────────────────────────────────────────────────── */
.table-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.table-scroll { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
thead th {
  text-align: left; font: 600 11px/1 var(--sans);
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-3);
  padding: 8px 12px; background: var(--surface-2); border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
tbody td { padding: 8px 12px; border-bottom: 1px solid var(--line-soft); color: var(--text-2); }
tbody tr:last-child td { border-bottom: 0; }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover td { background: var(--surface-2); color: var(--text); }
td .mono { font-size: 12.5px; }
.empty-row td, .empty-state { color: var(--text-3); text-align: center; padding: var(--s-6) var(--s-4); }
.recent-table td:first-child, .recent-table th:first-child { padding-left: var(--s-4); }
.toolbar-row { display: flex; gap: var(--s-2); align-items: center; margin-bottom: var(--s-3); flex-wrap: wrap; }

/* ── status pills ────────────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 21px; padding: 0 8px; border-radius: var(--r-pill);
  font: 600 11.5px/1 var(--sans);
  background: var(--surface-3); color: var(--text-2);
  border: 1px solid transparent;
}
.badge.completed { background: var(--good-dim); color: var(--good); }
.badge.failed, .badge.danger { background: var(--bad-dim); color: var(--bad); }
.badge.warn { background: var(--warn-dim); color: var(--warn); }
.badge.ok { background: var(--good-dim); color: var(--good); }
.badge .m-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }

/* ── health strip ────────────────────────────────────────────────────────── */
/* One line per service. The markup is a row of SPANS, not divs -- styling
   ".health-strip > div" matched nothing, which is why this looked unstyled and
   its dividers drew through the middle of the section when it wrapped.
   Dividers are gone entirely: a wrapping grid with border-right always draws a
   line where a column ends mid-row, and a gap says the same thing safely. */
.health-strip {
  display: flex; flex-wrap: wrap; gap: 6px;
  background: transparent; border: 0; padding: 0;
}
.hs-item {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 10px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-pill);
  font-size: 12px; white-space: nowrap;
}
.hs-name { color: var(--text-3); }
.hs-state { color: var(--text); font-weight: 550; }
.hs-item.bad .hs-state, .hs-item.failed .hs-state { color: var(--bad); }
.hs-item.warn .hs-state { color: var(--warn); }
.hs-updated { font-size: 11px; color: var(--text-3); }

/* ── banners ─────────────────────────────────────────────────────────────── */
.alert-banner {
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-3) var(--s-4); margin-bottom: var(--s-4);
  border: 1px solid color-mix(in srgb, var(--bad) 35%, var(--line));
  background: var(--bad-dim); border-radius: var(--r);
}
.ab-title { font-weight: 600; font-size: 13.5px; color: var(--bad); }
.ab-sub, .ab-body { font-size: 12.5px; color: var(--text-2); }

/* ── chart ───────────────────────────────────────────────────────────────── */
.chart-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: var(--s-4); }
/* No horizontal scroll. The chart is redrawn to the holder's width on every
   render and resize, so it never needs to scroll -- and an auto overflow here
   produced a scrollbar for a couple of stray pixels. */
.chart-holder { position: relative; overflow: hidden; }
#activity-chart { display: block; width: 100%; height: 250px; }
.chart-tip {
  position: absolute; pointer-events: none; z-index: 5;
  background: var(--surface-3); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 7px 10px; font-size: 12px; box-shadow: var(--lift-2); white-space: nowrap;
}
.ct-date { color: var(--text-3); font-size: 11px; }
.ct-row { display: flex; align-items: center; gap: 6px; }

/* ── in-game console ─────────────────────────────────────────────────────── */
.mc-log {
  font: 12px/1.55 var(--mono);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 10px 12px; height: 170px; overflow-y: auto;
  white-space: pre-wrap; word-break: break-word; color: var(--text-2);
}
.mc-log .me { color: var(--text); }
.mc-row { display: flex; gap: var(--s-2); margin-top: var(--s-3); }
.mc-row input { flex: 1; min-width: 0; font-family: var(--mono); font-size: 13px; }

/* ── order detail ────────────────────────────────────────────────────────── */
.detail-head { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; margin-bottom: var(--s-5); }
.detail-head h2 { margin: 0; font: 600 17px/1.25 var(--sans); letter-spacing: -0.02em; }
.kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px,1fr)); gap: var(--s-4) var(--s-5); }
.kv { display: grid; gap: 4px; min-width: 0; align-content: start; }
.kv .kpi-label, .kv > em, .kv > span:first-child {
  font-size: 11.5px; color: var(--text-3); font-style: normal;
}
.kv > b, .kv > span:last-child {
  font-size: 13.5px; font-weight: 550; min-width: 0;
  overflow-wrap: anywhere; word-break: break-word;
}
.kv > b.mono { font-size: 12px; line-height: 1.45; }
.code-row { display: flex; align-items: center; gap: 8px; }
.copy-btn {
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text-2);
  border-radius: var(--r-sm); height: 26px; padding: 0 8px; font-size: 11.5px; cursor: pointer;
}
.copy-btn:hover { background: var(--surface-3); color: var(--text); }
.copy-btn.copied { color: var(--good); border-color: color-mix(in srgb, var(--good) 40%, var(--line)); }

.timeline { display: grid; gap: 0; }
.tl-item { display: grid; grid-template-columns: 18px 1fr; gap: var(--s-3); }
.tl-rail { display: grid; justify-items: center; }
.tl-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--text-3); margin-top: 5px; }
.tl-item.ok .tl-dot { background: var(--good); }
.tl-item.failed .tl-dot { background: var(--bad); }
.tl-line { width: 1px; flex: 1; background: var(--line); min-height: 18px; }
.tl-body { padding-bottom: var(--s-3); }
.tl-msg { font-size: 13px; }
.tl-time { font-size: 11.5px; color: var(--text-3); }

/* ── review queue ────────────────────────────────────────────────────────── */
.review-card {
  display: flex; gap: var(--s-4); align-items: flex-start;
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--bad);
  border-radius: var(--r); padding: var(--s-4); margin-bottom: var(--s-3);
}
.review-main { flex: 1; min-width: 0; }
.review-reason { font-size: 12.5px; color: var(--text-2); margin-top: 4px; }

/* ── settings ────────────────────────────────────────────────────────────── */
.settings-grid { display: grid; gap: var(--s-5); }
.settings-group { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: var(--s-4); }
.settings-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); gap: var(--s-3); }
.save-bar {
  position: sticky; bottom: 0; z-index: 20;
  display: flex; justify-content: flex-end; gap: var(--s-2);
  padding: var(--s-3) 0; margin-top: var(--s-4);
  background: linear-gradient(to top, var(--bg) 70%, transparent);
}

/* ── 2FA ─────────────────────────────────────────────────────────────────── */
.qr { background: #fff; padding: 10px; border-radius: var(--r-sm); display: inline-block; }
.qr img, .qr canvas { display: block; }

/* ── sign-in and account setup ────────────────────────────────────
   These were dropped when the stylesheet was rewritten: login.html has been
   rendering as a bare unstyled form on a default background ever since. It is
   the first screen anyone sees, and the only one a new person sees. */
.login-body {
  min-height: 100vh; margin: 0; display: grid; place-items: center;
  padding: var(--s-5); background: var(--bg); color: var(--text);
  font: 400 14px/1.5 var(--sans);
}
.login-card {
  width: 100%; max-width: 380px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s-6);
  box-shadow: var(--lift-3);
}
.login-brand { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-6); }
.login-brand .brand-mark { width: 38px; height: 38px; border-radius: 11px; }
.login-card .field { margin-bottom: var(--s-4); }
.login-card .field > span { font-size: 12px; color: var(--text-2); }
.login-card input { width: 100%; height: 36px; }
.login-card .subtitle { margin: 0 0 var(--s-5); font-size: 12.5px; line-height: 1.5; }
.login-card .hint { margin: calc(var(--s-2) * -1) 0 var(--s-4); }
.btn.full { width: 100%; justify-content: center; height: 38px; font-size: 13.5px; }
.error-box {
  background: var(--bad-dim); border: 1px solid color-mix(in srgb, var(--bad) 35%, transparent);
  color: var(--bad); border-radius: var(--r-sm);
  padding: 9px 11px; font-size: 12.5px; margin-bottom: var(--s-4);
}

/* ── modal ───────────────────────────────────────────────────────────────── */
.modal-root {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: rgba(0,0,0,.6);
  padding: var(--s-4);
}
.modal {
  width: min(460px, 100%);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--lift-3);
  padding: var(--s-5);
}
.modal h3 { margin: 0 0 var(--s-2); font: 600 16px/1.3 var(--sans); letter-spacing: -0.015em; }
.modal p { margin: 0 0 var(--s-4); color: var(--text-2); font-size: 13.5px; }
.modal-actions { display: flex; justify-content: flex-end; gap: var(--s-2); margin-top: var(--s-4); }

/* ── toasts ──────────────────────────────────────────────────────────────── */
.toast-stack {
  position: fixed; right: var(--s-4); bottom: var(--s-4); z-index: 120;
  display: grid; gap: var(--s-2); width: min(340px, calc(100vw - 32px));
}
.toast-stack > div {
  display: flex; gap: 10px; align-items: flex-start;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--lift-2); padding: 12px 14px;
  animation: toast-in .18s ease;
}
.toast-stack > div.out { animation: toast-out .18s ease forwards; }
.t-icon { width: 16px; height: 16px; flex: none; margin-top: 1px; color: var(--text-3); }
.t-title { font-size: 13px; font-weight: 600; }
.t-sub { font-size: 12px; color: var(--text-2); }
.t-close { margin-left: auto; background: 0; border: 0; color: var(--text-3); cursor: pointer; font-size: 15px; line-height: 1; }
@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(6px); } }

/* ── misc ────────────────────────────────────────────────────────────────── */
code {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 4px; padding: 1px 5px; font-size: 12.5px;
}
.legend { display: flex; gap: var(--s-3); flex-wrap: wrap; font-size: 12px; color: var(--text-3); }
.unit, .subtitle { color: var(--text-3); font-size: 12px; }
.pay-live { color: var(--good); }
.backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.5);
  z-index: 35; opacity: 0; pointer-events: none; transition: opacity .18s ease;
}
.backdrop.open { opacity: 1; pointer-events: auto; }

/* ── responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 1100px) {
  .grid-4, .figure-row { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .figure { border-bottom: 1px solid var(--line-soft); }
  .figure:nth-child(even) { border-right: 0; }
  .wide-left { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
  .search input { width: 120px; }
  .sidebar {
    position: fixed; inset: 0 auto 0 0;
    transform: translateX(-100%); transition: transform .2s ease;
    box-shadow: var(--lift-3);
  }
  .sidebar.open { transform: none; }
  .menu-btn, .sidebar-close { display: grid; }
  .sidebar-close { position: absolute; top: 12px; right: 12px; }
  .view { padding: var(--s-4); }
  .topbar { padding: 0 var(--s-4); }
  .search-wrap input { width: 120px; }
  .kbd { display: none; }
  .notif-panel { right: var(--s-4); width: calc(100vw - 32px); }
}
@media (max-width: 620px) {
  .grid-2, .grid-4, .figure-row { grid-template-columns: 1fr; }
  .figure { border-right: 0; }
  #page-subtitle { display: none; }
  .search { display: none; }
  .restock-row { flex-wrap: wrap; }
  .restock-row > * { flex: 1 1 100%; }
  .toast-stack { left: var(--s-4); right: var(--s-4); width: auto; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ── Custom select ────────────────────────────────────────────────────────
   app.js replaces every native <select> with a button + menu so the dropdown
   matches the rest of the interface instead of looking like a browser default
   dropped into the page. That widget had NO styles in this stylesheet, which
   is why the chevron rendered at its natural SVG size (a huge grey block) and
   the native select showed through underneath it.

   The native element is hidden only once JS has actually enhanced it, so if
   the script fails the real control is still there and usable. */
.sel { position: relative; display: inline-flex; min-width: 0; }
select[data-enhanced] { display: none !important; }

.sel-btn {
  display: flex; align-items: center; gap: 8px;
  width: 100%; height: 30px; padding: 0 9px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font: 400 13px/1 var(--sans); cursor: pointer; text-align: left;
  transition: background .12s ease, border-color .12s ease;
}
.sel-btn:hover { background: var(--surface-3); }
.sel-btn[aria-expanded="true"] { border-color: var(--text-3); background: var(--surface); }
.sel-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sel-chev { width: 13px; height: 13px; flex: none; color: var(--text-3); }

.sel-menu {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 70;
  min-width: 100%; max-height: 260px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-sm); box-shadow: var(--lift-2); padding: 4px;
}
.sel-opt {
  display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 7px 8px; border: 0; border-radius: 4px;
  background: transparent; color: var(--text-2);
  font: 400 13px/1 var(--sans); text-align: left; cursor: pointer; white-space: nowrap;
}
.sel-opt:hover { background: var(--surface-3); color: var(--text); }
.sel-opt.current { color: var(--text); }
.sel-opt > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sel-tick { width: 13px; height: 13px; flex: none; opacity: 0; color: var(--good); }
.sel-opt.current .sel-tick { opacity: 1; }

/* ── Settings ─────────────────────────────────────────────────────────────
   Was a row of full-width bars: every input stretched to a quarter of a very
   wide screen, so a two-character rate got the same 340px as a wallet address
   and the eye had nothing to anchor on. Fields are capped and the label sits
   tight to its input so each one reads as a pair. */
.settings-group { padding: var(--s-5) var(--s-5) var(--s-6); }
.settings-group > .card-title,
.settings-group > h3 {
  font: 600 10.5px/1 var(--sans); letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-3); margin: 0 0 var(--s-4);
}
/* Groups sit two across so the form fills the width, and the fields inside
   each group wrap at three -- rather than one long strip of six squeezed
   inputs with the whole page empty underneath it. */
.settings-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 430px), 1fr));
  align-items: start;
}
.settings-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: var(--s-5); align-items: start;
}
.settings-fields input, .settings-fields select, .settings-fields .sel-btn { height: 34px; }
.settings-fields .field { margin: 0; gap: 5px; }
.settings-fields .field > label,
.settings-fields .field > span {
  font-size: 12px; color: var(--text-2); font-weight: 500;
  display: flex; align-items: baseline; gap: 5px;
}
.settings-fields .field .unit { font-size: 10.5px; font-style: normal; color: var(--text-3); }
.settings-fields input, .settings-fields select, .settings-fields .sel { max-width: 100%; }
.save-bar { align-items: center; gap: var(--s-4); }
.save-bar .hint { margin: 0; }

/* ── Native controls, made native to THIS site ────────────────────────────
   Anything the browser draws itself is a visitor from another design system:
   scrollbars, number spinners, the search field's clear button, checkboxes.
   Left alone they read as Chrome dropped into the page, which is exactly the
   thing this interface is not supposed to look like. */

/* Scrollbars. Firefox takes the two-value shorthand; WebKit needs the parts. */
* { scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--surface-3); border-radius: var(--r-pill);
  border: 2px solid var(--bg);          /* inset, so it reads as a slim bar */
}
::-webkit-scrollbar-thumb:hover { background: #333940; }
::-webkit-scrollbar-corner { background: transparent; }

/* Scroll areas that sit on a card get a thumb matched to the card, not the page. */
.mc-log::-webkit-scrollbar-thumb,
.sel-menu::-webkit-scrollbar-thumb,
.notif-list::-webkit-scrollbar-thumb,
.search-results::-webkit-scrollbar-thumb,
.table-scroll::-webkit-scrollbar-thumb { border-color: var(--surface); }

/* Number inputs: the spinner arrows are unstyleable and always look foreign.
   Every number field here is typed, never nudged. */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* Search fields draw their own clear button and magnifier in WebKit. */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button { -webkit-appearance: none; }

/* Checkboxes and radios, drawn rather than inherited. */
input[type="checkbox"], input[type="radio"] {
  appearance: none; width: 16px; height: 16px; flex: none; margin: 0;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 4px; cursor: pointer; position: relative;
  transition: background .12s ease, border-color .12s ease;
}
input[type="radio"] { border-radius: 50%; }
input[type="checkbox"]:hover, input[type="radio"]:hover { border-color: var(--text-3); }
input[type="checkbox"]:checked, input[type="radio"]:checked {
  background: var(--accent); border-color: var(--accent);
}
input[type="checkbox"]:checked::after {
  content: ''; position: absolute; left: 5px; top: 1.5px;
  width: 4px; height: 9px; border: solid var(--accent-ink);
  border-width: 0 2px 2px 0; transform: rotate(45deg);
}
input[type="radio"]:checked::after {
  content: ''; position: absolute; inset: 4px;
  border-radius: 50%; background: var(--accent-ink);
}

/* The autofill wash is Chrome's, and it is always the wrong colour. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--text);
  -webkit-box-shadow: 0 0 0 1000px var(--surface-2) inset;
  caret-color: var(--text);
}

/* Date/time pickers keep their native popup, but the indicator can at least
   match the palette instead of being black on dark. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator { filter: invert(.65); cursor: pointer; }
:root[data-theme="light"] input[type="date"]::-webkit-calendar-picker-indicator { filter: none; }

/* ══ Tidy-up pass ═════════════════════════════════════════════════════════
   Fixes found by looking at the thing on a wide screen rather than at the
   markup: dead space down the right, icons drawn at their natural size, and
   a couple of layouts that only break once there is room to break in. */

/* Use the whole window. The 1360px cap left a third of a wide screen empty
   while the tables inside it were still scrolling horizontally. Content now
   fills, with a generous cap so text lines never become unreadably long. */
.view { max-width: none; width: 100%; }
.view > .section, .view > .alert-banner, .view > .health-strip { max-width: 1600px; }
.view.narrow, .section.narrow { max-width: 720px; }

/* Any inline SVG without its own width renders at natural size. That is how a
   32px tick became a 900px checkmark filling the Manual Review screen. Every
   icon context gets an explicit size, and a defensive default catches any new
   one added later. */
svg:where(:not([width]):not([height])) { width: 16px; height: 16px; }
.qr svg { width: auto; height: auto; }
.empty-state svg:not([width]):not([height]) { width: 28px; height: 28px; display: block; margin: 0 auto var(--s-3); color: var(--text-3); }
.t-icon svg { width: 15px; height: 15px; }
.modal-icon svg { width: 20px; height: 20px; }
.delta svg { width: 11px; height: 11px; }
.btn svg, .icon-btn svg, .nav svg, .card-title svg, .kpi-label svg { width: 15px; height: 15px; }
.nav svg { width: 16px; height: 16px; }

.empty-state {
  display: grid; place-items: center; gap: 2px;
  padding: var(--s-7) var(--s-4); color: var(--text-3); font-size: 13px;
}

/* The two ends of a meter's scale belong at the two ends of the meter --
   stacked in normal flow they read as one word: "LowHealthy". */
.meter-legend {
  display: flex; justify-content: space-between;
  font-size: 10.5px; color: var(--text-3); margin-top: 4px;
}

/* Search was too narrow to show what it searches. */
.search input, .search-wrap input { width: 240px; }
@media (max-width: 1100px) { .search input, .search-wrap input { width: 160px; } }

/* Modal icon, which had no styling at all. */
.modal-icon {
  width: 34px; height: 34px; border-radius: var(--r-sm); flex: none;
  display: grid; place-items: center; margin-bottom: var(--s-3);
  background: var(--surface-3); color: var(--text-2);
}
.modal-icon.danger { background: var(--bad-dim); color: var(--bad); }

/* ── Smoothing ────────────────────────────────────────────────────────────
   Motion is limited to things that actually change state. Nothing animates on
   load, because a dashboard that fades in every time you glance at it is
   slower to read, not nicer. */
.card, .kpi, .liq-card, .mkt, .hs-item, .table-card, .chart-card, .settings-group {
  transition: border-color .14s ease, background-color .14s ease;
}
tbody tr.clickable { transition: background-color .1s ease; }
.nav, .btn, .icon-btn, .sel-btn, .sel-opt, .copy-btn, .search-wrap { transition: all .14s ease; }
.btn:active, .icon-btn:active, .sel-btn:active { transform: translateY(1px); }
.sel-menu, .notif-panel, .search-results { animation: pop .13s ease; transform-origin: top; }
@keyframes pop { from { opacity: 0; transform: scale(.98) translateY(-3px); } }

/* Hover states that were missing, so cards felt inert. */
.kpi:hover, .liq-card:hover { border-color: #2E333A; }

/* ═══════════════════════════════════════════════════════════════════════════
   GLASS — appended layer, 2026-08-22
   ═══════════════════════════════════════════════════════════════════════════
   Everything below overrides the palette above by cascade order alone. To go
   back, delete from this banner to the end of the file; nothing above it was
   edited, so there is no unpicking to do.

   THREE THINGS MAKE THIS READ AS GLASS

   1. An ambient ground. Translucent surfaces over a flat colour blur to that
      same flat colour and nothing happens -- which is why the one
      backdrop-filter already in this file never looked like anything. Three
      very soft blooms on the body give the blur something to pick up.
   2. A lit top edge on every raised surface. One inset highlight, and it is
      the detail the eye reads as a pane catching light.
   3. Neutral chrome. The accent is a grey, so colour now means status and
      nothing else -- a green pill carries information instead of competing
      with a coloured button beside it.

   BLUR IS NOT FREE. It is applied to the sidebar, topbar, cards, modals and
   the notification panel only -- never table rows, pills or buttons, which
   would put dozens of blurred layers on one scrolling screen.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Surfaces become translucent. Kept deliberately close together: stacking a
     0.075 surface inside a 0.045 one already compounds, and a third nested
     level turns to milk. */
  --surface:   rgba(255,255,255,.045);
  --surface-2: rgba(255,255,255,.075);
  --surface-3: rgba(255,255,255,.105);
  --line:      rgba(255,255,255,.09);
  --line-soft: rgba(255,255,255,.05);

  /* Neutral chrome. The charts are unaffected -- they draw with --green,
     --accent-2 and --cyan-bright, never this. */
  --accent:      #A8B0B8;
  --accent-ink:  #14161A;
  --accent-dim:  rgba(255,255,255,.09);
  --accent-line: rgba(255,255,255,.18);

  --r: 12px; --r-lg: 18px;

  --glass-blur: blur(22px) saturate(140%);
  --glass-edge: inset 0 1px 0 rgba(255,255,255,.09);
  --glass-drop: 0 10px 34px -14px rgba(0,0,0,.7);
}

/* The light theme gets the same treatment inverted: dark glass over a pale
   ground is white-on-white, so the surfaces tint down rather than up. */
:root[data-theme="light"] {
  --surface:   rgba(255,255,255,.72);
  --surface-2: rgba(16,24,40,.05);
  --surface-3: rgba(16,24,40,.08);
  --line:      rgba(16,24,40,.10);
  --line-soft: rgba(16,24,40,.06);
  --accent:      #59626B;
  --accent-ink:  #FFFFFF;
  --accent-dim:  rgba(16,24,40,.06);
  --accent-line: rgba(16,24,40,.16);
  --glass-edge: inset 0 1px 0 rgba(255,255,255,.75);
  --glass-drop: 0 10px 30px -16px rgba(16,24,40,.22);
}

/* ── the ambient ground ────────────────────────────────────────────────────
   On the body rather than the .ambient div: a fixed element behind everything
   has to sit at a negative z-index, which puts it behind the body background
   as well and makes it invisible. Painting the body directly avoids the whole
   stacking question. */
body {
  background-color: var(--bg);
  background-image:
    radial-gradient(820px 500px at 10% -8%, rgba(150,170,190,.10), transparent 62%),
    radial-gradient(700px 540px at 94% 4%,  rgba(120,135,155,.09), transparent 60%),
    radial-gradient(960px 680px at 50% 110%, rgba(100,115,135,.08), transparent 64%);
  background-attachment: fixed;
}
/* .login-body sets `background` as a shorthand, which resets background-image
   to none -- so the sign-in screen, the first thing anyone sees, was the one
   page with no ambient behind its glass. */
.login-body {
  background-color: var(--bg);
  background-image:
    radial-gradient(820px 500px at 10% -8%, rgba(150,170,190,.10), transparent 62%),
    radial-gradient(700px 540px at 94% 4%,  rgba(120,135,155,.09), transparent 60%),
    radial-gradient(960px 680px at 50% 110%, rgba(100,115,135,.08), transparent 64%);
  background-attachment: fixed;
}
.login-card {
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-edge), var(--glass-drop);
  border-radius: var(--r-lg);
}

:root[data-theme="light"] body {
  background-image:
    radial-gradient(820px 500px at 10% -8%, rgba(90,120,160,.10), transparent 62%),
    radial-gradient(700px 540px at 94% 4%,  rgba(120,140,170,.08), transparent 60%),
    radial-gradient(960px 680px at 50% 110%, rgba(80,100,130,.07), transparent 64%);
}

/* ── raised surfaces ──────────────────────────────────────────────────────── */
.card,
.liq-card, .restock-card, .review-card, .chart-card, .sys-widget, .table-card {
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-edge), var(--glass-drop);
  border-radius: var(--r-lg);
}
.sidebar, .topbar {
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-edge);
}
.modal, .notif-panel, .search-results {
  backdrop-filter: blur(26px) saturate(150%); -webkit-backdrop-filter: blur(26px) saturate(150%);
  box-shadow: var(--glass-edge), var(--lift-3);
}

/* A card sitting inside a card would blur twice and go milky. The inner one
   keeps the border and drops the glass. */
.card .card {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  box-shadow: none; background: var(--surface-2);
}

/* ── outline primary ───────────────────────────────────────────────────────
   No filled accent button. The primary is the same glass as everything else,
   distinguished by a brighter edge and heavier text. On a panel where a
   mis-click moves real money, nothing shouting is the point -- it leaves the
   amber attention states as the loudest thing on screen. */
.btn.primary {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--accent-line);
  box-shadow: var(--glass-edge);
  font-weight: 650;
}
.btn.primary:hover { background: var(--surface-3); opacity: 1; }

.btn {
  border-radius: var(--r-sm);
  box-shadow: var(--glass-edge);
}

/* ── neutral active states ─────────────────────────────────────────────────
   The nav no longer tints; it lifts. Same affordance, no colour spent. */
.nav.active {
  background: var(--surface-2);
  color: var(--text);
  box-shadow: var(--glass-edge);
}
.nav.active svg { opacity: 1; }

/* Inputs sit INTO the glass rather than on it -- a raised input inside a
   raised card has no depth left to read. */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="submit"]):not([type="button"])),
textarea, select, .sel {
  background: rgba(0,0,0,.20);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.25);
}
:root[data-theme="light"] input:where(:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="submit"]):not([type="button"])),
:root[data-theme="light"] textarea,
:root[data-theme="light"] select,
:root[data-theme="light"] .sel {
  background: rgba(16,24,40,.04);
  box-shadow: inset 0 1px 2px rgba(16,24,40,.06);
}

/* Table rows and pills deliberately get NO blur -- dozens of blurred layers on
   one scrolling screen is where the frame rate goes. */
tbody tr:hover { background: var(--surface-2); }

/* Softer than the flat build, because a hard hairline reads as a seam on a
   translucent surface rather than an edge. */
.card, .liq-card, .restock-card, .review-card, .chart-card, .sys-widget, .table-card {
  border-color: var(--line);
}

/* Blur is GPU work. Anyone who has asked for less motion has usually asked
   their device for less work generally, so drop to opaque surfaces. */
@media (prefers-reduced-transparency: reduce) {
  .card, .sidebar, .topbar, .modal, .notif-panel, .search-results,
  .liq-card, .restock-card, .review-card, .chart-card, .sys-widget, .table-card {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: #15161A;
  }
  body { background-image: none; }
}

/* ── floating panels are NOT see-through ───────────────────────────────────
   Glass works for large chrome that sits over a calm background. It fails for
   a small panel floating over dense text: the in-game console dropdown was
   rendering at 4.5% white over a wall of chat lines, and the log read straight
   through the menu.

   These get their own near-opaque ground and keep the blur, so they still
   belong to the same material without becoming unreadable. */
:root { --glass-panel: rgba(21,23,27,.94); }
:root[data-theme="light"] { --glass-panel: rgba(255,255,255,.96); }

.sel-menu, .notif-panel, .search-results, .modal, .chart-tip {
  background: var(--glass-panel);
  backdrop-filter: blur(26px) saturate(140%); -webkit-backdrop-filter: blur(26px) saturate(140%);
  box-shadow: var(--glass-edge), var(--lift-3);
}
/* The selected row has to beat the panel it sits on, not blend into it. */
.sel-opt[aria-selected="true"], .sel-opt.sel { background: var(--surface-3); color: var(--text); }
.sel-opt:hover { background: var(--surface-2); }

/* ── no green on controls ──────────────────────────────────────────────────
   Colour means status now. A toggle is a control, so its on-state is chrome:
   a light track with a dark thumb, which is unmistakable against the dark
   off-state without spending a colour on it. */
.sw input:checked ~ .sw-track { background: var(--accent); border-color: transparent; }
.sw input:checked ~ .sw-thumb { background: #14161A; }

.btn.resume {
  color: var(--text);
  background: var(--surface-2);
  border-color: var(--accent-line);
}
.btn.resume:hover { background: var(--surface-3); }

/* ══════════════════════════════════════════════════════════════════════════
   SIMPLIFY PASS — four tabs, fewer blocks per page, more room for each.
   To revert: delete from this banner to the end of the file.
   ══════════════════════════════════════════════════════════════════════════ */

/* Sub-tabs inside Advanced. A quiet segmented control, not a second sidebar:
   these are three rarely-opened pages, not a navigation tier. */
.subnav {
  display: flex; gap: var(--s-1); flex-wrap: wrap;
  padding: var(--s-1); margin-bottom: var(--s-6);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 11px; width: fit-content; max-width: 100%;
}
.subnav-btn {
  appearance: none; border: 0; cursor: pointer;
  padding: 8px 15px; border-radius: 8px;
  font: 600 13.5px/1 inherit; color: var(--text-2);
  background: transparent; transition: background .14s ease, color .14s ease;
}
.subnav-btn:hover { color: var(--text); background: var(--surface-3); }
.subnav-btn.active { color: var(--text); background: var(--surface); box-shadow: 0 1px 2px rgb(0 0 0 / .25); }
.subview { display: none; }
.subview.active { display: block; }

/* Fewer things per page means each one can be bigger. The old pages fitted
   seven blocks by making every block small; these fit four by letting them
   breathe, which is the same information and less work to read. */
.view { padding: var(--s-7) var(--s-7) calc(var(--s-7) * 2); }
.section { margin-bottom: calc(var(--s-7) * 1.15); }
.section:last-child { margin-bottom: var(--s-6); }
.section-head { margin-bottom: var(--s-5); }
.section-head h2 { font-size: 17px; letter-spacing: -.015em; }

/* Cards were sized for a crowded page. With half as many they can hold their
   content at a comfortable size instead of a compressed one. */
.card { padding: var(--s-6); }
.table-card { padding: 0; }
.grid-2, .grid-4 { gap: var(--s-4); }

/* Stat tiles read as the headline of the page they sit on, so the number
   leads and the label gets out of its way. */
.grid-4 .stat-value, .figure-row .stat-value { font-size: clamp(22px, 2.4vw, 28px); }

@media (max-width: 900px) {
  .view { padding: var(--s-5) var(--s-5) var(--s-7); }
  .card { padding: var(--s-5); }
  /* Four tiles across is unreadable on a phone; two rows of two is not. */
  .grid-4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

/* ══════════════════════════════════════════════════════════════════════════
   SITE THEME — matches relayservices.org, appended 2026-08-24
   To revert: delete from this banner to the end of the file, and put the Inter
   font link back in index.html.

   Deliberately a token override rather than a rewrite. The panel was already
   built on custom properties, so re-pointing those retints every component at
   once -- including ones added later, which a component-by-component restyle
   would silently miss.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Ground and surfaces, biased navy rather than neutral grey, so they sit in
     the same family as the logo instead of beside it. Kept OPAQUE: plenty of
     components stack on these, and translucent surfaces two deep turn to mud. */
  --bg:          #03040C;
  --surface:     #0B0E1A;
  --surface-2:   #101526;
  --surface-3:   #18203A;
  --line:        #1E2740;
  --line-soft:   #141A2C;

  --text:        #F0F0F0;
  --text-2:      #A8A8C0;   /* the silver from the logo */
  --text-3:      #6B7089;

  /* Mint -> the brand blue. This is the single biggest visual change. */
  --accent:      #1E63FF;
  --accent-ink:  #FFFFFF;
  --accent-dim:  rgba(30, 99, 255, .14);
  --accent-line: rgba(30, 99, 255, .34);

  --info:        #6FA5FF;
  --info-dim:    rgba(111, 165, 255, .13);

  --mono: "JetBrains Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  /* Dropdowns and popovers must stay READABLE, not glassy -- a translucent
     menu over a chat log is how the log ends up showing through the options. */
  --glass-panel: rgba(11, 14, 26, .96);
}

body {
  font-family: Outfit, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Fredoka carries the headings, same as the site. Numbers stay monospace and
   tabular so columns of money line up. */
h1, h2, h3, .card-title, .page-title, .stat-value, .v {
  font-family: Fredoka, Outfit, ui-sans-serif, system-ui, sans-serif;
  letter-spacing: -.025em;
}
.stat-value, .v, .num, td.num, .mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

/* ── the ambient wash, fixed behind everything ───────────────────────────── */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(52vw 34vw at 8% -8%,  rgba(30, 99, 255, .22), transparent 70%),
    radial-gradient(46vw 30vw at 96% -6%, rgba(11, 67, 175, .20), transparent 72%);
}
/* Everything real sits above it. The app shell is positioned already; this
   just guarantees the stacking rather than relying on source order. */
.app, .sidebar, .main, header, .topbar { position: relative; z-index: 1; }

/* ── glass, but only one layer deep ──────────────────────────────────────── */
.card {
  background: rgba(255, 255, 255, .035);
  border: 1px solid rgba(255, 255, 255, .085);
  border-radius: 16px;
  backdrop-filter: blur(22px) saturate(150%);
  -webkit-backdrop-filter: blur(22px) saturate(150%);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .10);
}
/* Tables and inputs sit INSIDE cards, so they stay solid -- glass on glass
   loses the edges entirely and the table stops reading as a table. */
.table-card, .chart-card { background: rgba(255, 255, 255, .03); }
.card table, .card thead, .card input, .card select, .card textarea { backdrop-filter: none; }

input, select, textarea {
  background: var(--surface-2);
  border-color: var(--line);
  border-radius: 10px;
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
  outline: none;
}

.btn { border-radius: 999px; }
.btn.primary {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
  box-shadow: 0 8px 22px rgba(30, 99, 255, .34);
}
.btn.primary:hover { filter: brightness(1.08); }

.nav { border-radius: 11px; }
.nav.active { background: var(--accent-dim); color: var(--text); }

.subnav { border-radius: 999px; }
.subnav-btn { border-radius: 999px; }
.subnav-btn.active { background: var(--accent-dim); color: var(--text); }

.badge, .chip, .pill { border-radius: 999px; }

@media (prefers-reduced-motion: reduce) {
  .btn.primary:hover { filter: none; }
}
