/* PulseChain Explorer — Main Stylesheet */

/* ===== CSS Variables / Theming =====
 * Design-system tokens (I1495, 2026-04-21) — see
 * docs/research/frontend-design-audit.md for the full rationale.
 *
 * Token groups:
 *   - Surfaces / lines / text / brand / status / links — shipped pre-I1495
 *   - Shadows: --shadow-sm/-/-lg/-xl/-dropdown (I1495: +sm, +xl, +dropdown)
 *   - Radii: --radius-sm/-/lg/-pill (I1495: +pill)
 *   - Spacing: --space-1 through --space-16 on a 4px grid (I1495: NEW)
 *   - Type: --fs-xs through --fs-3xl, 9-step scale (I1495: NEW)
 *   - State backgrounds: --success-bg, --error-bg, --warning-bg, --info-bg
 *     (I1495: NEW — previously inlined as rgba(…) literals in tables.css)
 */
:root,
[data-theme="light"] {
  --bg-primary: #f8fafc;
  --bg-secondary: #ffffff;
  --bg-card: #ffffff;
  --bg-card-hover: #f1f5f9;
  --bg-input: #f1f5f9;
  --border-color: #e2e8f0;
  --border-subtle: #f1f5f9;
  --text-primary: #1e293b;
  --text-secondary: #475569;
  --text-muted: #94a3b8;
  --accent: #3b82f6;
  --accent-hover: #2563eb;
  --accent-bg: rgba(59, 130, 246, 0.08);
  --accent-border: rgba(59, 130, 246, 0.2);
  --success: #16a34a;
  --error: #dc2626;
  --warning: #d97706;
  --info: #3b82f6;
  --link: #3b82f6;
  --link-hover: #2563eb;
  --badge-contract: #7c3aed;
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.05);
  --shadow: 0 2px 8px rgba(0,0,0,0.08);
  --shadow-lg: 0 8px 24px rgba(0,0,0,0.12);
  --shadow-xl: 0 8px 32px rgba(0,0,0,0.18);
  --shadow-dropdown: 0 4px 12px rgba(0,0,0,0.15);
  --bg-elevated: #f1f5f9;
  --radius: 8px;
  --radius-sm: 4px;
  --radius-lg: 12px;
  --radius-pill: 999px;
  /* Spacing scale — 4px grid, 9 tokens */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;
  /* Type scale — 9 tokens, rem-based so iOS text-size-adjust honors it */
  --fs-xs: 0.7rem;
  --fs-sm: 0.75rem;
  --fs-base-sm: 0.8rem;
  --fs-body-sm: 0.85rem;
  --fs-body: 0.9rem;
  --fs-md: 1rem;
  --fs-lg: 1.1rem;
  --fs-xl: 1.25rem;
  --fs-2xl: 1.5rem;
  --fs-3xl: 2rem;
  /* Semantic state backgrounds — replace inline rgba(…) in tables.css + elsewhere */
  --success-bg: rgba(22, 163, 74, 0.08);
  --error-bg: rgba(220, 38, 38, 0.08);
  --warning-bg: rgba(217, 119, 6, 0.08);
  --info-bg: rgba(37, 99, 235, 0.08);
  /* I1814 slice 3: state-color borders — used by .badge-* + future status pills */
  --success-border: rgba(22, 163, 74, 0.25);
  --error-border: rgba(220, 38, 38, 0.25);
  --warning-border: rgba(217, 119, 6, 0.25);
  --info-border: rgba(37, 99, 235, 0.25);
  --neutral-bg: rgba(100, 116, 139, 0.08);
  --neutral-border: rgba(100, 116, 139, 0.22);
  --badge-contract-bg: rgba(124, 58, 237, 0.10);
  --badge-contract-border: rgba(124, 58, 237, 0.25);
  --header-height: 56px;
  --nav-height: 40px;
  --font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

[data-theme="dark"] {
  --bg-primary: #0a0e17;
  --bg-secondary: #111827;
  --bg-card: #1a2035;
  --bg-card-hover: #1f2847;
  --bg-input: #151c2e;
  --border-color: #2a3456;
  --border-subtle: #1e2744;
  --text-primary: #e2e8f0;
  --text-secondary: #94a3b8;
  --text-muted: #64748b;
  --accent: #00D4AA;
  --accent-hover: #00eabc;
  --accent-bg: rgba(0, 212, 170, 0.1);
  --accent-border: rgba(0, 212, 170, 0.25);
  --success: #22c55e;
  --error: #ef4444;
  --warning: #f59e0b;
  --info: #3b82f6;
  --link: #60a5fa;
  --link-hover: #93bbfd;
  --badge-contract: #8b5cf6;
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.2);
  --shadow: 0 2px 8px rgba(0,0,0,0.3);
  --shadow-lg: 0 8px 24px rgba(0,0,0,0.4);
  --shadow-xl: 0 8px 32px rgba(0,0,0,0.5);
  --shadow-dropdown: 0 4px 12px rgba(0,0,0,0.4);
  --bg-elevated: #1e2744;
  /* Dark-theme state backgrounds — higher alpha to stay visible on dark surfaces */
  --success-bg: rgba(34, 197, 94, 0.15);
  --error-bg: rgba(239, 68, 68, 0.15);
  --warning-bg: rgba(245, 158, 11, 0.15);
  --info-bg: rgba(59, 130, 246, 0.15);
  /* I1814 slice 3: dark-theme state-color borders */
  --success-border: rgba(34, 197, 94, 0.30);
  --error-border: rgba(239, 68, 68, 0.30);
  --warning-border: rgba(245, 158, 11, 0.30);
  --info-border: rgba(59, 130, 246, 0.30);
  --neutral-bg: rgba(156, 163, 175, 0.12);
  --neutral-border: rgba(156, 163, 175, 0.28);
  --badge-contract-bg: rgba(139, 92, 246, 0.15);
  --badge-contract-border: rgba(139, 92, 246, 0.30);
}

/* ===== Reset ===== */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 14px;
  scroll-behavior: smooth;
  /* I1485: prevent iOS/Android from bumping body text on rotation */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: var(--font-sans);
  background: var(--bg-primary);
  color: var(--text-primary);
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* I1485: clip (not hidden) horizontal overflow. `clip` doesn't create a
     new scroll container the way `hidden` does, so position:sticky on the
     header still works correctly. Fallback to `hidden` on older browsers
     — still better than wide content pushing the page wider than viewport
     on mobile. */
  overflow-x: hidden;
  overflow-x: clip;
}

a {
  color: var(--link);
  text-decoration: none;
  transition: color 0.15s;
}

.text-muted { color: var(--text-muted); }

/* I1814: Layout utilities — replace inline style="text-align:..." across pages */
.text-right { text-align: right; }
.text-center { text-align: center; }
.text-left { text-align: left; }

/* I1814 slice 4: Spacing utilities — replace inline style="margin-bottom:Npx",
 * style="margin-top:Npx", style="padding:Npx" across pages. Values mirror
 * --space-1..--space-6 (4/8/12/16/20/24px) on the existing 4px grid. */
.mb-1 { margin-bottom: var(--space-1); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-5 { margin-bottom: var(--space-5); }
.mb-6 { margin-bottom: var(--space-6); }
.mt-1 { margin-top: var(--space-1); }
.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mt-5 { margin-top: var(--space-5); }
.mt-6 { margin-top: var(--space-6); }
.p-1 { padding: var(--space-1); }
.p-2 { padding: var(--space-2); }
.p-3 { padding: var(--space-3); }
.p-4 { padding: var(--space-4); }
.p-5 { padding: var(--space-5); }
.p-6 { padding: var(--space-6); }

a:hover {
  color: var(--link-hover);
  text-decoration: underline;
}

img { max-width: 100%; }

/* ===== Header ===== */
header {
  background: #111827; /* Deep blue/slate */
  border-bottom: none;
  position: sticky;
  top: 0;
  z-index: 100;
  color: #f8fafc;
}

.header-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 20px;
  height: var(--header-height);
  display: flex;
  align-items: center;
  gap: 20px;
}

.logo {
  font-size: 1.25rem;
  font-weight: 700;
  color: #ffffff !important;
  text-decoration: none !important;
  white-space: nowrap;
  letter-spacing: -0.02em;
}

/* I1797: Hamburger toggle — hidden on desktop, shown via mobile @media below.
   The drawer close (X) button is also styled here so it inherits the same
   hit-target sizing. Both buttons live in the header markup. */
.nav-toggle,
.nav-close {
  display: none;
  background: transparent;
  border: 1px solid #334155;
  color: #ffffff;
  border-radius: var(--radius-sm);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
}

.nav-toggle:hover,
.nav-close:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Backdrop behind the open drawer — clicking it closes the drawer (JS). */
.nav-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 9998;
}
body.nav-locked .nav-backdrop { display: block; }
body.nav-locked { overflow: hidden; }

.search-bar {
  flex: 1;
  max-width: 600px;
  display: flex;
  gap: 0;
  position: relative;
}

/* Hide header search on landing page — hero search is the primary search there */
body.home .header-inner .search-bar {
  display: none;
}

.search-bar input {
  flex: 1;
  padding: 8px 14px;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-right: none;
  border-radius: var(--radius) 0 0 var(--radius);
  color: var(--text-primary);
  font-size: 0.9rem;
  outline: none;
  transition: border-color 0.15s;
}

.search-bar input:focus {
  border-color: var(--accent);
}

.search-bar input::placeholder {
  color: var(--text-muted);
}

.search-bar button {
  padding: 8px 16px;
  background: var(--accent);
  color: #ffffff;
  border: 1px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s;
}

.search-bar button:hover {
  background: var(--accent-hover);
}

.header-right {
  display: flex;
  align-items: center;
  gap: 12px;
  white-space: nowrap;
  font-size: 0.85rem;
  margin-left: auto;
}

.network-badge {
  background: var(--accent-bg);
  color: var(--accent);
  border: 1px solid var(--accent-border);
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-weight: 600;
  font-size: 0.8rem;
  text-decoration: none;
  display: inline-block;
}

.network-badge.testnet {
  background: #fff3e0;
  color: #e65100;
  border-color: #ffb74d;
}

.network-toggle {
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  font-weight: 600;
  font-size: 0.75rem;
  text-decoration: none;
  display: inline-block;
  transition: background 0.2s, color 0.2s;
}

.network-toggle:hover {
  background: var(--accent);
  color: var(--bg);
}

.footer-network-info .network-toggle {
  display: inline-block;
  margin-top: 6px;
}

.network-footer {
  color: var(--text-secondary);
  font-size: 0.85rem;
  margin-bottom: 4px;
}

.network-footer a {
  color: var(--accent);
  text-decoration: underline;
}

.wallet-btn {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  padding: 4px 10px;
  cursor: pointer;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  transition: background 0.15s;
}
.wallet-btn:hover { background: var(--accent-hover); }
.wallet-btn.connected {
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  font-family: var(--font-mono);
  font-size: 0.75rem;
}
.wallet-add-chain {
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
}
.wallet-add-chain:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

#theme-toggle {
  background: none;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  cursor: pointer;
  font-size: 1rem;
  color: var(--text-secondary);
}

/* ===== Main Nav ===== */
.main-nav {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 20px;
  height: var(--nav-height);
  display: flex;
  align-items: center;
  gap: 4px;
  border-top: 1px solid #1f2937; /* Dark slate border */
}

.main-nav > a {
  padding: 6px 14px;
  border-radius: var(--radius-sm);
  color: #cbd5e1; /* Light gray text */
  font-weight: 500;
  font-size: 0.9rem;
  transition: all 0.15s;
  text-decoration: none;
}

.main-nav > a:hover, .main-nav > a.active {
  color: #ffffff;
  background: rgba(255, 255, 255, 0.1);
  text-decoration: none;
}

/* ===== Nav Dropdowns ===== */
.nav-dropdown {
  position: relative;
}

.nav-dropdown-trigger {
  padding: 6px 14px;
  border-radius: var(--radius-sm);
  color: #cbd5e1;
  font-weight: 500;
  font-size: 0.9rem;
  transition: all 0.15s;
  text-decoration: none !important;
  cursor: pointer;
  display: inline-block;
}

/* Split label + arrow into separate spans so Playwright can match
   the trigger label by `hasText: /^Tokens$/` etc., and so that the
   arrow is hidden from screen readers (aria-hidden in HTML). The
   span layout keeps the original visual rendering — same baseline,
   ~one-space gap — without the inline text node containing the
   arrow glyph. .nav-label inherits everything; only the arrow needs
   styling. */
.nav-dropdown-trigger .nav-arrow {
  margin-left: 0.25em;
  font-size: 0.85em;
  display: inline-block;
}

.nav-dropdown-trigger.active,
.nav-dropdown.open .nav-dropdown-trigger {
  color: var(--accent);
  background: var(--accent-bg);
}

/* I1485: hover states only on true hover-capable devices (desktop mouse).
   Touch devices report hover: none — they use click-toggle via app.js. */
@media (hover: hover) and (pointer: fine) {
  .nav-dropdown-trigger:hover,
  .nav-dropdown:hover .nav-dropdown-trigger,
  .nav-dropdown:focus-within .nav-dropdown-trigger {
    color: var(--accent);
    background: var(--accent-bg);
  }
}

.nav-dropdown-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 160px;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  z-index: 200;
  /* I609: Use padding-top instead of margin-top to avoid hover gap —
     margin creates dead zone where mouse loses hover, closing dropdown */
  padding: 6px 0 4px 0;
}

/* I1485: open state is JS-driven (toggled by click + outside-tap close).
   Desktop hover-open still works inside the media query below. */
.nav-dropdown.open .nav-dropdown-menu {
  display: block;
}

@media (hover: hover) and (pointer: fine) {
  .nav-dropdown:hover .nav-dropdown-menu,
  .nav-dropdown:focus-within .nav-dropdown-menu {
    display: block;
  }
}

.nav-dropdown-menu a {
  display: block;
  padding: 8px 16px;
  color: var(--text-secondary);
  font-size: 0.88rem;
  font-weight: 500;
  text-decoration: none;
  transition: all 0.1s;
}

.nav-dropdown-menu a:hover {
  color: var(--accent);
  background: var(--accent-bg);
  text-decoration: none;
}

.nav-dropdown-menu a.active {
  color: var(--accent);
  font-weight: 600;
}

/* I1811: visual separator inside nav dropdowns — applied to the link
   immediately following the divider line (e.g. "All Token Transfers" in
   the unified Tokens menu, separating per-standard collection links from
   the firehose feeds). */
.nav-dropdown-menu a.dropdown-divider {
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 10px;
}

/* ===== Main Container ===== */
main.container {
  max-width: 1400px;
  margin: 0 auto;
  padding: 24px 20px;
  width: 100%;
  flex: 1;
}

/* ===== Cards =====
 * Canonical "card surface" pattern (I1814 cards normalization slice):
 *   - background: var(--bg-card)
 *   - border:     1px solid var(--border-color)
 *   - border-radius: var(--radius-lg) for headline panels, var(--radius)
 *     for grid tiles, var(--radius-sm) for inline alert pills
 *   - padding: use canonical spacing tokens (--space-3..--space-6)
 *   - box-shadow: only on the top-level .card; grid tiles stay flat
 * Variants (.stat-card, .gas-card, .queue-card, .nft-card,
 * .symptom-card, .metric-card, .network-overview-card) tweak only
 * padding / radius / shadow per the role they play; the surface
 * tokens (bg, border) are always shared. */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-subtle);
}

.card-header h2 {
  font-size: 1.1rem;
  font-weight: 600;
}

.card-header a {
  font-size: 0.85rem;
  color: var(--accent);
}

/* ===== Utility Shadows ===== */
.shadow-sm { box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); }
.shadow { box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); }
.shadow-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); }
.shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
.shadow-xl { box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); }

/* ===== Stats Banner ===== */
.stats-banner {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
  margin-bottom: 8px;
}

/* I929: 6-column layout for balanced two-row stat cards */
.stats-banner.stats-row-6 {
  grid-template-columns: repeat(6, 1fr);
}

/* I1725: 3-row grid ensures label TOP / value MIDDLE / sub BOTTOM
   align consistently across a row of cards regardless of whether
   individual cards have a sub-text or how long it is. Cards missing
   a .stat-sub still reserve the same bottom-row height via a
   ::after placeholder, so 6 cards side-by-side show their values
   on a perfectly straight horizontal line.
   Replaces the previous flex+space-between approach which drifted
   when sub-text was absent or multi-line. */
.stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  padding: var(--space-4);
  text-align: center;
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 104px;
  row-gap: 6px;
}

/* Reserve the bottom row even when a card has no .stat-sub child.
   Without this an absent sub lets the value fill the remaining space
   and drift downward. */
.stat-card:not(:has(.stat-sub))::after {
  content: "";
  display: block;
  min-height: 1em;
}

.stat-card .stat-label {
  font-size: 0.8rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  align-self: start;
}

.stat-card .stat-value {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--text-primary);
  align-self: center;
}

.stat-card .stat-sub {
  font-size: 0.8rem;
  color: var(--text-secondary);
  align-self: end;
  min-height: 1em;
}

/* I1505: Counter-strip tiles — clickable stat cards that link to tabs.
   Override anchor default colors/underline so the tile looks identical
   to a non-link .stat-card; add hover affordance + keyboard focus ring. */
.stats-banner.counter-strip .counter-tile {
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  display: block;
  transition: transform 0.08s ease, border-color 0.08s ease;
}

.stats-banner.counter-strip .counter-tile:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}

.stats-banner.counter-strip .counter-tile:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.stats-banner.counter-strip .counter-slash {
  color: var(--text-muted);
  margin: 0 4px;
  font-weight: 500;
}

/* ===== Hero Search ===== */
.hero-wrapper {
  background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 100%);
  padding: 56px 20px 80px;
  text-align: center;
  color: #ffffff;
  margin-bottom: -50px;
}

.hero-wrapper h1 {
  font-size: 2.5rem;
  font-weight: 700;
  margin-bottom: 12px;
}

.hero-wrapper p {
  color: #94a3b8;
  font-size: 1.1rem;
  margin-bottom: 32px;
}

.hero-wrapper .search-bar {
  max-width: 800px;
  margin: 0 auto;
  box-shadow: 0 4px 20px rgba(0,0,0,0.4);
  border-radius: var(--radius);
}

.hero-wrapper .search-bar input {
  padding: 16px 24px;
  font-size: 1.15rem;
  background: #ffffff;
  color: #1e293b;
  border: none;
}

.hero-wrapper .search-bar button {
  padding: 16px 32px;
  font-size: 1.15rem;
  background: var(--accent);
  color: #ffffff;
  border: none;
  font-weight: 600;
  cursor: pointer;
}


/* ===== Page Header ===== */
.page-header {
  margin-bottom: 20px;
}

.page-header h1 {
  font-size: 1.5rem;
  font-weight: 700;
  margin-bottom: 4px;
}

.page-header .subtitle {
  color: var(--text-secondary);
  font-size: 0.9rem;
}

/* ===== Overview Section ===== */
.overview-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.overview-row {
  display: flex;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border-subtle);
  gap: 16px;
}

.overview-row:last-child {
  border-bottom: none;
}

.overview-label {
  width: 200px;
  min-width: 200px;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.overview-value {
  flex: 1;
  word-break: break-all;
  font-size: 0.9rem;
}

.overview-divider {
  border: none;
  border-top: 2px solid var(--border-color);
  margin: 0;
}

/* ===== Badges ===== */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

/* I1814 slice 3: badge color tokens — replace per-rule rgba literals.
   Base .badge defines layout (display, padding, radius, font-size, weight);
   color variants below set only background / color / border via tokens, so
   they adapt to light + dark themes consistently. */
.badge-success {
  background: var(--success-bg);
  color: var(--success);
  border: 1px solid var(--success-border);
}

.badge-error {
  background: var(--error-bg);
  color: var(--error);
  border: 1px solid var(--error-border);
}

.badge-warning {
  background: var(--warning-bg);
  color: var(--warning);
  border: 1px solid var(--warning-border);
}

.badge-info {
  background: var(--info-bg);
  color: var(--info);
  border: 1px solid var(--info-border);
}

/* I596: Missing badge classes used by validator pages */
.badge-neutral {
  background: var(--neutral-bg);
  color: var(--text-muted);
  border: 1px solid var(--neutral-border);
}
.badge-danger {
  background: var(--error-bg);
  color: var(--error);
  border: 1px solid var(--error-border);
}

.badge-contract {
  background: var(--badge-contract-bg);
  color: var(--badge-contract);
  border: 1px solid var(--badge-contract-border);
}

/* I1814 slice 3: tighter-padding state-colored variants used in tx flow tables */
.badge-in {
  background: var(--success-bg);
  color: var(--success);
  border: 1px solid var(--success-border);
  font-size: 0.7rem;
  padding: 1px 6px;
}

.badge-out {
  background: var(--warning-bg);
  color: var(--warning);
  border: 1px solid var(--warning-border);
  font-size: 0.7rem;
  padding: 1px 6px;
}

.badge-self {
  background: var(--info-bg);
  color: var(--info);
  border: 1px solid var(--info-border);
  font-size: 0.7rem;
  padding: 1px 6px;
}

.badge-method {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  color: var(--text-secondary);
  font-size: 0.72rem;
  padding: 2px 6px;
  border-radius: 3px;
  font-family: var(--font-mono);
  max-width: 100px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* I1101: Genesis allocation and fork credit badges
   I1814 slice 3: migrated to state-color tokens (was rgba literals) */
.badge-genesis {
  background: var(--success-bg);
  color: var(--success);
  border: 1px solid var(--success-border);
  font-size: 0.7rem;
  padding: 1px 6px;
  font-weight: 600;
}

.badge-credit {
  background: var(--info-bg);
  color: var(--info);
  border: 1px solid var(--info-border);
  font-size: 0.7rem;
  padding: 1px 6px;
  font-weight: 600;
}

/* ===== Tabs ===== */
.tabs {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--border-color);
  margin-bottom: 16px;
  overflow-x: auto;
  overflow-y: hidden;
}

.tab-btn {
  padding: 10px 20px;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  color: var(--text-secondary);
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s;
}

.tab-btn:hover {
  color: var(--text-primary);
}

.tab-btn.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.tab-btn .tab-count {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin-left: 4px;
}

.tab-content {
  display: none;
}

.tab-content.active {
  display: block;
}

/* ===== Gas Bar ===== */
.gas-bar {
  display: flex;
  align-items: center;
  gap: 8px;
}

.gas-bar-track {
  flex: 1;
  height: 6px;
  background: var(--bg-input);
  border-radius: 3px;
  overflow: hidden;
  max-width: 80px;
}

.gas-bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width 0.3s;
}

.gas-bar-text {
  font-size: 0.8rem;
  color: var(--text-secondary);
  min-width: 35px;
}

/* ===== Copy Button ===== */
.copy-btn {
  background: none;
  border: 1px solid var(--border-color);
  color: var(--text-muted);
  padding: 2px 6px;
  border-radius: 3px;
  cursor: pointer;
  font-size: 0.75rem;
  margin-left: 6px;
  transition: all 0.15s;
}

.copy-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.copy-btn.copied {
  color: var(--success);
  border-color: var(--success);
}

/* ===== Block Navigation ===== */
.block-nav {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.block-nav a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: 0.85rem;
  text-decoration: none;
}

.block-nav a:hover {
  border-color: var(--accent);
  color: var(--accent);
  text-decoration: none;
}

/* ===== Loading States ===== */
.loading-spinner {
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 2px solid var(--border-color);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.skeleton {
  background: linear-gradient(90deg, var(--bg-input) 25%, var(--bg-card-hover) 50%, var(--bg-input) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: var(--radius-sm);
}

@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

.skeleton-text { height: 14px; margin: 4px 0; }
.skeleton-row { height: 44px; margin: 2px 0; }

.loading-overlay {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  color: var(--text-muted);
  gap: 12px;
}

.loading-overlay .loading-spinner {
  width: 32px;
  height: 32px;
}

/* ===== Error State ===== */
.error-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--error);
}

.error-state .error-icon { font-size: 2rem; margin-bottom: 8px; }
.error-state .error-msg { color: var(--text-secondary); margin-top: 8px; }

/* ===== Empty State ===== */
.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-muted);
}

/* I1537: Widget empty-state with primary message + context line.
 * Used by home page + charts/tables that can be genuinely empty during
 * early sync. Titles are concise; the `.empty-context` line explains
 * why (e.g. "Chain will show data once indexer catches up"). */
.empty-state .empty-title {
  display: block;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 4px;
}
.empty-state .empty-context {
  display: block;
  font-size: 0.8rem;
  color: var(--text-muted);
  max-width: 320px;
  margin: 0 auto;
  line-height: 1.4;
}

/* Compact variant for mini-chart containers + small widget panels */
.empty-state.empty-compact {
  padding: 24px 16px;
}

/* I1814: Table-row variant — applied directly to a <td> spanning all
 * columns inside a single-row tbody placeholder. Used for "Loading...",
 * "No data on this page.", and inline error messages. Replaces 15
 * inline style="text-align:center;padding:32px;color:var(--text-muted)"
 * occurrences across nft-mints / nft-transfers / tokentxns pages. */
.empty-state.empty-table-row {
  padding: 32px;
}

/* Stat-tile dimming when the underlying value is zero / unknown */
.stat-value.stat-empty {
  color: var(--text-muted);
  font-weight: 500;
}

/* Motion-safety: disable spinner + slot pulse for users who opt out */
@media (prefers-reduced-motion: reduce) {
  .loading-spinner {
    animation: none;
    border-top-color: var(--accent);
  }
  .slot-box.current {
    animation: none;
  }
  .skeleton {
    animation: none;
  }
}

/* ===== Two Column Layout ===== */
.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
.two-col > * {
  min-width: 0;
  overflow: hidden;
}

/* ===== Footer ===== */
footer {
  background: #1a1f2e;
  color: #94a3b8;
  margin-top: auto;
}

[data-theme="dark"] footer {
  background: #0d1017;
}

.footer-top {
  max-width: 1400px;
  margin: 0 auto;
  padding: 40px 24px 28px;
  display: grid;
  grid-template-columns: 1.8fr 1fr 1fr 1fr;
  gap: 32px;
  font-size: 0.85rem;
}

.footer-col h4 {
  color: #e2e8f0;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 14px;
}

.footer-col a {
  display: block;
  color: #94a3b8;
  padding: 4px 0;
  transition: color 0.15s;
}

.footer-col a:hover {
  color: #00D4AA;
  text-decoration: none;
}

.footer-col .footer-brand {
  color: #00D4AA;
  font-weight: 700;
  font-size: 1.1rem;
  margin-bottom: 10px;
}

.footer-col p {
  line-height: 1.6;
  color: #64748b;
  font-size: 0.84rem;
}

.footer-network-info {
  display: flex;
  gap: 16px;
  margin-top: 14px;
  font-size: 0.8rem;
  color: #64748b;
}

.footer-network-info span {
  display: flex;
  align-items: center;
  gap: 4px;
}

.footer-network-info .dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #00D4AA;
}

.footer-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 16px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.8rem;
  color: #64748b;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.footer-inner a { color: #94a3b8; }
.footer-inner a:hover { color: #00D4AA; }

.footer-built-by {
  color: #94a3b8;
  font-weight: 500;
}

/* Mobile footer */
@media (max-width: 768px) {
  .footer-top {
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    padding: 28px 16px 20px;
  }
  .footer-col:first-child {
    grid-column: 1 / -1;
  }
  .footer-inner {
    flex-direction: column;
    gap: 6px;
    text-align: center;
    padding: 14px 16px;
  }
}

/* ===== Gas Tracker Cards ===== */
.gas-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}

.gas-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  text-align: center;
}

.gas-card .gas-label {
  font-size: 0.85rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.gas-card .gas-value {
  font-size: 2rem;
  font-weight: 700;
  margin: 8px 0 4px;
}

.gas-card .gas-unit { color: var(--text-secondary); font-size: 0.9rem; }
.gas-card .gas-usd { font-size: 0.85rem; color: var(--text-muted); margin-top: 4px; }
.gas-card.low .gas-value { color: var(--success); }
.gas-card.avg .gas-value { color: var(--warning); }
.gas-card.high .gas-value { color: var(--error); }

/* ===== Cost Table ===== */
.cost-table {
  width: 100%;
  border-collapse: collapse;
}

/* Let the table scroll horizontally on narrow viewports rather than
   pushing the whole page wider. */
.cost-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.cost-table th, .cost-table td {
  padding: 10px 16px;
  text-align: left;
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
}

@media (max-width: 768px) {
  .cost-table th, .cost-table td { padding: 8px 10px; font-size: 0.85rem; }
}

.cost-table th {
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.8rem;
  text-transform: uppercase;
}

/* ===== Chart Container ===== */
.chart-container {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 20px;
  margin-bottom: 20px;
}

.chart-container h3 {
  font-size: 1rem;
  margin-bottom: 12px;
  color: var(--text-secondary);
}

.chart-placeholder {
  height: 250px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  border: 1px dashed var(--border-color);
  border-radius: var(--radius);
}

canvas.chart-canvas {
  width: 100% !important;
  height: 250px !important;
}

/* ===== Address Header ===== */
.address-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}

.address-header h1 {
  font-size: 1.1rem;
  font-weight: 500;
  font-family: var(--font-mono);
  word-break: break-all;
}

.address-meta {
  display: flex;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.address-meta .meta-item { display: flex; flex-direction: column; }
.address-meta .meta-label { font-size: 0.8rem; color: var(--text-muted); }
.address-meta .meta-value { font-size: 1.1rem; font-weight: 600; }

/* ===== Token Page ===== */
.token-header {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 20px;
}

.token-icon {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  color: var(--text-muted);
}

.token-info h1 {
  font-size: 1.3rem;
  display: flex;
  align-items: center;
  gap: 8px;
}

.token-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

/* ===== NFT Grid ===== */
.nft-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
}

.nft-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  overflow: hidden;
}

.nft-card .nft-image {
  width: 100%;
  aspect-ratio: 1;
  background: var(--bg-input);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 2rem;
}

.nft-card .nft-meta { padding: 10px; }
.nft-card .nft-id { font-size: 0.85rem; font-weight: 600; }

/* ===== Search Results ===== */
.search-results-group { margin-bottom: 24px; }

.search-results-group h2 {
  font-size: 1.1rem;
  margin-bottom: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.search-result-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  margin-bottom: 8px;
  background: var(--bg-card);
  transition: background 0.15s;
}

.search-result-item:hover { background: var(--bg-card-hover); }

.search-result-item .result-icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--accent-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  font-size: 1rem;
  flex-shrink: 0;
}

.search-result-item .result-info { flex: 1; min-width: 0; }
.search-result-item .result-title { font-weight: 600; font-size: 0.95rem; }

.search-result-item .result-subtitle {
  font-size: 0.8rem;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ===== Filter Bar ===== */
.filter-bar {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}

.filter-btn {
  padding: 6px 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--text-secondary);
  font-size: 0.85rem;
  cursor: pointer;
  transition: all 0.15s;
}

.filter-btn:hover, .filter-btn.active {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-bg);
}

/* ===== Hex Data ===== */
.hex-data {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  padding: 12px 16px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  word-break: break-all;
  max-height: 200px;
  overflow-y: auto;
  color: var(--text-secondary);
}

/* ===== Breadcrumbs ===== */
.breadcrumbs {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-bottom: 8px;
}

.breadcrumbs a {
  color: var(--text-muted);
  text-decoration: none;
}

.breadcrumbs a:hover {
  color: var(--accent);
  text-decoration: none;
}

.breadcrumbs .separator {
  color: var(--text-muted);
  font-size: 0.7rem;
}

.breadcrumbs .current {
  color: var(--text-secondary);
  font-weight: 500;
}

/* ===== Responsive ===== */
@media (max-width: 1024px) {
  .two-col, .chart-row { grid-template-columns: 1fr; }
  .gas-cards { grid-template-columns: 1fr 1fr; }
  .stats-banner.stats-row-6 { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 768px) {
  .header-inner {
    flex-wrap: wrap;
    height: auto;
    padding: 10px 16px;
  }
  .search-bar { order: 3; max-width: 100%; width: 100%; }
  .search-bar input { min-height: 44px; font-size: 16px; }
  .search-bar button { min-height: 44px; min-width: 64px; }
  /* I1797: hamburger button visible top-right on mobile. */
  .nav-toggle { display: inline-flex; }
  .header-right { gap: 8px; font-size: 0.75rem; }
  /* I1485: header buttons meet 44x44 touch target */
  .header-right #theme-toggle,
  .header-right .wallet-btn {
    min-width: 44px;
    min-height: 44px;
    padding: 8px 12px;
  }
  .overview-row { flex-direction: column; gap: 4px; }
  .overview-label { width: auto; min-width: auto; }
  .stats-banner { grid-template-columns: repeat(2, 1fr); }
  .stats-banner.stats-row-6 { grid-template-columns: repeat(2, 1fr); }
  .gas-cards { grid-template-columns: 1fr; }
  main.container { padding: 16px 12px; }
  .footer-inner { flex-direction: column; gap: 8px; text-align: center; }
  /* I1485: banner mobile overrides now live in a separate @media block
     AFTER the main .indexing-banner rules below, so cascade picks them up. */
}

/* ===== Indexing Banner =====
   I1485: banner must reflow cleanly on narrow viewports.
   - flex-wrap so text wraps onto next line instead of overflowing.
   - close button is INSIDE the flex (not absolute) so the wrapped text
     never hides underneath it and the button stays tappable at 44x44px.
   - min-width: 0 on .banner-text so it can shrink inside flex.
*/
.indexing-banner {
  background: linear-gradient(90deg, #fef3c7, #fde68a);
  border-bottom: 1px solid #f59e0b;
  padding: 10px 56px 10px 20px;
  text-align: center;
  font-size: 0.875rem;
  color: #78350f;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
}
[data-theme="dark"] .indexing-banner {
  background: linear-gradient(90deg, #451a03, #78350f);
  border-bottom-color: #92400e;
  color: #fde68a;
}
.indexing-banner .banner-icon {
  font-size: 1.1rem;
  flex-shrink: 0;
}
.indexing-banner .banner-text {
  font-weight: 500;
  min-width: 0;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.indexing-banner .banner-progress {
  font-weight: 700;
  margin-left: 4px;
}
.indexing-banner .banner-close {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  color: #92400e;
  font-size: 1.5rem;
  line-height: 1;
  padding: 0;
  border-radius: 4px;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.indexing-banner .banner-close:hover {
  background: rgba(0,0,0,0.1);
}
[data-theme="dark"] .indexing-banner .banner-close {
  color: #fde68a;
}
.indexing-banner.banner-error {
  background: linear-gradient(90deg, #fecaca, #fca5a5);
  border-bottom-color: #ef4444;
  color: #991b1b;
}
[data-theme="dark"] .indexing-banner.banner-error {
  background: linear-gradient(90deg, #450a0a, #7f1d1d);
  border-bottom-color: #dc2626;
  color: #fca5a5;
}
.indexing-banner .banner-progress-bar.progress-error {
  background: #ef4444;
}
[data-theme="dark"] .indexing-banner .banner-progress-bar.progress-error {
  background: #dc2626;
}
.indexing-banner.hidden {
  display: none;
}

/* I1485: mobile banner overrides — placed after the main .indexing-banner
   rules so CSS cascade picks them up on mobile viewports. */
@media (max-width: 768px) {
  .indexing-banner { font-size: 0.8rem; padding: 8px 52px 8px 12px; }
  .indexing-banner .banner-icon { font-size: 0.95rem; }
  .indexing-banner .banner-close { font-size: 1.35rem; right: 4px; }
}

/* ===== Label Tags (I101) =====
 *
 * I1814 (2026-05-01): split .addr-tag from .badge-method.
 * Both classes were originally grouped in this selector (intent: share
 * the inline-block label look). But .badge-method also had an earlier
 * definition above (mono font, max-width: 100px, ellipsis truncation
 * — for tx method names like 'transfer(...)'). Cascade resulted in
 * mixed/contradictory styling. The two components serve different
 * roles — keep them separate:
 *   .badge-method  — tx method-name pills (mono, truncated). Defined above.
 *   .addr-tag      — address-label tags (token/dex/validator/PNS). Defined here.
 */
.addr-labeled {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-decoration: none;
}
.addr-tag {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 0.78em;
  font-weight: 500;
}
.tag-token { background: #e8f0fe; color: #1a73e8; border: 1px solid #c6dafc; }
.tag-dex { background: #f3e8ff; color: #7c3aed; border: 1px solid #dcc6fc; }
.tag-validator { background: #e6f9ed; color: #0d7a3e; border: 1px solid #b7ebc9; }
.tag-system { background: #f0f0f0; color: #666666; border: 1px solid #d4d4d4; }
.tag-exchange { background: #fff3e0; color: #e65100; border: 1px solid #ffcc80; }
/* I1779: PNS .pls name badge — PulseChain-branded teal */
.tag-pns { background: #d1f5ec; color: #00674f; border: 1px solid #9fe3d1; text-decoration: none; }
.tag-pns:hover { background: #b8ecdf; text-decoration: none; }
.tag-pns-more { background: #f0f0f0; color: #666; border: 1px solid #d4d4d4; cursor: default; margin-left: 4px; }
.tag-name { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
.cat-transfer { background: #e8f0fe; color: #1a73e8; border: 1px solid #c6dafc; }
.cat-swap { background: #f3e8ff; color: #7c3aed; border: 1px solid #dcc6fc; }
.cat-liquidity { background: #e6f9ed; color: #0d7a3e; border: 1px solid #b7ebc9; }
.cat-approval { background: #fff3e0; color: #e65100; border: 1px solid #ffcc80; }
.cat-other { background: #f0f0f0; color: #666666; border: 1px solid #d4d4d4; }
[data-theme="dark"] .tag-token { background: #1e3a5f; color: #7eb6ff; border-color: #2a4d7a; }
[data-theme="dark"] .tag-dex { background: #2d1a4e; color: #c4a5ff; border-color: #3d2a66; }
[data-theme="dark"] .tag-validator { background: #1a3d2a; color: #7edba5; border-color: #2a5a3d; }
[data-theme="dark"] .tag-system { background: #2a2a2a; color: #aaa; border-color: #444; }
[data-theme="dark"] .tag-exchange { background: #3d2a1a; color: #ffb74d; border-color: #5a3d2a; }
[data-theme="dark"] .tag-pns { background: #0d3d2f; color: #7ee0c4; border-color: #1a5a47; }
[data-theme="dark"] .tag-pns:hover { background: #134d3b; }
[data-theme="dark"] .tag-pns-more { background: #2a2a2a; color: #aaa; border-color: #444; }
[data-theme="dark"] .tag-name { background: #4a3416; color: #fcd34d; border-color: #5a4423; }
[data-theme="dark"] .cat-transfer { background: #1e3a5f; color: #7eb6ff; border-color: #2a4d7a; }
[data-theme="dark"] .cat-swap { background: #2d1a4e; color: #c4a5ff; border-color: #3d2a66; }
[data-theme="dark"] .cat-liquidity { background: #1a3d2a; color: #7edba5; border-color: #2a5a3d; }
[data-theme="dark"] .cat-approval { background: #3d2a1a; color: #ffb74d; border-color: #5a3d2a; }
[data-theme="dark"] .cat-other { background: #2a2a2a; color: #aaa; border-color: #444; }

/* ===== Slot/Epoch Status Badges =====
   Used on slot/epoch tables (index.html slot-list, slots.html, epoch.html,
   slot.html) via utils.js slotStatusBadge() + epoch.js. Five states share
   a common pill shape; only bg/color differ.

   Cascade caveat: valdash.css also defines `.status-pending` (validator
   state, color !important). That sheet only loads on /valdash, where
   `.status-pending` is used for validator state, NOT slot status, so the
   conflict is currently inert. If slot pills are ever rendered into
   /valdash, rename these to `.slot-status-*` per I1814. */
.status-proposed,
.status-missed,
.status-finalized,
.status-pending,
.status-orphaned {
  padding: 2px 10px;
  border-radius: 12px;
  font-size: 0.82rem;
  font-weight: 500;
}
.status-proposed {
  background: var(--accent-bg);
  color: var(--accent);
}
.status-missed {
  background: var(--error-bg);
  color: var(--error);
}
.status-finalized {
  background: var(--success-bg);
  color: var(--success);
}
/* I1815: pending = slot pre-rendered ahead of indexer cursor (no block yet) */
.status-pending {
  background: var(--neutral-bg);
  color: var(--text-muted);
  font-style: italic;
}
.status-orphaned {
  background: var(--warning-bg);
  color: var(--warning);
}
tr.slot-pending-row {
  opacity: 0.65;
}
tr.slot-pending-row:hover {
  opacity: 0.9;
}

/* ===== Queue Cards ===== */
.queue-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 20px;
}
.queue-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  padding: var(--space-5);
}
.queue-card h3 {
  margin: 0 0 12px 0;
  font-size: 1rem;
}
.queue-stat {
  display: flex;
  justify-content: space-between;
  padding: 6px 0;
  border-bottom: 1px solid var(--border-color);
}
.queue-stat:last-child {
  border-bottom: none;
}
.queue-stat-label {
  color: var(--text-secondary);
}
.queue-stat-value {
  font-weight: 600;
}

/* ===== Validator Filter Bar ===== */
.validator-filter-bar {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 16px;
}
.validator-filter-bar .filter-btn {
  padding: 6px 16px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.85rem;
  transition: all 0.15s;
}
.validator-filter-bar .filter-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.validator-filter-bar .filter-btn.active {
  background: var(--accent);
  color: white;
  border-color: var(--accent);
}
.validator-search-box {
  flex: 1;
  min-width: 240px;
  padding: 8px 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  color: var(--text-primary);
  font-size: 0.9rem;
  font-family: var(--font-mono);
}

/* ===== DEX Filter Bar ===== */
.dex-filter-bar {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
  flex-wrap: wrap;
  align-items: center;
}
.dex-filter-select {
  padding: 8px 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  color: var(--text-primary);
  font-size: 0.88rem;
  cursor: pointer;
  min-width: 160px;
}
.dex-filter-select:focus {
  border-color: var(--accent);
  outline: none;
}
.dex-filter-input {
  padding: 8px 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  color: var(--text-primary);
  font-size: 0.88rem;
  min-width: 200px;
  flex: 1;
  max-width: 320px;
}
.dex-filter-input:focus {
  border-color: var(--accent);
  outline: none;
}
.dex-filter-input::placeholder {
  color: var(--text-muted);
}

/* ===== Epoch/Slot Navigation Arrows ===== */
.epoch-nav, .slot-nav {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.epoch-nav a, .slot-nav a {
  color: var(--accent);
  text-decoration: none;
  font-size: 1.1rem;
}
.epoch-nav a:hover, .slot-nav a:hover {
  opacity: 0.8;
}

/* ===== Responsive: forms + buttons — 44px touch targets across mobile ===== */
@media (max-width: 768px) {
  /* I1485: all interactive form inputs and buttons meet 44x44 touch target.
     font-size: 16px on inputs prevents iOS zoom-on-focus. */
  input[type="text"],
  input[type="search"],
  input[type="number"],
  input[type="email"],
  input[type="url"],
  input[type="password"],
  input[type="tel"],
  select,
  textarea {
    min-height: 44px;
    font-size: 16px;
  }
  textarea { min-height: 88px; }
  .btn {
    min-height: 44px;
    padding: 10px 20px;
  }
  .adv-filter-field input,
  .adv-filter-field select { min-height: 44px; font-size: 16px; }
  .dex-filter-input { min-height: 44px; font-size: 16px; }
}

/* ===== Responsive: Queue + Nav Dropdown ===== */
@media (max-width: 768px) {
  .queue-cards { grid-template-columns: 1fr; }
  /* I1797: Mobile nav becomes a right-side slide-in drawer.
     - Default: hidden (translateX 100%) so it never takes header space.
     - .is-open: slides in (translateX 0). Body adds .nav-locked to freeze
       background scroll. Click outside / link / ESC closes (handled in
       utils.js).
     - Inside drawer: dropdown groups stack inline (tap-toggle .open via
       existing app.js handler). */
  .nav-dropdown {
    width: 100%;
  }
  .nav-dropdown-trigger {
    display: block;
    width: 100%;
    min-height: 44px;
    line-height: 32px;
    padding: 6px 12px;
  }
  .nav-dropdown-menu {
    position: static;
    box-shadow: none;
    border: none;
    margin-top: 0;
    padding: 0 0 0 12px;
    width: 100%;
  }
  /* I1797 follow-up: when the drawer is open on mobile, expand every
     dropdown sub-menu inline so the user sees + taps every link in one
     shot. The desktop tap-to-expand pattern fights touch UX in a
     vertical drawer — no point making the user tap "Blockchain" then
     "Blocks" when the screen has plenty of room to list everything.
     The drawer has overflow-y:auto so a long list scrolls inside it. */
  .main-nav.is-open .nav-dropdown-menu {
    display: block;
  }
  .nav-dropdown-menu a {
    min-height: 44px;
    line-height: 1.3;
    padding: 12px 16px;
  }
  /* When the menu auto-expands, the trigger anchor stops being a
     toggle and becomes the section heading. Strip its hover-arrow and
     dim it slightly so users see "this is a category, the children are
     the actionable links." */
  .main-nav.is-open .nav-dropdown-trigger {
    color: var(--text-muted);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 14px 12px 4px;
    cursor: default;
    pointer-events: none;
  }
  .main-nav {
    position: fixed;
    top: 0;
    right: 0;
    width: 280px;
    max-width: 85vw;
    height: 100vh;
    height: 100dvh;
    background: var(--bg-secondary);
    border-left: 1px solid var(--border-color);
    box-shadow: -4px 0 12px rgba(0, 0, 0, 0.15);
    z-index: 9999;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 60px 16px 24px;
    overflow-y: auto;
    /* iOS Safari: explicit momentum scroll. -webkit-overflow-scrolling
       is deprecated post-13 but still helps older iOS; touch-action
       pan-y unblocks vertical-only swipe-to-scroll inside the drawer
       even when body has overflow:hidden via .nav-locked. */
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
    overscroll-behavior: contain;
    transform: translateX(100%);
    transition: transform 0.2s ease-out;
    border-top: none;
    margin: 0;
  }
  /* Hard-set pointer-events:auto on every actionable child inside the
     drawer so any inherited pointer-events from a parent media-query
     rule can't accidentally swallow taps. Pairs with the
     pointer-events:none we set on .nav-dropdown-trigger above. */
  .main-nav.is-open > a,
  .main-nav.is-open .nav-dropdown-menu a {
    pointer-events: auto;
    cursor: pointer;
    touch-action: manipulation;
  }
  .main-nav.is-open {
    transform: translateX(0);
  }
  .main-nav > a {
    display: block;
    min-height: 44px;
    line-height: 32px;
    padding: 6px 12px;
    width: 100%;
  }
  /* X close button anchored to drawer top-right; only visible while open. */
  .nav-close {
    display: none;
    position: absolute;
    top: 12px;
    right: 12px;
  }
  .main-nav.is-open .nav-close {
    display: inline-flex;
  }
}

/* ===== Row Highlight Animation (E22 I197) ===== */
@keyframes fadeHighlight {
  0% { background-color: rgba(0, 158, 126, 0.15); }
  100% { background-color: transparent; }
}

tr.new-row {
  animation: fadeHighlight 2.5s ease-out forwards;
}

@keyframes confirmFade {
  0% { background-color: rgba(245, 158, 11, 0.15); border-left-color: var(--warning); }
  50% { background-color: rgba(34, 197, 94, 0.15); border-left-color: var(--success); }
  80% { background-color: rgba(34, 197, 94, 0.08); transform: translateX(2px); }
  100% { background-color: transparent; border-left-color: transparent; transform: translateX(0); }
}

.tx-pending {
  border-left: 3px solid var(--warning);
}

.tx-confirming {
  border-left: 3px solid var(--success);
  animation: confirmFade 1.4s ease-out forwards;
}

/* ===== Transaction Pool Widget ===== */

/* ===== Epoch Progress Widget ===== */
.epoch-progress {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-color);
}
.epoch-progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
}
.epoch-progress-label {
  font-size: 0.85rem;
  color: var(--text-secondary);
}
.epoch-progress-label strong {
  color: var(--text-primary);
}
.epoch-progress-timer {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.epoch-progress-bar {
  height: 6px;
  background: var(--bg-input);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 4px;
}
.epoch-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), #00d4aa);
  border-radius: 3px;
  transition: width 0.3s ease;
}
.epoch-progress-slots {
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* Compact epoch rows */
.epoch-compact-row {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  gap: 12px;
  border-bottom: 1px solid var(--border-subtle);
  cursor: pointer;
  transition: background 0.15s;
  font-size: 0.85rem;
}
.epoch-compact-row:last-child {
  border-bottom: none;
}
.epoch-compact-row:hover {
  background: var(--bg-card-hover);
}
.epoch-compact-num {
  font-weight: 600;
  color: var(--accent);
  min-width: 55px;
}
.epoch-compact-status {
  min-width: 70px;
}
.epoch-compact-part {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 6px;
}
.epoch-compact-part-bar {
  flex: 1;
  height: 5px;
  background: var(--bg-input);
  border-radius: 3px;
  overflow: hidden;
  max-width: 60px;
}
.epoch-compact-part-fill {
  height: 100%;
  border-radius: 3px;
}
.epoch-compact-part-text {
  font-weight: 500;
  font-size: 0.8rem;
  min-width: 42px;
}
.epoch-compact-blocks {
  color: var(--text-muted);
  font-size: 0.78rem;
}

.pending-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
  background: var(--warning-bg);
  color: var(--warning);
  border: 1px solid var(--warning-border);
}

.new-data-banner {
  background: var(--accent-bg);
  border: 1px solid var(--accent-border);
  border-radius: var(--radius);
  padding: 8px 16px;
  text-align: center;
  font-size: 0.85rem;
  color: var(--accent);
  font-weight: 500;
  cursor: pointer;
  margin-bottom: 12px;
  transition: background 0.15s;
}

.new-data-banner:hover {
  background: var(--accent-border);
}

/* ===== Enhanced Indexing Banner with Progress Bar (E22 I200) ===== */
.indexing-banner .banner-progress-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 3px;
  background: #f59e0b;
  transition: width 0.5s ease-out;
  border-radius: 0 2px 0 0;
}

[data-theme="dark"] .indexing-banner .banner-progress-bar {
  background: #fde68a;
}

.indexing-banner .banner-progress-bar.progress-good {
  background: var(--success);
}

.indexing-banner .banner-progress-bar.progress-slow {
  background: var(--error);
}

/* ===== Epoch Progress Bar (E26 B2) ===== */
.epoch-progress-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 16px 20px;
  margin-bottom: 24px;
  box-shadow: var(--shadow);
}

.epoch-progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.epoch-progress-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.95rem;
  color: var(--text-primary);
}

.epoch-progress-slot {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

.epoch-slot-bar {
  display: flex;
  gap: 3px;
  margin-bottom: 8px;
}

.slot-box {
  flex: 1;
  height: 24px;
  border-radius: 3px;
  transition: background 0.2s;
  min-width: 0;
}

.slot-box.proposed {
  background: var(--success);
}

.slot-box.missed {
  background: var(--error);
}

.slot-box.current {
  background: var(--warning);
  animation: slotPulse 1.5s ease-in-out infinite;
}

.slot-box.pending {
  background: var(--bg-input);
  /* I1539: use inset box-shadow instead of border so the slot's painted
   * rectangle matches proposed/missed/current siblings exactly. With
   * `border: 1px` on pending only, box-sizing:border-box kept the
   * outer box size identical but cost 2px of visible painted area,
   * misaligning the current-epoch (bottom) row vs the 6 past-epoch
   * rows above it. */
  box-shadow: inset 0 0 0 1px var(--border-color);
}

@keyframes slotPulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.4); }
  50% { opacity: 0.6; box-shadow: 0 0 0 4px rgba(245, 158, 11, 0); }
}

.epoch-progress-legend {
  display: flex;
  gap: 16px;
  font-size: 0.78rem;
  color: var(--text-muted);
}

.epoch-progress-legend span {
  display: flex;
  align-items: center;
  gap: 4px;
}

@media (max-width: 768px) {
  .slot-box { height: 18px; }
  .epoch-slot-bar { gap: 2px; }
  .epoch-progress-legend { gap: 10px; flex-wrap: wrap; }
}

/* ===== Validator Status Bar (E26 C1) ===== */
.val-status-bar {
  margin-bottom: 16px;
}

.val-status-segments {
  display: flex;
  height: 28px;
  border-radius: var(--radius);
  overflow: hidden;
  gap: 2px;
}

.status-segment {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  transition: flex 0.3s;
}

.status-segment .seg-label {
  font-size: 0.72rem;
  font-weight: 600;
  color: white;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 6px;
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}

/* ===== Missed Slot Row (E26) ===== */
tr.slot-missed-row {
  opacity: 0.55;
}

tr.slot-missed-row:hover {
  opacity: 0.8;
}

.seg-active { background: var(--success); }
.seg-pending { background: var(--warning); }
.seg-exiting { background: var(--info); }
.seg-exited { background: #6b7280; }
.seg-slashed { background: var(--error); }

/* ===== Slotviz Grid (I752) ===== */
.slotviz-card {
  margin-bottom: 24px;
}
.slotviz-grid {
  padding: 0.75rem 1rem;
}
.slotviz-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 3px;
}
.slotviz-epoch-label {
  width: 60px;
  flex-shrink: 0;
  text-align: right;
  font-size: 0.8rem;
  color: var(--text-secondary);
  text-decoration: none;
}
.slotviz-epoch-label:hover {
  color: var(--accent);
  text-decoration: none;
}
.slotviz-slots {
  display: flex;
  gap: 1px;
  flex: 1;
}
.slotviz-slots .slot-box {
  flex: 1;
  min-width: 6px;
  height: 18px;
  border-radius: 2px;
  display: inline-block;
  cursor: pointer;
  transition: transform 0.1s;
}
.slotviz-slots .slot-box:hover {
  transform: scale(1.5);
  z-index: 1;
}
.slotviz-participation {
  width: 50px;
  flex-shrink: 0;
  text-align: right;
  font-size: 0.8rem;
  font-weight: 600;
}
.slotviz-legend {
  display: flex;
  gap: 1rem;
  padding: 0.5rem 1rem;
  border-top: 1px solid var(--border-color);
  font-size: 0.75rem;
  color: var(--text-muted);
}
.legend-item {
  display: flex;
  align-items: center;
  gap: 4px;
}
.legend-item .slot-box {
  width: 10px;
  height: 10px;
  cursor: default;
  flex: none;
  min-width: 0;
}

@media (max-width: 768px) {
  .slotviz-slots .slot-box {
    min-width: 4px;
    height: 14px;
  }
  .slotviz-epoch-label { width: 50px; font-size: 0.72rem; }
  .slotviz-participation { width: 40px; font-size: 0.72rem; }
}

/* ===== Daily TX Mini-Chart (I753) ===== */
.chart-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-bottom: 1.5rem;
}
.chart-row.single {
  grid-template-columns: 1fr;
}
.chart-row > * {
  min-width: 0;
  overflow: hidden;
}
.mini-chart-container {
  padding: 0.5rem 1rem 1rem;
  height: 160px;
}

/* ===== Gas Heatmap (I796) ===== */
.gas-heatmap-section {
  margin: 24px 0;
}
.gas-heatmap-section h3 {
  margin: 0 0 4px;
  font-size: 1.1rem;
}
.gas-heatmap-section .section-desc {
  color: var(--text-secondary);
  font-size: 0.85rem;
  margin: 0 0 16px;
}
.gas-heatmap {
  /* Heatmap is 25 cols × 7 rows = overflows on narrow viewports.
     Let the container scroll horizontally; don't push the page. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.heatmap-grid {
  display: grid;
  grid-template-columns: 50px repeat(24, minmax(15px, 1fr));
  gap: 2px;
  min-width: 460px;
}
.heatmap-cell {
  text-align: center;
  font-size: 0.7rem;
  padding: 6px 2px;
  border-radius: 2px;
}
.heatmap-header {
  font-weight: 600;
  color: var(--text-secondary);
  font-size: 0.65rem;
}
.heatmap-day {
  font-weight: 600;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.heatmap-data {
  cursor: pointer;
  min-height: 28px;
  border-radius: 3px;
  transition: transform 0.1s;
}
.heatmap-data:hover {
  transform: scale(1.3);
  z-index: 1;
  box-shadow: var(--shadow);
}
.heatmap-legend {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  justify-content: center;
}
.legend-gradient {
  width: 200px;
  height: 12px;
  border-radius: 6px;
  background: linear-gradient(to right, rgb(0,200,50), rgb(255,200,50), rgb(255,0,50));
}
.legend-label {
  font-size: 0.8rem;
  color: var(--text-secondary);
}

/* ===== CSV Export Button (I777) ===== */
.csv-export-btn {
  float: right;
  font-size: 0.8rem;
  padding: 4px 12px;
  margin-bottom: 8px;
  background: var(--bg-elevated);
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm, 4px);
  cursor: pointer;
}
.csv-export-btn:hover {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

/* ===== Advanced Filter (I787) ===== */
.adv-filter-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 8px 0;
}
.adv-filter-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.adv-filter-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.adv-filter-field label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-secondary);
}
.adv-filter-field input,
.adv-filter-field select {
  padding: 8px 12px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm, 4px);
  background: var(--bg-input, var(--bg-elevated));
  color: var(--text-primary);
  font-size: 0.9rem;
  font-family: inherit;
}
.adv-filter-field input:focus,
.adv-filter-field select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-bg, rgba(0, 158, 126, 0.1));
}
.adv-filter-field input::placeholder {
  color: var(--text-muted, #999);
}
.adv-filter-actions {
  flex-direction: row;
  align-items: flex-end;
  gap: 8px;
}
.btn {
  padding: 8px 20px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm, 4px);
  font-size: 0.9rem;
  cursor: pointer;
  font-family: inherit;
}
.btn-primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.btn-primary:hover {
  opacity: 0.9;
}
.btn-secondary {
  background: var(--bg-elevated);
  color: var(--text-secondary);
}
.btn-secondary:hover {
  background: var(--bg-card);
  color: var(--text-primary);
}
@media (max-width: 640px) {
  .adv-filter-row {
    grid-template-columns: 1fr;
  }
}

/* ===== QR Code Modal (I799) ===== */
.qr-modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}
.qr-modal {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg, 12px);
  padding: 32px;
  text-align: center;
  position: relative;
  min-width: 280px;
  max-width: 360px;
  box-shadow: var(--shadow-xl);
}
.qr-modal h3 {
  margin: 0 0 16px 0;
  font-size: 1.1rem;
  color: var(--text-primary);
}
.qr-modal-close {
  position: absolute;
  top: 8px;
  right: 12px;
  background: none;
  border: none;
  font-size: 1.5rem;
  color: var(--text-secondary);
  cursor: pointer;
  line-height: 1;
  padding: 4px 8px;
}
.qr-modal-close:hover {
  color: var(--text-primary);
}
#qr-code-container {
  display: flex;
  justify-content: center;
  margin: 16px 0;
}
#qr-code-container svg {
  width: 200px;
  height: 200px;
}
.qr-modal-address {
  font-family: var(--font-mono, monospace);
  font-size: 0.75rem;
  color: var(--text-secondary);
  word-break: break-all;
  margin: 12px 0 0 0;
  padding: 8px;
  background: var(--bg-elevated);
  border-radius: var(--radius-sm, 4px);
}

/* ===== Search Autocomplete (I775) ===== */
.search-autocomplete {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 0 0 var(--radius-sm, 4px) var(--radius-sm, 4px);
  box-shadow: var(--shadow-dropdown);
  z-index: 1000;
  max-height: 300px;
  overflow-y: auto;
  display: none;
}
.search-autocomplete.active { display: block; }
.search-autocomplete-item {
  padding: 10px 14px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.9rem;
  border-bottom: 1px solid var(--border-color);
}
.search-autocomplete-item:last-child { border-bottom: none; }
.search-autocomplete-item:hover { background: var(--bg-elevated); }
.search-autocomplete-item .type-badge {
  font-size: 0.75rem;
  padding: 2px 8px;
  border-radius: var(--radius-sm, 4px);
  font-weight: 600;
  text-transform: uppercase;
  flex-shrink: 0;
}
.search-autocomplete-item .type-badge.address { background: #dbeafe; color: #1e40af; }
.search-autocomplete-item .type-badge.tx { background: #fef3c7; color: #92400e; }
.search-autocomplete-item .type-badge.block { background: #d1fae5; color: #065f46; }
.search-autocomplete-item .type-badge.token { background: #ede9fe; color: #5b21b6; }
.search-autocomplete-item .match-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
}

/* ===== Search Filter Bar (I778) ===== */
.search-filter-bar {
  display: flex;
  gap: 8px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.search-filter-bar .filter-btn .filter-count {
  font-size: 0.8em;
  color: var(--text-muted);
  margin-left: 2px;
}

/* ===== Transaction Action Summary (I759) ===== */
.tx-action-summary {
  background: var(--accent-bg);
  border: 1px solid var(--accent-border);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 12px;
  font-size: 0.9rem;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.tx-action-summary .action-icon {
  font-size: 1.1rem;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-weight: 700;
  font-size: 0.8rem;
}
.tx-action-summary .action-text {
  flex: 1;
  line-height: 1.5;
}

/* ===== DEX Stats Banner ===== */
.dex-stats-banner {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.dex-stats-banner .stat-card {
  text-align: center;
  padding: 14px 12px;
}

/* ===== DEX Chip Filters ===== */
.chip-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 16px;
}
.chip-filter {
  padding: 4px 12px;
  border-radius: 16px;
  border: 1px solid var(--border-color);
  background: var(--bg-card);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.8rem;
  transition: all 0.15s;
}
.chip-filter:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.chip-filter.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

/* ===== Sort Toggle Buttons ===== */
.sort-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 12px;
}
.sort-toggle {
  padding: 4px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-color);
  background: var(--bg-card);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.8rem;
  transition: all 0.15s;
}
.sort-toggle:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.sort-toggle.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

/* ===== Token Logo ===== */
.token-logo {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg-input);
}
.token-logo-sm {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg-input);
}
.token-logo-fallback {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--bg-input);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--text-muted);
  flex-shrink: 0;
}
.token-logo-fallback.sm {
  width: 20px;
  height: 20px;
  font-size: 0.55rem;
}
.token-cell {
  display: flex;
  align-items: center;
  gap: 8px;
}
.token-cell .token-name {
  font-weight: 600;
}
.token-cell .token-symbol {
  color: var(--text-muted);
  font-size: 0.85rem;
}

/* ===== Pool Pair Display ===== */
.pool-pair {
  display: flex;
  align-items: center;
  gap: 4px;
}
.pool-logos {
  display: flex;
  align-items: center;
}
.pool-logos .token-logo-sm:nth-child(2) {
  margin-left: -6px;
}

/* ===== Slippage Colors ===== */
.slippage-low { color: var(--success); }
.slippage-med { color: var(--warning); }
.slippage-high { color: var(--error); }

/* ===== Price Change Colors ===== */
.price-up { color: var(--success); }
.price-down { color: var(--error); }

/* ===== Trade Type Badges ===== */
.trade-buy { color: var(--success); font-weight: 600; }
.trade-sell { color: var(--error); font-weight: 600; }

/* ===== Watchlist Star Button (I795) ===== */
.watchlist-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.4rem;
  color: var(--text-muted);
  padding: 0 4px;
  transition: color 0.2s;
}
.watchlist-btn:hover { color: var(--warning); }
.watchlist-btn.watched { color: var(--warning); }

/* PNS name badge on address links (E93/I1392) */
.pls-name {
  display: inline-block;
  font-size: 0.82em;
  color: var(--primary);
  margin-right: 4px;
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

/* ========================================================================
   I1554 — Live-feel animations
   Keyframes + classes used by frontend/js/live.js:
     - .live-new-row     → slide-in + fade-highlight for new list rows
     - .live-removing    → fade-out + collapse for rows that are leaving
     - .live-heartbeat   → 2s pulse on the header "Live" indicator
     - .live-value-bump  → brief green flash when a stat value animates
   All animations are gated by `prefers-reduced-motion: reduce` → no motion.
   ======================================================================== */

@keyframes live-slide-in {
  from { transform: translateY(-8px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@keyframes live-highlight-fade {
  0%   { background: var(--accent-soft, rgba(0, 158, 126, 0.15)); }
  100% { background: transparent; }
}
@keyframes live-fade-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}
@keyframes live-heartbeat-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.55; transform: scale(1.25); }
}
@keyframes live-value-bump {
  0%   { color: var(--success, #00d4aa); }
  100% { color: inherit; }
}

.live-new-row {
  animation: live-slide-in 0.3s ease-out, live-highlight-fade 1.8s ease-out;
}
.live-removing {
  animation: live-fade-out 0.3s ease-in forwards;
  pointer-events: none;
}
.live-heartbeat {
  animation: live-heartbeat-pulse 2s ease-in-out infinite;
}
.live-value-bump {
  animation: live-value-bump 0.6s ease-out;
}

/* I1673 — Pending → Finalized status-transition flash on existing rows.
   Triggered by index.html's reconcileSlotStatuses / reconcileEpochStatuses
   when a row stays (same slot/epoch key) but its status badge flips from
   Proposed/Pending to Finalized. The row row-highlights green for 1.5s
   without being rebuilt in the DOM — gives valdash-style "watch
   finality advance" feel. */
@keyframes live-status-change {
  0%   { background: rgba(34, 197, 94, 0.22); }
  100% { background: transparent; }
}
.live-status-change {
  animation: live-status-change 1.5s ease-out;
}

/* I1673 — subtle flash when a slotviz cell transitions pending → proposed
   (or missed). Per-cell diff keeps the `.current` pulse animation from
   restarting every 12s; this flash calls attention to newly-settled
   slots as finality catches up. */
@keyframes slot-box-change {
  0%   { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.6); transform: scale(1.15); }
  100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);   transform: scale(1); }
}
.slot-box.slot-box-change {
  animation: slot-box-change 0.9s ease-out;
}

/* I1673 — epoch progress bar: add a smooth width transition so the fill
   glides across the bar every second instead of snapping. Duration a
   hair under the 1000ms poll so it visibly settles before the next
   tick — valdash-style continuous progress. */
.epoch-progress-fill {
  transition: width 0.9s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .live-new-row,
  .live-removing,
  .live-heartbeat,
  .live-value-bump,
  .live-status-change,
  .slot-box.slot-box-change {
    animation: none !important;
  }
  .epoch-progress-fill {
    transition: none !important;
  }
}

/* ===== I1504: Validator header (pubkey + creds + balances + status timeline) ===== */
.validator-header {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 20px;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.vheader-grid { display: flex; flex-direction: column; gap: 12px; }

.vheader-row { display: flex; gap: 16px; align-items: flex-start; }

.vheader-label {
  width: 200px;
  min-width: 200px;
  color: var(--text-muted);
  font-size: 0.9rem;
  padding-top: 4px;
}

.vheader-value {
  flex: 1;
  font-size: 0.9rem;
  word-break: break-all;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.vheader-mono { font-family: var(--font-mono); font-size: 0.85rem; }

.vheader-balances {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  border-top: 1px solid var(--border-subtle);
  padding-top: 20px;
}

.vheader-balance-tile {
  background: var(--bg-alt, var(--bg-subtle, rgba(0, 0, 0, 0.02)));
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 14px 16px;
}

.vheader-balance-label {
  color: var(--text-muted);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin-bottom: 6px;
}

.vheader-balance-value {
  font-size: 1.6rem;
  font-weight: 600;
  color: var(--text-primary);
}

.vheader-balance-unit {
  font-size: 1rem;
  color: var(--text-muted);
  font-weight: 400;
  margin-left: 4px;
}

/* Status timeline — horizontal stepper across 5 stages */
.vtimeline {
  display: flex;
  align-items: flex-start;
  gap: 0;
  border-top: 1px solid var(--border-subtle);
  padding-top: 20px;
  overflow-x: auto;
}

.vtimeline-step {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  padding: 0 8px;
  text-align: center;
}

/* Connector line between steps */
.vtimeline-step::before {
  content: '';
  position: absolute;
  top: 10px;
  left: calc(-50% + 12px);
  right: calc(50% + 12px);
  height: 2px;
  background: var(--border-color);
  z-index: 0;
}

.vtimeline-step:first-child::before { display: none; }

.vtimeline-step.vtimeline-reached::before,
.vtimeline-step.vtimeline-current::before {
  background: #00d4aa;
}

.vtimeline-dot {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--bg-card);
  border: 2px solid var(--border-color);
  position: relative;
  z-index: 1;
  margin-bottom: 8px;
}

.vtimeline-reached .vtimeline-dot {
  background: #00d4aa;
  border-color: #00d4aa;
}

.vtimeline-current .vtimeline-dot {
  background: #00d4aa;
  border-color: #00d4aa;
  box-shadow: 0 0 0 4px rgba(0, 212, 170, 0.24);
}

.vtimeline-future .vtimeline-dot { opacity: 0.5; }

.vtimeline-title {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 4px;
}

.vtimeline-future .vtimeline-title,
.vtimeline-future .vtimeline-meta {
  opacity: 0.5;
}

.vtimeline-meta {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.vtimeline-epoch-link {
  color: var(--accent, #00d4aa);
  text-decoration: none;
}

.vtimeline-epoch-link:hover { text-decoration: underline; }

.vtimeline-epoch-future { color: var(--text-muted); font-style: italic; }

.vtimeline-epoch-na { color: var(--text-muted); }

.vheader-status-text {
  padding: 12px 16px;
  background: var(--bg-alt, var(--bg-subtle, rgba(0, 0, 0, 0.02)));
  border-left: 3px solid #00d4aa;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: 0.9rem;
  color: var(--text-primary);
  line-height: 1.5;
}

@media (max-width: 768px) {
  .vheader-row { flex-direction: column; gap: 4px; }
  .vheader-label { width: auto; min-width: auto; }
  .vheader-balances { grid-template-columns: 1fr; }
  .vheader-balance-value { font-size: 1.3rem; }
  .vtimeline { flex-direction: column; gap: 12px; padding-top: 16px; }
  .vtimeline-step { flex-direction: row; align-items: center; text-align: left; gap: 12px; padding: 0; }
  .vtimeline-step::before {
    top: -12px;
    bottom: auto;
    left: 10px;
    right: auto;
    width: 2px;
    height: 12px;
  }
  .vtimeline-dot { margin-bottom: 0; flex-shrink: 0; }
  .vtimeline-title { margin-bottom: 0; margin-right: 8px; min-width: 100px; }
}


/* ============================================================
 * I1842 — Cluster Status matrix (admin dashboard)
 * Row state colors + layer tiles + drill-down panel.
 * ============================================================ */

.row-state-green   { background: rgba(22, 163, 74, 0.10); }
/* I1889: WATCH tier — amber, between green and yellow.
   Operator's "trending toward bad" signal; never fires Telegram. */
.row-state-watch   { background: rgba(245, 158, 11, 0.10); }
.row-state-yellow  { background: rgba(217, 119, 6, 0.12); }
.row-state-red     { background: rgba(220, 38, 38, 0.14); }
.row-state-unknown { background: rgba(148, 163, 184, 0.10); }
.row-cascade-greyed { opacity: 0.4; pointer-events: none; }

.state-chip {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.state-chip-green   { background: var(--success); color: white; }
.state-chip-watch   { background: #f59e0b; color: white; }
.state-chip-yellow  { background: var(--warning); color: white; }
.state-chip-red     { background: var(--error); color: white; }
.state-chip-unknown { background: var(--text-muted); color: white; }

.layer-tile {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-left: 4px solid var(--text-muted);
  border-radius: var(--radius);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.layer-tile.layer-green   { border-left-color: var(--success); }
.layer-tile.layer-watch   { border-left-color: #f59e0b; }
.layer-tile.layer-yellow  { border-left-color: var(--warning); }
.layer-tile.layer-red     { border-left-color: var(--error); }
.layer-tile.layer-unknown { border-left-color: var(--text-muted); }
.layer-tile .layer-id {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--text-muted);
  letter-spacing: 0.06em;
}
.layer-tile .layer-name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
}
.layer-tile .layer-counts {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

.cluster-status-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.cluster-status-table th,
.cluster-status-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-color);
  text-align: left;
}
.cluster-status-table tr.cluster-status-row { cursor: pointer; }
.cluster-status-table tr.cluster-status-row:hover { background: var(--bg-card-hover); }

/* I1842 follow-up — host group header rows. Slightly elevated
   background, bold left-aligned host name, monospace muted summary. */
.cluster-status-table tr.host-group-header td {
  background: var(--bg-elevated, var(--bg-card));
  border-top: 2px solid var(--border-color);
  padding: 10px 12px;
  font-size: 0.95rem;
}
.cluster-status-table tr.host-group-header strong {
  font-family: ui-monospace, monospace;
  font-size: 0.95rem;
}

.drill-down-panel {
  background: var(--bg-elevated, var(--bg-card));
  border-left: 3px solid var(--accent);
  padding: 16px;
  font-size: 0.85rem;
}
.drill-down-panel pre {
  font-family: monospace;
  font-size: 0.8rem;
  white-space: pre-wrap;
  margin: 0;
  max-height: 400px;
  overflow: auto;
}
.drill-down-section { margin-bottom: 16px; }
.drill-down-section h4 {
  margin: 0 0 8px 0;
  font-size: 0.85rem;
  text-transform: uppercase;
  color: var(--text-muted);
  letter-spacing: 0.05em;
}
.criterion-row {
  display: flex;
  gap: 10px;
  padding: 4px 0;
  font-size: 0.85rem;
}
.criterion-pass { color: var(--success); }
.criterion-fail { color: var(--error); }

.cluster-status-filters {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
  margin: 12px 0;
}
.cluster-status-filters select,
.cluster-status-filters input[type="text"] {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  color: var(--text-primary);
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  font-size: 0.88rem;
}
.cluster-status-banner {
  margin: 8px 0 12px 0;
  padding: 10px 14px;
  border-radius: var(--radius);
  border-left: 4px solid var(--error);
  background: rgba(220, 38, 38, 0.10);
  color: var(--text-primary);
  font-size: 0.9rem;
}

/* I1857 — Active Symptoms panel. I1814: surface tokenized to
   --bg-elevated (was --bg-tertiary which is undefined). */
.symptom-card {
  display: grid;
  grid-template-columns: max-content max-content 1fr;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 6px;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--border-color);
  background: var(--bg-elevated);
  font-size: 0.88rem;
}
.symptom-card.symptom-red    { border-left-color: var(--error);   background: rgba(220, 38, 38, 0.08); }
.symptom-card.symptom-yellow { border-left-color: var(--warning); background: rgba(234, 179, 8, 0.08); }
.symptom-card.symptom-info   { border-left-color: var(--text-muted); }
.symptom-cat {
  font-weight: 600;
  font-family: var(--font-mono, monospace);
  color: var(--text-primary);
}
.symptom-sev {
  font-size: 0.72rem;
  text-transform: uppercase;
  padding: 1px 7px;
  border-radius: 999px;
  letter-spacing: 0.05em;
}
.symptom-sev-red    { background: var(--error);   color: #fff; }
.symptom-sev-yellow { background: var(--warning); color: #000; }
.symptom-sev-info   { background: var(--text-muted); color: var(--bg-primary); }
.symptom-evidence { color: var(--text-primary); }
.symptom-affected {
  grid-column: 1 / -1;
  font-size: 0.78rem;
  color: var(--text-muted);
  font-family: var(--font-mono, monospace);
  margin-top: 2px;
}
