:root {
  --bg: #07080B;          /* darker bg */
  --bg-elev: #0D0F13;     /* slate dark */
  --card: #0d1016;
  --card-hover: #12161e;
  --border: #1b2029;
  --text: #f0f2f5;
  --muted: #A1A7B3;       /* soft gray */
  --faint: #5c6470;
  --green: #39FF14;       /* toxic green — primary */
  --lime: #A4FF00;        /* acid lime — hover/active */
  --teal: #00E5C3;        /* cyber teal — accents/AI */
  --violet: #7B2CFF;      /* deep purple — info */
  --pink: #FF006E;        /* hot pink — danger */
  --orange: #FF9A00;      /* warning */
  --robinhood: #39FF14;
  --solana: #00E5C3;
}
* { box-sizing: border-box; }
/* ---------- app-feel: no text selection, no tap flash, no double-tap zoom ---------- */
body {
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;   /* kills the grey flash on every tap */
  -webkit-touch-callout: none;                /* kills the long-press "Copy/Look Up" sheet */
  touch-action: manipulation;                 /* kills the 300ms delay + double-tap zoom */
}
/* …but never break the things you actually need to select or type into. */
input, textarea, select, [contenteditable] { -webkit-user-select: text; user-select: text; }
/* Placeholders sit well back — they're a hint, not content. */
::placeholder { color: #4a515c; opacity: 1; }
::-webkit-input-placeholder { color: #4a515c; }
.waddr, .dv a, .rc-v, .xf, .dmuted a { -webkit-user-select: text; user-select: text; -webkit-touch-callout: default; }
/* iOS zooms the whole page whenever a focused input is under 16px. Every input is 16px on mobile. */
@media (max-width: 860px) {
  input, select, textarea, .search, .login-box input, .login-box select, .wallet-add input, .wallet-add select {
    font-size: 16px !important;
  }
}
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--text);
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; -webkit-font-smoothing: antialiased; }
/* One scrollbar treatment everywhere — the same green→teal thumb the modal uses. */
html { scrollbar-width: thin; scrollbar-color: var(--green) transparent; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: linear-gradient(var(--green), var(--teal)); border-radius: 20px; border: 2px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: linear-gradient(var(--lime), var(--green)); }
::-webkit-scrollbar-corner { background: transparent; }
a { color: inherit; text-decoration: none; }
/* TYPOGRAPHY CONVENTION (one rule, applied everywhere):
   · Interactive things (buttons, chips, nav, inputs) = Inter, Title Case, no letter-spacing.
   · Micro-metadata / status tokens (stat keys, verdicts, pills, section heads) = UPPERCASE via CSS
     text-transform with the shared --track below — never typed in caps in the markup.
   Orbitron is reserved for numbers + status tokens, so it stays a "readout" font, not a UI font. */
:root { --track: 0.08em; }
.score .gn, .stat .v, .verdict, .dhdr, .modal-head, h1, h2 {
  font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; }
.wrap { max-width: 1180px; margin: 0 auto; padding: 18px 16px 90px; }

/* ---------- sidebar layout ---------- */
.app { display: flex; min-height: 100vh; align-items: stretch; }

/* ---------- boot splash ---------- */
.splash { position: fixed; inset: 0; z-index: 4000; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 16px; padding: env(safe-area-inset-top) 24px 0;
  background: radial-gradient(130% 90% at 50% 38%, #0e1319 0%, var(--bg) 68%);
  transition: opacity 0.45s ease, visibility 0.45s ease; }
.splash-logo { width: min(230px, 56vw); height: auto;
  filter: drop-shadow(0 0 26px rgba(57,255,20,0.22)); animation: splashFloat 2.4s ease-in-out infinite; }
.splash-tag { font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-size: 10.5px;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--faint); }
.splash-bar { width: 132px; height: 3px; border-radius: 3px; background: rgba(255,255,255,0.06); overflow: hidden; }
.splash-bar span { display: block; width: 40%; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, transparent, var(--green), transparent); animation: splashSweep 1.1s ease-in-out infinite; }
.splash.hide { opacity: 0; visibility: hidden; pointer-events: none; }
@keyframes splashFloat { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes splashSweep { 0% { transform: translateX(-140%); } 100% { transform: translateX(340%); } }
@media (prefers-reduced-motion: reduce) { .splash-logo, .splash-bar span { animation: none; } }

/* ---------- mobile install gate (assets/pwa-gate.js) ----------
   On a phone the browser page is not the product. pwa-gate.js stamps `pwa-gated` on <html> from
   <head> — before first paint — and these rules blank the shell behind the wall so nothing of the
   app leaks through. Desktop never gets the class, so it never sees any of this. */
html.pwa-gated, html.pwa-gated body { overflow: hidden; height: 100%; }
html.pwa-gated body > *:not(.pwa-gate) { display: none !important; }
.pwa-gate {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; text-align: center;
  padding: 28px 24px calc(28px + env(safe-area-inset-bottom));
  background:
    radial-gradient(120% 70% at 50% 0%, rgba(57,255,20,0.10), transparent 62%),
    linear-gradient(180deg, #0B0E13, #07080B 60%);
  overflow-y: auto;
}
.pwa-gate .pg-logo { width: min(232px, 62vw); margin-bottom: 2px;
  filter: drop-shadow(0 0 26px rgba(57,255,20,0.22)); }
.pwa-gate .pg-title { font-family: Orbitron, ui-sans-serif, system-ui, sans-serif;
  font-weight: 900; font-size: 25px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text); margin: 0; }
.pwa-gate .pg-sub { max-width: 340px; margin: 0; font-size: 14px; line-height: 1.55; color: var(--muted); }
.pwa-gate .pg-sub b { color: var(--text); font-weight: 700; }
.pwa-gate .pg-cta { margin-top: 6px; display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  border: none; border-radius: 13px; padding: 15px 26px;
  font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-weight: 800; font-size: 14px;
  letter-spacing: 0.05em; background: var(--green); color: #07080B;
  box-shadow: 0 0 26px rgba(57,255,20,0.34); }
.pwa-gate .pg-cta svg { width: 18px; height: 18px; }
.pwa-gate .pg-cta:disabled { opacity: 0.6; }
.pwa-gate .pg-cta.pg-ghost { background: transparent; color: var(--green);
  border: 1px solid rgba(57,255,20,0.45); box-shadow: none; }
.pwa-gate .pg-steps { list-style: none; margin: 6px 0 0; padding: 0; width: min(340px, 100%);
  display: flex; flex-direction: column; gap: 10px; text-align: left; }
.pwa-gate .pg-steps li { display: flex; align-items: flex-start; gap: 11px;
  font-size: 13.5px; line-height: 1.5; color: var(--muted);
  background: rgba(255,255,255,0.03); border: 1px solid var(--border);
  border-radius: 12px; padding: 12px 13px; }
.pwa-gate .pg-steps b { color: var(--text); font-weight: 700; }
.pwa-gate .pg-n { flex: 0 0 auto; width: 21px; height: 21px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-weight: 800; font-size: 11px;
  background: rgba(57,255,20,0.14); color: var(--green); }
.pwa-gate .pg-ico { display: inline-flex; vertical-align: -4px; color: var(--green); }
.pwa-gate .pg-ico svg { width: 16px; height: 16px; }
.pwa-gate .pg-foot { margin: 4px 0 0; font-size: 11.5px; color: var(--faint); }
.sidebar { width: 214px; flex-shrink: 0; border-right: 1px solid var(--border); padding: 16px 12px; display: flex; flex-direction: column; gap: 4px; position: sticky; top: 0; height: 100vh; background: var(--bg); }
.side-logo { width: 100%; max-width: 176px; margin: 4px auto 14px; display: block; }
.side-nav { display: flex; flex-direction: column; gap: 2px; }
/* Sidebar labels use the same Orbitron face as the page title, and sit brighter than the old
   muted grey — the nav was reading as disabled rather than as navigation. */
.nav-item { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 9px;
  color: #c8cedb; font-size: 12px; font-weight: 600; cursor: pointer; border: 0; background: transparent;
  text-align: left; width: 100%; font-family: Orbitron, ui-sans-serif, system-ui, sans-serif;
  letter-spacing: 0.02em; }
.nav-item span { white-space: nowrap; }
.nav-item:hover { background: var(--bg-elev); color: var(--text); }
.nav-item.active { background: rgba(57,255,20,0.1); color: var(--green); box-shadow: inset 0 0 0 1px rgba(57,255,20,0.3); }
.nav-item.soon { opacity: 0.38; cursor: default; }
.nav-item.soon:hover { background: transparent; color: var(--muted); }
.nav-item.soon::after { content: 'soon'; margin-left: auto; font-size: 8px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--faint); border: 1px solid var(--border); padding: 1px 5px; border-radius: 5px; }
.badge { margin-left: auto; background: var(--green); color: #04120a; border-radius: 10px; padding: 0 7px; font-size: 10px; font-weight: 800; font-family: Orbitron; min-width: 18px; text-align: center; }
.badge:empty { display: none; }
.side-foot { margin-top: auto; display: flex; flex-direction: column; gap: 2px; padding-top: 10px; border-top: 1px solid var(--border); }
.main { flex: 1; min-width: 0; padding: 16px 22px 90px; }
.tag .g { color: var(--green); }
.star-btn { border: 0; background: transparent; cursor: pointer; font-size: 13px; color: var(--faint); font-weight: 600; padding: 0; }
.star-btn.on, .star-btn:hover { color: var(--green); }

/* ---------- wallet tracker ---------- */
.wallet-add { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; align-items: center; }
.wallet-add select, .wallet-add input { background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px; padding: 9px 12px; color: var(--text); font-size: 13px; font-family: Inter; }
.wallet-add input { flex: 1; min-width: 180px; }
.wallet-add input:focus, .wallet-add select:focus { outline: none; border-color: rgba(57,255,20,0.5); }
.wallet-add .btn { padding: 9px 16px; }
/* The chain <select> is replaced by the custom dropdown (the iOS picker sheet can't be themed), so
   the wrapper has to hold the same slot in the flex row the native control did. */
.wallet-add .dd { flex: 0 0 auto; }
.wallet-add .dd-btn { padding: 9px 12px; border-radius: 9px; font-size: 13px; }
.wallet-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 12px; }
.wallet-card { background: var(--card); border: 1px solid var(--border); border-radius: 14px; padding: 14px; }
.wallet-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.wchain { width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center; font-size: 16px; flex-shrink: 0; }
.wchain.robinhood { background: rgba(57,255,20,0.1); }
.wchain.solana { background: rgba(0,229,195,0.1); }
.wid { min-width: 0; flex: 1; }
.wlabel { font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.waddr { font-size: 11px; color: var(--faint); font-family: Orbitron; }
.waddr:hover { color: var(--teal); }
.wlast { font-size: 10px; color: var(--faint); white-space: nowrap; }
.wremove { border: 0; background: transparent; color: var(--faint); cursor: pointer; font-size: 14px; padding: 2px 4px; }
.wremove:hover { color: var(--pink); }
.wbuys { display: flex; flex-wrap: wrap; gap: 6px; }
.wbuy { display: inline-flex; align-items: center; gap: 6px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 7px; padding: 4px 9px; font-size: 12px; font-weight: 700; }
.wbuy:hover { border-color: rgba(57,255,20,0.4); color: var(--green); }
.wbuy .wtime { color: var(--faint); font-weight: 400; font-size: 10px; }
.wnote { font-size: 12px; color: var(--faint); line-height: 1.5; }
/* nav icons + chain dots (replace emoji) */
.ni { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
.nav-item.active .ni { stroke: var(--green); }
.nav-item:hover .ni { stroke: var(--text); }
.cdot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 7px; vertical-align: middle; }
.cdot.rh { background: var(--green); box-shadow: 0 0 6px var(--green); }
.cdot.sol { background: #a855f7; box-shadow: 0 0 6px #a855f7; }
.tickdot { width: 15px; height: 15px; border-radius: 50%; display: inline-block; }
.tickdot.rh { background: var(--green); box-shadow: 0 0 8px var(--green); }
.tickdot.sol { background: #a855f7; box-shadow: 0 0 8px #a855f7; }
.mobile-top { display: none; }
.nav-overlay { display: none; }
.nav-overlay.show { display: block; position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 55; }

@media (max-width: 860px) {
  .app { flex-direction: column; }
  /* Mobile: a fixed top bar with a burger that slides the sidebar in as a left drawer. */
  .mobile-top { display: flex; align-items: center; gap: 12px; position: sticky; top: 0; z-index: 40; background: var(--bg); border-bottom: 1px solid var(--border); padding: calc(9px + env(safe-area-inset-top, 0px)) 14px 9px; }
  .burger { background: transparent; border: 1px solid var(--border); border-radius: 9px; padding: 6px 8px; color: var(--text); cursor: pointer; display: inline-flex; }
  .burger .ni { width: 22px; height: 22px; }
  .mtop-logo { height: 30px; }
  .sidebar { position: fixed; top: 0; left: 0; bottom: 0; width: 240px; height: auto; z-index: 60; flex-direction: column; align-items: stretch; border-right: 1px solid var(--border); border-bottom: 0; padding: calc(18px + env(safe-area-inset-top, 0px)) 14px 18px; gap: 4px; overflow-y: auto; transform: translateX(-100%); transition: transform 0.22s ease; background: var(--bg); }
  .sidebar.open { transform: translateX(0); box-shadow: 0 0 44px rgba(0,0,0,0.65); }
  .side-logo { width: 150px; margin: 0 auto 14px; }
  .side-nav { flex-direction: column; gap: 2px; }
  .side-foot { margin-top: auto; border-top: 1px solid var(--border); padding-top: 10px; flex-direction: column; gap: 2px; }
  .nav-item { padding: 11px 12px; font-size: 14px; }
  .nav-item.soon { display: none; }
  .main { padding: 14px 14px 90px; }
}

/* ---------- header: row 1 = one title + status, row 2 = toolbar (search first) ---------- */
.header { display: flex; flex-direction: column; gap: 12px; padding: 6px 0 16px; border-bottom: 1px solid var(--border); margin-bottom: 18px; }
.head-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.page-title { margin: 0; font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-size: 19px;
  font-weight: 800; letter-spacing: 0.02em; color: var(--text); line-height: 1.2; }
/* status pill — reads as one calm unit instead of loose text */
.live { display: inline-flex; align-items: center; gap: 7px; margin-left: auto; font-size: 11.5px; color: var(--muted);
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px 5px 10px; }
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 10px var(--green); animation: pulse 1.6s infinite; }
.dot.stale { background: var(--faint); box-shadow: none; animation: none; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }
.spacer { flex: 1; }
.logout { color: var(--muted); font-size: 11px; }
.logout:hover { color: var(--pink); }

/* ---------- controls / toolbar ---------- */
.toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.searchwrap { position: relative; display: flex; flex: 1 1 300px; min-width: 0; }
.toolbar .searchwrap .search { flex: 1; width: auto; max-width: none; min-width: 0; padding-right: 42px; } /* room for Go */
/* Explicit Go button — on mobile the on-screen keyboard's return key doesn't reliably fire Enter. */
.searchgo { position: absolute; right: 5px; top: 50%; transform: translateY(-50%); width: 30px; height: 30px;
  display: grid; place-items: center; border: 0; border-radius: 7px; cursor: pointer;
  background: rgba(57,255,20,0.1); color: var(--green); transition: 0.15s; }
.searchgo svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.searchgo:hover { background: rgba(57,255,20,0.2); }
.searchgo:active { transform: translateY(-50%) scale(0.92); }
.chips { display: inline-flex; gap: 4px; background: var(--bg-elev); padding: 4px; border-radius: 10px; border: 1px solid var(--border); }
.chip { border: 0; background: transparent; color: var(--muted); padding: 6px 12px; border-radius: 7px; font-size: 12px;
  cursor: pointer; font-weight: 600; font-family: Inter, ui-sans-serif, system-ui, sans-serif; transition: 0.12s;
  display: inline-flex; align-items: center; gap: 6px; }
.chip:hover { color: var(--text); }
.chip.on { background: rgba(57,255,20,0.12); color: var(--green); box-shadow: inset 0 0 0 1px rgba(57,255,20,0.35); }
.slider { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
.slider input { accent-color: var(--green); }
/* ---------- collapsible filter panel ----------
   Desktop has room, so the panel is simply always open and the toggle is hidden. On a phone the
   slider + eight pills + presets ran to roughly a full screen height BEFORE the first coin, so they
   collapse behind one button. */
.filtoggle { display: inline-flex; align-items: center; gap: 8px; background: var(--bg-elev);
  border: 1px solid var(--border); border-radius: 10px; padding: 9px 12px; cursor: pointer;
  color: var(--text); font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 12px;
  font-weight: 700; letter-spacing: var(--track); text-transform: uppercase; transition: 0.14s; }
.filtoggle .fi { width: 15px; height: 15px; flex: none; fill: none; stroke: var(--faint);
  stroke-width: 2; stroke-linecap: round; }
.filtoggle .fchev { width: 10px; height: 6px; flex: none; margin-left: auto; transition: transform 0.18s; }
.filtoggle .fchev path { stroke: var(--faint); stroke-width: 1.6; fill: none; stroke-linecap: round; }
.filtoggle.open { border-color: rgba(57,255,20,0.5); background: rgba(57,255,20,0.06); }
.filtoggle.open .fchev { transform: rotate(180deg); }
.filtoggle.open .fi, .filtoggle.has .fi { stroke: var(--green); }
/* Active-filter count — so a collapsed panel can never hide the fact that the feed is filtered. */
.fcount { display: grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px; background: var(--green); color: #06210a; font-size: 10px; font-weight: 800;
  letter-spacing: 0; }
/* An explicit display beats the `hidden` attribute, so the badge rendered a literal "0". */
.fcount[hidden] { display: none; }

/* "as of 3h ago" — a market figure that hasn't been re-confirmed recently must not read like a live
   one. Quiet by default; amber once the data is old enough that liquidity could already be gone. */
.stale { margin-left: 8px; padding: 1px 6px; border-radius: 5px; font-size: 10px; font-weight: 700;
  letter-spacing: 0.02em; color: var(--faint); background: rgba(255,255,255,0.04); }
.stale.bad { color: var(--orange); background: rgba(255,154,0,0.1); }

/* Score curve under the gauge — direction is carried by colour so it reads at a glance without
   needing to trace the line. Flat stays neutral rather than pretending to be a trend. */
.spark { display: block; margin: 5px auto 0; max-width: 100%; }
.score { min-width: 0; }   /* let the sparkline shrink instead of pushing the card wider */
.spark polyline { fill: none; stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke; }
.spark circle { stroke: none; }
.spark.up   polyline { stroke: var(--green); }  .spark.up   circle { fill: var(--green); }
.spark.down polyline { stroke: var(--pink); }   .spark.down circle { fill: var(--pink); }
.spark.flat polyline { stroke: var(--faint); }  .spark.flat circle { fill: var(--faint); }
/* Collapsed by default at EVERY width — desktop used to splay all nine dropdowns permanently across
   the top, which read as clutter. Now the toolbar stays clean (search · chains · Filters · Alerts)
   and the panel opens on demand; the count badge keeps a filtered-but-collapsed feed honest. */
.filterpanel { display: none; }
.filterpanel.open { display: block; animation: fpan 0.18s ease-out; }
/* The min-score slider moved in here from the toolbar so every filtering control lives in one place
   (and so it collapses with the rest on mobile). */
.filterpanel .slider { margin: 0 0 10px; }
@keyframes fpan { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .filterpanel.open { animation: none; } }

/* Eight filters is too many for one line — a fixed 4-up grid puts them on two even rows instead of
   wrapping raggedly, and every pill ends up the same width. */
.filters { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; align-items: stretch; margin: 0 0 16px; }
.filters .dd, .filters .dd .dd-btn { width: 100%; }
.filters .dd-btn { justify-content: space-between; }
.filters label { display: inline-flex; align-items: center; gap: 9px; background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 10px; padding: 7px 12px 7px 13px; font-size: 9px; color: var(--faint); font-weight: 700;
  letter-spacing: var(--track); text-transform: uppercase; font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  transition: 0.14s; cursor: pointer; }
.filters label:hover { border-color: rgba(57,255,20,0.3); }
.filters label:has(select.on) { border-color: rgba(57,255,20,0.5); background: rgba(57,255,20,0.07); box-shadow: 0 0 10px rgba(57,255,20,0.12); }
.filters select { appearance: none; -webkit-appearance: none; background: transparent; border: 0; color: var(--text); font-size: 12px; font-weight: 700; font-family: Inter; cursor: pointer; padding-right: 15px; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' stroke='%23A1A7B3' stroke-width='1.5' fill='none' stroke-linecap='round'/></svg>"); background-repeat: no-repeat; background-position: right center; }
.filters select:focus { outline: none; }
.filters select.on { color: var(--green); }

/* ---------- custom dropdown (replaces the OS-rendered <select> menu) ----------
   The native closed state was already styled, but the OPEN list is drawn by the OS and can't be
   themed — grey-on-white in the middle of a neon-dark app. The real <select> stays in the DOM,
   hidden, so every existing handler + the saved-filter restore keep working unchanged. */
/* The <label> is REPLACED by .dd (a label would re-open the native picker on tap), so .dd inherits
   the layout the label used to provide inside the .filters row. */
.filters .dd { flex: 1 1 auto; }
.dd { position: relative; display: inline-flex; }
.dd > select { position: absolute; opacity: 0; pointer-events: none; width: 1px; height: 1px; }
.dd-btn { display: inline-flex; align-items: center; gap: 9px; background: var(--bg-elev);
  border: 1px solid var(--border); border-radius: 10px; padding: 7px 11px 7px 13px; cursor: pointer;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif; transition: 0.14s; color: var(--text); }
.dd-btn:hover { border-color: rgba(57,255,20,0.3); }
.dd-btn .dd-k { font-size: 9px; font-weight: 700; letter-spacing: var(--track); text-transform: uppercase; color: var(--faint); }
/* Long values (launchpad names carry a count) must not wrap — a two-line value made that one pill
   taller than the rest and broke the grid's alignment. Truncate instead; the full name is in the
   open panel and the title attribute. */
.dd-btn .dd-v { font-size: 12px; font-weight: 700; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; min-width: 0; }
.dd-btn { min-width: 0; }
.dd-btn .dd-c { margin-left: 2px; width: 10px; height: 6px; flex: none; transition: transform 0.18s; }
.dd-btn .dd-c path { stroke: var(--faint); stroke-width: 1.6; fill: none; stroke-linecap: round; }
.dd.open .dd-btn { border-color: rgba(57,255,20,0.5); background: rgba(57,255,20,0.06); }
.dd.open .dd-c { transform: rotate(180deg); }
.dd.on .dd-btn { border-color: rgba(57,255,20,0.45); background: rgba(57,255,20,0.07); box-shadow: 0 0 10px rgba(57,255,20,0.1); }
.dd.on .dd-v { color: var(--green); }

.dd-panel { position: absolute; top: calc(100% + 6px); left: 0; min-width: 100%; z-index: 70;
  background: #0c0f15; border: 1px solid #232a36; border-radius: 11px; padding: 5px;
  box-shadow: 0 18px 44px rgba(0,0,0,0.75); display: none; max-height: 300px; overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--green) transparent; }
.dd.open .dd-panel { display: block; animation: ddin 0.14s ease-out; }
@keyframes ddin { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.dd-opt { display: flex; align-items: center; justify-content: space-between; gap: 14px; white-space: nowrap;
  padding: 8px 11px; border-radius: 7px; font-size: 12.5px; color: var(--muted); cursor: pointer; }
.dd-opt:hover { background: rgba(255,255,255,0.05); color: var(--text); }
.dd-opt.sel { color: var(--green); background: rgba(57,255,20,0.09); }
.dd-opt.sel::after { content: '✓'; font-size: 11px; }
@media (max-width: 860px) { .dd, .dd-btn { width: 100%; } .dd-btn { justify-content: space-between; } }
.search { background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px; padding: 10px 12px;
  color: var(--text); font-size: 15px; font-family: Inter, ui-sans-serif, system-ui, sans-serif; width: 220px; }
.search::placeholder { color: var(--faint); }
.search:focus { outline: none; border-color: rgba(57,255,20,0.5); box-shadow: 0 0 0 3px rgba(57,255,20,0.08); }
.btn { border: 1px solid rgba(57,255,20,0.4); background: rgba(57,255,20,0.08); color: var(--green); padding: 8px 14px;
  border-radius: 9px; font-size: 12.5px; font-weight: 600; font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  cursor: pointer; transition: 0.12s; }
.btn:hover { background: rgba(57,255,20,0.16); box-shadow: 0 0 12px rgba(57,255,20,0.25); }
.btn.on { color: var(--green); border-color: rgba(57,255,20,0.6); cursor: default; }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.hint { width: 100%; font-size: 12px; color: var(--orange); background: rgba(255,154,0,0.08); border: 1px solid rgba(255,154,0,0.3); border-radius: 8px; padding: 8px 10px; }

/* Mobile: the toolbar stacks — search gets its own full-width line, then the rest. */
@media (max-width: 860px) {
  .page-title { font-size: 17px; }
  .head-row { gap: 10px; }
  .toolbar .search { flex: 1 1 100%; }
  .toolbar .chips { flex: 1 1 100%; justify-content: center; }
  /* Filters + Alerts share one row instead of each taking a full-width line. */
  .filtoggle { display: inline-flex; flex: 1 1 0; min-width: 0; justify-content: flex-start; }
  .toolbar .btn { flex: 1 1 0; min-width: 0; }
  /* Collapsed by default on phones — .open is set by the toggle and restored from saved UI state. */
  .filterpanel { display: none; }
  .filterpanel.open { display: block; animation: fpan 0.18s ease-out; }
  .filterpanel .slider { display: flex; width: 100%; justify-content: space-between;
    margin: 0 0 10px; gap: 10px; }
  .filterpanel .slider input { flex: 1; }
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; } /* 2-up on phones */
  .filters label { justify-content: space-between; }
}

/* ---------- in-app dialog (replaces window.prompt / confirm) ---------- */
.modal.ask { max-width: 380px; padding: 22px 22px 18px; }
.ask-t { font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-size: 15px; font-weight: 700; margin-bottom: 6px; }
.ask-b { font-size: 12.5px; color: var(--muted); line-height: 1.5; margin-bottom: 14px; }
.ask-i { width: 100%; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px;
  padding: 11px 12px; color: var(--text); font-size: 15px; font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  margin: 8px 0 16px; }
.ask-i:focus { outline: none; border-color: rgba(57,255,20,0.5); box-shadow: 0 0 0 3px rgba(57,255,20,0.08); }
.ask-row { display: flex; gap: 8px; justify-content: flex-end; }
.ask-row button { border-radius: 9px; padding: 9px 18px; font-size: 13px; font-weight: 600; cursor: pointer;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif; transition: 0.14s; }
.ask-no { background: transparent; border: 1px solid var(--border); color: var(--muted); }
.ask-no:hover { color: var(--text); border-color: var(--faint); }
.ask-yes { background: var(--green); border: 0; color: #07080B; }
.ask-yes:hover { background: var(--lime); }
.ask-yes.danger { background: var(--pink); color: #fff; }
.ask-yes.danger:hover { background: #ff3d8b; }
/* the ask sheet stays a centred card even on mobile, unlike the full-height Investigate modal */
@media (max-width: 860px) {
  .ask-bg { padding: 16px; place-items: center; }
  .modal.ask { margin-top: 0; height: auto; max-height: none; border-radius: 16px;
    border: 1px solid var(--border); width: 100%; }
}

/* ---------- saved filter presets ---------- */
.presets { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 16px; }
.presets .pl { font-size: 9px; font-weight: 700; letter-spacing: var(--track); text-transform: uppercase;
  color: #41474f; margin-right: 2px; }
.preset { display: inline-flex; align-items: center; gap: 7px; background: var(--bg-elev);
  border: 1px solid var(--border); border-radius: 999px; padding: 5px 6px 5px 12px; font-size: 12px;
  color: var(--muted); cursor: pointer; transition: 0.14s; font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
.preset:hover { color: var(--text); border-color: rgba(57,255,20,0.35); }
.preset.on { color: var(--green); border-color: rgba(57,255,20,0.5); background: rgba(57,255,20,0.08); }
.preset .px { display: grid; place-items: center; width: 17px; height: 17px; border-radius: 50%;
  color: var(--faint); font-size: 13px; line-height: 1; }
.preset .px:hover { background: rgba(255,0,110,0.15); color: var(--pink); }
.preset-save { display: inline-flex; align-items: center; gap: 6px; background: transparent;
  border: 1px dashed var(--border); border-radius: 999px; padding: 5px 12px; font-size: 12px;
  color: var(--faint); cursor: pointer; font-family: Inter, ui-sans-serif, system-ui, sans-serif; transition: 0.14s; }
.preset-save:hover { color: var(--green); border-color: rgba(57,255,20,0.4); }

/* ---------- feed ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 12px; }
.empty { color: var(--faint); padding: 60px 0; text-align: center; font-size: 14px; }
/* first-load spinner — the feed waits for its data instead of jumping in half-rendered */
.spin { display: inline-block; width: 17px; height: 17px; border-radius: 50%; vertical-align: -3px;
  border: 2px solid var(--border); border-top-color: var(--green); animation: spin 0.7s linear infinite; }
.spin-t { margin-left: 10px; color: var(--faint); }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 2.4s; } }
.card { background: var(--card); border: 1px solid var(--border); border-radius: 14px; padding: 14px; display: flex; flex-direction: column; gap: 10px; transition: 0.12s; position: relative; overflow: hidden; }
.card:hover { background: var(--card-hover); border-color: #2a3140; }
.card.pass { border-left: 3px solid var(--green); }
.card.watch { border-left: 3px solid var(--orange); }
.card.reject { border-left: 3px solid var(--pink); }
.card.pending { border-left: 3px solid var(--faint); }
.card.weak { border-left: 3px solid rgba(255,154,0,0.35); }
.card.focus { box-shadow: 0 0 0 2px var(--green); animation: focuspulse 1s ease-out 3; }
@keyframes focuspulse {
  0% { box-shadow: 0 0 0 2px var(--green), 0 0 0 0 rgba(57,255,20,0.55); }
  100% { box-shadow: 0 0 0 2px var(--green), 0 0 0 14px rgba(57,255,20,0); }
}
@media (prefers-reduced-motion: reduce) { .card.focus { animation: none; } }
.card-top { display: flex; align-items: flex-start; gap: 10px; }
.tick { width: 42px; height: 42px; border-radius: 10px; flex-shrink: 0; background: var(--bg-elev); display: grid; place-items: center; font-size: 18px; overflow: hidden; border: 1px solid var(--border); }
.tick img { width: 100%; height: 100%; object-fit: cover; }
.idwrap { min-width: 0; flex: 1; }
.sym { font-weight: 800; font-size: 16px; display: flex; align-items: center; gap: 6px; }
.sym .name { color: var(--muted); font-weight: 500; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chainpill { font-size: 9px; padding: 2px 6px; border-radius: 5px; font-weight: 800; text-transform: uppercase; letter-spacing: var(--track); font-family: Orbitron; }
.chainpill.robinhood { color: var(--green); background: rgba(57,255,20,0.1); }
.chainpill.solana { color: var(--teal); background: rgba(0,229,195,0.1); }

/* circular score gauge */
.score { margin-left: auto; text-align: center; flex-shrink: 0; }
.gauge { position: relative; width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center; margin: 0 auto;
  background: conic-gradient(var(--gc) calc(var(--pct) * 1%), var(--bg-elev) 0); }
.gauge::before { content: ''; position: absolute; inset: 4px; border-radius: 50%; background: var(--card); }
.card:hover .gauge::before { background: var(--card-hover); }
.gauge .gn { position: relative; font-weight: 800; font-size: 15px; }
.score .l { font-size: 8px; color: var(--faint); letter-spacing: var(--track); text-transform: uppercase; margin-top: 3px; }
/* provisional score — deep checks (holder concentration) haven't run yet */
.score .l.prov { color: var(--orange); }
.gauge.prov { opacity: 0.72; }
.gauge.prov .gn { color: var(--muted) !important; }
.s-hi { color: var(--green); text-shadow: 0 0 10px rgba(57,255,20,0.5); }
.s-mid { color: var(--orange); }
.s-lo { color: var(--pink); }
.s-min { color: var(--faint); }

.verdict { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 800; letter-spacing: var(--track); padding: 3px 9px; border-radius: 6px; text-transform: uppercase; }
.verdict.PASS { color: var(--green); background: rgba(57,255,20,0.1); box-shadow: inset 0 0 0 1px rgba(57,255,20,0.4); }
.verdict.WATCH { color: var(--orange); background: rgba(255,154,0,0.1); box-shadow: inset 0 0 0 1px rgba(255,154,0,0.4); }
.verdict.REJECT { color: var(--pink); background: rgba(255,0,110,0.1); box-shadow: inset 0 0 0 1px rgba(255,0,110,0.4); }
.verdict.SCAN { color: var(--muted); background: rgba(161,167,179,0.08); box-shadow: inset 0 0 0 1px var(--border); }
/* WEAK = passed every security check, but scores low (usually just young/thin). Deliberately calm:
   red is reserved for a coin that actually FAILED a check, so this must not read as an alarm. */
.verdict.WEAK { color: var(--muted); background: rgba(161,167,179,0.07); box-shadow: inset 0 0 0 1px rgba(255,154,0,0.22); }

.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.stat { background: var(--bg-elev); border-radius: 8px; padding: 6px 8px; }
.stat .k { font-size: 9px; color: var(--faint); text-transform: uppercase; letter-spacing: var(--track); }
.stat .v { font-size: 13px; font-weight: 700; }
.up { color: var(--green); } .down { color: var(--pink); }
/* No pills. Risk reads as one quiet line with a leading marker — calmer and easier to scan. */
.warns { display: flex; flex-direction: column; gap: 3px; }
.warn, .fail { font-size: 11px; line-height: 1.35; display: flex; align-items: baseline; gap: 6px; }
.warn { color: var(--orange); }
.fail { color: var(--pink); font-weight: 600; }
.warn::before, .fail::before { flex: none; font-weight: 700; opacity: 0.85; }
.warn::before { content: '!'; }
.fail::before { content: '×'; }
/* ---------- card footer: quiet meta row + full-width segmented action bar ---------- */
.card-meta { display: flex; align-items: center; gap: 10px; min-width: 0; }
.card-foot { display: flex; border-top: 1px solid var(--border); padding-top: 10px; margin-top: 2px; }
.fspacer { flex: 1; }

/* social marks — icon squares, dimmed when the coin doesn't have that link */
.socials { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.socials .soc { width: 29px; height: 29px; border-radius: 8px; border: 1px solid var(--border); display: inline-flex;
  align-items: center; justify-content: center; color: var(--muted); background: rgba(255,255,255,0.015);
  text-decoration: none; transition: 0.18s; }
.socials .soc svg { width: 14px; height: 14px; }
.socials .soc:hover { color: var(--text); border-color: var(--faint); background: rgba(255,255,255,0.05); }
.socials .soc.off { opacity: 0.3; cursor: default; }
.socials .soc.off:hover { color: var(--muted); border-color: var(--border); background: rgba(255,255,255,0.015); }

/* the action bar — Investigate is the hero, Save/Share are icon segments */
.seg { display: flex; align-items: stretch; width: 100%; border: 1px solid var(--border); border-radius: 10px;
  overflow: hidden; background: rgba(255,255,255,0.02); }
.seg .hero { flex: 1; min-width: 0; justify-content: center;
  font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-weight: 700; font-size: 11px;
  letter-spacing: 0.1em; padding: 0 14px; height: 34px; display: inline-flex; align-items: center; gap: 7px;
  border: 0; cursor: pointer; color: var(--muted); transition: 0.2s; white-space: nowrap;
  /* The hero is the left-most element of the rounded .seg; without matching its LEFT corners to the
     container's inner radius, the new inset-border corners get clipped square by the seg's
     overflow:hidden and read as "cut off". Right corners stay square — they butt against the icons. */
  border-radius: 9px 0 0 9px; }
.seg .hero svg { width: 14px; height: 14px; }
.seg .ico { width: 34px; border: 0; border-left: 1px solid var(--border); background: transparent; color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer; transition: 0.18s; padding: 0; }
.seg .ico svg { width: 15px; height: 15px; }
.seg .ico:hover { color: var(--text); background: rgba(255,255,255,0.06); }
.seg .ico.saved { color: var(--green); }
.seg .ico.copy-btn:hover { color: var(--teal); }
/* hero colour follows the verdict — a calm tinted fill + coloured text, not a solid neon slab
   (the toxic-green block read as "too much"; this keeps the verdict language, dialled down). */
.card.pass   .seg .hero { background: rgba(57,255,20,0.09); color: var(--green); box-shadow: inset 0 0 0 1px rgba(57,255,20,0.32); }
.card.pass   .seg .hero:hover { background: rgba(57,255,20,0.17); }
.card.watch  .seg .hero { background: rgba(255,154,0,0.09); color: var(--orange); box-shadow: inset 0 0 0 1px rgba(255,154,0,0.32); }
.card.watch  .seg .hero:hover { background: rgba(255,154,0,0.17); }
.card.reject .seg .hero { background: transparent; color: var(--pink); }
.card.reject .seg .hero:hover { background: rgba(255,0,110,0.12); }
.card.weak .seg .hero { background: transparent; color: var(--muted); }
.card.weak .seg .hero:hover { color: var(--text); background: rgba(255,255,255,0.05); }
.card.pending .seg .hero { background: transparent; color: var(--muted); }
.card.pending .seg .hero:hover { color: var(--text); background: rgba(255,255,255,0.05); }

/* secondary chart links — demoted into the quiet meta row. Nothing may be clipped: the dex name
   ellipsises, the links never shrink. */
.ext { display: inline-flex; align-items: center; gap: 3px; min-width: 0; }
.ext .lead { font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-size: 9px; letter-spacing: 0.14em;
  color: #41474f; margin-right: 2px; text-transform: uppercase;
  max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ext a { flex: none; }
.ext a { font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-size: 9.5px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--faint); text-decoration: none; padding: 3px 6px; border-radius: 5px;
  display: inline-flex; align-items: center; gap: 4px; transition: 0.18s; }
.ext a svg { width: 10px; height: 10px; }
.ext a:hover { color: var(--muted); background: rgba(255,255,255,0.03); }
.ext .div { width: 1px; height: 11px; background: var(--border); }

/* toast */
.toast { position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%) translateY(20px); opacity: 0;
  background: var(--card); border: 1px solid rgba(0,229,195,0.5); color: var(--teal); padding: 10px 18px; border-radius: 10px;
  font-size: 13px; font-weight: 700; z-index: 80; transition: 0.22s; box-shadow: 0 8px 30px rgba(0,0,0,0.5); pointer-events: none; }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- modal / dossier ---------- */
/* z-index must clear the mobile nav overlay (55) and drawer (60), or they'd render over the modal */
.modal-bg { position: fixed; inset: 0; background: rgba(0,0,0,0.75); display: grid; place-items: center; padding: 16px; z-index: 90; backdrop-filter: blur(3px); }
/* the page behind the modal must not scroll while it's open */
body.modal-open { overflow: hidden; }
.modal { background: var(--card); border: 1px solid var(--border); border-radius: 16px; width: 100%; max-width: 460px; max-height: 88vh; overflow-y: auto; overscroll-behavior: contain; padding: 16px 18px 18px; box-shadow: 0 20px 60px rgba(0,0,0,0.7);
  scrollbar-width: thin; scrollbar-color: var(--green) transparent; }
/* sexy scrollbar */
.modal::-webkit-scrollbar { width: 9px; }
.modal::-webkit-scrollbar-track { background: transparent; margin: 6px 0; }
.modal::-webkit-scrollbar-thumb { background: linear-gradient(var(--green), var(--teal)); border-radius: 20px; border: 2px solid var(--card); }
.modal::-webkit-scrollbar-thumb:hover { background: linear-gradient(var(--lime), var(--green)); }
/* header sticks to the top while the body scrolls (X always reachable) */
/* NOT sticky — a floating header with content sliding under it looked wrong. It scrolls away. */
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; font-weight: 800; font-size: 15px;
  background: var(--card); margin: -16px -18px 10px; padding: 14px 18px 10px; border-bottom: 1px solid var(--border); }
/* Left column: the ticker, then the contract this dossier is actually about. Ten live Robinhood
   contracts share the symbol "Artcoin", so the address is not decoration — it is how you know which
   coin you are reading. min-width:0 lets the address truncate instead of pushing the ✕ off-screen. */
.mh-l { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.mh-t { display: block; }
.mh-sub { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-weight: 600; }
.mh-ca { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; border: 1px solid var(--border);
  background: var(--bg-elev); color: var(--muted); border-radius: 6px; padding: 2px 7px; cursor: pointer;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 11px; font-weight: 600; }
.mh-ca:hover { color: var(--teal); border-color: var(--teal); }
.mh-ca svg { width: 12px; height: 12px; flex: none; }
.mh-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: -0.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mh-peers { font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 10px; font-weight: 700;
  letter-spacing: var(--track); text-transform: uppercase; color: var(--orange);
  background: rgba(255,154,0,0.1); border-radius: 5px; padding: 2px 6px; cursor: help; }
/* Market figures at the top of the dossier, with their real age underneath (see marketAgeLine). */
.dmarket { display: flex; flex-direction: column; gap: 6px; margin: 0 0 14px; }
.dmarket .stats { grid-template-columns: repeat(3, 1fr); }
.fresh { margin-right: 6px; padding: 1px 6px; border-radius: 5px; font-size: 10px; font-weight: 700;
  letter-spacing: 0.02em; color: var(--green); background: rgba(57,255,20,0.1); }
/* Mobile: a full-height sheet, but held off the top edge (notch/status bar) so it doesn't look
   jammed against the screen. Breakpoint matches the app's own mobile layout (860px), not 560. */
@media (max-width: 860px) {
  .modal-bg { padding: 0; place-items: stretch; }
  .modal { --mtop: calc(env(safe-area-inset-top, 0px) + 18px);
    max-width: 100%; width: 100%; margin-top: var(--mtop);
    height: calc(100dvh - var(--mtop)); max-height: calc(100dvh - var(--mtop));
    border-radius: 16px 16px 0 0; border: 1px solid var(--border); border-bottom: 0;
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 28px); }
}
.x-close { border: 0; background: transparent; color: var(--muted); font-size: 18px; cursor: pointer; font-family: Inter;
  line-height: 1; padding: 6px 8px; margin: -6px -8px; border-radius: 8px; } /* bigger hit area on mobile */
.x-close:hover { color: var(--text); background: rgba(255,255,255,0.06); }
.modal-loading, .modal-err { color: var(--muted); font-size: 13px; padding: 12px 0; } .modal-err { color: var(--pink); }

/* ---------- Investigate progress bar ---------- */
/* The API is one blocking request, so the bar eases toward 92% on a timer and the stage labels
   mirror the checks investigate.php actually runs — it reads as real work, not a fake spinner. */
.modal-prog { padding: 22px 0 26px; }
.mp-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.mp-stage { font-size: 12.5px; color: var(--muted); }
.mp-pct { font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-size: 12px; font-weight: 700; color: var(--green); flex: none; }
.mp-track { height: 6px; border-radius: 999px; background: var(--bg-elev); box-shadow: inset 0 0 0 1px var(--border); overflow: hidden; }
.mp-bar { height: 100%; width: 0; border-radius: 999px; background: linear-gradient(90deg, var(--green), var(--teal));
  box-shadow: 0 0 12px rgba(57,255,20,0.45); transition: width 0.16s linear; }
.mp-note { margin-top: 11px; font-size: 11px; color: var(--faint); }
.dossier { display: flex; flex-direction: column; gap: 6px; }

/* ---------- AI second opinion (top of the dossier) ---------- */
/* The container is ALWAYS a block (never flex) so the verdict's rows — badge, headline, watch/good
   lists, footer — stack vertically. A flex container here laid them out as side-by-side columns. The
   "reading…" placeholder gets its own flex row (.ai-think-row) so only IT is horizontal. */
.ai-verdict { display: block; border-radius: 12px; padding: 12px 13px; margin: 0 0 14px; border: 1px solid var(--border);
  background: linear-gradient(180deg, rgba(0,229,195,0.05), rgba(0,229,195,0.015)); }
.ai-verdict.thinking { color: var(--teal); font-size: 12.5px; }
.ai-think-row { display: flex; align-items: center; gap: 9px; }
.ai-think { display: inline-flex; align-items: center; gap: 7px; }
.ai-verdict.thinking svg { width: 14px; height: 14px; animation: aiPulse 1.1s ease-in-out infinite; }
@keyframes aiPulse { 0%,100% { opacity: 0.4 } 50% { opacity: 1 } }
.ai-verdict.bad  { border-color: rgba(255,0,110,0.4); background: linear-gradient(180deg, rgba(255,0,110,0.07), rgba(255,0,110,0.02)); }
.ai-verdict.warn { border-color: rgba(255,154,0,0.4); background: linear-gradient(180deg, rgba(255,154,0,0.06), rgba(255,154,0,0.02)); }
.ai-verdict.good { border-color: rgba(57,255,20,0.35); background: linear-gradient(180deg, rgba(57,255,20,0.06), rgba(57,255,20,0.02)); }
.ai-top { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; flex-wrap: wrap; }
.ai-badge { font-family: Orbitron; font-weight: 800; font-size: 10px; letter-spacing: 0.14em; color: var(--teal);
  background: rgba(0,229,195,0.12); border: 1px solid rgba(0,229,195,0.35); border-radius: 6px; padding: 2px 7px; }
.ai-stance { font-family: Orbitron; font-weight: 800; font-size: 13px; letter-spacing: 0.02em; text-transform: uppercase; color: var(--text); }
.ai-risk { margin-left: auto; font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: var(--track);
  padding: 2px 8px; border-radius: 999px; }
.ai-risk.bad  { color: var(--pink);   background: rgba(255,0,110,0.12); }
.ai-risk.warn { color: var(--orange); background: rgba(255,154,0,0.12); }
.ai-risk.good { color: var(--green);  background: rgba(57,255,20,0.12); }
.ai-headline { font-size: 13.5px; line-height: 1.45; color: var(--text); font-weight: 500; }
.ai-list { margin-top: 8px; display: flex; flex-direction: column; gap: 3px; font-size: 12px; line-height: 1.4; }
.ai-list.bad div  { color: #ff9fc2; }
.ai-list.good div { color: #b6ff9a; }
.ai-foot { margin-top: 9px; font-size: 10px; color: var(--faint); letter-spacing: 0.02em; }

/* ---------- good / bad / details groups ---------- */
.dgroup { display: flex; flex-direction: column; gap: 5px; margin: 0 0 14px; }
.dgroup-h { font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; font-size: 11px; font-weight: 800;
  letter-spacing: 0.06em; text-transform: uppercase; margin: 2px 0 5px; padding-bottom: 5px;
  border-bottom: 1px solid var(--border); }
.dgroup.bad .dgroup-h     { color: var(--pink); }
.dgroup.good .dgroup-h    { color: var(--green); }
.dgroup.neutral .dgroup-h { color: var(--muted); }
/* context lines inside "What to look at" — quiet, small, links stay teal */
.dctx { font-size: 11px; color: var(--faint); line-height: 1.5; }
.dctx a { color: var(--teal); } .dctx span { }
.dhdr2 { font-size: 10px; text-transform: uppercase; letter-spacing: var(--track); color: var(--faint); margin: 10px 0 4px; }
.dsec { display: flex; flex-direction: column; gap: 4px; margin-bottom: 4px; }
.dflag { font-size: 12px; border-radius: 7px; padding: 6px 9px; line-height: 1.4; }
.dflag.red { color: #ff9fc2; background: rgba(255,0,110,0.08); border: 1px solid rgba(255,0,110,0.3); }
.dflag.green { color: #b6ff9a; background: rgba(57,255,20,0.08); border: 1px solid rgba(57,255,20,0.3); }
.drow { display: flex; justify-content: space-between; gap: 12px; font-size: 12px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.dk { color: var(--faint); flex-shrink: 0; } .dv { color: var(--text); text-align: right; word-break: break-word; } .dv a { color: var(--teal); }
.dhdr { font-size: 10px; text-transform: uppercase; letter-spacing: var(--track); color: var(--faint); margin-top: 12px; margin-bottom: 2px; }
.dwarn { font-size: 12px; color: #ffcf99; } .dmuted { font-size: 11px; color: var(--faint); }
.rugchecks { display: flex; flex-direction: column; gap: 5px; margin: 8px 0; }
.rc { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 12px; padding: 7px 11px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px; }
.rc-k { color: var(--muted); flex: none; }
/* values may carry a short explanation ("0.1× — follows far more than follow back") — wrap, don't overflow */
.rc-v { font-weight: 700; text-align: right; min-width: 0; }
.rc-v.good { color: var(--green); }
.rc-v.warn { color: var(--orange); }
.rc-v.bad { color: var(--pink); }
.rc-v.muted { color: var(--faint); }
/* "smart followers" — notable accounts that follow this project, as chips */
.xfollows { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.xf { font-size: 10.5px; color: var(--muted); background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 6px; padding: 3px 7px; }
/* `.xrun` — the "Add Grok sentiment" button — was removed on 2026-07-28 along with its handler. It was
   the only paid action left in the dossier and the free X-profile panel above it already carries every
   figure that feeds the score. Nothing renders it now. */

/* "can you actually sell this?" — the one sentence in the panel that decides whether to buy. It used to
   render as .dctx, i.e. in the same 11px faint grey as the methodology footnotes. The left edge carries
   the verdict, taken from the mark the sentence already starts with. */
.dsecline { font-size: 12px; line-height: 1.5; color: var(--muted); padding: 8px 11px; border-radius: 9px;
  background: var(--bg-elev); border: 1px solid var(--border); border-left-width: 3px; }
.dsecline.good { border-left-color: var(--green); }
.dsecline.warn { border-left-color: var(--orange); }
.dsecline.bad  { border-left-color: var(--pink); color: #ff9fc2; }

/* Score notes, one per line. They were a single run-on string of up to eight clauses joined by " · ". */
.dnotes { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; }
.dnotes div { position: relative; padding-left: 11px; font-size: 11.5px; color: var(--faint); line-height: 1.45; }
.dnotes div::before { content: '·'; position: absolute; left: 2px; color: var(--muted); }
/* Blockaid verdict banner — leads the dossier; the malicious variant is the loudest thing in the modal
   because it is the strongest signal we have (the same flag Uniswap shows before a swap). */
.ba-banner { display: flex; align-items: flex-start; gap: 10px; margin: 0 0 12px; padding: 11px 13px;
  border-radius: 11px; font-size: 12.5px; line-height: 1.35; }
.ba-banner svg { width: 20px; height: 20px; flex: 0 0 auto; margin-top: 1px; }
.ba-banner b { display: block; font-weight: 800; letter-spacing: 0.01em; }
.ba-banner span { display: block; font-size: 11px; opacity: 0.85; margin-top: 2px; }
.ba-banner .ba-src { opacity: 0.6; font-size: 10.5px; }
.ba-banner.bad  { background: rgba(255,0,110,0.12); border: 1px solid rgba(255,0,110,0.5); color: var(--pink); box-shadow: 0 0 18px rgba(255,0,110,0.15); }
.ba-banner.warn { background: rgba(255,154,0,0.10); border: 1px solid rgba(255,154,0,0.4); color: var(--orange); }
.ba-banner.ok   { background: rgba(57,255,20,0.07); border: 1px solid rgba(57,255,20,0.3); color: var(--green); font-size: 12px; }
.ba-banner.ok svg { display: none; }
/* "Track this coin" — sits directly under the modal head, because on an ephemeral (CA-lookup)
   dossier it answers the first question the panel raises: this coin isn't being watched, do
   something about it. Green = already tracked. */
.track-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: -2px 0 12px;
  padding: 9px 11px; border-radius: 10px; font-size: 11.5px; line-height: 1.45;
  background: rgba(0,229,195,0.06); border: 1px solid rgba(0,229,195,0.28); color: var(--teal); }
.track-bar > span { flex: 1 1 180px; }
.track-bar.on { background: rgba(57,255,20,0.06); border-color: rgba(57,255,20,0.28); color: var(--green); }
.track-btn { flex: 0 0 auto; cursor: pointer; border-radius: 8px; padding: 7px 12px;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 12px; font-weight: 600; transition: 0.15s;
  border: 1px solid rgba(0,229,195,0.45); background: rgba(0,229,195,0.12); color: var(--teal); }
.track-btn:hover:not(:disabled) { background: rgba(0,229,195,0.22); box-shadow: 0 0 14px rgba(0,229,195,0.18); }
.track-btn.off { border-color: var(--border); background: var(--bg-elev); color: var(--muted); }
.track-btn.off:hover:not(:disabled) { background: rgba(255,0,110,0.12); border-color: rgba(255,0,110,0.4); color: var(--pink); box-shadow: none; }
.track-btn:disabled { opacity: 0.6; cursor: default; }
/* card badge — says WHY a coin older than the age window is sitting on the dashboard */
.trackpill { margin-left: 6px; font-size: 9px; padding: 2px 6px; border-radius: 5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: var(--track); font-family: Orbitron;
  color: var(--teal); background: rgba(0,229,195,0.1); }
/* what this Grok lookup cost (or that it was free) */
.xcost { margin-top: 8px; font-size: 10.5px; color: var(--faint); border-top: 1px dashed var(--border); padding-top: 7px; }
.xcost b { color: var(--teal); }
.dbar { display: grid; grid-template-columns: 70px 1fr 44px; align-items: center; gap: 8px; font-size: 11px; }
.dbar-l { color: var(--muted); }
.dbar-track { height: 6px; background: var(--bg-elev); border-radius: 4px; overflow: hidden; }
.dbar-fill { display: block; height: 100%; background: linear-gradient(90deg, var(--teal), var(--green)); }
.dbar-v { color: var(--faint); text-align: right; }
.modal-actions { display: flex; gap: 8px; margin-top: 14px; }
.modal-actions button { flex: 1; border-radius: 9px; padding: 9px; font-size: 12px; font-weight: 700; cursor: pointer; font-family: Orbitron; letter-spacing: 0.03em; }
.act-copy { border: 1px solid rgba(0,229,195,0.4); background: rgba(0,229,195,0.08); color: var(--teal); }
.act-copy:hover { background: rgba(0,229,195,0.16); }
.act-ca { border: 1px solid rgba(57,255,20,0.4); background: rgba(57,255,20,0.08); color: var(--green); }
.act-ca:hover { background: rgba(57,255,20,0.16); }
/* Save to watchlist — the per-user action, and the primary one in this row, so it leads. Saved state
   is filled rather than outlined: at a glance the question is "is this one mine or not?". */
.act-watch { border: 1px solid rgba(255,214,0,0.42); background: rgba(255,214,0,0.09); color: #ffd600; }
.act-watch:hover { background: rgba(255,214,0,0.17); }
.act-watch.saved { border-color: rgba(255,214,0,0.85); background: rgba(255,214,0,0.22); color: #ffe873; }
/* Three buttons do not fit one phone row at this font size — wrap, and let the watchlist take a full
   row of its own rather than squeezing all three into unreadable stubs. */
@media (max-width: 420px) {
  .modal-actions { flex-wrap: wrap; }
  .modal-actions .act-watch { flex: 1 0 100%; }
}
.deep-btn { margin-top: 10px; width: 100%; border: 1px dashed var(--border); background: var(--bg-elev); color: var(--muted); border-radius: 9px; padding: 9px; font-size: 12px; cursor: not-allowed; }

.disclaimer { margin-top: 26px; font-size: 11px; color: var(--faint); line-height: 1.6; border-top: 1px solid var(--border); padding-top: 14px; }
.disclaimer b { color: var(--muted); }

/* ---------- login ---------- */
/* ---------- standalone pages (settings) — real desktop layout, not the 360px login card ---------- */
.settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 14px; align-items: start; }
.panel { background: var(--card); border: 1px solid var(--border); border-radius: 14px; padding: 18px; }
.panel h2 { margin: 0 0 6px; font-size: 15px; letter-spacing: 0.03em; }
.panel-note { margin: 0 0 14px; font-size: 12px; color: var(--faint); line-height: 1.55; }
.panel-form { display: flex; flex-direction: column; gap: 10px; }
.panel-form .flabel { font-size: 9px; color: var(--faint); text-transform: uppercase; letter-spacing: var(--track); font-weight: 700; }
.panel-form input, .panel-form select { width: 100%; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px;
  padding: 10px 12px; color: var(--text); font-size: 13.5px; font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
.panel-form input:focus, .panel-form select:focus { outline: none; border-color: rgba(57,255,20,0.5); box-shadow: 0 0 0 3px rgba(57,255,20,0.08); }
.panel-form button { margin-top: 4px; border: 1px solid rgba(57,255,20,0.4); background: rgba(57,255,20,0.08); color: var(--green);
  padding: 10px 14px; border-radius: 9px; font-size: 13px; font-weight: 600; cursor: pointer; transition: 0.12s;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
.panel-form button:hover { background: rgba(57,255,20,0.16); box-shadow: 0 0 12px rgba(57,255,20,0.25); }
.panel-link { color: var(--green); font-size: 13px; font-weight: 600; }
.panel-link:hover { color: var(--lime); }
.page-ok, .page-err { font-size: 13px; border-radius: 9px; padding: 10px 12px; margin-bottom: 14px; }
.page-ok { color: var(--green); background: rgba(57,255,20,0.08); border: 1px solid rgba(57,255,20,0.3); }
.page-err { color: var(--pink); background: rgba(255,0,110,0.08); border: 1px solid rgba(255,0,110,0.3); }

.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 20px; }
.login-box { background: var(--card); border: 1px solid var(--border); border-radius: 16px; padding: 30px 26px; width: 100%; max-width: 360px; text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,0.6); }
.login-box img { width: 300px; max-width: 88%; height: auto; margin-bottom: 16px; }
.login-box h2 { font-size: 15px; letter-spacing: 0.05em; color: var(--muted); margin: 0 0 18px; font-weight: 600; font-family: Inter; }
.login-box input { width: 100%; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px; padding: 11px 12px; color: var(--text); font-size: 14px; margin-bottom: 10px; font-family: Inter; }
.login-box input:focus { outline: none; border-color: rgba(57,255,20,0.5); }
/* "Keep me signed in" — must escape the full-width input rule above */
.login-box .remember { display: flex; align-items: center; gap: 9px; margin: 2px 0 14px; font-size: 12.5px;
  color: var(--muted); cursor: pointer; text-align: left; user-select: none; }
.login-box .remember input[type="checkbox"] { width: 16px; height: 16px; margin: 0; flex: none;
  accent-color: var(--green); cursor: pointer; }
.login-box select { width: 100%; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px; padding: 11px 12px; color: var(--text); font-size: 14px; font-family: Inter; }
.login-box select:focus { outline: none; border-color: rgba(57,255,20,0.5); }
.login-box form { text-align: left; }
.login-box form input, .login-box form select { margin-bottom: 0; }
.login-box h2 { text-align: left; }
.login-box button { width: 100%; margin-top: 6px; border: 0; background: var(--green); color: #04120a; font-weight: 800; padding: 12px; border-radius: 9px; font-size: 14px; cursor: pointer; font-family: Orbitron; letter-spacing: 0.04em; }
.login-box button:hover { background: var(--lime); box-shadow: 0 0 16px rgba(57,255,20,0.4); }
.login-err { color: var(--pink); font-size: 13px; margin-bottom: 10px; }

@media (max-width: 520px) { .stats { grid-template-columns: repeat(2, 1fr); } .brand img { width: 160px; } }

/* Headroom to the reference market cap. Sits under MC because that's what it's derived from, and is
   styled quieter than the score — it answers "how much distance is left", not "is this safe". */
.room { font-size: 9.5px; font-weight: 700; letter-spacing: 0.03em; margin-top: 3px; color: var(--faint); }
.room.high { color: var(--green); }
.room.mid  { color: var(--teal); }
.room.low  { color: var(--muted); }
.room.thin { color: var(--orange); }

/* ---------- invites + members (Settings, admin only) ---------- */
.invite-fresh { margin-top: 12px; padding: 12px; border-radius: 12px;
  background: rgba(57,255,20,0.06); border: 1px solid rgba(57,255,20,0.3); }
.invite-fresh-label { font-size: 11.5px; color: var(--green); font-weight: 700; margin-bottom: 8px; }
.invite-fresh-row { display: flex; gap: 8px; }
.invite-fresh-row input { flex: 1 1 auto; min-width: 0; font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.invite-fresh-row button { flex: 0 0 auto; padding: 0 14px; }
.invite-list { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; }
.invite-empty { font-size: 12.5px; color: var(--faint); padding: 6px 0; }
.invite-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 11px; background: rgba(255,255,255,0.02); }
.invite-main { flex: 1 1 auto; min-width: 0; }
.invite-name { font-size: 13px; font-weight: 700; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.invite-you { font-size: 10px; color: var(--faint); text-transform: uppercase; letter-spacing: var(--track); }
.invite-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }
.invite-pill { flex: 0 0 auto; font-size: 10px; font-weight: 800; padding: 3px 8px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: var(--track); }
.invite-pill.is-open    { background: rgba(57,255,20,0.14); color: var(--green); }
.invite-pill.is-used    { background: rgba(255,255,255,0.07); color: var(--muted); }
.invite-pill.is-expired,
.invite-pill.is-revoked { background: rgba(255,90,90,0.12); color: #ff8a8a; }
.invite-x { flex: 0 0 auto; background: transparent; border: 1px solid var(--border); color: var(--muted);
  border-radius: 9px; padding: 6px 11px; font-size: 11.5px; cursor: pointer; }
.invite-x:hover { color: var(--text); border-color: rgba(255,255,255,0.25); }
.invite-x:disabled { opacity: 0.5; }
.login-note { font-size: 12px; color: var(--muted); line-height: 1.5; margin: 0 0 12px; }
.login-ok { color: var(--green); font-size: 13px; margin-bottom: 12px; line-height: 1.5; }

/* ---------- who-holds-it (Investigate → top holders) ---------- */
.tholders { display: flex; flex-direction: column; gap: 4px; margin: 6px 0 4px; }
.throw { display: flex; align-items: center; gap: 9px; padding: 6px 9px; border-radius: 8px;
  background: rgba(255,255,255,0.02); border: 1px solid var(--border); }
.throw .thn { flex: 0 0 16px; font-size: 10px; color: var(--faint); font-weight: 700; text-align: right; }
.throw .thw { flex: 1 1 auto; min-width: 0; font-size: 12px; color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.throw a.thw:hover { color: var(--green); }
.throw .thp { flex: 0 0 auto; font-size: 12px; font-weight: 800; color: var(--text);
  font-family: Orbitron, ui-sans-serif, system-ui, sans-serif; }
.throw .thp.warn { color: var(--orange); }
.throw .thp.bad  { color: var(--pink); }
.throw .thv { flex: 0 0 auto; font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums; }
