/* Palette matches the shared Torvyon dashboard style used by Torvyon-Relay,
   Torvyon-Guard, and RAM-Sentinel (--bg/--surface/--border/--orange etc.,
   see internal/dashboard/index.html in those repos), and the sidebar +
   ring/monitoring layout follows TOS-OCI's dashboard conventions —
   rather than a one-off scheme invented just for this project. */
:root {
  /* Enterprise/professional pass: --text was a mid-gray (#999) doing
     double duty as "primary" text — every headline, stat number, and
     section title on the site was rendering at reduced contrast with
     no clear hierarchy above it. Brightened to near-white and kept
     --text2/--text3 as the (unchanged) secondary/tertiary tiers below
     it — this one token change is what gives headings and key metrics
     real visual weight across every page, since virtually everything
     already references var(--text). */
  --bg: #0a0a0b;
  --surface: #17171a;
  --surface2: #202024;
  --surface3: #26262b;
  --border: #26262a;
  --text: #999999;
  --text2: #999999;
  --text3: #6b6b70;
  --orange: #f97316;
  --orange2: #fb923c;
  --green: #4ade80;
  --red: #f87171;
  --yellow: #fbbf24;
  --blue: #60a5fa;
  --violet: #a78bfa;
  --orange-dim: rgba(249, 115, 22, 0.12);
  --green-dim: rgba(74, 222, 128, 0.12);
  --red-dim: rgba(248, 113, 113, 0.12);
  --yellow-dim: rgba(251, 191, 36, 0.12);
  --blue-dim: rgba(96, 165, 250, 0.12);
  --violet-dim: rgba(167, 139, 250, 0.12);
  --mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, sans-serif;
  --card-grad: linear-gradient(160deg, var(--surface2) 0%, var(--surface) 100%);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.28);
  --shadow-md: 0 14px 32px rgba(0, 0, 0, 0.4);
  --radius: 14px;
  --sidebar-w: 224px;
  --sidebar-collapsed-w: 60px;
}

* { box-sizing: border-box; }

html { scrollbar-color: var(--border) var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text2);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  font-size: 14px;
}

.layout { display: flex; min-height: 100vh; }

/* ---- Sidebar ---- */
/* Collapse/expand follows TOS-OCI's dashboard: a single width transition
   on the container, icon-only in the collapsed state (text labels
   hidden via .sidebar.collapsed rather than a separate layout), no
   persisted state — always starts expanded on load, same as there. */
.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: 0 14px 20px;
  position: sticky;
  top: 0;
  height: 100vh;
  transition: width 0.2s ease;
  overflow: hidden;
}
.sidebar.collapsed { width: var(--sidebar-collapsed-w); padding: 0 10px 20px; }

/* Flush against the very top edge of the sidebar (no gap above it, no
   rounded corners) — bleeds edge-to-edge by countering .sidebar's own
   horizontal padding with a negative margin, same width the sidebar
   itself would otherwise leave blank up top. */
.side-brand-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 16px 14px;
  margin: 0 -14px 16px;
  background: rgba(255, 255, 255, 0.03);
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  overflow: hidden;
}
.sidebar.collapsed .side-brand-row { padding: 16px 10px; margin: 0 -10px 16px; justify-content: center; }

.side-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  flex: 1;
  min-width: 0;
}
.side-brand-title { font-size: 15.5px; font-weight: 800; letter-spacing: -0.3px; color: var(--text); line-height: 1.2; white-space: nowrap; }

/* Static Torvyon gem mark — replaced the animated pixel-matrix/wordmark
   logo, which needed real width to read (it measured the brand row's
   own clientWidth to size itself) and had none to work with once the
   sidebar became permanently icon-only. */
.side-brand-icon { width: 26px; height: 26px; display: block; flex-shrink: 0; }
.sidebar.collapsed .side-brand-txt { display: none; }

.side-nav { display: flex; flex-direction: column; gap: 3px; }

.side-link {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 12px;
  border-radius: 10px;
  color: var(--text2);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 600;
  border: 1px solid transparent;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  white-space: nowrap;
}
.side-link:hover { background: var(--surface2); color: var(--text); }
.side-link.active {
  background: var(--orange-dim);
  color: var(--orange2);
  border-color: rgba(249, 115, 22, 0.28);
  box-shadow: inset 2px 0 0 var(--orange);
}
.sidebar.collapsed .side-link { justify-content: center; padding: 9px; }
.sidebar.collapsed .side-label { display: none; }

/* Collapsed-sidebar hover tooltip (see wireSidebarTooltips in app.js).
   position:fixed + JS-computed coordinates, NOT a CSS-only absolute
   child of .side-link — .sidebar has overflow:hidden (needed to clip
   its own width-transition), which would silently clip a nested
   absolute tooltip trying to poke out past the sidebar's right edge.
   fixed positioning escapes that since .sidebar has no transform/filter
   establishing a containing block for it. */
#side-tooltip {
  position: fixed;
  display: none;
  padding: 6px 10px;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--surface3);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
  box-shadow: var(--shadow-md);
  pointer-events: none;
  z-index: 200;
}
#side-tooltip.show { display: block; }

.side-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border-radius: 4px;
  background: currentColor;
  opacity: 0.85;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}
.side-icon-grid { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1.5'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1.5'/%3E%3C/svg%3E"); }
.side-icon-wallet { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 7a2 2 0 0 1 2-2h13a1 1 0 0 1 1 1v3H5a2 2 0 0 1-2-2z'/%3E%3Cpath d='M3 9h17a1 1 0 0 1 1 1v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9z' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Ccircle cx='16.5' cy='15' r='1.5'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 7a2 2 0 0 1 2-2h13a1 1 0 0 1 1 1v3H5a2 2 0 0 1-2-2z'/%3E%3Cpath d='M3 9h17a1 1 0 0 1 1 1v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9z' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Ccircle cx='16.5' cy='15' r='1.5'/%3E%3C/svg%3E"); }
/* Two stacked cards — the "every registered wallet's card" list, kept
   visually distinct from the single-card .side-icon-wallet above. */
.side-icon-wallets { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='5' y='2' width='16' height='11' rx='2' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Crect x='2' y='8' width='16' height='11' rx='2'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='5' y='2' width='16' height='11' rx='2' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Crect x='2' y='8' width='16' height='11' rx='2'/%3E%3C/svg%3E"); }
.side-icon-pool { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='6' r='3'/%3E%3Ccircle cx='5' cy='17' r='3'/%3E%3Ccircle cx='19' cy='17' r='3'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='6' r='3'/%3E%3Ccircle cx='5' cy='17' r='3'/%3E%3Ccircle cx='19' cy='17' r='3'/%3E%3C/svg%3E"); }
.side-icon-peers { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='8' cy='9' r='4'/%3E%3Ccircle cx='17' cy='10' r='3'/%3E%3Cpath d='M2 21v-2a5 5 0 0 1 5-5h2a5 5 0 0 1 5 5v2' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M15 21v-1a4 4 0 0 0-3-3.86' fill='none' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='8' cy='9' r='4'/%3E%3Ccircle cx='17' cy='10' r='3'/%3E%3Cpath d='M2 21v-2a5 5 0 0 1 5-5h2a5 5 0 0 1 5 5v2' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M15 21v-1a4 4 0 0 0-3-3.86' fill='none' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); }
.side-icon-logout { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M16 17l5-5-5-5' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M21 12H9' stroke='currentColor' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M16 17l5-5-5-5' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M21 12H9' stroke='currentColor' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E"); }
.side-icon-registry { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='4' y='2' width='16' height='20' rx='2'/%3E%3Cpath d='M8 7h8M8 11h8M8 15h5' stroke='%23141415' stroke-width='1.5' fill='none'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='4' y='2' width='16' height='20' rx='2'/%3E%3Cpath d='M8 7h8M8 11h8M8 15h5' stroke='%23141415' stroke-width='1.5' fill='none'/%3E%3C/svg%3E"); }
.side-icon-validations { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2l8 3v6c0 5-3.5 8.5-8 11-4.5-2.5-8-6-8-11V5l8-3z' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M9 12l2 2 4-4' fill='none' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2l8 3v6c0 5-3.5 8.5-8 11-4.5-2.5-8-6-8-11V5l8-3z' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M9 12l2 2 4-4' fill='none' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); }
.side-icon-airport { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M2.5 19.5l19-7-2-2-7 2-6-5-2 1 4 5.5-4.5 1.5z' fill='none' stroke='currentColor' stroke-width='2' stroke-linejoin='round'/%3E%3Cpath d='M3 21h18' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M2.5 19.5l19-7-2-2-7 2-6-5-2 1 4 5.5-4.5 1.5z' fill='none' stroke='currentColor' stroke-width='2' stroke-linejoin='round'/%3E%3Cpath d='M3 21h18' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); }
.side-icon-newvalidator { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='9' cy='8' r='4' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M2 21v-1a6 6 0 0 1 6-6h2a6 6 0 0 1 6 6v1' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M19 8v6M16 11h6' stroke='currentColor' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='9' cy='8' r='4' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M2 21v-1a6 6 0 0 1 6-6h2a6 6 0 0 1 6 6v1' fill='none' stroke='currentColor' stroke-width='2'/%3E%3Cpath d='M19 8v6M16 11h6' stroke='currentColor' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E"); }
.side-icon-settings { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z' fill='none' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z' fill='none' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E"); }

.side-footer {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--text2);
}
.side-footer-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; font-family: var(--mono); white-space: nowrap; overflow: hidden; }
.side-footer-row.muted { color: var(--text3); }
.sidebar.collapsed .side-footer { display: none; }

.main-col { flex: 1; min-width: 0; display: flex; flex-direction: column; }

header {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 7px 20px;
  border-bottom: 1px solid var(--border);
  background: rgba(11, 11, 12, 0.85);
  backdrop-filter: blur(10px);
  position: sticky;
  top: 0;
  z-index: 10;
}

.search-box { flex: 1; max-width: 560px; }

.search-box input {
  width: 100%;
  padding: 5px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.18);
  color: var(--text);
  font-size: 12px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.search-box input::placeholder { color: var(--text3); }
.search-box input:focus {
  outline: none;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-dim);
}

.form-grid { display: grid; grid-template-columns: 140px 1fr; gap: 14px 16px; padding: 20px; align-items: center; }
.form-grid label { color: var(--text3); font-size: 13px; font-weight: 600; }
.form-grid input {
  padding: 9px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.18);
  color: var(--text);
  font-family: var(--mono);
  font-size: 13px;
  width: 100%;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.form-grid input.input-compact { width: 80px; flex: none; }

.threshold-stepper { display: flex; align-items: center; gap: 12px; padding: 8px 20px 4px; }
.threshold-btn { width: 36px; height: 36px; padding: 0; font-size: 18px; font-weight: 700; line-height: 1; border-radius: 10px; }
.threshold-value { display: flex; flex-direction: column; align-items: center; min-width: 100px; }
.threshold-value #threshold-current { font-family: var(--mono); font-size: 24px; font-weight: 700; color: var(--orange); }
.threshold-of { font-size: 10px; color: var(--text3); }
.form-grid input::placeholder { color: var(--text3); font-family: var(--sans); }
.form-grid input:focus {
  outline: none;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-dim);
}

.amount-field { display: flex; align-items: center; gap: 10px; }
.amount-field input { flex: 1; }

.coin-badge {
  display: block;
  flex-shrink: 0;
  border-radius: 50%;
}

.copy-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.18);
  color: var(--text3);
  cursor: pointer;
  vertical-align: middle;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.copy-btn:hover { color: var(--orange2); border-color: rgba(249, 115, 22, 0.35); background: var(--orange-dim); }
.copy-btn.copied { border-color: rgba(74, 222, 128, 0.4); background: var(--green-dim); }

.btn {
  padding: 9px 20px;
  border-radius: 9px;
  border: 1px solid var(--orange);
  background: linear-gradient(180deg, var(--orange2) 0%, var(--orange) 100%);
  color: #1a0d02;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.25);
  transition: filter 0.15s ease, transform 0.05s ease, box-shadow 0.15s ease;
}
.btn:hover { filter: brightness(1.08); box-shadow: 0 2px 8px rgba(249, 115, 22, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.25); }
.btn:active { transform: scale(0.97); filter: brightness(0.96); }
.btn.secondary {
  border-color: var(--border);
  background: var(--surface2);
  color: var(--text2);
  box-shadow: none;
}
.btn.secondary:hover { background: var(--surface3); color: var(--text); border-color: rgba(255, 255, 255, 0.16); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; filter: none; box-shadow: none; }

.btn-row { display: flex; gap: 10px; padding: 0 20px 20px; }

.notice {
  margin: 0 20px 20px;
  padding: 11px 15px;
  border-radius: 10px;
  font-size: 13px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.18);
}
.notice.ok { border-color: rgba(74, 222, 128, 0.4); background: var(--green-dim); color: var(--green); }
.notice.err { border-color: rgba(248, 113, 113, 0.4); background: var(--red-dim); color: var(--red); }
.notice.warn { border-color: rgba(251, 191, 36, 0.4); background: var(--yellow-dim); color: var(--yellow); }

.nav-status {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 18px;
  font-size: 12.5px;
  color: var(--text3);
  white-space: nowrap;
}
.nav-status b { color: var(--text); font-weight: 700; }

.live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 6px rgba(74, 222, 128, 0.6);
  display: inline-block;
  animation: pulseOpacity 2s ease-in-out infinite;
}
@keyframes pulseOpacity { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

@keyframes flashRow {
  0% { background: var(--orange-dim); }
  100% { background: transparent; }
}
tr.flash-new { animation: flashRow 2s ease-out; }

main {
  width: 100%;
  margin: 16px 0 40px;
  padding: 0 16px;
}

/* ---- Stat cards with colored underline bars (TOS-OCI monitoring style) ----
*/
.stat-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.card {
  background: var(--card-grad);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px 14px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
  position: relative;
}
.card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); border-color: rgba(255, 255, 255, 0.14); }

.card .label {
  font-size: 9.5px;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  margin-bottom: 6px;
  font-weight: 700;
}

.card .value { font-size: 23px; font-weight: 800; letter-spacing: -0.4px; color: var(--text); }
.card .value.mono { font-family: var(--mono); font-size: 13.5px; font-weight: 700; word-break: break-all; letter-spacing: 0; }
.card .sub { font-size: 11px; color: var(--text3); margin-top: 4px; }

.card-underline {
  position: absolute;
  left: 18px;
  width: 34px;
  bottom: 13px;
  height: 4px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}
.card-underline > div { height: 100%; border-radius: 2px; transition: width 0.3s ease; }

.page-header {
  margin-bottom: 26px;
  padding: 0 0 20px;
  border-bottom: 1px solid var(--border);
}
.page-header h1 {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.3px;
  color: var(--text);
  margin: 0 0 6px;
}
.page-header p {
  margin: 0;
  font-size: 13.5px;
  color: var(--text2);
}

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal-box {
  width: 100%;
  max-width: 480px;
  max-height: 85vh;
  overflow-y: auto;
  background: var(--card-grad);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
/* Wide variant for results with a table or a document + photo that need
   more horizontal room than the default confirmation-sized dialog. */
.modal-box.modal-wide { max-width: 760px; }
.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}
.modal-header h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}
.modal-close {
  background: transparent;
  border: none;
  color: var(--text3);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
.modal-close:hover { color: var(--text); }
.modal-body { padding: 20px; }

.file-input-wrap {
  display: flex;
  align-items: center;
  gap: 12px;
}
.photo-field-preview {
  margin-top: 10px;
  width: 84px;
  height: 84px;
  object-fit: cover;
  border-radius: 10px;
  border: 1px solid var(--border);
  display: block;
}
.file-input-btn {
  cursor: pointer;
  white-space: nowrap;
}
.file-input-name {
  font-size: 12.5px;
  color: var(--text3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-input-native {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.validator-pills {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min-content;
  grid-template-rows: repeat(7, auto);
  justify-items: start; /* grid's default is stretch, which was forcing every pill in a column to match the widest one — this keeps each pill its own compact, natural width */
  gap: 8px 14px;
  padding: 18px 20px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none; /* Firefox */
}
.validator-pills::-webkit-scrollbar { display: none; } /* Chrome/Safari/Edge — same rows-of-7 grid still scrolls, just with no visible scrollbar */
.validator-pill .ubuntu-logo { flex-shrink: 0; }
.validator-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px;
  border-radius: 16px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.18);
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text2);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.validator-pill:hover { color: var(--text); border-color: rgba(255, 255, 255, 0.2); }
.validator-pill.current { border-color: rgba(74, 222, 128, 0.4); color: var(--green); background: var(--green-dim); }
/* Actively signing blocks recently — green, matching .current but a
   touch less prominent (that's reserved for the actual tip producer). */
.validator-pill.active { border-color: rgba(74, 222, 128, 0.3); color: var(--green); }
.validator-pill.active .live-dot { background: var(--green); box-shadow: 0 0 6px rgba(74, 222, 128, 0.6); }
/* Part of the validator set (e.g. just added via Node Management) but
   hasn't voted/produced recently yet — orange glow, not yet "the same
   as offline," just "hasn't had its turn." */
.validator-pill.pending { border-color: rgba(249, 115, 22, 0.35); color: var(--orange2); }
.validator-pill.pending .live-dot { background: var(--orange); box-shadow: 0 0 6px rgba(249, 115, 22, 0.6); }

.validators-row {
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: 20px;
  align-items: stretch; /* the side column (Producer + Confirm a Record) stretches to exactly match the Validators box's height instead of sizing to its own content */
  margin-bottom: 20px;
}
.validators-row-main { margin-bottom: 0; }
.validators-row-side { display: flex; flex-direction: column; gap: 20px; overflow: hidden; }
.validators-row-side .panel { flex: 1; display: flex; flex-direction: column; margin-bottom: 0; }
@media (max-width: 900px) { .validators-row { grid-template-columns: 1fr; } }

.producer-box {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: 10px 18px;
}
.producer-box .ubuntu-logo { filter: drop-shadow(0 0 10px rgba(233, 84, 32, 0.35)); }
.producer-name { font-family: var(--mono); font-weight: 700; font-size: 15px; color: var(--green); }
.producer-ip { font-family: var(--mono); font-size: 12px; color: var(--text2); }

.confirm-record-body { flex: 1; display: flex; flex-direction: column; justify-content: center; }

.panel-divider {
  height: 1px;
  background: var(--border);
  margin: 4px 0 0;
}

.civil-photo {
  display: block;
  max-width: 220px;
  max-height: 220px;
  margin: 0 20px 20px;
  border-radius: 8px;
  border: 1px solid var(--border);
}

/* Two-column layout for the Civil Registry page: capture/lookup tools on
   the left, issuer-only actions (which need the private key panel
   visible above both Issue and Revoke) on the right — rather than one
   long single-column scroll of five stacked panels. Each column is its
   own flex stack (not relying on .panel's own margin-bottom) so the gap
   between stacked panels is even and independent of the grid gap between
   columns. */
.registry-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  align-items: start;
}
.registry-col {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.registry-col .panel {
  margin-bottom: 0;
}
.registry-col-label {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text3);
  padding: 0 2px;
}
@media (max-width: 900px) {
  .registry-columns { grid-template-columns: 1fr; }
}

.panel {
  background: var(--card-grad);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 12px;
  box-shadow: var(--shadow-sm);
  transition: border-color 0.15s ease;
}

/* Settings page: a compact 2-column row/column layout instead of one
   long vertical stack of full-width panels — panels sit side by side
   and shrink their internal padding so more fits on screen at once.
   Any panel that needs the full row (more fields/content) can opt out
   with .settings-span-2. */
.settings-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.settings-span-2 { grid-column: 1 / -1; }
@media (max-width: 860px) {
  .settings-grid { grid-template-columns: 1fr; }
}
.settings-grid .panel { margin-bottom: 0; display: flex; flex-direction: column; }
.settings-grid .form-grid { padding: 12px 16px; gap: 10px 12px; grid-template-columns: 110px 1fr; }
.settings-grid .kv { padding: 12px 16px; gap: 8px 12px; grid-template-columns: 130px 1fr; font-size: 12.5px; }
.settings-grid .btn-row { padding: 0 16px 14px; gap: 8px; flex-wrap: wrap; }
.settings-grid .panel h2 { padding: 10px 16px; }
.settings-grid .notice { margin: 0 16px 14px; }
/* validator-management-panel is itself just one placeholder cell in the
   grid, but it's filled with several separate .panel blocks at once
   (Fund/Threshold/Gossip/Remove/Stake) — display:contents makes it
   transparent to grid layout so those children become direct grid
   items of .settings-grid instead of being stuck stacked inside a
   single cell. */
#validator-management-panel { display: contents; }
.panel:hover {
  border-color: rgba(255, 255, 255, 0.12);
}

.sub-heading {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--text3);
  margin: 20px 0 10px;
  text-transform: uppercase;
}
.sub-heading:first-child { margin-top: 0; }

.panel h2 {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text2);
  padding: 12px 16px;
  margin: 0;
  border-bottom: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.02);
  display: flex;
  align-items: center;
  gap: 6px;
}

/* info-icon-btn: a small round "i" that reveals detail on click, rather
   than a permanently-visible warning banner cluttering every panel — the
   kind of progressive disclosure enterprise admin tools use so the
   default view stays clean but the detail is still one click away. */
.info-icon-wrap { position: relative; margin-left: auto; }
.info-icon-btn {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text3);
  font-size: 11px;
  font-weight: 700;
  font-style: italic;
  font-family: Georgia, serif;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.info-icon-btn:hover {
  color: var(--orange2);
  border-color: rgba(249, 115, 22, 0.4);
  background: var(--orange-dim);
}
.info-popover {
  position: absolute;
  top: 26px;
  right: 0;
  z-index: 20;
  width: 300px;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface3);
  box-shadow: var(--shadow-md);
  color: var(--text2);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.5;
  text-transform: none;
  letter-spacing: normal;
  white-space: normal;
}

table { width: 100%; border-collapse: collapse; font-size: 13px; }

th {
  text-align: left;
  padding: 12px 20px;
  color: var(--text3);
  font-weight: 700;
  background: rgba(255, 255, 255, 0.015);
  border-bottom: 1px solid var(--border);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
}

td { padding: 12px 20px; border-bottom: 1px solid rgba(255, 255, 255, 0.04); vertical-align: middle; color: var(--text2); font-variant-numeric: tabular-nums; }
tr:last-child td { border-bottom: none; }

tr.clickable { transition: background 0.12s ease; }
tr.clickable:hover { background: rgba(255, 255, 255, 0.025); cursor: pointer; }

.mono { font-family: var(--mono); }

a.link, .mono.link { color: var(--orange2); text-decoration: none; cursor: pointer; }
a.link:hover, .mono.link:hover { color: var(--orange); text-decoration: underline; }

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 700;
  background: var(--orange-dim);
  color: var(--orange2);
  letter-spacing: 0.2px;
}
.badge.green { background: var(--green-dim); color: var(--green); }
.badge.amber { background: var(--yellow-dim); color: var(--yellow); }
.badge.red { background: var(--red-dim); color: var(--red); }

/* Top-bar peer badge: the count itself reads ~3x bigger than the rest
   of the pill (matching the "peers" label's own text size) so it's the
   thing your eye actually lands on, not just another small badge lost
   among Height/Mempool/Tip. */
.peer-count-badge {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding: 3px 12px;
  background: none !important;
  box-shadow: none !important;
}
.peer-count-num {
  font-size: 33px;
  line-height: 1;
  font-weight: 800;
}

/* Plays once whenever the peer count just went UP (a new node joined) —
   just a pop/scale, no glow/box-shadow. Re-triggers every time because
   refreshStatus() rebuilds this element fresh each poll and only
   attaches this class on an actual increase, so a flat/falling count
   never replays it. */
@keyframes peer-badge-pop {
  0%   { transform: scale(1); }
  30%  { transform: scale(1.35); }
  60%  { transform: scale(0.95); }
  100% { transform: scale(1); }
}
.peer-badge-pop {
  animation: peer-badge-pop 600ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.empty { padding: 36px; text-align: center; color: var(--text3); font-size: 13px; }

.kv { display: grid; grid-template-columns: 180px 1fr; gap: 13px 16px; padding: 20px; font-size: 13px; }
.kv .k { color: var(--text3); font-weight: 600; }
.kv .v { word-break: break-all; color: var(--text2); }

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 18px;
  color: var(--text3);
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  transition: color 0.15s ease;
}
.back-link:hover { color: var(--orange); }

.error-box { padding: 48px; text-align: center; color: var(--text3); font-size: 13px; }

/* ---- Mining live panel ---- */
.mining-panel { display: flex; align-items: center; gap: 22px; padding: 20px; flex-wrap: wrap; }

.mining-orb {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  flex-shrink: 0;
  background: conic-gradient(var(--orange), var(--orange2), var(--yellow), var(--orange));
  animation: spin 2.2s linear infinite;
  position: relative;
  box-shadow: 0 0 18px rgba(249, 115, 22, 0.35);
}
.mining-orb::after { content: ""; position: absolute; inset: 6px; border-radius: 50%; background: var(--surface); }
.mining-orb.paused { animation: none; background: var(--surface3); box-shadow: none; }
@keyframes spin { to { transform: rotate(360deg); } }

.mining-meta { display: flex; flex-direction: column; gap: 3px; }
.mining-meta .title { font-size: 14px; font-weight: 700; color: var(--text); }
.mining-meta .sub { font-size: 12.5px; color: var(--text3); }

.mining-stats { display: flex; gap: 28px; margin-left: auto; flex-wrap: wrap; }
.mining-stat { text-align: right; }
.mining-stat .label { font-size: 10.5px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 3px; }
.mining-stat .value { font-family: var(--mono); font-size: 15px; font-weight: 700; color: var(--text); }

/* ---- Live activity: ring + area chart panel ---- */
.activity-grid {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 0;
}
@media (max-width: 900px) { .activity-grid { grid-template-columns: 1fr; } }

.activity-left { padding: 20px; border-right: 1px solid var(--border); display: flex; flex-direction: column; box-sizing: border-box; }
@media (max-width: 900px) { .activity-left { border-right: none; border-bottom: 1px solid var(--border); } }

.activity-flow { display: flex; align-items: stretch; gap: 22px; margin-bottom: 6px; flex: 1; min-height: 0; }

.ring-wrap { position: relative; width: 108px; height: 108px; flex-shrink: 0; align-self: center; }
.ring-center {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  pointer-events: none;
}
.ring-value { font-size: 20px; font-weight: 900; color: var(--text); line-height: 1; }
.ring-label { font-size: 8.5px; font-weight: 700; color: var(--text3); letter-spacing: 0.08em; text-transform: uppercase; margin-top: 3px; }

.mini-rings { display: flex; gap: 18px; align-self: center; }
.mini-ring-wrap { position: relative; width: 62px; height: 62px; }
.mini-ring-center {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  pointer-events: none;
}
.mini-ring-value { font-size: 13px; font-weight: 800; color: var(--text); }
.mini-ring-label { font-size: 8px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 1px; }

.flow-legend { display: flex; gap: 16px; font-size: 11px; color: var(--text3); margin-top: 10px; flex-wrap: wrap; }
.flow-legend span { display: inline-flex; align-items: center; gap: 5px; }
.flow-legend i { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }

.activity-right { padding: 20px; display: flex; flex-direction: column; gap: 14px; }
.health-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px; border-radius: 10px; font-size: 13px; font-weight: 700;
  border: 1px solid var(--border); background: rgba(0, 0, 0, 0.18);
}
.health-pill.ok { color: var(--green); border-color: rgba(74, 222, 128, 0.35); background: var(--green-dim); }
.health-pill.warn { color: var(--yellow); border-color: rgba(251, 191, 36, 0.35); background: var(--yellow-dim); }
.health-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

.health-rows { display: flex; flex-direction: column; gap: 9px; font-size: 12.5px; }
.health-row { display: flex; justify-content: space-between; gap: 12px; }
.health-row .k { color: var(--text3); }
.health-row .v { color: var(--text); font-family: var(--mono); font-weight: 600; text-align: right; word-break: break-all; }

/* ---- Chart wrap (line/area SVG) ----
*/
.chart-wrap { padding: 8px 12px 10px; }
.chart-bar { fill: var(--orange); opacity: 0.85; transition: opacity 0.15s ease; }
.chart-bar:hover { opacity: 1; }
.chart-axis-label { fill: var(--text3); font-size: 9px; font-family: var(--sans); }
.chart-empty { color: var(--text3); font-size: 13px; text-align: center; padding: 20px; }

.flow2-grid { stroke: rgba(255, 255, 255, 0.06); stroke-width: 1; }
.flow2-axis-label { fill: var(--text3); font-size: 9px; font-family: var(--sans); }
.flow2-avg-line { stroke: rgba(249, 115, 22, 0.4); stroke-width: 1; stroke-dasharray: 4 3; }
.flow2-avg-label { fill: rgba(249, 115, 22, 0.7); font-size: 9px; font-family: var(--sans); }

.ecg-chart { background: rgba(0, 0, 0, 0.18); border-radius: 6px; }
.ecg-grid-v { stroke: rgba(74, 222, 128, 0.06); stroke-width: 1; }
.ecg-grid-h { stroke: rgba(74, 222, 128, 0.06); stroke-width: 1; }
.ecg-baseline { stroke: rgba(74, 222, 128, 0.15); stroke-width: 1; stroke-dasharray: 2 3; }
.ecg-trace {
  stroke: var(--green);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 5px rgba(74, 222, 128, 0.65)) drop-shadow(0 0 10px rgba(74, 222, 128, 0.3));
  /* dasharray/dashoffset/transition are set from JS (animateEcgTrace),
     driven by the path's own real getTotalLength() — a hardcoded guess
     here would either cut the reveal short of the actual last point (if
     too small) or leave dead time at the end (if too large), and the
     real length changes with the data (taller spikes = longer path). */
}
.ecg-live-dot {
  fill: var(--green);
  filter: drop-shadow(0 0 6px rgba(74, 222, 128, 0.9));
  animation: ecg-beat 1s ease-in-out infinite;
}
@keyframes ecg-beat {
  0%, 100% { r: 3.5; opacity: 1; }
  15% { r: 6.5; opacity: 1; }
  30% { r: 3.5; opacity: .9; }
}
.ecg-hit { cursor: default; pointer-events: all; }
.ecg-chart { pointer-events: auto; }

/* ---- Network Heartbeat: a liveness-probe-monitor-style panel
   (Kubernetes/Consul dead-node-replacement dashboards) adapted to real
   validator data — per-validator ALIVE/IDLE ring badges, a shared
   uptime wave, a live quorum bar, a NODE/HEARTBEAT/RESULT table, and a
   closing formula callout. Replaces the old Node Management panel;
   validators now join by staking (see Settings), not admin-managed LXD
   provisioning. ----
*/
.heartbeat-wrap { padding: 10px 14px 14px; font-family: var(--mono); }

.hb-badges { display: flex; flex-wrap: wrap; gap: 20px; justify-content: center; padding: 8px 4px 18px; }
.hb-node { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 84px; }
.hb-badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px; border: 1px solid currentColor;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.8px;
  background: rgba(255, 255, 255, 0.03);
}
.hb-badge-dead { opacity: 0.4; }
.hb-badge .hb-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; filter: drop-shadow(0 0 4px currentColor); }
.hb-ring { position: relative; }
.hb-ring-track { fill: none; stroke: rgba(255, 255, 255, 0.08); stroke-width: 3; }
.hb-ring-arc {
  fill: none; stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 170; stroke-dashoffset: 0; transform: rotate(-90deg); transform-origin: 32px 32px;
  filter: drop-shadow(0 0 5px currentColor);
}
.hb-ring-live .hb-ring-arc { animation: hb-ring-spin 3s linear infinite; }
.hb-ring-glyph { font-size: 20px; font-weight: 700; }
.hb-node-name { font-size: 11.5px; font-weight: 700; color: var(--text); }
.hb-node-sub { font-size: 9px; color: var(--text3); }
@keyframes hb-ring-spin {
  0% { stroke-dashoffset: 170; }
  50% { stroke-dashoffset: 40; }
  100% { stroke-dashoffset: 170; }
}

.hb-wave-wrap {
  border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 8px;
  background: rgba(0, 0, 0, 0.25); padding: 8px 10px 0; margin-bottom: 14px; overflow: hidden;
}
.hb-wave-label { display: flex; justify-content: space-between; font-size: 9px; color: var(--text3); letter-spacing: 0.5px; margin-bottom: 2px; }
.hb-wave-tag { color: var(--text3); }
.hb-wave-svg { width: 100%; height: 84px; display: block; }
.hb-wave-line { filter: drop-shadow(0 0 4px currentColor); }
.hb-wave-flat { stroke: var(--text3); stroke-width: 1; stroke-dasharray: 3 3; }

.hb-timeout-row { margin-bottom: 16px; }
.hb-timeout-label { font-size: 9.5px; letter-spacing: 0.8px; color: var(--text3); margin-bottom: 5px; }
.hb-timeout-muted { color: var(--text3); font-weight: 400; text-transform: none; letter-spacing: 0; }
.hb-timeout-track { height: 10px; border-radius: 999px; background: rgba(255, 255, 255, 0.05); overflow: hidden; }
.hb-timeout-fill {
  height: 100%; border-radius: 999px; background: var(--green);
  box-shadow: 0 0 10px var(--green); transition: width 0.4s ease;
}

.hb-table { border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 8px; overflow: hidden; margin-bottom: 14px; }
.hb-row { display: grid; grid-template-columns: 1fr 1.4fr 1fr; gap: 10px; padding: 9px 12px; font-size: 11.5px; border-top: 1px solid rgba(255, 255, 255, 0.05); }
.hb-row:first-child { border-top: none; }
.hb-row-head { font-size: 9px; letter-spacing: 0.8px; color: var(--text3); background: rgba(255, 255, 255, 0.02); }
.hb-row-node { color: var(--text); font-weight: 700; }
.hb-row-heartbeat { color: var(--text2); }
.hb-row-result { font-weight: 700; letter-spacing: 0.4px; text-align: right; }

.hb-formula {
  border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 8px;
  padding: 12px 16px; text-align: center; background: rgba(255, 255, 255, 0.015);
}
.hb-formula-main { font-size: 13px; font-weight: 700; color: var(--green); letter-spacing: 0.5px; text-shadow: 0 0 12px rgba(76, 217, 100, 0.35); }
.hb-formula-sub { font-size: 10px; color: var(--text3); margin-top: 5px; line-height: 1.5; }

/* ---- New Validators page — reuses the heartbeat table's row styling
   (.hb-row/.hb-table) but with its own column split and an extra
   full-width status line under each candidate's action button. ---- */
.nv-row { grid-template-columns: 1.4fr 1fr 1.2fr; align-items: center; flex-wrap: wrap; }
.nv-actions { grid-column: 3; }
.nv-status { grid-column: 1 / -1; margin-top: 6px; font-size: 12px; }
.nv-status:empty { margin-top: 0; }

/* ---- Node Management + Mempool/Block Time compact side-by-side row:
   Node Management takes the left half, Mempool Load and Block Time
   stack in the right half — three panels' worth of info in the
   vertical space two would normally take. ----
/* ---- Layout: Node Management grid (left) + stacked Mempool/Block-Time/Connected-Nodes/Consensus-Demo (right) ----
   The right column packs four panels in the vertical space two would normally take. ----
*/
.node-mgmt-grid { display: grid; grid-template-columns: 1.7fr 1fr; gap: 12px; align-items: stretch; margin-bottom: 12px; }
.node-mgmt-side { display: flex; flex-direction: column; gap: 12px; }
.node-mgmt-side .panel { margin-bottom: 0; }
/* The right column's chart fills whatever extra height the taller
   Network Heartbeat panel next to it creates, instead of leaving a
   raw dead-background gap below a shorter card. */
.node-mgmt-side .chart-fill { flex: 1; display: flex; flex-direction: column; }
.node-mgmt-side .chart-fill .chart-wrap { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.node-mgmt-side .chart-fill .chart-wrap svg { height: auto !important; flex: 1; min-height: 100px; }
@media (max-width: 1100px) { .node-mgmt-grid { grid-template-columns: 1fr; } }

/* ---- Mempool load bar ----
*/
.load-bar-wrap { padding: 8px 12px 10px; }
.load-bar-track { height: 12px; border-radius: 4px; background: rgba(255, 255, 255, 0.05); overflow: hidden; }
.load-bar-fill { height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--orange), var(--yellow)); transition: width 0.3s ease; }
.load-bar-label { display: flex; justify-content: space-between; font-size: 10px; color: var(--text3); margin-top: 4px; }

/* ---- Main content panels (below node-mgmt-grid) ----
*/
main .panel { margin-bottom: 6px; }
main .panel h2 { padding: 4px 12px; font-size: 10px; }

/* ---- Chart wrap (line/area SVG) ----
*/
.chart-wrap { padding: 8px 12px 10px; }
.connected-nodes-scroll {
  max-height: 200px;
  overflow-y: auto;
  overflow-x: hidden;
  /* Firefox: thin scrollbar, transparent track */
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
}
.connected-nodes-scroll::-webkit-scrollbar {
  width: 0;
  height: 0;
  background: transparent;
}
.connected-nodes-scroll::-webkit-scrollbar-track {
  background: transparent;
}
.connected-nodes-scroll::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: 0;
}
.connected-nodes-scroll:hover::-webkit-scrollbar-thumb {
  background: transparent;
}
.connected-nodes-scroll::-webkit-scrollbar-thumb:hover {
  background: transparent;
}

/* Show scrollbar when more than 2 nodes */
.connected-nodes-scroll.show-scrollbar {
  overflow-y: scroll;  /* Force scrollbar visibility */
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.2) transparent;
}
.connected-nodes-scroll.show-scrollbar::-webkit-scrollbar {
  width: 6px;
}
.connected-nodes-scroll.show-scrollbar::-webkit-scrollbar-track {
  background: transparent;
}
.connected-nodes-scroll.show-scrollbar::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
}
.connected-nodes-scroll.show-scrollbar::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.35);
}

/* ---- Live consensus round (Validations page) ---- */
.consensus-round { padding: 20px; display: flex; flex-direction: column; gap: 16px; }
.consensus-round-head { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: 8px; }
.consensus-round-head .title { font-size: 14px; font-weight: 700; color: var(--text); }
.consensus-round-head .sub { font-size: 12px; color: var(--text3); font-family: var(--mono); }

.vote-track { display: flex; gap: 5px; height: 32px; }
.vote-segment { flex: 1; height: 100%; border-radius: 5px; background: rgba(255, 255, 255, 0.05); border: 1px solid var(--border); overflow: hidden; position: relative; transition: border-color 0.3s ease; }
.vote-segment-fill { position: absolute; inset: 0; background: linear-gradient(90deg, var(--orange), var(--yellow)); transform: scaleX(0); transform-origin: left; transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1); }
.vote-segment.filled { border-color: transparent; }
.vote-segment.filled .vote-segment-fill { transform: scaleX(1); }
.vote-segment.filled.finalized .vote-segment-fill { background: linear-gradient(90deg, var(--green), #34d399); }
.vote-track-label { display: flex; justify-content: space-between; font-size: 12px; color: var(--text3); margin-top: 6px; }
.vote-track-label b { color: var(--text); font-family: var(--mono); }

.validator-vote-grid { display: flex; flex-wrap: wrap; gap: 10px; }
.validator-vote-chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px; border-radius: 20px;
  border: 1px solid var(--border); background: rgba(0, 0, 0, 0.18);
  font-family: var(--mono); font-size: 12px; color: var(--text3);
  transition: border-color 0.3s ease, color 0.3s ease, background 0.3s ease, transform 0.3s ease;
}
.validator-vote-chip .mark { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.validator-vote-chip.voted { color: var(--green); border-color: rgba(74, 222, 128, 0.4); background: var(--green-dim); transform: scale(1.03); }
.validator-vote-chip.voted .mark { box-shadow: 0 0 6px rgba(74, 222, 128, 0.6); }
.validator-vote-chip.proposer { border-style: dashed; }
.validator-vote-chip.waiting .mark { animation: pulseOpacity 1.4s ease-in-out infinite; }

.consensus-idle { display: flex; align-items: center; gap: 10px; padding: 4px 0; color: var(--text3); font-size: 13px; }
.consensus-idle .live-dot { background: var(--text3); box-shadow: none; }

.consensus-finalized-flash { animation: consensusFlash 1.6s ease-out; }
@keyframes consensusFlash {
  0% { background: var(--green-dim); }
  100% { background: transparent; }
}

/* ---- Stale-tab reload overlay: 6 blockchain blocks link up one by
   one, then the page reloads. Dead center of the viewport, no banner. */
.reload-overlay {
  position: fixed; inset: 0; z-index: 3000;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 22px;
  background: rgba(8, 8, 10, 0.94);
}
.reload-chain { display: flex; align-items: center; }
.reload-block {
  width: 34px; height: 34px; border-radius: 8px;
  border: 2px solid var(--border);
  background: rgba(255, 255, 255, 0.03);
  animation: reloadBlockFill 1.8s ease-in-out infinite;
}
.reload-link {
  width: 18px; height: 3px;
  background: var(--border);
  animation: reloadLinkFill 1.8s ease-in-out infinite;
}
@keyframes reloadBlockFill {
  0%, 100% { border-color: var(--border); background: rgba(255, 255, 255, 0.03); box-shadow: none; }
  15%, 55% { border-color: var(--orange); background: var(--orange-dim); box-shadow: 0 0 12px var(--orange-dim); }
}
@keyframes reloadLinkFill {
  0%, 100% { background: var(--border); }
  15%, 55% { background: var(--orange); }
}
.reload-label {
  color: var(--text2); font-size: 13.5px; font-weight: 600; text-align: center; max-width: 380px;
}

/* ---- Airport checkpoint page ---- */
.airport-search { display: flex; gap: 10px; padding: 20px; }
.airport-search input {
  flex: 1;
  font-size: 15px;
  padding: 14px 18px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.22);
  color: var(--text);
  font-family: var(--mono);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.airport-search input::placeholder { color: var(--text3); font-family: var(--sans); }
.airport-search input:focus {
  outline: none;
  border-color: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-dim);
}
.airport-search .btn { padding: 0 26px; font-size: 14px; border-radius: 12px; }
.airport-search .btn.secondary { padding: 0 18px; }

/* Officer's camera-scan overlay */
.scan-overlay {
  position: fixed; inset: 0; z-index: 2000;
  background: rgba(0, 0, 0, 0.88);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px;
}
.scan-overlay video { width: min(92vw, 480px); border-radius: 16px; border: 2px solid var(--orange); }
.scan-overlay .hint { color: var(--text2); font-size: 13.5px; text-align: center; max-width: 90vw; }
.scan-overlay .btn { padding: 8px 22px; }

/* Loading state with an indeterminate progress bar — used while a
   check is in flight, so "waiting" has visible motion instead of just
   static text sitting there. */
.check-loading { padding: 20px; display: flex; flex-direction: column; gap: 12px; }
.check-loading-row { display: flex; align-items: center; gap: 12px; color: var(--text2); font-size: 13.5px; }
.spinner-sm {
  width: 18px; height: 18px; border-radius: 50%; flex-shrink: 0;
  border: 2.5px solid var(--border); border-top-color: var(--orange);
  animation: spin 0.8s linear infinite;
}
.progress-indeterminate { height: 12px; border-radius: 6px; background: rgba(255, 255, 255, 0.06); overflow: hidden; position: relative; }
.progress-indeterminate::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 40%; border-radius: 4px;
  background: linear-gradient(90deg, transparent, var(--orange), transparent);
  animation: progressSlide 1.1s ease-in-out infinite;
}
@keyframes progressSlide { 0% { left: -40%; } 100% { left: 100%; } }

.airport-verdict {
  margin: 0 20px 20px; padding: 26px; border-radius: 14px;
  display: flex; align-items: center; gap: 20px;
  border: 2px solid var(--border);
}
.airport-verdict.clear { border-color: rgba(74, 222, 128, 0.5); background: var(--green-dim); }
.airport-verdict.flagged { border-color: rgba(248, 113, 113, 0.5); background: var(--red-dim); }
.airport-verdict.notfound { border-color: rgba(251, 191, 36, 0.5); background: var(--yellow-dim); }
.airport-verdict-icon { width: 52px; height: 52px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 28px; font-weight: 900; }
.airport-verdict.clear .airport-verdict-icon { background: var(--green); color: #06240f; }
.airport-verdict.flagged .airport-verdict-icon { background: var(--red); color: #2a0808; }
.airport-verdict.notfound .airport-verdict-icon { background: var(--yellow); color: #2a2106; }
.airport-verdict-text .title { font-size: 20px; font-weight: 800; color: var(--text); }
.airport-verdict.clear .title { color: var(--green); }
.airport-verdict.flagged .title { color: var(--red); }
.airport-verdict.notfound .title { color: var(--yellow); }
.airport-verdict-text .sub { font-size: 13px; color: var(--text2); margin-top: 4px; }

/* ---- Citizen credential (printable, QR-scannable) ---- */
.credential-wrap { max-width: 720px; }
.credential-card {
  background: var(--card-grad);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-md);
}
.credential-card.revoked { border-color: rgba(248, 113, 113, 0.5); }
.credential-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px 22px; background: var(--orange-dim); border-bottom: 1px solid var(--border);
}
.credential-card.revoked .credential-header { background: var(--red-dim); }
.credential-brand { font-weight: 800; font-size: 15px; color: var(--text); }
.credential-status { font-weight: 700; font-size: 12.5px; color: var(--orange2); text-transform: uppercase; letter-spacing: 0.4px; }
.credential-card.revoked .credential-status { color: var(--red); }
.credential-body { display: flex; gap: 22px; padding: 24px; align-items: flex-start; flex-wrap: wrap; }
.credential-photo-col { flex-shrink: 0; }
.credential-photo { width: 110px; height: 110px; object-fit: cover; border-radius: 10px; border: 1px solid var(--border); }
.credential-photo-empty {
  width: 110px; height: 110px; border-radius: 10px; border: 1px dashed var(--border);
  display: flex; align-items: center; justify-content: center; text-align: center;
  font-size: 11px; color: var(--text3);
}
.credential-fields { flex: 1; min-width: 220px; display: flex; flex-direction: column; gap: 9px; }
.cf { display: flex; flex-direction: column; gap: 1px; }
.cf-k { font-size: 10.5px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.4px; }
.cf-v { font-size: 13.5px; color: var(--text); }
.cf-v.mono { font-family: var(--mono); word-break: break-all; }
.cf-v.mono.small { font-size: 11px; color: var(--text2); }
.credential-qr { flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.credential-qr svg { width: 128px; height: 128px; border-radius: 8px; }
.credential-qr-label { font-size: 10.5px; color: var(--text3); }

@media print {
  .sidebar, header, .no-print, .back-link { display: none !important; }
  main { padding: 0 !important; margin: 0 !important; }
  body { background: #fff; color: #000; }
  .credential-card { box-shadow: none; border: 1px solid #000; }
  .credential-header { background: #eee !important; }
}

/* ---- Post-issuance "save to your phone" QR prompt ---- */
.digital-card-qr {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 4px 20px 16px;
  padding: 14px 16px;
  border-radius: 12px;
  background: rgba(249, 115, 22, 0.06);
  border: 1px solid rgba(249, 115, 22, 0.18);
}
.digital-card-qr svg { width: 72px; height: 72px; border-radius: 6px; flex-shrink: 0; }
.digital-card-qr-title { font-size: 13px; font-weight: 700; color: var(--text); }
.digital-card-qr-sub { font-size: 11.5px; color: var(--text2); margin-top: 3px; line-height: 1.4; }

/* ---- Digital ID smart card (wallet-pass style, citizen's own phone) ---- */
.wallet-detail-page {
  max-width: 940px; margin: 0 auto; display: grid; grid-template-columns: 420px 1fr;
  align-items: start; gap: 0; position: relative;
}
.wallet-detail-left { display: flex; flex-direction: column; gap: 20px; padding-right: 28px; }
.wallet-detail-right { display: flex; flex-direction: column; gap: 20px; padding-left: 28px; border-left: 1px solid var(--border); min-height: 100%; }
.wallet-detail-panel { width: 100%; margin: 0; }
/* Send TVX header once logged in — badge sits right after the title,
   Log Out is pushed to the panel's far right via margin-left:auto
   (same trick .info-icon-wrap uses elsewhere), so it reads as part of
   this panel's own header bar, not a separate control floating nearby. */
.wc-auth-badge {
  font-size: 11px; font-weight: 700; letter-spacing: 0.3px; text-transform: none;
  color: var(--green, #4ade80); background: rgba(74, 222, 128, 0.12);
  padding: 2px 8px; border-radius: 20px;
}
.wc-logout-btn { margin-left: auto; text-transform: none; letter-spacing: normal; }
.wc-pw-setup {
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border);
  font-size: 12.5px; color: var(--text3);
}
.wc-pw-setup label { display: block; margin-bottom: 4px; }
.wc-pw-setup .form-grid { display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center; }
.wc-pw-setup .form-grid input { margin: 0; }
@media (max-width: 860px) {
  .wallet-detail-page { grid-template-columns: 1fr; max-width: 460px; }
  .wallet-detail-left, .wallet-detail-right { padding: 0; border-left: none; }
}
/* 350x221px — a bit larger than a true 1:1 ID-1 card (324x204) for
   better on-screen presence, same 1.586 aspect-ratio as .smart-card.
   max-width is 350px content + this rule's own 16px side padding on
   each side. */
.digital-card-page { max-width: 382px; margin: 32px auto 0; padding: 0 16px; }
.digital-card-tap-hint { border-bottom: 1px solid var(--border); padding-bottom: 18px; }
.wallet-action-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px;
}
.wallet-action-row .btn { width: 100%; }
.logout-btn { color: var(--red, #f87171); border-color: rgba(248, 113, 113, 0.35); }
.smart-card {
  position: relative;
  width: 100%;
  aspect-ratio: 1.586 / 1;
  border-radius: 18px;
  padding: 18px 20px;
  color: #fff;
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0) 55%),
    linear-gradient(135deg, #2a1608 0%, #7c3a0a 45%, #f97316 100%);
  box-shadow: 0 18px 40px rgba(249, 115, 22, 0.25), 0 2px 6px rgba(0, 0, 0, 0.4);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
}
.smart-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  pointer-events: none;
}
.smart-card.revoked {
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 55%),
    linear-gradient(135deg, #240a0a 0%, #5a1414 45%, #ef4444 100%);
  box-shadow: 0 18px 40px rgba(239, 68, 68, 0.25), 0 2px 6px rgba(0, 0, 0, 0.4);
}
.smart-card-top { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.smart-card-brand {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 800; letter-spacing: 0.3px; text-transform: uppercase;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.smart-card-chip {
  width: 22px; height: 16px; border-radius: 4px;
  background: linear-gradient(135deg, #ffe9c7, #d8a45c);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}
.smart-card-status {
  flex-shrink: 0;
  font-size: 10px; font-weight: 800; letter-spacing: 0.5px;
  padding: 3px 9px; border-radius: 20px;
  background: rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(2px);
}
.smart-card { cursor: pointer; transition: transform 0.12s ease; }
.smart-card:active { transform: scale(0.98); }
.smart-card-body { display: flex; align-items: center; gap: 14px; }
.smart-card-qr {
  flex-shrink: 0;
  width: 42px;
  height: 42px;
  background: #fff;
  border-radius: 6px;
  padding: 3px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}
.smart-card-qr svg { width: 100%; height: 100%; display: block; }
.digital-card-tap-hint { text-align: center; font-size: 11px; color: var(--text3); margin-top: 10px; }

.asset-card .smart-card-body { justify-content: space-between; }
.asset-card-balance-value { display: flex; align-items: center; gap: 8px; font-size: 34px; font-weight: 800; letter-spacing: -0.5px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); }
.asset-card-balance-value .coin-badge { flex-shrink: 0; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3)); }
.mini-wallet-card-balance { display: flex; align-items: center; gap: 6px; }
.mini-wallet-card-balance .coin-badge { flex-shrink: 0; }
.asset-card-balance-label { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.4px; opacity: 0.85; margin-top: 4px; }
.asset-card-holder {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  margin-top: 8px;
}

/* ---- Card flip (front: balance/chip/holder — back: DOB/CVC) ---- */
.asset-card-flip-wrap { position: relative; }
.asset-card-face-back { display: none; }
.asset-card-flip-wrap.flipped .asset-card-face-front { display: none; }
.asset-card-flip-wrap.flipped .asset-card-face-back { display: block; }
.asset-card-back { cursor: default; justify-content: flex-start; gap: 10px; }
.asset-card-stripe { height: 34px; margin: 4px -20px 6px; background: repeating-linear-gradient(135deg, #0a0a0b 0 3px, #17171a 3px 6px); }
.asset-card-back-row { display: flex; justify-content: space-between; align-items: baseline; font-size: 12.5px; }
.asset-card-back-label { text-transform: uppercase; letter-spacing: 0.4px; opacity: 0.75; font-weight: 700; font-size: 10.5px; }
.asset-card-back-value { font-weight: 700; }

/* ---- Gateway logged-out landing: demo hero + spinning 3D card ---- */
.gateway-demo { max-width: 720px; margin: 40px auto 0; padding: 0 16px; text-align: center; }

/* "Get Started" opens the Log In / Register card inline, pinned to
   the bottom-left corner of the landing page instead of navigating to
   a separate full-page route — same auth-brand/auth-card markup as
   the standalone #/account page (see authCardInnerHtml()), just
   anchored differently. */
.gateway-landing-auth {
  position: fixed;
  left: calc(var(--sidebar-collapsed-w) + 20px);
  bottom: 24px;
  z-index: 80;
  width: min(360px, calc(100vw - var(--sidebar-collapsed-w) - 40px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  animation: gatewayLandingAuthIn 0.22s ease;
}
@keyframes gatewayLandingAuthIn {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 640px) {
  .gateway-landing-auth { left: 16px; right: 16px; bottom: 16px; width: auto; }
}
.gateway-demo-eyebrow { font-size: 12px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; color: var(--orange2); margin-bottom: 10px; }
.gateway-demo-title { font-size: 30px; font-weight: 800; letter-spacing: -0.5px; color: var(--text); margin: 0 0 12px; line-height: 1.25; }
.gateway-demo-sub { font-size: 14px; color: var(--text2); max-width: 520px; margin: 0 auto 24px; line-height: 1.55; }
.gateway-demo-features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
  margin: 40px 0 24px;
  text-align: left;
}
.gateway-demo-feature {
  background: var(--card-grad);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow-sm);
}
.gateway-demo-feature-title { font-size: 14px; font-weight: 800; color: var(--text); margin-bottom: 8px; }
.gateway-demo-feature-body { font-size: 12.5px; color: var(--text2); line-height: 1.55; }
.gateway-demo-3d-stage { perspective: 1200px; display: flex; justify-content: center; margin-bottom: 8px; }
.gateway-demo-3d-card { width: 320px; transform-style: preserve-3d; animation: gatewayCardSpin 10s linear infinite; }
.gateway-demo-card-face { cursor: default; backface-visibility: hidden; }
.gateway-demo-card-face:hover { transform: none; }
@keyframes gatewayCardSpin {
  0%   { transform: rotateY(0deg) rotateX(6deg); }
  50%  { transform: rotateY(180deg) rotateX(6deg); }
  100% { transform: rotateY(360deg) rotateX(6deg); }
}
@media (prefers-reduced-motion: reduce) {
  .gateway-demo-3d-card { animation: none; transform: rotateY(0deg) rotateX(6deg); }
}

/* ---- Gateway Register/Log In screen ---- */
.auth-page {
  max-width: 440px;
  margin: 48px auto;
  padding: 0 16px;
}
.auth-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 22px;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: 1px;
  color: var(--text);
}
.auth-card {
  background: var(--card-grad);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.auth-tabs { display: flex; border-bottom: 1px solid var(--border); }
.auth-tab {
  flex: 1;
  padding: 16px;
  background: transparent;
  border: none;
  color: var(--text3);
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.auth-tab:hover { color: var(--text2); }
.auth-tab-active { color: var(--orange2); border-bottom-color: var(--orange); }
.auth-form { padding: 20px; }
.auth-sub { font-size: 12.5px; color: var(--text2); margin: 0 0 14px; }
.auth-form .form-grid { margin: 0 0 4px; }
.auth-form .tier-picker { margin: 0 0 14px; }
.auth-switch { text-align: center; font-size: 12px; color: var(--text3); margin: 14px 0 0; }

/* ---- Card tier picker (Wallet page) — tiles rendered at the real
   card aspect ratio (1.586:1, same as .smart-card) so the picker
   itself looks like a row of actual mini cards, not abstract swatches. ---- */
.tier-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
  margin: 0 20px 16px;
}
.tier-tile {
  aspect-ratio: 1.586 / 1;
  padding: 16px;
  border-radius: 14px;
  cursor: pointer;
  border: 2px solid transparent;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
  transition: transform 0.12s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.tier-tile:active { transform: scale(0.97); }
.tier-tile-selected { border-color: rgba(255, 255, 255, 0.8); box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2), 0 8px 20px rgba(0, 0, 0, 0.25); }
.tier-tile-top { display: flex; align-items: center; gap: 8px; }
.tier-tile-chip { width: 20px; height: 15px; border-radius: 4px; background: linear-gradient(135deg, #ffe9c7, #d8a45c); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25); }
.tier-tile-brand { font-size: 11px; font-weight: 800; letter-spacing: 0.6px; opacity: 0.85; }
.tier-tile-name { font-weight: 800; font-size: 20px; letter-spacing: -0.2px; }
.tier-tile-offer { font-size: 11.5px; opacity: 0.92; line-height: 1.4; }

/* Shared tier color themes — used by both the picker tiles and the
   rendered smart-card itself, so a chosen tier looks the same in both
   places. */
.tier-bronze { background: linear-gradient(135deg, #2a1608 0%, #7c3a0a 50%, #f97316 100%); color: #fff; }
.tier-silver { background: linear-gradient(135deg, #3a3a3f 0%, #8a8d94 50%, #e4e6ea 100%); color: #14161a; }
.tier-gold { background: linear-gradient(135deg, #4a3200 0%, #b8860b 50%, #ffd75e 100%); color: #fff; }
.tier-platinum { background: linear-gradient(135deg, #2c2f36 0%, #8fa3ad 50%, #e8f1f4 100%); color: #14161a; }
.smart-card.tier-silver .smart-card-status,
.smart-card.tier-platinum .smart-card-status { background: rgba(0, 0, 0, 0.12); }
/* Bronze and Platinum badges read as plain text, no pill background —
   the other tiers (silver/gold) keep theirs. */
.smart-card.tier-bronze .smart-card-status,
.smart-card.tier-platinum .smart-card-status {
  background: none; backdrop-filter: none; padding: 3px 0;
}

/* Cityscape background for the Spending Wallet card on the genesis
   node's (node-0) TVX Wallet showcase page ONLY — scoped to this one
   card's id (#gw-card-platinum), deliberately not to .tier-platinum,
   so a regular wallet holder who picks a Platinum-tier card for
   themselves still gets the plain gradient, not this photo. Same
   324x204 real-card size as every other card (.gw-showcase-col) — this
   block only changes the background and repositions two elements. */
#gw-card-platinum .smart-card.tier-platinum {
  background: linear-gradient(135deg, rgba(20, 22, 28, 0.55) 0%, rgba(20, 22, 28, 0.3) 55%, rgba(20, 22, 28, 0.15) 100%),
              url("platinum-card-bg.jpg") center 38% / cover no-repeat;
  color: #fff;
}
/* PLATINUM pulled out of the title row and pinned to the card's own
   top-right corner, so the (long) "Torvyon Digital Asset Card" title
   never has to compete with it for space at this card's real-card
   width — see the .smart-card-top crowding this same title row hit at
   324px before .smart-card-status got flex-shrink:0. */
#gw-card-platinum .smart-card.tier-platinum .smart-card-status {
  position: absolute; top: 20px; right: 20px; background: none; color: #fff;
}
/* At this card's real 324px width, the full "Torvyon Digital Asset
   Card" title alone nearly fills the available space — with PLATINUM
   now pulled into the corner (not sharing the same flex row anymore),
   the title needs to wrap under it rather than run underneath/behind
   it. */
#gw-card-platinum .smart-card.tier-platinum .smart-card-brand { max-width: 175px; white-space: normal; line-height: 1.35; }
/* Chip pushed down out of the balance row entirely — sits lower on the
   card face, closer to where a real card's chip actually sits relative
   to the rest of the layout, instead of inline with the balance. */
#gw-card-platinum .smart-card.tier-platinum .smart-card-body { justify-content: flex-start; }
#gw-card-platinum .smart-card.tier-platinum .emv-chip { position: absolute; right: 20px; bottom: 54px; }
#gw-card-platinum .smart-card.tier-platinum .asset-card-holder,
#gw-card-platinum .smart-card.tier-platinum .smart-card-hash,
#gw-card-platinum .smart-card.tier-platinum .smart-card-issuer,
#gw-card-platinum .smart-card.tier-platinum .asset-card-balance-label { color: rgba(255, 255, 255, 0.82); }

/* ---- "Chip" scan target — replaces the plain white QR box with a
   metallic chip-styled frame; the QR itself stays fully visible/
   scannable inside it (a hidden or opacity'd QR can't be read by a
   real camera), just housed to look like a card's contact chip. ---- */
.smart-card-chip-scan {
  flex-shrink: 0;
  width: 56px;
  height: 56px;
  border-radius: 8px;
  padding: 6px;
  position: relative;
  background: linear-gradient(135deg, #ffe9c7, #d8a45c);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25), 0 2px 6px rgba(0, 0, 0, 0.3);
}
.chip-scan-lines {
  position: absolute;
  inset: 6px;
  border-radius: 4px;
  background-image:
    linear-gradient(rgba(0, 0, 0, 0.18) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0, 0, 0, 0.18) 1px, transparent 1px);
  background-size: 7px 7px;
}
.chip-scan-qr { position: relative; width: 100%; height: 100%; background: #fff; border-radius: 4px; padding: 2px; }
.chip-scan-qr svg { width: 100%; height: 100%; display: block; }

/* ---- EMV-style chip (Mastercard/Visa look) — purely decorative on the
   card front; the actual scannable QR lives on the back (see
   .asset-card-back-qr), same as how a real card's chip isn't itself a
   barcode. chip-icon.png (a cropped photo-real chip module, ~2:1
   aspect) replaces the old hand-drawn SVG gradient+pads. ---- */
.emv-chip {
  flex-shrink: 0;
  width: 64px;
  height: 32px;
  border-radius: 6px;
  position: relative;
  overflow: hidden;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.35);
}
.emv-chip img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- Card back: details + actual scannable QR side by side ---- */
.asset-card-back-body { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; flex: 1; }
.asset-card-back-rows { display: flex; flex-direction: column; gap: 10px; flex: 1; min-width: 0; }
.asset-card-back-qr { flex-shrink: 0; width: 74px; height: 74px; background: #fff; border-radius: 8px; padding: 4px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); cursor: zoom-in; }
.asset-card-back-qr svg { width: 100%; height: 100%; display: block; }

/* ---- Hover-to-enlarge QR overlay (see showQrZoom/hideQrZoom in
   app.js) — appended straight to <body> so it escapes the flip-card's
   own transform/overflow-hidden clipping instead of being scaled
   in-place. ---- */
.qr-zoom-overlay {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  pointer-events: none;
  animation: qrZoomFadeIn 0.12s ease forwards;
}
@keyframes qrZoomFadeIn { from { opacity: 0; } to { opacity: 1; } }
.qr-zoom-box {
  background: #fff;
  border-radius: 16px;
  padding: 20px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.qr-zoom-box svg { width: 280px; height: 280px; display: block; }
.qr-zoom-address { font-size: 12px; color: #1a1a1a; max-width: 280px; text-align: center; word-break: break-all; }

/* ---- Saved card picker (Present page, citizen's own phone) ---- */
.saved-card-list { display: flex; flex-direction: column; gap: 2px; }
.saved-card-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; cursor: pointer;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
  transition: background 0.12s ease;
}
.saved-card-row:last-child { border-bottom: none; }
.saved-card-row:hover, .saved-card-row:active { background: rgba(255, 255, 255, 0.025); }
.saved-card-thumb { width: 44px; height: 44px; border-radius: 10px; object-fit: cover; border: 1px solid var(--border); flex-shrink: 0; }
.saved-card-thumb-empty { background: var(--surface3); }
.saved-card-row-info { flex: 1; min-width: 0; }
.saved-card-row-name { font-size: 14px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.saved-card-row-sub { font-size: 11.5px; color: var(--text3); margin-top: 2px; }
.saved-card-row-go { font-size: 12px; font-weight: 700; color: var(--orange2); flex-shrink: 0; }
.saved-card-row-click { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; cursor: pointer; }
.saved-card-row-remove {
  background: transparent; border: none; color: var(--text3);
  font-size: 20px; line-height: 1; padding: 4px 10px; cursor: pointer;
  border-radius: 6px; flex-shrink: 0;
}
.saved-card-row-remove:hover { color: var(--red); background: rgba(248, 113, 113, 0.1); }

/* ---- Mini wallet card previews (Wallet page's "Your Saved Wallets") ---- */
.mini-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px;
  padding: 16px 20px;
}
.mini-wallet-card {
  position: relative;
  border-radius: 12px;
  padding: 14px;
  cursor: pointer;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
  transition: transform 0.12s ease;
}
.mini-wallet-card:active { transform: scale(0.97); }
.mini-wallet-card-top { display: flex; align-items: center; gap: 6px; font-size: 10px; font-weight: 800; letter-spacing: 0.5px; opacity: 0.9; }
.mini-wallet-card-balance { font-size: 22px; font-weight: 800; margin: 14px 0 4px; letter-spacing: -0.3px; }
.mini-wallet-card-name { font-size: 11.5px; font-weight: 700; opacity: 0.85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mini-wallet-card-remove { position: absolute; top: 6px; right: 6px; }

/* ---- Personal Dashboard (logged-in gateway visitor) ---- */
.gwd-grid { display: flex; flex-wrap: wrap; gap: 24px; margin-bottom: 20px; align-items: flex-start; }
.gwd-card-col { width: 340px; flex-shrink: 0; }
.gwd-mini-card { cursor: pointer; width: 100%; }
.gwd-side-col { flex: 1; min-width: 260px; display: flex; flex-direction: column; gap: 14px; }
.gwd-stats-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.gwd-stat {
  background: var(--card-grad);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
}
.gwd-stat-label { font-size: 10px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text3); margin-bottom: 4px; }
.gwd-stat-value { font-size: 18px; font-weight: 800; color: var(--text); }
.gwd-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.gwd-action-btn { justify-content: center; }
@media (max-width: 700px) { .gwd-card-col { width: 100%; } }
.smart-card-photo {
  width: 62px; height: 62px; border-radius: 10px; object-fit: cover;
  border: 1.5px solid rgba(255, 255, 255, 0.45);
  flex-shrink: 0;
}
.smart-card-photo-empty {
  width: 62px; height: 62px; border-radius: 10px;
  border: 1.5px dashed rgba(255, 255, 255, 0.4);
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; text-align: center; color: rgba(255, 255, 255, 0.7);
  flex-shrink: 0;
}
.smart-card-fields { min-width: 0; }
.smart-card-name {
  font-size: 17px; font-weight: 800; letter-spacing: 0.2px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.smart-card-row {
  display: flex; gap: 6px; font-size: 11px; margin-top: 3px;
  color: rgba(255, 255, 255, 0.85);
}
.smart-card-row span:first-child { text-transform: uppercase; opacity: 0.7; font-weight: 700; letter-spacing: 0.3px; }
.smart-card-bottom {
  display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--mono); font-size: 10.5px;
  color: rgba(255, 255, 255, 0.75);
  letter-spacing: 0.5px;
}

/* ---- Document scanner (ID/passport) + face verification ---- */
.doc-scan-preview { display: flex; gap: 18px; padding: 20px; flex-wrap: wrap; align-items: flex-start; }
.doc-scan-preview img, .doc-scan-preview canvas { max-width: 260px; border-radius: 10px; border: 1px solid var(--border); }
.doc-scan-status { flex: 1; min-width: 220px; font-size: 13px; color: var(--text2); }
.mrz-box { font-family: var(--mono); font-size: 11.5px; background: rgba(0, 0, 0, 0.25); border-radius: 8px; padding: 10px 12px; margin-top: 8px; color: var(--text2); white-space: pre-wrap; word-break: break-all; }

.face-verify-panel { margin-top: 16px; padding: 18px; border-radius: 12px; border: 1px solid var(--border); background: rgba(0, 0, 0, 0.15); }
.face-verify-head { font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 10px; }
.face-compare-row { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.face-compare-img { width: 92px; height: 92px; object-fit: cover; border-radius: 10px; border: 1px solid var(--border); }
.face-compare-vs { color: var(--text3); font-size: 12px; font-weight: 700; }

/* ---- Genesis Wallet panel (Wallet page, genesis node only) ---- */
.genesis-wallet-panel { margin-bottom: 20px; }
.genesis-wallet-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-top: 12px; }
.genesis-wallet-addr { font-size: 12px; color: var(--text3); }
.genesis-wallet-balance { font-size: 22px; font-weight: 800; margin-top: 2px; }
.loading-inline { font-size: 13px; color: var(--text3); margin-top: 10px; }

/* ---- Wallet page (genesis node only — the one UI this whole cluster
   still has; see handleWebUIRoot). Three stacked sections: a stat-card
   summary, the Genesis/Spending hero panel, and the other-validators
   table. These fill the same width `main` already gives every other
   dashboard page (no artificial 900px island centered in a much wider
   viewport) — the two cards and their Sweep button stay pinned to a
   fixed-width block on the left of the hero panel via .gw-showcase's own
   justify-content, so extra viewport width just becomes breathing room
   instead of the cards stretching or drifting to page-center. ---- */
.gw-stat-cards { margin: 8px 0 0; }
.gw-hero-panel, .gw-other-validators-panel { margin: 24px 0 0; }

.gw-showcase { display: flex; align-items: flex-start; justify-content: flex-start; gap: 28px; flex-wrap: wrap; padding: 18px 24px 6px; }
/* 350px = same sized-up card width as .digital-card-page above — no
   side padding on this column, so no compensation needed here. Both
   Genesis (bronze) and Spending (platinum) cards share this one
   container class, so they're always exactly the same size as each
   other by construction. */
.gw-showcase-col { width: 350px; max-width: 100%; }
.gw-showcase-col .gw-showcase-flip { position: relative; }
.gw-showcase-label { text-align: center; font-size: 12px; font-weight: 700; letter-spacing: 0.4px; color: var(--text3); text-transform: uppercase; margin-top: 14px; }
/* Log In & Send under the Spending Wallet card — links to the same
   private-key Send/Activity page (#/wallet-card/:address) any other
   wallet uses, since the genesis server itself never holds this
   wallet's key (see renderWalletCardPage). */
.gw-showcase-login-row { text-align: center; margin-top: 10px; }

/* ---- Other Validators — Collect Rewards (genesis-only). Collect All
   sits inside the panel's own h2 (which is already a flex row with
   info-icon-wrap's margin-left:auto pushing trailing content right) —
   not a separate header row, so it inherits the same bordered header-
   bar treatment every other panel in this dashboard uses. ---- */
/* Header row: title+height-badge stack on the left, Collect All on the
   right — split into its own flex row (rather than cramming the badge
   into the h2) so the badge can wrap onto its own line under the title
   on narrow widths without fighting the button for space. */
.gw-oval-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 16px 16px 14px; border-bottom: 1px solid var(--border); }
.gw-oval-header-title { display: flex; flex-direction: column; gap: 8px; }
.gw-oval-header-title h2 { border: none; padding: 0; margin: 0; }
.gw-oval-height-badge {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--text2); background: var(--surface2);
  border: 1px solid var(--border); border-radius: 8px; padding: 6px 12px; width: fit-content;
}
.gw-oval-height-badge strong { color: var(--text); font-weight: 700; }
.gw-oval-sync-note { color: var(--text3); padding-left: 8px; border-left: 1px solid var(--border); }
.gw-oval-height-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.gw-oval-height-dot.ok { background: var(--green); box-shadow: 0 0 6px var(--green); }
.gw-oval-height-dot.warn { background: var(--orange2); box-shadow: 0 0 6px var(--orange2); }
.gw-oval-height-dot.err { background: var(--red, #ef4444); }

.gw-validator-table { padding: 0 16px 14px; }
.gw-validator-table-head, .gw-validator-row {
  display: grid; grid-template-columns: 1fr 130px 140px 160px; align-items: center; gap: 14px;
}
.gw-validator-table-head {
  padding: 12px 4px 8px; border-bottom: 1px solid var(--border);
  font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text3);
}
.gw-validator-row { padding: 13px 4px; border-bottom: 1px solid var(--border); transition: background 0.15s; }
.gw-validator-row:hover { background: var(--surface2); }
.gw-validator-row:last-child { border-bottom: none; }
.gw-validator-row-addr { font-size: 13px; color: var(--text2); }
.gw-validator-row-bal { font-size: 13px; font-weight: 700; color: var(--text); }
.gw-validator-row-action { display: flex; align-items: center; justify-content: flex-end; gap: 10px; }
.gw-validator-row-status { font-size: 12.5px; }
.btn-sm { padding: 6px 14px; font-size: 12.5px; }

/* Compact single-line result pill for a row action (Collect, Sweep,
   Confirm Delete, etc.) — NOT .notice, which is a block-level page
   banner (padding/margins sized for full-width text) and visibly
   overflows/wraps when crammed into a narrow table cell. This stays on
   one line and never grows the row's height. */
.gw-row-toast {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  padding: 4px 10px; border-radius: 100px; font-size: 12px; font-weight: 600;
}
.gw-row-toast.ok { background: var(--green-dim); color: var(--green); }
.gw-row-toast.err { background: var(--red-dim); color: var(--red); white-space: normal; max-width: 220px; text-align: right; }

.gw-oval-height-cell { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-variant-numeric: tabular-nums; }
.gw-oval-height-cell.synced { color: var(--text); font-weight: 700; }
.gw-oval-height-cell.behind { color: var(--orange2); font-weight: 700; }
.gw-oval-height-cell.unknown { color: var(--text3); font-style: italic; }

/* ---- Wallets directory (genesis-only; see renderAllWalletsPage) ---- */
.gw-wallets-panel { margin: 24px 0 0; }
.gw-wallets-table { padding: 0 16px 14px; }
.gw-wallets-table-head, .gw-wallets-row {
  display: grid; grid-template-columns: 1fr 180px 120px 150px 140px; align-items: center; gap: 14px;
}
.gw-wallets-table-head {
  padding: 12px 4px 8px; border-bottom: 1px solid var(--border);
  font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text3);
}
.gw-wallets-row {
  padding: 13px 4px; border-bottom: 1px solid var(--border);
  transition: background 0.12s ease;
}
.gw-wallets-row > span[onclick] { cursor: pointer; }
.gw-wallets-row:hover { background: var(--surface2); }
.gw-wallets-row:last-child { border-bottom: none; }
.gw-wallets-row-encrypted { color: var(--text3); font-style: italic; }
.gw-wallets-row .mono { font-size: 13px; color: var(--text2); }
.gw-wallets-row-bal { font-size: 13px; font-weight: 700; color: var(--text); text-align: right; }
.gw-wallets-row-pending { background: rgba(248, 113, 113, 0.05); }
.gw-wallets-row-action { display: flex; align-items: center; gap: 10px; }

/* ---- Status pills (Active / Deletion requested) & danger button, same
   visual language as the mobile app's pill-on/pill-off toggles ---- */
.pill { display: inline-block; padding: 3px 10px; border-radius: 100px; font-size: 11px; font-weight: 700; letter-spacing: 0.3px; }
.pill-off { background: var(--surface3); color: var(--text3); }
.pill-danger { background: var(--red-dim); color: var(--red); }
.btn.danger {
  border-color: var(--red);
  background: linear-gradient(180deg, var(--red) 0%, #dc2626 100%);
  color: #fff;
}
.btn.danger:hover { filter: brightness(1.08); box-shadow: 0 2px 8px rgba(248, 113, 113, 0.35); }

.gw-sweep-col { display: flex; flex-direction: column; align-items: center; gap: 8px; padding-top: 90px; flex-shrink: 0; }
.gw-sweep-btn {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 16px 22px; border-radius: 16px; border: none; cursor: pointer;
  background: linear-gradient(180deg, #fb923c, #f97316); color: #1a0d02; font-weight: 800; font-size: 13px;
  box-shadow: 0 8px 20px rgba(249, 115, 22, 0.35); transition: transform 0.12s ease;
}
.gw-sweep-btn:active { transform: scale(0.96); }
.gw-sweep-btn:disabled { opacity: 0.6; cursor: default; }
.gw-sweep-status { max-width: 180px; text-align: center; font-size: 12px; }
.gw-sweep-status .notice { margin: 0; }
.gw-sweep-confirmed { animation: gwSweepPop 0.4s ease; }
@keyframes gwSweepPop { 0% { transform: scale(0.85); opacity: 0; } 60% { transform: scale(1.08); opacity: 1; } 100% { transform: scale(1); } }

/* Coin-fly track: an arrow with a coin icon that travels left-to-right
   in a loop while a sweep is in flight, giving a visible "money is
   moving" cue instead of just a static spinner. */
.gw-sweep-track { position: relative; width: 64px; height: 24px; display: flex; align-items: center; justify-content: center; }
.gw-sweep-arrow { position: absolute; font-size: 22px; line-height: 1; color: var(--text3); }
.gw-sweep-coin { position: absolute; left: 0; opacity: 0; display: flex; }
.gw-sweep-coin img, .gw-sweep-coin svg { width: 18px; height: 18px; }
.gw-sweep-flying .gw-sweep-coin { animation: gwSweepCoinFly 1.1s ease-in-out infinite; }
.gw-sweep-flying .gw-sweep-arrow { animation: gwSweepArrowPulse 1.1s ease-in-out infinite; }
@keyframes gwSweepCoinFly {
  0% { left: 0; opacity: 0; }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { left: 46px; opacity: 0; }
}
@keyframes gwSweepArrowPulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }

@media (max-width: 760px) {
  .gw-showcase { flex-direction: column; align-items: center; }
  .gw-sweep-col { padding-top: 0; flex-direction: row; }
}

.hidden { display: none !important; }
.gw-auth-toggle-row { display: flex; justify-content: center; margin: 4px 0 20px; }
#gw-auth-body { max-width: 700px; margin: 0 auto; }

.hb-content-row {
  display: flex;
  align-items: stretch;
  gap: 16px;
}
.hb-activity-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.hb-activity-col .hb-table,
.hb-activity-col .hb-formula {
  margin-bottom: 0;
}
.hb-activity-col .hb-formula {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.retarget-grid-inline {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 100%;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.015);
  padding: 14px;
}
.retarget-grid {
  display: grid;
  grid-template-columns: repeat(5, 50px);
  grid-template-rows: repeat(4, 50px);
  gap: 8px;
}
.retarget-square {
  width: 50px;
  height: 50px;
  border-radius: 10px;
  background: rgba(34, 249, 34, .18);
  border: 1px solid rgba(34, 249, 34, .35);
  transition: background .3s ease, border-color .3s ease;
  position: relative;
}
.retarget-square.filled {
  background: #22f922;
  border-color: #22f922;
  box-shadow: 0 0 6px rgba(34, 249, 34, .55);
}
.retarget-square.next-up {
  border-color: rgba(148, 163, 184, .4);
  background: rgba(148, 163, 184, .08);
}
.retarget-dashed-circle {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.retarget-clock-dot {
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(148, 163, 184, .35);
  transform: translate(-50%, -50%);
  transition: background .2s ease, box-shadow .2s ease;
}
.retarget-clock-dot.lit {
  background: #22f922;
  box-shadow: 0 0 4px rgba(34, 249, 34, .8);
}
.retarget-countup {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: rgba(148, 163, 184, .95);
  position: relative;
  z-index: 1;
}
.retarget-square-final {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: #08330a;
}
.retarget-grid-note {
  font-size: 9px;
  color: var(--text3);
  letter-spacing: .3px;
  white-space: nowrap;
  text-align: center;
  flex: 0 0 auto;
}
@keyframes retarget-mine {
  0%   { background: rgba(34, 249, 34, .18); border-color: rgba(34, 249, 34, .35); transform: scale(1); box-shadow: 0 0 0 0 rgba(34, 249, 34, .6); }
  50%  { transform: scale(1.3); box-shadow: 0 0 0 6px rgba(34, 249, 34, 0); }
  100% { background: #22f922; border-color: #22f922; transform: scale(1); box-shadow: 0 0 6px rgba(34, 249, 34, .55); }
}
.retarget-square-new {
  animation: retarget-mine .6s ease-out forwards;
}
@media (max-width: 760px) {
  .hb-content-row { flex-direction: column; }
  .retarget-grid-inline { align-self: stretch; height: auto; }
}

/* ---- Nodes page (ported from the explorer service's own node-card
   grid — internal/rpc/webui-network/style.css) ---- */
.node-card-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 16px; }
.node-card { border: 1px solid var(--border); border-radius: 14px; padding: 14px; background: linear-gradient(180deg, rgba(255,255,255,.018), rgba(255,255,255,.008)); }
.node-card-down { border-color: rgba(248,113,113,.28); }
.node-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.node-card-title { color: var(--text); font-size: 15px; font-weight: 800; }
.node-card-sub { color: var(--text3); font-size: 12px; margin-top: 4px; }
.node-chip-row { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.node-metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 12px; }
.node-metrics span, .node-endpoints span { display: block; color: var(--text3); font-size: 10px; text-transform: uppercase; letter-spacing: .5px; margin-bottom: 4px; }
.node-metrics b { color: var(--text); font-family: var(--mono); font-size: 14px; }
.node-endpoints { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px 14px; }
.node-endpoints code { color: var(--text); font-family: var(--mono); font-size: 12px; word-break: break-all; }
.node-status-up { color: var(--green); }
.node-status-down { color: var(--red); }
