/**
 * DealerPro Elite — Single listing page styles
 *
 * Source mockup(s):
 *   - mockups/heavy-equipment/mockup-1C-single-listing.html
 *   - mockups/cars/mockup-2C-car-single-listing.html
 * Loaded conditionally on single-listing.php via wp_enqueue_style.
 *
 * @package DealerPro_Elite
 * @since 2.0.0
 */

/* ─── LISTING LAYOUT (gallery + sticky sidebar) ───────── */
.listing {
  padding: var(--s-8) 0 var(--s-6);
  /* Order matters: `hidden` first as a fallback for Safari < 15.4. Modern
     browsers override with `clip` (doesn't establish a containing block,
     so position:sticky on .listing__sidebar still works). Mirrors base.css. */
  overflow-x: hidden;
  overflow-x: clip;
  animation: fade-in-up 600ms ease-out backwards;
}
.listing__main {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: var(--s-10);
  align-items: start;
  min-width: 0;
}
.listing__main > * { min-width: 0; }
.listing__make {
  font-size: var(--t-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 2px;
  color: var(--accent);
}
.listing__title {
  font-size: clamp(24px, 3vw, 32px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--text);
  margin: var(--s-2) 0 0;
  /* "Hydraulic Excavator" was breaking mid-word at 320-375px. Modern
     overflow-wrap respects soft-break boundaries before falling back. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* iPad portrait (768–1024px): keep the 2-col gallery+inquiry layout but
   shift the ratio so the gallery isn't crammed. Below 768px collapses to
   single column (mobile). Was: full collapse at ≤1024px — wasted the
   tablet sweet spot, sidebar landed below the gallery. */
@media (min-width: 768px) and (max-width: 1024px) {
  .listing__main {
    grid-template-columns: 1.2fr 1fr;
    gap: var(--s-6);
  }
}
@media (max-width: 767px) {
  .listing__main {
    grid-template-columns: 1fr;
    gap: var(--s-8);
  }
  /* Center only the title/header block — was previously cascading
     text-align:center down to spec lists, paragraphs, and CTAs which
     looked broken on tablet. */
  .listing__head,
  .listing__head .listing__title,
  .listing__head .listing__make,
  .listing__head .year-badge,
  .listing__head .listing-badge {
    text-align: center;
  }
  .listing__make { display: block; }
}
@media (max-width: 480px) {
  .listing { padding: var(--s-6) 0 var(--s-5); }
}

/* ─── GALLERY ──────────────────────────────────────────── */
.gallery {
  min-width: 0;
  max-width: 100%;
}
.gallery__main {
  /* 3/2 landscape ratio — was 4/3 which felt too tall on the listing
     page. 3/2 matches the proportions of most camera shots and gives a
     less crowded layout when the inquiry sidebar sits next to it. */
  aspect-ratio: 3 / 2;
  border-radius: var(--r-lg);
  background:
    linear-gradient(135deg, var(--accent-soft), transparent 50%),
    linear-gradient(45deg, var(--bg-3), var(--bg-2));
  border: 1px solid var(--border-strong);
  position: relative;
  overflow: hidden;
  margin-bottom: var(--s-3);
  cursor: zoom-in;
}
/* v2.0.60: native <button> wrapper around the hero image (replaces the
   previous <div role="button"> JS hack). Must reset all native button
   chrome (background, border, padding, font inheritance) so visually
   nothing changes from the previous div implementation. */
.gallery__main-trigger {
  all: unset;
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  cursor: zoom-in;
  box-sizing: border-box;
}
.gallery__main-trigger:focus-visible {
  outline: var(--ring);
  outline-offset: -2px;
  border-radius: var(--r-lg);
}
.gallery__main-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Photo-switch loading state — only shows when the target image isn't yet in
   cache (rare, thanks to adjacent + hover + progressive preloading). Dims the
   current frame and spins a loader so changing photos reads as "loading" not
   "frozen on the old photo". Class is toggled by the gallery script. */
.gallery__main.is-loading .gallery__main-image {
  opacity: 0.5;
  transition: opacity 120ms ease;
}
.gallery__main.is-loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 36px;
  height: 36px;
  margin: -18px 0 0 -18px;
  border: 3px solid rgba(255, 255, 255, 0.45);
  border-top-color: #fff;
  border-radius: 50%;
  animation: dpelite-gallery-spin 0.7s linear infinite;
  pointer-events: none;
  z-index: 3;
}
@keyframes dpelite-gallery-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .gallery__main.is-loading::after { animation: none; }
}
.gallery__main--placeholder {
  cursor: default;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  color: var(--text-3);
  text-align: center;
}
.gallery__placeholder-icon {
  width: 64px;
  height: 64px;
  opacity: 0.5;
}
.gallery__placeholder-label {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-2);
}
.gallery__placeholder-sub {
  font-size: var(--t-sm);
  color: var(--text-3);
}
.gallery__thumb--placeholder {
  background: linear-gradient(45deg, var(--bg-3), var(--bg-2));
  border: 1px solid var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  cursor: default;
}
.gallery__thumb--placeholder svg {
  width: 24px;
  height: 24px;
  opacity: 0.4;
}
.gallery__counter {
  position: absolute;
  bottom: var(--s-4);
  right: var(--s-4);
  background: rgba(var(--bg-rgb), 0.85);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-strong);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 600;
  padding: 6px 12px;
  border-radius: var(--r-xs);
  color: var(--text);
}
.gallery__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: var(--r-full);
  background: rgba(var(--bg-rgb), 0.85);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text);
  cursor: pointer;
  transition: var(--transition);
  z-index: 2;
}
.gallery__nav:hover {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
}
.gallery__nav--prev { left: var(--s-4); }
.gallery__nav--next { right: var(--s-4); }
.gallery__nav svg { width: 18px; height: 18px; }
.gallery__share {
  position: absolute;
  top: var(--s-4);
  right: var(--s-4);
  width: 44px;
  height: 44px;
  border-radius: var(--r-full);
  background: rgba(var(--bg-rgb), 0.85);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text);
  cursor: pointer;
  transition: var(--transition);
  z-index: 2;
}
.gallery__share:hover {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
}
.gallery__share svg { width: 18px; height: 18px; }

.gallery__thumbs {
  /* Single-row horizontal strip per dealer feedback ("vreau ca sectiunea
     cu media de sub featured image mai compacta, sa fie un rand").
     Listings with 17+ photos used to render 4 rows of thumbnails which
     pushed the page content way down. Now a horizontal scrollable strip
     with scroll-snap — visible thumbs at a glance, scroll to see more. */
  display: flex;
  flex-wrap: nowrap;
  gap: var(--s-2);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  padding-bottom: var(--s-2); /* room for the scrollbar so it doesn't overlap thumbs */
}
.gallery__thumbs::-webkit-scrollbar { height: 6px; }
.gallery__thumbs::-webkit-scrollbar-track { background: transparent; }
.gallery__thumbs::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: var(--r-full);
}
.gallery__thumb {
  flex: 0 0 84px; /* fixed-width tile — same size at any viewport */
  width: 84px;
  height: 64px;
  aspect-ratio: auto;
  scroll-snap-align: start;
  border-radius: var(--r-sm);
  background: var(--bg-2);
  border: 2px solid transparent;
  cursor: pointer;
  transition: var(--transition);
  position: relative;
  overflow: hidden;
}
@media (max-width: 720px) {
  .gallery__thumb { flex: 0 0 72px; width: 72px; height: 54px; }
}
.gallery__thumb::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(135deg, var(--accent-soft), transparent 50%),
    linear-gradient(45deg, var(--bg-3), var(--bg-2));
}
.gallery__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  position: relative;
  z-index: 1;
}
.gallery__thumb--active {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.gallery__thumb:hover:not(.gallery__thumb--active) {
  border-color: var(--border-strong);
}
.gallery__thumbs-wrap { position: relative; }
.gallery__thumbs-meta { display: none; }

@media (max-width: 640px) {
  .gallery__main {
    aspect-ratio: 16/11;
    max-height: 50vh;
  }
  .gallery__thumbs {
    display: flex;
    grid-template-columns: none;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin-top: var(--s-3);
    padding-bottom: 4px;
  }
  .gallery__thumbs::-webkit-scrollbar { display: none; }
  .gallery__thumb {
    flex: 0 0 80px;
    width: 80px;
    height: 64px;
    aspect-ratio: auto;
    scroll-snap-align: start;
    animation: none !important;
  }
  .gallery__thumbs-meta {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    margin-top: var(--s-3);
    padding: 0 var(--s-1);
  }
  .gallery__thumbs-progress {
    height: 3px;
    background: var(--border);
    border-radius: 2px;
    overflow: hidden;
    position: relative;
  }
  .gallery__thumbs-progress-fill {
    height: 100%;
    width: 20%;
    background: var(--accent);
    border-radius: 2px;
    transition: width 200ms ease;
  }
  .gallery__thumbs-count {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    font-size: var(--t-xs);
    color: var(--text-muted);
    font-weight: 500;
    letter-spacing: 0.3px;
  }
  .gallery__thumbs-count strong {
    color: var(--accent);
    font-family: var(--font-mono);
    font-weight: 700;
  }
  .gallery__thumbs-count svg {
    width: 13px;
    height: 13px;
    color: var(--text-faint);
  }
}
@media (max-width: 375px) {
  .gallery__thumb {
    flex-basis: 72px;
    width: 72px;
    height: 58px;
  }
}

/* ─── LIGHTBOX (full-screen image viewer) ─────────────── */
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.lightbox {
  position: fixed;
  inset: 0;
  /* v2.0.62: bumped from --z-overlay (500) to --z-modal (1000) so the
     lightbox always wins stacking against the mobile-drawer overlay
     (also at z-overlay). Previously a tap on a gallery photo while
     the drawer was open landed somewhere between the drawer panel
     (z-modal) and the drawer overlay (z-overlay) — DOM-order
     stacking gave the lightbox the win on most browsers, but the
     equal z-index made the order unpredictable on Firefox. */
  z-index: var(--z-modal);
  background: rgba(0, 0, 0, 0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--s-5);
  animation: fade-in 200ms ease-out;
}
.lightbox.is-open { display: flex; }
.lightbox__stage {
  position: relative;
  width: 100%;
  max-width: 1400px;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lightbox__img {
  /* Native aspect ratio — let the image be whatever shape it is. v2.0.33
     and earlier had `aspect-ratio: 16/10` + `width: min(100%, 1200px)`
     which FORCED every photo into 16:10, so a 16:9 truck shot rendered
     stretched horizontally (dealer report: "tot arata lata"). Now: image
     fits within the viewport on both axes, preserves its native ratio,
     no stretching. (Fixed v2.0.34.) */
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--r-md);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
}
.lightbox__close {
  position: absolute;
  top: var(--s-4);
  right: var(--s-4);
  width: 44px;
  height: 44px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 150ms ease;
}
.lightbox__close:hover {
  background: var(--cta);
  border-color: var(--cta);
}
.lightbox__close svg {
  width: 20px;
  height: 20px;
}
.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 52px;
  height: 52px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 150ms ease;
}
.lightbox__nav:hover {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
}
.lightbox__nav--prev { left: var(--s-4); }
.lightbox__nav--next { right: var(--s-4); }
.lightbox__nav svg {
  width: 22px;
  height: 22px;
}
.lightbox__counter {
  position: absolute;
  bottom: var(--s-4);
  left: 50%;
  transform: translateX(-50%);
  padding: 8px 16px;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: var(--r-full);
  color: var(--text);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.05em;
}
@media (max-width: 640px) {
  .lightbox { padding: var(--s-3); }
  /* Apple HIG + Material both mandate 44×44 minimum touch targets.
     Previously 40×40 here dropped below that on the smallest viewports
     — exactly where touch precision is worst. v2.0.59: bumped back to 44. */
  .lightbox__close {
    top: var(--s-3);
    right: var(--s-3);
    width: 44px;
    height: 44px;
  }
  .lightbox__nav { width: 44px; height: 44px; }
  .lightbox__nav--prev { left: var(--s-2); }
  .lightbox__nav--next { right: var(--s-2); }
}
@media (prefers-reduced-motion: reduce) {
  .lightbox { animation: none; }
}

/* ─── SIDEBAR (natural flow, no sticky) ───────────────────
   An earlier iteration pinned the action panel via `.sidebar__sticky`
   (May 2026). The dealer flagged it as "breaks everything" — the
   pinned panel competed visually with gallery + specs. Reverted to
   plain flow: sidebar scrolls with the page like a normal column.
   Sticky CTA bar at the bottom of the viewport (separate component)
   already handles "always-visible action" on long scrolls. */
.sidebar {
  display: grid;
  gap: var(--s-5);
  min-width: 0;
  max-width: 100%;
}
.sidebar > * { min-width: 0; }
.sidebar__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
}
@media (max-width: 1024px) {
  .sidebar__head { justify-content: center; }
}

.year-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px 14px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  border-radius: var(--r-full);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 700;
  color: var(--accent);
  letter-spacing: 1px;
}
/* Listing-level badge (Featured / New Arrival / Low Hours) — sits next to
   the year-badge in the sidebar head. Uses --cta color to differentiate
   from the year (which is accent-themed). */
.listing-badge {
  display: inline-flex;
  align-items: center;
  padding: 6px 12px;
  background: var(--cta-soft, rgba(220, 38, 38, 0.12));
  border: 1px solid var(--cta);
  border-radius: var(--r-full);
  font-size: var(--t-2xs);
  font-weight: 800;
  color: var(--cta);
  letter-spacing: 1.5px;
  text-transform: uppercase;
  margin-left: var(--s-2);
}
.icon-btn {
  /* WCAG 2.5.5 / Apple HIG minimum touch target = 44px. Was 40 → users
     mistapped on phones. SVG stays 18px; the box just grew 4px. */
  width: 44px;
  height: 44px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-soft);
  cursor: pointer;
  transition: var(--transition);
}
.icon-btn:hover {
  background: var(--bg-3);
  border-color: var(--accent-border);
  color: var(--accent);
}
.icon-btn svg { width: 18px; height: 18px; }
.icon-btn--save:hover svg { color: var(--cta); }
.icon-btn--save.is-saved {
  background: var(--cta-soft);
  border-color: var(--cta);
  color: var(--cta);
}
.icon-btn--save.is-saved svg { fill: var(--cta); }
.icon-btn-group {
  display: flex;
  gap: var(--s-2);
}
@media (max-width: 1024px) {
  .icon-btn-group { justify-content: center; }
}

/* ─── PRICE BLOCK ──────────────────────────────────────── */
.price-block {
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: var(--s-5) var(--s-6);
}
@media (max-width: 480px) {
  .price-block { padding: var(--s-4) var(--s-4); }
}
.price-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  flex-wrap: wrap;
}
@media (max-width: 1024px) {
  .price-row { justify-content: center; }
}
.price-block__lbl {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 2px;
  color: var(--text-muted);
  font-weight: 600;
}
.price-block__stk {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-faint);
}
.price-block__price {
  font-family: var(--font-mono);
  font-size: clamp(36px, 4vw, 48px);
  font-weight: 800;
  color: var(--accent);
  line-height: 1;
  letter-spacing: -0.02em;
  margin-top: var(--s-2);
}
.price-block__call {
  font-family: 'Inter', -apple-system, system-ui, 'Segoe UI', Roboto, sans-serif !important;
  font-size: clamp(24px, 2.8vw, 32px);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--accent);
}

/* v2.0.104 — Variant A: struck asking price + "save $X" sit ABOVE the net
   price. Rendered only when there's a real reduction (discount and/or sale). */
.price-block__savings {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-top: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
}
@media (max-width: 1024px) {
  .price-block__savings { justify-content: center; }
}
.price-block__strike {
  color: var(--text-faint);
  text-decoration: line-through;
}
.price-block__save {
  color: var(--success);
  font-weight: 700;
  letter-spacing: 0.3px;
}
/* v2.0.105 — small "X% OFF" pill next to the savings, so the buyer sees the
   discount rate (parity with the inventory-card badge). */
.price-block__off {
  font-family: var(--font-sans);
  font-size: var(--t-2xs);
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 2px 8px;
  border-radius: var(--r-full);
}

/* ─── SOLD STATE ───────────────────────────────────────
   Single-source-of-truth via dpelite_listing_is_sold(). When sold:
   - .price-block--sold demotes the colour palette (no accent yellow)
   - .price-block__sold-badge is the small "SOLD" pill in the price row
   - .cta-stack--sold + .cta-sold-msg sit under the price in place of the
     primary inquiry/buy-now CTAs
   - .inquiry-sold-actions is the right-column replacement for the form */
.price-block--sold {
  border-color: rgba(220, 38, 38, 0.45);
  background: linear-gradient(180deg, rgba(220, 38, 38, 0.06), transparent);
}
.price-block--sold .price-block__price {
  color: var(--text-soft);
  text-decoration: line-through;
  text-decoration-color: rgba(220, 38, 38, 0.5);
  text-decoration-thickness: 2px;
}
.price-block__sold-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  background: var(--cta);
  color: var(--cta-fg);
  font-size: var(--t-2xs, 11px);
  font-weight: 800;
  letter-spacing: 0.12em;
  border-radius: var(--r-sm);
  text-transform: uppercase;
}
.cta-stack--sold {
  display: grid;
  gap: var(--s-3);
}
.cta-sold-msg {
  font-size: var(--t-sm);
  color: var(--text-soft);
  line-height: 1.55;
  margin: 0;
  padding: var(--s-3);
  background: var(--bg-2);
  border-radius: var(--r-md);
  border-left: 3px solid var(--cta);
}
.inquiry-sold-actions {
  display: grid;
  gap: var(--s-3);
  margin-top: var(--s-4);
}

/* ─── CTA STACK / ROW ──────────────────────────────────── */
.cta-stack {
  display: grid;
  gap: var(--s-3);
}
.cta-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-2);
}
@media (max-width: 540px) {
  .cta-row { grid-template-columns: 1fr; }
}

/* ─── RESERVE NOW CTA ───────────────────────────────────
   v2.0.104 — minimalist. The price + "save $X" story now lives in the price
   block above (Variant A); the Reserve Now part renders ONLY this button, as a
   full-width primary CTA inside .cta-stack (matching "Ask About This Unit").
   The old card chrome, left-edge stripe, countdown ribbon, compare line, pitch
   and trust chips were removed. .btn--primary supplies the gold fill — this
   rule just makes it span full width and animates the arrow on hover. */
.buy-now__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  width: 100%;
  font-weight: 700;
  letter-spacing: 0.3px;
}
.buy-now__cta svg {
  transition: transform 220ms cubic-bezier(0.4, 0, 0.2, 1);
}
.buy-now__cta:hover svg { transform: translateX(4px); }

/* `.trust-card` styles intentionally NOT redefined here — canonical block lives
   in components.css (loaded site-wide). Used by single-listing AND tpl-buy-now. */

/* ─── SPECS TABLE ──────────────────────────────────────── */
.specs {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.specs__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--border);
  background: var(--bg-2);
}
.specs__title {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 2px;
  color: var(--text-muted);
  font-weight: 700;
}
.specs__count {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--accent);
  font-weight: 700;
}
/* v2.0.81 — specs markup switched from <div>/<span> to <dl>/<dt>/<dd> for
   WCAG 1.3.1 (Info and Relationships). The class-based selectors below
   keep working unchanged, but the browser-default margins on <dl> and
   <dd> would have inserted spurious whitespace and broken the flex
   layout. Reset them at the source of truth here. */
.specs__list {
  margin: 0;
  padding: 0;
}
.specs__row-lbl,
.specs__row-val {
  margin: 0;
}
.specs__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-bottom: 1px solid var(--border);
  font-size: var(--t-sm);
  min-width: 0;
}
.specs__row:last-child { border-bottom: 0; }
.specs__row-lbl {
  color: var(--text-muted);
  font-weight: 500;
  flex-shrink: 0;
}
.specs__row-val {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--text);
  min-width: 0;
  text-align: right;
  word-break: break-word;
}
.specs__toggle {
  width: 100%;
  padding: var(--s-3) var(--s-5);
  background: var(--bg-2);
  border-top: 1px solid var(--border);
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 1.5px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  cursor: pointer;
  transition: var(--transition);
}
.specs__toggle:hover { background: var(--bg-3); }
.specs__toggle svg {
  width: 12px;
  height: 12px;
  transition: var(--transition);
}
@media (max-width: 480px) {
  .specs__row {
    padding: var(--s-3) var(--s-4);
    font-size: var(--t-xs);
  }
}
.specs__list > .specs__row {
  animation: fade-in-up 400ms ease-out backwards;
}
.specs__list > *:nth-child(2) { animation-delay: 60ms; }
.specs__list > *:nth-child(3) { animation-delay: 120ms; }
.specs__list > *:nth-child(4) { animation-delay: 180ms; }
.specs__list > *:nth-child(5) { animation-delay: 240ms; }
.specs__list > *:nth-child(6) { animation-delay: 300ms; }
.specs__list > *:nth-child(n+7) { animation-delay: 360ms; }
@media (prefers-reduced-motion: reduce) {
  .specs__list > * { animation-delay: 0ms !important; }
}

/* ─── SALES REP MINI CARD ──────────────────────────────── */
.rep-card {
  background:
    radial-gradient(ellipse 80% 100% at 100% 0%, var(--accent-soft), transparent 70%),
    var(--bg-1);
  border: 1px solid var(--accent-border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-4);
  align-items: center;
}
.rep-card__photo {
  width: 64px;
  height: 64px;
  border-radius: var(--r-full);
  background:
    linear-gradient(135deg, var(--accent-soft), transparent),
    linear-gradient(45deg, var(--bg-3), var(--bg-4));
  border: 2px solid var(--accent);
  position: relative;
  overflow: hidden;
}
.rep-card__lbl {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--text-muted);
  font-weight: 600;
  margin-bottom: 2px;
}
.rep-card__name {
  font-size: var(--t-md);
  font-weight: 700;
  margin-bottom: var(--s-1);
}
.rep-card__phone {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--accent);
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
}
.rep-card__phone svg {
  width: 12px;
  height: 12px;
}
@media (max-width: 1024px) {
  .rep-card {
    grid-template-columns: 1fr;
    text-align: center;
  }
  .rep-card__photo { margin: 0 auto; }
}

/* ─── LISTING LEFT COLUMN (gallery + description stack) ──
   v2.0.71 — wraps the gallery + description so they sit in the
   left grid track of .listing__main. Previously description was
   in a separate full-width section below, leaving empty space
   under the gallery whenever the right sidebar (specs + buyer
   protection + CTAs) overflowed downward.
   .listing__main is the parent grid; this is just a flex stack
   that fills its column with gap-controlled vertical rhythm. */
.listing__col-left {
  display: flex;
  flex-direction: column;
  gap: var(--s-6);
  min-width: 0;
}
.listing__col-left > * { min-width: 0; }

/* ─── INQUIRY SECTION (centered focused-CTA card) ────────
   v2.0.71 — was .content-grid (2-col: description + inquiry).
   Description moved up into .listing__col-left, so this
   section now centers the inquiry form alone with a narrower
   max-width — reads as a deliberate CTA rather than half a
   broken 2-col grid. */
.inquiry-section {
  max-width: 720px;
  margin: 0 auto;
}

.desc-block {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--s-8);
  animation: fade-in-up 600ms ease-out backwards;
}
.desc-block__head {
  margin-bottom: var(--s-5);
  padding-bottom: var(--s-5);
  border-bottom: 1px solid var(--border);
}
.desc-block__content {
  font-size: var(--t-base);
  color: var(--text-soft);
  line-height: 1.75;
  position: relative;
}
.desc-block__content p { margin-bottom: var(--s-4); }
.desc-block__content p:last-child { margin-bottom: 0; }
.desc-block__content strong {
  color: var(--text);
  font-weight: 700;
}
.desc-block__content ul,
.desc-block__content ol {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
}
.desc-block__content li {
  position: relative;
  padding-left: var(--s-4);
  color: var(--text-soft);
  line-height: 1.6;
}
.desc-block__content li::before {
  content: '•';
  position: absolute;
  left: 0;
  top: 0;
  color: var(--text-faint);
  font-weight: 700;
}
.desc-block__content a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.desc-block__content a:hover { color: var(--accent-dark); }

/* ─── INQUIRY FORM (sticky sidebar on listing) ────────── */
.inquiry {
  background:
    radial-gradient(ellipse 60% 100% at 50% 0%, var(--accent-soft), transparent 70%),
    var(--bg-2);
  border: 1px solid var(--accent-border);
  border-radius: var(--r-xl);
  padding: var(--s-7);
  position: sticky;
  /* Offset matches the sticky header (--header-h in tokens.css) so the
     inquiry sidebar pins flush below the nav. Hardcoded 90px was too
     small after the custom-logo size bump (header is now ~128px tall). */
  top: calc(var(--header-h) + var(--s-3));
  animation: fade-in-up 600ms ease-out backwards;
}
.admin-bar .inquiry { top: calc(var(--header-h) + 32px + var(--s-3)); }
@media (max-width: 782px) {
  .admin-bar .inquiry { top: calc(var(--header-h-mobile) + 46px + var(--s-3)); }
}
.inquiry__head {
  text-align: center;
  margin-bottom: var(--s-5);
}
.inquiry__title {
  font-size: var(--t-md) !important;
  margin-bottom: var(--s-3);
}
.inquiry__sub {
  font-size: var(--t-sm);
  color: var(--text-muted);
}
.inquiry__sub strong {
  color: var(--text);
  font-family: var(--font-mono);
  font-weight: 700;
}
@media (max-width: 1024px) {
  .inquiry { position: static; }
}
@media (max-width: 540px) {
  .inquiry { padding: var(--s-7) var(--s-5); }
}

/* ─── RELATED LISTINGS (you may also like) ────────────── */
.related-wrap {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--s-8);
  animation: fade-in-up 600ms ease-out backwards;
}
.related__head {
  text-align: center;
  margin-bottom: var(--s-7);
}
.related__title { margin: var(--s-3) 0 0; }
@media (max-width: 540px) {
  .related-wrap { padding: var(--s-6); }
}
.related__grid > * {
  animation: fade-in-up 400ms ease-out backwards;
}
.related__grid > *:nth-child(2) { animation-delay: 60ms; }
.related__grid > *:nth-child(3) { animation-delay: 120ms; }
@media (prefers-reduced-motion: reduce) {
  .related__grid > * { animation-delay: 0ms !important; }
}

/* Bottom-cta styles consolidated to components.css. Single-listing only
   adds the entrance animation since this CTA appears below the gallery. */
.bottom-cta {
  animation: fade-in-up 600ms ease-out backwards;
}

/* ─── STICKY CTA BAR (appears on scroll) ───────────────── */
.sticky-cta-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(var(--bg-rgb), 0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-top: 1px solid var(--border-strong);
  /* Bottom padding includes the iOS safe-area inset so the bar's CTA
     buttons don't sit under the iPhone home indicator. Without this,
     primary "Buy Now" button got 24px of its tap area covered. */
  padding: var(--s-4) var(--s-6) calc(var(--s-4) + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-sticky);
  box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.5);
  transform: translateY(100%);
  transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1);
}
.sticky-cta-bar.is-visible { transform: translateY(0); }
.sticky-cta-bar__inner {
  max-width: var(--shell);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
}
.sticky-cta-bar__info {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  min-width: 0;
}
.sticky-cta-bar__media {
  width: 56px;
  height: 56px;
  border-radius: var(--r-sm);
  background:
    linear-gradient(135deg, var(--accent-soft), transparent 50%),
    linear-gradient(45deg, var(--bg-3), var(--bg-2));
  border: 1px solid var(--border-strong);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sticky-cta-bar__media svg {
  width: 26px;
  height: 26px;
  color: var(--accent);
  opacity: 0.6;
}
.sticky-cta-bar__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.sticky-cta-bar__title {
  font-size: var(--t-sm);
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 320px;
}
.sticky-cta-bar__price {
  font-family: var(--font-mono);
  font-size: var(--t-md);
  font-weight: 800;
  color: var(--accent);
  letter-spacing: -0.01em;
}
.sticky-cta-bar__actions {
  display: flex;
  gap: var(--s-2);
  flex-shrink: 0;
}
/* Sticky CTAs are the primary conversion path on the listing — keep them
   above the 44px touch-target line on every viewport, even when other
   sticky-bar elements compress on narrow screens. */
.sticky-cta-bar__actions .btn {
  min-height: 48px;
}
@media (max-width: 720px) {
  .sticky-cta-bar { padding: var(--s-3); }
  .sticky-cta-bar__inner { gap: var(--s-3); }
  .sticky-cta-bar__media { display: none; }
  .sticky-cta-bar__title {
    max-width: 140px;
    font-size: var(--t-xs);
  }
  .sticky-cta-bar__price { font-size: var(--t-sm); }
  .sticky-cta-bar__actions .btn {
    /* Slightly less padding at narrow widths but keep 48px min-height. */
    padding: 12px 14px;
    font-size: var(--t-xs);
    min-height: 48px;
  }
}

/* v2.0.71 — DESKTOP: hide the sticky bar entirely. On mouse-driven
   layouts the bar trades persistent footer real estate (~80px) for a
   benefit the buyer doesn't need: the right sidebar is reachable
   with a single wheel-scroll, and the related-listings + bottom CTA
   sections already carry inquiry/call buttons. Removing it makes
   the page feel taller and stops covering content. The bar still
   appears on tablet (≤1024px) + mobile (≤720px) where finger-scroll
   distances are longer and the sidebar sits above the gallery. The
   body-padding compensation rules below are scoped accordingly so
   desktop doesn't carry phantom 84px of bottom space.

   Note on the JS hook: main.js still toggles `.is-visible` on the
   bar based on scroll position; `display:none` here wins over the
   transform-translate visibility — no JS change needed. */
@media (min-width: 1025px) {
  .sticky-cta-bar { display: none !important; }
  body.sticky-cta-active { padding-bottom: 0; scroll-padding-bottom: 0; }
}
/* Body padding compensates for the fixed sticky CTA bar so the last
   paragraph isn't covered. JS toggles `.sticky-cta-active`; the
   `:has()` rule below provides a CSS-only fallback when JS is blocked
   (Brave shields, no-JS users) — wrapped in @supports so older browsers
   that lack :has just keep the JS-only behavior instead of breaking
   the cascade.

   `scroll-padding-bottom` ensures keyboard users tabbing through the
   page don't land an element under the sticky bar (WCAG 2.4.11 Focus
   Not Obscured). */
body.sticky-cta-active {
  padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  scroll-padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
}
@supports selector(:has(*)) {
  body:has(.sticky-cta-bar.is-visible) {
    padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px));
    scroll-padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
  }
}

/* ─── BUYER PROTECTION CARD (v2.0.47) ──────────────────────
   Rendered in the sticky CTA stack after Buy Now — surfaces the
   universal warranty + buy-back promise on every listing so the
   buyer sees the safety net before they call. The card always
   renders when either program is enabled (helpers default true);
   markup lives in single-dpelite_listing.php. */
.dpelite-protection-card {
  background: linear-gradient(135deg, var(--bg-2), var(--bg-3));
  border: 1px solid var(--accent-border);
  border-radius: var(--r-md);
  padding: var(--s-5);
  margin-top: var(--s-5);
}
.dpelite-protection-card__title {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--accent);
  font-weight: 700;
  margin: 0 0 var(--s-4);
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.dpelite-protection-card__title svg {
  width: 14px;
  height: 14px;
}
.dpelite-protection-card__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--s-3);
}
.dpelite-protection-card__list li {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  font-size: var(--t-sm);
  color: var(--text-soft);
  line-height: 1.4;
}
.dpelite-protection-card__list li svg {
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  color: var(--success);
  margin-top: 3px;
}
.dpelite-protection-card__list a {
  color: var(--accent);
  text-decoration: none;
}
.dpelite-protection-card__list a:hover {
  text-decoration: underline;
}
/* WCAG 2.5.5 — inline "Terms" link is ~40×20px at desktop font size;
   under 44×44 it fails AA. Bump the hit area on tablet/mobile widths
   where touch input dominates. (v2.0.48 mobile audit fix.) */
@media (max-width: 720px) {
  .dpelite-protection-card__list a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 6px;
    margin: -10px 0; /* keep visual rhythm; min-height grows the box */
  }
}
