/* Sniper Desk — tactical targeting HUD theme, scoped to .sniper-theme so the
   scanner's case-board look is untouched. */

/* ─── CSS Variables ──────────────────────────────────────────────────────────
   The .sniper-theme palette, scanline overlay, page background and depth tokens all live
   in shared/theme.css now (loaded by every page) — this file used to carry its own copy,
   duplicated byte-for-byte in trenches.css and maintained by hand. */

/* ─── Page Layout ────────────────────────────────────────────────────────── */
/* Top padding is tight because the nav bar directly above now carries the page's
   controls — the redesign has no page-title block to breathe under. */
.sniper-layout {
  max-width: 1600px;
  margin: 0 auto;
  padding: 24px 28px 60px;
}

/* Header: title left, mode banner right. Top-aligned (not flex-end) so the
   right-hand controls sit level with the "LOCAL BOT" tag as one toolbar row,
   instead of bottom-anchoring to the tall title and floating disconnected
   above it. */
.sniper-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 28px;
  flex-wrap: wrap;
}

.sniper-header-left .tag {
  color: var(--pin);
  font-family: 'Rajdhani', monospace;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.22em;
  margin-bottom: 8px;
}

.sniper-header-left h1 {
  font-family: 'Rajdhani', 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: clamp(36px, 6vw, 64px);
  line-height: 0.95;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--safe);
  text-shadow: 0 0 20px rgba(57, 255, 138, 0.35);
  margin: 0;
}

.sniper-header-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  flex-shrink: 0;
}

/* Groups the wallet controls into one row and the mode banner/toggle into
   another, so the header-right cluster reads as two compact toolbar rows
   instead of four separately-floating pieces. */
.header-right-row {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}

/* Stats bar: two grid rows, each sized to its own box count, so the TP/SL +
   Trailing pair fills its row evenly instead of leaving a dead cell in a
   3-column grid built for the first row's 3 boxes. */
.sniper-stats-bar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 24px;
}

.sniper-stats-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.sniper-stats-row--pair {
  grid-template-columns: repeat(2, 1fr);
}

/* ─── Collapsible settings drawers ───────────────────────────────────────────
   Shared by the "Strategy Settings" drawer (TP/SL, Trailing, Smart Exit,
   Auto-Arm, Moon Bag) in the stats bar and the "Age Window" drawer in the
   discovery sidebar. Both hide config that's set occasionally, not glanced at
   constantly, behind a one-line summary + toggle — see setupCollapse() in
   snipe.js. */
.settings-toggle-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 10px 14px;
  cursor: pointer;
  user-select: none;
  transition: border-color 0.15s, background 0.15s;
}

.settings-toggle-bar:hover {
  border-color: var(--ink-dim);
  background: rgba(255, 255, 255, 0.02);
}

.settings-toggle-label {
  font-family: 'Rajdhani', monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  flex-shrink: 0;
}

.settings-toggle-summary {
  flex: 1;
  min-width: 0;
  font-family: 'Rajdhani', monospace;
  font-size: 11.5px;
  color: var(--ink-dim);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.settings-toggle-chevron {
  flex-shrink: 0;
  color: var(--safe);
  font-size: 11px;
  transition: transform 0.2s ease;
}

.settings-toggle-bar.expanded .settings-toggle-chevron {
  transform: rotate(180deg);
}

.settings-collapse-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.3s ease, opacity 0.2s ease;
}

.settings-collapse-body.expanded {
  max-height: 900px;
  opacity: 1;
}

.settings-collapse-body--filters.expanded {
  max-height: 500px;
}

/* ─── Strategy Settings cards ────────────────────────────────────────────────
   One card per settings TYPE (Trading Defaults / Auto-Arm / Moon Bag) instead of
   one small card per individual control — each groups its related fields as
   .control-group-section blocks (same pattern already used for the Trade
   Mode/Fire Mode card in the main column) separated by a divider, so related
   settings read as one unit instead of a grid of near-identical boxes. */
.settings-cards-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  align-items: start;
}

@media (max-width: 900px) {
  .settings-cards-row {
    grid-template-columns: 1fr;
  }
}

.settings-card-title {
  font-family: 'Rajdhani', monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--safe);
  margin: 0 0 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--card-edge);
}

/* Reduce Sells nested inline under Smart Exit's mode buttons, rather than as its
   own separate card — it's a detail of Smart Exit's Auto mode, not a peer setting. */
.inline-field-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 10px;
}

.inline-field-label {
  font-family: 'Rajdhani', monospace;
  font-size: 11px;
  color: var(--ink-dim);
  letter-spacing: 0.04em;
}

/* Three-column body */
.sniper-body {
  display: grid;
  grid-template-columns: 260px 1fr 320px;
  gap: 20px;
  align-items: start;
}

@media (max-width: 1280px) {
  .sniper-body {
    grid-template-columns: 220px 1fr 280px;
  }
}

@media (max-width: 960px) {
  .sniper-body {
    grid-template-columns: 1fr 1fr;
  }
  .sniper-main {
    grid-column: 1 / -1;
    order: -1;
  }
}

@media (max-width: 600px) {
  .sniper-body {
    grid-template-columns: 1fr;
  }
  .sniper-stats-row,
  .sniper-stats-row--pair {
    grid-template-columns: 1fr;
  }
  .sniper-header {
    flex-direction: column;
    align-items: flex-start;
  }
  .sniper-header-right {
    align-items: flex-start;
    width: 100%;
  }
}

/* ─── Sidebars ───────────────────────────────────────────────────────────── */
.sniper-sidebar {
  display: flex;
  flex-direction: column;
  gap: 14px;
  position: sticky;
  top: 24px;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--card-edge) transparent;
}

.sniper-sidebar::-webkit-scrollbar {
  width: 4px;
}

.sniper-sidebar::-webkit-scrollbar-track {
  background: transparent;
}

.sniper-sidebar::-webkit-scrollbar-thumb {
  background: var(--card-edge);
  border-radius: 8px;
}

.sidebar-section {
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 16px;
  position: relative;
  transition: border-color 0.3s, box-shadow 0.3s;
}

/* Corner-bracket HUD frame — dropped as part of the softer, flatter redesign
   (was the single biggest visual tell still reading as the old tactical-HUD
   look after the card/radius updates). content:none fully disables the
   pseudo-element rather than deleting the rule, so the "what this used to be"
   context above stays attached to something. */
.sidebar-section::after {
  content: none;
}

.sidebar-log {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 320px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--card-edge) transparent;
}

/* ─── Main Column ────────────────────────────────────────────────────────── */
.sniper-main {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

/* ─── Control Group (mode selectors) ─────────────────────────────────────── */
.control-group {
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 16px 18px;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Corner bracket dropped — see .sidebar-section::after's comment above. */
.control-group::after {
  content: none;
}

.control-group-section {
  padding: 12px 0;
}

.control-group-section:first-child {
  padding-top: 0;
}

.control-group-section:last-child {
  padding-bottom: 0;
}

.control-group-divider {
  height: 1px;
  background: var(--card-edge);
  margin: 0 -2px;
}

.control-label {
  font-family: 'Rajdhani', monospace;
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--ink-dim);
  text-transform: uppercase;
  margin-bottom: 10px;
}

/* ─── Intake / Mint Input ────────────────────────────────────────────────── */
.intake {
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 16px 18px;
  position: relative;
  box-shadow: 0 0 24px rgba(57, 255, 138, 0.05);
}

/* Corner brackets dropped — see .sidebar-section::after's comment above. */
.intake::after,
.intake::before {
  content: none;
}

.intake-label {
  font-family: 'Rajdhani', monospace;
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--ink-dim);
  text-transform: uppercase;
  margin-bottom: 10px;
}

.intake-row {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* .armed-section rules removed — armed orders moved into the positions ticker
   in the redesign, this container no longer exists in snipe.html. */

/* ─── Discovery / Right Sidebar ──────────────────────────────────────────── */
.sniper-sidebar--right {
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 16px;
  position: sticky;
  top: 24px;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}

/* Corner bracket dropped — see .sidebar-section::after's comment above. */
.sniper-sidebar--right::after {
  content: none;
}

/* Pinned to the top of the sidebar's own scroll area (sniper-sidebar--right has
   the overflow-y: auto) — search and the age-window filter are controls you're
   actively using, so they stay put while the live launch cards below scroll
   underneath them instead of carrying the controls away with the feed.
   .sniper-sidebar--right's own 16px padding is the trap here: padding on a
   scroll container is only a gap at rest — once you scroll, cards slide
   straight through it on every side (top, left, and right), because sticky's
   offsets are measured from the padding EDGE, not the border edge, so a header
   confined to the content box leaves that whole padding margin uncovered for
   scrolled-past cards (and their hover/status glow, which extends past their
   own edges) to peek through. Pulling the header out over the full padding box
   with matching negative margins — and re-adding the same padding inside it,
   where the opaque background actually covers it — closes the gap on all three
   sides at once. The matching border-radius keeps its top corners flush with
   the card's own rounded corners instead of squaring them off. */
.discovery-header {
  position: sticky;
  top: -16px;
  z-index: 2;
  background: var(--card);
  margin: -16px -16px 0;
  padding: 16px 16px 16px;
  border-radius: 4px 4px 0 0;
  border-bottom: 1px solid var(--card-edge);
}

.discovery-header .settings-toggle-bar {
  margin-top: 12px;
}

/* ─── Typography ─────────────────────────────────────────────────────────── */
/* Page kickers ("CASE FILE // OPEN INVESTIGATION", "TRUST CENTER // …") are the green
   accent with its glow in every redesign artboard — style.css still has them on the
   old amber --pin, which now reads as a caution state everywhere else on the site. */
.sniper-theme .case-header .tag,
.sniper-theme .sniper-header-left .tag {
  color: var(--safe);
  text-shadow: 0 0 12px rgba(var(--safe-rgb), 0.5);
}

.sniper-theme .cursor {
  color: var(--safe);
}

.sniper-theme .nav-link {
  color: var(--pin);
  text-decoration: none;
}

.sniper-theme .nav-link:hover {
  text-decoration: underline;
}

.sniper-theme .subhead {
  color: var(--ink-dim);
}

.sniper-theme .panel-label {
  color: var(--ink-dim);
  font-family: 'Rajdhani', monospace;
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin-bottom: 10px;
}

.sniper-theme .stat-value {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 20px;
  color: var(--paper);
}

.sniper-theme .status-line {
  color: var(--ink-dim);
  font-family: 'Rajdhani', monospace;
  font-size: 12px;
  /* Explicit 0 bottom margin — it's a <p>, and the browser default bottom
     margin was otherwise adding unaccounted-for space under every status line
     site-wide (mint status, session sign-in/withdraw status, discovery status). */
  margin: 8px 0 0;
  min-height: 16px;
}

.sniper-theme .status-line.error {
  color: var(--danger);
}

/* Base sweep/blink animation (.checking-scan/.checking-text/.status-line.checking)
   now lives in shared/style.css so the Scanner's Run Scan uses the same system —
   this just recolors it green to match the rest of this page, same idea as the
   .amber variant below recoloring it for the armed-card sweep. */
.sniper-theme .status-line.checking {
  color: var(--safe);
}

.sniper-theme .checking-scan {
  background: rgba(57, 255, 138, 0.15);
}

.sniper-theme .checking-scan::after {
  background: var(--safe);
  box-shadow: 0 0 6px var(--safe);
}

.sniper-theme .sidebar-empty {
  font-size: 11.5px;
  color: var(--ink-dim);
  line-height: 1.5;
}

/* Signed-out state for gated panels (positions, armed orders) — visually distinct from
   a plain "nothing here yet" empty state, so it reads as "locked, go sign in" rather
   than looking like the page is broken or you just have zero activity. */
.sniper-theme .sidebar-locked {
  padding: 14px 12px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px dashed var(--card-edge);
  border-radius: 10px;
  text-align: center;
}

/* ─── Stat Boxes ─────────────────────────────────────────────────────────── */
.sniper-theme .stat-box {
  position: relative;
}

/* Corner bracket dropped — see .sidebar-section::after's comment above. */
.sniper-theme .stat-box::after {
  content: none;
}

.sniper-theme .stat-box.safe { box-shadow: -4px 0 24px -8px rgba(57, 255, 138, 0.35); }
.sniper-theme .stat-box.danger { box-shadow: -4px 0 24px -8px rgba(255, 59, 59, 0.35); }
.sniper-theme .stat-box.caution { box-shadow: -4px 0 24px -8px rgba(255, 176, 32, 0.3); }

/* ─── Input + Buttons ────────────────────────────────────────────────────── */
.sniper-theme #snipe-mint-input {
  flex: 1;
  background: rgba(5, 8, 6, 0.5);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  color: var(--paper);
  caret-color: var(--safe);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12.5px;
  padding: 11px 14px;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.sniper-theme #snipe-mint-input::placeholder {
  color: var(--ink-dim);
}

.sniper-theme #snipe-mint-input:focus {
  border-color: var(--safe);
  box-shadow: 0 0 0 3px rgba(57, 255, 138, 0.1);
}

/* Primary CTAs are the green accent, not the amber --pin (style.css's #scan-btn
   predates the site-wide theme and still gradients to --pin). Amber stays reserved
   for caution/dry-run states throughout, which is exactly what the redesign does —
   so the Scanner's Run Scan reads as the same button as the Desk's Check. */
.sniper-theme #check-btn,
.sniper-theme #scan-btn {
  background: linear-gradient(135deg, #39ff8a, #1fbf67);
  color: #06140b;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 13px;
  padding: 10px 20px;
  border: none;
  border-radius: 10px;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 0 16px rgba(57, 255, 138, 0.25);
  transition: filter 0.15s, box-shadow 0.15s;
}

.sniper-theme #check-btn:hover,
.sniper-theme #scan-btn:hover {
  filter: brightness(1.1);
  box-shadow: 0 0 24px rgba(57, 255, 138, 0.4);
}

.sniper-theme #check-btn:disabled,
.sniper-theme #scan-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Shared pending/disabled feedback for the buttons that fire an async action —
   wallet connect/disconnect/switch, mode toggle, trade-mode switches, and the
   fire buttons. Several of these previously gave no visual feedback at all while
   their request was in flight (including the two fire buttons, where that also
   meant a double-click could send two buys before the first one landed). */
.sniper-theme .wallet-connect-btn:disabled,
.sniper-theme .wallet-disconnect-btn:disabled,
.sniper-theme .account-menu-logout-btn:disabled,
.sniper-theme .trade-mode-btn:disabled,
.sniper-theme .buy-confirm-btn:disabled,
.sniper-theme #quick-fire-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  filter: grayscale(0.3);
}

.sniper-theme #quick-fire-btn {
  background: linear-gradient(135deg, #ff6b6b, var(--danger));
  color: #1a0505;
  border: none;
  border-radius: 10px;
  padding: 10px 18px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 0 16px rgba(255, 59, 59, 0.35);
  animation: live-pulse 1.6s ease-in-out infinite;
}

/* ─── Mode Banner ────────────────────────────────────────────────────────────
   Now the single control for mode — no separate "Go Live"/toggle button (see
   snipe.js's click handler). Always clickable: prompt/dry/live all respond to a
   click, so cursor:pointer lives on the base rule rather than just .prompt. */
.sniper-theme .mode-banner {
  font-family: 'Rajdhani', monospace;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.05em;
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}

.sniper-theme .mode-banner.dry {
  background: rgba(255, 176, 32, 0.08);
  border-color: rgba(255, 176, 32, 0.3);
  color: var(--pin);
}

/* Hover flips toward the mode a click would switch TO — same "last-look
   warning before it actually arms real trades" idea the old separate toggle
   button had, just on the banner itself now. */
.sniper-theme .mode-banner.dry:hover {
  border-color: var(--danger);
  color: var(--danger);
  background: rgba(255, 59, 59, 0.1);
}

/* "Sign in" / "Create a session wallet" prompts — these aren't a trading
   status, they're pointing you at the real CTA elsewhere on the page, so they
   shouldn't compete with it as a second solid-amber pill. Muted + underlined
   like a link, and (see snipe.js) actually clickable: jumps to the session
   wallet panel instead of just telling you where it is. */
.sniper-theme .mode-banner.prompt {
  background: transparent;
  border-color: var(--card-edge);
  color: var(--ink-dim);
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

.sniper-theme .mode-banner.prompt:hover {
  color: var(--safe);
  border-color: var(--safe);
  background: transparent;
}

.sniper-theme .mode-banner.live {
  background: rgba(255, 59, 59, 0.1);
  border-color: rgba(255, 59, 59, 0.4);
  color: var(--danger);
  animation: live-pulse 1.6s ease-in-out infinite;
}

.sniper-theme .mode-banner.live:hover {
  border-color: var(--pin);
  color: var(--pin);
  background: rgba(255, 176, 32, 0.1);
}

@keyframes live-pulse {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 59, 59, 0); }
  50% { box-shadow: 0 0 20px rgba(255, 59, 59, 0.35); }
}

/* Wallet isn't delegated for automated trading AND at least one position is open right
   now — every auto-exit (stop-loss, trailing, Smart Exit, Moon Bag) is silently doing
   nothing. Deliberately louder than .live: that pulse means "real money is armed and
   working as intended," this one means "nothing is protecting what's already open." A
   faster, harder pulse plus a solid fill (vs. live's translucent one) keeps the two from
   reading as the same kind of alert at a glance. */
.sniper-theme .mode-banner.unprotected {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
  animation: unprotected-pulse 1s ease-in-out infinite;
}

.sniper-theme .mode-banner.unprotected:hover {
  border-color: var(--pin);
  background: var(--pin);
  color: #1a1200;
}

/* An RPC outage is a FAULT, not a policy pause, and must not read as the same thing as
   "New Entries Paused". The 2026-09-25 outage was invisible for ten hours precisely because
   every surface looked normal, so this one does not share the pause styling: solid amber, a
   slower and heavier pulse than `unprotected`'s, and it wins over every other banner state. */
.sniper-theme .mode-banner.outage {
  background: var(--pin);
  border-color: var(--pin);
  color: var(--board);
  font-weight: 700;
  animation: outage-pulse 1.6s ease-in-out infinite;
}

.sniper-theme .mode-banner.outage:hover {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--paper);
}

@keyframes outage-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(var(--pin-rgb), 0.55); }
  50%      { box-shadow: 0 0 0 7px rgba(var(--pin-rgb), 0); }
}

@keyframes unprotected-pulse {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 59, 59, 0); }
  50% { box-shadow: 0 0 24px rgba(255, 59, 59, 0.7); }
}

/* The mode banner lives inside the Trading Settings modal now (trade-modals.js's
   MODE & DISPLAY card) rather than the nav bar — full-width row there, same states. */
.sniper-theme .settings-mode-banner {
  display: block;
  width: 100%;
  text-align: center;
}

/* ── Paper/Live badges (position cards + trade history) ──────────────────────────────
   Previously only the paper side had a tag at all ("Dry run" / "(dry run)") — a live
   position or trade had no marker, so "live" was read from the ABSENCE of a badge rather
   than a statement of its own. That is exactly the kind of thing a release audit flags as
   easy to miss when scanning a list of cards. Both states now carry an explicit badge, and
   the live one intentionally borrows the nav banner's red/pulse language (.mode-banner.live
   above) so "this is real money" reads the same way wherever it appears on the page. */
.pos-card-tag, .history-mode-tag {
  font-family: 'Rajdhani', monospace;
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 6px;
  border: 1px solid transparent;
  display: inline-block;
}

.pos-card-tag--paper, .history-mode-tag--paper {
  background: rgba(255, 176, 32, 0.1);
  border-color: rgba(255, 176, 32, 0.35);
  color: var(--pin);
}

.pos-card-tag--live, .history-mode-tag--live {
  background: rgba(255, 59, 59, 0.12);
  border-color: rgba(255, 59, 59, 0.45);
  color: var(--danger);
  animation: live-pulse 1.6s ease-in-out infinite;
}

.history-mode-tag { margin-left: 4px; font-size: 9px; padding: 1px 6px; }

/* One-shot highlight so clicking the unprotected banner visibly lands somewhere, not
   just a silent scroll — sessionDelegateBtn already has its own resting style, this only
   needs to be noticeable for the ~1.6s window snipe.js applies it. */
.flash-attention {
  animation: flash-attention-ring 0.4s ease-in-out 2;
}

@keyframes flash-attention-ring {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 176, 32, 0); }
  50% { box-shadow: 0 0 0 4px rgba(255, 176, 32, 0.6); }
}

/* ─── Trade Mode Selector ────────────────────────────────────────────────── */
.sniper-theme .trade-mode-row {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}

.sniper-theme .trade-mode-btn {
  flex: 1;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  letter-spacing: 0.04em;
  padding: 9px 8px;
  border-radius: 100px;
  cursor: pointer;
  transition: all 0.15s;
  text-align: center;
}

.sniper-theme .trade-mode-btn:hover {
  border-color: var(--ink-dim);
  color: var(--ink);
}

/* Solid-fill active states (was a tinted outline) — matches the redesign's pill-button
   language elsewhere; still color-coded per mode (safe/amber/danger) same as before. */
.sniper-theme .trade-mode-btn[data-mode="safe"].active {
  background: var(--safe);
  border-color: var(--safe);
  color: #04140b;
}

.sniper-theme .trade-mode-btn[data-mode="balanced"].active {
  background: var(--pin);
  border-color: var(--pin);
  color: #1a1408;
}

.sniper-theme .trade-mode-btn[data-mode="danger"].active {
  background: var(--danger);
  border-color: var(--danger);
  color: #1a0505;
  animation: live-pulse 1.6s ease-in-out infinite;
}

/* Smart Exit mode row — same three-button pattern as trade-mode-btn above, deliberately
   reusing the safe/amber/danger color language: Off is neutral, Assisted is amber
   (watches and flags, never sells), Auto is red (can actually sell on your behalf). */
.sniper-theme .smart-exit-mode-row {
  display: flex;
  gap: 6px;
}

.sniper-theme .smart-exit-mode-btn {
  flex: 1;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: 0.03em;
  padding: 7px 6px;
  border-radius: 100px;
  cursor: pointer;
  transition: all 0.15s;
  text-align: center;
}

.sniper-theme .smart-exit-mode-btn:hover {
  border-color: var(--ink-dim);
  color: var(--ink);
}

/* Solid-fill active states (was a tinted outline) — see .trade-mode-btn's comment above. */
.sniper-theme .smart-exit-mode-btn[data-mode="off"].active {
  background: var(--ink-dim);
  border-color: var(--ink-dim);
  color: var(--board);
}

.sniper-theme .smart-exit-mode-btn[data-mode="assisted"].active {
  background: var(--pin);
  border-color: var(--pin);
  color: #1a1408;
}

.sniper-theme .smart-exit-mode-btn[data-mode="auto"].active {
  background: var(--danger);
  border-color: var(--danger);
  color: #1a0505;
}

/* Exit-risk badge on an open position card — same visual language as the entry-score
   row (entry-score-row/entry-score-item), just for the exit side. Only rendered once a
   position has a real reading (score isn't null), and only meaningfully colored once
   risk is elevated — a HOLD state fades into the background on purpose, so attention
   naturally goes to positions that actually need it. */
.sniper-theme .exit-risk-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 10px;
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
}
.sniper-theme .exit-risk-badge.watch { color: var(--pin); border-color: rgba(255, 176, 32, 0.4); background: rgba(255, 176, 32, 0.08); }
.sniper-theme .exit-risk-badge.reduce { color: #ff8a3d; border-color: rgba(255, 138, 61, 0.45); background: rgba(255, 138, 61, 0.1); }
.sniper-theme .exit-risk-badge.exit { color: var(--danger); border-color: rgba(255, 59, 59, 0.5); background: rgba(255, 59, 59, 0.1); animation: live-pulse 1.6s ease-in-out infinite; }

/* Live/delayed price disclosure (lib/position-monitor.js's getLivePriceUsd) — same badge
   shape as .exit-risk-badge above, always shown (not hidden-until-elevated) so a viewer
   can always tell whether this position's PnL/TP-SL is reading a live quote or a
   possibly-stale fallback, per the user's own request to always disclose this. */
.price-source-row { margin-top: 2px; }
.sniper-theme .price-source-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 9.5px;
  letter-spacing: 0.03em;
  padding: 1px 6px;
  border-radius: 10px;
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  cursor: help;
}
.sniper-theme .price-source-badge.live { color: #1f7a3f; border-color: rgba(31, 122, 63, 0.35); background: rgba(31, 122, 63, 0.1); }
.sniper-theme .price-source-badge.onchain { color: #0d9488; border-color: rgba(13, 148, 136, 0.4); background: rgba(13, 148, 136, 0.12); font-weight: 600; }
.sniper-theme .price-source-badge.delayed { color: #b8860b; border-color: rgba(184, 134, 11, 0.4); background: rgba(184, 134, 11, 0.12); }

.sniper-theme .trade-mode-note {
  font-size: 11px;
  color: var(--ink-dim);
  margin: 0;
  line-height: 1.5;
}

.sniper-theme .trade-mode-note.danger {
  color: #ff8080;
}

/* ─── Fire Mode Selector ─────────────────────────────────────────────────── */
.sniper-theme .fire-mode-row {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}

.sniper-theme .fire-mode-label {
  font-family: 'Rajdhani', sans-serif;
  font-size: 11px;
  color: var(--ink-dim);
  letter-spacing: 0.04em;
  flex-shrink: 0;
  align-self: center;
}

.sniper-theme .fire-mode-btn {
  flex: 1;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  letter-spacing: 0.03em;
  padding: 9px 8px;
  border-radius: 100px;
  cursor: pointer;
  transition: all 0.15s;
  text-align: center;
}

.sniper-theme .fire-mode-btn:hover {
  border-color: var(--ink-dim);
  color: var(--ink);
}

.sniper-theme .fire-mode-btn.active {
  background: var(--pin);
  border-color: var(--pin);
  color: #1a1408;
  font-weight: 700;
}

.sniper-theme .fire-mode-row.disabled .fire-mode-btn {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Pre-launch kill switch (lib/feature-flags.js, see snipe.js's status render) — same
   dimming as the danger-mode disable above, since :disabled covers both, plus a small
   badge so "coming soon" is visible without needing to hover for the tooltip/note. */
.sniper-theme .fire-mode-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.coming-soon-badge {
  display: none;
  margin-left: 5px;
  padding: 1px 5px;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-dim);
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  vertical-align: 1px;
}
.sniper-theme .fire-mode-btn.coming-soon .coming-soon-badge { display: inline-block; }

/* ─── Cluster / Check-Result Cards ───────────────────────────────────────── */
.sniper-theme .cluster-card {
  position: relative;
  border-color: var(--card-edge);
}

/* Corner bracket dropped — see .sidebar-section::after's comment above. */
.sniper-theme .cluster-card::after {
  content: none;
}

.sniper-theme .cluster-card.clean {
  border-color: rgba(57, 255, 138, 0.35);
  background: rgba(57, 255, 138, 0.04);
}

.sniper-theme .cluster-card.flagged {
  border-color: rgba(255, 59, 59, 0.4);
  background: rgba(255, 59, 59, 0.05);
}

.sniper-theme .cluster-card.warning {
  border-color: rgba(255, 176, 32, 0.45);
  background: rgba(255, 176, 32, 0.05);
}

.sniper-theme .cluster-card.kill-switch-card {
  border-color: rgba(255, 59, 59, 0.6);
  background: rgba(255, 59, 59, 0.08);
  box-shadow: 0 0 16px -4px rgba(255, 59, 59, 0.3);
}

.sniper-theme .cluster-tag.clean {
  background: var(--safe);
  color: #04160c;
}

.sniper-theme .cluster-tag.flagged {
  background: var(--danger);
  color: #1a0505;
}

.sniper-theme .cluster-tag.partial {
  background: rgba(255, 176, 32, 0.18);
  color: var(--pin);
  border: 1px solid rgba(255, 176, 32, 0.4);
}

.sniper-theme .cluster-tag.warning {
  background: var(--pin);
  color: #1a1005;
}

.sniper-theme .cluster-tag.whale-accumulating {
  background: var(--pin);
  color: #1a1408;
}

.sniper-theme .cluster-tag.whale-distributing {
  background: var(--danger);
  color: #1a0505;
}

.sniper-theme .cluster-tag.whale-stable {
  background: var(--safe);
  color: #04160c;
}

.sniper-theme .cluster-tag.whale-building {
  background: rgba(95, 122, 104, 0.35);
  color: var(--ink-dim);
}

.sniper-theme .cluster-funder {
  color: var(--ink-dim);
  font-size: 11.5px;
  margin-bottom: 8px;
}

.sniper-theme .repeat-note {
  color: #ffb020;
  background: rgba(255, 176, 32, 0.08);
  border-color: rgba(255, 176, 32, 0.3);
  font-size: 11.5px;
}

/* Advisory notes (e.g. "couldn't verify LP lock") are informational, not a red flag —
   deliberately don't reuse the amber warning color, so they read as a caveat rather
   than a reason this token was blocked or should give you pause. */
.sniper-theme .repeat-note.advisory-note {
  color: var(--ink-dim);
  background: rgba(255, 255, 255, 0.03);
  border-color: var(--card-edge);
}

/* Positive notes — same checks as the warnings above, read from the clean side, so a
   report isn't just a wall of red flags with "no warnings" as the only good news. */
.sniper-theme .repeat-note.positive-note {
  color: var(--safe);
  background: rgba(57, 255, 138, 0.08);
  border-color: rgba(57, 255, 138, 0.3);
}

/* Invalidation notes — "how close is this reading to a different verdict," using the
   same thresholds the checks already gate on. Distinct from advisory (informational
   caveat) and warning (already a problem) — this is "not a problem yet, but watch it." */
.sniper-theme .repeat-note.invalidation-note {
  color: #c9a8ec;
  background: rgba(160, 111, 214, 0.08);
  border-color: rgba(160, 111, 214, 0.3);
}

/* .entry-score-row/.entry-score-item now live in shared/style.css (identical rules)
   so the Scanner's entry read shows the same SAFETY/OPPORTUNITY/CONFIDENCE numbers. */

/* ─── Info Buttons & Toggles ─────────────────────────────────────────────── */
.sniper-theme .info-btn {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: none;
  background: var(--pin);
  color: #1a1408;
  font-size: 11px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 800;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 0 0 rgba(255,176,32,0.5);
  animation: info-btn-pulse-sniper 1.8s ease-in-out 3;
}

.sniper-theme .info-btn:hover {
  background: var(--paper);
  animation: none;
}

@keyframes info-btn-pulse-sniper {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,176,32,0.5); }
  50% { box-shadow: 0 0 0 5px rgba(255,176,32,0); }
}

.sniper-theme .info-toggle {
  cursor: pointer;
}

.sniper-theme span.info-toggle {
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.sniper-theme .stat-info {
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--ink-dim);
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transform: translateY(-6px) scale(0.98);
  transform-origin: top left;
  transition: max-height 0.25s ease, opacity 0.2s ease, margin-top 0.25s ease, transform 0.25s ease;
}

.sniper-theme .stat-info.open {
  max-height: 280px;
  opacity: 1;
  margin-top: 8px;
  margin-bottom: 4px;
  transform: translateY(0) scale(1);
}

/* ─── Action Buttons ─────────────────────────────────────────────────────── */
.sniper-theme .buy-confirm-btn {
  display: block;
  width: 100%;
  margin-top: 12px;
  background: linear-gradient(135deg, #39ff8a, #1fbf67);
  color: #06140b;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 14px;
  padding: 11px 20px;
  border: none;
  border-radius: 10px;
  cursor: pointer;
  box-shadow: 0 0 18px rgba(57, 255, 138, 0.3);
  transition: filter 0.15s, box-shadow 0.15s;
}

.sniper-theme .buy-confirm-btn:hover {
  filter: brightness(1.1);
  box-shadow: 0 0 26px rgba(57, 255, 138, 0.45);
}

.sniper-theme .buy-confirm-btn.warning-fire {
  background: linear-gradient(135deg, #ffc04d, var(--pin));
  box-shadow: 0 0 18px rgba(255, 176, 32, 0.3);
}

.sniper-theme .partial-sell-row {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}

.sniper-theme .partial-sell-btn {
  flex: 1;
  background: rgba(255, 176, 32, 0.08);
  border: 1px solid rgba(255, 176, 32, 0.3);
  color: var(--pin);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-family: 'Rajdhani', monospace;
  font-size: 11px;
  font-weight: 600;
  padding: 6px 4px;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.15s;
}

.sniper-theme .partial-sell-btn:hover {
  background: rgba(255, 176, 32, 0.18);
}

.sniper-theme .partial-sell-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.sniper-theme .sell-btn {
  display: block;
  width: 100%;
  margin-top: 6px;
  background: rgba(255, 59, 59, 0.1);
  border: 1px solid rgba(255, 59, 59, 0.35);
  color: var(--danger);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-family: 'Rajdhani', monospace;
  font-size: 12px;
  padding: 8px;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.15s;
}

.sniper-theme .sell-btn:hover {
  background: rgba(255, 59, 59, 0.2);
}

.sniper-theme .sell-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Manual (browser-wallet) positions — same sell-btn look, distinct "MANUAL" tag
   already carries the "no auto-monitoring" signal via the warning tag color. */
.sniper-theme .manual-position-card {
  border-color: rgba(255, 176, 32, 0.3);
}

.sniper-theme .manual-sell-btn {
  display: block;
  width: 100%;
  margin-top: 8px;
  background: rgba(255, 59, 59, 0.1);
  border: 1px solid rgba(255, 59, 59, 0.35);
  color: var(--danger);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-family: 'Rajdhani', monospace;
  font-size: 12px;
  padding: 8px;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.15s;
}

.sniper-theme .manual-sell-btn:hover {
  background: rgba(255, 59, 59, 0.2);
}

.sniper-theme .manual-sell-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.sniper-theme .cancel-arm-btn {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 8px;
  background: rgba(255, 176, 32, 0.1);
  border: 1px solid rgba(255, 176, 32, 0.35);
  color: var(--pin);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-family: 'Rajdhani', monospace;
  font-weight: 600;
  font-size: 12px;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.15s;
}

.sniper-theme .cancel-arm-btn:hover {
  background: rgba(255, 176, 32, 0.2);
}

.sniper-theme .review-btn {
  margin-top: 8px;
  background: rgba(57, 255, 138, 0.08);
  border: 1px solid rgba(57, 255, 138, 0.3);
  color: var(--safe);
  border-radius: 10px;
  padding: 7px 14px;
  font-family: 'Rajdhani', monospace;
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s;
  width: 100%;
}

.sniper-theme .review-btn:hover {
  background: rgba(57, 255, 138, 0.16);
}

.sniper-theme .mode-hint {
  font-size: 11px;
  color: var(--ink-dim);
  margin: 8px 0 0;
}

/* ─── Position Cards ─────────────────────────────────────────────────────── */
.sniper-theme .position-card {
  position: relative;
}

.sniper-theme .position-lock {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'Rajdhani', monospace;
  font-size: 9px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--safe);
  margin-bottom: 8px;
}

.sniper-theme .position-lock .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--safe);
  box-shadow: 0 0 0 0 rgba(57, 255, 138, 0.6);
  animation: pulse-lock 1.8s ease-out infinite;
  flex-shrink: 0;
}

@keyframes pulse-lock {
  0% { box-shadow: 0 0 0 0 rgba(57, 255, 138, 0.55); }
  70% { box-shadow: 0 0 0 8px rgba(57, 255, 138, 0); }
  100% { box-shadow: 0 0 0 0 rgba(57, 255, 138, 0); }
}

/* .pnl-spark-block and the corner "expand" overlay button that used to sit inside it
   were both part of the vertical position card the redesign replaced with the ticker
   chip, and nothing emits that markup any more.

   Their styling is deliberately NOT kept around the way the other superseded blocks in
   this file are: .spark-expand-btn survives as the CHIP's class — purely as the click
   hook that opens the position chart modal (see renderPositions() and the
   .spark-expand-btn handler in snipe.js) — so leaving the old overlay rule in place
   was actively breaking the new layout. It pinned every chip `position: absolute;
   top: 4px; right: 4px; width: 20px`, and since .sniper-theme is itself
   `position: relative`, the containing block was the whole page: chips left the ticker
   row entirely (which then measured 0 wide), stacked in the top-right corner over the
   nav, and stretched the document sideways. Re-adding a rule on this selector will do
   the same thing again — style .ticker-chip instead. */

/* Candles render at a fixed pixel width now (see renderCandles() in snipe.js) — the
   chart grows wider as history accumulates instead of squeezing existing candles to
   fit, so this wrapper scrolls horizontally once there's more than fits on screen. */
.sniper-theme .pnl-spark-wrap {
  margin: 0;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 6px 8px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  scrollbar-color: var(--card-edge) transparent;
}

.sniper-theme .pnl-spark-wrap::-webkit-scrollbar {
  height: 4px;
}

.sniper-theme .pnl-spark-wrap::-webkit-scrollbar-track {
  background: transparent;
}

.sniper-theme .pnl-spark-wrap::-webkit-scrollbar-thumb {
  background: var(--card-edge);
  border-radius: 8px;
}

.sniper-theme .pnl-spark {
  display: block;
  flex-shrink: 0;
}

/* Fallback candle chart inside the candle modal — used when DexScreener has no
   pair yet (fresh pre-graduation launches). Bigger than the position-card sparks;
   the background/border/scroll treatment comes from .pnl-spark-wrap (shared). */
.sniper-theme .candle-modal-fallback {
  padding: 12px 16px;
}

.sniper-theme .candle-modal-fallback .pnl-spark-wrap {
  margin: 8px 0;
}

.sniper-theme .candle-fallback-note {
  font-size: 11px;
  color: var(--ink-dim);
  margin-bottom: 8px;
}

/* ─── Armed Cards ────────────────────────────────────────────────────────── */
.sniper-theme .armed-card {
  border-color: rgba(255, 176, 32, 0.4);
}

.sniper-theme .armed-card .position-lock {
  color: var(--pin);
}

.sniper-theme .armed-card .position-lock .dot {
  background: var(--pin);
  box-shadow: 0 0 6px var(--pin);
  animation: pulse-lock-amber 1.8s ease-out infinite;
}

@keyframes pulse-lock-amber {
  0% { box-shadow: 0 0 0 0 rgba(255, 176, 32, 0.55); }
  70% { box-shadow: 0 0 0 8px rgba(255, 176, 32, 0); }
  100% { box-shadow: 0 0 0 0 rgba(255, 176, 32, 0); }
}

/* Smart Entry is continuously re-checking this token every 15s the whole time it's
   armed (see FIRE_MODE_NOTES.smart) — the dot-pulse on the WAITING FOR ENTRY label
   above is subtle enough to read as "idle," not "actively working." This is the same
   sweep-bar used for the manual check flow (.checking-scan/.checking-text, snipe.css),
   just recolored amber to match the rest of this card, so it reads as continuous
   background activity rather than a one-shot loading state. */
.sniper-theme .armed-scanning {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: 'Rajdhani', monospace;
  font-size: 10px;
  letter-spacing: 0.02em;
  color: var(--pin);
  margin: 8px 0;
}

.checking-scan.amber::after {
  background: var(--pin);
  box-shadow: 0 0 6px var(--pin);
}

/* Live chart + searching crosshair on an armed card — the same targeting-reticle motif
   as .scope-avatar's .scope-reticle (buildScopeAvatar), drifting around the actual price
   chart instead of sitting static around the coin's avatar. Reads as the bot visually
   examining the live chart for an entry, not just a text line saying it is. Percentage-
   based position (not pixels) so it stays correctly placed regardless of card width. */
.sniper-theme .armed-chart-block {
  position: relative;
  margin: 8px 0;
  overflow: hidden;
  border-radius: 10px;
}

.sniper-theme .armed-chart-wrap {
  height: 90px;
  padding: 4px 4px 0;
}

.sniper-theme .armed-chart-wrap .ohlc-chart-status {
  padding: 30px 12px;
  font-size: 10.5px;
}

.sniper-theme .armed-crosshair {
  position: absolute;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  color: var(--pin);
  opacity: 0.8;
  pointer-events: none;
  filter: drop-shadow(0 0 4px rgba(255, 176, 32, 0.65));
  animation: crosshair-search 7s ease-in-out infinite;
}

.sniper-theme .armed-crosshair svg {
  width: 100%;
  height: 100%;
}

/* Drifts to a handful of points across the chart rather than a straight back-and-forth
   sweep — reads as actually examining different parts of the price action, not just a
   mechanical scan bar. */
@keyframes crosshair-search {
  0%   { left: 14%; top: 38%; }
  20%  { left: 62%; top: 68%; }
  40%  { left: 84%; top: 30%; }
  60%  { left: 45%; top: 72%; }
  80%  { left: 24%; top: 22%; }
  100% { left: 14%; top: 38%; }
}

/* ─── Target Header (avatar + name) ─────────────────────────────────────── */
.sniper-theme .target-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

.sniper-theme .scope-avatar {
  position: relative;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  background: #0a0f0c;
  border: 1px solid var(--card-edge);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--safe);
}

.sniper-theme .scope-avatar img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sniper-theme .scope-fallback {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink-dim);
  z-index: 0;
}

.sniper-theme .scope-reticle {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  color: var(--safe);
  z-index: 1;
  pointer-events: none;
}

.sniper-theme .target-name {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--paper);
  margin-top: 2px;
}

.sniper-theme .target-symbol {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 400;
  font-size: 10px;
  color: var(--ink-dim);
  margin-left: 4px;
}

/* ─── Discovery / Dossier Board ─────────────────────────────────────────── */
.sniper-theme .discovery-label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.sniper-theme .discovery-label span {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  color: var(--ink-dim);
  text-transform: none;
  letter-spacing: normal;
}

.sniper-theme .discovery-note {
  font-size: 11px;
  color: var(--ink-dim);
  margin: 4px 0 12px;
  line-height: 1.5;
}

.sniper-theme .current-checking {
  font-family: 'Rajdhani', monospace;
  font-size: 11px;
  color: var(--safe);
  margin: 0 0 12px;
  animation: blink-check 1.4s ease-in-out infinite;
}

/* ─── Discovery Age Window Control ──────────────────────────────────────── */
.discovery-age-label {
  margin-bottom: 6px;
}

.discovery-age-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 5px;
  margin-bottom: 8px;
}

.sniper-theme .discovery-age-btn {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 10.5px;
  line-height: 1.5;
  letter-spacing: 0.02em;
  padding: 5px 4px;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.15s;
  text-align: center;
}

.sniper-theme .discovery-age-btn span {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  font-weight: 400;
  color: var(--ink-dim);
}

.sniper-theme .discovery-age-btn:hover {
  border-color: var(--ink-dim);
  color: var(--ink);
}

.sniper-theme .discovery-age-btn.active {
  background: rgba(57, 255, 138, 0.12);
  border-color: rgba(57, 255, 138, 0.5);
  color: var(--safe);
}

.sniper-theme .discovery-age-btn.active span {
  color: var(--safe);
}

.discovery-age-custom-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 4px;
  flex-wrap: wrap;
}

.sniper-theme .discovery-age-custom-row label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  color: var(--ink-dim);
}

.sniper-theme .discovery-age-custom-row input {
  width: 52px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  color: var(--ink);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  padding: 3px 5px;
}

.sniper-theme .discovery-age-custom-row button {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.04em;
  padding: 4px 10px;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.15s;
}

.sniper-theme .discovery-age-custom-row button:hover {
  border-color: var(--safe);
  color: var(--safe);
}

.discovery-age-status {
  font-size: 10.5px;
  color: var(--ink-dim);
  margin: 0 0 12px;
  min-height: 14px;
}

.discovery-age-status.ok { color: var(--safe); }
.discovery-age-status.err { color: var(--danger); }

.discovery-search-input {
  width: 100%;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  color: var(--ink);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11.5px;
  padding: 7px 10px;
  margin-top: 2px;
}

.discovery-search-input:focus {
  outline: none;
  border-color: var(--safe);
}

.discovery-search-input::placeholder {
  color: var(--ink-dim);
}

.sniper-theme .creator-profit-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  font-size: 11px;
  color: var(--ink-dim);
  cursor: pointer;
  user-select: none;
}
.sniper-theme .creator-profit-toggle input { accent-color: var(--pin); width: 14px; height: 14px; cursor: pointer; }
.sniper-theme .creator-profit-toggle:has(input:checked) { color: var(--pin); }

/* Smart Coin Finder Pro — anti-rug filter toggle + upgrade CTA. Locked (dimmed, input
   disabled) until updateProUI() in snipe.js confirms the signed-in user is Pro; the 🔒 Pro
   tag and the upgrade button below only appear while locked. */
/* ── Tier locks (Trading Settings modal) — see snipe.js's applyTierLocks() ─────────── */
/* feature-locked (below) shares this exact dimming — a pre-launch card and a plan-locked
   card should look the same, just carry a different chip. */
.settings-card.tier-locked .control-group-section,
.settings-card.feature-locked .control-group-section { opacity: 0.55; }
.settings-card.tier-locked input,
.settings-card.tier-locked .smart-exit-mode-btn,
.settings-card.tier-locked .moon-bag-settings-btn,
.settings-card.feature-locked input,
.settings-card.feature-locked .smart-exit-mode-btn,
.settings-card.feature-locked .moon-bag-settings-btn { cursor: not-allowed; }
/* #smart-exit-row IS a .control-group-section (it lives inside Trading Defaults, not its
   own .settings-card), so the compound .settings-card.feature-locked selectors above
   never match it — dim it directly instead. Only feature-locked, never tier-locked: a
   tier-only Smart Exit Auto lock leaves Off/Assisted at full opacity by design (see
   applyTierLocks), so this rule must not also fire for that case. */
#smart-exit-row.feature-locked { opacity: 0.55; }
#smart-exit-row.feature-locked .smart-exit-mode-btn,
#smart-exit-row.feature-locked input { cursor: not-allowed; }
.tier-lock-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  padding: 3px 9px;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--pin);
  border: 1px solid rgba(var(--pin-rgb), 0.45);
  border-radius: 999px;
  background: rgba(var(--pin-rgb), 0.08);
}
.tier-lock-chip:hover { background: rgba(var(--pin-rgb), 0.16); }
.tier-lock-chip .icn-slot svg { width: 11px; height: 11px; }

/* Pre-launch kill switch (lib/feature-flags.js) — see snipe.js's applyFeatureFlags().
   Same shape as .tier-lock-chip but neutral (not --pin) and not a link: there's no
   upgrade path for a feature that isn't live yet on ANY plan. Takes precedence over a
   tier-lock chip on the same card when both would otherwise apply. */
.coming-soon-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  padding: 3px 9px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-dim);
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  cursor: default;
}
.coming-soon-chip .icn-slot svg { width: 11px; height: 11px; }

#rug-filter-toggle-row.pro-locked { opacity: 0.55; cursor: not-allowed; }
#rug-filter-toggle-row.pro-locked input { cursor: not-allowed; }
#rug-filter-pro-lock {
  display: none;
  font-size: 9px;
  color: #b8860b;
  background: rgba(184, 134, 11, 0.14);
  border: 1px solid rgba(184, 134, 11, 0.4);
  border-radius: 8px;
  padding: 1px 4px;
  margin-left: 2px;
}
#rug-filter-toggle-row.pro-locked #rug-filter-pro-lock { display: inline-block; }

.pro-upgrade-btn {
  display: block;
  width: 100%;
  margin-top: 6px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  color: #fff;
  background: linear-gradient(135deg, #b8860b, #d4a017);
  border: none;
  border-radius: 10px;
  padding: 6px 8px;
  cursor: pointer;
}
.pro-upgrade-btn:hover { filter: brightness(1.08); }
.pro-upgrade-btn.hidden { display: none; }

.pro-upgrade-plans-link {
  display: block;
  margin-top: 6px;
  font-size: 10.5px;
  text-align: center;
}

/* Pricing-page hand-off banner (see snipe.js's handlePricingHandoff) — sits above the
   nav bar so it's the first thing a visitor arriving from /pricing.html sees. */
.upgrade-handoff-banner {
  background: linear-gradient(135deg, #b8860b, #d4a017);
  color: #1a1408;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  padding: 10px 16px;
}
.upgrade-handoff-banner strong { font-weight: 800; }
.upgrade-handoff-banner button {
  margin-left: 8px;
  background: #1a1408;
  color: #ffd479;
  border: none;
  border-radius: 10px;
  padding: 5px 12px;
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
}
.upgrade-handoff-banner button:hover { filter: brightness(1.2); }
.upgrade-handoff-banner button:disabled { opacity: 0.6; cursor: not-allowed; }

/* Current-plan badge, header-right-row (see #tier-badge in snipe.html) */
.tier-badge {
  display: inline-flex;
  align-items: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 5px 10px;
  border-radius: 10px;
  text-decoration: none;
  white-space: nowrap;
}
.tier-badge.hidden { display: none; }
.tier-badge--free {
  color: var(--pin);
  background: rgba(255, 176, 32, 0.1);
  border: 1px solid rgba(255, 176, 32, 0.35);
}
.tier-badge--free:hover { background: rgba(255, 176, 32, 0.18); }
.tier-badge--paid {
  color: var(--safe);
  background: rgba(57, 255, 138, 0.08);
  border: 1px solid rgba(57, 255, 138, 0.3);
  cursor: default;
}

/* Dossier card badges — already-dumped/rugged (visible to every viewer, filtering it out
   of the board entirely is the Pro perk, see loadCandidates() in snipe.js) and the social
   pre-pump alert (Pro-only detail; a locked teaser shows for non-Pro instead). */
.dossier-rug-badge {
  display: inline-block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 8.5px;
  color: #b3261e;
  background: rgba(179, 38, 30, 0.12);
  border: 1px solid rgba(179, 38, 30, 0.35);
  border-radius: 8px;
  padding: 1px 5px;
  margin-bottom: 4px;
  cursor: help;
}
.dossier-prepump-badge {
  display: inline-block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 8.5px;
  color: #b8860b;
  background: rgba(184, 134, 11, 0.12);
  border: 1px solid rgba(184, 134, 11, 0.4);
  border-radius: 8px;
  padding: 1px 5px;
  margin-bottom: 4px;
  cursor: help;
}

/* Badge on a dossier card for a creator with a real, sampled positive track record —
   see isProvenCreator in snipe.js. Distinct from the top-edge status accent (that's
   cleared/warning/rejected); this is purely a "this creator has made money before"
   signal, shown regardless of which of those three states the card is in. */
.dossier-creator-profit-badge {
  display: inline-block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 8.5px;
  color: #1f7a3f;
  background: rgba(31, 122, 63, 0.12);
  border: 1px solid rgba(31, 122, 63, 0.35);
  border-radius: 8px;
  padding: 1px 5px;
  margin-bottom: 4px;
}

/* ─── Dossier Cards ──────────────────────────────────────────────────────── */
/* Everything below .dossier-board down to the rejected-card section is the OLD
   tan-paper "mugshot" card — superseded by .feed-card (see its own block further
   down this file). Left in place as dead CSS rather than deleted outright, since
   nothing currently emits .dossier-card/.mugshot/.dossier-stamp markup anymore
   (renderClearedCard()/renderRejectedCard() in snipe.js build .feed-card now). */
.dossier-board {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 13px;
}

.dossier-card {
  position: relative;
  background: #ddd3b0;
  background-image:
    repeating-linear-gradient(0deg, rgba(0,0,0,0.02) 0px, rgba(0,0,0,0.02) 1px, transparent 1px, transparent 3px),
    radial-gradient(ellipse at top left, rgba(255,255,255,0.12), transparent 55%),
    radial-gradient(ellipse at bottom right, rgba(0,0,0,0.08), transparent 60%);
  color: #2a2416;
  border-radius: 10px;
  padding: 11px 11px 12px;
  transform: rotate(var(--tilt, 0deg));
  /* Layered: a tight dark contact shadow (grounds the card on the board) plus a soft,
     wider amber-tinted glow (--pin) so cleared cards read as spotlit against the dark
     HUD panel behind them, not just flat paper sitting on it. */
  box-shadow:
    3px 4px 12px rgba(0,0,0,0.55),
    0 0 0 1px rgba(0,0,0,0.18),
    0 0 22px rgba(255,176,32,0.10);
  transition: transform 0.18s ease, box-shadow 0.18s ease, opacity 0.25s ease, scale 0.25s ease;
}

/* Status accent — a thin glowing top edge so CLEARED/CLEARED*/REJECTED reads at a
   glance even before the eye reaches the stamp. Green by default (clean clear);
   overridden below for the warning/rejected variants. */
.dossier-card::before {
  content: '';
  position: absolute;
  top: 0; left: 8%; right: 8%;
  height: 2.5px;
  border-radius: 0 0 2px 2px;
  background: var(--safe);
  box-shadow: 0 0 8px var(--safe);
  opacity: 0.85;
}

.dossier-card:hover {
  transform: rotate(0deg) translateY(-4px) scale(1.025);
  box-shadow:
    5px 8px 20px rgba(0,0,0,0.6),
    0 0 0 1px rgba(0,0,0,0.2),
    0 0 30px rgba(255,176,32,0.22);
}

/* Applied the instant "Open Dossier" is clicked — the card fades/shrinks out of the
   feed for as long as this coin is being reviewed/checked, rather than sitting there
   unchanged while its own check runs somewhere else on the page (see the review-btn
   click handler and reviewingMints in snipe.js). Removed from the DOM once the
   transition finishes; comes back on the next natural render once checking is done. */
.dossier-card.dossier-card-reviewing {
  opacity: 0;
  scale: 0.85;
  pointer-events: none;
}

/* Base color is the fully-clean CLEARED case (no mode warnings) — was previously the
   same red as a REJECTED stamp with no override, which sent the wrong signal for the
   single best outcome the board can show. Green (--safe) now matches every other "all
   clear" indicator on this page (cluster-tag.clean, etc.); stamp-warning/stamp-rejected
   below still override it for their own states. */
.dossier-stamp {
  position: absolute;
  top: 6px;
  right: -4px;
  background: rgba(34, 156, 88, 0.92);
  color: #eafff0;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 8.5px;
  letter-spacing: 0.1em;
  padding: 2px 7px;
  border: 1.5px solid rgba(34, 156, 88, 0.95);
  border-radius: 8px;
  transform: rotate(6deg);
  box-shadow: 0 2px 8px rgba(0,0,0,0.35), 0 0 10px rgba(57, 255, 138, 0.35);
}

.dossier-source {
  position: absolute;
  top: 24px;
  right: 4px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 6.5px;
  letter-spacing: 0.08em;
  color: #8a7f5c;
  text-transform: uppercase;
}

.dossier-top {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  /* Clears the stamp badge (top: 6px, ~20px tall including border) by starting the
     name/mugshot row below it entirely, instead of squeezing name text sideways to
     avoid overlap — keeps the full card width available for the name instead of
     forcing early ellipsis truncation. */
  margin-top: 17px;
  margin-bottom: 7px;
}

.mugshot {
  position: relative;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  background: #b8ac86;
  border: 2px solid #6b6146;
  border-radius: 1px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: inset 0 0 8px rgba(0,0,0,0.25), 0 2px 6px rgba(0,0,0,0.3);
  transition: border-color 0.18s ease;
}

.dossier-card:hover .mugshot {
  border-color: var(--pin);
}

.mugshot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mugshot-fallback {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 19px;
  color: #6b6146;
}

.dossier-id {
  min-width: 0; /* lets long names actually truncate instead of stretching the grid column */
}

.dossier-alias {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  color: #1c1810;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dossier-ticker {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  font-size: 9.5px;
  color: #6b6146;
  margin-top: 2px;
  letter-spacing: 0.02em;
}

.dossier-plate {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  color: #8a7f5c;
  margin-top: 3px;
  letter-spacing: 0.03em;
}

/* ─── Simplified feed-card content (basic info only — full stat block moves to the
   check-result panel once "Open Dossier" actually runs a check) ────────────────── */
.dossier-mcap {
  font-family: 'Rajdhani', sans-serif;
  font-size: 12.5px;
  color: #4a4128;
  margin-bottom: 5px;
}

.dossier-mcap b {
  font-weight: 700;
  font-size: 17px;
  color: #1f7a3f;
}

/* Live on the dark theme (check panel + feed rows; .feed-card has its own override
   further down) — was still colored in the retired warm-paper palette. */
.dossier-creator-line {
  font-size: 9px;
  color: var(--ink-dim);
  margin-bottom: 4px;
  line-height: 1.3;
}

.dossier-creator-line.rugged {
  color: var(--danger);
  font-weight: 600;
}

.dossier-socials {
  display: flex;
  gap: 7px;
  margin-bottom: 8px;
}

.dossier-social-link {
  font-size: 13px;
  line-height: 1;
  text-decoration: none;
  opacity: 0.85;
  transition: transform 0.1s, opacity 0.1s;
}

.dossier-social-link:hover {
  transform: scale(1.2);
  opacity: 1;
}

.dossier-social-link.reused {
  filter: drop-shadow(0 0 3px rgba(194, 59, 46, 0.7));
}

.dossier-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 12px;
  border-top: 1px dashed #a89a70;
  padding-top: 10px;
  margin-bottom: 10px;
}

.dossier-stat {
  display: flex;
  flex-direction: column;
}

.dossier-stat-label {
  font-family: 'Rajdhani', monospace;
  font-size: 8.5px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: #6b6146;
  margin-bottom: 2px;
}

.dossier-stat-value {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 13px;
}

.dossier-stat-value.bounty       { color: #1f7a3f; }
.dossier-stat-value.threat-low   { color: #1f7a3f; }
.dossier-stat-value.threat-elevated { color: #a8501f; }
.dossier-stat-value.coord-low    { color: #1f7a3f; }
.dossier-stat-value.coord-medium { color: #a8501f; }
.dossier-stat-value.coord-high   { color: #c23b2e; }
.dossier-stat-value.whale-accumulating { color: #a8501f; }
.dossier-stat-value.whale-distributing { color: #c23b2e; }
.dossier-stat-value.whale-stable       { color: #1f7a3f; }
.dossier-stat-value.whale-building     { color: #6b6146; }

.dossier-entry {
  display: inline-block;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.03em;
  padding: 3px 8px;
  border-radius: 10px;
  margin-bottom: 6px;
  cursor: pointer;
}

.dossier-entry-expand {
  font-weight: 500;
  font-size: 10px;
  opacity: 0.75;
  margin-left: 2px;
}

.dossier-entry-reasons {
  font-size: 11px;
  line-height: 1.5;
}

.dossier-entry-reasons ul {
  margin: 4px 0 0;
  padding-left: 16px;
}

.dossier-entry-reasons li {
  margin-bottom: 3px;
}

.dossier-entry-disclaimer {
  font-style: italic;
  opacity: 0.85;
}

.dossier-card .dossier-entry-reasons {
  color: #4a4128;
}

.dossier-card .dossier-entry-reasons .dossier-entry-disclaimer {
  color: #6b6146;
}

/* Entry-read badge — renders on the DARK check panel (snipe.js's renderCheckResult),
   so it takes the neon tokens; the old forest/olive values dated from the paper cards. */
.dossier-entry.entry-strong {
  background: rgba(var(--safe-rgb), 0.12);
  color: var(--safe);
  border: 1px solid rgba(var(--safe-rgb), 0.4);
}

.dossier-entry.entry-watch {
  background: rgba(var(--pin-rgb), 0.12);
  color: var(--pin);
  border: 1px solid rgba(var(--pin-rgb), 0.4);
}

.dossier-entry.entry-risky {
  background: rgba(var(--danger-rgb), 0.12);
  color: var(--danger);
  border: 1px solid rgba(var(--danger-rgb), 0.4);
}

.dossier-entry-detail {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9.5px;
  color: var(--ink-dim);
  margin-bottom: 8px;
  margin-top: -2px;
}

.dossier-card .dossier-entry-detail {
  color: #6b6146;
}

/* Solid "stamp" style (matching .dossier-stamp) instead of translucent-on-light —
   this button sits on the tan .dossier-card paper background, not the dark theme.
   Selector specificity is deliberately higher than ".sniper-theme .review-btn"
   (which the button also carries as a class) — that rule was previously winning
   the cascade and rendering this button in pale green on a near-invisible tint. */
.sniper-theme .dossier-card .dossier-btn {
  width: 100%;
  background: #8b5a1f;
  color: #fff3d6;
  border: 1px solid #6b4315;
  border-radius: 8px;
  padding: 6px 6px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(0,0,0,0.25);
  transition: background 0.15s, border-color 0.15s;
}

.sniper-theme .dossier-card .dossier-btn:hover {
  background: #a1691f;
  border-color: #4f3110;
}

/* ─── Rejected Dossier Cards ─────────────────────────────────────────────── */
/* Same "case file" card, deliberately drained of color and marked REJECTED —
   these never got a clean safety check, so there's no stat block to show and
   no way to open them for trading. They exist purely so the board reads as a
   live feed of *everything* discovery looked at, not just what cleared. */
.dossier-card.dossier-rejected {
  filter: grayscale(0.6);
  opacity: 0.68;
}

.dossier-card.dossier-rejected::before {
  background: var(--danger);
  box-shadow: 0 0 8px var(--danger);
}

.dossier-card.dossier-rejected:hover {
  opacity: 0.88;
  transform: rotate(var(--tilt, 0deg));
  box-shadow: 3px 4px 12px rgba(0,0,0,0.55), 0 0 0 1px rgba(0,0,0,0.18);
}

.dossier-stamp.stamp-rejected {
  background: rgba(90, 20, 20, 0.9);
  border-color: rgba(90, 20, 20, 0.95);
  box-shadow: 0 2px 8px rgba(0,0,0,0.35), 0 0 10px rgba(255, 59, 59, 0.3);
}

/* Cleared, but only because a Safe-mode-only check (thin liquidity, creator repeat-rug
   pattern, reused social link) got relaxed to a warning instead of a hard block — see the
   discoveryCheckLoop comment in server.js. Distinct from a plain CLEARED stamp so Safe-mode
   viewers aren't misled into thinking this is fully clean. */
.dossier-stamp.stamp-warning {
  background: rgba(168, 80, 31, 0.9);
  border-color: rgba(168, 80, 31, 0.95);
  box-shadow: 0 2px 8px rgba(0,0,0,0.35), 0 0 10px rgba(255, 176, 32, 0.35);
}

.dossier-card:has(.stamp-warning)::before {
  background: var(--pin);
  box-shadow: 0 0 8px var(--pin);
}

.dossier-mode-warning {
  color: #a8501f;
  cursor: pointer;
}

/* Opens a modal (see the .dossier-rejected-why click handler in snipe.js) instead of
   expanding in place — an inline expand still made one grid card taller than its
   neighbors whenever the reason text wrapped past a couple of lines, throwing off row
   alignment across the whole board. A modal shows the full list with zero layout impact
   on the card grid. Styled as plain text-button, not .dossier-btn — this is informational,
   not an action. */
.dossier-rejected-why {
  display: block;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  font-size: 9.5px;
  color: #a8501f;
  text-align: left;
  cursor: pointer;
  margin-bottom: 6px;
}

.dossier-rejected-why:hover {
  color: #c2681f;
  text-decoration: underline;
}

.sniper-theme .dossier-card .dossier-locked-btn {
  width: 100%;
  background: rgba(90, 69, 48, 0.5);
  color: #a89880;
  border: 1px solid #443521;
  border-radius: 8px;
  padding: 8px 8px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  cursor: not-allowed;
}

/* ─── Misc: About, Disclaimer ────────────────────────────────────────────── */
.sniper-theme .about-panel,
.sniper-theme .about-panel p {
  color: var(--ink-dim);
}

.sniper-theme .about-panel strong {
  color: var(--paper);
}

.sniper-theme .disclaimer-banner {
  background: rgba(255, 176, 32, 0.06);
  border-color: rgba(255, 176, 32, 0.25);
  color: var(--pin);
}

/* ─── HUD Confirmation Modal ─────────────────────────────────────────────── */
.hud-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(3, 6, 4, 0.8);
  backdrop-filter: blur(4px);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Modal-behind-modal stacking fix (2026-09-08): #hud-modal-overlay, #settings-modal-
   overlay and #moon-bag-modal-overlay all share the plain .hud-modal-overlay class above
   (z-index:100), so on a tie CSS falls back to DOM order — and trade-modals.js defines
   #hud-modal-overlay FIRST, #moon-bag-modal-overlay next, #settings-modal-overlay last.
   showHudModal() (snipe.js) is the generic confirm/alert dialog and is routinely
   triggered from WITHIN an already-open modal — "Switch to Live Mode" and "Enable
   Auto-Arm — LIVE mode" fire from the #mode-banner/Auto-Arm toggle that live inside
   Settings, "Apply Degen Preset" fires from inside Moon Bag settings (itself opened from
   inside Settings), and saveConfig()'s "Config Error"/"Sign In Required" alerts can fire
   from either. Every one of those rendered invisible behind the modal it was confirming
   an action inside — same bug shape, same fix direction, as the Privy portal-root fix in
   shared/style.css: a higher, ID-specific z-index beats relying on source order. Kept
   well under .pro-chart-overlay/.scope-overlay's 3000 and #headlessui-portal-root's 9999
   — this only needs to clear the app's OWN modal layer, not the Privy portal or the
   full-screen chart. */
#moon-bag-modal-overlay { z-index: 110; }
#hud-modal-overlay { z-index: 200; }

.hud-modal-overlay.hidden {
  display: none;
}

.hud-modal {
  position: relative;
  width: 90%;
  max-width: 420px;
  background: #0d1410;
  border: 1px solid #1c2e22;
  border-radius: 10px;
  padding: 28px;
  box-shadow: 0 0 40px rgba(57, 255, 138, 0.12), 0 20px 60px rgba(0,0,0,0.6);
  animation: modal-in 0.15s ease;
}

@keyframes modal-in {
  from { opacity: 0; transform: scale(0.95); }
  to { opacity: 1; transform: scale(1); }
}

/* Corner brackets dropped — see .sidebar-section::after's comment (snipe.css) above. */
.hud-modal::after,
.hud-modal::before {
  content: none;
}

.hud-modal.dangerous {
  box-shadow: 0 0 40px rgba(255, 59, 59, 0.18), 0 20px 60px rgba(0,0,0,0.6);
}

.hud-modal-title {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 18px;
  letter-spacing: 0.02em;
  color: #d8f5df;
  margin-bottom: 12px;
}

.hud-modal.dangerous .hud-modal-title {
  color: #ff8080;
}

.hud-modal-message {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12.5px;
  line-height: 1.65;
  color: #a9c9b2;
  margin-bottom: 24px;
}

.hud-modal-reason-list {
  margin: 0;
  padding-left: 18px;
}

.hud-modal-reason-list li {
  margin-bottom: 8px;
}

.hud-modal-reason-list li:last-child {
  margin-bottom: 0;
}

.hud-modal-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.hud-modal-btn {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 10px 22px;
  border-radius: 10px;
  cursor: pointer;
  border: none;
  transition: filter 0.15s;
}

.hud-modal-btn.cancel {
  background: transparent;
  border: 1px solid #1c2e22;
  color: #5f7a68;
}

.hud-modal-btn.cancel:hover {
  border-color: #5f7a68;
  color: #a9c9b2;
}

.hud-modal-btn.confirm {
  background: linear-gradient(135deg, #39ff8a, #1fbf67);
  color: #06140b;
  box-shadow: 0 0 16px rgba(57, 255, 138, 0.3);
}

.hud-modal.dangerous .hud-modal-btn.confirm {
  background: linear-gradient(135deg, #ff6b6b, #ff3b3b);
  color: #1a0505;
  box-shadow: 0 0 16px rgba(255, 59, 59, 0.35);
}

.hud-modal-btn.confirm:hover {
  filter: brightness(1.1);
}

.hud-modal-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  filter: none;
}

/* ─── Safety Override modal — deliberately the most alarming-looking confirm flow in
   the app (see trade-modals.js's own comment on why this is heavy on purpose). Every
   reason gets its own checkbox row rather than a plain list, and the confirm button
   stays visibly disabled (.hud-modal-btn:disabled above) until every box is checked
   AND the typed phrase matches. ───────────────────────────────────────────────── */
.override-reason-list {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
}

.override-reason-item {
  background: rgba(255, 59, 59, 0.06);
  border: 1px solid rgba(255, 59, 59, 0.25);
  border-radius: 8px;
  padding: 10px 12px;
}

.override-reason-item label {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  line-height: 1.5;
  color: #f0b8b8;
}

.override-reason-item input[type="checkbox"] {
  flex-shrink: 0;
  margin-top: 2px;
  width: 16px;
  height: 16px;
  accent-color: #ff3b3b;
  cursor: pointer;
}

/* The button on the rejected-check card itself that opens the modal above — deliberately
   NOT styled like a normal action button (no green, no confident gradient); a plain
   outlined red warning button someone has to actually notice and choose, not stumble into. */
.sniper-theme .override-trigger-btn {
  display: block;
  width: 100%;
  margin-top: 14px;
  background: transparent;
  border: 1px solid rgba(255, 59, 59, 0.4);
  color: #ff8080;
  border-radius: 8px;
  padding: 10px 16px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}

.sniper-theme .override-trigger-btn:hover {
  background: rgba(255, 59, 59, 0.1);
  border-color: #ff3b3b;
}

/* ─── Wallet Connect (Sniper Desk) ────────────────────────────────────────── */
.sniper-theme .wallet-status-line {
  font-size: 11px;
  color: var(--ink-dim);
  min-height: 14px;
  flex-basis: 100%;
  /* It's a <p> — without this, the browser's default 1em top/bottom margin
     was adding ~20px of unexplained whitespace under the wallet controls. */
  margin: 4px 0 0;
}

.sniper-theme .wallet-status-line a { color: var(--pin); }

/* Numbered step badge, used by the Get Started modal's three steps below. */
.sniper-theme .onboard-step-num {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--pin);
  color: #1a1005;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 10px;
  margin-top: 1px;
}

.wallet-connect-btn,
.sniper-theme .wallet-connect-btn {
  background: rgba(255, 176, 32, 0.08);
  border: 1px solid rgba(255, 176, 32, 0.35);
  color: var(--pin);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 7px 14px;
  border-radius: 100px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
  white-space: nowrap;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.wallet-connect-btn:hover,
.sniper-theme .wallet-connect-btn:hover {
  background: rgba(255, 176, 32, 0.16);
  border-color: rgba(255, 176, 32, 0.65);
}

.wallet-connect-btn.connected,
.sniper-theme .wallet-connect-btn.connected {
  background: rgba(57, 255, 138, 0.08);
  border-color: rgba(57, 255, 138, 0.35);
  color: var(--safe);
}

/* ─── Account Menu ───────────────────────────────────────────────────────────────
   Consolidates wallet connect/disconnect/switch, the SOL/USD display toggle, and
   live/dry-run mode switching into one button + dropdown. wallet-connect-btn is
   both the "Get Started" CTA (signed out) and this dropdown's trigger (once fully
   onboarded) — see the click handler in snipe.js. The chevron only appears once a
   wallet is connected (reuses the existing .connected class as its signal). */
.account-menu {
  position: relative;
}

.account-menu-trigger.connected::after {
  content: '▾';
  margin-left: 6px;
  font-size: 9px;
  opacity: 0.75;
}

.account-menu-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 15;
  min-width: 230px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.account-menu-dropdown.hidden { display: none; }

.account-menu-dropdown .wallet-status-line {
  flex-basis: auto;
  margin: 0;
}

.account-menu-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.account-menu-section--row {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}
.account-menu-section-label {
  font-family: 'Rajdhani', monospace;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.account-menu-divider {
  height: 1px;
  background: var(--card-edge);
}

.account-menu-logout-btn {
  width: 100%;
  text-align: center;
}

.wallet-connect-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* ─── Get Started modal (centralized onboarding) ─────────────────────────── */
.onboard-modal { max-width: 460px; }

.onboard-modal-steps {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-bottom: 22px;
}

.onboard-modal-step {
  display: flex;
  gap: 12px;
  opacity: 0.4;
  filter: grayscale(0.6);
  transition: opacity 0.2s, filter 0.2s;
}

.onboard-modal-step.active,
.onboard-modal-step.done {
  opacity: 1;
  filter: none;
}

.onboard-modal-step .onboard-step-num {
  margin-top: 2px;
}

.onboard-modal-step.done .onboard-step-num {
  background: var(--safe);
}

.onboard-modal-step-body { flex: 1; min-width: 0; }

.onboard-modal-step-label {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.02em;
  color: var(--paper);
  margin-bottom: 3px;
}

.onboard-modal-step-sub {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-dim);
  margin-bottom: 10px;
}

.onboard-modal-step-sub a.nav-link { font-size: 11px; }

.onboard-modal-step .wallet-connect-btn { max-width: none; }

.onboard-modal-step .session-wallet-row,
.onboard-modal-step .session-balance-row {
  margin-top: 8px;
}

.onboard-terms-check {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 12px;
  cursor: pointer;
}
.onboard-terms-check input[type="checkbox"] {
  width: 15px;
  height: 15px;
  flex: none;
  margin-top: 1px;
  accent-color: var(--pin);
}
.onboard-terms-check span {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  line-height: 1.55;
  color: var(--ink-dim);
}
.onboard-terms-check a { color: var(--pin); }

/* Every scattered "sign in" pointer elsewhere on the page (sidebar, locked panels,
   trade log, status lines) is one of these — links back into the same modal above
   instead of repeating its own version of the flow. */
.onboard-open-link,
.status-line a {
  color: var(--pin);
  text-decoration: underline;
  cursor: pointer;
}
.onboard-open-link:hover,
.status-line a:hover {
  color: var(--paper);
}

/* ─── Session Wallet Panel ────────────────────────────────────────────────── */
.session-wallet-row {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(5, 8, 6, 0.5);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 8px 10px;
}

.session-wallet-addr {
  flex: 1;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--paper);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.session-copy-btn {
  background: rgba(57, 255, 138, 0.1);
  border: 1px solid rgba(57, 255, 138, 0.3);
  color: var(--safe);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: 10px;
  padding: 4px 10px;
  cursor: pointer;
  transition: filter 0.15s;
}

.session-copy-btn:hover { filter: brightness(1.2); }
.session-copy-btn.copied { background: rgba(57, 255, 138, 0.25); }

.session-balance-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 10px 0;
}

.session-balance-value {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 15px;
  color: var(--paper);
  font-weight: 500;
}

.session-withdraw-toggle-btn {
  background: transparent;
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: 10px;
  padding: 6px 14px;
  cursor: pointer;
  width: 100%;
  transition: border-color 0.15s, color 0.15s;
}

.session-withdraw-toggle-btn:hover {
  border-color: var(--pin);
  color: var(--pin);
}

.session-withdraw-form {
  margin-top: 10px;
}

.session-withdraw-form .intake-row input {
  flex: 1;
  background: rgba(5, 8, 6, 0.5);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  color: var(--paper);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  padding: 8px 10px;
}

.session-withdraw-form .intake-row input:focus {
  outline: none;
  border-color: var(--safe);
  box-shadow: 0 0 0 3px rgba(57, 255, 138, 0.1);
}

.session-withdraw-form .intake-row button {
  background: linear-gradient(135deg, #39ff8a, #1fbf67);
  color: #06140b;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 12px;
  border: none;
  border-radius: 10px;
  padding: 8px 16px;
  cursor: pointer;
}

/* Balance refresh button — small icon-only pill next to the SOL value */
.session-balance-value-group {
  display: flex;
  align-items: center;
  gap: 6px;
}

.session-refresh-btn {
  background: transparent;
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-size: 13px;
  line-height: 1;
  border-radius: 10px;
  padding: 3px 6px;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, transform 0.3s;
}

.session-refresh-btn:hover {
  border-color: var(--safe);
  color: var(--safe);
}

.session-refresh-btn.spinning {
  transform: rotate(360deg);
}

/* Withdraw quick-percent buttons */
.session-withdraw-pct-row {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}

.session-withdraw-pct-btn {
  flex: 1;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 11px;
  border-radius: 10px;
  padding: 5px 0;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}

.session-withdraw-pct-btn:hover {
  border-color: var(--pin);
  color: var(--pin);
}

/* SOL/USD display toggle */
.currency-toggle-btn {
  background: transparent;
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.05em;
  padding: 6px 12px;
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}

.currency-toggle-btn:hover {
  border-color: var(--safe);
  color: var(--safe);
}

.currency-toggle-btn.usd-mode {
  border-color: var(--pin);
  color: var(--pin);
}

/* Small supplementary ≈$ hints next to SOL-denominated inputs — always visible
   regardless of the SOL/USD toggle above, since these are inputs (stay SOL), not
   pure display values. */
.stat-unit-usd {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  color: var(--ink-dim);
  margin-left: 4px;
}

/* Shared by the sidebar's Session Wallet "Sign Out" and the account menu's "Log Out"
   (see #account-menu-logout-btn) — same action-family styling, two different scopes
   (sign out of the app session vs. full log out + wallet disconnect). */
.wallet-disconnect-btn,
.sniper-theme .wallet-disconnect-btn,
.account-menu-logout-btn,
.sniper-theme .account-menu-logout-btn {
  background: transparent;
  border: 1px solid rgba(255, 59, 59, 0.3);
  color: rgba(255, 59, 59, 0.7);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 10px;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.15s;
}

.wallet-disconnect-btn:hover,
.sniper-theme .wallet-disconnect-btn:hover,
.account-menu-logout-btn:hover,
.sniper-theme .account-menu-logout-btn:hover {
  background: rgba(255, 59, 59, 0.1);
  border-color: rgba(255, 59, 59, 0.6);
  color: #ff3b3b;
}

.wallet-pick-btn {
  background: rgba(255, 176, 32, 0.12);
  border: 1px solid rgba(255, 176, 32, 0.4);
  color: var(--pin);
  font-family: 'Rajdhani', sans-serif;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.15s;
}

.wallet-pick-btn:hover {
  background: rgba(255, 176, 32, 0.22);
}

/* ─── Editable Stats Bar ─────────────────────────────────────────────────── */
.sniper-theme .stat-box--editable {
  cursor: text;
}

.sniper-theme .stat-edit-row {
  display: flex;
  align-items: baseline;
  gap: 3px;
}

.sniper-theme .stat-input {
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(57, 255, 138, 0.25);
  color: var(--paper);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 20px;
  width: 60px;
  outline: none;
  padding: 0 2px;
  transition: border-color 0.2s;
  -moz-appearance: textfield;
}

.sniper-theme .stat-input::-webkit-outer-spin-button,
.sniper-theme .stat-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.sniper-theme .stat-input--narrow {
  width: 40px;
}

.sniper-theme .stat-input:focus {
  border-bottom-color: rgba(57, 255, 138, 0.75);
  outline: none;
}

.sniper-theme .stat-input.input-saved {
  border-bottom-color: var(--safe);
  color: var(--safe);
}

/* ─── Per-trade custom amount/TP/SL (in the fire confirm card) ─────────────── */
.sniper-theme .custom-trade-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: baseline;
  margin: 10px 0;
  padding: 8px 10px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
}

.sniper-theme .custom-trade-row label {
  display: flex;
  align-items: baseline;
  gap: 5px;
  font-size: 10.5px;
  color: var(--ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.sniper-theme .custom-trade-row .stat-input {
  font-size: 13px;
  width: 48px;
}

.sniper-theme .custom-trade-row .stat-input--narrow {
  width: 34px;
}

.sniper-theme .stat-input.input-error {
  border-bottom-color: var(--danger);
  color: var(--danger);
}

.sniper-theme .stat-unit {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-dim);
}

.sniper-theme .stat-prefix {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-dim);
}

.sniper-theme .stat-sep {
  font-family: 'Rajdhani', sans-serif;
  font-size: 18px;
  color: var(--ink-dim);
  margin: 0 3px;
}

/* ─── Candle Chart Modal ─────────────────────────────────────────────────── */
.candle-modal {
  max-width: 1100px !important;
  width: 95% !important;
  padding: 20px !important;
  /* The modal is centered by its overlay (align-items: center) with no scroll
     handling of its own — on a shorter browser window, a tall modal (chart + stat
     row + timeframe row + volume + trade panel) overflowed past the top AND bottom
     of the viewport with literally no way to reach the clipped parts, since the
     overlay itself doesn't scroll. Capping height and scrolling internally fixes
     that regardless of window size. */
  max-height: 90vh !important;
  overflow-y: auto !important;
}

/* Position chart modal — the "expand" view opened from a position card's spark
   chart. Same modal shell/width as the DexScreener chart modal above, but always
   shows our own OHLCV renderer (real GeckoTerminal bars + volume + entry marker)
   rather than an iframe, since only our own chart knows where the entry actually
   was. renderOhlcChart() returns two stacked SVGs (price, volume) sized to sum to
   exactly the h it was called with — no height:100% needed/wanted here, that would
   just stretch both to the full box and overlap them. */
.sniper-theme .position-chart-wrap {
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
}

.sniper-theme .position-chart-wrap .ohlc-volume {
  margin-top: 4px;
  border-top: 1px solid var(--card-edge);
  padding-top: 4px;
}

.sniper-theme .ohlc-chart-status {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--ink-dim);
  text-align: center;
  padding: 80px 20px;
}

/* ─── Check-result live chart ────────────────────────────────────────────── */
/* Same stacked price+volume OHLC chart as the position modal (renderOhlcChart,
   .position-chart-wrap), reused here so a token that's just cleared its check and is
   ready to fire gets a real price chart right at the decision point — not just after
   you've already bought it. See startCheckChart/loadCheckChart in snipe.js. */
.sniper-theme .check-chart-section {
  margin: 10px 0 14px;
}

.sniper-theme .check-chart-wrap {
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
}

.sniper-theme .check-chart-wrap .ohlc-volume {
  margin-top: 4px;
  border-top: 1px solid var(--card-edge);
  padding-top: 4px;
}

.sniper-theme .check-chart-wrap .ohlc-chart-status {
  padding: 40px 20px;
}

/* Header: title + a big live price ticker with a P&L pill next to it, instead of one
   small line of text — the "look like a real trading terminal" pass. */
.sniper-theme .position-chart-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-bottom: 14px;
}

.sniper-theme .position-chart-header .hud-modal-title {
  margin-bottom: 0;
}

.sniper-theme .position-chart-price-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.sniper-theme .position-chart-price {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 600;
  font-size: 22px;
  color: var(--paper);
  text-shadow: 0 0 12px rgba(57, 255, 138, 0.25);
}

.sniper-theme #position-chart-pnl-badge {
  font-size: 13px;
  padding: 4px 10px;
}

/* Stat-tile row: entry price, peak P&L, position size, holder concentration — the
   "see everything at a glance" grid, same corner-bracket language as .stat-box. */
.sniper-theme .position-chart-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-bottom: 16px;
}

@media (max-width: 700px) {
  .sniper-theme .position-chart-stats { grid-template-columns: repeat(2, 1fr); }
}

.sniper-theme .pc-stat {
  position: relative;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow: hidden;
}

/* Corner bracket dropped — see .sidebar-section::after's comment above. */
.sniper-theme .pc-stat::after {
  content: none;
}

.sniper-theme .pc-stat--wide {
  grid-column: span 2;
}

.sniper-theme .pc-stat-label {
  font-family: 'Rajdhani', monospace;
  font-size: 9px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.sniper-theme .pc-stat-value {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--paper);
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.sniper-theme .pc-stat-value.pc-up { color: var(--safe); }
.sniper-theme .pc-stat-value.pc-down { color: var(--danger); }

.sniper-theme .pc-stat-sub {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-dim);
}

.sniper-theme .chart-timeframe-row-outer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 12px;
  margin-bottom: 12px;
}

.sniper-theme .chart-timeframe-row {
  display: flex;
  gap: 4px;
}

.sniper-theme .chart-drag-hint {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-dim);
}

.sniper-theme .chart-drag-hint-tp {
  color: var(--safe);
  font-weight: 700;
}

.sniper-theme .chart-drag-hint-sl {
  color: var(--danger);
  font-weight: 700;
}

/* Canvas wrapping the scrollable chart — the TP/SL handles are positioned relative
   to THIS, as absolutely-positioned HTML (not SVG) elements. That's deliberate: the
   chart itself scrolls horizontally, but a draggable price handle needs to stay put
   at a fixed horizontal spot (pinned to the right edge, like a real trading platform's
   order line) regardless of how far back through history you've scrolled — an SVG-
   native handle would scroll away with the candles and be impossible to grab. */
.sniper-theme .position-chart-canvas {
  position: relative;
}

.sniper-theme .order-line-handle {
  position: absolute;
  right: 10px;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 10px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.03em;
  cursor: ns-resize;
  user-select: none;
  touch-action: none;
  z-index: 3;
  box-shadow: 0 2px 10px -2px rgba(0, 0, 0, 0.7);
  transition: filter 0.1s, box-shadow 0.1s;
}

.sniper-theme .order-line-handle.hidden {
  display: none;
}

.sniper-theme .order-line-handle:hover,
.sniper-theme .order-line-handle.dragging {
  filter: brightness(1.15);
}

.sniper-theme .order-line-handle.dragging {
  box-shadow: 0 0 14px -1px currentColor;
}

.sniper-theme .order-line-tp {
  background: var(--safe);
  color: #04160c;
}

.sniper-theme .order-line-sl {
  background: var(--danger);
  color: #1a0505;
}

.sniper-theme .chart-tf-btn {
  padding: 5px 12px;
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.3);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}

.sniper-theme .chart-tf-btn:hover {
  color: var(--ink);
  border-color: var(--ink-dim);
}

.sniper-theme .chart-tf-btn.active {
  color: var(--safe);
  border-color: var(--safe);
  background: rgba(57, 255, 138, 0.1);
}

/* The 1s timeframe is this bot own tick tape, updating as trades land rather than on a
   bar schedule — the pulsing dot is what tells you it is live rather than another
   historical resolution. */
.sniper-theme .chart-tf-btn--live {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.chart-tf-live-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.45;
}

.sniper-theme .chart-tf-btn--live.active .chart-tf-live-dot {
  opacity: 1;
  animation: tf-live-pulse 1s ease-in-out infinite;
}

@keyframes tf-live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.3; transform: scale(0.7); }
}

@media (prefers-reduced-motion: reduce) {
  .sniper-theme .chart-tf-btn--live.active .chart-tf-live-dot { animation: none; }
}

/* Trade panel — visually separated "danger zone" for closing the position, instead
   of the sell buttons just sitting loose under the chart. */
.sniper-theme .position-chart-trade-panel {
  border-top: 1px dashed var(--card-edge);
  padding-top: 14px;
}

.sniper-theme .position-chart-trade-panel .panel-label {
  margin-bottom: 8px;
}

.sniper-theme #position-chart-modal .partial-sell-row {
  margin-top: 0;
  gap: 8px;
}

.sniper-theme #position-chart-modal .partial-sell-btn {
  padding: 10px 4px;
  font-size: 12px;
}

.sniper-theme .sell-btn--full {
  margin-top: 10px;
  padding: 13px;
  font-size: 14px;
  font-weight: 700;
  background: linear-gradient(135deg, rgba(255, 107, 107, 0.18), rgba(255, 59, 59, 0.12));
  border: 1px solid rgba(255, 59, 59, 0.5);
  box-shadow: 0 0 20px -4px rgba(255, 59, 59, 0.35);
}

.sniper-theme .sell-btn--full:hover {
  background: linear-gradient(135deg, rgba(255, 107, 107, 0.28), rgba(255, 59, 59, 0.2));
  box-shadow: 0 0 26px -2px rgba(255, 59, 59, 0.5);
}

.sniper-theme #position-chart-modal .hud-modal-actions {
  margin-top: 14px;
}

.candle-modal-body {
  position: relative;
  margin-bottom: 16px;
}

.candle-iframe {
  display: block;
  width: 100%;
  height: min(80vh, 780px);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  background: #070a08;
}

.candle-modal-status {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--ink-dim);
  text-align: center;
  padding: 60px 0;
}

/* ─── Wallet balance stat box ─────────────────────────────────────────────── */
.sniper-theme #stat-wallet-bal .stat-value {
  font-size: 17px;
}

/* ─── Moon Bag Engine ────────────────────────────────────────────────────────
   Mode-button row reuses .smart-exit-mode-btn's base styling (see the Smart Exit
   block above) — just its own single accent color per active state instead of the
   safe/amber/danger risk-tier language Smart Exit's off/assisted/auto uses, since
   Classic/Smart/Extreme aren't risk-tiered the same way. */
.sniper-theme .moon-bag-mode-btn[data-mode].active {
  background: var(--pin);
  border-color: var(--pin);
  color: #1a1408;
}

.sniper-theme .moon-bag-settings-btn {
  width: 100%;
  padding: 6px 10px;
  font-size: 11px;
}

/* Settings modal */
.sniper-theme .moon-bag-modal {
  max-width: 480px !important;
}

.sniper-theme .moon-bag-modal-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.sniper-theme .moon-bag-preset-row {
  display: flex;
  gap: 8px;
}

.sniper-theme .moon-bag-preset-btn {
  flex: 1;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: 0.03em;
  padding: 8px 4px;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.15s ease;
}

.sniper-theme .moon-bag-preset-btn:hover {
  border-color: var(--safe);
  color: var(--safe);
}

.sniper-theme .moon-bag-preset-btn--degen:hover {
  border-color: var(--danger);
  color: var(--danger);
}

.sniper-theme .moon-bag-field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.sniper-theme .moon-bag-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.sniper-theme .moon-bag-field-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--ink-dim);
  text-transform: uppercase;
}

.sniper-theme .moon-bag-toggle-grid {
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-top: 1px solid var(--card-edge);
  padding-top: 12px;
}

.sniper-theme .moon-bag-toggle-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11.5px;
  color: var(--ink);
  cursor: pointer;
}

.sniper-theme .moon-bag-toggle-row input[type="checkbox"] {
  width: 14px;
  height: 14px;
  accent-color: var(--pin);
  margin: 0;
}

.sniper-theme .moon-bag-toggle-row--locked {
  color: var(--ink-dim);
  cursor: not-allowed;
  opacity: 0.75;
}

.sniper-theme .moon-bag-toggle-row--locked input[type="checkbox"] {
  accent-color: var(--safe);
}

/* Position-card dashboard section — inserted after .cluster-funder, same "return ''
   when nothing to show" convention as .exit-risk-badge above: only rendered once a
   position has actually crossed into moon-bag territory. */
.sniper-theme .moon-bag-row {
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px solid rgba(255, 176, 32, 0.25);
  border-radius: 10px;
  background: rgba(255, 176, 32, 0.04);
}

.sniper-theme .moon-bag-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 5px;
}

.sniper-theme .moon-bag-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
}

.sniper-theme .moon-bag-badge.strong { color: var(--safe); }
.sniper-theme .moon-bag-badge.weakening { color: var(--pin); }
.sniper-theme .moon-bag-badge.exiting { color: var(--danger); animation: live-pulse 1.6s ease-in-out infinite; }

.sniper-theme .moon-bag-score {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--ink-dim);
}

.sniper-theme .moon-bag-explanation {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink);
  margin-bottom: 5px;
}

.sniper-theme .moon-bag-capital-row {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-dim);
  margin-bottom: 4px;
}

.sniper-theme .moon-bag-capital-row.recovered {
  color: var(--safe);
}

.sniper-theme .moon-bag-meta {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  color: var(--ink-dim);
}

/* ══════════════════════════════════════════════════════════════════════════
   PHASE 1 REDESIGN ADDITIONS — softer, rounder card language (Traderly-
   inspired mockup), scoped to #sniper-app / .sniper-theme-only ids so it
   doesn't bleed onto the Scanner page (which also loads this stylesheet).
   Reuses the exact same tokens as the rest of the file (--safe/--pin/
   --danger/--card/--card-edge) — no new custom properties introduced.
   ══════════════════════════════════════════════════════════════════════════ */

/* ─── Gear icon (opens the Trading Settings modal) ─────────────────────── */
.settings-gear-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--card-edge);
  background: transparent;
  color: var(--ink-dim);
  font-size: 15px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s, color 0.15s, transform 0.15s;
}

.settings-gear-btn:hover {
  border-color: var(--safe);
  color: var(--safe);
  transform: rotate(30deg);
}

/* ─── Settings modal (extends .hud-modal, same pattern as .moon-bag-modal) ─ */
.sniper-theme .settings-modal {
  max-width: 560px !important;
  max-height: 84vh;
  overflow-y: auto;
  border-radius: 16px;
}

.settings-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}

.settings-modal-close-x {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--card-edge);
  background: transparent;
  color: var(--ink-dim);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  flex-shrink: 0;
}

.settings-modal-close-x:hover {
  border-color: var(--danger);
  color: var(--danger);
}

.settings-modal-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 18px;
}

/* Settings cards inside the modal reuse .control-group/.settings-card as-is
   (same corner-bracket HUD accent as everywhere else) but stack full-width
   instead of the old 3-column grid, since the modal itself is already narrow. */
.settings-modal-body .settings-card {
  border-radius: 12px;
}

/* ─── Positions ticker (open positions + Smart-Entry armed orders, merged) ─ */
/* Full-bleed bordered row flush under the nav, reading as one more band of page
   chrome rather than as the first card on the board — which is why the markup puts
   it outside .sniper-layout and this rule carries its own centred inner box at the
   same max-width/padding as .site-nav--wide's, so the label lines up with the brand
   above it and the board below. */
.positions-ticker {
  border-bottom: 1px solid var(--card-edge);
  background: var(--board);
}

.positions-ticker-inner {
  max-width: 1600px;
  margin: 0 auto;
  padding: 11px 28px;
  display: flex;
  align-items: center;
  gap: 22px;
}

.positions-ticker-label {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: 0.08em;
  color: var(--ink-dim);
  white-space: nowrap;
  flex-shrink: 0;
}

/* Only the chips scroll. Putting overflow on the whole row instead let a long run of
   open positions carry the label and the "Manage positions →" link off to the right
   with it, and gave the row a scrollbar that read as the page's own. */
.positions-ticker-scroll {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  overflow-x: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--card-edge) transparent;
}

.positions-ticker-scroll::-webkit-scrollbar { height: 4px; }
.positions-ticker-scroll::-webkit-scrollbar-track { background: transparent; }
.positions-ticker-scroll::-webkit-scrollbar-thumb { background: var(--card-edge); border-radius: 8px; }

.positions-ticker-link {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  color: var(--safe);
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
}

.positions-ticker-link:hover { text-decoration: underline; }

/* Second copy of that link, at the HEAD of the strip — only rendered once the ticker is
   carrying POSITIONS_HINT_MIN+ open positions (renderPositions() in snipe.js toggles
   .hidden; this never appears on count alone in CSS). A pill rather than bare text, so
   it reads as a control appearing next to the chips rather than as another chip. */
.positions-ticker-hint {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 4px 11px;
  border: 1px solid rgba(var(--pin-rgb), 0.45);
  border-radius: 100px;
  background: rgba(var(--pin-rgb), 0.1);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--pin);
  text-decoration: none;
  white-space: nowrap;
  /* Runs once, when the element goes from display:none to shown — i.e. exactly when the
     fifth position opens, not on every 3s re-render (the element is toggled, not
     rebuilt). */
  animation: positions-hint-pop 0.4s cubic-bezier(0.2, 0.9, 0.3, 1.4);
}

/* style.css's generic `.hidden { display: none }` loads BEFORE this file and carries the
   same specificity, so the display above would otherwise win and the hint would never
   actually hide. */
.positions-ticker-hint.hidden { display: none; }

.positions-ticker-hint:hover {
  background: rgba(var(--pin-rgb), 0.2);
  border-color: var(--pin);
}

@keyframes positions-hint-pop {
  from { opacity: 0; transform: translateX(-8px) scale(0.9); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .positions-ticker-hint { animation: none; }
}

.ticker-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

/* Empty rows must not reserve space, or the "no positions" and "nothing armed"
   placeholders both render and the row shows two of them side by side. */
.ticker-row:empty {
  display: none;
}

.ticker-row .sidebar-empty {
  white-space: nowrap;
  padding: 4px 0;
}

@media (max-width: 640px) {
  .positions-ticker-inner {
    padding: 10px 16px;
    gap: 14px;
  }
  .positions-ticker-label,
  .positions-ticker-hint,
  .positions-ticker-link { font-size: 11px; }
  .positions-ticker-hint { padding: 3px 9px; }
}

/* Compact ticker chip — an open position (renderPositions()) or an armed/waiting
   order (loadArmed()), both riding the same horizontal strip. Pill-shaped, one
   line: mini chart + symbol + price read, click opens the full position modal
   (see .spark-expand-btn's document-level handler in snipe.js). */
.ticker-chip {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  white-space: nowrap;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  border: 1px solid var(--card-edge);
  border-radius: 100px;
  padding: 5px 12px 5px 8px;
  cursor: pointer;
  background: var(--card);
  transition: border-color 0.15s;
}

.ticker-chip:hover {
  border-color: var(--safe);
}

/* overflow:hidden is the backstop for renderCandles() ever handing back a sparkline
   wider than the chip asked for — it used to, and the oversized SVG painted straight
   out of the chip and stretched the whole document sideways. The chart is sized by
   renderCandles({ fit: true }); this just guarantees nothing escapes if that changes. */
.ticker-chip-spark {
  display: flex;
  align-items: center;
  line-height: 0;
  overflow: hidden;
  flex-shrink: 0;
}

.ticker-chip-symbol {
  color: var(--ink);
}

.ticker-chip-pct {
  font-weight: 600;
}

.ticker-chip.pos .ticker-chip-pct { color: var(--safe); }
.ticker-chip.neg .ticker-chip-pct { color: var(--danger); }

.ticker-chip .exit-risk-badge {
  padding: 1px 6px;
  font-size: 9px;
}

/* Armed/waiting variant — dashed amber border instead of the solid card-edge
   border open positions use, so "not filled yet" reads at a glance. */
.ticker-chip--armed {
  border: 1px dashed var(--pin);
  padding-left: 10px;
  color: var(--ink-dim);
  cursor: default;
}

.ticker-chip--armed:hover {
  border-color: var(--pin);
}

.ticker-chip-meta {
  font-size: 11.5px;
}

.status-pill {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 9.5px;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 100px;
  display: inline-block;
}

.status-pill--armed {
  background: rgba(var(--pin-rgb), 0.15);
  color: var(--pin);
}

/* Resize-armed-order dialog content (snipe.js askArmAmount) — tokens only */
.arm-amount-edit { display: flex; flex-direction: column; gap: 12px; }
.arm-amount-meta { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; font-size: 12px; color: var(--ink-dim); }
.arm-amount-meta b { color: var(--ink); font-weight: 600; }
.arm-amount-sym { font-family: 'Space Grotesk', sans-serif; font-size: 15px; font-weight: 700; color: var(--safe); }
.arm-amount-presets { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.arm-amount-preset { padding: 8px 0; font-family: 'IBM Plex Mono', monospace; font-size: 12px; color: var(--ink); background: transparent; border: 1px solid var(--line); border-radius: var(--radius-s); cursor: pointer; transition: border-color .15s, background .15s; }
.arm-amount-preset:hover { border-color: rgba(var(--safe-rgb), 0.5); }
.arm-amount-preset.is-active { color: var(--safe); border-color: rgba(var(--safe-rgb), 0.7); background: rgba(var(--safe-rgb), 0.1); }
.arm-amount-field { display: flex; align-items: center; gap: 8px; padding: 0 12px; border: 1px solid rgba(var(--safe-rgb), 0.45); border-radius: var(--radius-s); background: rgba(var(--safe-rgb), 0.04); }
.arm-amount-field:focus-within { border-color: var(--safe); box-shadow: 0 0 0 3px rgba(var(--safe-rgb), 0.12); }
.arm-amount-field input { flex: 1; min-width: 0; padding: 11px 0; font-family: 'IBM Plex Mono', monospace; font-size: 18px; color: var(--ink); background: transparent; border: 0; outline: none; }
.arm-amount-field span { font-family: 'IBM Plex Mono', monospace; font-size: 12px; color: var(--ink-dim); letter-spacing: .08em; }
.arm-amount-hint { font-size: 11.5px; color: var(--ink-dim); }
.arm-amount-hint.is-error { color: var(--danger); }
.edit-arm-amount-btn { margin-left: 4px; padding: 1px 6px; font: inherit; font-size: 10.5px; color: var(--safe); background: transparent; border: 1px solid rgba(var(--safe-rgb), 0.45); border-radius: var(--radius-s); cursor: pointer; }
.edit-arm-amount-btn:hover:not(:disabled) { background: rgba(var(--safe-rgb), 0.12); }
.ticker-chip-cancel {
  background: none;
  border: none;
  color: var(--ink-dim);
  cursor: pointer;
  font-size: 11px;
  padding: 0 0 0 2px;
  line-height: 1;
}

.ticker-chip-cancel:hover {
  color: var(--danger);
}

/* ─── Check Result panel — rounder card, scoped to Sniper Desk's own check
   flow so the shared .cluster-card base (also used on the Scanner page)
   isn't affected there. ─────────────────────────────────────────────────── */
#check-result .cluster-card {
  /* containing block for the dismiss button pinned to the card corner */
  position: relative;
  border-radius: 14px;
  padding: 18px 20px;
}

/* Dismiss the dossier and fall back to the "High-Probability Right Now" panel.
   Sits in the card corner rather than the flow so it lands in the same place on
   every verdict variant (rejected, warning, passed). */
.check-close-btn {
  position: absolute;
  top: 10px;
  right: 12px;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 8px;
  border: 1px solid var(--card-edge);
  background: rgba(0, 0, 0, 0.35);
  color: var(--muted);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}

.check-close-btn:hover {
  color: var(--ink);
  border-color: var(--danger);
  background: rgba(var(--danger-rgb), 0.14);
}

/* The header text sits under an absolutely positioned button — keep the name and
   badge clear of it. */
#check-result .target-header {
  padding-right: 32px;
}

/* ─── Quick Snipe card (trade mode + fire mode + settings readout) ──────── */
#sniper-app .control-group,
#sniper-app .intake {
  border-radius: 14px;
}

.quick-snipe-readout {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--ink);
  flex-wrap: wrap;
}

.quick-snipe-edit-link {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--safe);
  font-family: 'Rajdhani', sans-serif;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}

.quick-snipe-edit-link:hover {
  text-decoration: underline;
}

/* ─── Account menu dropdown — wider now that it also holds the session
   wallet panel (moved here from the old left sidebar). ─────────────────── */
.account-menu-dropdown {
  width: 300px;
  max-height: 80vh;
  overflow-y: auto;
  border-radius: 14px;
}

/* ─── HUD confirmation modal — same visuals, tokens instead of hardcoded hex
   so it stays theme-consistent, plus the softer radius used everywhere else
   in this pass. ──────────────────────────────────────────────────────────── */
.hud-modal {
  background: var(--card);
  border-color: var(--card-edge);
  border-radius: 16px;
}

.hud-modal-message {
  color: var(--ink);
}

/* Get Started (onboarding) modal — same step logic in snipe.js, softer card. */
.onboard-modal {
  border-radius: 16px;
}

.onboard-modal-step .onboard-step-num {
  border-radius: 50%;
}

/* ─── Skeleton loading — a new coin still being checked, shown as the first
   card in the Live Feed board (see #current-checking-line's data driving
   renderFeed() in snipe.js). Reuses .dossier-card's own footprint but with a
   shimmering placeholder instead of real content. ──────────────────────── */
@keyframes dossier-skeleton-shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

.dossier-skeleton-bar {
  display: block;
  border-radius: 10px;
  background: linear-gradient(90deg, var(--card-edge) 25%, rgba(255,255,255,0.08) 37%, var(--card-edge) 63%);
  background-size: 400% 100%;
  animation: dossier-skeleton-shimmer 1.6s ease-in-out infinite;
}

.dossier-skeleton-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  font-style: italic;
  color: var(--ink-dim);
  margin-top: 6px;
}

.dossier-skeleton-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--pin);
  animation: dossier-skeleton-pulse 1.3s ease-in-out infinite;
}

@keyframes dossier-skeleton-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* ══════════════════════════════════════════════════════════════════════════
   FEED CARD — the Live Feed's real card, replacing the old tan "mugshot on a
   case board" .dossier-card with a flat dark rounded card matching the rest of
   the redesign. Built from the exact same candidate fields as before (see
   renderClearedCard()/renderRejectedCard() in snipe.js) — this is a visual
   rebuild, not new data.
   ══════════════════════════════════════════════════════════════════════════ */
.feed-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  padding: 16px;
  transition: border-color 0.15s, transform 0.15s;
}

.feed-card:hover {
  border-color: var(--safe);
  transform: translateY(-2px);
}

.feed-card--rejected {
  opacity: 0.6;
}

.feed-card--rejected:hover {
  opacity: 1;
  border-color: var(--danger);
}

.feed-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.feed-card-id {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.feed-card-avatar {
  position: relative;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--board);
  border: 1px solid var(--card-edge);
  display: flex;
  align-items: center;
  justify-content: center;
}

.feed-card-avatar img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.feed-card-avatar-fallback {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink-dim);
}

.feed-card-symbol {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13.5px;
  color: var(--ink);
}

.feed-card-name {
  font-size: 10.5px;
  color: var(--ink-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 120px;
}

.feed-card-badge {
  flex-shrink: 0;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 9.5px;
  letter-spacing: 0.06em;
  padding: 3px 8px;
  border-radius: 100px;
}

.feed-card-badge.safe { background: rgba(var(--safe-rgb), 0.14); color: var(--safe); }
.feed-card-badge.caution { background: rgba(var(--pin-rgb), 0.14); color: var(--pin); }
.feed-card-badge.risky { background: rgba(var(--danger-rgb), 0.14); color: var(--danger); }

.feed-card-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--ink-dim);
}

.feed-card-btn {
  width: 100%;
  text-align: center;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  border: none;
  border-radius: 10px;
  padding: 9px;
  background: var(--safe);
  color: #04140b;
  cursor: pointer;
}

.feed-card-btn:hover {
  filter: brightness(1.08);
}

.feed-card-btn--ghost {
  background: transparent;
  border: 1px solid var(--card-edge);
  color: var(--ink-dim);
}

.feed-card-btn--ghost:hover {
  border-color: var(--danger);
  color: var(--danger);
  filter: none;
}

/* Dark-card versions of badges/lines shared with the old .dossier-card (their base
   rules above were built for the light tan card and would be unreadable here). */
.feed-card .dossier-rug-badge,
.feed-card .dossier-prepump-badge,
.feed-card .dossier-creator-profit-badge {
  display: block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  padding: 4px 8px;
  border-radius: 8px;
}
.feed-card .dossier-rug-badge { color: var(--danger); background: rgba(var(--danger-rgb), 0.1); border: 1px solid rgba(var(--danger-rgb), 0.3); }
.feed-card .dossier-prepump-badge { color: var(--pin); background: rgba(var(--pin-rgb), 0.1); border: 1px solid rgba(var(--pin-rgb), 0.3); }
.feed-card .dossier-creator-profit-badge { color: var(--safe); background: rgba(var(--safe-rgb), 0.1); border: 1px solid rgba(var(--safe-rgb), 0.3); }

.feed-card .dossier-creator-line {
  font-size: 10.5px;
  color: var(--ink-dim);
  margin: 0;
}
.feed-card .dossier-creator-line.rugged {
  color: var(--danger);
  font-weight: 600;
}

.feed-card .dossier-socials {
  display: flex;
  gap: 8px;
  margin: 0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   REDESIGN LAYOUT — Sniper Desk board + Live Feed page
   ═══════════════════════════════════════════════════════════════════════════
   Everything from here down implements the redesign artboards. The Sniper Desk
   used to be a three-column board (trade log | controls | discovery sidebar);
   it's now: positions ticker → Quick Snipe beside the check result → a Live Feed
   preview across the bottom. Trade history became /stats.html and the full
   discovery board became /feed.html, both of which reuse the components here.

   The .sniper-header / .sniper-stats-bar rules further up are dead in this
   layout (the page title block and the daily-P&L/wallet/max-trade strip are
   gone — their contents live in the nav, the account menu, the Stats page and
   the ⚙ Settings modal). They're left in place because .stat-box, .panel-label
   and .stat-value are shared components the Stats page still styles against. */

/* ─── Sniper Desk board ──────────────────────────────────────────────────── */
.sniper-body {
  grid-template-columns: 400px 1fr;
}

@media (max-width: 1280px) {
  .sniper-body {
    grid-template-columns: 360px 1fr;
  }
}

@media (max-width: 960px) {
  .sniper-body {
    grid-template-columns: 1fr;
  }
  /* .sniper-main's `order: -1` from the old three-column rules would flip Quick
     Snipe above the check result — which is already the source order here. */
  .sniper-main {
    order: 0;
  }
}

/* ─── Quick Snipe card ───────────────────────────────────────────────────── */
/* One card, in the artboard's order: fire mode, mint + Check, trade mode, then a
   read-only mirror of the ⚙ Settings defaults. The .intake inside it drops its
   own card chrome — it's a section of this card, not a card of its own. */
.quick-snipe-card {
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.quick-snipe-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.quick-snipe-title {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--paper);
}

.quick-snipe-card .intake {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  /* style.css's .intake is a standalone card with a 48px top margin of its own —
     here it's a section inside this card, and the card's flex `gap` spaces it. */
  margin: 0;
  box-shadow: none;
}

/* Pills drop to their own line under the title when the card is narrow, rather
   than wrapping "Smart Entry" onto two lines inside the pill. */
.quick-snipe-head .fire-mode-btn {
  white-space: nowrap;
}

.quick-snipe-card .control-group-section {
  padding: 0;
}

.quick-snipe-card .trade-mode-note:empty {
  display: none;
}

/* ─── Check result column ────────────────────────────────────────────────── */
.sniper-check-col {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* The High-Probability panel below owns this column until a check has actually run,
   at which point the dossier takes over entirely. :has() on the column rather
   than a JS toggle: #check-result already owns the .hidden class as its single
   source of truth (runCheck/renderCheckResult flip it in five places), so this
   can never drift out of sync with it. */
.sniper-check-col:has(#check-result:not(.hidden)) .check-empty {
  display: none;
}

.check-empty {
  background: var(--card);
  border: 1px dashed var(--card-edge);
  border-radius: 16px;
  padding: 18px;
}

/* Demoted from the hero it used to be: the watchlist above is what actually fills
   this column now, and this is the one-line explanation of what replaces it once a
   check runs. */
.check-empty-hint {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 16px 2px 0;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--ink-dim);
}

.check-empty-hint .icn {
  margin-top: 2px;
  color: var(--card-edge);
}

.check-empty-hint strong {
  color: var(--safe);
  font-weight: 600;
}

/* ─── High-probability watchlist (owns the check column while nothing is checked) ── */
.check-empty-watchlist {
  text-align: left;
}

.check-empty-watchlist-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
  padding: 0 2px;
}

.check-empty-watchlist-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
}

.check-empty-watchlist-title .icn {
  color: var(--safe);
}

.check-empty-watchlist-sub {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--ink-dim);
}

.check-empty-watchlist-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* ── High-probability card ───────────────────────────────────────────────────────────
   Identity on top (the coin's own picture carries the card), a compact stats strip, and
   the price line running edge to edge across the whole base. */
.hp-card {
  position: relative;
  background: linear-gradient(180deg, rgba(var(--safe-rgb), 0.04), transparent 45%), var(--board);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  /* The graph is full-bleed, so the card clips instead of padding, and each section
     carries its own inset. */
  padding: 0;
  overflow: hidden;
  transition: border-color 0.18s, box-shadow 0.18s;
}

.hp-card:hover {
  border-color: rgba(var(--safe-rgb), 0.4);
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.08), 0 10px 30px rgba(0, 0, 0, 0.4);
}

.hp-head {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 16px 18px 12px;
}

/* The coin's picture, deliberately large — it's the fastest thing to recognise on a board
   of launches, and at the old 42px it read as a favicon. */
.hp-avatar-xl {
  position: relative;
  width: 76px;
  height: 76px;
  flex-shrink: 0;
  border-radius: 16px;
  overflow: hidden;
  background: #0a0f0c;
  border: 1px solid var(--card-edge);
  box-shadow: 0 0 0 3px rgba(var(--safe-rgb), 0.07);
}

.hp-avatar-xl img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.hp-avatar-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 30px;
  color: var(--ink-dim);
}

/* An image that loaded covers the fallback letter underneath it. */
.hp-avatar-xl img + .hp-avatar-fallback { display: none; }

.hp-head-main {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.hp-name {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 19px;
  line-height: 1.15;
  color: var(--paper);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hp-sym {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 400;
  font-size: 12.5px;
  color: var(--safe);
  margin-left: 7px;
}

.hp-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-dim);
}

.hp-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.hp-meta .icn { width: 1.05em; height: 1.05em; }

.hp-stage {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
}

.hp-stage-dot { width: 0.62em; height: 0.62em; color: var(--safe); }

/* ── Creator ─────────────────────────────────────────────────────────────────────── */
.hp-creator {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  align-self: flex-start;
  padding: 3px 8px 3px 6px;
  border-radius: 999px;
  border: 1px solid var(--card-edge);
  background: rgba(160, 111, 214, 0.08);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--creator);
  text-decoration: none;
  transition: border-color 0.15s, background 0.15s;
}

.hp-creator .icn { width: 1.05em; height: 1.05em; }
a.hp-creator:hover { border-color: var(--creator); background: rgba(160, 111, 214, 0.16); }
.hp-creator-name { color: var(--paper); }

/* ── Market cap + score ──────────────────────────────────────────────────────────── */
.hp-head-right {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-shrink: 0;
}

.hp-mcap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.hp-mcap-label {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 9px;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
}

.hp-mcap-value {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 20px;
  line-height: 1;
  color: var(--paper);
}

.hp-delta {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11.5px;
}

.hp-delta.up { color: var(--safe); }
.hp-delta.down { color: var(--danger); }


/* ── Score ring ──────────────────────────────────────────────────────────────────────
   The Smart Finder score as an arc as well as a number — "49 out of 100" readable without
   reading. Colour is set on the wrapper so the arc, the number and the ring all track it. */
.hp-score {
  position: relative;
  flex-shrink: 0;
  width: 62px;
  height: 62px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--ink-dim);
}

.hp-score.hot { color: var(--safe); }
.hp-score.warm { color: var(--pin); }
.hp-score.cool { color: var(--ink-dim); }

.hp-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.hp-ring-track {
  fill: none;
  stroke: var(--card-edge);
  stroke-width: 3.5;
}

.hp-ring-fill {
  fill: none;
  stroke: currentColor;
  stroke-width: 3.5;
  stroke-linecap: round;
  transition: stroke-dasharray 0.4s ease;
}

.hp-score-num {
  position: relative;
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 600;
  font-size: 17px;
  line-height: 1;
  color: currentColor;
}

.hp-score-label {
  position: relative;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 7.5px;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
  margin-top: 2px;
}

/* ── Stats strip ─────────────────────────────────────────────────────────────────── */
.hp-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  margin: 0 18px;
  background: var(--card-edge);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  overflow: hidden;
}

.hp-strip-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 10px;
  background: var(--board);
}

.hp-strip-label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 9.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.hp-strip-label .icn { width: 1.2em; height: 1.2em; }

.hp-strip-value {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12.5px;
  color: var(--paper);
  white-space: nowrap;
}

.hp-buys { color: var(--safe); }
.hp-sells { color: var(--danger); }
.hp-txn-sep { color: var(--ink-dim); margin: 0 3px; }

.hp-buzz { color: var(--ink-dim); font-size: 11px; }
.hp-buzz.warm { color: var(--pin); }
.hp-buzz.hot { color: var(--danger); }
.hp-buzz-num { opacity: 0.65; }

/* ── Footer ──────────────────────────────────────────────────────────────────────── */
.hp-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 18px;
}

/* -webkit-box (not flex) so the reason clamps to two lines; the icon rides inline. */
.hp-reason {
  min-width: 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-dim);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.hp-reason .icn { color: var(--pin); margin-right: 4px; }

/* .sniper-theme .review-btn (two classes) otherwise wins over a plain .hp-btn rule on
   specificity alone, width:100% and all — matching that prefix here is what overrides it. */
.sniper-theme .hp-btn {
  width: auto;
  margin-top: 0;
  flex-shrink: 0;
  padding: 8px 18px;
  font-size: 12px;
}

/* ── Full-bleed price line ───────────────────────────────────────────────────────── */
.hp-graph {
  position: relative;
  height: 96px;
  /* Sits flush to the card's edges — no padding, no border, the base of the card itself. */
  margin: 0;
  background: linear-gradient(180deg, transparent, rgba(var(--safe-rgb), 0.03));
  border-top: 1px solid var(--card-edge);
}

.hp-chart-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 100%;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-dim);
}

@media (max-width: 700px) {
  .hp-head { flex-wrap: wrap; }
  .hp-head-right { width: 100%; justify-content: space-between; }
  .hp-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hp-foot { flex-direction: column; align-items: stretch; }
  .sniper-theme .hp-btn { width: 100%; }
}

/* ── Live price line ─────────────────────────────────────────────────────────────────
   Replaces the candle mini-chart on these cards. A coin minutes old, sampled every ~10s,
   has nothing to say in candle form — it drew as a row of dashes. The line + gradient
   reads at a glance and visibly extends as points arrive. Colour is driven by the move
   itself via .up/.down setting `color`, which the stroke, the gradient stop and the dot
   all inherit through currentColor. */
.hp-line {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

/* Light green regardless of direction — this panel is a recommendation, not a P&L
   readout, and the market-cap delta right above already carries the up/down colour. A
   softer mint than the theme green keeps a full-width graph from shouting over the card. */
.hp-line,
.hp-line.up,
.hp-line.down { color: #7dffb4; }

.hp-line-stroke {
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* preserveAspectRatio="none" on the svg stretches the viewBox to the panel, which would
     also stretch the stroke into an uneven weight. This keeps it a constant hairline. */
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 3px currentColor);
}

.hp-line-dot {
  fill: currentColor;
  vector-effect: non-scaling-stroke;
  animation: hp-dot-pulse 1.6s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}

@keyframes hp-dot-pulse {
  0%, 100% { opacity: 1; r: 2.6; }
  50% { opacity: 0.45; r: 3.6; }
}

/* The heading's own live indicator, so the panel reads as live even while the first
   couple of points are still being collected. */
.hp-chart-label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.hp-live-dot {
  width: 0.6em;
  height: 0.6em;
  color: var(--danger);
  animation: hp-dot-pulse 1.6s ease-in-out infinite;
}

/* ── Social links ────────────────────────────────────────────────────────────────────
   Sits inline with the coin's meta line. Only links a coin actually has are rendered, so
   this collapses to nothing rather than showing dead buttons. */
.hp-socials {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.hp-social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: 1px solid var(--card-edge);
  background: rgba(0, 0, 0, 0.35);
  color: var(--ink-dim);
  text-decoration: none;
  transition: color 0.15s, border-color 0.15s, background 0.15s, transform 0.15s;
}

.hp-social .icn {
  width: 12px;
  height: 12px;
  vertical-align: 0;
}

.hp-social:hover {
  color: var(--paper);
  border-color: var(--safe);
  background: rgba(var(--safe-rgb), 0.12);
  transform: translateY(-1px);
}

.hp-social--twitter:hover { border-color: var(--ink); background: rgba(255, 255, 255, 0.08); }
.hp-social--telegram:hover { border-color: #4aa9e0; background: rgba(74, 169, 224, 0.14); color: #7fc9f5; }
.hp-social--pumpfun:hover { border-color: var(--pin); background: rgba(var(--pin-rgb), 0.14); color: var(--pin); }

@media (prefers-reduced-motion: reduce) {
  .hp-line-dot,
  .hp-live-dot { animation: none; }
}

/* ── Footer: why it scored, and the action ──────────────────────────────────── */
.hp-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid var(--card-edge);
}

/* -webkit-box (not flex) so the reason clamps to two lines — Smart Finder reasons run
   long and this card has a fixed rhythm. The icon is floated inline instead of being a
   flex child for the same reason. */
.hp-reason {
  min-width: 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-dim);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.hp-reason .icn {
  color: var(--pin);
  margin-right: 4px;
}

/* .sniper-theme .review-btn (two classes) otherwise wins over a plain .hp-btn rule on
   specificity alone, width:100% and all — matching that prefix here, not just adding a
   second class, is what actually overrides it. */
.sniper-theme .hp-btn {
  width: auto;
  margin-top: 0;
  flex-shrink: 0;
  padding: 8px 18px;
  font-size: 12px;
}

@media (max-width: 900px) {
  .hp-body {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 560px) {
  .hp-metrics {
    grid-template-columns: minmax(0, 1fr);
  }

  .hp-foot {
    flex-direction: column;
    align-items: stretch;
  }

  .sniper-theme .hp-btn {
    width: 100%;
  }
}

/* ─── Live Feed preview (Sniper Desk) ────────────────────────────────────── */
.feed-preview {
  margin-top: 24px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  padding: 20px;
}

.feed-preview-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.feed-preview-title-group {
  display: flex;
  align-items: center;
  gap: 12px;
}

.feed-preview-title {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--paper);
}

.feed-preview-count {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11.5px;
  color: var(--ink-dim);
}

.feed-live-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--safe);
  box-shadow: 0 0 6px var(--safe);
  flex-shrink: 0;
}

.feed-preview-link {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  color: var(--safe);
  text-decoration: none;
  white-space: nowrap;
}

.feed-preview-link:hover {
  text-decoration: underline;
}

/* Grid, not a <table>: the empty/loading states swap a single <div> message into
   #candidates-panel, which a real tbody would hoist straight back out. */
.feed-table {
  overflow-x: auto;
}

.feed-table-head,
.feed-row {
  display: grid;
  grid-template-columns: minmax(160px, 2fr) 1fr 1fr 1fr 1fr 1fr 96px;
  gap: 12px;
  align-items: center;
  min-width: 760px;
}

.feed-table-head {
  padding: 0 4px 10px;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
  text-transform: uppercase;
}

.feed-row {
  padding: 12px 4px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  transition: background 0.15s, opacity 0.25s, transform 0.25s;
}

.feed-row:hover {
  background: rgba(255, 255, 255, 0.02);
}

.feed-row--rejected {
  opacity: 0.55;
}

.feed-row.dossier-card-reviewing {
  opacity: 0;
  transform: translateX(-12px);
}

.feed-row-token {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.feed-row-token-text {
  min-width: 0;
}

.feed-row-cell {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--ink-dim);
  min-width: 0;
}

.feed-row-cell--action {
  display: flex;
  justify-content: flex-end;
}

.feed-row-btn {
  background: rgba(var(--safe-rgb), 0.12);
  border: 1px solid rgba(var(--safe-rgb), 0.35);
  color: var(--safe);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 11.5px;
  padding: 6px 12px;
  border-radius: 100px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s;
}

.feed-row-btn:hover {
  background: rgba(var(--safe-rgb), 0.2);
}

.feed-row-btn--ghost {
  background: transparent;
  border-color: rgba(var(--danger-rgb), 0.35);
  color: var(--danger);
}

.feed-row-btn--ghost:hover {
  background: rgba(var(--danger-rgb), 0.12);
}

.feed-row--skeleton .feed-card-symbol {
  color: var(--ink-dim);
}

@media (max-width: 700px) {
  .feed-table-head { display: none; }
  .feed-row {
    grid-template-columns: 1fr auto;
    min-width: 0;
    row-gap: 6px;
  }
  .feed-row-token { grid-column: 1 / -1; }
}

/* ─── Live Feed page (/feed.html) ────────────────────────────────────────── */
.feed-page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.feed-back-link {
  font-family: 'Rajdhani', sans-serif;
  font-size: 12.5px;
  color: var(--ink-dim);
  text-decoration: none;
}

.feed-back-link:hover {
  color: var(--paper);
}

.feed-page-title-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 8px;
}

.feed-page-title {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 28px;
  color: var(--paper);
  margin: 0;
}

.feed-layout .discovery-search-input {
  width: 320px;
  max-width: 100%;
  margin: 0;
}

.feed-page-body {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 24px;
  align-items: start;
}

@media (max-width: 960px) {
  .feed-page-body {
    grid-template-columns: 1fr;
  }
}

.feed-filters {
  display: flex;
  flex-direction: column;
  gap: 18px;
  position: sticky;
  top: 88px; /* clears the sticky nav */
}

@media (max-width: 960px) {
  .feed-filters { position: static; }
}

.feed-filter-card {
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  padding: 18px;
}

.feed-filter-divider {
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  margin: 16px 0;
}

/* One preset per row on this page (the old sidebar packed them 3-across in a
   220px column) — there's room for the label and its range to sit on one line. */
.feed-layout .discovery-age-row {
  grid-template-columns: 1fr;
  gap: 8px;
  margin-bottom: 0;
}

.feed-layout .discovery-age-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 12.5px;
  padding: 9px 12px;
  text-align: left;
}

.feed-layout .discovery-age-btn span {
  font-size: 11px;
}

.feed-apply-btn {
  width: 100%;
  margin-top: 10px;
  background: var(--safe);
  border: none;
  color: #04140b;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 12.5px;
  padding: 9px;
  border-radius: 10px;
  cursor: pointer;
}

.feed-apply-btn:hover {
  filter: brightness(1.08);
}

/* Two-line toggle rows on this page: title, then the explanation that used to be
   buried in a title="" tooltip in the cramped sidebar. */
.feed-filters .creator-profit-toggle {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  cursor: pointer;
}

.feed-filters .creator-profit-toggle input[type="checkbox"] {
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--safe);
  flex-shrink: 0;
  cursor: pointer;
}

.feed-filters .creator-profit-toggle input[type="checkbox"]:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.creator-profit-toggle-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.creator-profit-toggle-title {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
}

.creator-profit-toggle-note {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-dim);
}

.feed-board {
  min-width: 0;
}

.feed-migrated {
  background: rgba(var(--safe-rgb), 0.06);
  border: 1px solid rgba(var(--safe-rgb), 0.35);
  border-radius: 16px;
  padding: 18px;
  margin-bottom: 20px;
}

.feed-migrated.hidden {
  display: none;
}

/* Card grid — the sidebar version was a single column; the page has room for three. */
.feed-layout .dossier-board {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

@media (max-width: 1280px) {
  .feed-layout .dossier-board { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 700px) {
  .feed-layout .dossier-board { grid-template-columns: 1fr; }
}

.feed-migrated .dossier-board {
  grid-template-columns: repeat(2, 1fr);
}

@media (max-width: 700px) {
  .feed-migrated .dossier-board { grid-template-columns: 1fr; }
}

/* Fake-volume verdict on the recommended cards (see lib/wash-trade.js). Deliberately
   louder than the buzz label it replaces — "lots of activity" is worth nothing if the
   activity isn't real, and that's the more important thing to see. */
.hp-buzz.fake {
  color: var(--danger);
  font-weight: 600;
}

.hp-buzz-verified {
  display: inline-flex;
  color: var(--safe);
  margin-left: 4px;
}

.hp-buzz-verified .icn {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
}

/* ══ Depth pass ═══════════════════════════════════════════════════════════════════════
   Everything on this page sat at the same elevation: flat panels, hairline borders, the
   same background as the page behind them. The result read as a wireframe — nothing drew
   the eye first, and the price line ended up being the only thing with any presence.

   This gives the desk one shared depth system rather than styling each panel by hand:
   a slightly lifted surface, a light edge along the top (where a light source would catch
   it), a real shadow beneath, and a green cast that deepens on hover. Applied through
   variables so every panel stays consistent and one change moves all of them. */
/* The --surface/--surface-edge/--surface-lip/--surface-shadow tokens and the page-floor
   background now live in shared/theme.css (they were consumed by style.css on every page
   but only defined here, so pages without snipe.css fell back to hardcoded literals). */

.sniper-theme .quick-snipe-card,
.sniper-theme .check-empty,
.sniper-theme .feed-preview,
.sniper-theme #check-result .cluster-card,
.sniper-theme .sniper-panel {
  background: var(--surface);
  border: 1px solid var(--surface-edge);
  box-shadow: var(--surface-shadow);
  transition: box-shadow 0.22s ease, border-color 0.22s ease;
}

.sniper-theme .quick-snipe-card:hover,
.sniper-theme .feed-preview:hover,
.sniper-theme #check-result .cluster-card:hover {
  border-color: rgba(var(--safe-rgb), 0.26);
  box-shadow: var(--surface-shadow-lift);
}

/* The check column is the page's focal point — it gets the strongest presence, and stops
   being a dashed placeholder box. */
.sniper-theme .check-empty {
  border-style: solid;
}

.sniper-theme .hp-card {
  box-shadow: var(--surface-shadow);
}

.sniper-theme .hp-card:hover {
  box-shadow: var(--surface-shadow-lift);
}

/* ── Section headings ─────────────────────────────────────────────────────────────────
   Every label on the page was the same weight and colour as its own body text, so nothing
   announced itself. These get the treatment headings should have had: tighter tracking,
   more contrast, and an accent rule that ties them to the theme. */
.sniper-theme .check-empty-watchlist-title,
.sniper-theme .feed-preview-title,
.sniper-theme .quick-snipe-head h2,
.sniper-theme .panel-label {
  color: var(--paper);
  letter-spacing: 0.02em;
}

.sniper-theme .feed-preview-title,
.sniper-theme .check-empty-watchlist-title {
  position: relative;
  padding-left: 12px;
}

.sniper-theme .feed-preview-title::before,
.sniper-theme .check-empty-watchlist-title::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 1.05em;
  border-radius: 2px;
  background: var(--safe);
  box-shadow: 0 0 10px rgba(var(--safe-rgb), 0.6);
}

/* The watchlist title carries its own icon, which the accent bar would crowd. */
.sniper-theme .check-empty-watchlist-title { padding-left: 0; }
.sniper-theme .check-empty-watchlist-title::before { display: none; }

/* ── Positions ticker ─────────────────────────────────────────────────────────────────
   The top strip is the first thing on the page and read as a plain bar. */
.sniper-theme .positions-ticker {
  background: linear-gradient(180deg, rgba(var(--safe-rgb), 0.05), transparent 85%), var(--board);
  border-bottom: 1px solid var(--surface-edge);
  box-shadow: 0 8px 24px -18px rgba(0, 0, 0, 1);
}

/* ── Feed rows ────────────────────────────────────────────────────────────────────────
   Give the board rows something to respond to, so the list feels live rather than static. */
.sniper-theme .feed-row {
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.sniper-theme .feed-row:hover {
  background: rgba(var(--safe-rgb), 0.045);
  border-color: rgba(var(--safe-rgb), 0.22);
  /* No translateX nudge here — the rows carry a 760px min-width inside an
     overflow-x:auto container, so shifting a hovered row 2px right pushed it past the
     container edge and flashed a horizontal scrollbar under the Desk's feed preview. */
}

/* ── Primary actions ──────────────────────────────────────────────────────────────────
   The buttons that matter now carry a glow, so the eye lands on them before anything
   else on a busy panel. */
.sniper-theme .fire-btn,
.sniper-theme .buy-confirm-btn,
.sniper-theme .hp-btn {
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.18), 0 6px 20px -8px rgba(var(--safe-rgb), 0.55);
  transition: box-shadow 0.18s ease, transform 0.12s ease, background 0.18s ease;
}

.sniper-theme .fire-btn:hover,
.sniper-theme .buy-confirm-btn:hover,
.sniper-theme .hp-btn:hover {
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.35), 0 10px 28px -8px rgba(var(--safe-rgb), 0.75);
  transform: translateY(-1px);
}

.sniper-theme .fire-btn:active,
.sniper-theme .buy-confirm-btn:active,
.sniper-theme .hp-btn:active {
  transform: translateY(0);
}

/* ── Nav ──────────────────────────────────────────────────────────────────────────────
   Sits above the content instead of blending into it. */
.sniper-theme .site-nav {
  background: linear-gradient(180deg, #0c130f 0%, rgba(7, 10, 8, 0.92) 100%);
  border-bottom: 1px solid var(--surface-edge);
  backdrop-filter: blur(8px);
}

/* Respect a reduced-motion preference — every transform above is decorative. */
@media (prefers-reduced-motion: reduce) {
  .sniper-theme .feed-row:hover,
  .sniper-theme .fire-btn:hover,
  .sniper-theme .buy-confirm-btn:hover,
  .sniper-theme .hp-btn:hover {
    transform: none;
  }
}

/* ══ Armed = a target lock ════════════════════════════════════════════════════════════
   An armed order is the desk holding a coin in its sights, re-checking every few seconds,
   waiting for the entry to be worth taking. It used to render as a dashed grey pill with
   an hourglass, which said "loading" — the opposite of what's happening. This says
   tracking: a reticle whose arc drains as the wait window closes, ticks that rotate while
   it hunts, a core that pulses, and a scan line sweeping the chip. */
.sniper-theme .ticker-chip--armed {
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(var(--pin-rgb), 0.45);
  background: linear-gradient(180deg, rgba(var(--pin-rgb), 0.10), rgba(var(--pin-rgb), 0.02));
  padding-left: 8px;
  color: var(--ink);
  cursor: default;
  box-shadow: 0 0 0 1px rgba(var(--pin-rgb), 0.08), 0 6px 18px -10px rgba(var(--pin-rgb), 0.6);
}

/* The sweep: a soft band travelling left to right, like a scope passing over its target. */
.sniper-theme .ticker-chip--armed::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(100deg, transparent 30%, rgba(var(--pin-rgb), 0.16) 50%, transparent 70%);
  transform: translateX(-100%);
  animation: arm-sweep 2.8s ease-in-out infinite;
}

@keyframes arm-sweep {
  0%   { transform: translateX(-100%); }
  60%  { transform: translateX(100%); }
  100% { transform: translateX(100%); }
}

.arm-reticle {
  position: relative;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  color: var(--pin);
}

.arm-reticle svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.arm-reticle-track {
  fill: none;
  stroke: rgba(var(--pin-rgb), 0.18);
  stroke-width: 2.5;
}

/* Drains clockwise as the wait window runs down — the dasharray is set per render. */
.arm-reticle-arc {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linecap: round;
  transition: stroke-dasharray 0.6s linear;
  filter: drop-shadow(0 0 3px currentColor);
}

/* The hunting motion: ticks sweeping around while it waits for its entry. */
.arm-reticle-ticks {
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  opacity: 0.75;
  transform-origin: 18px 18px;
  animation: arm-scan 4s linear infinite;
}

@keyframes arm-scan {
  to { transform: rotate(360deg); }
}

.arm-reticle-core {
  fill: currentColor;
  animation: arm-core 1.5s ease-in-out infinite;
  transform-origin: 18px 18px;
}

@keyframes arm-core {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.62); }
}

.sniper-theme .ticker-chip--armed .ticker-chip-symbol {
  color: var(--paper);
  font-weight: 600;
}

.sniper-theme .ticker-chip--armed .status-pill--armed {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(var(--pin-rgb), 0.16);
  color: var(--pin);
  letter-spacing: 0.1em;
}

.arm-pulse {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  animation: arm-core 1.5s ease-in-out infinite;
}

.sniper-theme .ticker-chip--armed .ticker-chip-meta {
  font-family: 'IBM Plex Mono', monospace;
  color: var(--ink-dim);
}

/* Final minutes: the whole lock turns red and quickens. */
.sniper-theme .ticker-chip--armed.is-urgent {
  border-color: rgba(var(--danger-rgb), 0.5);
  background: linear-gradient(180deg, rgba(var(--danger-rgb), 0.12), rgba(var(--danger-rgb), 0.02));
}

.sniper-theme .ticker-chip--armed.is-urgent .arm-reticle,
.sniper-theme .ticker-chip--armed.is-urgent .status-pill--armed { color: var(--danger); }
.sniper-theme .ticker-chip--armed.is-urgent .status-pill--armed { background: rgba(var(--danger-rgb), 0.16); }
.sniper-theme .ticker-chip--armed.is-urgent .arm-reticle-core,
.sniper-theme .ticker-chip--armed.is-urgent .arm-pulse { animation-duration: 0.8s; }
.sniper-theme .ticker-chip--armed.is-urgent::after {
  background: linear-gradient(100deg, transparent 30%, rgba(var(--danger-rgb), 0.18) 50%, transparent 70%);
  animation-duration: 1.6s;
}

/* ══ Quick Snipe: the weapon panel ════════════════════════════════════════════════════
   This is where you actually fire, and it read as a plain form. Framed like a scope
   housing now: corner brackets, a faint grid, and a header that behaves like a status
   readout rather than a title. */
.sniper-theme .quick-snipe-card {
  position: relative;
  background:
    linear-gradient(180deg, rgba(var(--safe-rgb), 0.05), transparent 30%),
    repeating-linear-gradient(0deg, rgba(var(--safe-rgb), 0.022) 0 1px, transparent 1px 4px),
    var(--surface);
  overflow: hidden;
}

/* Targeting brackets — drawn as two boxes with only their corners visible, which gets
   four L-shapes out of two pseudo-elements. */
.sniper-theme .quick-snipe-card::before,
.sniper-theme .quick-snipe-card::after {
  content: '';
  position: absolute;
  width: 22px;
  height: 22px;
  pointer-events: none;
  border-color: rgba(var(--safe-rgb), 0.55);
  border-style: solid;
}

.sniper-theme .quick-snipe-card::before {
  top: 10px;
  left: 10px;
  border-width: 2px 0 0 2px;
  border-top-left-radius: 6px;
}

.sniper-theme .quick-snipe-card::after {
  bottom: 10px;
  right: 10px;
  border-width: 0 2px 2px 0;
  border-bottom-right-radius: 6px;
}

.sniper-theme .quick-snipe-title {
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 17px;
  letter-spacing: 0.01em;
}

/* A small live reticle beside the title — the panel's own "armed and ready" tell. */
.sniper-theme .quick-snipe-title::before {
  content: '';
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 2px solid var(--safe);
  box-shadow: 0 0 0 3px rgba(var(--safe-rgb), 0.12), 0 0 12px rgba(var(--safe-rgb), 0.6);
  animation: arm-core 2.4s ease-in-out infinite;
}

/* Section labels read as HUD readouts: brighter, with a tick before them. */
.sniper-theme .quick-snipe-card .control-label,
.sniper-theme .quick-snipe-card .intake-label {
  display: flex;
  align-items: center;
  gap: 7px;
  color: var(--ink);
  letter-spacing: 0.16em;
}

.sniper-theme .quick-snipe-card .control-label::before,
.sniper-theme .quick-snipe-card .intake-label::before {
  content: '';
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  background: var(--safe);
  transform: rotate(45deg);
  box-shadow: 0 0 8px rgba(var(--safe-rgb), 0.7);
}

/* Dividers stop being a flat hairline and fade from the accent. */
.sniper-theme .quick-snipe-card .control-group-divider {
  height: 1px;
  border: none;
  background: linear-gradient(90deg, rgba(var(--safe-rgb), 0.35), rgba(var(--safe-rgb), 0.06) 45%, transparent);
}

/* The mint field: the barrel. Focus lights it up rather than just changing its border. */
.sniper-theme .quick-snipe-card .intake-row input {
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid var(--surface-edge);
  transition: border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}

.sniper-theme .quick-snipe-card .intake-row input:focus {
  outline: none;
  border-color: rgba(var(--safe-rgb), 0.6);
  background: rgba(var(--safe-rgb), 0.05);
  box-shadow: 0 0 0 3px rgba(var(--safe-rgb), 0.10), inset 0 0 18px -8px rgba(var(--safe-rgb), 0.5);
}

/* Mode buttons: the selected one is lit, the others recede. */
.sniper-theme .trade-mode-btn.active,
.sniper-theme .fire-mode-btn.active {
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.25), 0 6px 18px -8px rgba(var(--safe-rgb), 0.6);
}

.sniper-theme .trade-mode-btn[data-mode="danger"].active {
  box-shadow: 0 0 0 1px rgba(var(--danger-rgb), 0.3), 0 6px 18px -8px rgba(var(--danger-rgb), 0.65);
}

.sniper-theme .quick-snipe-readout {
  padding: 9px 11px;
  border: 1px solid var(--surface-edge);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.35);
}

@media (prefers-reduced-motion: reduce) {
  .sniper-theme .ticker-chip--armed::after,
  .arm-reticle-ticks,
  .arm-reticle-core,
  .arm-pulse,
  .sniper-theme .quick-snipe-title::before {
    animation: none;
  }
}

/* Panel holding out for a coin that clears the bar — deliberately styled as a considered
   state rather than a blank, because "nothing qualifies right now" is the filter working. */
.hp-holding {
  padding: 34px 24px;
  text-align: center;
  border: 1px dashed var(--surface-edge);
  border-radius: 14px;
  background: rgba(0, 0, 0, 0.25);
}

.hp-holding-mark .icn {
  width: 26px;
  height: 26px;
  color: var(--card-edge);
}

.hp-holding-title {
  margin-top: 8px;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--ink);
}

.hp-holding-body {
  max-width: 430px;
  margin: 7px auto 0;
  font-size: 11.5px;
  line-height: 1.65;
  color: var(--ink-dim);
}

/* ── The action stays reachable ───────────────────────────────────────────────────────
   The dossier is long by design — chart, three scores, then every reason the check found,
   which is the point of it. But that pushed the button you came here to press below the
   fold, so firing meant reading, scrolling past everything, and hunting for it. It now
   sticks to the bottom of the panel: the reasons still scroll behind it, the decision is
   always one click away. */
#check-result .cluster-card {
  position: relative;
  /* Room for the docked bar so the last reason isn't hidden underneath it. */
  padding-bottom: 74px;
}

#check-result .buy-confirm-btn,
#check-result .override-trigger-btn {
  position: sticky;
  bottom: 12px;
  z-index: 4;
  width: calc(100% - 4px);
  margin: 14px 2px 0;
  /* Its own backing, so text scrolling underneath never shows through the button. */
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.22),
              0 -14px 26px -10px var(--board),
              0 10px 26px -10px rgba(var(--safe-rgb), 0.6);
}

#check-result .override-trigger-btn {
  box-shadow: 0 0 0 1px rgba(var(--danger-rgb), 0.25),
              0 -14px 26px -10px var(--board),
              0 10px 26px -10px rgba(var(--danger-rgb), 0.5);
}

/* ── Live price line ──────────────────────────────────────────────────────────────── */
.ohlc-live-line {
  stroke: var(--safe);
  stroke-width: 1;
  stroke-dasharray: 3 4;
  opacity: 0.75;
}

.ohlc-live-dot {
  fill: var(--safe);
  animation: hp-dot-pulse 1.6s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .ohlc-live-dot { animation: none; }
}

/* Card footer now holds two actions — the chart expander sits beside Check. */
.hp-foot-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* The dossier's compact action sits above its chart, right-aligned. Since the 2026-09-06
   swap this slot holds the FIRE/ARM button (see checkChartSectionHtml in snipe.js) and
   the big bottom button opens the full-screen chart instead. */
.check-chart-expand {
  display: inline-flex;
  margin: 0 0 8px auto;
}

/* Compact fire button — pro-chart-trigger's shape with the fire CTA's weight. */
.check-fire-compact {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: rgba(var(--safe-rgb), 0.14);
  border-color: rgba(var(--safe-rgb), 0.5);
}

.check-fire-compact.warning-fire {
  background: rgba(var(--pin-rgb), 0.14);
  border-color: rgba(var(--pin-rgb), 0.5);
  color: var(--pin);
}

.check-fire-compact.warning-fire:hover {
  background: rgba(var(--pin-rgb), 0.24);
  border-color: var(--pin);
  box-shadow: 0 0 0 1px rgba(var(--pin-rgb), 0.3), 0 8px 20px -8px rgba(var(--pin-rgb), 0.7);
}

/* The main action on a checked dossier — inherits .buy-confirm-btn's full-width weight. */
.check-fullscreen-btn .icn {
  width: 16px;
  height: 16px;
  vertical-align: -3px;
  margin-right: 4px;
}

@media (max-width: 560px) {
  .hp-foot-actions { width: 100%; }
  .hp-foot-actions .pro-chart-trigger { flex: 1; justify-content: center; }
}

/* ══ Scope view ═══════════════════════════════════════════════════════════════════════
   Watching Smart Entry hunt. The animation frames real numbers — the reticle turns while
   it's tracking and locks when every condition is met, and each bar is the actual score
   against the actual threshold. Nothing here moves for decoration alone. */
.scope-overlay {
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: rgba(2, 5, 3, 0.9);
  backdrop-filter: blur(7px);
  display: flex;
  padding: 20px;
}

.scope-overlay.hidden { display: none; }

.scope {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  max-width: 1180px;
  margin: auto;
  background: var(--surface, #0b120e);
  border: 1px solid rgba(var(--pin-rgb), 0.35);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(var(--pin-rgb), 0.08), 0 40px 90px -30px rgba(0, 0, 0, 1);
  transition: border-color 0.4s ease, box-shadow 0.4s ease;
}

/* Everything shifts from amber (hunting) to green (locked) the moment the gate opens. */
.scope-overlay.is-ready .scope {
  border-color: rgba(var(--safe-rgb), 0.55);
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.18), 0 0 70px -20px rgba(var(--safe-rgb), 0.6);
}

.scope-head {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--surface-edge, #1f3527);
  background: linear-gradient(180deg, rgba(var(--pin-rgb), 0.07), transparent);
}

.scope-overlay.is-ready .scope-head {
  background: linear-gradient(180deg, rgba(var(--safe-rgb), 0.09), transparent);
}

/* Chase hold (lib/smart-entry.js's chaseAssessment, the SOLE blocker): the target is
   locked, the desk is deliberately waiting out a vertical spike rather than buying its
   top. Amber, steadier than tracking, calmer than ready — a held breath, not a hunt. */
.scope-overlay.is-holding .scope-head {
  background: linear-gradient(180deg, rgba(var(--pin-rgb), 0.12), transparent);
}
.scope-overlay.is-holding .scope-reticle-lg { color: var(--pin); }
.scope-overlay.is-holding .scope-ring-outer { animation-duration: 14s; opacity: 0.8; }
.scope-overlay.is-holding .scope-cross { animation: none; }
.scope-overlay.is-holding .scope-status {
  color: var(--pin);
  animation: blink-check 1.6s ease-in-out infinite;
}

.scope-id { display: flex; align-items: center; gap: 14px; min-width: 0; }

/* ── The reticle ────────────────────────────────────────────────────────────────────── */
.scope-reticle-lg {
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  color: var(--pin);
  transition: color 0.4s ease;
}

.scope-overlay.is-ready .scope-reticle-lg { color: var(--safe); }
.scope-reticle-lg svg { width: 100%; height: 100%; overflow: visible; }

.scope-ring-outer,
.scope-ring-inner {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
}

.scope-ring-outer {
  opacity: 0.55;
  stroke-dasharray: 20 10;
  transform-origin: 30px 30px;
  animation: scope-spin 7s linear infinite;
}

.scope-ring-inner { opacity: 0.3; }

.scope-cross {
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  transform-origin: 30px 30px;
  animation: scope-hunt 3.4s ease-in-out infinite;
}

.scope-core {
  fill: currentColor;
  transform-origin: 30px 30px;
  animation: scope-pulse 1.5s ease-in-out infinite;
}

/* Locked on: the sweep stops, the ring snaps closed and the core holds steady. */
.scope-overlay.is-ready .scope-ring-outer { animation-duration: 1.6s; stroke-dasharray: none; opacity: 1; }
.scope-overlay.is-ready .scope-cross { animation: none; }
.scope-overlay.is-ready .scope-core { animation: scope-pulse 0.7s ease-in-out infinite; }

@keyframes scope-spin { to { transform: rotate(360deg); } }
@keyframes scope-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.6); }
}
/* Not a full rotation — a search sweep that hunts back and forth, like something looking. */
@keyframes scope-hunt {
  0%, 100% { transform: rotate(-16deg); }
  50% { transform: rotate(16deg); }
}

.scope-title {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 19px;
  color: var(--paper);
}

.scope-status {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11.5px;
  color: var(--pin);
  transition: color 0.4s ease;
}

.scope-overlay.is-ready .scope-status { color: var(--safe); }

.scope-timer {
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.scope-timer-label {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 9px;
  letter-spacing: 0.16em;
  color: var(--ink-dim);
}

.scope-timer-value {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 19px;
  color: var(--paper);
}

.scope-timer-value.urgent { color: var(--danger); }

/* ── Body ───────────────────────────────────────────────────────────────────────────── */
.scope-body {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  min-height: 0;
}

.scope-chart-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 16px;
  gap: 10px;
}

.scope-chart {
  flex: 1;
  min-height: 240px;
  overflow-x: auto;
  overflow-y: hidden;
  border: 1px solid var(--card-edge);
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.3);
  padding: 8px;
  position: relative;
}

/* Crosshair overlay, so the chart itself reads as something being sighted down. */
.scope-chart::before,
.scope-chart::after {
  content: '';
  position: absolute;
  background: rgba(var(--pin-rgb), 0.16);
  pointer-events: none;
  z-index: 2;
}

.scope-chart::before { left: 0; right: 0; top: 50%; height: 1px; }
.scope-chart::after { top: 0; bottom: 0; left: 50%; width: 1px; }

.scope-overlay.is-ready .scope-chart::before,
.scope-overlay.is-ready .scope-chart::after { background: rgba(var(--safe-rgb), 0.22); }

.scope-verdict {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-dim);
  min-height: 17px;
}

/* ── Gates ──────────────────────────────────────────────────────────────────────────── */
.scope-gates {
  border-left: 1px solid var(--surface-edge, #1f3527);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
  background: var(--board);
}

.scope-gates-title {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
}

.scope-gate { display: flex; flex-direction: column; gap: 5px; }

.scope-gate-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.scope-gate-name {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--ink);
}

.scope-gate-val {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 15px;
  color: var(--ink-dim);
  transition: color 0.3s ease;
}

.scope-gate.met .scope-gate-val { color: var(--safe); }
.scope-gate.met .scope-gate-name { color: var(--paper); }

.scope-gate-track {
  position: relative;
  height: 7px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.05);
  overflow: hidden;
}

.scope-gate-fill {
  height: 100%;
  width: 0;
  border-radius: 4px;
  background: var(--pin);
  /* Slower than the 2s poll so the bar glides between readings instead of snapping. */
  transition: width 0.7s ease, background 0.3s ease;
}

.scope-gate.met .scope-gate-fill { background: var(--safe); box-shadow: 0 0 10px rgba(var(--safe-rgb), 0.7); }

/* The threshold, drawn on the track so "how far is it" is visible rather than arithmetic. */
.scope-gate-mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  background: var(--paper);
  opacity: 0.5;
  transition: left 0.7s ease;
}

.scope-gate-need {
  font-size: 10px;
  line-height: 1.4;
  color: var(--ink-dim);
}

.scope-readout {
  margin-top: 2px;
  padding-top: 12px;
  border-top: 1px solid var(--card-edge);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.scope-readout-line {
  margin: 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-dim);
  padding-left: 12px;
  position: relative;
}

.scope-readout-line::before {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--pin);
}

.scope-readout-line.ready { color: var(--safe); }
.scope-readout-line.ready::before { background: var(--safe); }

/* Opportunity is displayed for context but is not a gate — dimmed and mark-less so it
   can't be misread as something the order is waiting on. */
.scope-gate--context { opacity: 0.72; }
.scope-gate--context .scope-gate-need { font-style: italic; }

/* The warnings actually holding the order. This is the thing the view never showed. */
.scope-checks {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--card-edge);
  background: rgba(0, 0, 0, 0.25);
}
.scope-checks-title {
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warn, var(--pin));
  margin-bottom: 6px;
}
.scope-checks.has-hard .scope-checks-title { color: var(--danger); }
.scope-checks-list {
  margin: 0;
  padding-left: 16px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-dim);
}
.scope-checks-list li { margin-bottom: 4px; }
.scope-checks-list li:last-child { margin-bottom: 0; }

/* The strategy version's filters — every one listed, met or not. */
.scope-legs .scope-checks-title { color: var(--ink-dim); }
.scope-legs-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 12px;
  line-height: 1.5;
}
.scope-legs-list li { display: flex; gap: 6px; margin-bottom: 4px; }
.scope-legs-list li:last-child { margin-bottom: 0; }
.scope-legs-list li::before { flex: none; width: 10px; text-align: center; font-weight: 700; }
.scope-legs-list li.ok { color: var(--safe); }
.scope-legs-list li.ok::before { content: '✓'; }
.scope-legs-list li.no { color: var(--pin); }
.scope-legs-list li.no::before { content: '✗'; }

.scope-actions {
  margin-top: auto;
  padding-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Manual override. Deliberately not styled as the primary action — the desk holding an
   order is usually right, and this is the exception, not the happy path. */
.scope-fire {
  padding: 11px 0;
  border-radius: 10px;
  border: 1px solid var(--pin);
  background: rgba(var(--pin-rgb, 255, 176, 0), 0.12);
  color: var(--pin);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: all 0.15s;
}
.scope-fire:hover { background: rgba(var(--pin-rgb, 255, 176, 0), 0.22); }
.scope-fire:disabled { opacity: 0.6; cursor: default; }
/* Second click of the two-step confirm, and the harder-edged variant for overriding a
   hard-blocking reason rather than a warning. */
.scope-fire.is-confirming {
  background: var(--pin);
  color: #0a0a0a;
  animation: scope-fire-pulse 1.2s ease-in-out infinite;
}
.scope-fire.is-dangerous { border-color: var(--danger); color: var(--danger); background: rgba(var(--danger-rgb), 0.1); }
.scope-fire.is-dangerous:hover { background: rgba(var(--danger-rgb), 0.2); }
.scope-fire.is-dangerous.is-confirming { background: var(--danger); color: #fff; }
@keyframes scope-fire-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.72; }
}
@media (prefers-reduced-motion: reduce) {
  .scope-fire.is-confirming { animation: none; }
}

.scope-cancel {
  margin-top: 0;
  padding: 10px 0;
  border-radius: 10px;
  border: 1px solid var(--card-edge);
  background: rgba(0, 0, 0, 0.3);
  color: var(--ink-dim);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  font-size: 12px;
  cursor: pointer;
  transition: all 0.15s;
}

.scope-cancel:hover { color: var(--danger); border-color: var(--danger); background: rgba(var(--danger-rgb), 0.1); }

/* The armed chip advertises that it opens this. */
.sniper-theme .ticker-chip--armed { cursor: pointer; }
.sniper-theme .ticker-chip--armed:hover { border-color: var(--pin); }

@media (max-width: 900px) {
  .scope-overlay { padding: 0; }
  .scope { border-radius: 0; }
  .scope-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
  .scope-gates { border-left: none; border-top: 1px solid var(--surface-edge, #1f3527); }
}

@media (prefers-reduced-motion: reduce) {
  .scope-ring-outer, .scope-cross, .scope-core { animation: none; }
  .scope-gate-fill, .scope-gate-mark { transition: none; }
}

/* ── Social links and the chart button, sized to be seen ──────────────────────────────
   These were 22px monochrome chips that read as decoration. Checking a coin's X or
   Telegram is one of the first things anyone does before touching a launch, and expanding
   the chart is the main way into the scalping view — both were losing to the noise around
   them. Bigger, brighter, and each network carries its own colour on hover so the row is
   scannable at a glance instead of four identical grey squares. */
.hp-socials { gap: 7px; }

.hp-social {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  border-color: rgba(var(--safe-rgb), 0.22);
  background: rgba(0, 0, 0, 0.45);
  /* No colour here — the per-network rules below own it. */
}

.hp-social .icn {
  width: 17px;
  height: 17px;
}

.hp-social:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px -6px rgba(var(--safe-rgb), 0.6);
}

/* Each network in its own colour — recognisable without reading, and coloured at REST,
   not only on hover. Sizing them up helped, but four identical grey chips still read as
   one undifferentiated block until you point at them; on a touch screen there is no hover
   at all, so the colour never arrived. Carrying the brand tint by default makes the row
   scannable at a glance, and hover just raises the same colour to full strength. */
.hp-social--twitter  { color: #e8e8ea; border-color: rgba(255, 255, 255, 0.3); }
.hp-social--telegram { color: #6fbdea; border-color: rgba(74, 169, 224, 0.42); }
.hp-social--website  { color: var(--safe); border-color: rgba(var(--safe-rgb), 0.42); }
.hp-social--pumpfun,
.hp-social--chart    { color: var(--pin); border-color: rgba(var(--pin-rgb), 0.42); }

.hp-social--twitter:hover { color: #fff; border-color: #fff; background: rgba(255, 255, 255, 0.16); }
.hp-social--telegram:hover { color: #9ad7fa; border-color: #4aa9e0; background: rgba(74, 169, 224, 0.22); }
.hp-social--website:hover { color: var(--safe); border-color: var(--safe); background: rgba(var(--safe-rgb), 0.2); }
.hp-social--pumpfun:hover,
.hp-social--chart:hover { color: var(--pin); border-color: var(--pin); background: rgba(var(--pin-rgb), 0.22); }

/* The full-screen chart button — a primary action, styled like one. */
.pro-chart-trigger {
  padding: 9px 16px;
  font-size: 12.5px;
  letter-spacing: 0.05em;
  border-color: rgba(var(--safe-rgb), 0.3);
  background: rgba(var(--safe-rgb), 0.08);
  color: var(--paper);
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.08);
}

.pro-chart-trigger .icn {
  width: 15px;
  height: 15px;
}

.pro-chart-trigger:hover {
  background: rgba(var(--safe-rgb), 0.18);
  border-color: var(--safe);
  transform: translateY(-1px);
  box-shadow: 0 0 0 1px rgba(var(--safe-rgb), 0.3), 0 8px 20px -8px rgba(var(--safe-rgb), 0.7);
}

.check-chart-expand {
  padding: 8px 15px;
}

@media (prefers-reduced-motion: reduce) {
  .hp-social:hover,
  .pro-chart-trigger:hover { transform: none; }
}

/* ── Entry Style doctrine cards (trade-modals.js's ENTRY STYLE section) ──────────────
   Two selectable doctrines, presented as HUD cards rather than plain toggle pills. All
   decoration is CSS-only: the active card's sheen is a single translated gradient
   (GPU-composited), guarded behind prefers-reduced-motion; nothing here loads anything. */
.entry-style-row-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.entry-style-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  text-align: left;
  background: var(--board);
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  padding: 12px 12px 11px;
  cursor: pointer;
  color: var(--ink-dim);
  transition: border-color .15s, transform .12s, box-shadow .15s;
}
.entry-style-card:hover { transform: translateY(-1px); border-color: rgba(var(--safe-rgb), 0.4); }
.entry-style-card:disabled { opacity: .6; cursor: wait; }
.entry-style-icon { color: var(--ink-dim); transition: color .15s; }
.entry-style-icon svg { width: 22px; height: 22px; display: block; }
.entry-style-name {
  font-family: 'Space Grotesk', sans-serif;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--paper);
}
.entry-style-kicker {
  position: absolute;
  top: 10px;
  right: 12px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--ink-dim);
  border: 1px solid var(--card-edge);
  border-radius: 4px;
  padding: 2px 5px;
}
.entry-style-sub {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  line-height: 1.45;
  color: var(--ink-dim);
}
.entry-style-card.active {
  border-color: rgba(var(--safe-rgb), 0.55);
  box-shadow: 0 0 16px rgba(var(--safe-rgb), 0.12), inset 0 0 12px rgba(var(--safe-rgb), 0.05);
}
.entry-style-card.active .entry-style-icon { color: var(--safe); filter: drop-shadow(0 0 6px rgba(var(--safe-rgb), 0.5)); }
.entry-style-card.active .entry-style-kicker { color: var(--safe); border-color: rgba(var(--safe-rgb), 0.5); }
/* Armed-doctrine sheen — one light band crossing the active card every few seconds. */
@media (prefers-reduced-motion: no-preference) {
  .entry-style-card.active::after {
    content: '';
    position: absolute;
    top: 0; bottom: 0;
    width: 40%;
    left: -45%;
    background: linear-gradient(105deg, transparent, rgba(var(--safe-rgb), 0.07), transparent);
    animation: entry-style-sheen 4.5s ease-in-out infinite;
    pointer-events: none;
  }
}
@keyframes entry-style-sheen {
  0%, 55% { transform: translateX(0); }
  85%, 100% { transform: translateX(360%); }
}

/* ── Loading skeletons (feed cards) ──────────────────────────────────────────────────
   A shimmering bar where a value hasn't been gathered yet (see snipe.js's skelHtml) —
   a live instrument warming up, not a dead em-dash. When the data lands, the next
   render simply swaps the shimmer for the number. Shimmer is a translated gradient on
   a small element (GPU-composited), stilled entirely for reduced-motion users. */
.hp-skel {
  display: inline-block;
  height: 11px;
  max-width: 100%;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.07);
  position: relative;
  overflow: hidden;
  vertical-align: middle;
}
@media (prefers-reduced-motion: no-preference) {
  .hp-skel::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, transparent 20%, rgba(var(--safe-rgb), 0.16) 50%, transparent 80%);
    transform: translateX(-100%);
    animation: hp-skel-shimmer 1.6s ease-in-out infinite;
  }
}
@keyframes hp-skel-shimmer {
  to { transform: translateX(100%); }
}

/* "building price history…" gets a live pulse-trace sweeping the empty chart area
   instead of bare text in a void — same honest message, now visibly working. */
.hp-chart-empty {
  position: relative;
  overflow: hidden;
}
@media (prefers-reduced-motion: no-preference) {
  .hp-chart-empty::before {
    content: '';
    position: absolute;
    left: -30%;
    top: 50%;
    width: 30%;
    height: 1px;
    background: linear-gradient(to right, transparent, rgba(var(--safe-rgb), 0.5));
    box-shadow: 0 0 8px rgba(var(--safe-rgb), 0.35);
    animation: hp-trace-sweep 2.6s ease-in-out infinite;
    pointer-events: none;
  }
}
@keyframes hp-trace-sweep {
  to { left: 100%; }
}

/* Honest banner above High-Probability fallback rows (see renderWatchlistTop + the
   never-empty fallback in lib/discovery.js): most-active-right-now, explicitly not a
   recommendation the evidence bar granted. */
.hp-fallback-note {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  line-height: 1.5;
  color: var(--pin);
  background: rgba(var(--pin-rgb), 0.07);
  border: 1px dashed rgba(var(--pin-rgb), 0.35);
  border-radius: 8px;
  padding: 8px 12px;
  margin-bottom: 10px;
}

/* ── Early-coin flag (2026-09-08) ────────────────────────────────────────────────────
   Discovery admits coins from 3m old now; anything under 60m carries this pill on the
   Live Feed rows and High-Probability cards. The matching "Limit early coins" checkbox
   lives in Trading Settings (trade-modals.js, #limit-early-toggle). Amber = caution. */
.early-pill {
  display: inline-block;
  margin-left: 6px;
  vertical-align: 1px;
  font-family: 'Space Grotesk', sans-serif;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--pin);
  background: rgba(var(--pin-rgb), 0.12);
  border: 1px solid rgba(var(--pin-rgb), 0.45);
  border-radius: 4px;
  padding: 1px 5px;
  cursor: help;
}

/* ── Phase 11 Desk VNext layer (2026-09-24): drawer, strip, palette, dense cards, states ── */
.qs-toggle { margin-left: auto; background: transparent; border: 1px solid var(--card-edge); color: var(--ink-dim); border-radius: 6px; width: 28px; height: 28px; cursor: pointer; font-size: 14px; line-height: 1; }
.qs-toggle:hover { color: var(--paper); border-color: rgba(var(--pin-rgb), .5); }
.quick-snipe-card.qs-collapsed > *:not(.quick-snipe-head) { display: none !important; }
.quick-snipe-card.qs-collapsed { padding-bottom: 10px; }
.qs-strip { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 10px; padding: 8px 10px; border: 1px solid var(--card-edge); border-radius: 8px; background: var(--card); font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; color: var(--ink); }
.qs-strip-item { padding: 2px 8px; border-radius: 999px; background: rgba(0,0,0,.25); white-space: nowrap; }
.qs-strip-btn { font-family: 'Space Grotesk', sans-serif; font-size: 10.5px; font-weight: 700; letter-spacing: .06em; color: var(--pin); background: transparent; border: 1px solid rgba(var(--pin-rgb), .45); border-radius: 6px; padding: 4px 9px; cursor: pointer; }
.qs-strip-btn--dim { color: var(--ink-dim); border-color: var(--card-edge); }
.desk-palette { position: fixed; inset: 0; z-index: 1200; background: rgba(0,0,0,.55); display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
.desk-palette.hidden { display: none; }
.desk-palette-box { width: min(640px, 92vw); border: 1px solid rgba(var(--pin-rgb), .4); border-radius: 12px; background: #0e1712; box-shadow: 0 20px 60px rgba(0,0,0,.6); overflow: hidden; }
.desk-palette-input { width: 100%; box-sizing: border-box; font-family: 'IBM Plex Mono', monospace; font-size: 15px; color: var(--paper); background: transparent; border: 0; border-bottom: 1px solid var(--card-edge); padding: 14px 16px; outline: none; }
.desk-palette-list { max-height: 50vh; overflow: auto; }
.desk-palette-item { display: flex; gap: 10px; align-items: center; padding: 9px 16px; font-family: 'IBM Plex Mono', monospace; font-size: 12.5px; color: var(--ink); cursor: pointer; }
.desk-palette-item.is-active { background: rgba(var(--pin-rgb), .12); color: var(--paper); }
.desk-palette-item.is-empty { color: var(--ink-dim); cursor: default; }
.desk-palette-kind { font-family: 'Space Grotesk', sans-serif; font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-dim); width: 46px; flex: 0 0 auto; }
.desk-palette-foot { padding: 8px 16px; font-size: 10.5px; color: var(--ink-dim); border-top: 1px solid var(--card-edge); }
.hp-card--palette-hit { outline: 2px solid var(--pin); outline-offset: 2px; }
.desk-dense-toggle { margin-left: auto; font-family: 'Space Grotesk', sans-serif; font-size: 10px; font-weight: 700; letter-spacing: .08em; color: var(--ink-dim); background: transparent; border: 1px solid var(--card-edge); border-radius: 6px; padding: 3px 8px; cursor: pointer; }
.hp-states { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 4px 10px; margin: 6px 0 2px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; }
.hp-state b { display: block; font-family: 'Space Grotesk', sans-serif; font-size: 9px; letter-spacing: .12em; color: var(--ink-dim); font-weight: 600; }
.hp-state span { color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; }
.hp-state-unk, .hp-state span.hp-state-unk { color: var(--ink-dim); }
.hp-state span.is-good, .is-good { color: var(--safe); } .hp-state span.is-bad, .is-bad { color: var(--danger); }
.hp-why { font-family: 'IBM Plex Mono', monospace; font-size: 10.5px; color: var(--ink); margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hp-why b { font-family: 'Space Grotesk', sans-serif; font-size: 9px; letter-spacing: .12em; color: var(--pin); margin-right: 4px; }
/* dense: ~45% shorter cards — tighter paddings, single-line strip, smaller ring */
body.desk-dense .hp-card { padding: 8px 10px; }
body.desk-dense .hp-card .hp-strip { gap: 8px; padding: 4px 0; }
body.desk-dense .hp-card .hp-foot { padding-top: 4px; }
body.desk-dense .hp-card .hp-meta, body.desk-dense .hp-card .hp-reason { font-size: 10.5px; }
body.desk-dense .hp-card .hp-score { transform: scale(.8); transform-origin: right top; }
body.desk-dense .hp-card .hp-buzz { display: none; } /* socials stay visible in dense mode (2026-09-28) — "what is this coin linked to" is the first thing people check */
body.desk-dense .hp-states { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 2px 8px; margin: 4px 0 0; }
body.desk-dense .hp-why { display: none; }
.dossier-vnext { margin-top: 14px; border: 1px solid var(--card-edge); border-radius: 10px; background: var(--card); padding: 12px 14px; }
.dossier-vnext-head { font-family: 'Space Grotesk', sans-serif; font-size: 12px; font-weight: 700; letter-spacing: .12em; color: var(--pin); margin-bottom: 8px; display: flex; gap: 10px; flex-wrap: wrap; }
.dossier-vnext-head .hp-state-unk { font-weight: 400; letter-spacing: 0; font-size: 11px; }
.dossier-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 10px; }
.dossier-sec { border: 1px solid var(--card-edge); border-radius: 8px; padding: 8px 10px; min-width: 0; }
.dossier-sec h4 { margin: 0 0 6px; font-family: 'Space Grotesk', sans-serif; font-size: 10px; letter-spacing: .12em; color: var(--ink-dim); font-weight: 700; }
.dossier-kv { margin: 0; display: grid; gap: 3px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; }
.dossier-kv div { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 8px; }
.dossier-kv dt { color: var(--ink-dim); } .dossier-kv dd { margin: 0; color: var(--ink); overflow: hidden; text-overflow: ellipsis; }
.dossier-vnext-foot { margin-top: 8px; font-size: 10.5px; color: var(--ink-dim); }
@media (max-width: 640px) { .dossier-kv div { grid-template-columns: 90px minmax(0, 1fr); } .hp-states { grid-template-columns: repeat(2, minmax(0, 1fr)); } body.desk-dense .hp-states { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* Phase 11 dense mode, second pass: the height was in the 76px avatar, the 16px head inset,
   the two-line reason and the full-bleed price line — not the paddings. Dense keeps every
   number and every state; it drops the picture size, the reason line and the sparkline base
   (the Chart button still opens the full chart). */
.hp-states-host { padding: 0 18px; }
body.desk-dense .hp-states-host { padding: 0 12px; }
body.desk-dense .hp-head { padding: 8px 12px 6px; gap: 10px; align-items: center; }
body.desk-dense .hp-avatar-xl { width: 40px; height: 40px; border-radius: 10px; }
body.desk-dense .hp-avatar-fallback { font-size: 16px; }
body.desk-dense .hp-head-main { gap: 2px; }
body.desk-dense .hp-name { font-size: 15px; line-height: 1.2; }
body.desk-dense .hp-creator { display: none; }
body.desk-dense .hp-mcap-value { font-size: 15px; }
body.desk-dense .hp-score { width: 46px; height: 46px; transform: none; }
body.desk-dense .hp-score svg { width: 46px; height: 46px; }
body.desk-dense .hp-score-num { font-size: 13px; }
body.desk-dense .hp-score-label { font-size: 6.5px; }
body.desk-dense .hp-strip { margin: 0 12px; }
body.desk-dense .hp-strip-item { padding: 4px 8px; }
body.desk-dense .hp-strip-value { font-size: 12px; }
body.desk-dense .hp-foot { padding: 5px 12px 7px; margin-top: 0; border-top: 0; }
body.desk-dense .hp-reason { display: none; }
body.desk-dense .hp-foot-actions button { padding: 4px 10px; font-size: 11px; }
/* 2026-09-24: the dense card keeps its price line — compact (30px), the full-bleed base of the
   card, drawn from the same real tracked points as the full card; the "5m +x%" chip rides on it. */
body.desk-dense .hp-graph { height: 30px; }
body.desk-dense .hp-graph .hp-chart-empty { font-size: 9.5px; padding: 0; height: 30px; }
body.desk-dense .hp-strip-item { padding: 3px 8px; gap: 2px; }
body.desk-dense .hp-states { margin: 3px 0 0; }
body.desk-dense .hp-foot { padding: 4px 12px 5px; }
.hp-move-chip { position: absolute; top: 4px; right: 8px; font-family: var(--font-mono, 'IBM Plex Mono', monospace); font-size: 10px; font-weight: 600; letter-spacing: .02em; padding: 1px 6px; border-radius: var(--radius-s, 6px); background: rgba(var(--board-rgb, 7, 10, 8), .75); border: 1px solid var(--card-edge); color: var(--ink); pointer-events: none; }
.hp-move-chip.up { color: var(--safe); } .hp-move-chip.down { color: var(--danger); }

/* Armed panel hold — Live Mode on a wallet that cannot be signed for (snipe.js armedHoldBannerHtml, 2026-09-27). Tokens only. */
.armed-hold-banner { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 10px; padding: 8px 10px; font-size: 11.5px; line-height: 1.45; color: var(--ink); background: rgba(var(--danger-rgb), 0.10); border: 1px solid rgba(var(--danger-rgb), 0.45); border-radius: var(--radius-s); }
.armed-hold-banner span { flex: 1 1 200px; }
.armed-hold-banner .armed-delegate-btn { margin-left: auto; padding: 4px 10px; font: inherit; font-weight: 600; color: var(--card); background: var(--danger); border: 0; border-radius: var(--radius-s); cursor: pointer; }
.armed-hold-banner .armed-delegate-btn:disabled { opacity: 0.6; cursor: default; }
.fire-mode-btn.tier-locked { opacity: 0.55; }

/* ── Discovery consolidation (2026-10-05, GitHub #27 handoff) ───────────────────────────────
   The Desk's discovery panels are hidden (kept in the DOM); a compact card points into the
   Discover presets on /trenches.html. Tokens only. */
.feed-preview[hidden], .check-empty-watchlist[hidden] { display: none !important; }
.desk-discover { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; padding: 12px 14px; margin-bottom: 14px; background: var(--card); border: 1px solid var(--card-edge); border-radius: 10px; text-align: left; }
.desk-discover-title { font-weight: 700; color: var(--ink); display: inline-flex; align-items: center; gap: 6px; }
.desk-discover-links { display: flex; flex-wrap: wrap; gap: 8px; }
.desk-discover-links a { color: var(--pin); border: 1px solid rgba(var(--pin-rgb), .45); border-radius: 999px; padding: 4px 10px; font-size: 12.5px; text-decoration: none; }
.desk-discover-links a:hover, .desk-discover-links a:focus-visible { background: rgba(var(--pin-rgb), .12); }
.feed-moving { margin: 0 0 14px; padding: 10px 14px; border: 1px solid rgba(var(--pin-rgb), .45); border-radius: 10px; background: rgba(var(--pin-rgb), .08); color: var(--ink); font-size: 13px; line-height: 1.5; }
.feed-moving a { color: var(--pin); }

/* The Quick Snipe strip is the collapsed card's stand-in. Its display:flex above beat style.css's
   plain .hidden (same specificity, later file), so it showed on every visit with an expanded card,
   filled with placeholder dashes ("mode — TP —% / SL —%") because it only syncs while collapsed. */
.qs-strip.hidden { display: none; }

/* ── Sniper Desk on Discover's charcoal (GitHub #68, Codex brief, 2026-10-10) ────────────────────
   The Desk is where Smart Entry is set up, armed coins are watched and a chosen coin is analysed;
   finding coins is Discover's job. It now reads like Discover: charcoal surfaces, muted borders, the
   normal sans-serif UI with tabular numbers and monospace for the mint, 8-12 px radii, no scanlines,
   glows, corner brackets or sweeps. Layout: a compact header, the positions / armed panel only when
   it has something in it, then the check card beside a balanced main column (the empty state is one
   "Find a coin" card, the checked state is the dossier with one primary action). Scoped to
   body[data-page="snipe"] because this sheet is shared with other pages. Tokens only (the colour
   ratchet allows no new literals here). Behaviour, ids and handlers are unchanged. */
body[data-page="snipe"] { background: var(--d-canvas); }
body[data-page="snipe"].sniper-theme::before { display: none; }
body[data-page="snipe"] #sniper-app { font-family: var(--d-font); color: var(--d-text); }
body[data-page="snipe"] #sniper-app :focus-visible { outline: 2px solid var(--d-accent); outline-offset: 2px; }
body[data-page="snipe"] .sniper-layout { max-width: 1280px; padding: 24px 24px 64px; }

/* Header: the page's name and purpose, the account's mode in words, Positions and Settings. */
body[data-page="snipe"] .desk-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 24px; margin-bottom: 16px; }
body[data-page="snipe"] .desk-head-title { margin: 0; font-family: var(--d-font); font-size: 24px; font-weight: 650; line-height: 1.2; letter-spacing: 0; text-transform: none; color: var(--d-text); }
body[data-page="snipe"] .desk-head-sub { margin: 4px 0 0; max-width: 640px; font-size: 14px; line-height: 1.5; color: var(--d-text-2); }
body[data-page="snipe"] .desk-head-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
body[data-page="snipe"] .desk-mode-status { display: inline-flex; align-items: center; gap: 8px; min-height: 32px; padding: 0 12px; font-size: 13px; font-weight: 600; color: var(--d-text); background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 999px; }
body[data-page="snipe"] .desk-mode-status[hidden] { display: none; }
body[data-page="snipe"] .desk-mode-status::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--d-spark); }
body[data-page="snipe"] .desk-mode-status[data-mode="live"] { color: var(--d-danger); background: var(--d-danger-soft); border-color: rgba(var(--d-danger-rgb), .45); }
body[data-page="snipe"] .desk-mode-status[data-mode="live"]::before { background: var(--d-danger); }
body[data-page="snipe"] .desk-head-link { display: inline-flex; align-items: center; min-height: 40px; padding: 0 8px; font-size: 14px; color: var(--d-text-2); text-decoration: underline; text-decoration-color: var(--d-border); text-underline-offset: 4px; }
body[data-page="snipe"] .desk-head-link:hover { color: var(--d-text); text-decoration-color: var(--d-text-2); }
body[data-page="snipe"] .desk-head-btn { display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 14px; font-family: var(--d-font); font-size: 14px; font-weight: 600; color: var(--d-text); background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 8px; cursor: pointer; }
body[data-page="snipe"] .desk-head-btn:hover { background: var(--d-panel-2); }

/* Positions and armed coins: a panel, not a full-bleed strip, and absent when both lists are empty
   (the header's Positions link stays). Positions stay compact chips; armed coins are cards. */
body[data-page="snipe"] .positions-ticker { margin-bottom: 20px; background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 12px; }
body[data-page="snipe"] .positions-ticker:not(:has(.ticker-chip, .armed-pos-card, .armed-hold-banner)) { display: none; }
body[data-page="snipe"] .positions-ticker-inner { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px 16px; max-width: none; padding: 14px 16px; }
body[data-page="snipe"] .positions-ticker-label { display: inline-flex; align-items: center; gap: 8px; font-family: var(--d-font); font-size: 15px; font-weight: 650; letter-spacing: 0; color: var(--d-text); }
body[data-page="snipe"] .positions-ticker-hint { display: none; }
body[data-page="snipe"] .positions-ticker-link { grid-column: 2; grid-row: 1; font-family: var(--d-font); font-size: 14px; font-weight: 500; color: var(--d-text-2); text-decoration: underline; text-decoration-color: var(--d-border); text-underline-offset: 4px; }
body[data-page="snipe"] .positions-ticker-link:hover { color: var(--d-text); }
body[data-page="snipe"] .positions-ticker-scroll { grid-column: 1 / -1; display: grid; gap: 14px; overflow: visible; }
body[data-page="snipe"] .desk-queue-group { display: grid; gap: 8px; min-width: 0; }
body[data-page="snipe"] .desk-queue-group:has(> .ticker-row > .sidebar-empty:only-child) { display: none; }
body[data-page="snipe"] .desk-queue-label { font-size: 13px; font-weight: 600; color: var(--d-text-2); }
body[data-page="snipe"] #positions-panel { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: thin; }
body[data-page="snipe"] #armed-panel { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; }
body[data-page="snipe"] .ticker-chip { font-family: var(--d-font); background: var(--d-canvas); border-color: var(--d-border); border-radius: 10px; }
body[data-page="snipe"] .ticker-chip:hover { border-color: var(--d-accent-line); }
/* Armed card: status, the last entry read in words, size with Change, time left, Cancel. Clicking
   the card opens the Scope (scope-view.js), exactly as the chip did. */
body[data-page="snipe"] .armed-pos-card { display: grid; gap: 6px; min-width: 0; padding: 12px 14px; color: var(--d-text); background: var(--d-canvas); border: 1px dashed rgba(var(--d-caution-rgb), .55); border-radius: 10px; box-shadow: none; cursor: pointer; }
body[data-page="snipe"] .armed-pos-card::after { display: none; }
body[data-page="snipe"] .armed-pos-card:hover { border-color: var(--d-caution); }
body[data-page="snipe"] .armed-pos-card-head { display: flex; align-items: center; gap: 8px; }
body[data-page="snipe"] .armed-pos-card-head .ticker-chip-symbol { font-size: 15px; font-weight: 650; color: var(--d-text); }
body[data-page="snipe"] .armed-pos-card-cancel { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; margin-left: auto; color: var(--d-text-2); background: transparent; border: 1px solid var(--d-border); border-radius: 8px; cursor: pointer; }
/* The cancel handler reads e.target, so a click on the icon itself must land on the button. */
body[data-page="snipe"] .armed-pos-card-cancel > * { pointer-events: none; }
body[data-page="snipe"] .armed-pos-card-cancel:hover { color: var(--d-danger); border-color: rgba(var(--d-danger-rgb), .45); }
body[data-page="snipe"] .armed-pos-card-read { font-size: 14px; color: var(--d-text); }
body[data-page="snipe"] .armed-pos-card-detail { font-size: 13px; line-height: 1.45; color: var(--d-text-2); }
body[data-page="snipe"] .armed-pos-card-meta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; font-size: 13px; color: var(--d-text-2); font-variant-numeric: tabular-nums; }
body[data-page="snipe"] .armed-pos-card-meta .edit-arm-amount-btn { min-height: 32px; margin-left: 6px; padding: 0 10px; font-family: var(--d-font); font-size: 13px; color: var(--d-text); background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 8px; cursor: pointer; }
body[data-page="snipe"] .armed-pos-card-meta .edit-arm-amount-btn:hover { border-color: var(--d-accent-line); }
body[data-page="snipe"] .armed-pos-card-bar { height: 4px; overflow: hidden; background: var(--d-panel-2); border-radius: 4px; }
body[data-page="snipe"] .armed-pos-card-bar span { display: block; height: 100%; background: var(--d-caution); }

/* Two balanced columns: the check card (entry setup) and the main column. Both size to content. */
body[data-page="snipe"] .sniper-body { grid-template-columns: minmax(320px, 380px) minmax(0, 1fr); gap: 20px; align-items: start; }

/* Check card (Quick Snipe): fire mode, mint + Check, trade mode, defaults. */
body[data-page="snipe"] .quick-snipe-card { gap: 14px; padding: 18px; overflow: visible; background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 12px; }
body[data-page="snipe"] .quick-snipe-card::before, body[data-page="snipe"] .quick-snipe-card::after { display: none; }
/* Title and the collapse toggle share the first row; Instant / Smart Entry get the full width below
   (the toggle used to wrap onto a row of its own). */
body[data-page="snipe"] .quick-snipe-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 10px; }
body[data-page="snipe"] .quick-snipe-head .qs-toggle { grid-column: 2; grid-row: 1; margin: 0; }
body[data-page="snipe"] .quick-snipe-head .fire-mode-row { grid-column: 1 / -1; margin: 0; }
body[data-page="snipe"] .quick-snipe-head .fire-mode-btn { flex: 1; }
body[data-page="snipe"] .quick-snipe-title { font-family: var(--d-font); font-size: 17px; font-weight: 650; letter-spacing: 0; color: var(--d-text); }
body[data-page="snipe"] .quick-snipe-title::before { display: none; }
body[data-page="snipe"] .quick-snipe-card :is(.control-label, .intake-label) { margin-bottom: 8px; font-family: var(--d-font); font-size: 13px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--d-text-2); }
body[data-page="snipe"] .quick-snipe-card :is(.control-label, .intake-label)::before { display: none; }
body[data-page="snipe"] .quick-snipe-card .control-group-divider { background: var(--d-border); }
/* Fire mode and trade mode: Discover's selected state (lifted, green underline) instead of filled gold
   or green; Balanced underlines amber and Danger stays red so the risky choice still reads as one. */
body[data-page="snipe"] :is(.fire-mode-btn, .trade-mode-btn) { min-height: 40px; font-family: var(--d-font); font-size: 14px; font-weight: 550; letter-spacing: 0; color: var(--d-text-2); background: var(--d-canvas); border: 1px solid var(--d-border); border-radius: 8px; box-shadow: none; }
body[data-page="snipe"] :is(.fire-mode-btn, .trade-mode-btn):hover:not(:disabled) { color: var(--d-text); border-color: var(--d-text-2); }
body[data-page="snipe"] :is(.fire-mode-btn, .trade-mode-btn[data-mode]).active { color: var(--d-text); background: var(--d-panel-2); border-color: var(--d-accent-line); box-shadow: inset 0 -2px 0 var(--d-accent); animation: none; }
body[data-page="snipe"] .trade-mode-btn[data-mode="balanced"].active { border-color: rgba(var(--d-caution-rgb), .55); box-shadow: inset 0 -2px 0 var(--d-caution); }
body[data-page="snipe"] .trade-mode-btn[data-mode="danger"].active { color: var(--d-danger); background: var(--d-danger-soft); border-color: rgba(var(--d-danger-rgb), .6); box-shadow: inset 0 -2px 0 var(--d-danger); }
body[data-page="snipe"] #snipe-mint-input { min-height: 44px; font-family: var(--d-mono); font-size: 14px; color: var(--d-text); background: var(--d-canvas); border: 1px solid var(--d-border); border-radius: 8px; box-shadow: none; }
body[data-page="snipe"] #snipe-mint-input::placeholder { font-family: var(--d-font); color: var(--d-muted); }
body[data-page="snipe"] #snipe-mint-input:focus { outline: 2px solid var(--d-accent); outline-offset: 1px; background: var(--d-canvas); border-color: transparent; box-shadow: none; }
/* Check is the secondary way in (Discover is the primary one; Fire / Arm is the primary action once a
   coin is checked), so it is outlined, not a second green slab. */
body[data-page="snipe"] #check-btn { min-height: 44px; padding: 0 18px; font-family: var(--d-font); font-size: 15px; font-weight: 650; letter-spacing: 0; text-transform: none; color: var(--d-text); background: var(--d-panel-2); border: 1px solid var(--d-accent-line); border-radius: 8px; box-shadow: none; }
body[data-page="snipe"] #check-btn:hover:not(:disabled) { background: var(--d-canvas); box-shadow: none; filter: none; }
body[data-page="snipe"] .quick-snipe-card .trade-mode-note { font-family: var(--d-font); font-size: 13px; line-height: 1.5; color: var(--d-text-2); }
body[data-page="snipe"] .quick-snipe-card .trade-mode-note.danger { color: var(--d-danger); }
body[data-page="snipe"] .quick-snipe-card .status-line { font-family: var(--d-font); font-size: 13px; }
body[data-page="snipe"] .quick-snipe-readout { padding: 10px 12px; font-family: var(--d-font); font-size: 14px; font-variant-numeric: tabular-nums; color: var(--d-text); background: var(--d-canvas); border: 1px solid var(--d-border); border-radius: 8px; }
body[data-page="snipe"] .quick-snipe-edit-link { font-family: var(--d-font); font-size: 13px; color: var(--d-text-2); }
body[data-page="snipe"] .qs-toggle { width: 36px; height: 36px; color: var(--d-text-2); border-color: var(--d-border); border-radius: 8px; }
body[data-page="snipe"] .qs-strip { font-family: var(--d-font); font-size: 13px; color: var(--d-text-2); background: var(--d-panel); border-color: var(--d-border); border-radius: 10px; }
body[data-page="snipe"] .qs-strip-item { background: var(--d-canvas); }
body[data-page="snipe"] .qs-strip-btn { min-height: 32px; font-family: var(--d-font); font-size: 13px; font-weight: 600; letter-spacing: 0; color: var(--d-text); border-color: var(--d-border); border-radius: 8px; }

/* Empty state: one "Find a coin" card. Discover is the primary link; the check card beside it is
   the secondary way in; the list says what Check, Instant and Smart Entry each do. */
body[data-page="snipe"] .check-empty { padding: 20px; background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 12px; }
body[data-page="snipe"] .desk-find { display: grid; gap: 12px; }
body[data-page="snipe"] .desk-find-title { margin: 0; font-family: var(--d-font); font-size: 18px; font-weight: 650; letter-spacing: 0; text-transform: none; color: var(--d-text); }
body[data-page="snipe"] .desk-find-sub { max-width: 640px; margin: 0; font-size: 14px; line-height: 1.55; color: var(--d-text-2); }
body[data-page="snipe"] .desk-find-sub b { font-weight: 600; color: var(--d-text); }
body[data-page="snipe"] .desk-find-primary { justify-self: start; display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px; font-size: 15px; font-weight: 650; color: var(--d-canvas); background: var(--d-accent); border-radius: 8px; text-decoration: none; }
body[data-page="snipe"] .desk-find-primary:hover { filter: brightness(1.06); }
body[data-page="snipe"] .desk-discover { display: block; margin: 0; padding: 0; background: none; border: 0; }
body[data-page="snipe"] .desk-discover-links a { display: inline-flex; align-items: center; min-height: 36px; padding: 0 12px; font-family: var(--d-font); font-size: 14px; color: var(--d-text-2); background: var(--d-canvas); border: 1px solid var(--d-border); border-radius: 8px; }
body[data-page="snipe"] .desk-discover-links a:hover { color: var(--d-text); background: var(--d-canvas); border-color: var(--d-accent-line); }
/* The explanations fold away (Codex review of #68): one line until opened. */
body[data-page="snipe"] .desk-how { margin-top: 2px; padding-top: 10px; border-top: 1px solid var(--d-border); }
body[data-page="snipe"] .desk-how-summary { display: inline-flex; align-items: center; gap: 8px; min-height: 36px; font-size: 14px; font-weight: 600; color: var(--d-text-2); cursor: pointer; list-style: none; }
body[data-page="snipe"] .desk-how-summary::-webkit-details-marker { display: none; }
body[data-page="snipe"] .desk-how-summary::before { content: '▸'; color: var(--d-muted); transition: transform .15s ease; }
body[data-page="snipe"] .desk-how[open] > .desk-how-summary::before { transform: rotate(90deg); }
body[data-page="snipe"] .desk-how-summary:hover { color: var(--d-text); }
body[data-page="snipe"] .desk-how > .desk-find-sub { margin: 8px 0 0; }
body[data-page="snipe"] .desk-steps { display: grid; gap: 6px; margin: 10px 0 0; padding: 0 0 0 18px; font-size: 14px; line-height: 1.5; color: var(--d-text-2); }
body[data-page="snipe"] .desk-steps b { font-weight: 600; color: var(--d-text); }
body[data-page="snipe"] .check-empty-hint { margin: 12px 0 0; font-family: var(--d-font); font-size: 13px; color: var(--d-muted); }
body[data-page="snipe"] .check-empty-hint .icn { color: var(--d-muted); }
body[data-page="snipe"] .check-empty-hint strong { color: var(--d-text); }

/* Checked coin: identity, the analysis, the entry setup, then one primary action — Fire (Instant) or
   Arm Smart Entry — with the full-screen chart as the secondary. Verdict colours keep their meaning:
   a rejected card is outlined red, a warning amber, a passed card neutral. */
body[data-page="snipe"] #check-result .cluster-card { padding: 18px; background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 12px; box-shadow: none; }
body[data-page="snipe"] #check-result .cluster-card.flagged { border-color: rgba(var(--d-danger-rgb), .45); }
body[data-page="snipe"] #check-result .cluster-card.warning { border-color: rgba(var(--d-caution-rgb), .45); }
body[data-page="snipe"] #check-result .cluster-card.clean { background: var(--d-panel); border-color: var(--d-border); }
body[data-page="snipe"] #check-result .target-name { font-family: var(--d-font); font-size: 17px; font-weight: 650; color: var(--d-text); }
body[data-page="snipe"] #check-result .target-symbol { font-family: var(--d-font); color: var(--d-text-2); }
body[data-page="snipe"] #check-result .cluster-tag { font-family: var(--d-font); letter-spacing: .02em; }
body[data-page="snipe"] #check-result .repeat-note { font-family: var(--d-font); font-size: 13px; line-height: 1.5; color: var(--d-caution); background: var(--d-caution-soft); border-color: rgba(var(--d-caution-rgb), .35); }
body[data-page="snipe"] #check-result .repeat-note.advisory-note { color: var(--d-text-2); background: var(--d-panel-2); border-color: var(--d-border); }
body[data-page="snipe"] #check-result .cluster-funder { font-family: var(--d-font); font-size: 13px; color: var(--d-text-2); }
body[data-page="snipe"] #check-result .mode-hint { font-family: var(--d-font); font-size: 13px; color: var(--d-text-2); }
body[data-page="snipe"] #check-result .chart-tf-btn { min-height: 32px; font-family: var(--d-font); font-size: 13px; letter-spacing: 0; color: var(--d-text-2); background: transparent; border: 1px solid transparent; border-radius: 8px; box-shadow: none; }
body[data-page="snipe"] #check-result .chart-tf-btn.active { color: var(--d-text); background: var(--d-panel-2); border-color: var(--d-accent-line); box-shadow: inset 0 -2px 0 var(--d-accent); }
body[data-page="snipe"] #check-result .check-chart-wrap { background: var(--d-canvas); border-color: var(--d-border); border-radius: 10px; }
body[data-page="snipe"] #check-result .custom-trade-row { font-family: var(--d-font); background: var(--d-canvas); border-color: var(--d-border); border-radius: 8px; }
body[data-page="snipe"] #check-result .custom-trade-row .stat-input { font-family: var(--d-font); font-variant-numeric: tabular-nums; color: var(--d-text); }
body[data-page="snipe"] .check-close-btn { width: 36px; height: 36px; color: var(--d-text-2); background: var(--d-panel-2); border-color: var(--d-border); border-radius: 8px; }
/* The action row docks to the bottom of the screen while the reasons above it are read (the Desk's
   "the action stays reachable" rule, which used to dock the fire button alone), on an opaque backing so
   nothing shows through it. The rejected card's Override button docks the same way. */
body[data-page="snipe"] .check-actions { position: sticky; bottom: 12px; z-index: 4; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: stretch; gap: 10px; margin: 12px -10px 0; padding: 10px; background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 12px; box-shadow: 0 -12px 24px -12px var(--d-canvas); }
body[data-page="snipe"] #check-result .check-actions .buy-confirm-btn { position: static; width: auto; margin: 0; }
body[data-page="snipe"] #check-result .override-trigger-btn { min-height: 44px; font-family: var(--d-font); font-size: 14px; letter-spacing: 0; color: var(--d-danger); background: var(--d-panel); border-color: rgba(var(--d-danger-rgb), .5); box-shadow: 0 -12px 24px -12px var(--d-canvas); }
body[data-page="snipe"] #check-result .override-trigger-btn:hover { background: var(--d-danger-soft); }
body[data-page="snipe"] #check-result .check-fire-btn { min-height: 48px; margin: 0; font-family: var(--d-font); font-size: 16px; font-weight: 650; letter-spacing: 0; text-transform: none; color: var(--d-canvas); background: var(--d-accent); border-radius: 10px; box-shadow: none; }
body[data-page="snipe"] #check-result .check-fire-btn:hover { filter: brightness(1.06); box-shadow: none; }
body[data-page="snipe"] #check-result .check-fire-btn.warning-fire { color: var(--d-canvas); background: var(--d-caution); box-shadow: none; }
body[data-page="snipe"] #check-result .check-fire-btn:disabled { color: var(--d-muted); background: var(--d-panel-2); cursor: not-allowed; filter: none; }
body[data-page="snipe"] #check-result .check-fullscreen-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 48px; padding: 0 16px; font-family: var(--d-font); font-size: 14px; font-weight: 600; color: var(--d-text); background: transparent; border: 1px solid var(--d-border); border-radius: 10px; cursor: pointer; }
body[data-page="snipe"] #check-result .check-fullscreen-btn:hover { background: var(--d-panel-2); }
/* The read-only token dossier under a checked coin (desk-vnext.js). */
body[data-page="snipe"] .dossier-vnext { font-family: var(--d-font); background: var(--d-panel); border-color: var(--d-border); border-radius: 12px; }
body[data-page="snipe"] .dossier-vnext-head { font-family: var(--d-font); font-size: 15px; font-weight: 650; letter-spacing: 0; color: var(--d-text); }
body[data-page="snipe"] .dossier-sec { background: var(--d-canvas); border-color: var(--d-border); border-radius: 10px; }
body[data-page="snipe"] .dossier-sec h4 { font-family: var(--d-font); font-size: 13px; letter-spacing: 0; color: var(--d-text-2); }
body[data-page="snipe"] .dossier-kv { font-family: var(--d-font); font-size: 13px; font-variant-numeric: tabular-nums; }
body[data-page="snipe"] .dossier-kv dt { color: var(--d-muted); }
body[data-page="snipe"] .dossier-kv dd { color: var(--d-text); }

/* Floating trade notifications (shared/trade-popups.js) are hidden on the Desk at every width (Zion,
   2026-10-14). The Desk's "Positions and Smart Entry" panel already lists each fill, and the floating
   cards sat bottom-right: on phones over Discover and the check form, on desktop over the docked Fire /
   Full Screen Chart row of a checked coin (with three cards, Full Screen Chart could not be tapped until
   they were dismissed). Every other page keeps the notifications unchanged. */
body[data-page="snipe"] .stp-stack { display: none; }

/* Narrow screens: one column in task order — the header, positions and armed coins, then the way to
   a coin (Discover first while nothing is checked; the dossier first once one is), then the check
   card. Every control at least 44 px tall; nothing scrolls the page sideways. */
@media (max-width: 960px) {
  body[data-page="snipe"] .sniper-layout { padding: 16px 12px 48px; }
  body[data-page="snipe"] .desk-head-title { font-size: 20px; }
  body[data-page="snipe"] .sniper-body { grid-template-columns: minmax(0, 1fr); }
  body[data-page="snipe"] .sniper-check-col { order: -1; }
  body[data-page="snipe"] .positions-ticker-inner { grid-template-columns: minmax(0, 1fr); }
  body[data-page="snipe"] .positions-ticker-link { grid-column: 1; grid-row: auto; }
  body[data-page="snipe"] .check-actions { grid-template-columns: minmax(0, 1fr); }
  body[data-page="snipe"] :is(.fire-mode-btn, .trade-mode-btn, #check-btn, .desk-discover-links a, .qs-strip-btn, .desk-head-btn, .desk-head-link, .positions-ticker-link, .edit-arm-amount-btn, .armed-pos-card-cancel, .chart-tf-btn, .check-close-btn, .desk-how-summary) { min-height: 44px; }
  body[data-page="snipe"] .armed-pos-card-cancel, body[data-page="snipe"] .check-close-btn, body[data-page="snipe"] .qs-toggle { min-width: 44px; min-height: 44px; }
  body[data-page="snipe"] .quick-snipe-edit-link { display: inline-flex; align-items: center; min-height: 44px; }
}

/* A single task comes first: prepare a coin, then read its dossier. Queued orders
   stay below the workspace rather than pushing the primary form off the screen. */
body[data-page="snipe"] .sniper-body { margin-bottom: 24px; grid-template-columns: minmax(340px, 420px) minmax(0, 1fr); }
body[data-page="snipe"] .desk-head-sub { max-width: 620px; }
body[data-page="snipe"] .desk-review-intro { font: 15px/1.65 var(--d-font); color: var(--d-text-2); margin: 12px 0 22px; max-width: 520px; }
body[data-page="snipe"] .desk-find-primary { background: var(--d-panel-2); color: var(--d-accent-ink); border: 1px solid var(--d-accent-line); }
body[data-page="snipe"] .desk-find { padding: 24px; }
body[data-page="snipe"] .desk-find-title { font-size: 21px; }
body[data-page="snipe"] .desk-discover-links a { font-size: 13px; }
body[data-page="snipe"] .intake-label { display: block; }
body[data-page="snipe"] #check-btn { min-height: 48px; background: var(--d-accent); color: var(--d-canvas); font-weight: 700; }
body[data-page="snipe"] .positions-ticker { margin-top: 4px; }
@media (max-width: 960px) {
  body[data-page="snipe"] .sniper-body { grid-template-columns: minmax(0, 1fr); }
  body[data-page="snipe"] .sniper-check-col { order: 0; }
  body[data-page="snipe"] .desk-find { padding: 18px; }
}

/* Keep the empty Desk focused on choosing one coin. Entry preferences remain
   available through a native disclosure; trading handlers and ids are unchanged. */
body[data-page="snipe"] .sniper-body { grid-template-columns: minmax(300px, 360px) minmax(0, 1fr); }
body[data-page="snipe"] .desk-entry-choice { padding-top: 16px; border-top: 1px solid var(--d-border); }
body[data-page="snipe"] .desk-entry-choice .fire-mode-row { margin: 10px 0 0; }
body[data-page="snipe"] .desk-entry-settings { border-top: 1px solid var(--d-border); padding-top: 4px; }
body[data-page="snipe"] .desk-entry-settings > summary { display: flex; flex-direction: column; justify-content: center; gap: 4px; min-height: 64px; cursor: pointer; font: 600 14px var(--d-font); color: var(--d-text); }
body[data-page="snipe"] .desk-entry-settings > summary span { font-size: 12px; font-weight: 400; color: var(--d-muted); }
body[data-page="snipe"] .desk-entry-settings > summary::after { content: '＋'; align-self: flex-end; margin-top: -30px; }
body[data-page="snipe"] .desk-entry-settings[open] > summary::after { content: '−'; }
body[data-page="snipe"] .desk-entry-settings > .control-group-divider:first-of-type { display: none; }
body[data-page="snipe"] .desk-entry-settings .control-group-section { padding-top: 16px; }
body[data-page="snipe"] .desk-review-empty { min-height: 360px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; background: var(--d-canvas); border-style: dashed; }
body[data-page="snipe"] .desk-review-symbol { display: grid; place-items: center; width: 56px; height: 56px; margin-bottom: 20px; border: 1px solid var(--d-border); border-radius: 16px; color: var(--d-muted); font-size: 32px; }
body[data-page="snipe"] .desk-review-empty .desk-find-title { font-size: 20px; }
body[data-page="snipe"] .desk-review-empty .desk-review-intro { font-size: 14px; margin: 12px 0 20px; }
body[data-page="snipe"] .desk-review-empty .desk-find-primary { padding: 8px 0; min-height: 44px; border: 0; background: transparent; font-size: 14px; text-decoration: underline; text-underline-offset: 4px; }
body[data-page="snipe"] .desk-queue-group--positions[hidden] { display: none; }
body[data-page="snipe"] .positions-ticker-hint { display: none; }
body[data-page="snipe"] .positions-ticker:not(:has(.armed-pos-card, .armed-hold-banner)) { display: none; }
@media (max-width: 960px) {
  body[data-page="snipe"] .sniper-body { grid-template-columns: minmax(0, 1fr); }
  body[data-page="snipe"] .desk-review-empty { min-height: 240px; }
}
body[data-page="snipe"] .desk-review-empty { border: 0; background: transparent; }
