.dashboard-section { padding: 76px 0; display: flex; flex-direction: column; gap: 56px; }
.dashboard-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; }
.dashboard-header-chips { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dashboard-tier-chip { display: inline-flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em; color: var(--ink-soft); border: 1px solid var(--line); padding: 8px 14px; }
.dashboard-tier-chip-agent { color: var(--accent-dim); border-color: var(--accent-faint); }
.dashboard-tier-chip-agent .live-dot { background: var(--accent) !important; }

.checkout-banner {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 24px; padding: 12px 16px;
  border: 1px solid var(--accent-faint);
  background: var(--accent-glow);
  font-family: var(--sans); font-size: 13px; color: var(--ink);
}
.checkout-banner-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%; flex-shrink: 0;
  background: var(--accent); color: var(--bg); font-size: 11px;
}
.checkout-banner-close {
  margin-left: auto; background: none; border: none; color: var(--ink-faint);
  font-size: 17px; line-height: 1; padding: 0 4px; cursor: pointer;
}
.checkout-banner-close:hover { color: var(--ink); }

/* The form panel is now the same moving dark-console surface as the
   scan console below it and the homepage scanner - "the grey box"
   reads as flat/static no longer. Same background/sweep/corner motif
   as .scan-console, just its own instance so each animates on its own
   clock (feels less mechanically synced). */
/* Setup surface - deliberately a shade darker/quieter than the results
   console next to it ("composing" vs "live") rather than an identical
   twin panel. See .scan-console below for the brighter/mirrored other
   half of that pairing. */
.scan-form {
  display: flex; flex-direction: column; gap: 20px; max-width: 640px;
  position: relative; overflow: hidden;
  background-color: oklch(0.17 0.01 258);
  background-image:
    radial-gradient(800px 620px at 12% -20%, oklch(0.86 0.004 255 / 0.11), transparent 58%),
    radial-gradient(700px 620px at 108% 120%, oklch(0.62 0.19 254 / 0.22), transparent 58%),
    linear-gradient(155deg, oklch(0.22 0.012 258) 0%, oklch(0.15 0.01 258) 55%, oklch(0.19 0.012 254) 100%);
  background-repeat: no-repeat;
  background-size: 220% 220%, 220% 220%, 100% 100%;
  animation: panelDrift 13.3s ease-in-out infinite alternate, glowPulse 4.8s ease-in-out infinite;
  border: 1px solid var(--console-line);
  padding: 30px 26px;
  box-shadow: 0 30px 70px -28px oklch(0.62 0.19 254 / 0.22), 0 24px 50px -32px oklch(0 0 0 / 0.4);
}
.scan-form-row { display: flex; flex-direction: column; gap: 8px; }
.scan-form-label { font-family: var(--sans); font-size: 10px; letter-spacing: 0.1em; color: var(--silver-faint); }
.scan-form-chips { display: flex; gap: 8px; flex-wrap: wrap; }
.scan-form-chip { font-family: var(--sans); font-size: 11px; letter-spacing: 0.05em; color: var(--silver-dim); border: 1px solid var(--console-line); padding: 9px 14px; cursor: pointer; background: none; }
.scan-form-chip:hover { border-color: var(--silver-dim); }
.scan-form-chip.active { color: var(--console); background: var(--silver); border-color: var(--silver); }
.scan-form-chip-disabled,
.scan-form-chip-disabled:hover {
  cursor: default;
  color: var(--silver-faint);
  border-color: var(--console-line);
  border-style: dashed;
  opacity: 0.7;
}
/* Free/mid's one locked platform (see app/routes/me.py's one-time
   locked_platform) - reads as selected like any other active chip, but
   can't be un-toggled since there is nothing else to pick this period. */
.scan-form-chip-locked { pointer-events: none; }

/* A feature-gated chip (e.g. Manual's WORD LIST source, PREMIUM-only -
   see dashboard.js's loadAccount) - dimmed like a disabled picker card
   (.board-picker-card-disabled), but deliberately still clickable rather
   than pointer-events:none, since clicking it is what surfaces the
   "upgrade to unlock" hint rather than just doing nothing. */
.scan-form-chip-feature-locked { opacity: 0.45; }

/* AGENT is the premium mode - it gets its own accent treatment instead
   of the plain dark MANUAL/active fill, so it reads as distinct even
   before you switch to it. */
.scan-form-chip[data-setup="agent"] { color: var(--accent-dim); border-color: var(--accent-faint); }
.scan-form-chip[data-setup="agent"]:hover { border-color: var(--accent); }
.scan-form-chip[data-setup="agent"].active {
  color: oklch(0.98 0.005 254); border-color: var(--accent);
  background: linear-gradient(135deg, var(--accent-dim), var(--accent));
  background-size: 220% 220%; animation: agentChipShimmer 4s ease-in-out infinite;
}
@keyframes agentChipShimmer {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) .scan-form-chip[data-setup="agent"].active { animation: none; }
}
.scan-form-inline { display: flex; gap: 12px; }
.scan-form-input { font-family: var(--sans); font-size: 13px; color: var(--silver); background: oklch(0.16 0.01 258); border: 1px solid var(--console-line); padding: 10px 12px; width: 100%; }
.scan-form-input::placeholder { color: var(--silver-faint); }
/* A pattern mode (e.g. "2d") locks the length inputs to its own fixed
   length rather than leaving them as an editable range - visually
   distinct from a normal editable field so it reads as "set by your
   pattern choice," not "disabled/broken." */
.scan-form-input:disabled { color: var(--silver-faint); background: oklch(0.13 0.008 258); cursor: not-allowed; }
.scan-form-submit { font-family: var(--sans); font-size: 13px; letter-spacing: 0.06em; background: var(--accent); color: oklch(0.99 0.003 254); padding: 13px; border: none; cursor: pointer; }
.scan-form-submit:hover:not(:disabled) { background: var(--accent-dim); }
.scan-form-submit:disabled { opacity: 0.5; cursor: default; }
.scan-form-error { font-family: var(--sans); font-size: 12.5px; color: oklch(0.68 0.16 25); display: none; }
.scan-form-error.visible { display: block; }
.scan-form-hint { font-family: var(--sans); font-size: 11.5px; color: var(--silver-faint); line-height: 1.5; }

/* Import-your-own-list panel (Dictionary board) - deliberately plain
   next to the chip rows above it: one drop zone, one textarea fallback,
   a live count, and a single commit action. Kept uncluttered on
   purpose rather than mirroring a dense power-user wordlist panel. */
.dictionary-import-optional { font-weight: normal; text-transform: none; letter-spacing: normal; color: var(--silver-faint); opacity: 0.8; }
.dictionary-import-panel { display: flex; flex-direction: column; gap: 10px; border: 1px solid var(--console-line); padding: 14px; background: oklch(0.15 0.008 258); }
.dictionary-import-dropzone {
  border: 1px dashed var(--console-line); padding: 18px 14px; text-align: center;
  transition: border-color 0.15s, background-color 0.15s;
}
.dictionary-import-dropzone.dragover { border-color: var(--accent); background: var(--accent-glow); }
.dictionary-import-dropzone-text { font-family: var(--sans); font-size: 12px; color: var(--silver-faint); margin: 0; }
.dictionary-import-browse { background: none; border: none; padding: 0; color: var(--accent); text-decoration: underline; cursor: pointer; font: inherit; }
.dictionary-import-or { font-family: var(--sans); font-size: 10.5px; letter-spacing: 0.06em; color: var(--silver-faint); text-align: center; margin: 0; opacity: 0.75; }
.dictionary-import-textarea {
  font-family: var(--mono); font-size: 12px; color: var(--silver); background: oklch(0.16 0.01 258);
  border: 1px solid var(--console-line); padding: 10px 12px; width: 100%; min-height: 84px; resize: vertical;
}
.dictionary-import-textarea::placeholder { color: var(--silver-faint); }
.dictionary-import-status { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.dictionary-import-count { font-family: var(--sans); font-size: 11px; color: var(--silver-faint); }
.dictionary-import-actions { display: flex; gap: 8px; }
.dictionary-import-use, .dictionary-import-clear {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.05em; padding: 8px 14px; cursor: pointer; border: 1px solid var(--console-line); background: none; color: var(--silver-dim);
}
.dictionary-import-use { background: var(--accent); color: oklch(0.99 0.003 254); border-color: var(--accent); }
.dictionary-import-use:disabled { opacity: 0.4; cursor: default; }
.dictionary-import-clear:hover { border-color: var(--silver-dim); }
.dictionary-import-error { font-family: var(--sans); font-size: 12px; color: oklch(0.68 0.16 25); margin: 0; display: none; }
.dictionary-import-error.visible { display: block; }
.dictionary-import-active { font-family: var(--sans); font-size: 12px; color: var(--accent); margin: 0; display: none; }
.dictionary-import-active.visible { display: block; }

.scan-history { display: flex; flex-direction: column; gap: 16px; }
.scan-item {
  display: flex; flex-direction: column; gap: 14px; padding: 20px 24px;
  position: relative; overflow: hidden;
  background-color: oklch(0.20 0.01 258);
  background-image:
    radial-gradient(650px 500px at 12% -20%, oklch(0.86 0.004 255 / 0.13), transparent 58%),
    radial-gradient(550px 480px at 108% 120%, oklch(0.62 0.19 254 / 0.22), transparent 58%),
    linear-gradient(155deg, oklch(0.26 0.012 258) 0%, oklch(0.19 0.01 258) 55%, oklch(0.23 0.012 254) 100%);
  background-repeat: no-repeat;
  background-size: 220% 220%, 220% 220%, 100% 100%;
  animation: panelDrift 16s ease-in-out infinite alternate, glowPulse 5.3s ease-in-out infinite;
  border: 1px solid var(--console-line);
  box-shadow: 0 24px 50px -30px oklch(0.62 0.19 254 / 0.2);
}
.scan-item-head { display: flex; align-items: center; justify-content: space-between; }
.scan-item-meta { font-family: var(--mono); font-size: 11px; color: var(--silver-faint); letter-spacing: 0.04em; }
.scan-item-status { display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; padding: 5px 10px; border: 1px solid var(--console-line); }
.scan-item-status-queued, .scan-item-status-running { color: var(--silver-dim); }
.scan-item-status-completed { color: var(--accent); border-color: var(--accent-faint); }
.scan-item-status-failed { color: var(--silver-faint); }
.scan-item-results { display: flex; flex-direction: column; }
.scan-result-row { display: flex; align-items: baseline; justify-content: space-between; font-family: var(--mono); font-size: 12px; padding: 7px 0; border-bottom: 1px solid var(--console-line); }
.scan-result-row:last-child { border-bottom: none; }
.scan-result-name { color: var(--accent); }
.scan-result-link { font-family: var(--mono); font-size: 10px; letter-spacing: 0.06em; color: var(--silver); text-decoration: underline; text-underline-offset: 2px; }
.scan-empty { font-family: var(--sans); font-size: 13px; color: var(--silver-faint); }
.scan-loading { font-family: var(--mono); font-size: 11px; color: var(--silver-faint); letter-spacing: 0.06em; }

/* Live scan console - the dashboard's active-scan-only, cipher-reveal
   view. Reuses the same dark console-panel treatment as .scan-item /
   .tier-card-pilot (radial glow + faint scanline texture over a navy
   gradient) rather than inventing a second dark surface language. */
/* Results surface - brighter than .scan-form, with its glow anchored
   from the opposite corners (mirrored, not identical) and a bright
   accent edge along the top marking it as the "live" side of the pair. */
.scan-console[hidden] { display: none; }
.scan-console {
  display: flex; flex-direction: column; gap: 0; max-width: 640px; min-height: 560px;
  position: relative; overflow: hidden;
  background-color: oklch(0.23 0.011 258);
  background-image:
    radial-gradient(800px 620px at 88% -20%, oklch(0.86 0.004 255 / 0.17), transparent 58%),
    radial-gradient(700px 620px at -8% 120%, oklch(0.62 0.19 254 / 0.32), transparent 58%),
    linear-gradient(205deg, oklch(0.29 0.013 258) 0%, oklch(0.22 0.011 258) 55%, oklch(0.26 0.013 254) 100%);
  background-repeat: no-repeat;
  background-size: 220% 220%, 220% 220%, 100% 100%;
  animation: panelDrift 12s ease-in-out infinite alternate, glowPulse 4.5s ease-in-out infinite;
  border: 1px solid var(--console-line); box-shadow: 0 30px 70px -28px oklch(0.62 0.19 254 / 0.4), 0 30px 60px -30px oklch(0 0 0 / 0.55);
}
.scan-console::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; z-index: 2;
  background: linear-gradient(90deg, transparent, var(--accent) 20%, var(--accent) 80%, transparent);
  box-shadow: 0 0 12px 1px oklch(0.62 0.19 254 / 0.6);
}
.scan-console-head { display: flex; align-items: center; justify-content: space-between; padding: 18px 22px; border-bottom: 1px solid var(--console-line); }
.scan-console-meta { font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; color: var(--silver-faint); }
.scan-console-status { font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; padding: 5px 10px; border: 1px solid var(--console-line); color: var(--silver-dim); }
.scan-console-status-completed { color: var(--accent); border-color: var(--accent-faint); }
.scan-console-status-failed { color: var(--silver-faint); }
.scan-console-status-cancelled { color: var(--silver-faint); }

/* Stop/pause a scan mid-run - POST /scans/{id}/stop (or /dictionary/{id}/
   stop for a dictionary job's chunks). Lives in the setup form directly
   below the START/submit button ("stop what I just started" reads as
   a setup-panel action, not a results-panel one) rather than in the
   results console's head - full-width to match the submit button
   above it, but with a danger/stop treatment (red outline, no fill)
   so the two are never confused for equally-safe actions. Hidden once
   the scan reaches any terminal status (completed/failed/cancelled) -
   see js/scan-player.js's updateStopButton. */
.scan-console-stop-btn {
  font-family: var(--sans); font-size: 13px; letter-spacing: 0.06em; color: oklch(0.68 0.16 25);
  background: none; border: 1px solid oklch(0.68 0.16 25 / 0.55); padding: 13px; cursor: pointer;
  width: 100%; margin-top: 14px;
}
.scan-console-stop-btn:hover:not(:disabled) { border-color: oklch(0.68 0.16 25); background: oklch(0.68 0.16 25 / 0.12); }
.scan-console-stop-btn:disabled { opacity: 0.5; cursor: default; }

.scan-console-feed { display: flex; flex-direction: column; max-height: 260px; overflow-y: auto; }
.scan-console-row { display: flex; align-items: center; justify-content: space-between; padding: 13px 22px; border-bottom: 1px solid var(--console-line); }
.scan-console-row-name { font-family: var(--mono); font-size: 13px; color: var(--silver-dim); letter-spacing: 0.02em; }
.scan-console-row-name-available { color: var(--accent); }
.scan-console-row-status { font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; color: var(--silver-faint); }
.scan-console-link { font-family: var(--mono); font-size: 10px; letter-spacing: 0.06em; color: var(--silver); text-decoration: underline; text-underline-offset: 2px; }
.scan-console-actions, .scan-result-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }

/* Self-reported "I claimed this" (POST /claims) - shared by the live
   console and saved-scans history (see js/scan-history.js). */
.claim-btn { font-family: var(--mono); font-size: 10px; letter-spacing: 0.06em; color: var(--silver-dim); background: none; border: 1px solid var(--console-line); padding: 4px 9px; cursor: pointer; }
.claim-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.claim-btn:disabled { cursor: default; }
.claim-btn-done { color: var(--accent); border-color: var(--accent-faint); }

@keyframes dropIn {
  0% { opacity: 0; transform: translateY(-8px); }
  100% { opacity: 1; transform: translateY(0); }
}
.scan-console-row-in { animation: dropIn 0.3s ease-out; }

/* The single persistent "decrypting" slot - scrambles through random
   characters while waiting, then settles on the real platform/username
   once that candidate resolves (see js/dashboard.js's reveal player)
   before the row drops into the feed above and the slot resets. */
.scan-console-progress { display: flex; align-items: center; justify-content: space-between; padding: 16px 22px; }
.scan-console-slot { font-family: var(--mono); font-size: 13px; letter-spacing: 0.1em; color: var(--silver-dim); position: relative; }
.scan-console-slot::after { content: ""; display: inline-block; width: 7px; height: 14px; margin-left: 6px; background: var(--accent-dim); vertical-align: -2px; animation: dotPulse 0.9s step-end infinite; }
@keyframes slotLockIn {
  0% { opacity: 0.4; transform: scale(0.97); }
  100% { opacity: 1; transform: scale(1); }
}
.scan-console-slot-resolved { color: var(--silver); animation: slotLockIn 0.15s ease-out; }
.scan-console-slot-resolved::after { animation: none; opacity: 0; }
.scan-console-slot-available { color: var(--accent); }
.scan-console-count, .scan-console-summary { font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; color: var(--silver-faint); }
.scan-console-summary { width: 100%; }

/* Board-picker cards - richer than a flat bordered panel: a subtle top
   accent stripe per mode, an icon, and a hover lift so the four choices
   feel like distinct destinations rather than four identical rectangles. */
.board-picker-card { position: relative; overflow: hidden; transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease; }
.board-picker-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--accent); opacity: 0; transition: opacity 0.18s ease;
}
.board-picker-card:hover { transform: translateY(-4px); box-shadow: 0 30px 60px -30px oklch(0.3 0 0 / 0.22); }
.board-picker-card:hover::before { opacity: 1; }
.board-picker-card-icon {
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--accent-glow); color: var(--accent-dim);
  /* A gentle at-rest breathing glow (not just on hover) - four cards
     that visibly do something, even idle, read as a live product
     rather than four flat static tiles. glowPulseLight is the same
     "brightness breathes" motif every dark console surface already
     uses, tuned down for a light panel background. */
  animation: glowPulseLight 4.5s ease-in-out infinite;
}
.board-picker-card-agent::before { background: var(--accent); opacity: 0.7; }
.board-picker-card-agent .board-picker-card-icon { background: oklch(0.62 0.19 254 / 0.22); color: var(--accent); animation: glowPulse 4.5s ease-in-out infinite; }
.board-picker-card-sniper::before { background: oklch(0.72 0.16 155); }
.board-picker-card-sniper .board-picker-card-icon { background: oklch(0.72 0.16 155 / 0.16); color: oklch(0.5 0.15 155); }
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) .board-picker-card-icon { animation: none !important; }
}
