:root {
  --bg: #07080b;
  --panel: #0e1118;
  --panel2: #141826;
  --border: #1d2433;
  --border-soft: #161c29;
  --text: #e8ecf4;
  --muted: #8b94a7;
  --gold: #e8c68f;
  --gold-dim: #b89a6a;
  --green: #4ade80;
  --red: #f87171;
  --amber: #fbbf24;
  --radius: 16px;
  --shadow: 0 20px 50px rgba(0,0,0,0.45);
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background:
    radial-gradient(1100px 600px at 85% -10%, rgba(232,198,143,0.07), transparent 60%),
    radial-gradient(900px 500px at -10% 110%, rgba(60,80,140,0.08), transparent 55%),
    var(--bg);
  color: var(--text);
  font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.hidden { display: none !important; }
.muted { color: var(--muted); }
.small { font-size: 12px; }
.mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; }

/* Login */
.login-wrap {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
}
.login-card {
  width: min(400px, 100%);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 34px;
  box-shadow: var(--shadow);
}
.login-card h1 { margin: 18px 0 4px; font-size: 24px; }
.login-card p { margin: 0 0 22px; }
.login-card label { display: block; margin: 14px 0 6px; font-size: 12px; color: var(--muted); }
/* The sign-in card spaces every block 18px from the next (4px under a field, plus
   the 14px the thing after it brings). The password box used to sit FLUSH against
   Continue: it had no bottom margin, and the error line between the two is
   display:none until something goes wrong, so nothing at all separated them
   (measured on the live page 2026-10-28: 0px, while the email box is 14px from
   the label under it). Same fault on the recovery card, where the codes ran into
   their button. A field and a button are both inline-level, so their margins ADD
   rather than collapse: 4 + 14 is the card's 18px. */
.login-card input { margin-bottom: 4px; }
.login-card input + .btn,
.login-card input + p + .btn,
.login-card .codes + .btn { margin-top: 14px; }
/* The "wrong password" line lives between the field and the button, and the card's
   own paragraph rule gives it 22px underneath - which added to the button's 14px
   left the red text hugging the box and 36px of air above Continue. It takes the
   same 4px-under / 14px-over rhythm as everything else, so the card reads the
   same whether the line is showing or not (18px each side, measured). */
.login-card #loginError { margin: 14px 0 4px; }
/* Same on the second-factor step: the hint under the code box was 4px from it
   (it had no top margin of its own and a field's 4px was all there was). */
.login-card #verifyHint { margin-top: 14px; }
/* The WELUX logo (2026-10-30): the gold box with a W round its corner, the same mark
   as every WELUX site and app. It carries its own colours, so no tile behind it. */
.brand-mark {
  display: block;
  width: 44px; height: 44px;
  object-fit: contain;
}
.brand-mark.small { width: 34px; height: 34px; }
.login-note { margin-top: 20px !important; line-height: 1.6; }

/* Second-factor step on the sign-in screen */
.setup-block {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel2);
  padding: 14px 16px;
  margin: 18px 0 4px;
}
.secret-row { display: flex; flex-direction: column; gap: 6px; margin: 12px 0 10px; }
.secret-row .secret {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 13px;
  letter-spacing: 0.14em;
  color: var(--gold);
  word-break: break-all;
}
.method-row { display: flex; gap: 10px; margin: 18px 0 4px; }
.method-row .btn { flex: 1; }
.login-links { display: flex; justify-content: space-between; gap: 12px; margin-top: 16px; }
.link-btn {
  background: none;
  border: 0;
  padding: 0;
  color: var(--muted);
  font-size: 12px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.link-btn:hover { color: var(--gold); }
.info { color: var(--gold-dim); font-size: 13px; }
.codes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 18px 0 4px; }
.codes .code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 13px;
  color: var(--text);
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 10px;
  text-align: center;
}

/* Layout */
.app { display: flex; min-height: 100vh; }
.sidebar {
  width: 230px;
  flex: 0 0 230px;
  background: rgba(10,13,19,0.85);
  border-right: 1px solid var(--border-soft);
  padding: 22px 14px;
  display: flex;
  flex-direction: column;
  gap: 26px;
  position: sticky;
  top: 0;
  height: 100vh;
}
/* The header row and its toggle. On a wide screen this is just the brand: the
   menu is always on show in the sidebar and there is nothing to open. On a
   phone the same row becomes a slim bar and the toggle opens the menu - see the
   narrow-screen block below. */
.side-top { display: flex; align-items: center; gap: 10px; }
.nav-toggle { display: none; }
.side-brand { display: flex; align-items: center; gap: 10px; padding: 0 8px; }
/* Everything below the brand: the menu, then the account block at its foot.
   On a wide screen this is the rest of the sidebar column. On a phone it is the
   panel the toggle opens. */
.side-menu {
  display: flex; flex-direction: column; gap: 26px;
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
}
.side-brand strong { display: block; font-size: 15px; letter-spacing: 0.3px; }
.side-brand span { display: block; color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }

.nav { display: flex; flex-direction: column; gap: 6px; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  background: transparent; border: 0; color: var(--muted);
  padding: 11px 12px; border-radius: 10px;
  font-size: 14px; cursor: pointer; text-align: left;
  transition: background 0.15s, color 0.15s;
}
.nav-item:hover { background: var(--panel2); color: var(--text); }
.nav-item.active { background: linear-gradient(135deg, rgba(232,198,143,0.14), rgba(232,198,143,0.05)); color: var(--gold); }
.nav-icon { width: 18px; text-align: center; opacity: 0.85; }

.side-foot { margin-top: auto; display: flex; flex-direction: column; gap: 10px; padding: 0 6px; }
.balance-pill {
  align-self: flex-start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(232,198,143,0.1);
  border: 1px solid rgba(232,198,143,0.25);
  color: var(--gold);
  font-weight: 700;
  font-size: 13px;
}

.main { flex: 1; min-width: 0; padding: 30px 34px 60px; }
.topbar {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; margin-bottom: 26px;
}
.topbar h2 { margin: 0 0 2px; font-size: 24px; }
.topbar p { margin: 0; }

/* Standing warnings (e.g. the console running without a second factor) */
.alert {
  display: flex; gap: 12px; align-items: flex-start;
  max-width: 1000px; margin: 0 0 22px;
  padding: 14px 16px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--panel);
  font-size: 13px; line-height: 1.5;
}
.alert p { margin: 4px 0 0; color: var(--muted); }
.alert code {
  padding: 1px 5px; border-radius: 5px;
  background: rgba(255, 255, 255, 0.06);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px;
}
.alert.warn {
  border-color: rgba(245, 158, 11, 0.45);
  background: rgba(245, 158, 11, 0.09);
}
.alert.warn .alert-icon { color: #f59e0b; font-size: 15px; line-height: 1.35; }
.alert.warn strong { color: #fbbf24; }

/* Panels */
.tab-panel { max-width: 1000px; }

/* Stat cards */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-bottom: 18px;
}
/* The Overview's figures: one card, kept the width one column had. */
.stat-grid.single { grid-template-columns: minmax(200px, 320px); }
.stat-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.stat-label { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.8px; }
.stat-value { font-size: 26px; font-weight: 700; color: var(--gold); }

/* Cards */
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
  margin-bottom: 18px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.25);
}
.card-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; margin-bottom: 18px;
}
.card-head.standalone { margin-bottom: 0; }
.card-head h3 { margin: 0 0 4px; font-size: 17px; }
.card-head p { margin: 0; }

input[type="range"] {
  width: 100%;
  accent-color: var(--gold);
  height: 6px;
  cursor: pointer;
}

/* Buttons */
.btn {
  border: 1px solid var(--border);
  background: var(--panel2);
  color: var(--text);
  padding: 10px 16px;
  border-radius: 10px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.btn:hover { border-color: var(--gold); color: var(--gold); }
.btn.primary {
  background: linear-gradient(135deg, var(--gold), #d4b17a);
  border-color: transparent;
  color: #16130c;
}
.btn.primary:hover { background: linear-gradient(135deg, #f4d5a2, #d4b17a); color: #16130c; }
.btn.ghost { background: transparent; }
.btn.wide { width: 100%; }
.btn.small { padding: 6px 10px; font-size: 12px; }
.btn.active { border-color: var(--gold); color: var(--gold); background: rgba(232,198,143,0.08); }

.btn-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }

/* Pills */
.pill {
  display: inline-flex; align-items: center;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  border: 1px solid var(--border);
  background: var(--panel2);
}
.pill.green { color: var(--green); border-color: rgba(74,222,128,0.35); background: rgba(74,222,128,0.08); }
.pill.red { color: var(--red); border-color: rgba(248,113,113,0.35); background: rgba(248,113,113,0.08); }
.pill.gold { color: var(--gold); border-color: rgba(232,198,143,0.35); background: rgba(232,198,143,0.08); }
.pill.amber { color: var(--amber); border-color: rgba(251,191,36,0.35); background: rgba(251,191,36,0.08); }

/* Forms */
.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.form-grid label {
  display: flex; flex-direction: column; gap: 6px;
  color: var(--muted); font-size: 12px;
}
/* A field whose value is prose rather than a number: full width in a two-column grid. */
.form-grid label.span-2 { grid-column: 1 / -1; }
.node-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
input[type="text"], input[type="url"], input[type="password"], input[type="email"] {
  background: var(--panel2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 12px 14px;
  border-radius: 10px;
  font-size: 14px;
  outline: none;
}
input:focus { border-color: var(--gold); }
::placeholder { color: #586178; }

.error { color: var(--red); font-size: 13px; }

/* Models */
.model-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px;
}
.model-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
}
.model-card.blocked { border-color: rgba(248,113,113,0.45); }
.model-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.model-name { font-family: ui-monospace, monospace; font-size: 13px; word-break: break-all; }
.model-role { display: flex; gap: 6px; }
.model-price {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 12px;
}
.price-cell {
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  padding: 10px 12px;
}
.price-cell .label { display: block; color: var(--muted); font-size: 11px; margin-bottom: 3px; }
.price-cell .value { font-size: 14px; font-weight: 700; }
.model-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.advanced-toggle {
  background: transparent; border: 0; color: var(--muted);
  font-size: 12px; cursor: pointer; padding: 0;
}
.advanced-toggle:hover { color: var(--gold); }
.model-advanced {
  margin-top: 12px;
  border-top: 1px solid var(--border-soft);
  padding-top: 12px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  font-size: 12px;
}

/* Provider / test */
.test-result {
  margin-top: 14px;
  padding: 14px;
  border-radius: 10px;
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  font-size: 13px;
  white-space: pre-wrap;
}
.test-result .ok { color: var(--green); }
.test-result .err { color: var(--red); }

/* Safety */
.loss-list { display: flex; flex-direction: column; gap: 8px; }
.loss-item {
  display: flex; justify-content: space-between;
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 13px;
}
.reconcile-box {
  padding: 14px;
  border-radius: 10px;
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  white-space: pre-wrap;
}

.sync-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* Email delivery outbox. One row per attempt: address, what it was, when, and
   whether it left the building. */
.mail-outbox { display: flex; flex-direction: column; gap: 8px; }
.mail-row {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) auto;
  gap: 6px 14px;
  align-items: baseline;
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--green);
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 13px;
}
.mail-row.failed { border-left-color: var(--red); }
.mail-row .mail-to { font-weight: 600; }
.mail-row .mail-when { color: var(--muted); font-size: 12px; text-align: right; }
.mail-row .mail-sub { grid-column: 1 / -1; color: var(--muted); font-size: 12px; }
.mail-row .mail-err { grid-column: 1 / -1; color: var(--red); font-size: 12px; white-space: pre-wrap; }

/* Users */
.users-layout {
  display: grid;
  grid-template-columns: minmax(300px, 380px) 1fr;
  gap: 18px;
  align-items: start;
}
.users-list-card, .users-detail-card { margin-bottom: 0; }
.users-list-card input[type="text"] { width: 100%; margin-bottom: 14px; }
.user-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 70vh;
  overflow-y: auto;
  padding-right: 4px;
}
.user-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  padding: 12px 14px;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.user-row:hover { border-color: var(--gold); }
.user-row.active { border-color: var(--gold); background: rgba(232,198,143,0.07); }
.user-row .u-main { min-width: 0; }
.user-row .u-name { display: block; font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-row .u-email { display: block; color: var(--muted); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-row .u-credit { color: var(--gold); font-weight: 800; font-size: 14px; white-space: nowrap; }
/* The identity badges sit under the address so a narrow phone still shows the
   name, the email, the admin flag and the verification state without wrapping
   into each other. */
.user-row .u-badges { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.pill.tiny { padding: 2px 8px; font-size: 10px; letter-spacing: 0.4px; text-transform: uppercase; }

/* Above the search box: the three questions this list is opened to answer. */
.user-filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }

.verify-control {
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px;
}
.verify-control h4 { margin: 0 0 8px; font-size: 14px; }

.user-detail { display: flex; flex-direction: column; gap: 16px; }
.user-detail .empty { margin: 0; }
.user-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
}
.meta-cell {
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  padding: 12px 14px;
}
.meta-cell .label { display: block; color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.7px; margin-bottom: 4px; }
.meta-cell .value { font-size: 16px; font-weight: 700; }
.meta-cell .value.gold { color: var(--gold); }

.balance-control {
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px;
}
.balance-control h4 { margin: 0 0 12px; font-size: 14px; }
.balance-edit-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.balance-edit-row input {
  width: 180px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--gold);
  font-size: 22px;
  font-weight: 800;
  padding: 10px 14px;
  border-radius: 10px;
  outline: none;
}
.balance-edit-row input:focus { border-color: var(--gold); }
.quick-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.balance-msg { margin: 12px 0 0; font-size: 12px; }

.usage-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.usage-stats .meta-cell .value { font-size: 14px; }

.tx-list { display: flex; flex-direction: column; gap: 8px; max-height: 280px; overflow-y: auto; }
.tx-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 13px;
}
.tx-row .tx-type { color: var(--muted); text-transform: capitalize; }
.tx-row .tx-date { color: var(--muted); font-size: 12px; }
.tx-row .tx-amount { font-weight: 700; }
.tx-row .tx-amount.pos { color: var(--green); }
.tx-row .tx-amount.neg { color: var(--red); }

/* The tap-outside layer that closes the menu. Narrow screens only; the rule
   below is the base and the media block further down turns it on. */
.nav-scrim { display: none; }

/* Responsive */
/* Narrow screens.
   What this used to do: the sidebar became a wrapping header, the brand and the
   account block took the first row, and the twelve tabs were pushed into a
   horizontal scroller underneath. On a 390px-wide phone that scroller had
   nothing to say it continued off the edge, so four of the twelve tabs (Node
   Terminal, Requests, Safety, Email, Cloud API) were simply absent, the six
   section headings sat as loose words in the same grid as the buttons they
   labelled, and the header ate 237px - 28% - of the screen before any content.
   Measured on the live console, 2026-10-09: nav box 366x133 with scrollWidth
   791, four items off-viewport, header 237px of an 844px viewport.

   What it does now: one slim bar carrying the brand and a Menu button, and the
   whole menu behind that button as a drawer - the same groups, the same order,
   nothing hidden, all twelve reachable with a thumb. Tapping a tab closes it.
   The account block (balance, address, Log out) moves into the drawer foot so
   the bar can stay 56px tall.

   The bar keeps a SOLID background and no backdrop-filter on purpose: either
   one would make this element the containing block for the fixed drawer, and
   the drawer would then be positioned against the bar instead of the screen. */
@media (max-width: 820px) {
  .app { flex-direction: column; }

  .sidebar {
    width: 100%; flex: none; height: auto;
    flex-direction: column; gap: 0;
    padding: 0;
    position: sticky; top: 0; z-index: 40;
    background: #090c11;
    border-right: 0;
    border-bottom: 1px solid var(--border-soft);
  }

  /* The bar's height is a variable because two other boxes are positioned
     against it: the drawer (top) and the tap-outside layer (inset top). The
     safe-area term is zero on any screen without a notch or a rounded corner -
     which is why this measures exactly as before on the test devices - and in
     landscape on a notched phone (viewport-fit=cover is set in index.html) it
     is what keeps the bar and the menu clear of the cutout. */
  /* On .app, not on .sidebar: the tap-outside layer is the sidebar's SIBLING and
     reads the same variable, so it has to be defined where both inherit it.
     Measured with a simulated 47px inset: from .sidebar the scrim's top stayed 0
     (an unresolvable var() drops to the property's initial value) and the layer
     would have covered the bar itself. */
  .app { --bar-h: 56px; --bar-top: calc(var(--bar-h) + env(safe-area-inset-top, 0px)); }
  .side-top {
    height: var(--bar-top); padding: 0 12px; gap: 10px;
    padding-top: env(safe-area-inset-top, 0px);
  }
  .side-brand { padding: 0; gap: 10px; }
  .side-brand span { display: none; }
  .side-brand strong { font-size: 14px; }

  .nav-toggle {
    display: flex; align-items: center; gap: 9px;
    margin-left: auto;
    background: var(--panel); border: 1px solid var(--border); color: var(--text);
    padding: 8px 12px; border-radius: 10px;
    font: inherit; font-size: 13px; cursor: pointer;
  }
  .nav-toggle:hover { border-color: var(--gold); color: var(--gold); }
  .sidebar.nav-open .nav-toggle { border-color: var(--gold); color: var(--gold); }
  .nav-bars { display: inline-flex; flex-direction: column; gap: 3px; width: 15px; }
  .nav-bars i { display: block; height: 2px; border-radius: 2px; background: currentColor; }

  .side-menu {
    position: fixed; left: 0; right: 0; top: var(--bar-top);
    max-height: calc(100vh - var(--bar-top));
    max-height: calc(100dvh - var(--bar-top));
    padding: 10px 12px 18px;
    gap: 14px;
    background: #0b0f16;
    border-bottom: 1px solid var(--border);
    box-shadow: 0 24px 44px rgba(0,0,0,0.55);
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    opacity: 0; transform: translateY(-6px);
    visibility: hidden; pointer-events: none;
    transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
    z-index: 1;
  }
  /* While the menu is open it must be the top layer, above the console@s own
     floating assistant button (which the chat bundle positions fixed at
     z-index 61 in the bottom-right corner). Measured at 360x640, that button
     sat exactly across the Requests and Safety rows of the menu. Raising the
     bar@s own stacking only while the menu is open puts the menu and its
     tap-outside layer above it; the bar is 56px tall and nowhere near the
     corner, so nothing else changes. */
  .sidebar.nav-open { z-index: 70; }

  .sidebar.nav-open .side-menu {
    opacity: 1; transform: none;
    visibility: visible; pointer-events: auto;
  }

  /* The menu itself: one column, wide rows, the group headings between them. */
  .nav { flex-direction: column; gap: 12px; }
  .nav-group { display: flex; flex-direction: column; gap: 2px; }
  .nav-group-label { padding: 6px 10px 2px; font-size: 10px; }
  .nav-item { padding: 11px 12px; font-size: 15px; border-radius: 10px; }
  .nav-icon { width: 20px; font-size: 15px; }

  .side-foot {
    margin-top: 0; padding: 12px 0 0;
    flex-direction: row; align-items: center; flex-wrap: wrap;
    gap: 10px;
    border-top: 1px solid var(--border-soft);
  }
  .side-foot .balance-pill { padding: 6px 10px; font-size: 12px; }
  .side-foot .btn { width: auto; padding: 8px 12px; }
  #sideUser {
    order: 3; flex: 1 1 100%; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Tapping anywhere outside the drawer closes it. It sits below the bar's own
     stacking context, so the bar keeps the drawer on top of this one. */
  .nav-scrim {
    display: block;
    position: fixed; inset: var(--bar-top) 0 0 0; z-index: 35;
    background: rgba(3,5,8,0.6);
    opacity: 0; visibility: hidden;
    transition: opacity 0.16s ease, visibility 0.16s;
  }
  .sidebar.nav-open ~ .nav-scrim { opacity: 1; visibility: visible; }

  .main { padding: 18px 14px 60px; }
  .topbar { margin-bottom: 18px; }
  .topbar h2 { font-size: 20px; }
  /* A narrow screen must not force the page wider than the phone.
     These two tabs did: the Accounts view measured a 402px column and Hosting
     472px inside a 390px viewport, because a grid item@s automatic minimum size
     is its widest unbreakable child (the user address and credit are nowrap
     value cells; the Hosting card heads are a heading plus a row of buttons)
     and a multi-column grid cannot shrink below that. The browser then widens
     the layout viewport, so the operator sees a zoomed-out page with a sideway
     scroll on both. Measuring what actually sticks out, 2026-10-09:
       Accounts  .users-layout   362px client, 402px scroll
       Hosting   .hosting-layout 362px client, 472px scroll
     min-width:0 lets the columns shrink and the value cells ellipsis (they
     already carry overflow:hidden; text-overflow: ellipsis). */
  .users-layout, .hosting-layout,
  .users-layout > *, .hosting-layout > * { min-width: 0; }
  .user-row .u-main { flex: 1 1 auto; min-width: 0; }

  /* Hosting, the same story one level down: inside the node card a row holds a
     line of facts (agent address, SSH detail, capacity) beside a column of
     buttons, and one unbreakable word in that line - http://10.77.0.2:9000 was
     the measured one - set the card@s automatic minimum width, which set the
     grid@s, which widened the whole page to 448px on a 390px phone. Letting the
     facts line break anywhere and removing the automatic minimum on the row
     chain brings it back to 362px inside the viewport, measured 2026-10-09. */
  .hosting-servers, .hosting-server-row, .hosting-plan,
  .hs-top, .hs-meta, .node-actions { min-width: 0; }
  .hs-meta, .hs-top, .hosting-plan .hp-specs { overflow-wrap: anywhere; }
  /* The detail column keeps its own columns: on a phone they stack. */
  .stat-grid, .form-grid,
  .users-layout, .hosting-layout { grid-template-columns: 1fr; }
}

/* Hosting */
.hosting-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  align-items: start;
}
.hosting-plans, .hosting-servers {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 16px 0;
}
.hosting-plan, .hosting-server-row {
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  padding: 14px;
}
.hosting-plan .hp-top, .hosting-server-row .hs-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.hosting-plan .hp-name { font-weight: 700; }
.hosting-plan .hp-specs, .hosting-server-row .hs-meta {
  color: var(--muted);
  font-size: 12px;
  margin-top: 6px;
}
.hosting-plan .hp-price { color: var(--gold); font-weight: 700; }
.hosting-plan-form {
  border-top: 1px solid var(--border-soft);
  margin-top: 16px;
  padding-top: 16px;
}
.hosting-plan-form h4 { margin: 0 0 12px; font-size: 14px; }
@media (max-width: 820px) {
  .hosting-layout { grid-template-columns: 1fr; }
}

/* Cloud API (OVHcloud) */
select {
  background: var(--panel2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 12px 14px;
  border-radius: 10px;
  font-size: 14px;
  outline: none;
}
select:focus { border-color: var(--gold); }
.btn.danger { color: var(--red); border-color: rgba(248,113,113,0.35); }
.btn.danger:hover { border-color: var(--red); color: var(--red); background: rgba(248,113,113,0.08); }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }

.cloud-layout { display: flex; flex-direction: column; gap: 18px; }

.cloud-steps {
  margin: 0;
  padding-left: 20px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.75;
}
.cloud-steps strong { color: var(--text); }
.cloud-steps em { color: var(--gold); font-style: normal; }
.cloud-steps a { color: var(--gold); }
.cloud-steps .mono {
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  padding: 1px 5px;
  color: var(--text);
  font-size: 12px;
}
.cloud-steps .rights {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.cloud-steps .rights .mono {
  background: transparent;
  border: none;
  padding: 0;
  color: var(--gold);
  min-width: 150px;
  display: inline-block;
}

.ovh-warn { color: var(--amber); }
.ovh-facts { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 14px; }
.ovh-fact { display: flex; flex-direction: column; gap: 2px; }
.ovh-fact span { color: var(--muted); font-size: 12px; }
.ovh-fact strong { font-size: 15px; }

/* Deliverability checks in the Email tab. */
.mail-dns { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.mail-dns-row {
  border: 1px solid var(--line, #2a2d33);
  border-radius: 8px;
  padding: 10px 12px;
}
.mail-dns-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mail-dns-head strong { font-size: 0.95rem; }
.mail-dns-why { margin: 6px 0 8px; line-height: 1.45; }
.mail-dns-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.65;
  margin-top: 6px;
}
.mail-dns-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.76rem;
  word-break: break-all;
  background: rgba(127, 127, 127, 0.12);
  border-radius: 6px;
  padding: 6px 8px;
  margin-top: 2px;
}
.mail-dns-copy { margin-top: 6px; }

/* Credit grants in the operator's own currency.
   Balances stay in US dollars; these rules are what turns a typed £ amount into
   the dollars that actually get credited, and shows a dollar balance back in
   pounds. The symbol sits inside the amount field so the box reads as money
   rather than as a bare number. */
.grant-cur-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.grant-cur-row label { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.7px; }
.grant-cur-row select { padding: 8px 10px; font-size: 13px; max-width: 100%; }
/* One line saying whose currency this is — the operator's own profile, or the
   platform default they fall back to — so the picker does not look like it came
   from nowhere. */
.grant-cur-note { margin: 0 0 8px; font-size: 12px; color: var(--muted); max-width: 60ch; line-height: 1.5; }
.rate-line {
  margin: 0 0 12px; font-size: 12px; color: var(--muted);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.money-field {
  display: flex; align-items: center;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0 14px;
}
.money-field:focus-within { border-color: var(--gold); }
.money-field .cur { color: var(--gold-dim); font-size: 18px; font-weight: 700; }
.money-field input {
  width: 140px;
  background: transparent;
  border: 0;
  color: var(--gold);
  font-size: 22px;
  font-weight: 800;
  padding: 10px 6px;
  outline: none;
}
.conv-hint { margin: 10px 0 0; font-size: 12px; color: var(--gold-dim); min-height: 15px; }
.user-row .u-credit .u-credit-alt { display: block; font-size: 11px; font-weight: 600; color: var(--muted); }

/* The switch between the two consoles, on the sign-in screen and in the sidebar.
   The sign-in screen has no .app to sit in, so it is placed by itself. */
#weluxChannelSwitch{display:inline-block;margin-top:14px;font-size:13px;font-weight:600;
  color:#94a3b8;text-decoration:none}
#weluxChannelSwitch:hover{color:#e8c68f}

/* ---------------------------------------------------------------------------
   The sidebar, grouped.

   The console had twelve tabs in one flat list, which is a list nobody reads as
   a shape: "Backups" sat next to "Cloud API" next to "Email" with nothing to
   say why. The sections group them by the question they answer, so the eye can
   skip a whole group it does not need. The code that builds the list reads
   .nav-group / .nav-group-label, and nothing else changed about .nav-item.
   --------------------------------------------------------------------------- */
.nav { gap: 18px; }
.nav-group { display: flex; flex-direction: column; gap: 4px; }
.nav-group-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 1.2px;
  color: #5d6675;
  padding: 0 12px 2px;
}
.nav-item { padding: 9px 12px; font-size: 13.5px; }

/* A referred account: the same pill shape as the other badges, in a hue that is
   not already spoken for. Gold is the brand, green is proven, purple was free. */
.pill.violet {
  color: #c4b5fd;
  border-color: rgba(196,181,253,0.35);
  background: rgba(196,181,253,0.08);
}

/* The one destructive control on the page. It is deliberately quiet until you
   look at it: a red-bordered ghost button, not a filled red one, because the
   operator's eye should catch it only when they are reading that card. */
.danger-zone {
  margin-top: 22px;
  padding: 14px 16px;
  border: 1px solid rgba(248,113,113,0.22);
  border-radius: 12px;
  background: rgba(248,113,113,0.03);
}
.danger-zone h4 { margin: 0 0 6px; font-size: 14px; color: var(--red); }

/* Referral rows use the shared .loss-item shell; these keep their columns from
   collapsing when a long address sits beside a short code. */
.loss-item .mono { flex: 0 0 auto; }
#referralSummary .stat-value { font-size: 22px; }

/* --- the Nodes card: the file browser ---------------------------------------
 *
 * A flat list, because that is what it is: a name, what kind of thing it is and
 * how big. The row is a button so a keyboard can walk it, and the columns are
 * fixed so a long name cannot push the size off the row.
 */
.node-files-list {
  margin-top: 8px;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.08));
  border-radius: 8px;
  max-height: 380px;
  overflow-y: auto;
}
.node-file-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 4px 10px;
  border-bottom: 1px solid var(--line, rgba(255, 255, 255, 0.06));
}
.node-file-row:last-child { border-bottom: 0; }
.node-file-row:hover { background: rgba(255, 255, 255, 0.035); }
.node-file-name {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: 0;
  padding: 3px 0;
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.node-file-icon { opacity: 0.6; width: 12px; flex: 0 0 12px; }
.node-file-row .muted { flex: 0 0 auto; }

/* The command block: monospace, wrapped, and never taller than it needs to be -
 * a command that scrolls sideways is a command that gets copied wrong. */
#nodeEnrolCmd {
  white-space: pre-wrap;
  word-break: break-all;
  font-size: 11.5px;
  line-height: 1.45;
}
#nodeBlockInput {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  resize: vertical;
}

/* ==========================================================================
   HOSTING DASHBOARD
   --------------------------------------------------------------------------
   The Hosting tab answers two questions before it lists anything: how much
   room is left to sell, and what is running while I read this. So it gets the
   whole width of the page (the other tabs stop at 1000px), a strip of figures,
   three rings, and the hardware underneath them - then the nodes, the
   instances, the rate sheet and the requests, in that order.

   Everything here is additive: the panels, pills, buttons and rows the rest of
   the console already styles (.card, .pill, .btn, .hosting-server-row) are used
   unchanged, so this reads as the same console with a better front page.
   ========================================================================== */
.tab-panel.hosting-panel { max-width: 1240px; }

/* --- the hero ------------------------------------------------------------ */
.fleet-hero {
  background:
    radial-gradient(760px 300px at 92% -40%, rgba(232,198,143,0.10), transparent 62%),
    var(--panel);
}
.fleet-hero .card-head { margin-bottom: 14px; }

/* A card's buttons do not shrink: the paragraph beside them does. Without this
   the long description squeezed "Add a machine" onto two lines and stacked
   Refresh under the capacity switch. */
.hosting-panel .card-head .btn-row { flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; }
.hosting-panel .card-head .btn { white-space: nowrap; }

/* A two-position switch. It is a pair of buttons rather than a select because
   the operator flips it while reading the rings, not while filling a form. */
.seg {
  display: inline-flex;
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 3px;
  gap: 2px;
}
.seg-btn {
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  padding: 7px 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease;
}
.seg-btn:hover { color: var(--text); }
.seg-btn.active {
  background: var(--gold);
  color: #16130c;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}

/* --- the figures --------------------------------------------------------- */
.fleet-kpis {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
  margin: 2px 0 18px;
}
.kpi {
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.kpi-label {
  color: var(--muted);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
}
.kpi-value {
  font-size: 19px;
  font-weight: 800;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kpi-sub { color: var(--muted); font-size: 11.5px; }
.kpi.gold .kpi-value { color: var(--gold); }
.kpi.warn .kpi-value { color: var(--amber); }

.kpi-link { cursor: pointer; }
.kpi-link:hover { border-color: rgba(232,198,143,0.35); }
.kpi-link:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.kpi-link .kpi-sub { text-decoration: underline; text-underline-offset: 3px; }

.capacity-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 4px 0 10px;
}
.capacity-head-label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.9px;
  color: var(--muted);
}

/* --- the rings ----------------------------------------------------------- */
.capacity-rings {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}
.cap-tile {
  display: flex;
  /* Wraps when the column is too narrow for a dial plus words: at 1024px the
     three columns are 217px each, and the old side-by-side layout made a
     1087px-tall tile with the words squeezed into 60px. The dial goes on top
     and the words get the whole width instead. */
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  padding: 16px;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  background: var(--panel2);
  min-width: 0;
}
@media (max-width: 767px) {
  .fleet-hero { display: flex; flex-direction: column; }
  .fleet-hero > .card-head { order: 0; }
  .fleet-hero > #capacityRings { order: 1; }
  .fleet-hero > .cap-legend { order: 2; }
  .fleet-hero > #capacityHint { order: 3; }
  .fleet-hero > #fleetKpis { order: 4; }
  .fleet-hero > .capacity-head { order: 5; }
  .fleet-hero > .reality-intro { order: 6; }
  .fleet-hero > #hostReality { order: 7; }
  .fleet-hero > #fleetStamp { order: 8; }
}

/* One key for the three rings: which dial is which. */
.cap-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 10px 0 0;
  font-size: 11.5px;
  color: var(--muted);
}
.cap-key { display: inline-flex; align-items: center; gap: 7px; }
.cap-key-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; }
.cap-key-dot.is-setaside { background: var(--gold); }
.cap-key-bar { width: 16px; height: 6px; border-radius: 999px; background: #4e6b8f; flex: 0 0 16px; }
.cap-key-bar.is-peak { background: #3c5c85; }
.cap-key-bar.is-now { background: #7ea7d4; }
.capacity-hint {
  margin: 0 0 12px;
  max-width: 92ch;
  font-size: 12px;
  line-height: 1.55;
  color: var(--muted);
}
.capacity-hint strong { color: var(--gold-dim); font-weight: 600; }

/* --- the hardware under it ----------------------------------------------- */
.reality-intro {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border-soft);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.9px;
  color: var(--muted);
}
.reality-intro span { text-transform: none; letter-spacing: 0; color: var(--gold-dim); }
.host-reality {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  gap: 16px;
  margin-top: 8px;
}
.reality-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.reality-name { font-size: 12.5px; font-weight: 700; }
.reality-meta { font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reality-row {
  display: grid;
  grid-template-columns: 74px minmax(0, 1fr);
  align-items: start;
  gap: 10px;
  padding: 3px 0;
}
/* The meter and its words on one line, and under them the sentence that says
   what the machine is ("64 GB installed as 2 × 32 GB modules"). Two lines per
   meter rather than one crammed one: "45.9 of 62.4 GB in use" alone is exactly
   the figure that looked wrong, and the note is the answer to it. */
.reality-cell { display: grid; gap: 3px; min-width: 0; }
.reality-line {
  display: grid;
  grid-template-columns: minmax(56px, 1fr) auto;
  align-items: center;
  gap: 10px;
}
.reality-note {
  font-size: 11px;
  line-height: 1.45;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.reality-spec {
  font-size: 11.5px;
  color: var(--gold-dim);
  margin: -2px 0 8px;
  overflow-wrap: anywhere;
}
.reality-label { font-size: 11.5px; color: var(--muted); }
.reality-bar {
  height: 6px;
  border-radius: 999px;
  background: #1b2130;
  overflow: hidden;
}
.reality-bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--gold-dim), var(--gold));
  transition: width 0.4s ease;
}
.reality-bar.warm i { background: linear-gradient(90deg, #b98b2c, var(--amber)); }
.reality-bar.hot i { background: linear-gradient(90deg, #b3453f, var(--red)); }
.reality-bar.quiet { background: transparent; }
.reality-value { font-size: 12px; color: #b6bfd0; white-space: nowrap; font-variant-numeric: tabular-nums; }

.fleet-stamp { margin: 12px 0 0; line-height: 1.6; }

/* --- nodes --------------------------------------------------------------- */
.hosting-servers.node-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-items: start;
}
.node-card {
  background: var(--panel2);
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 16px;
  min-width: 0;
}
.node-card.is-off { opacity: 0.72; }
.node-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.node-id { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.node-name { font-weight: 700; font-size: 14.5px; overflow-wrap: anywhere; }
.node-slug { font-size: 11px; color: var(--muted); overflow-wrap: anywhere; }
.node-badges { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; flex: 0 0 auto; }

.node-fill { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.fill-row {
  display: grid;
  grid-template-columns: 56px minmax(50px, 1fr) auto;
  align-items: center;
  gap: 10px;
}
.fill-label { font-size: 11.5px; color: var(--muted); }
.fill-bar { height: 6px; border-radius: 999px; background: #1b2130; overflow: hidden; }
.fill-bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--gold-dim), var(--gold));
  transition: width 0.4s ease;
}
.fill-bar.warm i { background: linear-gradient(90deg, #b98b2c, var(--amber)); }
.fill-bar.hot i { background: linear-gradient(90deg, #b3453f, var(--red)); }
.node-fill-note {
  /* A sentence with the machine's own figures in it, so it is read as one:
     uppercase tracking turned "16 threads, 64 GB, 466 GB" into a label. */
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
  margin: -6px 0 10px;
  overflow-wrap: anywhere;
}
.fill-value { font-size: 11.5px; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }

.node-facts { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.node-fact {
  font-size: 11px;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  padding: 3px 9px;
  white-space: nowrap;
}
.node-meta {
  font-size: 11.5px;
  color: var(--muted);
  overflow-wrap: anywhere;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 2px;
}
.node-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-soft);
}

/* --- machines on the boxes that are nobody's ----------------------------- */
.unmanaged-guests { display: flex; flex-direction: column; gap: 12px; }
.unmanaged-group { display: flex; flex-direction: column; gap: 6px; }
.unmanaged-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--muted);
}
.unmanaged-title em {
  font-style: normal;
  color: var(--gold-dim);
  margin-left: 4px;
}
.unmanaged-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.unmanaged-pill {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11.5px;
  color: var(--text);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 4px 9px;
  overflow-wrap: anywhere;
}

/* --- instances ----------------------------------------------------------- */
.instance-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.instance-bar input {
  flex: 1 1 240px;
  min-width: 0;
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  padding: 9px 12px;
  font-size: 13px;
  outline: none;
}
.instance-bar input:focus { border-color: var(--gold); }
.inst-chips { display: flex; gap: 6px; flex-wrap: wrap; }

.inst-table { margin-top: 4px; }
.inst-head, .inst-row {
  display: grid;
  grid-template-columns:
    minmax(170px, 1.7fr) minmax(140px, 1.2fr) minmax(152px, 0.95fr)
    88px 86px 100px 84px;
  gap: 12px;
  align-items: center;
}
.inst-head {
  padding: 0 14px 8px;
  border-bottom: 1px solid var(--border-soft);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--muted);
}
.inst-row {
  padding: 11px 14px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  transition: background 0.12s ease;
}
.inst-row:nth-child(even) { background: rgba(255, 255, 255, 0.026); }
.inst-row:hover { background: rgba(255, 255, 255, 0.035); }
.inst-row:last-child { border-bottom: 0; }
.inst-cell { font-size: 12.5px; min-width: 0; overflow-wrap: anywhere; }
.inst-name { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.inst-title {
  font-weight: 700;
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.inst-sub { font-size: 11px; color: var(--muted); overflow-wrap: anywhere; }
.inst-owner, .inst-node { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A spec is a number and its unit: breaking between them ("40" / "GB") reads as
   a different machine, and it set the height of every row that wrapped. */
.inst-spec { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.inst-since { text-align: right; }
/* The console's pills are letter-spaced capitals; "suspended" broke across two
   lines inside a column 86px wide. A pill is never allowed to wrap. */
.hosting-panel .pill { white-space: nowrap; }
.inst-money { text-align: right; }
.inst-rate { font-weight: 700; color: var(--gold); font-variant-numeric: tabular-nums; }
.inst-money .inst-sub { font-variant-numeric: tabular-nums; }
.inst-cell .inst-sub { display: block; }
.inst-since { color: var(--muted); font-size: 11.5px; }

/* --- charging and requests, side by side --------------------------------- */
/* The rate sheet's rows are a label and a figure. The console's own rule keeps
   that figure at its full width (".loss-item .mono { flex: 0 0 auto }"), which
   is right in a wide column and pushed this page 600px sideways on a phone -
   so inside this panel the figure may shrink and wrap like any other word. */
.hosting-panel .loss-item { gap: 12px; }
.hosting-panel .loss-item > span { min-width: 0; overflow-wrap: anywhere; }
.hosting-panel .loss-item .mono { flex: 0 1 auto; text-align: right; }

.hosting-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

/* A finger needs a bigger target than a cursor. The console's buttons are built
   for a mouse; inside this panel they are lifted to a thumb's size on a touch
   screen, and only on one. */
@media (pointer: coarse) {
  .hosting-panel .btn { min-height: 40px; padding-left: 14px; padding-right: 14px; }
  .hosting-panel .seg-btn { min-height: 38px; }
  .instance-bar input { min-height: 42px; }
}

/* --- narrower screens ---------------------------------------------------- */
@media (max-width: 1180px) {
  .fleet-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Below this width the three text columns share what is left instead of
     claiming minimums the card does not have - a grid that cannot fit its own
     minimums does not shrink, it pushes the whole page sideways. */
  .inst-head, .inst-row {
    grid-template-columns:
      minmax(0, 1.6fr) minmax(0, 1.15fr) minmax(120px, 1fr)
      80px 78px 92px;
  }
  .inst-since { display: none; }
  .inst-head span:nth-child(7) { display: none; }
}
@media (max-width: 980px) {
  /* Two across, then one: a ring tile needs about 260px before its words start
     breaking, and three of them do not fit a laptop at half the page width. */
  .capacity-rings { grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
  .cap-tile { padding: 14px; }
  .hosting-servers.node-grid { grid-template-columns: 1fr; }
  .hosting-split { grid-template-columns: 1fr; }
}
@media (max-width: 980px) {
  .fleet-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Five figures in two columns leave the last one beside an empty cell, which
     reads as a tile that failed to load. The odd one out takes the whole row. */
  .fleet-kpis .kpi:last-child:nth-child(odd) { grid-column: span 2; }
  .inst-head { display: none; }
  .inst-row {
    grid-template-columns: 1fr;
    gap: 5px;
    padding: 12px 14px;
    border: 1px solid var(--border-soft);
    border-radius: 12px;
    margin-bottom: 8px;
  }
  .inst-cell {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    text-align: right;
  }
  .inst-cell::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    flex: 0 0 auto;
  }
  /* On a phone every cell is a labelled row of its own, so nothing has to be
     kept on one line any more - and holding it on one line is what would push
     the card wider than the screen. */
  .inst-spec, .inst-owner, .inst-node, .inst-title {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }
  .inst-name { display: flex; flex-direction: column; text-align: left; }
  .inst-name::before { content: none; }
  .inst-cell .inst-sub { text-align: right; }
  .inst-since { display: flex; }
    /* A phone gets the bar on its own line and the figure under it: side by side,
     "46.9 GB of 62.4 GB in use" plus a bar and a label is wider than a 320px
     screen and pushed the whole page 6px sideways. */
  .reality-row { grid-template-columns: 52px minmax(0, 1fr); gap: 8px; }
  .reality-line { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .reality-value { white-space: normal; }
  .seg { width: 100%; }
  .seg-btn { flex: 1 1 auto; }
}
/* On a narrow card the head's two halves go on top of each other: the capacity
   switch alone is wider than the space left beside a paragraph, and holding the
   two side by side pushed the page sideways. */
@media (max-width: 720px) {
  .hosting-panel .card-head { flex-direction: column; align-items: stretch; gap: 12px; }
  .hosting-panel .card-head .btn-row { justify-content: flex-start; width: 100%; }
  .seg { flex-wrap: wrap; }
  .capacity-head { flex-direction: column; align-items: flex-start; gap: 8px; }
}
@media (max-width: 520px) {
  .fleet-kpis { grid-template-columns: 1fr 1fr; }
  .node-head { flex-direction: column; align-items: flex-start; }
  .node-badges { justify-content: flex-start; }
}

/* --- THE THREE CHARTS: PEAK, NOW, DEDICATED -------------------------------
   The operator, 2026-10-22: "make it so there is peak compute/memory/storage
   usage and dedicated compute/memory/storage, so I can easily see how much is
   being used at peak and how much is dedicated to customers".

   Three bars per resource, each with its own number and its own sentence, and
   no bar means two things. Steel is the machine working (pale = its highest in
   the last 24 hours, bright = right now); gold is what is committed to a
   customer. The phone keeps all three: at 390px the label and the number stay
   on one line and the note wraps under the bar. */
/* All three tiles are one height, so the three peaks line up across the row
   and no card looks like it is missing a line. */
.capacity-rings { align-items: stretch; }
.use-tile {
  /* the tile is a column, whatever .cap-tile says: a chart needs the full width
     of its tile, not a dial's worth of it beside the words */
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 10px;
}
.use-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.use-unit { font-size: 11px; color: #7f8899; white-space: nowrap; }
.use-rows { display: flex; flex-direction: column; gap: 10px; }
.use-row {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr) 52px;
  grid-template-areas: "key meter val" "note note note";
  align-items: center;
  gap: 3px 10px;
  min-width: 0;
}
.use-key {
  grid-area: key;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: #9ba6b8;
  white-space: nowrap;
}
.use-meter {
  grid-area: meter;
  display: block;
  height: 7px;
  border-radius: 999px;
  background: #1b2230;
  overflow: hidden;
}
.use-meter > i { display: block; height: 100%; border-radius: 999px; }
.use-row[data-use="peak"] .use-meter > i { background: #3c5c85; }
.use-row[data-use="now"] .use-meter > i { background: #7ea7d4; }
.use-row[data-use="dedicated"] .use-meter > i { background: var(--gold); }
/* A resource at 90% of itself is worth looking at whatever the bar means. */
.use-meter.is-warm > i { background: var(--amber); }
.use-meter.is-hot > i { background: var(--red); }
/* Past 100% (a load can queue beyond the thread count) the bar is full, so a
   full bar and 112% would look identical - the end is capped in amber and the
   last of the fill is hatched, which reads as "and it keeps going". */
.use-meter.is-over { box-shadow: inset -3px 0 0 0 var(--amber); }
.use-row .use-meter.is-over > i {
  background-image: repeating-linear-gradient(135deg,
    rgba(255, 255, 255, 0.30) 0 3px, rgba(255, 255, 255, 0) 3px 7px);
}
.use-val {
  grid-area: val;
  text-align: right;
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #cfd6e2;
}
.use-row[data-use="peak"] .use-val { font-size: 15px; font-weight: 800; color: #eef3fa; }
.use-row[data-use="dedicated"] .use-val { color: var(--gold-dim); }
.use-val.is-over { color: var(--amber); }
.use-sub {
  grid-area: note;
  font-size: 12px;
  line-height: 1.4;
  color: #9ba6b8;
  overflow-wrap: anywhere;
}
.use-foot {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px solid var(--border-soft);
}
.use-room { font-size: 12.5px; line-height: 1.45; color: var(--gold-dim); }
.use-ever { font-size: 11.5px; line-height: 1.45; color: #97a1b3; }
@media (max-width: 520px) {
  .use-row { grid-template-columns: 74px minmax(0, 1fr) 48px; gap: 3px 8px; }
  .use-key { font-size: 10.5px; letter-spacing: 0.4px; }
  .use-sub { font-size: 11.5px; }
  .use-row[data-use="peak"] .use-val { font-size: 14px; }
}
