/* ── Custom properties ─────────────────────────────────────────────────────── */
:root {
  --bg-primary: #080c14;
  --bg-secondary: #0d1117;
  --bg-tertiary: #111822;
  --bg-card: #0d1117;
  --border-subtle: #1a2332;
  --border-muted: #1e2d3d;

  --text-primary: #e2e8f0;
  --text-secondary: #94a3b8;
  --text-muted: #4a5568;

  --accent-emerald: #10b981;
  --accent-emerald-dim: #065f46;
  --accent-sky: #38bdf8;
  --accent-amber: #f59e0b;
  --accent-orange: #fb923c;
  --accent-red: #ef4444;

  --grade-a-color: #10b981;
  --grade-a-bg: rgba(16, 185, 129, 0.08);
  --grade-a-border: rgba(16, 185, 129, 0.3);
  --grade-b-color: #38bdf8;
  --grade-b-bg: rgba(56, 189, 248, 0.08);
  --grade-b-border: rgba(56, 189, 248, 0.25);
  --grade-c-color: #f59e0b;
  --grade-c-bg: rgba(245, 158, 11, 0.08);
  --grade-c-border: rgba(245, 158, 11, 0.2);
  --grade-d-color: #fb923c;
  --grade-d-bg: rgba(251, 146, 60, 0.06);
  --grade-d-border: rgba(251, 146, 60, 0.18);
  --grade-f-color: #64748b;
  --grade-f-bg: rgba(100, 116, 139, 0.05);
  --grade-f-border: rgba(100, 116, 139, 0.15);

  --font-display: 'Syne', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;

  --sidebar-width: 220px;
  --mobile-nav-height: 54px;
  --transition: 0.15s ease;
}

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

html, body {
  height: 100%;
}

body {
  background: var(--bg-primary);
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 13px;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  /* Subtle dot grid texture */
  background-image: radial-gradient(circle, #1a2332 1px, transparent 1px);
  background-size: 24px 24px;
}

a {
  color: inherit;
  text-decoration: none;
}

/* ── App layout ─────────────────────────────────────────────────────────────── */
.app-layout {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: var(--sidebar-width);
  background: var(--bg-secondary);
  border-right: 1px solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  z-index: 100;
}

.main-content {
  margin-left: var(--sidebar-width);
  flex: 1;
  min-height: 100vh;
}

/* ── Sidebar ─────────────────────────────────────────────────────────────────── */
.sidebar-logo {
  padding: 24px 20px 20px;
  border-bottom: 1px solid var(--border-subtle);
}

.logo-text {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--accent-emerald);
  text-shadow: 0 0 24px rgba(16, 185, 129, 0.25);
}

.logo-sub {
  font-size: 9px;
  color: var(--text-muted);
  letter-spacing: 0.2em;
  margin-top: 3px;
  text-transform: uppercase;
}

.sidebar-nav {
  flex: 1;
  padding: 12px 0;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  cursor: pointer;
  color: var(--text-muted);
  transition: all var(--transition);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-left: 2px solid transparent;
  user-select: none;
}

.nav-item:hover {
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.02);
}

.nav-item.active {
  color: var(--accent-emerald);
  border-left-color: var(--accent-emerald);
  background: rgba(16, 185, 129, 0.05);
}

.nav-icon {
  font-size: 14px;
  width: 18px;
  text-align: center;
}

.ws-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 16px 20px;
  border-top: 1px solid var(--border-subtle);
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ws-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-red);
  flex-shrink: 0;
}

.ws-dot.connected {
  background: var(--accent-emerald);
  box-shadow: 0 0 6px var(--accent-emerald);
  animation: wsPulse 2s infinite;
}

@keyframes wsPulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.5; }
}

.backoff-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  border-top: 1px solid var(--border-subtle);
  font-size: 10px;
  color: var(--accent-amber);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
}

.backoff-indicator:hover {
  background: rgba(245, 158, 11, 0.05);
}

.ws-dot.in-backoff {
  background: var(--accent-amber);
  box-shadow: 0 0 6px var(--accent-amber);
  animation: wsPulse 1s infinite;
}

.ws-indicator.fetch-error {
  color: var(--accent-red);
  cursor: pointer;
}

.ws-indicator.fetch-error:hover {
  background: rgba(239, 68, 68, 0.05);
}

.ws-dot.fetch-error {
  background: var(--accent-red);
  box-shadow: 0 0 6px var(--accent-red);
  animation: wsPulse 1s infinite;
}

/* ── Logs page ───────────────────────────────────────────────────────────────── */
.backoff-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  background: rgba(245, 158, 11, 0.08);
  border: 1px solid rgba(245, 158, 11, 0.3);
  border-radius: 6px;
  padding: 10px 14px;
  margin-bottom: 12px;
  color: var(--accent-amber);
  font-size: 12px;
}

.backoff-pill {
  background: rgba(245, 158, 11, 0.12);
  border-radius: 4px;
  padding: 2px 8px;
  font-family: var(--font-mono);
  font-size: 11px;
}

.logs-toolbar {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: 12px;
}

/* One button per market, plus All and System. The chosen one has to read at a
   glance, because it decides which lines are missing from the list.           */
.logs-markets {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
}

.market-filter {
  padding: 5px 12px;
  border: 1px solid var(--border-muted);
  border-radius: 4px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 11px;
  cursor: pointer;
  transition: border-color var(--transition), color var(--transition), background var(--transition);
}

.market-filter:hover {
  border-color: var(--accent-emerald-dim);
  color: var(--text-primary);
}

.market-filter:focus-visible {
  outline: 2px solid var(--accent-sky);
  outline-offset: 2px;
}

.market-filter.on {
  border-color: var(--accent-emerald);
  background: rgba(16, 185, 129, .09);
  color: var(--text-primary);
}

.logs-count {
  color: var(--text-muted);
  font-size: 11px;
  white-space: nowrap;
}

.logs-container {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  max-height: calc(100vh - 260px);
  overflow-y: auto;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 11px;
}

.log-row {
  display: flex;
  gap: 12px;
  padding: 5px 14px;
  border-bottom: 1px solid rgba(26, 35, 50, 0.5);
  align-items: baseline;
}

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

.log-time {
  color: var(--text-muted);
  white-space: nowrap;
  flex-shrink: 0;
}

.log-level {
  flex-shrink: 0;
  width: 44px;
  font-weight: 600;
  letter-spacing: 0.05em;
  font-size: 10px;
}

.level-info  { color: var(--accent-sky); }
.level-warn  { color: var(--accent-amber); }
.level-error { color: var(--accent-red); }

.log-msg {
  color: var(--text-secondary);
  white-space: pre-wrap;
  word-break: break-word;
}

.msg-warn  { color: var(--accent-amber); }
.msg-error { color: var(--accent-red); }

/* ── Page header ─────────────────────────────────────────────────────────────── */
.page-header {
  padding: 24px 28px 16px;
  border-bottom: 1px solid var(--border-subtle);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
}

.page-title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
}

.page-subtitle {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
  letter-spacing: 0.05em;
  font-family: var(--font-mono);
}

/* ── Filter bar ──────────────────────────────────────────────────────────────── */
.filter-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 28px;
  border-bottom: 1px solid var(--border-subtle);
  flex-wrap: wrap;
  background: var(--bg-secondary);
}

.filter-label {
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-right: 2px;
}

/* Grade filter pills */
.grade-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 4px;
  border: 1px solid var(--border-muted);
  cursor: pointer;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 13px;
  transition: all var(--transition);
  color: var(--text-muted);
  user-select: none;
}

.grade-pill:hover {
  border-color: var(--text-secondary);
  color: var(--text-secondary);
}

.grade-pill.active-A {
  color: var(--grade-a-color);
  border-color: var(--grade-a-border);
  background: var(--grade-a-bg);
}

.grade-pill.active-B {
  color: var(--grade-b-color);
  border-color: var(--grade-b-border);
  background: var(--grade-b-bg);
}

.grade-pill.active-C {
  color: var(--grade-c-color);
  border-color: var(--grade-c-border);
  background: var(--grade-c-bg);
}

.grade-pill.active-D {
  color: var(--grade-d-color);
  border-color: var(--grade-d-border);
  background: var(--grade-d-bg);
}

.grade-pill.active-F {
  color: var(--grade-f-color);
  border-color: var(--grade-f-border);
  background: var(--grade-f-bg);
}

select.filter-select {
  background: var(--bg-tertiary);
  border: 1px solid var(--border-muted);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer;
  outline: none;
}

select.filter-select:focus {
  border-color: var(--accent-emerald);
}

/* ── Listings ────────────────────────────────────────────────────────────────── */
.listings-container {
  padding: 20px 28px;
}

.listings-count {
  font-size: 10px;
  color: var(--text-muted);
  margin-bottom: 16px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.listings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 12px;
}

/* ── Listing card ────────────────────────────────────────────────────────────── */
.listing-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  overflow: hidden;
  transition: all 0.2s ease;
  cursor: pointer;
  position: relative;
}

.listing-card:hover {
  border-color: var(--border-muted);
  transform: translateY(-1px);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}

.listing-card.grade-A {
  border-color: var(--grade-a-border);
  box-shadow: 0 0 20px rgba(16, 185, 129, 0.06);
}

.listing-card.grade-A:hover {
  box-shadow: 0 0 30px rgba(16, 185, 129, 0.14), 0 4px 24px rgba(0, 0, 0, 0.4);
}

.listing-card.grade-B {
  border-color: var(--grade-b-border);
}

.listing-card.grade-B:hover {
  box-shadow: 0 0 20px rgba(56, 189, 248, 0.08), 0 4px 24px rgba(0, 0, 0, 0.4);
}

.card-image {
  width: 100%;
  height: 160px;
  object-fit: cover;
  display: block;
  background: var(--bg-tertiary);
}

.card-image-placeholder {
  width: 100%;
  height: 160px;
  background: var(--bg-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 32px;
}

.card-body {
  padding: 12px 14px;
}

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

.card-title {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.3;
  flex: 1;
}

.card-grade {
  flex-shrink: 0;
}

.card-price-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}

.card-price {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
}

/* A word in the price slot — "Bieden", "N.o.t.k." — instead of an amount.
   It reads in the display face at a smaller size, so a card with a word is
   never mistaken at a glance for a card with a number. */
.card-price-text {
  font-family: var(--font-display);
  font-size: 15px;
  color: var(--text-secondary);
}

/* The qualifier beside an amount that is not the asking price. */
.card-price-type {
  font-family: var(--font-display);
  font-size: 11px;
  color: var(--text-muted);
}

.card-ref-price {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  text-decoration: line-through;
}

.card-discount {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--accent-emerald);
}

.card-score-row {
  margin-bottom: 8px;
}

.card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.card-condition {
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.05em;
}

.card-brand {
  font-size: 10px;
  color: var(--text-secondary);
  font-weight: 500;
  letter-spacing: 0.05em;
}

.card-time {
  font-size: 10px;
  color: var(--text-muted);
  font-family: var(--font-mono);
}

.card-seller {
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.card-actions {
  display: flex;
  gap: 6px;
  margin-top: 10px;
  border-top: 1px solid var(--border-subtle);
  padding-top: 10px;
}

.btn-action {
  flex: 1;
  padding: 6px 10px;
  border-radius: 4px;
  border: 1px solid var(--border-muted);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  transition: all var(--transition);
  display: flex;
  align-items: center;
  justify-content: center;
}

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

.btn-action.primary {
  background: var(--accent-emerald);
  border-color: var(--accent-emerald);
  color: #000;
  font-weight: 700;
}

.btn-action.primary:hover {
  background: #0ea572;
}

.btn-action.btn-delete {
  flex: 0 0 auto;
  padding: 6px 8px;
  color: var(--text-muted);
}

.btn-action.btn-delete:hover {
  border-color: #ef4444;
  color: #ef4444;
}

/* ── Score bar ───────────────────────────────────────────────────────────────── */
.score-bar-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
}

.score-bar-track {
  flex: 1;
  height: 4px;
  background: var(--border-subtle);
  border-radius: 2px;
  overflow: hidden;
}

.score-bar-fill {
  height: 100%;
  border-radius: 2px;
  transition: width 0.6s ease;
}

.score-bar-fill.grade-A {
  background: var(--grade-a-color);
  box-shadow: 0 0 8px var(--grade-a-color);
}

.score-bar-fill.grade-B {
  background: var(--grade-b-color);
}

.score-bar-fill.grade-C {
  background: var(--grade-c-color);
}

.score-bar-fill.grade-D {
  background: var(--grade-d-color);
}

.score-bar-fill.grade-F {
  background: var(--grade-f-color);
}

.score-bar-label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  min-width: 24px;
  text-align: right;
}

.score-bar-label.grade-A { color: var(--grade-a-color); }
.score-bar-label.grade-B { color: var(--grade-b-color); }
.score-bar-label.grade-C { color: var(--grade-c-color); }
.score-bar-label.grade-D { color: var(--grade-d-color); }
.score-bar-label.grade-F { color: var(--grade-f-color); }

/* ── Score breakdown tooltip ─────────────────────────────────────────────────── */
.score-tooltip {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  right: 0;
  background: var(--bg-secondary);
  border: 1px solid var(--border-muted);
  border-radius: 6px;
  padding: 8px 10px;
  z-index: 10;
  pointer-events: none;
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
}

.score-tooltip-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 10px;
  line-height: 1.6;
}

.score-tooltip-label {
  color: var(--text-muted);
  font-family: var(--font-mono);
}

.score-tooltip-value {
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-weight: 700;
}

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

.score-tooltip-warning {
  font-size: 9px;
  color: var(--accent-amber);
  font-family: var(--font-mono);
  margin-top: 3px;
}

/* ── Grade badge ─────────────────────────────────────────────────────────────── */
.grade-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 14px;
}

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

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

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

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

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

/* ── Platform badge ──────────────────────────────────────────────────────────── */
.platform-badge {
  display: inline-block;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-family: var(--font-mono);
  background: rgba(56, 189, 248, 0.08);
  color: var(--accent-sky);
  border: 1px solid rgba(56, 189, 248, 0.2);
}

/* One target carries one badge per market, so they need to sit apart. */
.platform-badge + .platform-badge {
  margin-left: 4px;
}

/* A market kept but switched off. Muted rather than hidden — the target still
   holds its settings, and a hidden market looks like a deleted one. */
.platform-badge.off {
  background: rgba(148, 163, 184, 0.06);
  color: var(--text-muted);
  border-color: var(--border-muted);
}

/* The badge spelled out rather than abbreviated. A listing card carries the
   market's name, because "MA" next to "VI" is a puzzle at the exact moment the
   reader is comparing two cards. The table keeps the short form: a row there
   may carry three badges at once. */
.platform-badge.named {
  text-transform: none;
  letter-spacing: 0.02em;
  font-size: 10px;
}

/* One colour per market, so the market is readable before the word is. The
   colours are the markets' own, dimmed to sit on a dark card. A market with no
   rule here falls back to the sky blue above rather than losing its badge. */
.platform-badge.market-vinted {
  background: rgba(45, 212, 191, 0.08);
  color: #2dd4bf;
  border-color: rgba(45, 212, 191, 0.22);
}

.platform-badge.market-marktplaats {
  background: rgba(251, 146, 60, 0.08);
  color: var(--accent-orange);
  border-color: rgba(251, 146, 60, 0.22);
}

.platform-badge.market-tweakers {
  background: rgba(129, 140, 248, 0.08);
  color: #818cf8;
  border-color: rgba(129, 140, 248, 0.22);
}

.watchlist-badge {
  display: inline-block;
  max-width: 100%;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 0.04em;
  font-family: var(--font-mono);
  background: rgba(148, 163, 184, 0.08);
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

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

.empty-state-icon {
  font-size: 40px;
  margin-bottom: 16px;
  opacity: 0.5;
}

.empty-state-title {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--text-secondary);
  margin-bottom: 8px;
}

.empty-state-text {
  font-size: 12px;
  line-height: 1.6;
}

/* ── Loading spinner ─────────────────────────────────────────────────────────── */
.loading-spinner {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px;
}

.spinner {
  width: 20px;
  height: 20px;
  border: 2px solid var(--border-subtle);
  border-top-color: var(--accent-emerald);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

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

/* ── Toast notifications ─────────────────────────────────────────────────────── */
.toast-container {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}

.toast {
  background: var(--bg-secondary);
  border: 1px solid var(--border-muted);
  border-radius: 6px;
  padding: 12px 16px;
  font-size: 12px;
  max-width: 300px;
  animation: toastIn 0.2s ease;
  pointer-events: auto;
}

.toast-image {
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border-muted);
}

.toast.grade-A {
  border-color: var(--grade-a-border);
  box-shadow: 0 0 16px rgba(16, 185, 129, 0.1);
}

.toast.grade-B {
  border-color: var(--grade-b-border);
}

@keyframes toastIn {
  from { transform: translateX(110%); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* ── Watchlist table ─────────────────────────────────────────────────────────── */
.watchlist-table {
  width: 100%;
  border-collapse: collapse;
}

.watchlist-table th {
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 10px 14px;
  text-align: left;
  border-bottom: 1px solid var(--border-subtle);
}

.watchlist-table td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  font-size: 12px;
  vertical-align: middle;
}

.watchlist-table tr:last-child td {
  border-bottom: none;
}

.watchlist-table tr:hover td {
  background: rgba(255, 255, 255, 0.01);
}

.target-cell {
  cursor: pointer;
}

.target-cell:hover .target-name {
  color: var(--accent-emerald);
}

.target-name {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--text-primary);
  font-size: 13px;
}

.target-query {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* ── Toggle switch ───────────────────────────────────────────────────────────── */
.toggle {
  position: relative;
  display: inline-block;
  width: 32px;
  height: 18px;
}

.toggle input {
  opacity: 0;
  width: 0;
  height: 0;
}

.toggle-slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-muted);
  border-radius: 10px;
  transition: all var(--transition);
}

.toggle input:checked + .toggle-slider {
  background: var(--accent-emerald);
  border-color: var(--accent-emerald);
}

.toggle-slider::before {
  content: '';
  position: absolute;
  height: 12px;
  width: 12px;
  left: 2px;
  bottom: 2px;
  background: var(--text-muted);
  border-radius: 50%;
  transition: all var(--transition);
}

.toggle input:checked + .toggle-slider::before {
  transform: translateX(14px);
  background: #000;
}

/* A switch over something that is not configured yet. It stays visible, so the
   control is where it will be, but it does not invite a click that does
   nothing. */
.toggle input:disabled + .toggle-slider {
  cursor: not-allowed;
  opacity: 0.4;
}

/* ── Buttons ─────────────────────────────────────────────────────────────────── */
.btn {
  padding: 7px 14px;
  border-radius: 4px;
  border: 1px solid var(--border-muted);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: all var(--transition);
}

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

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

.btn-primary {
  background: var(--accent-emerald);
  border-color: var(--accent-emerald);
  color: #000;
  font-weight: 700;
}

.btn-primary:hover {
  background: #0ea572;
  border-color: #0ea572;
  color: #000;
}

.btn-danger {
  border-color: rgba(239, 68, 68, 0.3);
  color: var(--accent-red);
}

.btn-danger:hover {
  background: rgba(239, 68, 68, 0.08);
  border-color: var(--accent-red);
}

.btn-sm {
  padding: 4px 10px;
  font-size: 10px;
}

/* ── Modal ───────────────────────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.modal {
  background: var(--bg-secondary);
  border: 1px solid var(--border-muted);
  border-radius: 8px;
  padding: 24px;
  min-width: 440px;
  max-width: 560px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
}

.modal-title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
  margin-bottom: 20px;
  color: var(--text-primary);
}

/* ── Form elements ───────────────────────────────────────────────────────────── */
.form-group {
  margin-bottom: 14px;
}

.form-label {
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 5px;
  display: block;
}

.form-input,
.form-select,
.form-textarea {
  width: 100%;
  padding: 8px 10px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-muted);
  border-radius: 4px;
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 12px;
  outline: none;
  transition: border-color var(--transition);
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
  border-color: var(--accent-emerald);
}

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

/* ── Mode toggle (Model / Free search) ───────────────────────────────────────── */
.mode-toggle {
  display: flex;
  border: 1px solid var(--border-muted);
  border-radius: 4px;
  overflow: hidden;
}

.mode-btn {
  flex: 1;
  padding: 7px 12px;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: all var(--transition);
}

.mode-btn + .mode-btn {
  border-left: 1px solid var(--border-muted);
}

.mode-btn.active {
  background: var(--accent-emerald);
  color: #000;
  font-weight: 700;
}

.mode-btn:not(.active):hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.form-textarea {
  resize: vertical;
  min-height: 80px;
}

/* ── Stats page ──────────────────────────────────────────────────────────────── */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
  padding: 20px 28px;
}

.stats-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  padding: 16px;
}

.stats-model-name {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 12px;
}

.stats-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 0;
  border-bottom: 1px solid var(--border-subtle);
}

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

.stats-key {
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.stats-val {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-secondary);
  font-weight: 500;
}

.stats-val.ema {
  color: var(--accent-emerald);
  font-weight: 700;
}

.stats-condition-header {
  font-size: 9px;
  color: var(--text-muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin: 8px 0 4px;
}

/* ── Settings page ───────────────────────────────────────────────────────────── */
.settings-section {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  padding: 20px;
  margin-bottom: 16px;
}

.settings-section-title {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 16px;
  letter-spacing: 0.05em;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border-subtle);
}

/* ── Range slider ────────────────────────────────────────────────────────────── */
.slider-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}

.slider-label {
  font-size: 11px;
  color: var(--text-secondary);
  min-width: 90px;
  font-family: var(--font-mono);
}

input[type="range"] {
  flex: 1;
  -webkit-appearance: none;
  height: 3px;
  background: var(--border-muted);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  background: var(--accent-emerald);
  border-radius: 50%;
  cursor: pointer;
}

input[type="range"]::-moz-range-thumb {
  width: 14px;
  height: 14px;
  background: var(--accent-emerald);
  border-radius: 50%;
  cursor: pointer;
  border: none;
}

.slider-value {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--accent-emerald);
  min-width: 32px;
  text-align: right;
  font-weight: 700;
}

/* ── New listing animation ───────────────────────────────────────────────────── */
@keyframes fadeInDown {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

.listing-new {
  animation: fadeInDown 0.3s ease;
}

/* ── Scrollbar ───────────────────────────────────────────────────────────────── */
::-webkit-scrollbar {
  width: 5px;
  height: 5px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--border-muted);
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

/* ── Mobile bottom navigation ────────────────────────────────────────────────── */
.mobile-nav {
  display: none;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: var(--mobile-nav-height);
  padding-bottom: env(safe-area-inset-bottom, 0);
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-subtle);
  z-index: 100;
}

.mobile-nav-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  cursor: pointer;
  color: var(--text-muted);
  transition: color var(--transition);
  border-top: 2px solid transparent;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.mobile-nav-item.active {
  color: var(--accent-emerald);
  border-top-color: var(--accent-emerald);
  background: rgba(16, 185, 129, 0.05);
}

.mobile-nav-icon {
  font-size: 16px;
  line-height: 1;
}

.mobile-nav-label {
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ── Status Bar ──────────────────────────────────────────────────────────────── */
.status-bar {
  position: fixed;
  bottom: 0;
  left: var(--sidebar-width);
  right: 0;
  height: 28px;
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-subtle);
  display: flex;
  align-items: center;
  gap: 0;
  padding: 0 16px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
  z-index: 50;
  transition: background 0.15s;
}

.status-bar:hover {
  background: var(--bg-tertiary);
}

.status-bar-section {
  display: flex;
  align-items: center;
  gap: 6px;
}

.status-divider {
  color: var(--border-muted);
  margin: 0 12px;
}

.status-bar-hint {
  margin-left: auto;
  color: var(--text-muted);
  font-size: 10px;
}

.status-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

.status-dot.idle {
  background: var(--accent-emerald);
}

.status-dot.fetching {
  background: var(--accent-sky);
  animation: status-pulse 1s ease-in-out infinite;
}

.status-dot.error {
  background: var(--accent-red);
  box-shadow: 0 0 6px var(--accent-red);
  animation: status-pulse 1s ease-in-out infinite;
}

.status-error-text {
  color: var(--accent-red);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 60vw;
}

@keyframes status-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

.status-text strong {
  color: var(--text-primary);
  font-weight: 600;
}

.fetching-label {
  color: var(--accent-sky);
}

/* Push main content up so status bar doesn't overlap */
.main-content {
  padding-bottom: 28px;
}

/* ── Scheduler Modal ─────────────────────────────────────────────────────────── */
.scheduler-modal {
  background: var(--bg-secondary);
  border: 1px solid var(--border-muted);
  border-radius: 8px;
  width: 100%;
  max-width: 1100px;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.scheduler-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 24px 16px;
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
}

.scheduler-body {
  padding: 20px 24px;
  overflow-y: auto;
  flex: 1;
}

.scheduler-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 11px;
}

.scheduler-table th {
  text-align: left;
  color: var(--text-muted);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 6px 12px 6px 0;
  border-bottom: 1px solid var(--border-subtle);
  font-weight: 400;
}

.scheduler-table td {
  padding: 7px 12px 7px 0;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle;
}

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

.scheduler-row.row-error td,
.scheduler-row.row-rate_limited td {
  background: rgba(239, 68, 68, 0.04);
}

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

.status-pill {
  display: inline-block;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.pill-ok {
  background: var(--accent-emerald-dim);
  color: var(--accent-emerald);
}

.pill-rate_limited {
  background: rgba(245, 158, 11, 0.15);
  color: var(--accent-amber);
}

.pill-error {
  background: rgba(239, 68, 68, 0.15);
  color: var(--accent-red);
}

.scheduler-empty {
  padding: 32px 0;
  color: var(--text-muted);
  font-size: 12px;
  text-align: center;
}


/* ── Scheduler window ────────────────────────────────────────────────────────
   Three zones on one scroll: market cards, loop rows grouped by product, and
   one activity feed across every pair. No tab strip: a tab per pair drew the
   same product name once per market, and hid every market but the first.     */

.scheduler-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 24px;
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
}

.scheduler-search {
  flex: 1 1 200px;
  min-width: 160px;
  padding: 5px 10px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-muted);
  border-radius: 4px;
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 11px;
}

.scheduler-search:focus {
  outline: none;
  border-color: var(--accent-emerald-dim);
}

.scheduler-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

/* The problem filter is a warning, not a choice like a market chip. */
.market-filter.problems {
  border-color: var(--accent-red);
  background: rgba(239, 68, 68, 0.1);
}

.scheduler-zone-label {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 10px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 22px 0 10px;
}

.scheduler-zone-label:first-child {
  margin-top: 0;
}

.scheduler-zone-note {
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
  opacity: 0.75;
}

/* ── Zone A — one card per market ─────────────────────────────────────────── */
.market-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
}

.market-card {
  padding: 10px 12px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-subtle);
  border-left: 2px solid var(--accent-emerald);
  border-radius: 4px;
}

.market-card.state-warn { border-left-color: var(--accent-amber); }
.market-card.state-paused { border-left-color: var(--accent-orange); }
.market-card.state-error { border-left-color: var(--accent-red); }

.market-card-name {
  margin-bottom: 6px;
}

.market-card-loops {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
}

.market-card-running {
  color: var(--accent-sky);
}

.market-card-counts {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
}

.count-ok { color: var(--accent-emerald); }
.count-primed { color: var(--accent-sky); }
.count-limited { color: var(--accent-amber); }
.count-error { color: var(--accent-red); }

.market-card-note {
  margin-top: 6px;
  font-size: 10px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.market-card-note.paused { color: var(--accent-orange); }
.market-card-note.error { color: var(--accent-red); }

/* ── Zone B — one row per (target, market) pair ───────────────────────────── */
.loop-groups {
  border: 1px solid var(--border-subtle);
  border-radius: 4px;
  overflow: hidden;
}

.loop-group + .loop-group {
  border-top: 1px solid var(--border-subtle);
}

.loop-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--bg-tertiary);
  cursor: pointer;
  user-select: none;
}

.loop-group-head:hover {
  background: rgba(56, 189, 248, 0.05);
}

.loop-caret {
  color: var(--text-muted);
  font-size: 10px;
  width: 10px;
  flex-shrink: 0;
}

.loop-group-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.loop-group-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
}

.loop-group-alert {
  margin-left: auto;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: rgba(239, 68, 68, 0.15);
  color: var(--accent-red);
  font-size: 10px;
  font-weight: 700;
  text-align: center;
  line-height: 16px;
  flex-shrink: 0;
}

/* The header and the rows share one column set, so they cannot drift apart. */
.loop-head-row,
.loop-row {
  display: grid;
  grid-template-columns: 96px 104px 78px 76px 44px minmax(80px, 1fr) 12px;
  align-items: center;
  gap: 10px;
  padding: 7px 12px 7px 30px;
}

.loop-head-row {
  padding-top: 6px;
  padding-bottom: 6px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-subtle);
  font-size: 10px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.loop-row {
  border-top: 1px solid var(--border-subtle);
  font-family: var(--font-mono);
  font-size: 11px;
  cursor: pointer;
}

.loop-row:hover {
  background: rgba(56, 189, 248, 0.04);
}

.loop-row.state-error { background: rgba(239, 68, 68, 0.05); }
.loop-row.state-paused { background: rgba(251, 146, 60, 0.05); }

.loop-state {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.loop-state.state-fetching { color: var(--accent-sky); }
.loop-state.state-idle { color: var(--accent-emerald); }
.loop-state.state-primed { color: var(--accent-sky); }
.loop-state.state-paused { color: var(--accent-orange); }
.loop-state.state-error { color: var(--accent-red); }

.loop-cell {
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.loop-result { text-align: right; }
.loop-new { color: var(--accent-emerald); font-weight: 600; }
.loop-muted { color: var(--text-muted); }
.loop-paused { color: var(--accent-orange); }

/* The last cycles as bars. Height is how many listings were new, colour is how
   the cycle ended, so a run of failures reads before any number does. */
.spark {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: 18px;
  overflow: hidden;
}

.spark-bar {
  flex: 1 1 auto;
  min-width: 2px;
  max-width: 6px;
  border-radius: 1px 1px 0 0;
  background: var(--text-muted);
}

.spark-bar.bar-ok { background: var(--accent-emerald); }
.spark-bar.bar-primed { background: var(--accent-sky); }
.spark-bar.bar-rate_limited { background: var(--accent-amber); }
.spark-bar.bar-error { background: var(--accent-red); }

.spark-empty {
  font-size: 10px;
  align-self: center;
  white-space: nowrap;
}

.loop-caret-end { text-align: right; }

.loop-detail {
  padding: 4px 12px 12px 30px;
  border-top: 1px solid var(--border-subtle);
  background: var(--bg-primary);
  overflow-x: auto;
}

/* ── Zone C — every cycle, newest first ───────────────────────────────────── */
.activity-feed {
  border: 1px solid var(--border-subtle);
  border-radius: 4px;
  overflow: hidden;
}

.activity-row {
  display: grid;
  grid-template-columns: 68px minmax(90px, 1fr) 96px 84px 42px 52px minmax(0, 1.4fr);
  align-items: center;
  gap: 10px;
  padding: 5px 12px;
  font-size: 11px;
}

.activity-row + .activity-row {
  border-top: 1px solid var(--border-subtle);
}

.activity-row.row-error,
.activity-row.row-rate_limited {
  background: rgba(239, 68, 68, 0.05);
}

/* A row prints the clock time only, so the day is marked once where it turns. */
.activity-day {
  padding: 5px 12px;
  background: var(--bg-tertiary);
  border-top: 1px solid var(--border-subtle);
  font-size: 10px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.activity-feed > .activity-day:first-child {
  border-top: none;
}

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

.activity-target {
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.activity-new { text-align: right; }

.activity-duration,
.activity-error {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cell-error {
  color: var(--accent-red);
  font-size: 10px;
}

.activity-more {
  display: flex;
  justify-content: center;
  padding: 12px 0 4px;
  font-size: 11px;
}

/* A primed cycle is a market's first look, neither a success nor a fault. */
.pill-primed {
  background: rgba(56, 189, 248, 0.15);
  color: var(--accent-sky);
}

.scheduler-row.row-primed td {
  background: rgba(56, 189, 248, 0.03);
}

/* ── Status bar WS indicator (mobile only — desktop has it in the sidebar) ───── */
.status-ws {
  display: none;
}

/* ── Responsive ──────────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  .sidebar {
    display: none;
  }

  .mobile-nav {
    display: flex;
  }

  .main-content {
    margin-left: 0;
    padding-bottom: calc(var(--mobile-nav-height) + 28px + env(safe-area-inset-bottom, 0));
  }

  .listings-grid {
    grid-template-columns: 1fr;
  }

  .modal {
    min-width: unset;
  }

  .form-row {
    grid-template-columns: 1fr;
  }

  .status-bar {
    left: 0;
    bottom: calc(var(--mobile-nav-height) + env(safe-area-inset-bottom, 0));
  }

  .status-ws {
    display: flex;
  }

  .status-bar-hint {
    display: none;
  }

  .scheduler-modal {
    max-width: 100%;
    margin: 0 12px;
  }

  .scheduler-toolbar,
  .scheduler-body {
    padding-left: 14px;
    padding-right: 14px;
  }

  /* A narrow screen cannot hold seven columns, so the cells flow instead and
     the sparkline takes a line of its own. A column header cannot survive that
     move, so it goes. */
  .loop-head-row {
    display: none;
  }

  .loop-row,
  .activity-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  .loop-row {
    padding-left: 16px;
  }

  .loop-detail {
    padding-left: 16px;
  }

  .spark {
    flex: 1 1 100%;
  }

  .activity-target,
  .activity-error {
    flex: 1 1 100%;
  }

  .loop-caret-end {
    display: none;
  }

  /* Watchlist table → stacked cards */
  .watchlist-table,
  .watchlist-table tbody {
    display: block;
  }

  .watchlist-table thead {
    display: none;
  }

  .watchlist-table tr {
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
      "target   target   toggle"
      "markets  price    price"
      "polled   found    found"
      "telegram telegram telegram"
      "actions  actions  actions";
    align-items: center;
    gap: 10px 12px;
    padding: 14px;
    border-bottom: 1px solid var(--border-subtle);
  }

  .watchlist-table tr:last-child {
    border-bottom: none;
  }

  .watchlist-table td {
    display: block;
    padding: 0;
    border-bottom: none;
  }

  .watchlist-table td.col-target  { grid-area: target; }
  .watchlist-table td.col-markets { grid-area: markets; }
  .watchlist-table td.col-price   { grid-area: price; }
  .watchlist-table td.col-polled  { grid-area: polled; }
  .watchlist-table td.col-found   { grid-area: found; }
  .watchlist-table td.col-toggle  { grid-area: toggle; justify-self: end; }

  /* The stacked card hides the header row, so this toggle needs its label
     beside it. The Active toggle keeps its place next to the target name,
     where it is the only control and needs no label. */
  .watchlist-table td.col-telegram {
    grid-area: telegram;
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .watchlist-table td.col-actions { grid-area: actions; }

  .watchlist-table td.col-polled::before,
  .watchlist-table td.col-found::before,
  .watchlist-table td.col-telegram::before {
    content: attr(data-label) " ";
    font-size: 9px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
  }
}

/* ── Rule builder ────────────────────────────────────────────────────────────── */
.rule-builder {
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  padding: 12px;
  background: var(--bg-primary);
}

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

.rule-match-toggle {
  flex: 0 0 auto;
}

.rule-match-toggle .mode-btn {
  padding: 4px 10px;
  font-size: 10px;
}

.rule-empty {
  font-size: 11px;
  color: var(--text-muted);
  padding: 10px 2px;
}

.rule-join {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  color: var(--text-muted);
  padding: 5px 0 5px 10px;
}

.rule-row {
  border: 1px solid var(--border-muted);
  border-radius: 4px;
  padding: 8px;
  background: var(--bg-tertiary);
}

.rule-row-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 7px;
}

.rule-select {
  width: auto;
  flex: 1 1 auto;
  min-width: 0;
  padding: 5px 7px;
  font-size: 11px;
}

.rule-word-btn {
  flex: 0 0 auto;
  padding: 5px 8px;
  border-radius: 4px;
  border: 1px solid var(--border-muted);
  background: transparent;
  color: var(--accent-sky);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.05em;
  cursor: pointer;
  white-space: nowrap;
  transition: all var(--transition);
}

.rule-word-btn.loose {
  color: var(--accent-amber);
}

.rule-word-btn:hover {
  border-color: currentColor;
}

.rule-remove {
  flex: 0 0 auto;
  padding: 4px 7px;
  border-radius: 4px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  font-size: 11px;
  cursor: pointer;
  transition: all var(--transition);
}

.rule-remove:hover {
  border-color: rgba(239, 68, 68, 0.3);
  color: var(--accent-red);
}

.rule-terms {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  min-height: 30px;
  padding: 4px 6px;
  border: 1px solid var(--border-muted);
  border-radius: 4px;
  background: var(--bg-primary);
  cursor: text;
}

.rule-terms:focus-within {
  border-color: var(--accent-emerald);
}

.term-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 6px;
  border-radius: 3px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-muted);
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 11px;
}

.term-chip-x {
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 9px;
  line-height: 1;
  padding: 0;
  cursor: pointer;
}

.term-chip-x:hover {
  color: var(--accent-red);
}

.term-input {
  flex: 1 1 90px;
  min-width: 90px;
  border: none;
  background: transparent;
  outline: none;
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 3px 2px;
}

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

.rule-add {
  margin-top: 8px;
}

.rule-summary {
  margin-top: 10px;
  padding: 8px 10px;
  border-left: 2px solid var(--accent-emerald);
  background: var(--bg-tertiary);
  border-radius: 0 4px 4px 0;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.6;
  color: var(--text-secondary);
  word-break: break-word;
}

.rule-note {
  margin-top: 7px;
  font-size: 10px;
  line-height: 1.5;
  color: var(--text-muted);
}

.rule-note.warn {
  color: var(--accent-amber);
}

/* ── Numeric rule row ────────────────────────────────────────────────────────── */
.rule-num {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

.rule-num-label {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  padding: 5px 2px;
}

.rule-num-input {
  width: 92px;
  flex: 0 0 auto;
  padding: 5px 7px;
  font-size: 11px;
  font-family: var(--font-mono);
}

.rule-num-unit {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
}

.rule-num-sep {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
}

.rule-num-hint {
  flex: 1 1 100%;
  font-size: 10px;
  color: var(--text-muted);
}

/* ── Variants ────────────────────────────────────────────────────────────────── */
.variant-section {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed var(--border-muted);
}

.variant-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.variant-title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.variant-sub {
  font-size: 10px;
  color: var(--text-muted);
}

.variant-card {
  border: 1px solid var(--border-muted);
  border-left: 2px solid var(--accent-sky);
  border-radius: 4px;
  padding: 9px;
  background: var(--bg-secondary);
}

.variant-card-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}

.variant-name {
  flex: 1 1 auto;
  min-width: 0;
  padding: 5px 8px;
  font-size: 11px;
  font-family: var(--font-mono);
}

.variant-card .rule-row {
  background: var(--bg-primary);
}

.rule-summary-variants {
  margin-top: 4px;
}

.rule-summary-and {
  color: var(--text-muted);
  margin: 4px 0 2px;
}

.rule-summary-variant {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 1px 0 1px 10px;
}

.rule-summary-name {
  color: var(--accent-sky);
}

.rule-summary-variant .warn {
  color: var(--accent-amber);
}

.mode-btn:disabled {
  opacity: 0.55;
  cursor: default;
}

/* ── Rule tester ─────────────────────────────────────────────────────────────── */
.rule-test {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 10px;
}

.rule-test-tally {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
}

.rule-test-tally .pass { color: var(--accent-emerald); }
.rule-test-tally .fail { color: var(--accent-red); }
.rule-test-tally .unknown { color: var(--accent-amber); }

.rule-test-list {
  margin-top: 8px;
  max-height: 190px;
  overflow-y: auto;
  border: 1px solid var(--border-subtle);
  border-radius: 4px;
}

.rule-test-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border-bottom: 1px solid var(--border-subtle);
  font-size: 11px;
  color: var(--text-secondary);
}

.rule-test-item:last-child {
  border-bottom: none;
}

.rule-test-item.fail {
  color: var(--text-muted);
}

.rule-test-mark {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 10px;
}

.rule-test-item.pass .rule-test-mark    { color: var(--accent-emerald); }
.rule-test-item.fail .rule-test-mark    { color: var(--accent-red); }
.rule-test-item.unknown .rule-test-mark { color: var(--accent-amber); }

.rule-test-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rule-test-tag {
  flex: 0 0 auto;
  padding: 1px 5px;
  border-radius: 3px;
  border: 1px solid var(--border-muted);
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-muted);
}

.rule-test-tag.variant {
  color: var(--accent-sky);
  border-color: rgba(56, 189, 248, 0.35);
}

.rule-test-tag.qty {
  color: var(--accent-amber);
  border-color: rgba(245, 158, 11, 0.35);
}

/* ── Preset word lists ───────────────────────────────────────────────────────── */
.rule-preset {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
}

.rule-preset .rule-select {
  flex: 1 1 auto;
}

.rule-preset-terms {
  margin-top: 6px;
  padding: 7px 9px;
  border-radius: 4px;
  background: var(--bg-primary);
  border: 1px solid var(--border-muted);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.7;
  color: var(--text-secondary);
  word-break: break-word;
}

.rule-bound-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  font-size: 11px;
  color: var(--text-secondary);
  cursor: pointer;
}

.card-unit-price {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--accent-amber);
}

.variant-badge {
  display: inline-block;
  max-width: 100%;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 0.04em;
  font-family: var(--font-mono);
  background: rgba(56, 189, 248, 0.08);
  color: var(--accent-sky);
  border: 1px solid rgba(56, 189, 248, 0.3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A listing the seller holds for another buyer. Amber, not red: the listing is
   still live and the reservation can fall through, so it is a warning about
   the odds rather than an end state.                                          */

.reserved-badge {
  display: inline-block;
  max-width: 100%;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 0.04em;
  font-family: var(--font-mono);
  background: rgba(245, 158, 11, 0.1);
  color: var(--accent-amber);
  border: 1px solid rgba(245, 158, 11, 0.35);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Market picker ────────────────────────────────────────────────────────────
   Which marketplaces one target searches. A chip is a checkbox: the whole thing
   is the hit area, and the ticked state has to read at a glance, because it is
   the difference between a product being watched somewhere and nowhere.        */

.market-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.market-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 13px;
  border: 1px solid var(--border-muted);
  border-radius: 6px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 12px;
  cursor: pointer;
  user-select: none;
  transition: border-color .12s, color .12s, background .12s;
}

.market-chip:hover {
  border-color: var(--accent-emerald-dim);
}

.market-chip:focus-within {
  outline: 2px solid var(--accent-sky);
  outline-offset: 2px;
}

.market-chip.on {
  border-color: var(--accent-emerald);
  background: rgba(16, 185, 129, .09);
  color: var(--text-primary);
}

.market-chip input {
  margin: 0;
  cursor: pointer;
  accent-color: var(--accent-emerald);
}

/* ── Per-market panel ─────────────────────────────────────────────────────────
   Collapsed by default and summarised on its header, so a target on several
   markets stays readable. The tags say what this market does differently — the
   whole reason the panel exists.                                              */

.market-panel {
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  margin-bottom: 10px;
  overflow: hidden;
}

.market-panel-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  text-align: left;
  cursor: pointer;
}

.market-panel-head:hover {
  background: var(--bg-secondary);
}

.market-panel-head:focus-visible {
  outline: 2px solid var(--accent-sky);
  outline-offset: -2px;
}

.market-panel-caret {
  color: var(--text-muted);
  font-size: 10px;
  width: 10px;
}

.market-panel-name {
  font-weight: 600;
}

.market-panel-tag {
  padding: 1px 6px;
  border-radius: 3px;
  background: var(--bg-primary);
  border: 1px solid var(--border-muted);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .04em;
}

.market-panel-body {
  padding: 13px 12px 4px;
  border-top: 1px solid var(--border-subtle);
}

/* A market's extra rules sit inside an already-boxed panel, so the builder
   drops its own frame rather than drawing a second one around the first. */
.market-panel-body .rule-builder {
  border: 0;
  padding: 0;
  background: none;
}

/* ── Telegram layout preview ───────────────────────────────────────────────── */
/* The preview draws the alert layout the way Telegram draws it.
   `public/js/telegram-html.js` keeps Telegram's own tags and prints every other
   one as text, so this set is all that needs a style. */
.tg-preview {
  white-space: pre-wrap;
  word-break: break-word;
  background: var(--bg-primary);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  padding: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--text-primary);
}

/* A link keeps its look and lost its address in the translation, so it is not
   a thing to click here. */
.tg-preview a.tg-link {
  color: var(--accent-sky);
  text-decoration: none;
  cursor: default;
}

.tg-preview code,
.tg-preview pre {
  font-family: var(--font-mono);
  background: var(--bg-tertiary);
  border-radius: 3px;
  padding: 0 3px;
}

.tg-preview pre {
  display: block;
  margin: 4px 0;
  padding: 6px 8px;
  white-space: pre-wrap;
}

.tg-preview blockquote {
  margin: 4px 0;
  padding-left: 8px;
  border-left: 2px solid var(--border-muted);
  color: var(--text-secondary);
}

/* Telegram covers a spoiler until the reader taps it. The preview draws the
   same cover, and lifts it on hover so the words stay checkable. */
.tg-preview .tg-spoiler {
  background: var(--border-muted);
  color: transparent;
  border-radius: 3px;
  transition: color var(--transition), background var(--transition);
}

.tg-preview .tg-spoiler:hover {
  background: transparent;
  color: inherit;
}
