/* ==========================================================================
   RevRadar listing detail — "Ledger" direction pass
   ==========================================================================
   Loads AFTER tokens.css → listing-legacy.css → components.css.
   listing-legacy.css is the original page stylesheet re-based onto tokens;
   this file is the deliberate redesign on top:

   1. Deal score = the page's verdict. Ledger panel with a tier-coloured
      rail, themed from --rr-deal-* (rust for overpriced — never brand red).
   2. Sponsored cards = quiet. The audit found three animated affiliate
      cards out-competing the deal score — the product's own value prop.
      All entry/hover/shimmer animation is neutralised and the brand-heavy
      CTAs become standard quiet buttons. "Sponsored" stays clearly legible
      (compliance) — it just stops performing.
   3. Report link demoted to the sidebar tail (was above the price).
   4. Skeleton loading states (galleries, similar/also-on) — shapes come
      from components.css, geometry-reservation logic from the page.
   ========================================================================== */

/* ---- deal score: the verdict panel ---- */
.deal-score-block {
  position: relative;
  border-radius: var(--rr-radius) !important;
  padding: var(--rr-space-4) var(--rr-space-5) !important;
  text-align: left !important;
  border: 1px solid var(--rr-line) !important;
  border-left-width: 4px !important;
  background: var(--rr-surface) !important;
}
.deal-score-block.great,
.deal-score-block.good  { border-left-color: var(--rr-deal-positive) !important; background: var(--rr-deal-positive-wash) !important; }
.deal-score-block.fair  { border-left-color: var(--rr-deal-neutral) !important;  background: var(--rr-deal-neutral-wash) !important; }
.deal-score-block.high  { border-left-color: var(--rr-deal-warn) !important;     background: var(--rr-deal-warn-wash) !important; }
.deal-score-block.over  { border-left-color: var(--rr-deal-negative) !important; background: var(--rr-deal-negative-wash) !important; }

.deal-score-label {
  font-family: var(--rr-font-mono) !important;
  font-size: var(--rr-text-xs) !important;
  letter-spacing: var(--rr-tracking-wide) !important;
}
/* text on the tinted wash -> the AA-safe ink, never the base tier colour */
.deal-score-block.great .deal-score-label,
.deal-score-block.good  .deal-score-label { color: var(--rr-deal-positive-ink) !important; }
.deal-score-block.fair  .deal-score-label { color: var(--rr-deal-neutral-ink) !important; }
.deal-score-block.high  .deal-score-label { color: var(--rr-deal-warn-ink) !important; }
.deal-score-block.over  .deal-score-label { color: var(--rr-deal-negative-ink) !important; }

.deal-score-icon { display: none !important; /* the rail + label already carry the tier; the emoji tripled it */ }

.deal-score-main {
  font-family: var(--rr-font-mono) !important;
  font-variant-numeric: tabular-nums;
  font-size: var(--rr-text-xl) !important;
  font-weight: var(--rr-fw-bold) !important;
}
.deal-score-block.great .deal-score-main,
.deal-score-block.good  .deal-score-main { color: var(--rr-deal-positive-ink) !important; }
.deal-score-block.fair  .deal-score-main { color: var(--rr-ink) !important; }
.deal-score-block.high  .deal-score-main { color: var(--rr-deal-warn-ink) !important; }
.deal-score-block.over  .deal-score-main { color: var(--rr-deal-negative-ink) !important; }

.deal-score-avg {
  color: var(--rr-muted) !important;
  font-family: var(--rr-font-mono);
  font-size: var(--rr-text-xs) !important;
  font-variant-numeric: tabular-nums;
}

/* ---- deal score: hero rev gauge — "Pass 2.5" full instrument, no numerals ----
   The page's ONE animated moment: arriving from the results grid, the needle
   sweeps from rest (down-left) to the verdict — landing in the rust zone IS the
   overpriced warning. The painted ring is fine here because it renders once; the
   same ring failed the 24-card grid test (badge-options-v3.html). The linear
   track that briefly replaced it on the cards is ALSO gone (retired 2026-07-14):
   the grid's verdict is now a plain text pill on a tinted band, and this hero is
   the only gauge left in the product — the click-in payoff, nothing more.

   Realism level chosen after the real-size test (gauge-realsize.html, 2026-07-14):
   full instrument treatment — 240° sweep, metal bezel, recessed face, glass gloss,
   redline hairline, tapered needle + counterweight, domed hub — but NO NUMERALS.
   Numerals were measured at 8.5px on a 140px dial and 7px on mobile: illegible at
   every diameter the panel can afford. The mobile test proved they aren't needed
   for comprehension (the delta readout inside the face carries the number), so
   they're dropped everywhere rather than split desktop/mobile.

   Geometry is derived from ONE knob, --ds-d (face diameter). Everything else —
   bezel, arc width, tick radii, needle, hub — is a ratio of it, so resizing the
   dial is a one-line change and can't drift out of proportion. The 240° sweep
   needs a ROUND face (today's was a half-dial in a 140x70 box), so the dial box
   is square; --ds-d is tuned so the panel height stays close to the old one.

   Anatomy, back to front: bezel ring -> recessed face -> colour arc -> redline ->
   ticks -> readout -> needle (pointer + tail) -> hub cap -> glass.
   JS sets --ds-angle inline and adds .is-set one frame later so the sweep runs. */
/* Two tier vars, not one, and the split is load-bearing: --ds-c is the GRAPHIC
   colour (arc, needle, hub, drop-shadow — a 3:1 non-text boundary at most),
   --ds-ink is the TEXT colour for anything sitting on the block's tinted wash
   (the readout numeral, the label, the headline figure). The base tier colours
   are not AA-safe as text on their own wash — see the tier triplet note in
   tokens.css — so text must never read --ds-c. */
.deal-score-block { --ds-c: var(--rr-deal-neutral); --ds-ink: var(--rr-deal-neutral-ink); }
.deal-score-block.great,
.deal-score-block.good  { --ds-c: var(--rr-deal-positive); --ds-ink: var(--rr-deal-positive-ink); }
.deal-score-block.high  { --ds-c: var(--rr-deal-warn);     --ds-ink: var(--rr-deal-warn-ink); }
.deal-score-block.over  { --ds-c: var(--rr-deal-negative); --ds-ink: var(--rr-deal-negative-ink); }

/* instrument surface tokens (face/bezel/hub/glass) — dark is the default */
.deal-score-block {
  --ds-face-1: #191A1E; --ds-face-2: #0C0C0F;
  --ds-bezel-1: #4A4B52; --ds-bezel-2: #1C1D21; --ds-bezel-3: #35363C;
  --ds-hub-1: #6A6B73; --ds-hub-2: #2A2B30;
  --ds-glass: rgba(255, 255, 255, 0.055);
}
body.light .deal-score-block {
  --ds-face-1: #FBFBFC; --ds-face-2: #E7E8EB;
  --ds-bezel-1: #FFFFFF; --ds-bezel-2: #B9BAC1; --ds-bezel-3: #DDDEE3;
  --ds-hub-1: #FFFFFF; --ds-hub-2: #9FA0A8;
  --ds-glass: rgba(255, 255, 255, 0.55);
}

/* listing-legacy.css sets flex-direction:column on .deal-score-block — must be
   overridden explicitly here, or the dial stacks above the text. */
.deal-score-block.has-gauge {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--rr-space-5);
}
.ds-gauge { flex: none; }

/* The sweep: 240° centred on 12 o'clock. conic 0deg = 12 o'clock, so the arc
   starts at 360-120=240deg. Zone splits are the same proportions as the linear
   track on the cards (43.75 / 12.5 / 18.75 / 25 of the sweep) — Fair at the top. */
.ds-dial {
  /* The one knob. 104px is chosen, not inherited: the 240° sweep forces a ROUND
     face, which costs panel height no matter what (the old half-dial was 140x70).
     Measured on the real page: d=140 -> 194px panel (+47% vs the old 132px),
     d=122 -> 171px, d=104 -> 151px (+19px), d=88 -> 134px (exact parity but the
     dial reads as a wristwatch, not a hero). 104 is the largest dial that keeps
     the fold cost negligible. Same value on mobile — one dial everywhere. */
  --ds-d: 104px;
  --ds-bezel: calc(var(--ds-d) * 0.045);
  --ds-sweep: 240deg;
  --ds-from: 240deg;
  --ds-z1: 105deg;                            /* 43.75% of 240 */
  --ds-z2: 135deg;                            /* 56.25% */
  --ds-z3: 180deg;                            /* 75% */
  --ds-cy: calc(var(--ds-d) / 2 + var(--ds-bezel) + 2px);
  --ds-rest: -120deg;
  position: relative;
  width:  calc(var(--ds-d) + var(--ds-bezel) * 2 + 4px);
  height: calc(var(--ds-d) + var(--ds-bezel) * 2 + 4px);
}
.ds-layer {
  position: absolute; left: 50%; top: var(--ds-cy);
  width: var(--ds-d); height: var(--ds-d);
  margin-left: calc(var(--ds-d) / -2); margin-top: calc(var(--ds-d) / -2);
  border-radius: 50%;
}
/* bezel sits on a LARGER layer than the face */
.ds-bezel {
  width:  calc(var(--ds-d) + var(--ds-bezel) * 2);
  height: calc(var(--ds-d) + var(--ds-bezel) * 2);
  margin-left: calc((var(--ds-d) + var(--ds-bezel) * 2) / -2);
  margin-top:  calc((var(--ds-d) + var(--ds-bezel) * 2) / -2);
  background: conic-gradient(from 210deg, var(--ds-bezel-1), var(--ds-bezel-2) 25%,
    var(--ds-bezel-3) 50%, var(--ds-bezel-2) 75%, var(--ds-bezel-1));
  -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) / 2), black calc(var(--ds-d) / 2 + 1px) 100%);
          mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) / 2), black calc(var(--ds-d) / 2 + 1px) 100%);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}
.ds-face {
  background: radial-gradient(circle at 50% 38%, var(--ds-face-1) 0%, var(--ds-face-2) 78%);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.45), inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}
body.light .ds-face { box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.10), inset 0 0 0 1px rgba(0, 0, 0, 0.06); }
.ds-arc {
  background: conic-gradient(from var(--ds-from),
    var(--rr-deal-positive) 0deg var(--ds-z1),
    var(--rr-deal-neutral)  var(--ds-z1) var(--ds-z2),
    var(--rr-deal-warn)     var(--ds-z2) var(--ds-z3),
    var(--rr-deal-negative) var(--ds-z3) var(--ds-sweep),
    transparent var(--ds-sweep) 360deg);
  -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) * 0.405), black calc(var(--ds-d) * 0.405 + 1px) 100%);
          mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) * 0.405), black calc(var(--ds-d) * 0.405 + 1px) 100%);
}
/* redline: hairline at the rim over the overpriced zone only */
.ds-redline {
  background: conic-gradient(from var(--ds-from), transparent 0deg var(--ds-z3),
    var(--rr-deal-negative) var(--ds-z3) var(--ds-sweep), transparent var(--ds-sweep) 360deg);
  -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) / 2 - 2px), black calc(var(--ds-d) / 2 - 1px) 100%);
          mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) / 2 - 2px), black calc(var(--ds-d) / 2 - 1px) 100%);
}
/* graduations — minor every 20°, major every 60° (on the zone boundaries).
   Masked into a band inside the colour arc; the conic half of the mask clips
   them to the live sweep so none appear in the dial's dead 120°. */
.ds-ticks-minor {
  background: repeating-conic-gradient(from var(--ds-from), var(--rr-muted) 0deg 0.7deg, transparent 0.7deg 20deg);
  -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) * 0.304), black calc(var(--ds-d) * 0.304 + 1px) calc(var(--ds-d) * 0.361), transparent calc(var(--ds-d) * 0.361 + 1px) 100%),
                conic-gradient(from var(--ds-from), black 0deg var(--ds-sweep), transparent var(--ds-sweep) 360deg);
          mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) * 0.304), black calc(var(--ds-d) * 0.304 + 1px) calc(var(--ds-d) * 0.361), transparent calc(var(--ds-d) * 0.361 + 1px) 100%),
                conic-gradient(from var(--ds-from), black 0deg var(--ds-sweep), transparent var(--ds-sweep) 360deg);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
  opacity: 0.7;
}
.ds-ticks-major {
  background: repeating-conic-gradient(from var(--ds-from), var(--rr-ink-2) 0deg 1.5deg, transparent 1.5deg 60deg);
  -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) * 0.272), black calc(var(--ds-d) * 0.272 + 1px) calc(var(--ds-d) * 0.361), transparent calc(var(--ds-d) * 0.361 + 1px) 100%),
                conic-gradient(from var(--ds-from), black 0deg calc(var(--ds-sweep) + 1.5deg), transparent calc(var(--ds-sweep) + 1.5deg) 360deg);
          mask: radial-gradient(circle at 50% 50%, transparent 0 calc(var(--ds-d) * 0.272), black calc(var(--ds-d) * 0.272 + 1px) calc(var(--ds-d) * 0.361), transparent calc(var(--ds-d) * 0.361 + 1px) 100%),
                conic-gradient(from var(--ds-from), black 0deg calc(var(--ds-sweep) + 1.5deg), transparent calc(var(--ds-sweep) + 1.5deg) 360deg);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
}
/* needle: tapered pointer + counterweight tail, rotating as one layer about the
   face centre. Parks at the bottom of the sweep, sweeps to the verdict. */
.ds-needle {
  transform: rotate(var(--ds-rest));
  transition: transform 1.05s cubic-bezier(0.34, 1.15, 0.38, 1) 0.12s;
}
.deal-score-block.is-set .ds-needle { transform: rotate(var(--ds-angle, 0deg)); }
.ds-pointer, .ds-tail { position: absolute; left: 50%; background: var(--ds-c); }
.ds-pointer {
  bottom: 50%;
  width: calc(var(--ds-d) * 0.063); height: calc(var(--ds-d) * 0.367);
  margin-left: calc(var(--ds-d) * -0.0315);
  clip-path: polygon(50% 0%, 100% 22%, 62% 100%, 38% 100%, 0% 22%);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}
.ds-tail {
  top: 50%;
  width: calc(var(--ds-d) * 0.095); height: calc(var(--ds-d) * 0.108);
  margin-left: calc(var(--ds-d) * -0.0475);
  border-radius: 0 0 999px 999px;
}
.ds-hub {
  position: absolute; left: 50%; top: var(--ds-cy);
  width: calc(var(--ds-d) * 0.101); height: calc(var(--ds-d) * 0.101);
  margin-left: calc(var(--ds-d) * -0.0505); margin-top: calc(var(--ds-d) * -0.0505);
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, var(--ds-hub-1), var(--ds-hub-2) 72%);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.2);
}
.ds-glass {
  background: linear-gradient(160deg, var(--ds-glass) 0%, transparent 42%);
  pointer-events: none;
}
/* The delta prints INSIDE the face, in the dead space below the hub — which is
   where a real cluster puts its digital display, and the only place it can go now
   that the face is round (a full circle can't hang a readout underneath without
   overlapping it). Held at a FIXED size, not scaled off --ds-d: it's the one
   number a user actually reads, and it was the first thing to die when the
   numerals were scaled down. */
.ds-readout {
  position: absolute; left: 50%; top: calc(var(--ds-cy) + var(--ds-d) * 0.26);
  transform: translate(-50%, -50%);
  font: var(--rr-fw-bold) 0.95rem var(--rr-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ds-ink); white-space: nowrap; z-index: 3;
  opacity: 0; transition: opacity 0.35s ease 0.7s;
}
.deal-score-block.is-set .ds-readout { opacity: 1; transform: translate(-50%, -50%); }
.ds-text { min-width: 0; }
/* beyond-scale verdicts (clamped at either end): quiet pulse after landing */
.deal-score-block.is-rail.is-set .ds-needle,
.deal-score-block.is-rail.is-set .ds-hub { animation: ds-rail-pulse 2.2s ease-in-out 1.4s infinite; }
@keyframes ds-rail-pulse {
  0%, 100% { filter: drop-shadow(0 0 0 transparent); }
  50%      { filter: drop-shadow(0 0 5px var(--ds-c)); }
}
@media (prefers-reduced-motion: reduce) {
  .ds-needle { transition: none !important; transform: rotate(var(--ds-angle, 0deg)) !important; }
  .ds-readout { transition: none !important; opacity: 1 !important; }
  .deal-score-block.is-rail .ds-needle,
  .deal-score-block.is-rail .ds-hub { animation: none !important; }
}

/* Narrow: a dial beside text squeezes the verdict line to two words per row, so
   stack — dial first (it's the hero), text under it. The dial itself is NOT
   resized here: it's the same 104px instrument as desktop (the old half-dial had
   to shrink to 116px because a 140px-wide one crowded the stacked panel; a 104px
   round one doesn't). One dial, one size, everywhere. */
@media (max-width: 519px) {
  .deal-score-block.has-gauge { flex-direction: column; align-items: stretch; gap: var(--rr-space-3); }
  .ds-gauge { align-self: center; }
}


/* ---- sponsored cards: still present, no longer a show ---- */
.aff-card,
.aff-card:nth-child(1),
.aff-card:nth-child(2) {
  animation: none !important;
  transition: border-color 0.15s ease !important;
  background: var(--rr-surface) !important;
  border: 1px solid var(--rr-line) !important;
  border-radius: var(--rr-radius) !important;
  box-shadow: none !important;
}
.aff-card:hover { transform: none !important; box-shadow: none !important; border-color: var(--rr-line-strong) !important; }
.aff-accent-bar,
.aff-card .aff-accent-bar {
  animation: none !important;
  background: var(--rr-line-strong) !important;
  height: 2px !important;
}
.aff-card .aff-feature { animation: none !important; opacity: 1 !important; }
.aff-label {
  font-family: var(--rr-font-mono) !important;
  font-size: var(--rr-text-xs) !important;
  letter-spacing: var(--rr-tracking-wide) !important;
  text-transform: uppercase !important;
  color: var(--rr-muted) !important;
}
/* CTA buttons carry inline brand colours (#e01a1a / #f97316 / #0d9488) —
   author !important beats inline style. One quiet outline button for all. */
.aff-btn {
  background: transparent !important;
  border: 1px solid var(--rr-line-strong) !important;
  color: var(--rr-ink) !important;
  border-radius: var(--rr-radius-sm) !important;
  font-weight: var(--rr-fw-semibold) !important;
  box-shadow: none !important;
}
.aff-btn:hover { border-color: var(--rr-ink-2) !important; background: var(--rr-surface-2) !important; }
.aff-badge {
  background: var(--rr-surface-2) !important;
  border: 1px solid var(--rr-line) !important;
  color: var(--rr-ink-2) !important;
}

/* ---- report link: sidebar tail, quiet ---- */
.rr-report-link {
  background: none;
  border: none;
  color: var(--rr-muted);
  font-size: var(--rr-text-xs);
  font-family: var(--rr-font-sans);
  cursor: pointer;
  padding: var(--rr-space-2) 0;
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.rr-report-link:hover { color: var(--rr-ink-2); }
/* Mobile dissolves the sidebar (display:contents) and orders every child
   explicitly — without an order the report link jumps to the top (order:0).
   Last content slot before similar/also-on: */
@media (max-width: 899px) {
  .rr-report-link { order: 13; }
}

/* ---- similar-listings cards ---- */
/* Image plate follows the theme (legacy hardcoded a dark plate that light
   mode never overrode) */
.similar-section .card-img { background: var(--rr-surface-2) !important; }
/* Legacy "first tag is red" convention — red is brand + primary action only
   in this direction; a year chip is neither. */
.similar-section .tag.red {
  background: var(--rr-surface-2) !important;
  border-color: var(--rr-line) !important;
  color: var(--rr-ink-2) !important;
}

/* ---- loading states ---- */
.gallery-main.rr-skel img { opacity: 0; }
.gallery-main img { transition: opacity 0.2s ease; }
.card-img.rr-skel img { opacity: 0; }

/* Skeleton page: mirrors .listing-layout's real rendered geometry — same
   grid template + 2.5rem gap as legacy.css's .listing-layout, block heights
   taken from measured real content (scripts/preview-shots/measure-skel.js
   verifies the match; run it after touching either side). */
.rr-skel-backrow { height: 15px; width: 130px; margin-bottom: 1.5rem; }
.rr-listing-skel {
  display: grid;
  grid-template-columns: 2fr minmax(280px, 1fr);
  gap: 2.5rem;
  align-items: start;
  position: relative;
}
.rr-listing-skel-gallery-cell { grid-column: 1; margin-bottom: 24px; }
.rr-skel-gallery { height: 450px; border-radius: 4px; }
.rr-skel-thumbs { display: flex; gap: 0.5rem; margin-top: 0.5rem; }
.rr-skel-thumb { width: 80px; height: 60px; border-radius: var(--rr-radius-sm); flex: none; }
.rr-listing-skel-hero { grid-column: 1; }
.rr-skel-title-block { height: 118px; }
.rr-skel-price-block { height: 88px; margin-bottom: 28px; }
/* One chip per real key stat (year/mileage/gearbox/fuel/body), widths from
   rendered content so the wrap count matches at narrow widths too */
.rr-skel-stats { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 24px; }
.rr-skel-stat { height: 27px; border-radius: var(--rr-radius-sm); }
.rr-skel-stat.s1 { width: 92px; }
.rr-skel-stat.s2 { width: 165px; }
.rr-skel-stat.s3 { width: 151px; }
.rr-skel-stat.s4 { width: 99px; }
.rr-skel-stat.s5 { width: 134px; }
.rr-skel-deal { height: 151px; border-radius: var(--rr-radius); }  /* rev-gauge panel, measured */
/* Absolutely positioned so its (tall) height can't inflate the grid's row
   tracks and push the hero cell down — the real page sidesteps the same
   problem with grid-row: 1 / span 20 across its many main-column sections. */
.rr-listing-skel-side {
  position: absolute;
  top: 0;
  right: 0;
  width: calc((100% - 2.5rem) / 3);
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
@media (max-width: 899px) {
  .rr-listing-skel { display: block; }
  .rr-listing-skel-gallery-cell { margin-bottom: 20px; }
  .rr-skel-gallery { height: 240px; }
  .rr-skel-thumb { width: 64px; height: 48px; }
  .rr-skel-title-block { height: 57px; }
  .rr-skel-price-block { height: 35px; }
  .rr-skel-stat.s1 { width: 84px; }
  .rr-skel-stat.s2 { width: 156px; }
  .rr-skel-stat.s3 { width: 141px; }
  .rr-skel-stat.s4 { width: 93px; }
  .rr-skel-stat { height: 23px; }
  .rr-skel-stat.s5 { width: 123px; }
  .rr-skel-deal { height: 285px; }  /* stacked rev-gauge panel, measured */
  .rr-listing-skel-side { position: static; width: auto; margin-top: 28px; }
}
.rr-visually-hidden {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
