:root {
  --bg: #f5f7fb;
  --ink: #172033;
  --muted: #687386;
  --muted-2: #9aa7b9;
  --line: #e2e8f2;
  --line-soft: #eef2f8;
  --panel: #ffffff;
  --blue: #2563eb;
  --blue-soft: #eef4ff;
  --blue-ink: #1947a3;
  --green: #0f8f68;
  --green-soft: #eaf8f1;
  --red: #b42318;
  --red-soft: #fff0ed;
  --amber: #92400e;
  --amber-soft: #fef3e0;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(23, 32, 51, 0.04), 0 8px 24px -12px rgba(23, 32, 51, 0.12);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-width: 320px;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, "Segoe UI", Inter, Arial, Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
p {
  margin: 0;
}

/* ---------- top loading bar ---------- */

.top-loader {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0;
  background: linear-gradient(90deg, var(--blue), #7c3aed);
  z-index: 100;
  opacity: 0;
  transition: width 0.4s ease, opacity 0.2s ease;
}

.top-loader.active {
  opacity: 1;
  width: 70%;
}

/* ---------- header ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 18px 32px;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

.eyebrow {
  margin: 0 0 2px;
  color: var(--blue);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

h1 {
  font-size: 22px;
  line-height: 1.15;
  font-weight: 800;
}

h2 {
  font-size: 17px;
  font-weight: 700;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 38px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #ffffff;
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.icon-btn:hover {
  background: #f1f5fb;
  border-color: #c7d2e3;
}

.icon-btn .icon {
  width: 16px;
  height: 16px;
}

.mode-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
}

.mode-pill .icon {
  width: 8px;
  height: 8px;
}

.mode-pill.live {
  background: var(--green-soft);
  color: var(--green);
}

.mode-pill.live .icon {
  fill: var(--green);
}

.mode-pill.readonly {
  background: var(--amber-soft);
  color: var(--amber);
}

.mode-pill.readonly .icon {
  fill: var(--amber);
}

/* ---------- generic form controls ---------- */

input,
select,
button {
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
  font-size: 14px;
}

input,
select {
  width: 100%;
  padding: 0 12px;
  background: #ffffff;
  color: var(--ink);
}

input:focus,
select:focus,
button:focus-visible,
.icon-btn:focus-visible,
a:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 1px;
}

button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-color: var(--blue);
  background: var(--blue);
  color: #ffffff;
  font-weight: 700;
  cursor: pointer;
  padding: 0 16px;
  white-space: nowrap;
  transition: filter 0.15s ease;
}

button:hover {
  filter: brightness(1.06);
}

button:disabled {
  border-color: var(--muted-2);
  background: var(--muted-2);
  cursor: not-allowed;
  filter: none;
}

button .icon {
  width: 15px;
  height: 15px;
}

.secondary-action {
  border-color: var(--ink);
  background: var(--ink);
}

/* Secondary button. Used by "Reset" (a link) and "Expand all models" (a
   button), so it sets its own colours instead of inheriting the solid blue
   of plain buttons or relying on white text. */
.ghost-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #ffffff;
  color: var(--ink);
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.ghost-btn:hover {
  background: #eef2f8;
  border-color: #c7d2e3;
  color: var(--ink);
  filter: none;
}

main {
  width: min(1280px, calc(100% - 32px));
  margin: 22px auto 48px;
}

/* ---------- job status ---------- */

.job-status {
  position: relative;
  overflow: hidden;
  margin-bottom: 16px;
  padding: 14px 18px;
  background: #ffffff;
  border: 1px solid var(--line);
  border-left: 4px solid var(--blue);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.job-status-text {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.job-status span {
  color: var(--muted);
  font-size: 13px;
}

.job-status.running {
  border-left-color: var(--green);
}

.job-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: #eaf8f1;
  overflow: hidden;
}

.job-bar i {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 40%;
  background: var(--green);
  border-radius: 3px;
  animation: job-bar-slide 1.4s ease-in-out infinite;
}

@keyframes job-bar-slide {
  0% {
    left: -40%;
  }
  100% {
    left: 100%;
  }
}

/* When the job reports a percentage, the bar fills instead of sliding. */
.job-bar.determinate i {
  left: 0;
  width: var(--job-pct, 0%);
  animation: none;
  transition: width 0.6s ease;
}

/* ---------- scrape toolbar ---------- */

.scrape-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
  padding: 12px;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.scope-form {
  display: flex;
  gap: 8px;
  margin-left: auto;
  flex-wrap: wrap;
}

.scope-form select {
  width: 150px;
}

.scope-form input {
  width: 220px;
}

/* ---------- KPI cards ---------- */

.stats {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}

.stats article {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 16px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.stats article .icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  padding: 9px;
  border-radius: 10px;
  background: var(--blue-soft);
  color: var(--blue-ink);
}

.stats article:nth-child(2) .icon {
  background: #f1eafe;
  color: #6d28d9;
}

.stats article:nth-child(3) .icon {
  background: var(--amber-soft);
  color: var(--amber);
}

.stats article:nth-child(4) .icon {
  background: var(--green-soft);
  color: var(--green);
}

.stats article:nth-child(5) .icon {
  background: #e6f6fb;
  color: #0e7490;
}

/* Let the text wrap inside a narrow card instead of pushing the row wider. */
.stats article > div {
  min-width: 0;
}

.stats small {
  display: block;
  margin-top: 1px;
  color: var(--muted-2, #8a94a6);
  font-size: 12px;
  white-space: nowrap;
}

.stats strong {
  display: block;
  font-size: 22px;
  font-weight: 800;
  line-height: 1.2;
}

.stats span {
  color: var(--muted);
  font-size: 12.5px;
}

/* ---------- panel ---------- */

.panel {
  margin-top: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  /* No overflow:hidden here: it would create a scroll container that
     confines position:sticky (thead, filter bar) to this box instead of
     the viewport. Panel-heading/table-wrap round their own corners instead. */
}

.table-footer:last-child {
  border-radius: 0 0 var(--radius) var(--radius);
  overflow: hidden;
}

/* table-wrap itself is deliberately never overflow:hidden (with or without
   being the panel's last child, e.g. Recent Checks has no table-footer
   below it): that would confine/break position:sticky on the thead inside
   it, same issue as .panel above. Trade-off accepted: the table's own
   bottom corners stay square instead of following the panel's radius. */

.panel-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
}

.panel-heading p {
  color: var(--muted);
  font-size: 13px;
}

/* ---------- filter bar ---------- */

.filter-bar {
  position: sticky;
  top: var(--topbar-h, 65px);
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  background: #fbfcfe;
  border-bottom: 1px solid var(--line);
}

.filter-bar-compact {
  position: sticky;
  justify-content: flex-end;
}

.filter-bar-compact select {
  width: 190px;
}

.filter-search {
  position: relative;
  flex: 1 1 260px;
  min-width: 220px;
}

.filter-search .icon {
  position: absolute;
  left: 11px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--muted-2);
  pointer-events: none;
}

.filter-search input {
  padding-left: 34px;
}

.filter-bar select {
  width: 160px;
}

.filter-actions {
  display: flex;
  gap: 8px;
  margin-left: auto;
}

/* ---------- multi-select brand dropdown ---------- */

.brand-select {
  position: relative;
}

.brand-select summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 160px;
  min-height: 40px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #ffffff;
  color: var(--ink);
  font-size: 14px;
  cursor: pointer;
  list-style: none;
}

.brand-select summary::-webkit-details-marker {
  display: none;
}

.brand-select summary .icon {
  width: 14px;
  height: 14px;
  color: var(--muted-2);
  transform: rotate(90deg);
  flex-shrink: 0;
}

.brand-select[open] summary .icon {
  transform: rotate(-90deg);
}

.brand-select-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 200px;
  max-height: 260px;
  overflow-y: auto;
  padding: 8px;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow);
}

.brand-select-panel label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 6px;
  font-size: 13.5px;
  cursor: pointer;
}

.brand-select-panel label:hover {
  background: var(--blue-soft);
}

.brand-select-panel input[type="checkbox"] {
  width: auto;
  min-height: 0;
}

/* ---------- active filter chips ---------- */

.filter-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 20px;
  border-bottom: 1px solid var(--line);
  background: #ffffff;
}

.filter-chips-label {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--blue-soft);
  color: var(--blue-ink);
  font-size: 12.5px;
  font-weight: 700;
  text-decoration: none;
  transition: background 0.1s ease;
}

.chip:hover {
  background: #dde9ff;
}

.chip span {
  font-weight: 800;
  opacity: 0.7;
}

/* ---------- table ---------- */

.table-wrap {
  /* No overflow-x:auto here: CSS resolves an unset overflow-y to "auto" as
     soon as overflow-x isn't "visible", which turns this box into its own
     scroll container and confines/breaks position:sticky on the thead
     inside it. The table fits without horizontal scroll above the 820px
     breakpoint; below it, rows become cards (see the responsive block). */
}

table.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13.5px;
}

.data-table thead th {
  position: sticky;
  top: calc(var(--topbar-h, 65px) + var(--filter-h, 56px));
  z-index: 5;
  background: #f8fafc;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  text-align: left;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.filter-bar-compact + .table-wrap .data-table thead th {
  top: calc(var(--topbar-h, 65px) + var(--filter-compact-h, 56px));
}

.sort-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

.sort-link:hover {
  color: var(--ink);
}

.sort-link .icon {
  width: 12px;
  height: 12px;
}

.sort-link.active {
  color: var(--blue-ink);
}

.data-table td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

.data-table tbody tr.row-toggle {
  cursor: pointer;
  transition: background 0.1s ease;
}

.data-table tbody tr.row-toggle:nth-child(4n+1) {
  background: #fbfcfe;
}

.data-table tbody tr.row-toggle:hover {
  background: var(--blue-soft);
}

.data-table tbody tr.row-toggle.expanded {
  background: var(--blue-soft);
}

.expand-cell {
  width: 28px;
  padding-left: 18px !important;
  color: var(--muted-2);
}

.expand-cell .icon {
  width: 15px;
  height: 15px;
  transition: transform 0.15s ease;
}

tr.expanded .expand-cell .icon {
  transform: rotate(90deg);
  color: var(--blue);
}

/* ---------- model accordions (Latest Prices) ---------- */
/* Consecutive rows sharing brand+model (e.g. sorted by Brand or Model) get one
   synthetic group-header row from dashboard.py; the member rows (group-child)
   start hidden and toggle open on header click, instead of repeating the
   brand/model badge on every part row down the page. */

.data-table tbody tr.group-header {
  cursor: pointer;
  background: var(--line-soft);
  border-top: 2px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-weight: 700;
}

.data-table tbody tr.group-header:first-child {
  border-top: none;
}

.data-table tbody tr.group-header:hover,
.data-table tbody tr.group-header.expanded {
  background: var(--blue-soft);
}

.data-table tbody tr.group-header td {
  padding: 12px 16px;
  border-bottom: none;
}

.data-table tbody tr.group-header .group-model {
  margin-left: 4px;
  color: var(--ink);
}

.data-table tbody tr.group-header .group-meta {
  color: var(--muted);
  font-weight: 600;
  font-size: 12.5px;
  text-align: right;
}

.data-table tbody tr.row-toggle.group-child {
  background: #fbfcfe;
}

.data-table tbody tr.row-toggle.group-child:hover,
.data-table tbody tr.row-toggle.group-child.expanded {
  background: var(--blue-soft);
}

/* Inside an expanded model the brand and model are already in the group
   header, so the repeated cells are left empty. They keep their place so
   the columns stay lined up. On phones each part is its own card and still
   shows them. */
@media (min-width: 821px) {
  .data-table tbody tr.row-toggle.group-child td.grouped-cell {
    font-size: 0;
    color: transparent;
  }

  .data-table tbody tr.row-toggle.group-child td.grouped-cell > * {
    visibility: hidden;
  }
}

.detail-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.detail-grid div {
  min-width: 0;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}

.detail-grid div:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.detail-grid span {
  display: block;
  margin-bottom: 4px;
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.detail-grid strong {
  font-size: 14.5px;
  font-weight: 600;
  word-break: break-word;
}

.detail-grid .truncate {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- row details drawer ---------- */

.drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(15, 23, 42, 0.32);
  opacity: 0;
  transition: opacity 0.2s ease;
}

.drawer-backdrop.open {
  opacity: 1;
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 41;
  width: min(420px, 100vw);
  display: flex;
  flex-direction: column;
  background: #ffffff;
  border-left: 1px solid var(--line);
  box-shadow: -12px 0 32px rgba(15, 23, 42, 0.14);
  transform: translateX(100%);
  transition: transform 0.22s ease;
}

.drawer.open {
  transform: translateX(0);
}

.drawer-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 20px 16px;
  border-bottom: 1px solid var(--line);
}

.drawer-header h3 {
  font-size: 17px;
  line-height: 1.4;
}

.drawer-close {
  flex-shrink: 0;
  min-height: 32px;
  min-width: 32px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
  border-radius: 8px;
}

.drawer-close:hover {
  background: var(--line-soft);
  color: var(--ink);
}

.drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border-radius: 999px;
  padding: 4px 10px;
  font-weight: 700;
  font-size: 11.5px;
}

.badge .icon {
  width: 11px;
  height: 11px;
}

.badge-brand {
  background: var(--blue-soft);
  color: var(--blue-ink);
}

.badge-status-ok {
  background: var(--green-soft);
  color: var(--green);
}

.badge-status-error {
  background: var(--red-soft);
  color: var(--red);
}

.price {
  font-weight: 800;
}

/* ---------- multi-source price comparison ---------- */

.price-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.price-line {
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
}

.price-other {
  font-weight: 600;
  font-size: 12.5px;
  color: var(--muted);
}

.src-tag {
  display: inline-block;
  min-width: 52px;
  margin-right: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--blue-soft);
  color: var(--blue-ink);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-align: center;
  line-height: 1.5;
}

.src-tag-alt {
  background: var(--amber-soft);
  color: var(--amber);
}

.compare-flag {
  color: var(--amber);
  font-weight: 700;
}

.detail-subheading {
  margin: 16px 0 8px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.detail-grid small {
  display: block;
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--muted);
}

a {
  color: var(--blue);
  font-weight: 700;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* ---------- empty state ---------- */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 48px 20px;
  color: var(--muted);
  text-align: center;
}

.empty-state .icon {
  width: 40px;
  height: 40px;
  margin-bottom: 6px;
  color: var(--muted-2);
}

.empty-state strong {
  color: var(--ink);
  font-size: 15px;
}

.empty-state span {
  font-size: 13px;
}

/* ---------- skeleton loader ---------- */

.skeleton-row td {
  padding: 14px 16px;
}

.skeleton-block {
  height: 14px;
  border-radius: 4px;
  background: linear-gradient(90deg, #eef1f6 25%, #e4e9f2 37%, #eef1f6 63%);
  background-size: 400% 100%;
  animation: skeleton-shimmer 1.4s ease infinite;
}

@keyframes skeleton-shimmer {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0 50%;
  }
}

/* ---------- footer / pagination ---------- */

.table-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  background: #f8fafc;
  border-top: 1px solid var(--line);
}

.footer-summary {
  color: var(--muted);
  font-size: 13px;
}

.pagination {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.pagination a,
.pagination span,
.pagination strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  min-height: 34px;
  padding: 0 9px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: #ffffff;
  font-size: 13px;
  font-weight: 600;
}

.pagination a:hover {
  border-color: var(--blue);
  color: var(--blue);
  text-decoration: none;
}

.pagination span.disabled {
  color: var(--muted-2);
  border-color: var(--line);
}

.pagination span.ellipsis {
  border: none;
  background: none;
  min-width: auto;
  padding: 0 2px;
  color: var(--muted-2);
}

.pagination strong.current-page {
  background: var(--blue);
  border-color: var(--blue);
  color: #ffffff;
}

/* ---------- responsive ---------- */

/* Five cards share one row on desktop widths; they fold to three, then two. */
@media (max-width: 1040px) {
  .stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .topbar {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 16px;
  }

  .header-actions {
    justify-content: space-between;
  }

  main {
    width: min(100% - 20px, 1280px);
  }

  .scrape-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .scope-form {
    margin-left: 0;
    flex-direction: column;
  }

  .scope-form select,
  .scope-form input {
    width: 100%;
  }

  .filter-bar {
    position: static;
    flex-direction: column;
    align-items: stretch;
  }

  .filter-bar select {
    width: 100%;
  }

  .filter-actions {
    margin-left: 0;
  }

  .data-table thead th {
    position: static;
  }

  .panel-heading {
    flex-direction: column;
    align-items: flex-start;
  }

  .table-footer {
    flex-direction: column;
    align-items: stretch;
  }

  .pagination {
    justify-content: center;
  }

  /* card layout for tables */
  .data-table thead {
    display: none;
  }

  .data-table,
  .data-table tbody,
  .data-table tr {
    display: block;
    width: 100%;
  }

  /* The rule above forces every <tr> to display:block, including rows the
     JS has [hidden] (collapsed group members). Without this override they'd
     render as visible cards despite being collapsed. */
  .data-table tr[hidden] {
    display: none;
  }

  .data-table tbody tr.row-toggle {
    margin: 12px;
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 6px 4px;
  }

  .data-table tbody tr.row-toggle:nth-child(4n+1) {
    background: #ffffff;
  }

  /* Model accordions still work on mobile (tapping the header card reveals its
     part cards), but a part card that's currently expanded must show every
     field on its own -- there's no header alongside it once you're mid-list. */
  .data-table tbody tr.row-toggle.group-child td.grouped-cell {
    opacity: 1;
  }

  .data-table tbody tr.row-toggle.group-child {
    background: #ffffff;
  }

  .data-table tbody tr.group-header {
    margin: 12px;
    padding: 12px 10px;
    border: 1px solid var(--line);
    border-radius: 10px;
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .data-table tbody tr.group-header td {
    border: none;
    padding: 0;
  }

  .data-table tbody tr.group-header td.expand-cell {
    display: flex;
  }

  .data-table tbody tr.group-header .group-meta {
    margin-left: auto;
  }

  .data-table td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 14px;
    border-bottom: none;
    text-align: right;
  }

  .data-table td.expand-cell {
    display: none;
  }

  .data-table td .price-stack {
    align-items: flex-end;
  }

  .data-table td::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    text-align: left;
  }

  .drawer {
    width: 100vw;
  }
}

/* ---------- export menu ---------- */

.export-menu {
  position: relative;
}

.export-menu summary {
  list-style: none;
}

.export-menu summary::-webkit-details-marker {
  display: none;
}

.export-menu summary .icon:last-child {
  width: 12px;
  height: 12px;
  transform: rotate(90deg);
  transition: transform 0.15s ease;
}

.export-menu[open] summary .icon:last-child {
  transform: rotate(-90deg);
}

.export-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 300px;
  max-width: calc(100vw - 32px);
  padding: 8px;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow);
}

.export-option {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 10px;
  border-radius: 8px;
  color: var(--ink);
  text-decoration: none;
}

.export-option:hover {
  background: var(--blue-soft);
  text-decoration: none;
}

.export-option strong,
.export-model strong {
  font-size: 13px;
  font-weight: 700;
}

.export-option span {
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
}

.export-model {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
  padding: 10px;
  border-top: 1px solid var(--line-soft);
}

.export-model input {
  width: 100%;
  height: 36px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
  font-size: 13px;
}

.export-model button {
  height: 36px;
  border: none;
  border-radius: 8px;
  background: var(--blue);
  color: #ffffff;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

@media (max-width: 820px) {
  .export-panel {
    left: 0;
    right: auto;
  }
}

/* Page links jump back to this section; keep its title clear of the sticky header. */
#recent-checks {
  scroll-margin-top: 120px;
}

@media (max-width: 820px) {
  #recent-checks {
    scroll-margin-top: 170px;
  }
}

/* ---------- sign-in pages, accounts, and the header's user menu ---------- */

.auth-body {
  min-height: 100vh;
}

main.auth-wrap {
  width: min(420px, calc(100% - 32px));
  margin: 8vh auto 48px;
}

main.auth-wrap.auth-wide {
  width: min(980px, calc(100% - 32px));
  margin-top: 32px;
}

.auth-card {
  padding: 26px 26px 22px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.auth-card h1 {
  margin: 0 0 6px;
}

.auth-note {
  margin: 0 0 16px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.auth-note code {
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--line-soft);
  font-size: 12px;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.auth-form label {
  margin-top: 8px;
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
}

.auth-form button {
  margin-top: 16px;
}

.auth-foot {
  margin: 16px 0 0;
  font-size: 13px;
}

.auth-foot a {
  color: var(--blue);
  text-decoration: none;
}

.auth-alert {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
}

.auth-alert.error {
  border: 1px solid #f5c2c0;
  background: #fdecec;
  color: #b42318;
}

.auth-alert.ok {
  border: 1px solid #bfe6d5;
  background: var(--green-soft);
  color: var(--green);
}

.auth-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 6px;
}

.auth-subhead {
  margin: 22px 0 10px;
  font-size: 15px;
}

.auth-muted {
  color: var(--muted-2);
}

.users-table td {
  vertical-align: middle;
}

.inline-form {
  display: flex;
  align-items: center;
  gap: 8px;
}

.inline-form select,
.inline-form input {
  width: auto;
  min-width: 120px;
  min-height: 36px;
}

.inline-form .ghost-btn {
  min-height: 36px;
}

.add-user-form {
  display: grid;
  grid-template-columns: 1.2fr 1.2fr 0.8fr auto;
  gap: 10px;
}

.danger-btn {
  min-height: 36px;
  border-color: #f5c2c0;
  background: #ffffff;
  color: #b42318;
}

.danger-btn:hover {
  background: #fdecec;
  filter: none;
}

.user-menu .export-panel {
  width: 250px;
}

.user-menu-who {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px 10px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 13px;
}

.role-tag {
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
}

.role-tag.role-admin {
  background: var(--blue-soft);
  color: var(--blue-ink);
}

.role-tag.role-user {
  background: var(--line-soft);
  color: var(--muted);
}

.logout-form {
  margin-top: 4px;
  padding: 8px 2px 2px;
  border-top: 1px solid var(--line-soft);
}

.logout-form button {
  width: 100%;
  min-height: 36px;
  border-color: var(--line);
  background: #ffffff;
  color: var(--ink);
}

.logout-form button:hover {
  background: #eef2f8;
  filter: none;
}

@media (max-width: 700px) {
  .add-user-form {
    grid-template-columns: 1fr;
  }

  .inline-form {
    flex-wrap: wrap;
  }
}

/* ---------- buyback: Cashify vs DOFY ---------- */

.platform-price {
  font-weight: 800;
  white-space: nowrap;
}

.platform-price.is-best {
  color: var(--green);
}

.platform-missing {
  color: var(--muted-2);
  font-weight: 600;
}

.source-link {
  margin-left: 6px;
  color: var(--muted-2);
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
}

.source-link:hover {
  color: var(--blue);
}

.offer {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}

.offer small {
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}

.badge-platform-cashify,
.badge-offer-cashify {
  background: var(--blue-soft);
  color: var(--blue-ink);
}

.badge-platform-dofy,
.badge-offer-dofy {
  background: var(--amber-soft);
  color: var(--amber);
}

.badge-offer-same {
  background: var(--line-soft);
  color: var(--muted);
}

.variant-cell {
  white-space: nowrap;
  font-weight: 600;
}

.stats .offer-split {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
}

.stats .offer-split b {
  font-size: 13px;
  color: var(--muted);
  font-weight: 700;
}

.scope-form select[name="scrape_platform"] {
  width: 150px;
}

.filter-bar select[name="compare"] {
  min-width: 170px;
}

/* Phones: the header's buttons wrap, and its drop-down panels open full width
   under the header instead of hanging off the right edge. */
@media (max-width: 820px) {
  .header-actions {
    flex-wrap: wrap;
    justify-content: flex-start;
  }

  .header-actions .export-menu {
    position: static;
  }

  .header-actions .export-panel {
    top: auto;
    left: 16px;
    right: 16px;
    width: auto;
    max-width: none;
    margin-top: 6px;
  }

  /* Table rows become cards with side margins; a full-width card plus its
     margins would push the page sideways. */
  .data-table tbody tr {
    width: auto;
  }
}

/* ---------- setup help (shown until api/config.php exists) ---------- */

.setup-steps {
  margin: 16px 0;
  padding-left: 20px;
  display: grid;
  gap: 14px;
  font-size: 14px;
  line-height: 1.55;
}

.auth-card code {
  padding: 1px 6px;
  border-radius: 6px;
  background: var(--line-soft);
  font-size: 12.5px;
}

.setup-steps pre {
  margin: 8px 0 0;
  padding: 10px 12px;
  overflow-x: auto;
  border-radius: 8px;
  background: #0f172a;
  color: #e2e8f0;
  font-size: 12px;
  line-height: 1.6;
}
