/* ==========================================================================
   RevRadar Components — "Ledger" direction, search-results page
   ==========================================================================
   Loads AFTER legacy.css. legacy.css re-skins the whole page automatically
   (its rules mostly reference var(--red)/var(--surface)/etc., now aliased
   to Ledger tokens in tokens.css) — this file is ONLY the deliberate
   redesign on top of that baseline: the results page's own chrome, and the
   card component, which needed new markup so needed new CSS too.

   Known, deliberate gap: legacy.css's `body.light .selector {...}` overrides
   were mostly written as hardcoded hex (not var()), from before tokens
   existed. Every such rule for an element THIS file touches is explicitly
   re-stated below in both themes, so it's correct. Elements outside today's
   scope (auth modal, quick-view modal, save-search modal, msd dropdown
   panels, PWA install banner) still carry a few leftover hardcoded reds in
   light mode specifically — expected until those get their own pass.
   ========================================================================== */

/* ---- base ---- */
body {
  font-family: var(--rr-font-sans);
  background: var(--rr-ground);
  color: var(--rr-ink);
}
/* The hidden attribute must always win. Without this, any author display
   rule (e.g. .listing-inactive-banner{display:flex}) silently defeats
   [hidden] — a real bug found on the listing page, where the "may have been
   sold" banner showed on every listing. (Same cascade exists in production.) */
[hidden] { display: none !important; }
::selection { background: var(--rr-accent-wash); color: var(--rr-ink); }
:focus-visible { outline: 2px solid var(--rr-focus-ring); outline-offset: 2px; }

/* ---- preview banner (this page only — not part of the reusable layer) ---- */
.rr-preview-banner {
  background: var(--rr-accent);
  color: var(--rr-accent-ink);
  font: var(--rr-fw-semibold) var(--rr-text-xs) var(--rr-font-mono);
  letter-spacing: var(--rr-tracking-wide);
  text-transform: uppercase;
  text-align: center;
  padding: var(--rr-space-2) var(--rr-space-3);
}
.rr-preview-banner a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* ---- nav ---- */
nav {
  background: var(--rr-nav-bg);
  border-bottom: 1px solid var(--rr-line);
  box-shadow: none;
  backdrop-filter: saturate(140%) blur(10px);
}
nav .logo { color: var(--rr-ink); font-weight: var(--rr-fw-bold); letter-spacing: var(--rr-tracking-normal); }
nav .logo span { color: var(--rr-accent); }
.nav-links a { color: var(--rr-ink-2); font-weight: var(--rr-fw-medium); font-size: var(--rr-text-sm); }
.nav-links a:hover { color: var(--rr-ink); }
.nav-badge { background: var(--rr-accent); color: var(--rr-accent-ink); }
.theme-toggle {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  color: var(--rr-ink-2);
  border-radius: var(--rr-radius-sm);
  font-family: var(--rr-font-mono);
  font-size: var(--rr-text-xs);
}
.theme-toggle:hover { border-color: var(--rr-line-strong); color: var(--rr-ink); }
.nav-signin-link { color: var(--rr-accent); font-weight: var(--rr-fw-semibold); }
.nav-avatar-btn { background: var(--rr-accent); color: var(--rr-accent-ink); }
.nav-dropdown {
  background: var(--rr-dropdown-bg);
  border: 1px solid var(--rr-line);
  border-radius: var(--rr-radius);
  box-shadow: var(--rr-shadow-dropdown);
}
.nav-dropdown a, .nav-dropdown-signout { color: var(--rr-dropdown-ink); }
.nav-dropdown a:hover, .nav-dropdown-signout:hover { background: var(--rr-surface-2); }
.nav-tier-badge { background: var(--rr-accent-wash); color: var(--rr-accent); border-radius: var(--rr-radius-sm); }
.nav-hamburger span { background: var(--rr-ink); }

/* ---- hero / search ---- */
.hero-eyebrow {
  color: var(--rr-muted);
  font: var(--rr-fw-semibold) var(--rr-text-xs) var(--rr-font-mono);
  letter-spacing: var(--rr-tracking-wide);
  text-transform: uppercase;
}
.hero-title {
  font-family: var(--rr-font-sans);
  font-weight: var(--rr-fw-bold);
  letter-spacing: var(--rr-tracking-tight);
  color: var(--rr-ink);
}
.hero-title em { font-style: normal; color: var(--rr-accent); }
.hero-sub { color: var(--rr-ink-2); }
.hero-sub em { font-style: normal; color: var(--rr-ink); font-weight: var(--rr-fw-medium); }

.search-box {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  border-radius: var(--rr-radius);
}
.search-box:focus-within { border-color: var(--rr-accent); }
.search-box input {
  color: var(--rr-ink);
  font-family: var(--rr-font-sans);
}
.search-box input::placeholder { color: var(--rr-muted); }
.search-box button {
  background: var(--rr-accent);
  color: var(--rr-accent-ink) !important;
  border-radius: var(--rr-radius-sm);
  font-weight: var(--rr-fw-semibold);
  letter-spacing: var(--rr-tracking-wide);
}
.search-box button:hover { background: var(--rr-accent-strong); }
body.light .search-box button { color: var(--rr-accent-ink) !important; }

/* ---- filters bar ---- */
.filters-bar {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  border-radius: var(--rr-radius);
}
.filter-label { color: var(--rr-muted); font-family: var(--rr-font-mono); font-size: var(--rr-text-xs); text-transform: uppercase; letter-spacing: var(--rr-tracking-wide); }
.filter-select, .msd-btn, .feat-dropdown-btn {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  color: var(--rr-ink-2);
  border-radius: var(--rr-radius-sm);
  font-family: var(--rr-font-sans);
  font-size: var(--rr-text-sm);
}
.filter-select:hover, .msd-btn:hover, .feat-dropdown-btn:hover { border-color: var(--rr-line-strong); color: var(--rr-ink); }
.msd-panel, .feat-dropdown-panel {
  background: var(--rr-dropdown-bg);
  border: 1px solid var(--rr-line);
  border-radius: var(--rr-radius-sm);
  box-shadow: var(--rr-shadow-dropdown);
  color: var(--rr-dropdown-ink);
}
.msd-item:hover { background: var(--rr-surface-2); }
.damaged-toggle-label { color: var(--rr-ink-2); font-size: var(--rr-text-sm); }
.damaged-toggle-label input[type="checkbox"] { accent-color: var(--rr-accent) !important; }
.apply-btn {
  background: var(--rr-accent);
  color: var(--rr-accent-ink) !important;
  border-radius: var(--rr-radius-sm);
  font-weight: var(--rr-fw-semibold);
}
.apply-btn:hover { background: var(--rr-accent-strong); }
.mobile-filter-btn {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  color: var(--rr-ink);
  border-radius: var(--rr-radius-sm);
}
.mobile-filter-backdrop { background: var(--rr-backdrop); }

/* ---- results header ---- */
.results-title { color: var(--rr-ink); font-family: var(--rr-font-sans); font-weight: var(--rr-fw-bold); letter-spacing: var(--rr-tracking-tight); }
.results-title span { color: var(--rr-accent); }
.results-sources-line { color: var(--rr-muted); font-size: var(--rr-text-xs); }
.results-meta { color: var(--rr-muted); font-family: var(--rr-font-mono); font-size: var(--rr-text-xs); font-variant-numeric: tabular-nums; }
.save-search-btn {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  color: var(--rr-ink-2);
  border-radius: var(--rr-radius-sm);
  font-size: var(--rr-text-sm);
}
.save-search-btn:hover { border-color: var(--rr-accent); color: var(--rr-accent); }
#exportCsvBtn { border-color: var(--rr-line) !important; color: var(--rr-ink-2) !important; border-radius: var(--rr-radius-sm) !important; }
.pro-lock-badge { color: var(--rr-deal-warn); }

/* ---- view / sort / platform tabs ---- */
.view-tabs { border: 1px solid var(--rr-line); border-radius: var(--rr-radius-sm); overflow: hidden; }
.view-tab, body.light .view-tab {
  background: var(--rr-surface);
  color: var(--rr-ink-2);
  font-family: var(--rr-font-mono);
  font-size: var(--rr-text-xs);
  letter-spacing: var(--rr-tracking-wide);
}
.view-tab:hover, body.light .view-tab:hover { background: var(--rr-surface-2); color: var(--rr-ink); }
.view-tab.active, body.light .view-tab.active { background: var(--rr-accent); color: var(--rr-accent-ink); }
.view-tab.active .tab-count, body.light .view-tab.active .tab-count { background: transparent; color: var(--rr-accent-ink); }
.tab-count { background: var(--rr-surface-2); color: var(--rr-muted); font-variant-numeric: tabular-nums; border-radius: var(--rr-radius-pill); }
.sort-select { background: var(--rr-surface); border: 1px solid var(--rr-line); color: var(--rr-ink-2); border-radius: var(--rr-radius-sm); font-size: var(--rr-text-sm); }

.source-tabs { border-bottom: 1px solid var(--rr-line); }
.source-tab, body.light .source-tab {
  background: transparent;
  border: 1px solid transparent;
  color: var(--rr-muted);
  border-radius: var(--rr-radius-sm);
  font-family: var(--rr-font-mono);
  font-size: var(--rr-text-xs);
}
.source-tab:hover, body.light .source-tab:hover { background: var(--rr-surface-2); border-color: var(--rr-line); }
/* tab labels keep their platform brand colours (2026-07-14 restore);
   the active state marks itself with border + wash only */
.source-tab.active, body.light .source-tab.active {
  background: var(--rr-accent-wash) !important;
  border-color: var(--rr-accent) !important;
}
.source-tab .tab-count, body.light .source-tab .tab-count { background: var(--rr-surface-2); color: var(--rr-muted) !important; }
.source-tab.active .tab-count, body.light .source-tab.active .tab-count { background: transparent !important; color: var(--rr-accent) !important; }

/* ---- filter chips ---- */
.chips-bar { display: flex; flex-wrap: wrap; gap: var(--rr-space-2); }
.chip, body.light .chip {
  display: inline-flex; align-items: center; gap: var(--rr-space-1);
  background: var(--rr-accent-wash);
  border: 1px solid var(--rr-accent);
  color: var(--rr-accent);
  border-radius: var(--rr-radius-pill);
  font-size: var(--rr-text-xs);
  font-family: var(--rr-font-sans);
  font-weight: var(--rr-fw-medium);
  padding: 0.3rem 0.55rem 0.3rem 0.75rem;
}
.chip-x { color: inherit; opacity: 0.65; }
.chip-x:hover { opacity: 1; }
.chips-clear { color: var(--rr-muted); font-size: var(--rr-text-xs); text-decoration: underline; text-underline-offset: 2px; }
.chips-clear:hover { color: var(--rr-ink); }
.variant-chip {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  color: var(--rr-ink-2);
  border-radius: var(--rr-radius-sm);
  font-family: var(--rr-font-mono);
  font-size: var(--rr-text-xs);
}
.variant-chip:hover { border-color: var(--rr-accent); color: var(--rr-ink); }
.variant-chip.active { background: var(--rr-accent); border-color: var(--rr-accent); color: var(--rr-accent-ink); }

/* ---- loading / empty / no-results ---- */
.loading-text { color: var(--rr-ink); font-family: var(--rr-font-mono); letter-spacing: var(--rr-tracking-wide); }
.loading-sub { color: var(--rr-muted); }
.loading-spinner { border-color: var(--rr-line); border-top-color: var(--rr-accent); }
/* Skeleton loading grid (replaces the spinner): stretch to the page width
   the legacy .loading centering would otherwise shrink-wrap */
.loading { align-items: stretch; }
.rr-loading-status {
  color: var(--rr-muted);
  font-family: var(--rr-font-mono);
  font-size: var(--rr-text-sm);
  letter-spacing: var(--rr-tracking-wide);
  text-align: left;
}
/* The loading view must occupy exactly #results' box (legacy.css) or the
   grid jumps when results swap in: same padding, max-width and flow. */
#loading.loading {
  display: none;
  padding: 6rem 2rem 4rem;
  max-width: 1400px;
  margin: 0 auto;
  gap: 0;
}
#loading.loading.visible { display: block; }
@media (max-width: 600px) {
  #loading.loading { padding: 5rem 1rem 3rem; }
}
.rr-loading-grid { width: 100%; }
@media (max-width: 720px) {
  /* fewer skeletons on one column — don't imply a page of results */
  .rr-skel-card--tail { display: none; }
}
.no-results-title { color: var(--rr-ink); font-weight: var(--rr-fw-semibold); }
.no-results-sub { color: var(--rr-muted); }
.no-results-clear, body.light .no-results-clear {
  background: var(--rr-accent);
  color: var(--rr-accent-ink) !important;
  border-radius: var(--rr-radius-sm);
}
.pro-alert-banner {
  background: var(--rr-accent-wash);
  border: 1px solid var(--rr-accent);
  color: var(--rr-ink);
  border-radius: var(--rr-radius);
}

/* ---- pagination ---- */
.pagination-nav { display: flex; align-items: center; justify-content: center; gap: var(--rr-space-2); font-family: var(--rr-font-mono); }
.pagination-nav button {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  color: var(--rr-ink-2);
  border-radius: var(--rr-radius-sm);
  font-size: var(--rr-text-sm);
  font-variant-numeric: tabular-nums;
  padding: 0.4rem 0.75rem;
  cursor: pointer;
}
.pagination-nav button:hover:not(:disabled) { border-color: var(--rr-accent); color: var(--rr-accent); }
.pagination-nav button.active { background: var(--rr-accent); border-color: var(--rr-accent); color: var(--rr-accent-ink); }
.pagination-nav button:disabled { opacity: 0.4; cursor: default; }

/* ==========================================================================
   CARD — the redesigned component. New markup (see js/render-card.js),
   styled here from scratch rather than retheming the legacy .card rules.
   ========================================================================== */
/* .listings-grid is the actual container class still in the page markup
   (untouched — only the card template inside it was redesigned). .rr-grid
   is the same rule under its intended reusable name for listing.html /
   account.html once those get their own pass. */
.rr-grid, .listings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--rr-space-4);
}
.rr-card {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  border-radius: var(--rr-radius);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.15s ease;
  display: flex;
  flex-direction: column;
}
.rr-card:hover { border-color: var(--rr-line-strong); }
.rr-card:focus-visible { outline: 2px solid var(--rr-accent); outline-offset: -2px; }

.rr-card-plate {
  position: relative;
  height: 168px;
  background: var(--rr-card-img-bg);
  border-bottom: 1px solid var(--rr-line);
  overflow: hidden;
}
.rr-card-plate img { width: 100%; height: 100%; object-fit: cover; display: block; transition: opacity 0.2s ease; }
.rr-card-plate.rr-skel img { opacity: 0; }
/* keep the plate's badges above the skeleton shimmer overlay */
.rr-card-plate .rr-card-source, .rr-card-plate .rr-damage-flag, .rr-card-plate .rr-card-nav { z-index: 2; }
.rr-card-plate-empty {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: var(--rr-surface-2);
  color: var(--rr-muted);
  font-size: var(--rr-text-xs);
  font-family: var(--rr-font-mono);
}
.rr-card-source {
  position: absolute; top: var(--rr-space-2); right: var(--rr-space-2);
  background: var(--rr-source-badge-bg);
  border: 1px solid var(--rr-line);
  color: var(--rr-ink-2);
  font: var(--rr-fw-medium) var(--rr-text-xs) var(--rr-font-mono);
  letter-spacing: var(--rr-tracking-wide);
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border-radius: var(--rr-radius-sm);
}
.rr-card-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: var(--rr-card-arrow-bg);
  border: 1px solid var(--rr-card-arrow-border);
  color: var(--rr-ink);
  width: 26px; height: 26px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  font-size: 0.8rem;
}
.rr-card-nav.prev { left: var(--rr-space-2); }
.rr-card-nav.next { right: var(--rr-space-2); }

/* Body is a stack of SECTIONS, not one padded column (Variant B, approved
   2026-07-14 — card-simple.html). The divider is drawn by the CONTAINER
   (.rr-card-body > .rr-card-sec + .rr-card-sec), never hand-placed per section,
   so a section added later can't forget its rule. The gauge that used to live
   here is gone from the grid entirely: at a 280px column a dial (and even the
   4px linear track) was noise, and the verdict is a word and a number. The rev
   gauge survives ONLY as the listing-detail hero — the click-in payoff. */
.rr-card-body { padding: 0; display: flex; flex-direction: column; flex: 1; }
.rr-card-sec {
  padding: var(--rr-space-3) var(--rr-space-4);
  display: flex; flex-direction: column; gap: var(--rr-space-2);
}
.rr-card-body > .rr-card-sec + .rr-card-sec { border-top: 1px solid var(--rr-line); }

/* Price + verdict: one locked row. Price is the ledger figure (left), the
   deal chip is the verdict on that figure (right) — they never separate. */
.rr-price-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--rr-space-2);
  flex-wrap: wrap;
}

/* ---- the verdict band ---------------------------------------------------
   The card's ANSWER (price, verdict, what it's worth) sits on a tinted band so
   it separates from the card's DESCRIPTION (title, specs) at a glance.
   Reinforced 2026-07-14 after the first light-mode pass was a 1.07:1 step —
   effectively invisible. Three moves, and the split between them is the point:

     1. FILL, light 0.035 -> 0.07 (#EEEEEF, a 1.16:1 step). That is exactly
        where --rr-surface-2 already sits (1.15:1): it reads as a surface, not a
        highlight. Darkening past this is a trap — see (3).
     2. EDGES, --rr-line -> --rr-line-strong on the band's two rules. This buys
        most of the perceived separation and costs ZERO text contrast (a rule
        has no text on it), which is precisely why the fill doesn't have to go
        dark enough to hurt.
     3. INK. A darker fill LOWERS contrast for the dark text on top, so the fill
        is only allowed to take what the text can be repaid: caption -> ink-2,
        pill text -> the --rr-deal-*-ink tokens. Pushing the fill to 0.16 was
        tried and rejected: it reads as a warning box AND fails 9 of 10 text
        checks. "Just darken it" makes legibility worse, not better.

   --rr-surface-2 is ~4% off --rr-surface in dark, so the band must be an
   explicit per-theme overlay or the variant is a no-op on dark. */
.rr-card-verdict { background: rgba(255, 255, 255, 0.05); }
body.light .rr-card-verdict { background: rgba(15, 15, 20, 0.07); }
.rr-card-body > .rr-card-sec + .rr-card-verdict,
.rr-card-body > .rr-card-verdict + .rr-card-sec { border-top-color: var(--rr-line-strong); }

/* The verdict itself: TEXT. A tier-toned pill, label + magnitude. No dial, no
   track, no marker — at a 280px column a tile has room for a word and a number,
   and that is all it ever needed. Colour is carried by the border (--dc, the
   graphic role) and the text (--dc-ink, the AA-safe role); the two are separate
   tokens on purpose — see the tier triplet note in tokens.css. */
.rr-deal-pill {
  display: inline-flex; align-items: baseline; gap: 0.35rem;
  font-family: var(--rr-font-mono);
  border: 1px solid var(--dc);
  border-radius: var(--rr-radius-pill);
  background: var(--dc-wash);
  padding: 0.3rem 0.6rem;
  white-space: nowrap;
}
.rr-deal-word {
  font: var(--rr-fw-bold) 0.7rem var(--rr-font-mono);
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--dc-ink);
}
/* No opacity here, ever. The old .rr-gauge-pct carried opacity:0.85, which
   blended the ink toward the pill and silently ate ~0.9 of contrast ratio for
   no visual gain — it was a direct cause of the AA failure. */
.rr-deal-pct {
  font: var(--rr-fw-medium) 0.72rem var(--rr-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--dc-ink);
}
.rr-deal-pill.positive { --dc: var(--rr-deal-positive); --dc-wash: var(--rr-deal-positive-wash); --dc-ink: var(--rr-deal-positive-ink); }
.rr-deal-pill.neutral  { --dc: var(--rr-deal-neutral);  --dc-wash: var(--rr-deal-neutral-wash);  --dc-ink: var(--rr-deal-neutral-ink); }
.rr-deal-pill.warn     { --dc: var(--rr-deal-warn);     --dc-wash: var(--rr-deal-warn-wash);     --dc-ink: var(--rr-deal-warn-ink); }
.rr-deal-pill.negative { --dc: var(--rr-deal-negative); --dc-wash: var(--rr-deal-negative-wash); --dc-ink: var(--rr-deal-negative-ink); }

/* The band's caption: what the verdict is actually claiming, in money.
   --rr-ink-2, not --rr-muted: muted lands at 4.37:1 on the reinforced band —
   a fail. This is the text being "repaid" what the fill cost it. */
.rr-deal-sub {
  font: var(--rr-fw-regular) var(--rr-text-xs) var(--rr-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--rr-ink-2);
}

/* Flip margin: quiet secondary line — data, not a banner. The slot always
   renders (--empty spacer when there's no flip figure) so card height is
   identical across tiers/results and the skeleton can match it exactly.
   It lives INSIDE the verdict band (it's part of the card's answer, not its
   description), so it takes the AA-safe ink like everything else on the band. */
.rr-flip-line {
  font: var(--rr-fw-medium) var(--rr-text-xs) var(--rr-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--rr-deal-positive-ink);
}
.rr-flip-line--empty { visibility: hidden; }
.rr-flip-line.locked {
  color: var(--rr-muted);
  text-decoration: none;
  cursor: pointer;
}
.rr-flip-line.locked:hover { color: var(--rr-accent); }

/* Damage: stamped on the photo plate (top-left), mirroring the source badge
   (top-right) — vehicle facts live on the plate, judgments in the body. */
.rr-damage-flag {
  position: absolute; top: var(--rr-space-2); left: var(--rr-space-2);
  background: var(--rr-source-badge-bg);
  border: 1px solid var(--rr-deal-warn);
  color: var(--rr-deal-warn);
  font: var(--rr-fw-semibold) var(--rr-text-xs) var(--rr-font-mono);
  letter-spacing: var(--rr-tracking-wide);
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border-radius: var(--rr-radius-sm);
  z-index: 1;
}

.rr-card-title {
  font: var(--rr-fw-semibold) var(--rr-text-base) var(--rr-font-sans);
  color: var(--rr-ink);
  line-height: var(--rr-leading-snug);
  letter-spacing: var(--rr-tracking-tight);
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
/* Spec tags — the card's primary at-a-glance layer. Was a single muted mono
   line (year · mileage · gearbox · fuel); now six discrete tags including body
   type and engine size, at full ink-2 contrast, so the car's facts are read
   first and the deal strip is the second look.
   The row height is FIXED to exactly two tag rows (24px + 5px gap + 24px) and
   clips — cards carry a variable number of tags (missing bodyType, no engine
   size on some sources), and a variable-height tag row would reintroduce the
   card-height variance the flip slot exists to prevent, breaking the loading
   skeleton's geometry match. Two rows fits all six tags at the 280px column
   minimum; the reserve is constant whether a card has three tags or six. */
.rr-card-specs {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 5px;
  height: 53px;
  overflow: hidden;
}
.rr-card-spec {
  display: inline-flex; align-items: center;
  height: 24px;
  padding: 0 0.5rem;
  border: 1px solid var(--rr-line);
  border-radius: var(--rr-radius-sm);
  background: var(--rr-surface-2);
  color: var(--rr-ink-2);
  font: var(--rr-fw-medium) var(--rr-text-sm) var(--rr-font-sans);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* mileage is the number buyers actually compare — mono, full ink */
.rr-card-spec.mileage {
  font-family: var(--rr-font-mono);
  color: var(--rr-ink);
}
.rr-price {
  font: var(--rr-fw-bold) var(--rr-text-xl) var(--rr-font-mono);
  letter-spacing: var(--rr-tracking-tight);
  color: var(--rr-ink);
  font-variant-numeric: tabular-nums;
}
/* The footer is now a .rr-card-sec like every other band, so the container
   draws its rule and its padding — it no longer carries its own border-top /
   padding-top. `margin-top: auto` moves to the SECTION so short cards still
   pin the footer to the bottom. */
.rr-card-sec.rr-card-foot-sec { margin-top: auto; }
.rr-card-footer {
  display: flex; align-items: center; justify-content: space-between;
  font-size: var(--rr-text-xs);
  color: var(--rr-muted);
}
.rr-card-footer a { color: var(--rr-muted); text-decoration: none; }
.rr-card-footer a:hover { color: var(--rr-accent); }
.rr-card-footer-loc { display: inline-flex; align-items: center; gap: 0.3ch; min-width: 0; }
.rr-fresh { color: var(--rr-deal-positive); font-weight: var(--rr-fw-medium); }
.rr-fav-btn { background: none; border: none; cursor: pointer; color: var(--rr-muted); font-size: 1rem; line-height: 1; padding: 0; }
.rr-fav-btn.saved { color: var(--rr-deal-negative); }
.rr-fav-btn:hover { color: var(--rr-deal-negative); }

/* ==========================================================================
   SIGN-IN WALL — the highest-traffic screen on the site. One signature
   element (the radar sweep — the product's namesake), everything else quiet.
   #loginWall's fixed positioning/show-hide comes from legacy.css; this
   restyles the contents.
   ========================================================================== */
#loginWall { overflow-y: auto; }
.rr-wall {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 420px;
  padding: var(--rr-space-6) var(--rr-space-4);
  margin: auto;
}

/* The brand mark, no-dots edition (approved 2026-07-14, wall-only scope —
   nav bars everywhere keep REV_RADAR_logo_white_png/light).
   Emblem: rr-logo-nodots-{light,dark}.png — preview-side derivations of
   public/REV_RADAR_logo_nodots.png, which is RGB/opaque-white, emblem-only
   and black-ink: white keyed to alpha (so the sweep shows through and dark
   mode works) plus a white-ink copy; source file untouched. Wordmark: the
   new file has none, so the wipe reuses the REAL wordmark band of the
   production logo PNGs (bottom strip, clipped — rows 422–473 of 492).

   0–450ms    emblem focuses in
   500–1750ms sweep spins up BEHIND the artwork (full turn −10.7°→349.3°,
              so the beam's bright edge (rotation+52°) finishes on the
              needle tip at 41.3° from 12 o'clock)
   ~1690ms    PING at the needle tip (flash + halo) as the wordmark strip
              wipes in left→right
   1750ms→    idle: sweep re-bases 349.3°→709.3° every 7s; the ping loops
              fire 1120ms in (16%), i.e. from 7630ms and every 7s after —
              always as the beam crosses the tip.

   Measured in the 1254² emblem file: gauge centre (48.4%, 49.8%), needle
   tip (62.8%, 33.5%), ring Ø 55.7% of image. Layout: img at 240px inside
   a 150×150 viewport (ring ≈ 134px) offset so the gauge centre sits at
   the viewport centre; landmarks in viewport %: centre (50%, 50%), tip
   (73%, 23.9%). Reduced motion: full logo immediately, static beam,
   static blip, no ping. */
.rr-wall-logo {
  position: relative;
  width: 150px;
  aspect-ratio: 1;
  margin-bottom: var(--rr-space-2);
}
.rr-wall-logo-emblem {
  position: absolute;
  inset: 0;
  animation: rr-focus-in 450ms ease-out both;
}
.rr-wall-logo-emblem img {
  position: absolute;
  width: 240px;
  left: -41.2px;
  top: -44.5px;
  max-width: none;
  z-index: 1;
}
.rr-wall-logo-emblem .rr-logo--light,
.rr-wall-logo-wordstrip .rr-logo--light { display: none; }
body.light .rr-wall-logo-emblem .rr-logo--dark,
body.light .rr-wall-logo-wordstrip .rr-logo--dark { display: none; }
body.light .rr-wall-logo-emblem .rr-logo--light,
body.light .rr-wall-logo-wordstrip .rr-logo--light { display: block; }
/* real wordmark strip from the production lockup */
.rr-wall-logo-wordstrip {
  position: relative;
  width: 210px;
  height: 33px;
  overflow: hidden;
  margin-bottom: var(--rr-space-5);
  animation: rr-word-wipe 450ms cubic-bezier(.22,.61,.36,1) 1620ms both;
}
.rr-wall-logo-wordstrip img {
  position: absolute;
  width: 210px;
  top: -141px;   /* 82% of 210×(492/600)=172.2 — clip line sits in the band gap */
  left: 0;
}
.rr-wall-logo-sweep {
  position: absolute;
  left: 50%; top: 50%;
  width: 134px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(from 0deg, var(--rr-accent-wash), var(--rr-radar-beam) 52deg, transparent 60deg);
  z-index: 0;
  transform: translate(-50%, -50%) rotate(349.3deg);
  animation:
    rr-logo-sweep-enter 1250ms cubic-bezier(.22,.61,.36,1) 500ms both,
    rr-logo-spin 7s linear 1750ms infinite;
}
.rr-wall-logo-blip {
  position: absolute;
  left: 73%; top: 23.9%;
  width: 8px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--rr-accent);
  z-index: 2;
  opacity: 0;
  transform: translate(-50%, -50%);
  animation:
    rr-logo-blip-enter 2200ms linear both,
    rr-radar-blip 7s ease-out 7630ms infinite;
}
.rr-wall-logo-pulse {
  position: absolute;
  left: 73%; top: 23.9%;
  width: 46px;
  aspect-ratio: 1;
  border: 1.5px solid var(--rr-accent);
  border-radius: 50%;
  z-index: 2;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.15);
  animation:
    rr-logo-pulse-enter 2200ms linear both,
    rr-logo-pulse-idle 7s linear 7630ms infinite;
}
.rr-wall-title, .rr-wall-sub, .rr-wall-points,
.rr-wall-actions, .rr-wall-beta, .rr-wall-sources {
  animation: rr-rise-in 500ms ease-out 350ms both;
}

@keyframes rr-focus-in { from { opacity: 0; filter: blur(6px); } to { opacity: 1; filter: blur(0); } }
@keyframes rr-rise-in  { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes rr-word-wipe {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes rr-logo-sweep-enter {
  0%   { transform: translate(-50%, -50%) rotate(-10.7deg); opacity: 0; }
  12%  { opacity: 1; }
  100% { transform: translate(-50%, -50%) rotate(349.3deg); opacity: 1; }
}
@keyframes rr-logo-spin {
  from { transform: translate(-50%, -50%) rotate(349.3deg); }
  to   { transform: translate(-50%, -50%) rotate(709.3deg); }
}
@keyframes rr-radar-blip {
  0%, 14%  { opacity: 0; }
  16%      { opacity: 1; }
  55%      { opacity: 0.25; }
  100%     { opacity: 0; }
}
@keyframes rr-logo-blip-enter {
  0%, 74% { opacity: 0; transform: translate(-50%, -50%) scale(0.4); box-shadow: 0 0 0 0 transparent; }
  78%     { opacity: 1; transform: translate(-50%, -50%) scale(2); box-shadow: 0 0 12px 2px var(--rr-radar-beam); }
  100%    { opacity: 0; transform: translate(-50%, -50%) scale(1); box-shadow: 0 0 0 0 transparent; }
}
@keyframes rr-logo-pulse-enter {
  0%, 76% { opacity: 0; transform: translate(-50%, -50%) scale(0.15); }
  80%     { opacity: 0.75; }
  100%    { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}
@keyframes rr-logo-pulse-idle {
  0%, 14% { opacity: 0; transform: translate(-50%, -50%) scale(0.15); }
  18%     { opacity: 0.7; }
  32%     { opacity: 0; transform: translate(-50%, -50%) scale(1); }
  100%    { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .rr-wall-logo-emblem, .rr-wall-logo-wordstrip, .rr-wall-logo-sweep,
  .rr-wall-logo-blip, .rr-wall-logo-pulse,
  .rr-wall-title, .rr-wall-sub, .rr-wall-points,
  .rr-wall-actions, .rr-wall-beta, .rr-wall-sources { animation: none; }
  .rr-wall-logo-blip  { opacity: 0.8; }
  .rr-wall-logo-pulse { opacity: 0; }
  .rr-wall-logo-wordstrip { clip-path: none; }
}

.rr-wall-title {
  font-family: var(--rr-font-display);
  font-size: var(--rr-text-display);
  letter-spacing: var(--rr-tracking-display);
  line-height: var(--rr-leading-tight);
  color: var(--rr-ink);
  margin-bottom: var(--rr-space-3);
}
.rr-wall-title em { font-style: normal; color: var(--rr-accent); }

.rr-wall-sub {
  color: var(--rr-ink-2);
  font-size: var(--rr-text-base);
  line-height: var(--rr-leading-normal);
  max-width: 40ch;
  margin-bottom: var(--rr-space-5);
}

.rr-wall-points {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--rr-space-6);
  display: flex;
  flex-direction: column;
  gap: var(--rr-space-2);
}
.rr-wall-points li {
  font-size: var(--rr-text-sm);
  color: var(--rr-ink-2);
  display: flex;
  align-items: center;
  gap: var(--rr-space-2);
}
.rr-wall-points li::before {
  content: '';
  width: 12px; height: 2px;
  background: var(--rr-accent);
  flex: none;
}

.rr-wall-actions {
  display: flex;
  flex-direction: column;
  gap: var(--rr-space-3);
  width: 100%;
  max-width: 300px;
  margin-bottom: var(--rr-space-4);
}
.rr-wall-btn {
  font: var(--rr-fw-semibold) var(--rr-text-sm) var(--rr-font-sans);
  letter-spacing: var(--rr-tracking-wide);
  padding: 0.8rem var(--rr-space-4);
  border-radius: var(--rr-radius-sm);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.rr-wall-btn.primary {
  background: var(--rr-accent);
  border: 1px solid var(--rr-accent);
  color: var(--rr-accent-ink);
}
.rr-wall-btn.primary:hover { background: var(--rr-accent-strong); border-color: var(--rr-accent-strong); }
.rr-wall-btn.ghost {
  background: transparent;
  border: 1px solid var(--rr-line-strong);
  color: var(--rr-ink);
}
.rr-wall-btn.ghost:hover { border-color: var(--rr-ink-2); }

.rr-wall-beta {
  font-size: var(--rr-text-xs);
  color: var(--rr-muted);
  max-width: 36ch;
  line-height: var(--rr-leading-snug);
  margin-bottom: var(--rr-space-6);
}

.rr-wall-sources {
  font-family: var(--rr-font-mono);
  font-size: var(--rr-text-xs);
  letter-spacing: 0.12em;
  color: var(--rr-muted);
  border-top: 1px solid var(--rr-line);
  padding-top: var(--rr-space-4);
  max-width: 100%;
}

/* ---- responsive ---- */
@media (max-width: 720px) {
  .rr-grid { grid-template-columns: 1fr; }
  .results-header { flex-direction: column; align-items: flex-start; gap: var(--rr-space-3); }
  .view-sort-bar { flex-direction: column; align-items: stretch; gap: var(--rr-space-2); }
  .source-tabs { overflow-x: auto; flex-wrap: nowrap; }
}

/* ==========================================================================
   SOURCE-PLATFORM COLOURS RESTORED (2026-07-14) — partial revert of the
   2026-07-13 zero-blue sweep, at Jack's request ("unless asked" — he
   asked). Marketplace badges/tabs show each platform's brand colours
   again (sourceBadgeHTML()'s inline spans + legacy rules). Zero-blue
   remains the policy for all non-source UI chrome. The badge surface is
   pinned dark in BOTH themes because several brand marks include white
   glyphs ("Auto", "tree", "Heads") that vanish on light surfaces.
   ========================================================================== */
.rr-card-source {
  background: rgba(8, 8, 10, 0.85);
  border-color: rgba(255, 255, 255, 0.14);
}

/* ==========================================================================
   SKELETON SHAPES — shared placeholder geometry for loading states.
   The .rr-skel primitive (surface + shimmer + reduced-motion) lives in
   tokens.css; these are the component-shaped instances of it.
   ========================================================================== */
/* Chip shaped like a .highlight-chip (also-on row): mono 0.7rem + 0.3rem
   vertical padding renders 25.6px on desktop, 23px under 600px. */
.rr-skel-chip { display: inline-block; width: 240px; height: 26px; border-radius: var(--rr-radius-sm); }
@media (max-width: 600px) { .rr-skel-chip { width: 220px; height: 23px; } }
.rr-skel-line { height: 13px; margin-top: var(--rr-space-2); }
.rr-skel-line.w40 { width: 40%; }
.rr-skel-line.w60 { width: 60%; }
.rr-skel-line.w80 { width: 80%; }

/* Skeleton card mirrors .rr-card's real anatomy 1:1 (verified against rendered
   geometry by scripts/preview-shots/measure-skel.js — run it after changing
   EITHER side; it fails at >2px drift). It mirrors the SECTIONS, not just the
   heights: same four .rr-card-sec bands, same paddings, same dividers, and the
   verdict band's tint too — otherwise the tint would pop in on load, which is
   the same class of jump the geometry check exists to prevent.
   plate 168 + border, then: title / specs (53, fixed two tag rows) /
   verdict band (price-row 31 + sub 15 + flip 15) / footer. */
/* NOTE: no `display: flex` here. Every skeleton row is a fixed height, so it
   buys nothing — and it silently un-hides the two --tail cards, whose
   `display: none` mobile rule (above) carries the same specificity and would
   lose to a later base rule. That regression is invisible on desktop (8 vs 6
   cards both fill 2 rows) and only shows up as a ~900px mobile grid overshoot.
   measure-skel.js catches it; don't reintroduce it. */
.rr-skel-card {
  background: var(--rr-surface);
  border: 1px solid var(--rr-line);
  border-radius: var(--rr-radius);
  overflow: hidden;
}
.rr-skel-card-img { height: 168px; border-radius: 0; border-bottom: 1px solid var(--rr-line); }
.rr-skel-card-body { padding: 0; display: flex; flex-direction: column; }
.rr-skel-card-body .rr-skel-line { margin-top: 0; }
.rr-skel-card-sec {
  padding: var(--rr-space-3) var(--rr-space-4);
  display: flex; flex-direction: column; gap: var(--rr-space-2);
}
.rr-skel-card-body > .rr-skel-card-sec + .rr-skel-card-sec { border-top: 1px solid var(--rr-line); }
/* the verdict band — same overlay, both themes, as .rr-card-verdict */
.rr-skel-card-verdict { background: rgba(255, 255, 255, 0.05); }
body.light .rr-skel-card-verdict { background: rgba(15, 15, 20, 0.07); }
.rr-skel-card-body > .rr-skel-card-sec + .rr-skel-card-verdict,
.rr-skel-card-body > .rr-skel-card-verdict + .rr-skel-card-sec { border-top-color: var(--rr-line-strong); }

.rr-skel-card-title { height: 20px; }
.rr-skel-card-meta  { height: 53px; }   /* the fixed two-row spec-tag block */
.rr-skel-card-price { height: 31px; display: flex; align-items: center; justify-content: space-between; }
.rr-skel-card-price .price   { width: 96px; height: 31px; }
.rr-skel-card-price .verdict { width: 122px; height: 26px; border-radius: var(--rr-radius-pill); }
.rr-skel-card-sub  { height: 15px; width: 60%; }   /* the always-reserved market-average caption */
.rr-skel-card-flip { height: 15px; }               /* the always-reserved flip slot */
/* 16px = the real .rr-card-footer's measured content height now that the
   section (not the footer) owns the padding and the rule. */
.rr-skel-card-foot { height: 16px; display: flex; align-items: center; }
.rr-skel-card-foot .rr-skel { width: 45%; height: 15px; margin: 0; }
/* listing.html's similar grid still uses the legacy card template, whose
   image plate is 160px (not 168) — total 308 vs the rr-card's 317. It also
   keeps the legacy one-line meta, so it must NOT inherit the results card's
   two-row spec-tag reserve.
   It also predates the sectioned body: its children sit DIRECTLY in
   .rr-skel-card-body with no .rr-skel-card-sec wrappers, so it must keep the
   old padded-column box (the results skeleton moved that padding onto the
   sections). Retire this block only when the similar grid gets .rr-card. */
.rr-skel-card--similar .rr-skel-card-img  { height: 159px; }
.rr-skel-card--similar .rr-skel-card-meta { height: 15px; }
.rr-skel-card--similar .rr-skel-card-body {
  padding: var(--rr-space-4);
  gap: var(--rr-space-2);
}
.rr-skel-card--similar .rr-skel-card-foot {
  height: 25px;
  padding-top: var(--rr-space-2);
  box-sizing: border-box;
}

/* ==========================================================================
   NAV TOGGLE/AVATAR OVERLAP FIX (2026-07-13)
   legacy.css carries `body.light .theme-toggle { width:38px; height:38px;
   font-size:1.25rem }` — an icon-only square from an older design. The button
   renders "☾ Dark" TEXT (label only hidden ≤600px), so in light mode the
   nowrap text overflowed the fixed 38px box and the avatar — flex-gapped from
   the BOX, not the overflow — sat on top of it. Same specificity, later file:
   this wins. Auto width in both themes; content defines the box again.
   ========================================================================== */
body.light .theme-toggle {
  width: auto;
  height: 32px;
  font-size: var(--rr-text-xs);
  border: 1px solid var(--rr-line-strong);
  background: var(--rr-surface);
  color: var(--rr-ink-2);
}
body.light .theme-toggle:hover {
  border-color: var(--rr-accent);
  background: var(--rr-accent-wash);
  color: var(--rr-accent);
}
