/* =====================================================================
   detail.css — RV detail page styles — EE EDITION.
   Diverges from redesign/detail.css on purpose; ./rvn.sh sync prefers this
   copy (pick_src(), plan doc 14.3) and serves it at /css/redesign/detail.css.
   What changed vs the prototype (plan doc 33):
     1. The dead .equipment-group-title / .equipment-list rules are gone
        (nothing renders them; the Standard Features block was removed).
     2. The Overview "Unit details", Specifications "Key measurements" +
        spec-sheet disclosure, and Equipment card stack (.f-* classes) are
        appended at the end of the file.
     3. Plan doc 34: inventory/view (staff sold VDP) was ported to the same
        three sections, so the old .advantage-* (free-item cards) and
        .specs-* (two spec tables) rules are gone, and so is .vdp-card-meta
        (the purchase card's length / weight / sleeps line).
   Originally extracted from detail.html's inline <style> block on 2026-09-03.
   ===================================================================== */
        body {
            background-color: var(--bg-light);
        }

        /* Breadcrumb bar sits below the fixed header */
        .vdp-breadcrumb-bar {
            max-width: 1200px;
            margin: 0 auto;
            padding: 94px 24px 0;
        }

        .vdp-breadcrumb {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 8px;
            font-size: 0.85rem;
            color: var(--text-muted);
        }

        .vdp-breadcrumb a {
            color: var(--primary-link);
            font-weight: 500;
        }

        .vdp-breadcrumb a:hover {
            text-decoration: underline;
        }

        .vdp-breadcrumb .crumb-sep {
            color: var(--border-color);
        }

        /* Main two-column layout */
        .vdp-layout {
            max-width: 1200px;
            margin: 0 auto;
            padding: 16px 24px 80px;
            display: grid;
            grid-template-columns: minmax(0, 1fr) 380px;
            gap: 32px;
            align-items: start;
        }

        .vdp-main {
            min-width: 0;
        }

        /* ---------- Gallery ---------- */
        .vdp-gallery {
            position: relative;
            /* At <=1024px .vdp-main becomes display:contents, so .vdp-gallery is
               itself the grid item. Without min-width:0 the thumb strip's
               min-content width (47 tiles wide) blows the page out horizontally. */
            min-width: 0;
        }

        .vdp-gallery-main {
            position: relative;
            aspect-ratio: 16 / 10;
            border-radius: var(--radius-md);
            overflow: hidden;
            background-color: #eaeaea;
            border: 1px solid var(--border-color);
            /* Vertical page scrolling must still work over the hero; the swipe
               controller only hijacks the gesture once horizontal movement wins. */
            touch-action: pan-y;
        }

        .vdp-gallery-main img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        /* ---------- Swipe track (shared by the hero and the lightbox stage) ----------
           Three slides — prev | current | next — in a row 3x the surface width.
           The resting transform translateX(-100%) parks the CURRENT slide over the
           surface, so both neighbours are already laid out and simply peek in as
           the finger drags. detail.js drives the transform; the transition is set
           inline only while a commit/settle animation runs. */
        .vdp-swipe-track,
        .vdp-lb-track {
            position: absolute;
            inset: 0;
            display: flex;
            transform: translate3d(-100%, 0, 0);
            will-change: transform;
            touch-action: pan-y;
        }

        .vdp-swipe-slide,
        .vdp-lb-slide {
            position: relative;
            flex: 0 0 100%;
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
        }

        .vdp-swipe-track img,
        .vdp-lb-track img {
            -webkit-user-drag: none;
            user-select: none;
        }

        .vdp-swipe-track.is-dragging,
        .vdp-lb-track.is-dragging { cursor: grabbing; }

        /* The neighbours exist for the GESTURE ONLY — they must be invisible at
           rest. They can't be relied on to sit off-screen: `.vdp-lb-stage` reserves
           horizontal padding for its arrows and `overflow: hidden` clips at the
           PADDING box, so a neighbour parked exactly at the content-box edge still
           showed an 8px (mobile) / 68px (desktop) sliver of the adjacent photo
           welded to the current one. A letterboxed image would leak the same way.
           So rather than fight the geometry: hidden by default, and detail.js marks
           the track `.is-active` for the whole gesture — drag PLUS the commit/settle
           animation — which is the only time they paint. */
        .vdp-swipe-slide:not(.is-current),
        .vdp-lb-slide:not(.is-current) {
            visibility: hidden;
        }

        .vdp-swipe-track.is-active .vdp-swipe-slide:not(.is-current),
        .vdp-lb-track.is-active .vdp-lb-slide:not(.is-current) {
            visibility: visible;
        }

        /* Floorplan is a separate mode, not part of the photo sequence: swiping is
           off there, so `.is-active` can never be set — but keep this LAST as a
           belt-and-braces override (equal specificity, so source order decides). */
        .vdp-gallery-main.showing-floorplan .vdp-swipe-slide:not(.is-current),
        .vdp-lb-figure.floorplan .vdp-lb-slide:not(.is-current) {
            visibility: hidden;
        }

        .vdp-photo-count {
            position: absolute;
            right: 14px;
            bottom: 14px;
            background-color: rgba(10, 17, 24, 0.75);
            color: var(--text-light);
            font-size: 0.78rem;
            font-weight: 600;
            padding: 6px 12px;
            border-radius: 20px;
            display: flex;
            align-items: center;
            gap: 6px;
            backdrop-filter: blur(4px);
        }

        .vdp-status-badge {
            position: absolute;
            top: 14px;
            left: 14px;
            font-family: var(--font-headings);
            font-size: 0.75rem;
            font-weight: 800;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            padding: 6px 14px;
            border-radius: 4px;
            box-shadow: var(--shadow-sm);
            z-index: 5;
        }

        .vdp-status-badge.status-instock { background-color: var(--accent-teal-fill); color: #fff; }
        .vdp-status-badge.status-order { background-color: var(--primary-fill); color: #fff; }
        .vdp-status-badge.status-pending { background-color: var(--accent-gold); color: var(--primary-dark); }

        /* Main image is clickable (opens the lightbox) */
        .vdp-gallery-main img {
            cursor: zoom-in;
        }

        /* Floorplan is shown on a white matte instead of cover-cropped */
        .vdp-gallery-main.showing-floorplan {
            background-color: #fff;
        }

        .vdp-gallery-main.showing-floorplan img {
            object-fit: contain;
            padding: 14px;
            background-color: #fff;
        }

        /* Prev/next arrows over the hero image */
        .vdp-gal-arrow {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: 44px;
            height: 44px;
            border-radius: 50%;
            border: 1px solid rgba(15, 41, 66, 0.08);
            background-color: rgba(255, 255, 255, 0.9);
            color: var(--primary-dark);
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            padding: 0;
            z-index: 6;
            box-shadow: var(--shadow-sm);
            transition: var(--transition-fast);
        }

        .vdp-gal-arrow:hover { background-color: #fff; }
        .vdp-gal-arrow.prev { left: 12px; }
        .vdp-gal-arrow.next { right: 12px; }
        .vdp-gal-arrow[hidden] { display: none; }

        /* Persistent Floorplan toggle, bottom-left of the hero */
        .vdp-floorplan-toggle {
            position: absolute;
            left: 14px;
            bottom: 14px;
            z-index: 6;
            display: inline-flex;
            align-items: center;
            gap: 7px;
            font-family: var(--font-headings);
            font-size: 0.78rem;
            font-weight: 700;
            letter-spacing: 0.4px;
            text-transform: uppercase;
            padding: 9px 15px;
            border-radius: 20px;
            border: 1px solid rgba(15, 41, 66, 0.1);
            background-color: rgba(255, 255, 255, 0.92);
            color: var(--primary-dark);
            cursor: pointer;
            backdrop-filter: blur(4px);
            transition: var(--transition-fast);
        }

        .vdp-floorplan-toggle:hover {
            background-color: #fff;
        }

        .vdp-floorplan-toggle[aria-pressed="true"] {
            background-color: var(--primary-fill);
            border-color: var(--primary-fill);
            color: #fff;
        }

        /* Horizontally scrolling thumbnail strip */
        .vdp-thumbs {
            display: flex;
            gap: 10px;
            margin-top: 10px;
            overflow-x: auto;
            overflow-y: hidden;
            padding-bottom: 6px;
            scrollbar-width: thin;
            scrollbar-color: rgba(15, 41, 66, 0.25) transparent;
            -webkit-overflow-scrolling: touch;
        }

        .vdp-thumbs::-webkit-scrollbar { height: 6px; }
        .vdp-thumbs::-webkit-scrollbar-track { background: transparent; }
        .vdp-thumbs::-webkit-scrollbar-thumb {
            background-color: rgba(15, 41, 66, 0.2);
            border-radius: 3px;
        }
        .vdp-thumbs:hover::-webkit-scrollbar-thumb { background-color: rgba(15, 41, 66, 0.35); }

        .vdp-thumb {
            flex: 0 0 auto;
            width: 116px;
            aspect-ratio: 16 / 10;
            border-radius: var(--radius-sm);
            overflow: hidden;
            border: 2px solid transparent;
            background-color: #eaeaea;
            cursor: pointer;
            padding: 0;
            transition: var(--transition-fast);
        }

        .vdp-thumb img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .vdp-thumb:hover {
            border-color: var(--primary-light);
        }

        .vdp-thumb.active {
            border-color: var(--primary-light);
            box-shadow: 0 0 0 3px rgba(0, 164, 228, 0.15);
        }

        /* ---------- Lightbox ----------
           z-index sits above the fixed header (100), the brand overlay (200) and
           the mobile CTA bar (60) so nothing pokes through it. */
        .vdp-lightbox {
            position: fixed;
            inset: 0;
            z-index: 500;
            background-color: #080d13;
            display: flex;
            flex-direction: column;
        }

        .vdp-lightbox[hidden] { display: none; }

        .vdp-lb-topbar {
            flex: 0 0 auto;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            padding: 12px 16px;
            color: var(--text-light);
        }

        .vdp-lb-counter {
            font-family: var(--font-headings);
            font-size: 0.85rem;
            font-weight: 600;
            letter-spacing: 0.5px;
            color: rgba(255, 255, 255, 0.85);
        }

        .vdp-lb-close {
            width: 44px;
            height: 44px;
            border-radius: 50%;
            border: 1px solid rgba(255, 255, 255, 0.18);
            background-color: rgba(255, 255, 255, 0.08);
            color: #fff;
            font-size: 1.5rem;
            line-height: 1;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            transition: var(--transition-fast);
        }

        .vdp-lb-close:hover { background-color: rgba(255, 255, 255, 0.18); }

        /* The stage is the ONLY zone the photo may occupy: it is the flex-grow
           child between the topbar and the rail band, and it clips, so the image
           can never bleed under the thumbnail rail (Carvana/Airbnb-style split). */
        .vdp-lb-stage {
            flex: 1 1 auto;
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 0;
            overflow: hidden;
            padding: 0 68px;
        }

        /* height:100% is load-bearing: it gives the figure a DEFINITE height so
           the image's max-height:100% actually resolves. Without it the figure is
           auto-height, the percentage is circular (ignored), and the image renders
           at intrinsic size — that was the bug that made the photo run behind the
           rail. */
        .vdp-lb-figure {
            position: relative;
            width: 100%;
            height: 100%;
            min-height: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            touch-action: pan-y;
        }

        .vdp-lb-image {
            max-width: 100%;
            max-height: 100%;
            min-height: 0;
            object-fit: contain;
            border-radius: var(--radius-sm);
        }

        /* White matte behind the floorplan. It lives on the IMAGE (background +
           padding), not on the figure — the figure now fills the whole stage, so
           matting it would paint the entire stage white. */
        /* The image now lives inside the absolutely-positioned swipe track, so the
           floorplan caption can no longer be a flex sibling of it — it is pinned to
           the bottom of the figure and the slide reserves room for it. */
        .vdp-lb-figure.floorplan .vdp-lb-slide {
            padding-bottom: 26px;
        }

        .vdp-lb-figure.floorplan .vdp-lb-image {
            background-color: #fff;
            border-radius: var(--radius-md);
            padding: 18px;
        }

        .vdp-lb-fp-label {
            position: absolute;
            left: 0;
            right: 0;
            bottom: 0;
            text-align: center;
            font-family: var(--font-headings);
            font-size: 0.75rem;
            font-weight: 800;
            letter-spacing: 1px;
            text-transform: uppercase;
            color: rgba(255, 255, 255, 0.82);
        }

        .vdp-lb-fp-label[hidden] { display: none; }

        .vdp-lb-arrow {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: 48px;
            height: 48px;
            border-radius: 50%;
            /* Dark fill (not translucent white) so the arrows stay legible when
               the white floorplan matte is behind them. */
            border: 1px solid rgba(255, 255, 255, 0.22);
            background-color: rgba(10, 17, 24, 0.72);
            color: #fff;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            padding: 0;
            z-index: 2;
            transition: var(--transition-fast);
        }

        .vdp-lb-arrow:hover { background-color: rgba(10, 17, 24, 0.92); }
        .vdp-lb-arrow.prev { left: 10px; }
        .vdp-lb-arrow.next { right: 10px; }
        /* Needed for the same reason .vdp-gal-arrow has it: the class sets
           display:flex, which outranks the UA's [hidden] { display: none }. */
        .vdp-lb-arrow[hidden] { display: none; }

        /* Dedicated rail band: reads as chrome, not content. Slightly lifted off
           the #080d13 backdrop, with a hairline + soft shadow separating it from
           the stage above. */
        .vdp-lb-rail {
            flex: 0 0 auto;
            display: flex;
            align-items: center;
            gap: 8px;
            overflow-x: auto;
            overflow-y: hidden;
            padding: 14px 16px 16px;
            padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
            background-color: #0d151d;
            border-top: 1px solid rgba(255, 255, 255, 0.10);
            box-shadow: 0 -10px 22px rgba(0, 0, 0, 0.45);
            scrollbar-width: none;
            -webkit-overflow-scrolling: touch;
        }

        .vdp-lb-rail::-webkit-scrollbar { display: none; }

        .vdp-lb-thumb {
            flex: 0 0 auto;
            width: 92px;
            aspect-ratio: 16 / 10;
            border-radius: var(--radius-sm);
            overflow: hidden;
            border: 2px solid transparent;
            background-color: #1b2733;
            cursor: pointer;
            padding: 0;
            opacity: 0.55;
            transition: var(--transition-fast);
        }

        .vdp-lb-thumb img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .vdp-lb-thumb:hover,
        .vdp-lb-thumb:focus-visible { opacity: 1; }

        .vdp-lb-thumb:focus-visible {
            outline: 2px solid var(--accent-gold);
            outline-offset: 2px;
        }

        /* High-contrast blue ring so the current position reads at a glance */
        .vdp-lb-thumb.active {
            border-color: var(--primary-light);
            box-shadow: 0 0 0 2px rgba(0, 164, 228, 0.45);
            opacity: 1;
        }

        /* Floorplan thumb: white tile + label, pinned first, visually distinct */
        .vdp-lb-thumb.is-floorplan {
            background-color: #fff;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 2px;
            opacity: 0.7;
            border-color: rgba(255, 255, 255, 0.35);
        }

        .vdp-lb-thumb.is-floorplan img {
            height: auto;
            max-height: 60%;
            width: auto;
            max-width: 82%;
            object-fit: contain;
        }

        .vdp-lb-thumb.is-floorplan .fp-tag {
            font-family: var(--font-headings);
            font-size: 0.55rem;
            font-weight: 800;
            letter-spacing: 0.8px;
            text-transform: uppercase;
            color: var(--primary-dark);
        }

        .vdp-lb-thumb.is-floorplan:hover,
        .vdp-lb-thumb.is-floorplan:focus-visible { opacity: 1; }

        .vdp-lb-thumb.is-floorplan.active {
            border-color: var(--primary-light);
            box-shadow: 0 0 0 2px rgba(0, 164, 228, 0.45);
            opacity: 1;
        }

        @media (prefers-reduced-motion: reduce) {
            .vdp-lightbox,
            .vdp-lb-image,
            .vdp-gallery-main img,
            /* Belt-and-braces: detail.js already skips the slide animation under
               reduced motion (drag still follows the finger, commit is instant),
               but the inline transition it writes needs !important to lose here. */
            .vdp-swipe-track,
            .vdp-lb-track {
                transition: none !important;
                animation: none !important;
            }
        }

        /* ---------- Sticky section nav ----------
           top matches .vdp-purchase-col so both sticky elements share the same
           gap below the fixed header while scrolling */
        .vdp-section-nav {
            position: sticky;
            top: 94px;
            z-index: 30;
            background-color: var(--bg-white);
            border: 1px solid var(--border-color);
            border-radius: 40px;
            box-shadow: var(--shadow-sm);
            margin: 24px 0;
            padding: 6px;
            display: flex;
            gap: 4px;
            overflow-x: auto;
            scrollbar-width: none;
        }

        .vdp-section-nav::-webkit-scrollbar { display: none; }

        .vdp-nav-pill {
            flex: 1;
            white-space: nowrap;
            font-size: 0.85rem;
            font-weight: 600;
            color: var(--text-muted);
            padding: 9px 18px;
            border-radius: 30px;
            text-align: center;
            transition: var(--transition-fast);
        }

        .vdp-nav-pill:hover {
            color: var(--primary-dark);
            background-color: var(--bg-light);
        }

        .vdp-nav-pill.active {
            background-color: rgba(0, 164, 228, 0.1);
            color: var(--primary-link);
        }

        /* ---------- Content sections ---------- */
        .vdp-section {
            background-color: var(--bg-white);
            border: 1px solid var(--border-color);
            border-radius: var(--radius-md);
            box-shadow: var(--shadow-sm);
            padding: 32px;
            margin-bottom: 24px;
            scroll-margin-top: 164px;
        }

        .vdp-section-title {
            font-family: var(--font-headings);
            font-size: 1.5rem;
            font-weight: 800;
            color: var(--primary-dark);
            letter-spacing: -0.3px;
            margin-bottom: 4px;
        }

        .vdp-section-title::before {
            content: "";
            display: block;
            width: 34px;
            height: 4px;
            border-radius: 2px;
            background-color: var(--accent-gold);
            margin-bottom: 12px;
        }

        .vdp-section-sub {
            color: var(--text-muted);
            font-size: 0.95rem;
            margin-bottom: 20px;
        }

        .vdp-overview-copy {
            color: var(--text-dark);
            font-size: 0.95rem;
            line-height: 1.7;
        }

        /* Payment calculator */
        .calc-grid {
            display: grid;
            grid-template-columns: 1fr 260px;
            gap: 32px;
            align-items: start;
        }

        .calc-fields {
            display: flex;
            flex-direction: column;
            gap: 20px;
        }

        .calc-field label {
            display: block;
            font-size: 0.85rem;
            font-weight: 600;
            color: var(--primary-dark);
            margin-bottom: 8px;
        }

        .calc-input-box {
            position: relative;
        }

        .calc-input-box .prefix {
            position: absolute;
            left: 14px;
            top: 50%;
            transform: translateY(-50%);
            color: var(--text-muted);
            font-size: 0.9rem;
        }

        .calc-input-box input,
        .calc-field select {
            width: 100%;
            padding: 12px 14px 12px 28px;
            border: 1px solid var(--border-color);
            border-radius: var(--radius-sm);
            font-family: var(--font-body);
            font-size: max(16px, 1rem);   /* 16px minimum: iOS zooms the page on focus below it (ee.css, last section) */
            color: var(--text-dark);
            background-color: var(--bg-white);
            outline: none;
            transition: var(--transition-fast);
        }

        .calc-field select {
            padding-left: 14px;
            cursor: pointer;
        }

        /* the boxes these had at 0.95rem: only the text grew to 16px. The
           vertical padding goes: an explicit height centres the text, and a
           select would cut its descenders in what the padding left over. */
        .calc-input-box input { height: 45px; padding-top: 0; padding-bottom: 0; }
        .calc-field select { height: 47px; padding-top: 0; padding-bottom: 0; }

        .calc-input-box input:focus,
        .calc-field select:focus {
            border-color: var(--primary-light);
            box-shadow: 0 0 0 3px rgba(0, 164, 228, 0.15);
        }

        .calc-result {
            background-color: var(--primary-dark);
            border-radius: var(--radius-md);
            color: var(--text-light);
            padding: 28px 24px;
            text-align: center;
            position: sticky;
            top: 150px;
        }

        .calc-result .calc-label {
            font-size: 0.8rem;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: var(--text-light-muted);
            margin-bottom: 8px;
        }

        .calc-result .calc-amount {
            font-family: var(--font-headings);
            font-size: 2.5rem;
            font-weight: 800;
            line-height: 1;
        }

        .calc-result .calc-amount .per {
            font-size: 1rem;
            font-weight: 600;
            color: var(--text-light-muted);
        }

        .calc-result .calc-note {
            font-size: 0.75rem;
            color: var(--text-light-muted);
            margin: 12px 0 20px;
        }

        .calc-result .btn {
            width: 100%;
        }

        /* Delivery section: the estimate calculator's rules are at the end
           of this file ("Delivery estimate", plan doc 35). */

        /* Similar models */
        .similar-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 20px;
        }

        .similar-card {
            background-color: var(--bg-white);
            border: 1px solid var(--border-color);
            border-radius: var(--radius-md);
            overflow: hidden;
            box-shadow: var(--shadow-sm);
            display: block;
            transition: transform var(--transition-fast), box-shadow var(--transition-fast);
        }

        .similar-card:hover {
            transform: translateY(-4px);
            box-shadow: var(--shadow-card-hover);
        }

        .similar-card-img {
            aspect-ratio: 16 / 10;
            background-color: #eaeaea;
            overflow: hidden;
        }

        .similar-card-img img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .similar-card-body {
            padding: 16px;
        }

        .similar-card-body .brand-pill {
            display: block;
            font-size: 0.7rem;
            font-weight: 700;
            color: var(--primary-link);
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-bottom: 4px;
        }

        .similar-card-body h3 {
            font-family: var(--font-headings);
            font-size: 1.05rem;
            font-weight: 700;
            color: var(--primary-dark);
            margin-bottom: 8px;
        }

        .similar-card-price {
            display: flex;
            align-items: baseline;
            gap: 8px;
        }

        .similar-card-price .dp {
            font-size: 0.72rem;
            font-weight: 600;
            color: var(--text-muted);
        }

        .similar-card-price .amt {
            font-family: var(--font-headings);
            font-size: 1.2rem;
            font-weight: 800;
            color: var(--primary-link);
        }

        /* ---------- Purchase card (right column) ---------- */
        .vdp-purchase-col {
            position: sticky;
            top: 94px;
        }

        .vdp-purchase-card {
            background-color: var(--bg-white);
            border: 1px solid var(--border-color);
            border-radius: var(--radius-md);
            box-shadow: var(--shadow-md);
            padding: 24px;
        }

        .vdp-card-brandline {
            font-size: 0.75rem;
            font-weight: 700;
            color: var(--primary-link);
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-bottom: 6px;
        }

        /* The length / weight / sleeps line that sat under the title
           (.vdp-card-meta) was removed (plan doc 34); its 18px gap above the
           price block's rule now lives on the title. */
        .vdp-card-title {
            font-family: var(--font-headings);
            font-size: 1.6rem;
            font-weight: 800;
            color: var(--primary-dark);
            line-height: 1.2;
            letter-spacing: -0.3px;
            margin-bottom: 18px;
        }

        .vdp-price-block {
            border-top: 1px solid var(--border-color);
            padding-top: 18px;
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
            gap: 12px;
        }

        .vdp-price-left {
            display: flex;
            flex-direction: column;
        }

        .vdp-dont-pay {
            font-size: 0.8rem;
            font-weight: 600;
            color: var(--text-muted);
            margin-bottom: 3px;
        }

        .vdp-price {
            font-family: var(--font-headings);
            font-size: 2.1rem;
            font-weight: 800;
            color: var(--primary-link);
            line-height: 1;
        }

        .vdp-msrp {
            font-size: 0.85rem;
            color: var(--text-muted);
            margin-top: 5px;
        }

        .vdp-msrp s { text-decoration: line-through; }

        .vdp-price-right {
            text-align: right;
            align-self: center;
        }

        .vdp-monthly {
            font-family: var(--font-headings);
            font-size: 1.4rem;
            font-weight: 800;
            color: var(--primary-dark);
            line-height: 1;
        }

        .vdp-monthly .per {
            font-family: var(--font-body);
            font-size: 0.7rem;
            font-weight: 600;
            color: var(--text-muted);
        }

        .vdp-down-note {
            font-size: 0.75rem;
            color: var(--text-muted);
            margin-top: 4px;
        }

        /* Gold-tinted highlight: complementary to the blue price, noticeable not loud */
        .vdp-savings-callout {
            background-color: rgba(255, 193, 7, 0.14);
            border: 1px solid rgba(255, 193, 7, 0.45);
            color: var(--accent-gold-text);
            font-family: var(--font-headings);
            font-weight: 700;
            font-size: 0.9rem;
            text-align: center;
            padding: 9px 10px;
            border-radius: var(--radius-sm);
            margin: 16px 0;
        }

        .vdp-get-approved-link {
            display: inline-block;
            font-size: 0.78rem;
            font-weight: 600;
            color: var(--primary-link);
            margin-top: 6px;
        }

        .vdp-get-approved-link:hover {
            color: var(--accent-gold-text);
            text-decoration: underline;
        }

        /* Tap target (WCAG 2.5.5): 98x20 rendered. Same transparent
           ::after hit-area technique as .get-approved-link in style.css --
           out of flow, so the visible design does not move. */
        .vdp-get-approved-link {
            position: relative;
        }

        .vdp-get-approved-link::after {
            content: '';
            position: absolute;
            left: 0;
            right: 0;
            top: 50%;
            transform: translateY(-50%);
            height: 44px;
            background: transparent;
        }

        /* Lead form (always visible in the purchase card) */
        .vdp-lead-form {
            border: 1px dashed rgba(0, 164, 228, 0.4);
            background-color: rgba(0, 164, 228, 0.04);
            border-radius: var(--radius-sm);
            padding: 16px;
            margin-top: 2px;
        }

        .vdp-lead-form .lead-blurb {
            font-size: 0.82rem;
            color: var(--text-dark);
            line-height: 1.5;
            margin-bottom: 12px;
        }

        .vdp-lead-form .lead-blurb strong {
            color: var(--primary-dark);
        }

        .vdp-lead-form input {
            width: 100%;
            padding: 0 12px;              /* was 11px top and bottom; see height */
            border: 1px solid var(--border-color);
            border-radius: var(--radius-sm);
            font-family: var(--font-body);
            font-size: max(16px, 1rem);   /* 16px minimum (ee.css, last section) */
            height: 41px;                 /* the box it had at 0.9rem with that padding (the consent checkbox sets its own size below) */
            outline: none;
            margin-bottom: 10px;
            transition: var(--transition-fast);
        }

        .vdp-lead-form input:focus {
            border-color: var(--primary-light);
            box-shadow: 0 0 0 3px rgba(0, 164, 228, 0.15);
        }

        /* "Full Name (first & last) *" at 16px is 1px wider than the field
           of a 320px screen: the hint keeps its old size there */
        @media (max-width: 360px) {
            .vdp-lead-form input::placeholder { font-size: 0.9rem; }
        }

        /* Field wrapper carries the 10px rhythm the bare inputs used to own, so
           the form measures identically when no errors are showing. */
        .vdp-lead-form .lead-field {
            margin-bottom: 10px;
        }

        .vdp-lead-form .lead-field input {
            margin-bottom: 0;
        }

        .vdp-lead-form .lead-error {
            display: none;
            font-size: 0.72rem;
            line-height: 1.35;
            color: #c62828;
            margin-top: 4px;
        }

        .vdp-lead-form .lead-field.has-error .lead-error {
            display: block;
        }

        .vdp-lead-form .lead-field.has-error input {
            border-color: #e53935;
        }

        .vdp-lead-form .lead-field.has-error input:focus {
            border-color: #e53935;
            box-shadow: 0 0 0 3px rgba(229, 57, 53, 0.15);
        }

        /* Real-time phone check (js/src/lead.js section 2b): the verdict under
           the phone field. The wrapper is always in the page (its text is an
           alert region) and has no size until a verdict is shown. 16px text,
           and the "It's Correct" control is a real button with a 24px target. */
        .vdp-lead-form .lead-phone-check {
            display: block;
            font-size: 1rem;
            line-height: 1.4;
            color: #c62828;
        }

        .vdp-lead-form .lead-phone-check.is-shown {
            margin-top: 6px;
        }

        .vdp-lead-form .lead-phone-check-ok {
            display: inline-block;
            min-height: 24px;
            margin: 0 0 0 8px;
            padding: 0;
            border: 0;
            background: none;
            font: inherit;
            font-weight: 600;
            color: inherit;
            text-decoration: underline;
            cursor: pointer;
        }

        .vdp-lead-form .lead-phone-check-ok[hidden] {
            display: none;
        }

        .vdp-lead-form .lead-phone-check-ok:focus-visible {
            outline: 2px solid currentColor;
            outline-offset: 2px;
        }

        .vdp-lead-form .lead-field input[aria-invalid="true"] {
            border-color: #e53935;
        }

        /* Honeypot — off-screen, never focusable, never validated. */
        .vdp-lead-form .lead-hp {
            position: absolute;
            width: 1px;
            height: 1px;
            overflow: hidden;
            clip: rect(0 0 0 0);
            clip-path: inset(50%);
            white-space: nowrap;
        }

        .visually-hidden {
            position: absolute;
            width: 1px;
            height: 1px;
            padding: 0;
            margin: -1px;
            overflow: hidden;
            clip: rect(0 0 0 0);
            clip-path: inset(50%);
            white-space: nowrap;
            border: 0;
        }

        /* Consent checkbox — mirrors build.html's .bp-consent pattern. The
           label wraps both the checkbox and the copy so the whole paragraph
           is a tap target, not just the 16px box. */
        .vdp-lead-form .lead-field-consent {
            margin-bottom: 12px;
        }

        .vdp-lead-form .lead-consent {
            display: flex;
            gap: 8px;
            align-items: flex-start;
            font-size: 0.68rem;
            color: var(--text-muted);
            line-height: 1.5;
            margin-bottom: 0;
            cursor: pointer;
        }

        .vdp-lead-form .lead-consent input[type="checkbox"] {
            width: 16px;
            height: 16px;
            flex-shrink: 0;
            /* Nudge down to align with the first line of the wrapped text
               rather than the label's own box top. */
            margin-top: 2px;
            accent-color: var(--primary-light);
        }

        @media (max-width: 480px) {
            .vdp-lead-form .lead-consent {
                gap: 10px;
                padding: 2px 0;
            }

            .vdp-lead-form .lead-consent input[type="checkbox"] {
                width: 18px;
                height: 18px;
            }
        }

        .vdp-lead-form .btn {
            width: 100%;
        }

        /* The button is disabled while a request is on its way and while the
           phone check holds the form: it has to look it. */
        .vdp-lead-form .btn:disabled {
            opacity: 0.55;
            cursor: not-allowed;
        }

        .lead-success {
            display: none;
            text-align: center;
            padding: 10px 0;
            color: var(--accent-teal-text);
            font-weight: 600;
            font-size: 0.9rem;
        }

        .vdp-stock-info {
            display: flex;
            justify-content: space-between;
            font-size: 0.75rem;
            color: var(--text-muted);
            border-top: 1px dashed var(--border-color);
            margin-top: 18px;
            padding-top: 12px;
        }

        .vdp-assurance {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-top: 14px;
            font-size: 0.75rem;
            color: var(--text-muted);
        }

        .vdp-assurance span {
            display: flex;
            align-items: center;
            gap: 5px;
        }

        /* ---------- Mobile sticky CTA bar ---------- */
        .vdp-mobile-bar {
            display: none;
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background-color: var(--bg-white);
            border-top: 1px solid var(--border-color);
            box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1);
            padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
            z-index: 60;
            align-items: center;
            gap: 14px;
        }

        .vdp-mobile-bar .bar-price-block {
            display: flex;
            flex-direction: column;
            line-height: 1.2;
        }

        .vdp-mobile-bar .bar-dont-pay {
            font-size: 0.65rem;
            font-weight: 600;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .vdp-mobile-bar .bar-price {
            font-family: var(--font-headings);
            font-size: 1.25rem;
            font-weight: 800;
            color: var(--primary-link);
        }

        .vdp-mobile-bar .bar-monthly {
            font-size: 0.7rem;
            color: var(--text-muted);
        }

        .vdp-mobile-bar .btn {
            flex: 1;
            text-align: center;
            padding: 13px;
            font-size: 0.9rem;
            font-weight: 700;
            border-radius: var(--radius-sm);
        }

        /* Not-found state */
        .vdp-not-found {
            grid-column: 1 / -1;
            background-color: var(--bg-white);
            border: 1px solid var(--border-color);
            border-radius: var(--radius-md);
            padding: 80px 24px;
            text-align: center;
        }

        .vdp-not-found h2 {
            font-family: var(--font-headings);
            font-size: 1.6rem;
            font-weight: 800;
            color: var(--primary-dark);
            margin-bottom: 8px;
        }

        .vdp-not-found p {
            color: var(--text-muted);
            margin-bottom: 24px;
        }

        /* ---------- Responsive ---------- */
        @media (max-width: 1024px) {
            .vdp-layout {
                /* minmax(0, ...): a bare 1fr column grows to its widest content, and
                   the open spec sheet (a table that does not wrap) then made the
                   whole page 12px wider than a 320px window. The table scrolls
                   inside .f-sheet-scroll instead. */
                grid-template-columns: minmax(0, 1fr);
                padding-top: 8px;
            }
            .vdp-breadcrumb-bar {
                padding-top: 80px;
            }
            .vdp-purchase-col {
                position: static;
                order: -1;
            }
            /* On tablet/mobile, gallery first then purchase card */
            .vdp-main {
                display: contents;
            }
            .vdp-gallery { order: -2; }
            /* The header is 73px tall at EVERY breakpoint (.header-container 72px
               + 1px border) — there is no responsive override. The old 60px tucked
               the pinned nav under it. 73 + 14 leaves the same breathing room the
               listings filter bar uses. The purchase card is static here, so this
               no longer has to match its 94px desktop offset. */
            .vdp-section-nav { top: 87px; }
            .calc-grid {
                grid-template-columns: 1fr;
            }
            .calc-result { position: static; }
        }

        @media (max-width: 768px) {
            .vdp-layout {
                padding: 8px 16px 120px;
                gap: 20px;
            }
            .vdp-breadcrumb-bar {
                padding-left: 16px;
                padding-right: 16px;
            }
            .vdp-section {
                padding: 22px 18px;
                /* Must clear the pinned stack: nav top (87) + nav height (~54)
                   + breathing room, or a tapped section's title lands under it. */
                scroll-margin-top: 156px;
            }
            .vdp-thumbs { gap: 6px; }
            .vdp-thumb { width: 88px; }
            .vdp-gal-arrow { width: 40px; height: 40px; }
            .vdp-gal-arrow.prev { left: 8px; }
            .vdp-gal-arrow.next { right: 8px; }
            .vdp-floorplan-toggle {
                left: 10px;
                bottom: 10px;
                padding: 8px 12px;
                font-size: 0.7rem;
            }
            .vdp-photo-count { right: 10px; bottom: 10px; font-size: 0.72rem; padding: 5px 10px; }
            /* Lightbox at 375: the stage gives the image nearly the full width,
               so the arrows overlay its edges — they stay 44x44 tap targets. */
            .vdp-lb-stage { padding: 0 8px; }
            .vdp-lb-arrow { width: 44px; height: 44px; }
            .vdp-lb-arrow.prev { left: 6px; }
            .vdp-lb-arrow.next { right: 6px; }
            /* 72px @ 16:10 = 45px tall, so a thumb stays a 44px-tall tap target. */
            .vdp-lb-thumb { width: 72px; }
            .vdp-lb-rail {
                padding: 10px 12px 12px;
                padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
                gap: 6px;
            }
            .vdp-lb-figure.floorplan .vdp-lb-image { padding: 10px; }
            .similar-grid { grid-template-columns: 1fr; }
            .vdp-mobile-bar { display: flex; }
            .vdp-card-title { font-size: 1.4rem; }
            .vdp-price { font-size: 1.9rem; }
        }

/* =====================================================================
   Overview / Specifications / Equipment (plan doc 33). Ported from the
   owner-approved mockup redesign/explore/vdp-details/concept-final.css
   (?eq=1, "everything is a card"). Site tokens only. One vocabulary:
     .f-block  vertical rhythm unit (28px between blocks)
     .f-head   sub-heading: 32px icon disc + Outfit title + count pill + action
     .f-disc   the icon disc (blue = structure, teal = "included / free")
     .f-count  count pill;  .f-check  teal check disc in every checklist
   Markup: site/.vdp-v2 renders every text server-side; js/src/detail.js
   regroups the equipment list into cards, refines the tiles from the spec
   sheet and wires the disclosures.
   ===================================================================== */

/* ---------- Rhythm + sub-heading ---------- */
.f-block + .f-block,
.vdp-overview-copy + .f-block { margin-top: 28px; }
.vdp-overview-copy:empty { display: none; }       /* entries with no description */

.f-head {
    display: flex;
    flex-wrap: wrap;                  /* <=360: "Expand all" drops to its own line */
    align-items: center;
    gap: 4px 10px;
    margin-bottom: 14px;
}
.f-head h3 {
    font-family: var(--font-headings);
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--primary-dark);
    line-height: 1.3;
    margin: 0;                        /* inside .vdp-legacy-html (equipment) the shim adds h3 margins */
    white-space: nowrap;
}
.f-head-action { margin-left: auto; }
.f-disc {
    flex: none;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: rgba(var(--primary-light-rgb), 0.12);
    color: var(--primary-link);
}
.f-disc-teal { background-color: rgba(18, 165, 148, 0.12); color: var(--accent-teal-text); }
.f-count {
    flex: none;
    display: inline-block;
    min-width: 24px;
    padding: 1px 8px;
    border-radius: 11px;
    background-color: var(--bg-light);
    border: 1px solid var(--border-color);
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.6;
    color: var(--text-muted);
    text-align: center;
    white-space: nowrap;
}
.f-free-tag {
    flex: none;
    font-family: var(--font-headings);
    font-size: 0.7rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--accent-teal-text);
    background-color: rgba(18, 165, 148, 0.12);
    padding: 3px 8px;
    border-radius: 4px;
}
.f-link-btn {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--primary-link);
    padding: 6px 4px;
    border-radius: 4px;
    white-space: nowrap;
}
.f-link-btn:hover { text-decoration: underline; }
.f-chev { flex: none; display: grid; color: var(--text-muted); transition: transform var(--transition-fast); }

/* ---------- Overview: unit details ---------- */
.f-dl {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
    column-gap: 40px;
}
.f-dl > div {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    padding: 11px 0;
    border-bottom: 1px solid var(--border-color);
    font-size: 0.9rem;
    min-width: 0;
}
.f-dl dt { flex: none; color: var(--text-muted); }
.f-dl dd {
    min-width: 0;
    color: var(--primary-dark);
    font-weight: 600;
    text-align: right;
    overflow-wrap: anywhere;          /* safety net only; a 17-char VIN fits */
}
.f-dl-vin dd { font-variant-numeric: tabular-nums; letter-spacing: 0.2px; }

/* ---------- Specs: key-measurement tiles ----------
   Rows are always even, with no inline spans: phones use two tracks and an
   odd last tile takes the whole row; above 768 a 12-track grid where 1-4
   tiles share one row, 5 = 3 + 2 (the last two widen to half) and 6 = 3 + 3.
   Quantity queries, so tiles detail.js adds re-flow with no extra code. */
.f-stats {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}
.f-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding: 14px 16px;
    background-color: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
}
.f-stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (min-width: 769px) {
    .f-stats { grid-template-columns: repeat(12, minmax(0, 1fr)); }
    .f-stat,
    .f-stat:last-child:nth-child(odd) { grid-column: span 3; }
    .f-stat:only-child { grid-column: span 12; }
    .f-stat:first-child:nth-last-child(2),
    .f-stat:first-child:nth-last-child(2) ~ .f-stat { grid-column: span 6; }
    .f-stat:first-child:nth-last-child(3),
    .f-stat:first-child:nth-last-child(3) ~ .f-stat,
    .f-stat:first-child:nth-last-child(n+5),
    .f-stat:first-child:nth-last-child(n+5) ~ .f-stat { grid-column: span 4; }
    .f-stat:first-child:nth-last-child(5) ~ .f-stat:nth-child(n+4) { grid-column: span 6; }
}
.f-stat-ico { display: flex; color: var(--primary-link); margin-bottom: 4px; }
.f-stat-v {
    font-family: var(--font-headings);
    font-size: 1.4rem;
    font-weight: 800;
    line-height: 1.15;
    color: var(--primary-dark);
    white-space: nowrap;
}
.f-stat-l { font-size: 0.8rem; color: var(--text-muted); }

/* ---------- Specs: spec-sheet disclosure ----------
   Server-rendered open with the button [hidden] (no-JS = the sheet in a
   card); detail.js shows the button and collapses the panel. */
.f-sheet {
    margin-top: 16px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background-color: var(--bg-white);
    overflow: hidden;
}
.f-sheet-toggle {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 12px 14px;
    background-color: var(--bg-light);
    text-align: left;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--primary-dark);
    border-radius: var(--radius-sm);
}
.f-sheet-toggle[hidden] { display: none; }
.f-sheet-toggle .f-count { background-color: var(--bg-white); }
.f-sheet-toggle .f-chev { margin-left: auto; }
.f-sheet-toggle:hover .f-sheet-label { color: var(--primary-link); }
.f-sheet-toggle[aria-expanded="true"] { border-bottom: 1px solid var(--border-color); border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.f-sheet-toggle[aria-expanded="true"] .f-chev { transform: rotate(180deg); }
.f-sheet-panel { padding: 6px 16px 14px; }

/* {inventory_specifications} is the manufacturer's raw <table> (thead
   Specification / Imperial / Metric, td cells; detail.js promotes the first
   cell of each row to <th scope="row">). Styled by column position so the
   no-JS render looks the same. */
.f-sheet-scroll { overflow-x: auto; }
.f-sheet-scroll table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.f-sheet-scroll th,
.f-sheet-scroll td {
    text-align: left;
    padding: 12px 8px;
    border-bottom: 1px solid var(--border-color);
    vertical-align: top;
}
.f-sheet-scroll tbody tr:last-child > * { border-bottom: none; }
.f-sheet-scroll thead th {
    padding-top: 8px;
    padding-bottom: 8px;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--text-muted);
}
.f-sheet-scroll tbody tr > :first-child { color: var(--text-muted); font-weight: 500; width: 45%; }
.f-sheet-scroll tbody tr > :nth-child(2) { color: var(--primary-dark); font-weight: 600; white-space: nowrap; }
.f-sheet-scroll tbody tr > :nth-child(3) { color: var(--text-muted); font-weight: 500; }
.f-note { margin-top: 8px; font-size: 0.8rem; color: var(--text-muted); }

/* ---------- Equipment: no-JS / pre-JS list ----------
   ee.css's .vdp-legacy-html list shim skips .vdp-eq; this is the plain,
   one-column list shown until detail.js regroups it (and forever without
   JS). Packages read as a bold line over their own item grid. */
.vdp-eq > :is(ul, ol) {
    list-style: none;
    display: grid;
    gap: 10px;
    margin: 0 0 12px;
}
.vdp-eq > :is(ul, ol) > li {
    position: relative;
    padding-left: 18px;
    font-size: 0.9rem;
    line-height: 1.5;
}
.vdp-eq > :is(ul, ol) > li::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 0.55em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: var(--primary-light);
}
.vdp-eq > :is(ul, ol) > li:has(> :is(ul, ol)) { font-weight: 600; color: var(--primary-dark); }
.vdp-eq > :is(ul, ol) li :is(ul, ol) {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
    gap: 4px 24px;
    margin: 6px 0 4px;
    font-weight: 400;
    color: var(--text-dark);
}
.vdp-eq > :is(ul, ol) li li { position: relative; padding-left: 14px; }
.vdp-eq > :is(ul, ol) li li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.62em;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background-color: var(--text-muted);
}
/* Used units keep dealer prose here; the shim's <p> rhythm applies. After
   the cards it gets the block rhythm. */
.vdp-eq .f-block + p { margin-top: 20px; }

/* ---------- Equipment: the card stack ---------- */
.f-pkg-list { display: grid; gap: 10px; }
.f-pkg {
    background-color: var(--bg-white);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.f-pkg[open] { box-shadow: var(--shadow-sm); }
.f-pkg summary {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    list-style: none;
    cursor: pointer;
    background-color: var(--bg-light);
    border-radius: var(--radius-sm);
}
.f-pkg summary::-webkit-details-marker { display: none; }
.f-pkg[open] summary { border-bottom: 1px solid var(--border-color); border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.f-pkg summary:hover .f-pkg-name { color: var(--primary-link); }
.f-pkg-name { flex: 1; min-width: 0; font-weight: 600; font-size: 0.95rem; line-height: 1.4; color: var(--primary-dark); }
.f-pkg-count { flex: none; font-size: 0.8rem; color: var(--text-muted); white-space: nowrap; }
.f-pkg[open] .f-chev { transform: rotate(180deg); }
.f-pkg-body { padding: 14px 16px 16px; }

.f-check-grid {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
    gap: 10px 24px;
}
.f-check-grid > li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 0.9rem;
    line-height: 1.45;
    color: var(--text-dark);
}
.f-check-grid > li > span:last-child { min-width: 0; overflow-wrap: anywhere; }
/* A third level (e.g. "Mandatory Equipment" > "Alta 200 Watt Solar Package" >
   Solar Panel / Controller / ...): an indented, muted sub-list under its item. */
.f-sublist { list-style: none; display: grid; gap: 2px; margin: 4px 0 0; }
.f-sublist > li {
    position: relative;
    padding-left: 14px;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--text-muted);
}
.f-sublist > li::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 0.6em;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background-color: var(--accent-teal-text);
}
.f-check-grid small { display: block; font-size: 0.8rem; color: var(--text-muted); }
.f-check {
    flex: none;
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    margin-top: 1px;
    border-radius: 50%;
    background-color: rgba(18, 165, 148, 0.12);
    color: var(--accent-teal-text);
}

/* A non-collapsible card whose header matches a package <summary>: the
   server-rendered "Included with every new RV" card (new units only). */
.f-pkg-summary {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    background-color: var(--bg-light);
    border-bottom: 1px solid var(--border-color);
}
/* h3.f-pkg-name: detail.js moves this card into #equipment-content, where
   ee.css's .vdp-legacy-html h3 (0,1,1) would restyle it; match the package
   titles (Inter 600 0.95rem) with and without JS. */
.f-pkg-summary h3.f-pkg-name {
    margin: 0;
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--primary-dark);
}
.f-pkg-static { box-shadow: var(--shadow-sm); }
.f-pkg-free { border-color: rgba(18, 165, 148, 0.35); }
.f-pkg-free .f-pkg-summary {
    background-color: rgba(18, 165, 148, 0.08);
    border-bottom-color: rgba(18, 165, 148, 0.25);
}
.f-pkg-free .f-pkg-name { flex: 0 1 auto; }
/* Outside the stack (no JS, prose-only or empty equipment) it needs its own
   gap; inside it the list's gap applies. */
#equipment > .f-pkg-free { margin-top: 20px; }

/* Keyboard focus rings on every control in the three sections. */
/* The toggle and the summaries sit inside overflow:hidden cards (.f-sheet,
   .f-pkg), which would clip an outside ring: draw theirs inside the box. */
.f-sheet-toggle:focus-visible,
.f-pkg summary:focus-visible { outline: 2px solid var(--primary-link); outline-offset: -3px; }
.f-link-btn:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; }

@media (max-width: 768px) {
    .f-stat-v { font-size: 1.2rem; }
    .f-pkg summary,
    .f-pkg-summary,
    .f-sheet-toggle { padding: 12px; gap: 10px; }
    .f-pkg summary .f-disc,
    .f-pkg-summary .f-disc { display: none; }
    .f-pkg-free .f-pkg-summary .f-disc { display: grid; }
    .f-sheet-panel { padding: 4px 10px 12px; }
    .f-sheet-scroll th,
    .f-sheet-scroll td { padding: 11px 6px; }
    .f-sheet-scroll tbody tr > :first-child { width: auto; }
}
@media (max-width: 400px) {
    .f-stat { padding: 12px; }
    .f-stat-v { font-size: 1.05rem; }
    .f-dl dd { font-size: 0.875rem; }
}

/* =====================================================================
   Delivery estimate (plan doc 35). Ported from the owner-approved mockup
   redesign/explore/delivery-calculator (concept B: delivery.css +
   concept-b.css), minus the purchase-card row the owner dropped. Site
   tokens only. Markup: site/.vdp-v2 renders every static string;
   js/src/detail.js fills in the result values, swaps the states and is
   the only thing that ever contacts Google (after an explicit action).
     #delivery-calc.dqb      form card, map, result
     .dq-map                 placeholder map / Google map / legend / overlays
     .lead-delivery          "Include delivery estimate" box in the lead form
     .dq-bar-link            "+ $X delivery" in the mobile sticky bar
   The lead box and the bar line appear only while a deliverable estimate
   exists (owner); nothing delivery-related shows there before that.
   ===================================================================== */

/* ---------- Section layout ---------- */
.dq-pickup {
    margin: -6px 0 18px;
    font-size: 0.95rem;
    line-height: 1.6;
    color: var(--text-dark);
}
.dqb { container-type: inline-size; }
.dqb[hidden] { display: none; }
.delivery-quote-box {
    background-color: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 18px;
}
.dqb-map { margin-top: 20px; height: 320px; }
/* On phones detail.js moves the result block in front of the map (same
   margins either way) and, after "Calculate", scrolls it to just under the
   header + pills: hence the scroll margin. */
.dqb-result { margin-top: 20px; scroll-margin-top: 164px; }
.dqb-result[hidden] { display: none; }
.dqb-route-title { white-space: normal !important; overflow-wrap: anywhere; }
.dqb-remember {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: 12px;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--text-dark);
}
.dqb-remember[hidden] { display: none; }
.dqb-remember .dq-text-btn { padding: 0; }

/* ---------- Form ---------- */
.dq-label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--primary-dark);
    margin-bottom: 8px;
}
/* The row wraps: the field keeps at least 240px beside the button; with
   less room than that (every phone width up to ~490px) the button drops
   under the field and both take the full width. */
.delivery-input-row { display: flex; flex-wrap: wrap; gap: 10px; }
.delivery-input-row input {
    flex: 999 1 240px;
    min-width: 0;
    min-height: 46px;
    padding: 12px 14px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: 1rem;                 /* 16px: no iOS zoom-on-focus */
    color: var(--text-dark);
    background-color: var(--bg-white);
    transition: var(--transition-fast);
}
.delivery-input-row input::placeholder { color: var(--text-muted); opacity: 1; }
.delivery-input-row input:focus { outline: none; border-color: var(--primary-light); }
.delivery-input-row input:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; }
.delivery-input-row input[aria-invalid="true"] { border-color: #e53935; }
.dq-submit {
    position: relative;
    flex: 1 0 auto;
    min-height: 46px;
    padding: 12px 22px;
}
.dq-submit:focus-visible,
.dq-map-show:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; }
.dq-submit[aria-disabled="true"] { cursor: progress; transform: none; box-shadow: none; opacity: 0.85; }
/* The label is hidden, not swapped, while a lookup runs: the button keeps its
   width, so the row cannot re-wrap. */
.dq-submit .dq-spinner { display: none; position: absolute; inset: 0; margin: auto; }
.dq-form.is-loading .dq-submit .dq-spinner { display: block; }
.dq-form.is-loading .dq-submit-text { visibility: hidden; }
.dq-error {
    margin-top: 8px;
    font-size: 0.85rem;
    font-weight: 500;
    line-height: 1.4;
    color: #c62828;
}
.dq-error[hidden] { display: none; }
.dq-error.is-note { color: var(--accent-teal-text); }      /* "That's our dealership": a note, not an error */
.delivery-note {
    margin-top: 10px;
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--text-muted);
}
.delivery-note a,
.dq-canada p a:not(.dq-link) { color: var(--primary-link); font-weight: 600; white-space: nowrap; }
.delivery-note a:hover,
.dq-canada p a:not(.dq-link):hover { text-decoration: underline; }
.delivery-note a:focus-visible,
.dq-canada p a:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; border-radius: 3px; }

.dq-spinner {
    flex: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid rgba(15, 41, 66, 0.25);
    border-top-color: var(--primary-dark);
    animation: dq-spin 0.8s linear infinite;
}
@keyframes dq-spin { to { transform: rotate(360deg); } }

/* ---------- Map ----------
   .dq-map-ph is a static outline of the lower 48 with the dealership dot: it
   is what the box shows until the shopper asks for a route, so the page
   never loads Google on its own. .is-live swaps it for the Google map. */
.dq-map {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background-color: #e3ebf3;
}
.dq-map-ph { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.dq-map-land { fill: var(--bg-light); stroke: #c2cedb; stroke-width: 1; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.dq-map-lake { fill: #e3ebf3; stroke: #c2cedb; stroke-width: 1; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.dq-map-origin circle { fill: var(--primary-dark); stroke: #fff; stroke-width: 3; vector-effect: non-scaling-stroke; }
.dq-map-origin .dq-map-origin-dot { fill: #fff; stroke: none; }
.dq-map-canvas { position: absolute; inset: 0; display: none; }
.dq-map.is-live .dq-map-canvas { display: block; }
.dq-map.is-live .dq-map-ph { display: none; }
.dq-map:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; }
.dq-map-legend {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    max-width: calc(100% - 20px);
    list-style: none;
    pointer-events: none;
}
.dq-map-legend li {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
    padding: 2px 8px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background-color: var(--bg-white);
    box-shadow: var(--shadow-sm);
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.6;
    color: var(--primary-dark);
}
.dq-map-legend li[hidden] { display: none; }
.dq-map-legend li + li { border-color: rgba(255, 193, 7, 0.7); }
.dq-map-legend li > :last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dq-map-key { flex: none; width: 10px; height: 10px; border-radius: 50%; }
.dq-map-key-origin { background-color: #fff; border: 3px solid var(--primary-dark); }
.dq-map-key-dest { background-color: var(--accent-gold); border: 1.5px solid var(--primary-dark); }
.dq-map-cta,
.dq-map-busy {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 16px;
}
.dq-map-cta[hidden],
.dq-map-busy[hidden] { display: none; }
.dq-map-busy {
    background-color: rgba(248, 249, 250, 0.78);
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--primary-dark);
}
.dq-map-show { gap: 8px; min-height: 46px; padding: 12px 20px; box-shadow: var(--shadow-md); }

/* ---------- Result ---------- */
.dq-stats .f-stat-l { line-height: 1.35; }     /* the price label is long: it may wrap */
.dq-stats .f-stat-v { white-space: normal; overflow-wrap: anywhere; }   /* never wider than its tile */
.dq-rows { display: grid; margin-top: 12px; }
.dq-rows > div {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    padding: 10px 0;
    border-top: 1px solid var(--border-color);
    font-size: 0.9rem;
    min-width: 0;
}
.dq-rows dt { min-width: 0; color: var(--text-muted); overflow-wrap: anywhere; }
.dq-rows dd { flex: 0 0 auto; max-width: 100%; margin: 0; text-align: right; font-weight: 700; color: var(--primary-dark); overflow-wrap: anywhere; }
.dq-rows dd small { font-size: 0.78rem; font-weight: 500; color: var(--text-muted); }
.dq-rows .dq-free { color: var(--accent-teal-text); }
.dq-disclaimer { margin-top: 8px; font-size: 0.75rem; line-height: 1.5; color: var(--text-muted); }

.dq-canada { display: flex; align-items: flex-start; gap: 12px; }
.dq-canada[hidden] { display: none; }
.dq-canada > div { min-width: 0; }
.dq-canada-title {
    font-family: var(--font-headings);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--primary-dark);
    margin: 4px 0 6px;
    overflow-wrap: anywhere;
}
.dq-canada p { font-size: 0.9rem; line-height: 1.6; color: var(--text-dark); }
.dq-canada p + p { margin-top: 8px; }
.dq-link,
.dq-text-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--primary-link);
    border-radius: 4px;
}
.dq-text-btn { padding: 4px 2px; }
.dq-link:hover,
.dq-text-btn:hover { text-decoration: underline; }
.dq-link:focus-visible,
.dq-text-btn:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; }

.dq-skeleton { display: grid; gap: 10px; }
.dq-skeleton[hidden] { display: none; }
.dq-skeleton span {
    display: block;
    height: 14px;
    border-radius: 7px;
    background: linear-gradient(90deg, #e9edf2 25%, #f4f6f8 37%, #e9edf2 63%) 0 0 / 300% 100%;
    animation: dq-shimmer 1.2s linear infinite;
}
.dq-skeleton span:nth-child(1) { width: 55%; }
.dq-skeleton span:nth-child(2) { width: 34%; height: 30px; border-radius: 8px; }
.dq-skeleton span:nth-child(3) { width: 78%; }
@keyframes dq-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

/* ---------- Lead form: "Include delivery estimate" box ----------
   Sits under the phone field once a deliverable estimate exists. "Change"
   is part of the sentence, so the box is no taller than its text. */
.lead-delivery { margin-bottom: 10px; }
.lead-delivery[hidden] { display: none; }
.lead-delivery-line {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 8px 4px 8px 10px;
    border: 1px solid rgba(18, 165, 148, 0.35);
    border-radius: var(--radius-sm);
    background-color: rgba(18, 165, 148, 0.08);
    font-size: 0.8rem;
    line-height: 1.45;
    color: var(--text-dark);
}
.lead-delivery-line[hidden] { display: none; }
.lead-delivery-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.lead-delivery-text strong { color: var(--primary-dark); }
.lead-delivery-change {
    position: relative;
    margin-left: 2px;
    font-weight: 600;
    color: var(--primary-link);
    white-space: nowrap;
    border-radius: 3px;
}
.lead-delivery-change:hover { text-decoration: underline; }
.lead-delivery-remove {
    position: relative;
    flex: none;
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    margin: -3px 0;
    border-radius: 50%;
    color: var(--text-muted);
}
.lead-delivery-remove::after { content: ""; position: absolute; inset: -8px; }   /* 44px hit area */
.lead-delivery-remove:hover { background-color: rgba(15, 41, 66, 0.08); color: var(--primary-dark); }
.lead-delivery-add {
    display: block;
    width: 100%;
    min-height: 44px;
    padding: 6px 2px;
    text-align: left;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--primary-link);
    border-radius: 4px;
}
.lead-delivery-add[hidden] { display: none; }
.lead-delivery-add:hover { text-decoration: underline; }
.lead-delivery-change:focus-visible,
.lead-delivery-remove:focus-visible,
.lead-delivery-add:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; }

/* ---------- Mobile sticky bar line (only with an estimate) ---------- */
.dq-bar-link {
    position: relative;
    align-self: flex-start;
    margin-top: 2px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.3;
    text-align: left;
    white-space: nowrap;
    color: var(--primary-link);
    border-radius: 3px;
}
.dq-bar-link[hidden] { display: none; }
/* 46px-tall hit area without growing the bar (same technique as
   .vdp-get-approved-link). It reaches down into the bar's 12px bottom padding
   and no further (anything below the bar is off screen), and up over the
   monthly line above it, which is not interactive. */
.dq-bar-link::after { content: ""; position: absolute; left: -6px; right: -6px; top: -19px; bottom: -11px; }
.dq-bar-link:focus-visible { outline: 2px solid var(--primary-link); outline-offset: 2px; }

/* Keyboard focus must not land under the pinned stack (header 73 + section
   nav) or, on phones, under the sticky price bar. The form itself is in the
   list for the message under the field: detail.js brings field + message
   into view when a lookup ends in one. */
.dq-form,
.dq-form :is(input, button),
.dq-map-show,
.dq-text-btn,
.dq-link,
.lead-delivery-change,
.lead-delivery-remove,
.lead-delivery-add { scroll-margin: 164px 0 24px; }

@container (max-width: 600px) {
    .dqb-map { height: 240px; margin-top: 16px; }
    .dq-map-origin { transform: scale(1.7); }
}
@media (max-width: 1024px) {
    /* Touch layouts: 44px targets. "Change" stays in the sentence; its hit
       area grows above and below the line and stops at the text block's
       right edge, where the remove button's own 44px area begins. */
    .dqb-remember .dq-text-btn { min-height: 44px; }
    .dq-canada .dq-link { min-height: 44px; }
    .lead-delivery-change::after { content: ""; position: absolute; left: -8px; right: 0; top: -15px; bottom: -15px; }
}
@media (max-width: 768px) {
    .delivery-quote-box { padding: 16px; }
    .dqb-result { scroll-margin-top: 156px; }
    .dq-form,
    .dq-form :is(input, button),
    .dq-map-show,
    .dq-text-btn,
    .dq-link,
    .lead-delivery-change,
    .lead-delivery-remove,
    .lead-delivery-add { scroll-margin: 156px 0 110px; }
}
@media (max-width: 359px) {
    /* 320px phones, and only while the delivery line is showing
       (.has-delivery, set by detail.js): the line widens the price block,
       which leaves "Get Lowest Price" ~10px short of one line. Tighten the
       button for that state; without an estimate the bar is untouched. */
    .vdp-mobile-bar.has-delivery { gap: 10px; }
    .vdp-mobile-bar.has-delivery .btn { min-height: 44px; padding: 13px 8px; font-size: 0.8rem; letter-spacing: 0.02em; white-space: nowrap; }
}
@media (prefers-reduced-motion: reduce) {
    .dq-spinner,
    .dq-skeleton span { animation: none; }
}

/* =====================================================================
   Mobile price bar, plan doc 38 (the bar itself: "Mobile sticky CTA bar"
   above; it exists up to 768px).

   1. It steps aside while the lead form (first field to submit button)
      is on screen: the Build & Price bar's rule (build.css 8.4), applied
      to the form itself and not to the sentence above it. The inline
      script after the bar in site/.vdp-v2 sets the first state while the
      page is parsed; initPriceBar() in detail.js takes over from it.
      .is-away: while the form is between the header and the bar, and for
      the rest of the page view once a request has been sent.
      .is-live: the slide. It goes on only after a state has been painted
      (and comes off above 768px, where there is no bar and detail.js
      leaves it .is-away), so the first state, on arrival or after a
      rotation, is simply there: no slide, and no bar drawn first.

      Without any class the bar is VISIBLE. Nothing here hides a bar that
      a script has not asked to hide, so no failure can leave it hidden
      (no script, a script that does not arrive or stops: the bar stays).

   2. The thumbnail strip keeps its height before detail.js fills it.
      The inline script measures where the form is before detail.js has
      run; the strip used to grow from 6px to 61px (78.5px from 769px)
      when it did, which moved the form down 55px on every page whose
      script came after the first paint (a layout shift of 0.04, and a
      first state that was right for one frame only). Reserved only where
      scripting is on, and given back when the page script did not arrive
      (.page-js-failed, site/.footer-v2): without the script there are no
      thumbnails. Figures: the thumb's width (116px, 88px up to 768px) at
      16:10, plus the strip's 6px of bottom padding.

   3. Room under the footer. At the end of the page the footer's bottom
      edge is the window's, so the fixed bar covered the last lines of the
      disclaimer. The footer of a page that HAS the bar (the bar comes
      before the footer in the HTML; the staff page inventory/view has
      none) gets the bar's height as extra bottom padding, in its own
      colour: --vdp-bar-h, the height initPriceBar() measured (it
      includes the bar's safe-area padding and grows with the text size
      and the delivery line); before the script, or without it, 75px for
      the 74.9px bar, 93px while the delivery line is showing (92.5px),
      plus the safe-area term. The footer's own 32px stay above the bar
      as the gap. The room does not follow .is-away: nothing at the end
      of the page moves when the bar comes and goes.
   ===================================================================== */
.vdp-mobile-bar.is-live { transition: transform 0.2s ease; }
.vdp-mobile-bar.is-away { transform: translateY(110%); visibility: hidden; }
/* visibility waits for the slide on the way out only: a returning bar is
   visible (and focusable, detail.js hands focus back to it) at once */
.vdp-mobile-bar.is-live.is-away { transition: transform 0.2s ease, visibility 0.2s; }
@media (scripting: enabled) {
    .vdp-thumbs { min-height: calc(116px * 0.625 + 6px); }
    html.page-js-failed .vdp-thumbs { min-height: 0; }
}
@media (max-width: 768px) {
    .vdp-mobile-bar ~ .site-footer { padding-bottom: var(--vdp-bar-h, calc(75px + env(safe-area-inset-bottom, 0px))); }
    .vdp-mobile-bar.has-delivery ~ .site-footer { padding-bottom: var(--vdp-bar-h, calc(93px + env(safe-area-inset-bottom, 0px))); }
}
@media (scripting: enabled) and (max-width: 768px) {
    .vdp-thumbs { min-height: calc(88px * 0.625 + 6px); }
}
@media (prefers-reduced-motion: reduce) {
    .vdp-mobile-bar.is-live,
    .vdp-mobile-bar.is-live.is-away { transition: none; }
}
