/* ===================================
    Carzon brand layer (CZN-22 tokens)

    Loads AFTER css/style.css, css/responsive.css and demos/real-estate/real-estate.css.
    The vendored theme files stay untouched so they can be re-vendored on a theme
    update; every Carzon-specific value lives here.

    Palette per CZN-26 (see docs/brand-palette.md): midnight navy + platinum,
    replacing the red the logo SVG was sampled for. The rendered mark is
    carzon-logo-white.svg, which is monochrome white, so nothing on screen is
    tied to the old #CB2027 — but carzon-logo-original.svg still carries it and
    should be re-issued by the client to match.
====================================== */

:root {
    --base-color: #1a5091;          /* midnight navy — the ONLY accent */
    --dark-gray: #0e1420;           /* navy-black chrome */
    --medium-gray: #6b7280;
    --extra-medium-gray: #bfc1c2;   /* platinum, demoted to the line/border neutral */
    /* The Crafto base leaves this at #f7f7f7, a warm neutral that sits visibly
       apart from a cool palette. bg-very-light-gray is on-page 8 times, so it
       has to be re-tokened here or those bands strand behind the rest. */
    --very-light-gray: #f4f6f9;
    --alt-font: 'Urbanist', sans-serif;
    --primary-font: 'Urbanist', sans-serif;
}

/* ---- accent tints -------------------------------------------------------
   real-estate.css hardcodes its green into three tint values that don't read
   from --base-color. Re-derive them from the brand navy. */
.bg-base-color-transparent { background-color: rgba(26, 80, 145, .15); }
.bg-base-color-light       { background-color: #eef3fa; }
.btn.btn-light-base-color  { background-color: #d8e4f2; border-color: #d8e4f2; color: var(--dark-gray); }

/* The eyebrow accent, for the one ground it cannot survive (CZN-28).

   `text-base-color` sets every section eyebrow on the site, and the navy holds
   against both grounds it had until now: white bands, and the near-black
   #0e1420 of the branches section. A mid-tone photograph is a third case — the
   import-to-order band sits on open sea under an overcast, and #1a5091 against
   that is mud.

   So this is a modifier rather than a change to the accent: the other nine
   eyebrows are correct and must not move. The value is the tint the theme
   already carries for buttons on dark, so no new colour enters the palette. */
.text-base-color-light     { color: #d8e4f2; }

/* Navy is the only accent — neutralise the demo's secondary hues so a stray
   class can never introduce a third colour. */
.bg-orange   { background-color: var(--base-color); }
.text-orange { color: var(--base-color); }
.text-red    { color: var(--base-color); }

/* ---- chrome -------------------------------------------------------------
   Dark header / hero / footer over light content bands. */
.bg-dark-gray  { background-color: var(--dark-gray); }
.footer-dark   { background-color: var(--dark-gray); }

/* Dark automotive ground wherever the demo used stock photography. */
.carzon-dark-ground {
    background-image: linear-gradient(120deg, #080b12 0%, #141a26 48%, #16283f 100%);
}

/* ---- hero ---------------------------------------------------------------
   The demo's banner is a full-screen swiper wrapper, so its height and its
   padding belonged to the slides. Carzon's hero is an ordinary section holding
   a statement beside a list of stock — nothing here is a slide — so the
   geometry lives on the section itself.

   The demo's banner sits under a transparent header and can start at y=0.
   Carzon's header is solid and position:fixed (CZN-18), so it covers the top
   100px of whatever is beneath it (84px below lg) and the hero pays for that
   in padding. --cz-header-h carries the measurement.

   `position: relative` is load-bearing here and not tidiness: the three
   background layers below are absolutely positioned children of this section. */
.carzon-hero {
    position: relative;
    min-height: 100vh;
    display: flex;
    align-items: center;
    padding-top: calc(var(--cz-header-h) + var(--cz-space-lg));
    padding-bottom: var(--cz-space-xl);
}

/* Five layers where this section used to have one.

   ~~A single three-stop gradient across a whole viewport reads as empty, and
   Carzon has no landscape photography to put behind the words — every real
   image in the repo is a portrait car shot or a portrait handover (PH-17). So
   the depth is built rather than shot. Nothing here loads a file.~~

   Amended by CZN-28. The reason the demo's banner was dropped was the absence of
   landscape imagery, not a preference for building it — so when that stopped
   being true, this reopened. There is now a photograph underneath, and the three
   built layers stayed exactly where they were and became its scrim. The
   composition was chosen against them: an empty hall whose left half is unbroken
   shadow, because that is where the h1 lands.

   Layer 0, the photograph. Out of flow like the rest, and first in the stack so
   everything below paints over it. It is generated, non-representational imagery
   registered as PH-24 — no vehicle, no branch, no third-party mark. */
.carzon-hero-photo {
    position: absolute;
    inset: 0;
}

.carzon-hero-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Off-centre to the left, which is not where the interest is — it is where the
       interest has to go. The source's bright glazing sits on its right, and the
       stock panel sits on the section's right, so centring the crop put the panel's
       prices over the busiest, brightest part of the frame. Pulling to 40% moves
       the calm interior behind the panel and pushes the glazing to the edge. */
    object-position: 40% 50%;
}

/* Layer 1, the ground: a wider spread than the flat gradient it replaces, and
   warmed toward the brand navy on the right rather than staying neutral.

   Now carries alpha, which is the whole of the change CZN-28 made here. Same
   angle, same three stops, same colours — the photograph shows through at 8% on
   the left and 38% on the right. Those two numbers are the contrast budget for
   the headline, and they were set by compositing candidates under this exact
   ramp with .claude/skills/carzon-media/scripts/band-preview.sh rather than by
   eye in the browser. Lower them and the copy starts to fight the picture. */
.carzon-hero-ground {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(85% 65% at 50% 120%, rgb(26 80 145 / 26%) 0%, transparent 70%),
        linear-gradient(118deg, rgb(5 7 12 / 92%) 0%, rgb(13 19 32 / 82%) 46%, rgb(20 38 60 / 62%) 100%);
}

/* Layer 2, measured rules. Barely visible on purpose: at 4% they read as
   precision when you are not looking at them and as a pattern when you are.
   Masked toward the top right, so the copy never sits on a ruled page and the
   rules are strongest exactly where the stock panel is. */
.carzon-hero-grid {
    position: absolute;
    inset: 0;
    background-image:
        repeating-linear-gradient(90deg, rgb(255 255 255 / 4%) 0 1px, transparent 1px 104px),
        repeating-linear-gradient(0deg, rgb(255 255 255 / 4%) 0 1px, transparent 1px 104px);
    -webkit-mask-image: radial-gradient(120% 110% at 82% 8%, #000 0%, transparent 72%);
    mask-image: radial-gradient(120% 110% at 82% 8%, #000 0%, transparent 72%);
}

/* Layer 3, a light source behind the stock panel so the panel has something to
   sit in front of, and a vignette in the opposite corner so the copy has
   something to sit on. This is the layer doing most of the work. */
.carzon-hero-glow {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(46% 52% at 76% 34%, rgb(38 105 186 / 42%) 0%, transparent 68%),
        radial-gradient(70% 45% at 6% 92%, rgb(0 0 0 / 55%) 0%, transparent 70%);
}

/* The three layers are out of flow, so the content needs to be told to stack
   above them. */
.carzon-hero-body {
    position: relative;
    z-index: 2;
}

/* ---- hero promises ------------------------------------------------------
   Closes the copy column. The corner under the CTAs was blank, and a blank
   corner in a 100vh section is most of what "it feels pretty empty" meant. */
/* Across the foot of the whole section, not under the copy. The empty corner
   was the right-hand one — the stock panel is shorter than the column beside
   it, and a strip stopping at the halfway line leaves exactly the gap it was
   added to close. Full width it reads as a floor for the section. */
.carzon-hero-proof {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--cz-space-sm);
    list-style: none;
    margin: var(--cz-space-lg) 0 0;
    padding: var(--cz-space-sm) 0 0;
    border-top: 1px solid rgb(255 255 255 / 12%);
}

.carzon-hero-proof li {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 15px;
    color: rgb(255 255 255 / 62%);
}

/* The brand red is mixed for a white ground; on this one it goes muddy, so it
   is brightened here rather than a second red being added to the palette. */
.carzon-hero-proof i {
    font-size: 17px;
    color: var(--base-color);
    filter: brightness(1.65);
}

/* ---- hero stock panel ---------------------------------------------------
   Three vehicles at once, where this was one card rotating on a 4.5s timer.
   The rotation was never the problem the timer was solving: a single card in
   the middle of a tall column has no top and no bottom, so the column read as
   empty however good the card was. A list has both.

   Losing the swiper also retires the constraint that governed everything in
   here — Swiper loops by cloning slide DOM with cloneNode, which copies markup
   but not Vue listeners, so no control in this panel was ever allowed to be
   more than a plain link. */
.carzon-hero-panel {
    padding: var(--cz-space-sm);
    border: 1px solid rgb(255 255 255 / 12%);
    border-radius: 8px;
    background-color: rgb(255 255 255 / 4%);
    backdrop-filter: blur(6px);
}

.carzon-hero-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 6px;
    font-family: var(--alt-font);
    font-size: 13px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: rgb(255 255 255 / 45%);
}

.carzon-hero-all {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: #fff;
    letter-spacing: .5px;
    transition: opacity .3s ease;
}
.carzon-hero-all:hover,
.carzon-hero-all:focus-visible { color: #fff; opacity: .7; }

.carzon-hero-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 0;
    border-bottom: 1px solid rgb(255 255 255 / 10%);
    color: #fff;
}
.carzon-hero-row:last-child { padding-bottom: 0; border-bottom: 0; }
.carzon-hero-row:hover,
.carzon-hero-row:focus-visible { color: #fff; }
.carzon-hero-row:hover .carzon-hero-row-title { text-decoration: underline; }

/* The background colour shows while the photograph decodes, and on the one
   vehicle in the queue that has no photograph at all. */
.carzon-hero-shot {
    flex: 0 0 auto;
    width: 88px;
    height: 62px;
    object-fit: cover;
    border-radius: 4px;
    background-color: #0b0f18;
}

.carzon-hero-row-main { flex: 1 1 auto; min-width: 0; }

/* Truncated rather than wrapped. Upstream titles run to "2021 TOYOTA ALPHARD
   2.5 SC PACKAGE SUNROOF", and a three-line row makes the panel taller than
   the column it is balancing. */
.carzon-hero-row-title {
    display: block;
    overflow: hidden;
    font-family: var(--alt-font);
    font-size: 16px;
    font-weight: 700;
    line-height: 1.25;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.carzon-hero-row-meta {
    display: block;
    margin-top: 3px;
    font-size: 13px;
    color: rgb(255 255 255 / 52%);
}

.carzon-hero-row-price {
    flex: 0 0 auto;
    font-family: var(--alt-font);
    font-size: 16px;
    font-weight: 700;
    white-space: nowrap;
}

@media (max-width: 991px) {
    /* Below lg the two columns stack, so a locked viewport height either crops
       the panel or strands the copy at the top of the screen. Size to content;
       the padding above already tracks the header via --cz-header-h. */
    .carzon-hero {
        min-height: 0;
    }

    /* The mask is aimed at a two-column layout — it fades the rules out of the
       bottom left, which is where the copy is only while the copy is beside
       the panel. Stacked, that corner is the panel. Drop the mask and take the
       whole layer down instead. */
    .carzon-hero-grid {
        -webkit-mask-image: none;
        mask-image: none;
        opacity: .5;
    }

    /* Three across is a phone's whole width for one line of text. Stack, and
       give the strip back the tighter spacing it can afford when it is not
       spanning the section. */
    .carzon-hero-proof {
        grid-template-columns: minmax(0, 1fr);
        gap: 12px;
        margin-top: var(--cz-space-md);
        padding-top: var(--cz-space-sm);
    }
}

/* ---- logo ---------------------------------------------------------------
   The SVGs ship with viewBox cropped to the art band (~3.6:1); height-driven
   sizing keeps the wordmark optically level with the nav links. */
header .navbar-brand img { max-height: 40px; height: 40px; width: auto; }
footer .footer-logo img  { max-height: 36px; height: 36px; width: auto; }

/* ---- prohibited surfaces ------------------------------------------------
   Trustpilot / third-party review widgets are not a Carzon surface (CZN-22),
   and partner or client logo strips are prohibited everywhere (CZN-12).
   Belt-and-braces: the markup carries none, this stops a transplant from
   reintroducing one. */
img[src*="trustpilot"] { display: none; }

/* ---- spec chips ---------------------------------------------------------
   The real-estate listing card's bed/bath/size icon columns become the
   vehicle card's year / mileage / transmission columns. */
.vehicle-spec-icon {
    width: 18px;
    height: 18px;
    opacity: .75;
}

/* Ready-stock badge — the demo's SELL/RENT pill, re-tokened. */
.badge-ready-stock {
    background-color: var(--base-color);
    color: #fff;
    letter-spacing: .5px;
}

/* ---- body-type pills ----------------------------------------------------
   The demo's apartment/condo/office row is an icon row. Bootstrap Icons and
   Font Awesome both collapse sedan, hatchback and SUV onto one car glyph, so
   half the row read as duplicates (CZN-18). Icons are dropped for text pills
   (CZN-21): nothing left to misread, and it sits better with the restrained
   tone. No stock counts — CZN-18 ruled a guessed count is a claim we cannot
   honour; counts become real when Phase 2 sync lands (CZN-20). */
.carzon-pill {
    display: inline-block;
    padding: 11px 26px;
    border: 1px solid var(--extra-medium-gray);
    border-radius: 30px;
    font-family: var(--alt-font);
    font-weight: 600;
    font-size: 16px;
    line-height: 20px;
    letter-spacing: -.2px;
    color: var(--dark-gray);
    background-color: transparent;
    transition: background-color .3s ease, border-color .3s ease, color .3s ease;
}
.carzon-pill:hover,
.carzon-pill:focus-visible {
    background-color: var(--base-color);
    border-color: var(--base-color);
    color: #fff;
}

/* ---- values accordion numeral -------------------------------------------
   accordion-style-05 pins .number at left:-13px inside an overflow:hidden
   item, so the theme deliberately crops the glyph. At Urbanist's width that
   slices "01" down the middle of the zero and reads as a rendering fault
   rather than a design device. The item already carries 65px of left padding,
   so the numeral has room to sit fully inside. */
.accordion-style-05 .accordion-item .number { left: 10px; }

/* ---- sourcing route graphic ---------------------------------------------
   Backs Components/RouteGraphic.vue. Abstract band, not a map — Crafto ships
   no world-map component, and an invented coastline is a fact we would have to
   defend. Silver lines, red terminus, on the dark ground. */
.carzon-route svg { width: 100%; height: auto; display: block; }

.carzon-route-line {
    fill: none;
    stroke: var(--extra-medium-gray);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-dasharray: 3 11;
    opacity: .55;
}
.carzon-route-trunk { opacity: .8; }
.carzon-route-head  { fill: var(--extra-medium-gray); opacity: .8; }
.carzon-route-node  { fill: var(--extra-medium-gray); }
.carzon-route-node-end { fill: var(--base-color); }
.carzon-route-ring {
    fill: none;
    stroke: var(--base-color);
    stroke-width: 1.5;
    opacity: .35;
}
.carzon-route-label {
    fill: #fff;
    font-family: var(--alt-font);
    font-size: 17px;
    font-weight: 600;
    letter-spacing: 2px;
    opacity: .7;
}
.carzon-route-label-end { fill: var(--base-color); opacity: 1; }

/* Dash flow reads as movement along the route. Pure CSS, so unlike the retired
   magic cursor it needs no per-navigation init or teardown (CZN-18). */
@media (prefers-reduced-motion: no-preference) {
    .carzon-route-line { animation: carzon-route-flow 2.4s linear infinite; }
}
@keyframes carzon-route-flow {
    to { stroke-dashoffset: -28; }
}

/* Labels are set in viewport-independent SVG units, so they shrink with the
   graphic. Below md that lands under ~11px — bump them back up. */
@media (max-width: 767px) {
    .carzon-route-label { font-size: 26px; letter-spacing: 1px; }
}

/* ---- floating WhatsApp button ------------------------------------------- */
.whatsapp-float {
    position: fixed;
    right: 30px;
    bottom: 30px;
    z-index: 1000;
    width: 58px;
    height: 58px;
    border-radius: 50%;
    background-color: #25d366;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 12px 30px rgba(0, 0, 0, .28);
    transition: transform .3s ease;
}
.whatsapp-float:hover { transform: scale(1.08); color: #fff; }
.whatsapp-float i { font-size: 26px; }

@media (max-width: 767px) {
    .whatsapp-float { right: 18px; bottom: 18px; width: 52px; height: 52px; }
    .whatsapp-float i { font-size: 23px; }
}

/* ---- handover photo tiles -----------------------------------------------
   The "Recently collected" band and the /customers gallery (CZN-25). Kept under
   its own prefix rather than reusing carzon-reel-*, and that turned out to matter:
   CZN-24 deleted the reel layer entirely and this band outlived it unchanged.

   Sources are all portrait 3:4, so the ratio is declared here rather than trusted
   to the file — a swapped-in photo of another shape crops instead of reflowing
   the grid. */
.carzon-photo-tile {
    position: relative;
    overflow: hidden;
    border-radius: 6px;
    background-color: var(--dark-gray);
}
.carzon-photo-tile-img {
    display: block;
    width: 100%;
    aspect-ratio: 3 / 4;
    object-fit: cover;
    transition: transform .4s cubic-bezier(.25, .46, .45, .94);
}
.carzon-photo-tile:hover .carzon-photo-tile-img { transform: scale(1.05); }

/* Same gradient-over-figure treatment the branch cards use, so the two photo
   surfaces on the page read as one system. The scrim is what keeps the caption
   legible over a bright bonnet. */
.carzon-photo-tile-caption {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    padding: 60px 20px 18px;
    background-image: linear-gradient(to bottom, rgba(8, 11, 18, 0) 0%, rgba(8, 11, 18, .85) 100%);
    font-family: var(--alt-font);
    font-size: 14px;
    line-height: 20px;
    color: rgba(255, 255, 255, .75);
    pointer-events: none;
}
.carzon-photo-tile-caption .fw-600 { color: #fff; font-size: 16px; }

@media (prefers-reduced-motion: reduce) {
    .carzon-photo-tile-img { transition: none; }
    .carzon-photo-tile:hover .carzon-photo-tile-img { transform: none; }
}

/* ---- delivery video tiles -----------------------------------------------
   The client's own footage of a customer collecting their car (CZN-24), replacing
   the Instagram and TikTok embeds this layer used to hold.

   Two things the embeds could not do, and the reason for the swap: the tile is a
   fixed 9:16 frame — we own the file, so there is no third-party card of unknown
   height wrapping it — and the poster is a real frame of the video rather than an
   empty rectangle waiting on somebody else's script.

   Nothing here autoplays. Six clips on the landing page would be the droplet
   serving bytes it used to hand to Meta and ByteDance, on a box shared with three
   live client sites (docs/infra-decisions.md). preload="none" plus a poster means
   a tile costs one JPEG until somebody actually wants to watch it. */
.carzon-delivery {
    position: relative;
    display: block;
    aspect-ratio: 9 / 16;
    overflow: hidden;
    border-radius: 6px;
    background-color: var(--dark-gray);
}
.carzon-delivery-video {
    display: block;
    width: 100%;
    height: 100%;
    background-color: var(--dark-gray);
}
/* Portrait fills the frame; anything landscape is letterboxed rather than centre-
   cropped, because cropping a wide handover shot cuts out one of the two people in
   it. The class is chosen from the transcoded dimensions, which the card carries. */
.carzon-delivery-video-portrait { object-fit: cover; }
.carzon-delivery-video-landscape { object-fit: contain; }

/* The play affordance and the caption both belong to the not-yet-playing state, so
   they are one overlay that leaves together the moment playback starts. */
.carzon-delivery-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    transition: opacity .25s ease;
}
.carzon-delivery-playing .carzon-delivery-overlay { opacity: 0; pointer-events: none; }

.carzon-delivery-play {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 62px;
    height: 62px;
    border-radius: 50%;
    background-color: var(--base-color);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
    color: #fff;
    font-size: 20px;
    /* Nudged right: an equilateral triangle centred on its bounding box reads as
       sitting left of centre inside a circle. */
    padding-left: 4px;
    transition: transform .25s ease;
}
.carzon-delivery:hover .carzon-delivery-play { transform: scale(1.08); }

/* Same gradient-over-figure treatment the handover photo tiles and the branch cards
   use, so all three read as one family. */
.carzon-delivery-caption {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    padding: 34px 20px 18px;
    background: linear-gradient(to top, rgba(0, 0, 0, .78), rgba(0, 0, 0, 0));
    font-family: var(--alt-font);
    font-size: 14px;
    line-height: 1.45;
    text-align: left;
    color: rgba(255, 255, 255, .82);
}
.carzon-delivery-caption .fw-600 { color: #fff; font-size: 16px; }

.carzon-delivery-duration {
    position: absolute;
    top: 14px;
    right: 14px;
    padding: 3px 9px;
    border-radius: 30px;
    background-color: rgba(0, 0, 0, .55);
    font-family: var(--alt-font);
    font-size: 12px;
    color: #fff;
}
.carzon-delivery-playing .carzon-delivery-duration { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
    .carzon-delivery-play,
    .carzon-delivery-overlay { transition: none; }
    .carzon-delivery:hover .carzon-delivery-play { transform: none; }
}

/* ---- "recently collected" slider ----------------------------------------
   The landing band slides instead of stacking into a grid, and carries either
   filling — video tiles or handover photographs — through the same rules.

   Swiper sets `overflow: hidden` on `.swiper`, which clips at the *padding* edge.
   Without the padding below, the box-shadow on every tile is sliced off flush at
   the container bounds and the row reads as a strip of stickers. The matching
   negative margin gives the band back the footprint the grid occupied, so the
   heading above and the section padding below are unchanged. */
.carzon-collected {
    padding: 14px 14px 0;
    margin: -14px -14px 0;
}

/* Slides are equal-height by default in a flex wrapper; the tiles inside declare
   their own aspect ratio, so let them set the height rather than stretching. */
.carzon-collected .swiper-slide { height: auto; }

/* Pull the bullets out of Swiper's absolute-bottom default, where they would sit
   on top of the last few pixels of every tile, and put them in the flow between
   the tiles and the arrows. */
.carzon-collected .carzon-collected-pagination {
    position: static;
    width: 100%;
    margin-top: 30px;
    text-align: center;
    /* Swiper centres the bullet strip with `left: 50%` + `translateX(-50%)`, which
       assumes it is absolutely positioned. Taking it into the flow leaves the
       transform behind, dragging a now-full-width block half the band off to the
       left; both halves of that rule have to go, not just the position. */
    left: auto;
    transform: none;
}
.carzon-collected .carzon-collected-pagination .swiper-pagination-bullet {
    width: 8px;
    height: 8px;
    margin: 0 5px;
    background-color: var(--dark-gray);
    opacity: .25;
    transition: opacity .3s ease, background-color .3s ease;
}
.carzon-collected .carzon-collected-pagination .swiper-pagination-bullet-active {
    background-color: var(--base-color);
    opacity: 1;
}

/* Arrows read as decoration once there is nothing left to reach; Swiper marks the
   state for us. Hidden rather than removed so the row does not reflow mid-swipe. */
.carzon-collected .swiper-button-disabled {
    opacity: .35;
    pointer-events: none;
}

@media (max-width: 575px) {
    /* One tile per view, so the arrows are the only affordance that is not a swipe.
       Tighten the gap rather than dropping them. */
    .carzon-collected .carzon-collected-pagination { margin-top: 22px; }
}

/* =========================================================================
    Spacing & typographic rhythm (see docs/spacing-rhythm.md)

    The Crafto base emits two parallel spacing scales under one naming
    convention: `*-Npx` are literal pixels, but bare `*-N` for N in 1..30 are
    PERCENTAGES of the containing block's inline size (style.css:4566-5890).
    The pages were built with the percentage set, which has three consequences
    measured on the live site:

      - one structural pattern, four values. The heading-band gap rendered
        35.7 / 47.6 / 59.5 / 71.4px depending only on which page you were on.
      - gaps collapse faster than the rhythm around them. Section padding falls
        90px -> 50px between desktop and phone (-44%); the heading gaps fell
        35.7px -> 10.8px (-70%), so headings nearly touched their grids.
      - card padding is unpredictable, because a percentage resolves against
        column width. The same card rendered 29 / 64 / 74.4 / 75.4px, and
        About's milestone cards carried 68.4px of padding on a 390px phone.

    So the scale below is fluid and interpolates 390px -> 1440px instead of
    stepping, and it replaces the percentage utilities at every structural
    gap. Values are px on purpose: the base drops html font-size 16 -> 14 ->
    12px at 991/767 (responsive.css:40-42, 77-79), so a rem scale would shrink
    a second time on mobile and reintroduce exactly the collapse this removes.
========================================================================== */

:root {
    /* Header clearance. The header is solid and position:fixed (CZN-18), so
       anything at the top of the document pays for it. Measured, not guessed. */
    --cz-header-h: 100px;

    --cz-space-xs:  clamp(12px,  9.0286px + 0.7619vw,  20px);
    --cz-space-sm:  clamp(20px, 15.5429px + 1.1429vw,  32px);
    --cz-space-md:  clamp(32px, 26.0571px + 1.5238vw,  48px);
    --cz-space-lg:  clamp(44px,    33.6px + 2.6667vw,  72px);
    --cz-space-xl:  clamp(64px, 46.1714px + 4.5714vw, 112px);
    --cz-space-2xl: clamp(80px, 53.2571px + 6.8571vw, 152px);
}

@media (max-width: 991px) {
    :root { --cz-header-h: 84px; }
}

/* ---- section rhythm -----------------------------------------------------
   Replaces the base's stepped 110/90/75/50px (style.css:325-345 plus three
   responsive overrides). Airier at both ends: 50 -> 64px on a phone, 90 ->
   112px at 1440.

   The hero and the page-title band set their own top padding because both sit
   under the fixed header; they are excluded via :where(), which contributes no
   specificity, so this rule stays at (0,1,1) and the two explicit rules below
   -- and .cz-tight -- outrank it without needing !important. */
.page-layout section:not(:where(.carzon-hero, .carzon-page-title)) {
    padding-top: var(--cz-space-xl);
    padding-bottom: calc(var(--cz-space-xl) + var(--cz-section-rise, 0px));
}

/* Bands that are a rule rather than a section -- the body-type pill row. */
.page-layout section.cz-tight {
    padding-top: var(--cz-space-lg);
    padding-bottom: calc(var(--cz-space-lg) + var(--cz-section-rise, 0px));
}

/* The CTA band rises half its own height out of the footer, and it was eating
   the section above to do it: 84 of that section's 112px of bottom padding, so
   its last line sat 28px off the band while the band sat 112px off the footer
   columns. Raising the band's own padding alone would have driven that 28px
   toward zero, since a taller band rises further.

   --cz-overlap-rise is that half-height, published by AppLayout.vue from the
   same measurement that positions the band. Paying it here as extra padding
   keeps the clearance above the band at a full --cz-space-xl at every width,
   whatever the band's height. It is set as a variable rather than as padding
   so it composes with .cz-tight above instead of fighting its specificity, and
   it falls back to 0px when the overlap is off below 768.

   :last-of-type, not :has(+ footer.footer-dark). The sibling form was correct
   on four pages and silently wrong on the fifth: a vehicle detail page renders
   VehicleCtaBar -- a plain fixed-position div -- between its last section and
   the footer, so nothing matched, nothing paid the rise, and the related rail
   ended 28px off the band. Matching the last section by type instead is immune
   to whatever trailing non-section elements a page adds, and a v-if'd section
   leaves a comment node, which a type selector already ignores. */
.page-layout > section:last-of-type {
    --cz-section-rise: var(--cz-overlap-rise, 0px);
}

footer.footer-dark {
    padding-top: var(--cz-space-xl);
    padding-bottom: var(--cz-space-xl);
}

/* ---- the structural gaps ------------------------------------------------
   One value for one pattern. .cz-band is the gap between a section's heading
   band and the content beneath it, and it is the same number on every page. */
/* Top only, and deliberately not .cz-tight. The listings grid opens directly
   under a page-title band that has already introduced it, so a full section's
   padding on top of a full band put the first row of cars off the fold -- but
   the *bottom* has to keep the section rhythm, because on a first visit the
   recently-viewed rail below it does not render and this becomes the last
   section on the page. Tightened at both ends it would sit 72px off the footer
   CTA band where every other page sits 112px off it, and only for visitors who
   have not opened a car yet. */
.page-layout section.cz-tight-top { padding-top: var(--cz-space-lg); }

.cz-band     { margin-bottom: var(--cz-space-lg); }
.cz-band-top { margin-top:    var(--cz-space-lg); }

/* Card interiors. Two sizes, chosen by how wide the card actually is, because
   the failure mode being fixed was a 297px card carrying 74px of padding. */
.cz-card    { padding: var(--cz-space-md); }
.cz-card-lg { padding: var(--cz-space-lg); }

/* Readability cap. Replaces w-80/w-85/w-90/w-95, which set an arbitrary
   percentage of the column and produced 33ch and 43ch measures on About. */
.cz-measure { max-width: 65ch; }

/* Wide container. Bootstrap's .container tops out at 1320px, which is a good
   measure for prose and a poor one for a catalogue: on a 1728px screen the
   listings page spent 200px of either side on nothing and still had room for
   only two cards across.

   Opted into per page rather than raised globally -- About and Contact are
   reading pages and 1320px is the right cap for them. Only the grid, which is
   a browsing surface, wants the extra room.

   The 1400px floor is deliberate: below it this rule would compute *narrower*
   than the container it overrides, so it starts exactly where 100% - 80px and
   1320px are equal and only ever grows from there. 80px is the pair of side
   gutters the page keeps at every width up to the cap. */
@media (min-width: 1400px) {
    .container.carzon-wide { max-width: min(1720px, 100% - 80px); }
}

/* ---- page-title band ----------------------------------------------------
   The band started at y=0 with no top offset -- ipad-top-space-margin only
   fires at <=991px (responsive.css:20289) -- so the 100px header covered its
   top and the content centre landed 49px above the visible centre on every
   inner page at desktop. Paying the header in padding fixes both ends.

   Releasing the row's hardcoded height (style.css:4374, 300px !important) lets
   the band size to its content, so it stays centred whether the headline runs
   to one line or two. Total height is within a couple of px of the old 480. */
.page-layout section.carzon-page-title {
    padding-top: calc(var(--cz-header-h) + var(--cz-space-xl));
    padding-bottom: var(--cz-space-xl);
    /* Load-bearing, not tidiness: the two layers below are absolutely positioned
       children of this section, the same arrangement the hero uses. */
    position: relative;
}
.carzon-page-title .extra-small-screen { height: auto !important; }

/* ---- page-title backdrop (CZN-28 continued) -----------------------------
   PH-17 recorded this band as the last thing on the flat dark ground: the demo
   put a cover photograph here and Carzon had none, so it rendered as gradient.
   It now carries one, and it is the same picture on every inner page. That is
   deliberate. The band is chrome — PageTitle.vue exists because four copies of
   the same markup were drifting apart, and the header and footer above and below
   it are identical everywhere too. Varying it per page would make chrome look
   like content and invite a question with no honest answer.

   .carzon-dark-ground stays underneath, opaque and unmodified. A 404 on any of
   the six derivatives therefore renders exactly the band that shipped before
   this — the same graceful-degradation trick the footer CTA card uses, and the
   reason nothing here needed a new fallback colour.

   Measured geometry, because this slot's crop range is the widest on the site
   and it is not close:

     vw    band       aspect   from a 16:9 master
     2560  2560x498   5.14:1   35% of its height
     1440  1440x496   2.90:1   61% of its height
      768   768x381   2.01:1   89% of its height
      393   393x330   1.19:1   67% of its *width* — the crop axis flips

   Above 768 the band takes a horizontal slice out of the middle of the frame;
   at 393 it takes a vertical one instead. Nothing with a subject, a horizon or
   a load-bearing edge survives both. The picture is horizontally stratified for
   exactly that reason: uniform along x, so the phone crop is a no-op, and every
   horizontal slice means the same thing, so the desktop crop cannot land wrong. */
.carzon-title-photo {
    position: absolute;
    inset: 0;
}

.carzon-title-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Y is the only axis that does anything. On a 2.90:1 box over a 16:9 source
       the visible rows run [0.39p, 0.39p + 0.61], so sweeping p across 30-70
       moves the window through 16 points of the frame and gives four pages four
       visibly different bands out of one file. Below 992 the crop flips to the
       horizontal axis and this stops having any effect, which is correct —
       nobody holds two phones side by side to compare page-title bands. */
    object-position: 50% var(--cz-title-focus, 50%);
}

/* The same 120deg and the same three stops as .carzon-dark-ground, with alpha
   added — the move CZN-28 made to .carzon-hero-ground, for the same reason.

   74% -> 54%, swept 90/82/74/66/58 against the real candidate rather than
   guessed. 90 -> 72 was the first pass and it repeated the CTA card's mistake
   exactly: the band was indistinguishable from the flat gradient it replaced.
   Below about 66 -> 46 the stone reads as a lit wall and the headline starts
   sitting on texture rather than on ground.

   What the ramp actually protects, measured on the live page at 1440: the
   ground behind the headline is srgb(14,18,27), which is the header's own
   srgb(14,20,32) to within a couple of levels and gives white 18.7:1. The lit
   corner is srgb(55,66,81) — roughly eight times the header's luminance, so the
   band is *not* uniformly darker than the header and the seam between them is
   visible. That is the deliberate half of it: the corner is where the picture
   is allowed to be a picture, it carries no text on any of the four pages, and
   a dark bar over a lit photograph is exactly what the demo did here before
   Carzon had one. The invariant is the copy side, not the whole band. */
.carzon-title-ground {
    position: absolute;
    inset: 0;
    background: linear-gradient(120deg,
        rgb(8 11 18 / 74%) 0%,
        rgb(20 26 38 / 65%) 48%,
        rgb(22 40 63 / 54%) 100%);
}

/* The compact variant, for a page whose content is the point.

   At full height this band is ~460px before a single car is visible, which is
   a fair trade on About -- the band *is* the opening -- and a bad one on the
   grid, where it pushes the first row of stock off the fold on a laptop. The
   listing page keeps the same band, shorter: the rhythm drops from the section
   scale to the card scale, and the headline stops at 42px so it cannot claim
   two lines of a band that no longer has room for them.

   Three classes deep so it outranks the two-class rule above regardless of
   which lands first in the file. */
.page-layout section.carzon-page-title.carzon-page-title-compact {
    padding-top: calc(var(--cz-header-h) + var(--cz-space-sm));
    padding-bottom: var(--cz-space-sm);
}
.carzon-page-title-compact .carzon-breadcrumb { margin-bottom: var(--cz-space-xs); }
.page-layout .carzon-page-title-compact .page-title-extra-small h2 {
    font-size: clamp(30px, 22px + 1.5vw, 42px);
}
.carzon-page-title-compact .page-title-extra-small h1 { margin-bottom: 12px !important; }

/* ---- typography ---------------------------------------------------------
   Heading margin-bottom is a flat 30px in the base (style.css:255-283) and
   never moves; tie it to the rhythm. text-wrap:balance is what stops headings
   dropping a single word onto its own line -- Contact's "One message is all it
   / takes." was the visible case -- without touching the markup. */
.page-layout :is(h1, h2, h3, h4, h5, h6) {
    margin-bottom: var(--cz-space-sm);
    text-wrap: balance;
}
.page-layout p { text-wrap: pretty; }

/* Card labels are spans, so neither rule above reaches them -- and widening the
   cards (the padding fix) gave them room to strand a single word on the last
   line. Short display text is exactly what balance is for. */
.page-layout .feature-box span { text-wrap: balance; }

/* The page-title headline is 3.8rem, so the root-size drop shrinks it twice.
   A px clamp decouples it from that and ramps smoothly instead of stepping to
   36px at 767 (responsive.css:20457). */
.page-layout .page-title-extra-small h2 {
    font-size: clamp(34px, 22px + 2.6vw, 60px);
    line-height: 1.08;
}

/* ---- footer rhythm ------------------------------------------------------
   The footer inherits the page's section padding above, but its interior was
   still on the theme's own density: the column headings sat 10px off their
   lists, the nav links stacked at zero margin (real-estate.css zeroes the
   base's `footer ul li` 5px), the "Talk to us" link sat 5px under its
   paragraph, and the registered-entity line sat 5px above the copyright. Nine
   hardcoded 5/10/15/30px values against 112px of outer padding, which is what
   made a 626px band read as a strip.

   Those utilities are all `!important` in the base, so they were removed from
   the markup rather than overridden here. */

/* The CTA band is the footer's primary seam and is a solid block, so it takes
   the full step. The columns row keeps .cz-band: its own ragged bottoms
   already add air above the rule, and doubling it would detach the legal
   strip. */
.cz-footer-cta { margin-bottom: var(--cz-space-xl); }

/* The CTA card's brushed panel (CZN-28).

   Three layers, and the order is the point: bg-base-color on the card, this
   photograph over it, the accent again as a scrim over that. The card is #1a5091
   whether or not the image arrives, so the site's one accent block cannot be
   turned into a grey rectangle by a 404.

   Clipped here rather than with overflow:hidden on the card itself — the button
   inside carries btn-box-shadow, and clipping the card would take the shadow with
   the image. The radius matches .border-radius-6px on the parent; the two have to
   be changed together.

   This is the most extreme crop on the site: 1190x216 is 5.51:1, and the card does
   not grow past 1190 because the container caps there. Below 992 the row stacks and
   the same card renders 360x228 — 1.58:1, nearly square, cropping horizontally
   instead. A picture with a subject would lose it in one of those two; this one is a
   single diagonal across a uniform surface, which is why it survives both. */
.cz-footer-cta-art {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: 6px;
}

.cz-footer-cta-art img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Below lg the row stacks, and two faults that cannot show at desktop show up.
   Neither is caused by the photograph — they were there while the card was a flat
   field, and putting a picture behind it is only what made them legible.

   1. real-estate.css:56 sets `h6 { line-height: 1.75rem }`, which is exactly the
      1.75rem font-size style.css gives it. Zero leading. The headline is one line at
      every width above 992 and two below it, so the wrap has never been seen: at 393
      the two lines are 21px tall each in a 42px box and touch. The vendored sheet
      stays untouched, so the correction is scoped to this card.
   2. The gap under the headline was `lg-mb-20px` — 20px against the card's own 44px
      interior, so the headline sat nearer the button than the card sat to its edge,
      and the pair read as one collided lump. --cz-space-md tracks the interior
      instead: 32px at 393 against 44, 41px at 991 against 60.

   The 44px interior itself is not touched. It is a measured value from the spacing
   pass (docs/spacing-rhythm.md:52) and is the same on every card at this width. */
@media (max-width: 991px) {
    .cz-footer-cta h6 { line-height: 1.35; }
    .cz-footer-cta-copy { margin-bottom: var(--cz-space-md); }
}

/* Raked 100deg: heaviest at the left, where a 28px headline sits on it, and
   thinnest at the right, where the button is opaque white and needs no help.

   76% -> 50%, arrived at by sweeping it in the browser against the real card. The
   first pass ran 92% -> 72% out of caution about the highlight competing with the
   button, and it was simply too heavy: at 92% the panel is 8% of itself and the card
   looks flat, which is what it looked like. The floor is the other end — below about
   68% -> 40% the top right goes pale and the block stops reading as #1a5091 at all,
   which would cost the site its one accent surface to gain a texture. 76% -> 50% is
   the widest opening that still leaves it unmistakably the accent block. */
.cz-footer-cta-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, rgb(26 80 145 / 76%) 0%, rgb(26 80 145 / 50%) 100%);
}

/* Carries the .overlap-section positioning the theme's own rule supplied
   (style.css:1153). The rest of that behaviour -- the negative margin that
   centres the band on the footer's top edge -- moved into AppLayout.vue, where
   it can be applied before first paint instead of half a second after it.
   Without JS the band simply sits inside the footer, which is a sound
   fallback rather than a broken one. */
.cz-footer-overlap { position: relative; }

/* Stacked columns below 992. Row-gap rather than per-column margins so the
   two-across state at 576-767 spaces its wrap correctly without a second
   breakpoint. Bootstrap's --bs-gutter-y is 0 here, so this is the only
   contributor. */
.cz-footer-cols { row-gap: var(--cz-space-lg); }

footer.footer-dark .footer-logo       { margin-bottom: var(--cz-space-sm); }
footer.footer-dark .elements-social   { margin-top: var(--cz-space-sm); }
footer.footer-dark .cz-footer-heading { margin-bottom: var(--cz-space-sm); }

/* Scoped to .cz-footer-links so it cannot reach the social-icon list, which is
   horizontal and wants no vertical margin at all. */
footer.footer-dark .cz-footer-links li:not(:last-child) { margin-bottom: var(--cz-space-xs); }

/* The link is inline; d-inline-block in the markup is what lets this apply. */
footer.footer-dark .cz-footer-aside { margin-top: var(--cz-space-xs); }

footer.footer-dark .footer-bottom { padding-top: var(--cz-space-md); row-gap: var(--cz-space-sm); }
footer.footer-dark .cz-footer-entity { margin-bottom: var(--cz-space-xs); }

/* =========================================================================
   READY STOCK — /vehicles and /vehicles/{slug}                    (CZN-14)
   =========================================================================
   Kept under its own carzon-vehicle-* prefix rather than reusing anything
   from the homepage rail. CZN-24 deleted the whole carzon-reel-* layer while
   the delivery band beside it survived unchanged, and the lesson was that a
   prefix is what lets one feature die without taking its neighbour with it.

   No section padding here — .page-layout drives that globally, and adding
   pt-* and pb-* in the markup is what this file exists to stop. */

/* ---- card ---------------------------------------------------------------
   The image is the one element whose height we do not control: derivatives
   are 16:11 today, but upstream photography is whatever a salesperson's
   phone produced, and the sync will letterbox rather than refuse a photo.
   A fixed ratio plus object-fit keeps a rogue portrait shot from making one
   card in a row twice the height of its neighbours. */
.carzon-vehicle-image {
    aspect-ratio: 16 / 11;
    object-fit: cover;
    display: block;
    background-color: var(--dark-gray);
}

/* Import-to-order band backdrop (CZN-28).

   This band was a flat light field and is now a photograph. The section keeps the
   theme's own vertical padding — only the ground changed — so the rhythm either
   side of it is untouched.

   The scrim is even rather than raked because the copy is centred: the hero can
   aim its contrast at one corner, this cannot. 68% at the top is higher than the
   hero's left-edge 92% would suggest it needs, and that is deliberate — the source
   is a pale overcast rather than a dark interior, so it takes more to hold white
   text. The section still lands lighter than the near-black branches band below it,
   which is what keeps the two from reading as one mass. */
.carzon-band-photo {
    position: absolute;
    inset: 0;
}

.carzon-band-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Anchored near the foot, and measured rather than guessed.

       The section is 1440x492 at a 1440 viewport — a 2.93:1 letterbox over a 16:9
       source, so only 61% of the picture's height is ever on screen and where that
       window sits decides whether this is a photograph or a flat blue rectangle.
       It was 35%, on the reasoning that the horizon sits low and should be kept out
       of the copy. It worked too well: the window ran 14%-75% of the frame, the
       horizon landed at 92% of the band and the water was a 39px strip under a 58%
       scrim. Nothing read as sea.

       85% puts the horizon at ~59% at 1440 and ~48% at 1920 — below the paragraph,
       above the button, with the vessel in that gap at the right — and gives the
       lower half of the band real water. Not 100%: anchoring hard to the foot rides
       the horizon up to 35% at 1920, where it crosses the headline and the vessel
       reads as attached to the words. */
    object-position: 50% 85%;
}

.carzon-band-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgb(10 17 29 / 68%) 0%, rgb(10 17 29 / 58%) 100%);
}

/* Branch card art (CZN-28). Same reason as the rule above: lock the ratio so the
   card's height comes from the layout rather than from whatever file happens to be
   in the slot. The placeholder this replaced was 370x510 — very slightly taller
   than 3:4 — so the cards lose about 3% of their height and are now a true 3:4,
   which is what the rest of the page's portrait slots already are. */
.carzon-branch-tile {
    aspect-ratio: 3 / 4;
    object-fit: cover;
    display: block;
    background-color: var(--dark-gray);
}

.carzon-vehicle-title {
    transition: color .3s ease;
}
.carzon-vehicle-title:hover,
.carzon-vehicle-title:focus-visible {
    color: var(--base-color);
}

/* Reserved is the only badge that renders. Available carries none — the
   default state needs no label — and is_special_offer is ignored for launch
   (CZN-14 §8), so there is no two-badge collision to design around. Neutral
   rather than red: red is the CTA colour, and a "you cannot buy this yet"
   marker should not read as the most actionable thing on the card. */
.badge-reserved {
    background-color: var(--dark-gray);
}

/* ---- the listings layout ------------------------------------------------
   A fixed rail beside a fluid grid, as CSS grid rather than as Bootstrap
   columns. col-lg-3 is a *proportion*, and on the wide container it resolved
   to a 400px filter rail -- a quarter of the page spent on six controls that
   need 260. A fixed track spends what the controls need and hands the rest to
   the cars, which is the whole reason for widening the page.

   align-items: start so the rail can be sticky: a stretched grid item is as
   tall as the row, and a sticky box as tall as its container never moves. */
/* minmax(0, 1fr) and not the implicit `auto` track, on both axes of the
   definition. An auto track is floored at its content's min-content width, and
   a stacked card row's min-content is wider than a phone: at 390 the single
   column measured 525px and took the whole page into horizontal scroll. */
.carzon-listing {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--cz-space-md);
}

@media (min-width: 992px) {
    .carzon-listing {
        grid-template-columns: 240px minmax(0, 1fr);
        gap: 30px;
        align-items: start;
    }
}

@media (min-width: 1400px) {
    .carzon-listing { grid-template-columns: 260px minmax(0, 1fr); gap: 40px; }
}

/* ---- filter rail --------------------------------------------------------
   Bespoke: demo-real-estate-rent.html donates a grid and pagination and no
   filter UI whatsoever. The theme styles bare inputs for its contact forms,
   so these carry their own class rather than inheriting rules written for a
   two-field enquiry box.

   A column beside the results, not a band above them. Filtering and reading
   what came back is one loop; stacked, the panel pushed the cars a screen
   down and made every adjustment a scroll in both directions.

   Not a card, though it was one. A bordered white panel on a white page is
   only visible as an outline, and because the rail is shorter than the grid
   the outline closed a third of the way down and left the box hanging in the
   margin. Borderless, the controls sit directly on the page and the column
   simply ends where it ends. What separates it from the results is the grid
   gap and the rule under its heading, which is the same rule the sort row
   carries -- one line across both columns, so the two start together.

   Below lg it goes back to being a card, because there it is a disclosure and
   a control needs an edge to read as pressable. */
/* 58px, fixed, and the sort row is the same. The rule under each is meant to
   read as one line across both columns, and on min-height they landed 10px
   apart: this side is sized by a 17px cap-height label, the other by a 42px
   select. */
.carzon-vehicle-rail-head {
    display: flex;
    align-items: center;
    min-height: 42px;
}

.carzon-vehicle-rail-title {
    font-family: var(--alt-font);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--dark-gray);
}

/* Below lg the rail is a disclosure -- a full-height panel above the grid on
   a phone is several screens of controls between a customer and the cars. The
   applied count rides on the toggle, so a shut panel can still say that
   something is narrowing the results without the chips taking room to say it. */
.carzon-vehicle-rail-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    font-family: var(--alt-font);
    font-size: 17px;
    font-weight: 600;
    color: var(--dark-gray);
}

.carzon-vehicle-rail-body {
    display: none;
    margin-top: var(--cz-space-xs);
}
.carzon-vehicle-rail-body.carzon-vehicle-rail-open { display: block; }

/* Space, not rules. Six blocks each divided by a hairline turned a 240px
   column into a stack of boxes and read as busier than the grid it filters;
   the labels are weight enough to separate them on their own. */
.carzon-vehicle-rail-block + .carzon-vehicle-rail-block { margin-top: 26px; }

.carzon-vehicle-rail-label {
    display: block;
    margin-bottom: 10px;
    font-family: var(--alt-font);
    font-size: 14px;
    font-weight: 600;
    color: var(--dark-gray);
}

@media (max-width: 991px) {
    .carzon-vehicle-rail {
        padding: 16px 20px;
        border: 1px solid var(--extra-medium-gray);
        border-radius: 6px;
        background-color: #fff;
    }
    .carzon-vehicle-rail-head { min-height: 0; }
}

@media (min-width: 992px) {
    /* Open, and with no way to be shut: the toggle is display:none up here, so
       a rail left closed by a stale flag would have no control to reopen it.
       This is also why the panel is shown by class rather than by v-show -- an
       inline display:none would outrank this rule and the desktop rail would
       render empty. */
    .carzon-vehicle-rail-body { display: block; margin-top: var(--cz-space-sm); }

    .carzon-vehicle-rail-head {
        height: 58px;
        border-bottom: 1px solid var(--extra-medium-gray);
    }

    /* Travels with the grid. The max-height is the fallback for a rail longer
       than the viewport: without it the body-type pills at the bottom sit
       permanently off-screen once the header offset is paid. The negative
       margin and matching padding are for that scrollbar -- an overflow box
       clips a focus ring against its own edge, so the controls are inset far
       enough to keep theirs. */
    .carzon-vehicle-rail {
        position: sticky;
        top: calc(var(--cz-header-h) + 20px);
        max-height: calc(100vh - var(--cz-header-h) - 40px);
        overflow-y: auto;
        margin-left: -4px;
        padding-left: 4px;
        padding-right: 4px;
    }
}

.carzon-vehicle-input {
    height: 48px;
    border: 1px solid var(--extra-medium-gray);
    border-radius: 4px;
    padding: 0 15px;
    font-family: var(--alt-font);
    font-size: 15px;
    color: var(--dark-gray);
    background-color: #fff;
    width: 100%;
}
.carzon-vehicle-input:focus {
    outline: none;
    border-color: var(--base-color);
    box-shadow: 0 0 0 3px rgb(26 80 145 / 12%);
}

/* The year row is two selects with a word between them. Without these the selects'
   width:100% wins the flex negotiation, the separator collapses to a few pixels,
   and "to" breaks across two lines. */
.carzon-vehicle-range { display: flex; align-items: center; gap: 10px; }
.carzon-vehicle-range .carzon-vehicle-input { flex: 1 1 0; min-width: 0; }
.carzon-vehicle-range-separator { flex: 0 0 auto; white-space: nowrap; color: var(--medium-gray); }

.carzon-vehicle-pills { display: flex; flex-wrap: wrap; gap: 8px; }

/* The homepage row has a full container to spread across; this one has a
   240px track, and the pill's 26px of side padding fits one per line there. */
.carzon-vehicle-rail .carzon-pill { padding: 8px 14px; font-size: 14px; }

/* The pill row becomes interactive in Phase 2. <button> rather than <a>: it
   filters in place and navigates nowhere, and a link that is not a
   destination is the kind of thing that lands in a screen reader's link list
   as noise. */
.carzon-pill-button {
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}
.carzon-pill-active,
.carzon-pill-active:hover {
    background-color: var(--base-color);
    border-color: var(--base-color);
    color: #fff;
}

/* ---- detail gallery -----------------------------------------------------
   The demo's 3-up Swiper is replaced rather than re-tokened. A crop-happy
   carousel suits property exteriors; a car walkaround needs one large frame
   and the ability to zoom, which is what the customer is actually here to do
   (CZN-14 §4). Magnific handles the zoom — initLightboxGalleries() rebinds
   it on every Inertia visit, so it costs nothing here. */
.carzon-gallery { position: relative; }

/* The frame is a button, not a link: it opens the lightbox by proxy rather than by
   being in it (see VehicleGallery.vue). Reset rather than restyle - everything that
   should be visible here belongs to the photograph. */
.carzon-gallery-open {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    line-height: 0;
    cursor: zoom-in;
}

.carzon-gallery-main {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 11;
    object-fit: cover;
    border-radius: 6px;
    background-color: var(--dark-gray);
}

/* Stepping through the photographs used to mean opening the lightbox, because the
   frame showed photograph one and nothing else. These sit on the frame rather than
   under it: a control below the picture is a control you scroll past on a phone. */
.carzon-gallery-step {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: 50%;
    background-color: rgb(255 255 255 / 92%);
    color: var(--dark-gray);
    font-size: 22px;
    line-height: 1;
    box-shadow: 0 2px 12px rgb(14 20 32 / 18%);
    transition: background-color .3s ease;
}
.carzon-gallery-step:hover,
.carzon-gallery-step:focus-visible { background-color: #fff; }
.carzon-gallery-prev { left: 20px; }
.carzon-gallery-next { right: 20px; }

@media (max-width: 575px) {
    /* The frame is edge-to-edge on a phone and the count pill already owns the
       bottom-left corner, so the arrows tuck in rather than stay at desktop inset. */
    .carzon-gallery-step { width: 38px; height: 38px; font-size: 19px; }
    .carzon-gallery-prev { left: 12px; }
    .carzon-gallery-next { right: 12px; }
}

.carzon-gallery-thumbs {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--cz-space-xs);
    margin-top: var(--cz-space-xs);
}
@media (min-width: 768px) {
    .carzon-gallery-thumbs { grid-template-columns: repeat(8, 1fr); }
}

/* The thumbnails drive the frame now, so they are buttons rather than lightbox
   anchors, and the state that used to sit on the image moves to the control. */
.carzon-gallery-thumb-btn {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    line-height: 0;
    border-radius: 4px;
}

.carzon-gallery-thumb {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 4px;
    background-color: var(--dark-gray);
    opacity: .55;
    transition: opacity .3s ease;
}
.carzon-gallery-thumb-btn:hover .carzon-gallery-thumb,
.carzon-gallery-thumb-btn:focus-visible .carzon-gallery-thumb { opacity: .85; }

/* Which one the frame is showing. Outlined rather than lit alone: across eight
   thumbnails the step from .85 to 1 is not a difference anybody reads as a state. */
.carzon-gallery-thumb-btn.is-current .carzon-gallery-thumb {
    opacity: 1;
    outline: 2px solid var(--base-color);
    outline-offset: 2px;
}

/* The lightbox group. Visually hidden, never focusable, and the only thing on the
   page carrying `data-group` - theme.js binds Magnific to those on every Inertia
   visit, which is why nothing a customer can see is one. */
.carzon-gallery-links {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
}

/* ---- detail spec block --------------------------------------------------
   Label/value pairs inside the price card, under a rule. Rows with no usable
   value never arrive here — Vehicle::specRows drops them — so there is no
   empty-state styling to write, which is the whole point of filtering
   server-side.

   This used to be a col-lg-5 beside an almost-empty equipment column, two
   screens below a header strip that already stated five of its rows. It is in
   the card because price and specification are one comparison, and because a
   label and its value sitting at opposite ends of a wide column is most of
   what made the old table hard to read. */
.carzon-vehicle-specs {
    margin-top: var(--cz-space-sm);
    padding-top: var(--cz-space-sm);
    border-top: 1px solid var(--extra-medium-gray);
}

/* The heading is the same small caps label the price above it uses — it is the
   same card, and a second heading style in it would make it read as two. */
.carzon-vehicle-specs .carzon-vehicle-cta-label { margin-bottom: 14px; }

.carzon-vehicle-spec {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--cz-space-xs);
    padding-bottom: 12px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--extra-medium-gray);
}
/* The label never wraps and the value takes the slack. In the rail's width
   `Unregistered (Recon Car)` is two lines whatever happens, and without this
   flex resolved it by breaking `Condition` after the second-to-last letter. */
.carzon-vehicle-spec-label {
    flex: 0 0 auto;
    color: var(--medium-gray);
    white-space: nowrap;
}
.carzon-vehicle-spec-value {
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--alt-font);
    font-weight: 600;
    color: var(--dark-gray);
    text-align: right;
}

/* The card's own padding closes the list; a rule and 12px under the last row
   would draw a second, weaker edge just inside the real one. */
.carzon-vehicle-specs .carzon-vehicle-spec:last-child {
    padding-bottom: 0;
    margin-bottom: 0;
    border-bottom: 0;
}

/* Upstream's descriptions are HTML fragments whose only real structure is the
   `<br>`. Vehicle::descriptionText converts those to newlines rather than
   letting third-party markup into the page; this is what makes them visible. */
.carzon-vehicle-prose { white-space: pre-line; }

/* ---- detail equipment ---------------------------------------------------
   Under the photographs, in the gallery's own column. The rail beside it now
   carries the whole specification and runs longer than the gallery; this is
   the only block on the page with no fixed shape, so it is what closes the
   gap.

   Two across, not three: three fitted while this was a full-width band, but at
   two thirds of the container the last row came out nearly empty. */
.carzon-vehicle-equipment {
    margin-top: var(--cz-space-md);
    padding-top: var(--cz-space-sm);
    border-top: 1px solid var(--extra-medium-gray);
}

.carzon-vehicle-equipment-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px var(--cz-space-sm);
    list-style: none;
    margin: 0;
    padding: 0;
}

.carzon-vehicle-equipment-list li {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 0;
    border-bottom: 1px solid var(--extra-medium-gray);
    font-family: var(--alt-font);
    font-weight: 600;
    color: var(--dark-gray);
}

.carzon-vehicle-equipment-list i {
    font-size: 17px;
    color: var(--base-color);
}

/* One column on a phone. Upstream codes are short, but a two-column grid at
   375px puts "BODYKIT V2" on two lines beside a tick. */
@media (max-width: 575px) {
    .carzon-vehicle-equipment-list { grid-template-columns: minmax(0, 1fr); }
}

/* ---- auction grade ------------------------------------------------------
   The strongest trust signal in the Malaysian recon market, and it costs us
   nothing to show. It carries no AP-holder implication: it describes the
   car's condition at auction, and "imported ready stock" already says where
   the car came from (CZN-14 §4). */
/* ---- price card ---------------------------------------------------------
   The auction grade used to render here as a filled base-color pill sitting a
   few pixels above a filled base-color button: two identical shapes in the
   same colour, one of them a fact and the other the page's only conversion.
   They read as a pair of choices. The grade is now a term in the ruled list
   below the price, and the button is the only coloured thing in the card. */
.carzon-vehicle-cta-label {
    display: block;
    margin-bottom: 6px;
    font-family: var(--alt-font);
    font-size: 13px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--medium-gray);
}

.carzon-vehicle-cta-price {
    display: block;
    font-family: var(--alt-font);
    font-size: clamp(30px, 26px + 0.9vw, 38px);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -1px;
    color: var(--dark-gray);
}

/* "Price on enquiry" and "This vehicle has been sold." are sentences rather
   than figures, and at price size they shout. */
.carzon-vehicle-cta-price-quiet {
    font-size: 24px;
    font-weight: 600;
    letter-spacing: normal;
}

/* Grade and stock reference share one ruled list, so the card has a structure
   instead of four differently-spaced paragraphs. */
.carzon-vehicle-terms {
    margin: var(--cz-space-sm) 0;
    padding: var(--cz-space-xs) 0;
    border-top: 1px solid var(--extra-medium-gray);
    border-bottom: 1px solid var(--extra-medium-gray);
}

.carzon-vehicle-term {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
}

.carzon-vehicle-term-label {
    font-family: var(--alt-font);
    font-size: 14px;
    color: var(--medium-gray);
}

.carzon-vehicle-term-value {
    font-family: var(--alt-font);
    font-size: 16px;
    font-weight: 700;
    color: var(--dark-gray);
    text-align: right;
}

.carzon-vehicle-term-note {
    margin: 0;
    padding-bottom: 6px;
    font-size: 14px;
    color: var(--medium-gray);
}

.carzon-vehicle-cta-note {
    margin: 15px 0 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--medium-gray);
}

/* ---- sticky CTA ---------------------------------------------------------
   The demo's agent card, with the contact form removed. Carzon captures no
   leads on-site — there is no form anywhere and no CRM behind one — so the
   panel is the WhatsApp handoff and the facts a customer needs before
   pressing it. */
.carzon-vehicle-cta {
    position: relative;
    border-radius: 6px;
    overflow: hidden;
}

/* A rule drawn on rather than a border-top: the card carries the theme's
   .border-color-extra-medium-gray utility, and a border-top declaration here
   would have to outrank it to show. */
.carzon-vehicle-cta::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 3px;
    background-color: var(--base-color);
}
@media (min-width: 992px) {
    .carzon-vehicle-cta {
        position: sticky;
        /* Clears the fixed header, which is what --cz-header-h exists for. */
        top: calc(var(--cz-header-h) + var(--cz-space-xs));
    }
}

/* Sold vehicles keep their URL and say so plainly. Neutral, not an alert:
   nothing has gone wrong, the car has simply been bought, and the recovery
   path is the CTA underneath rather than a warning colour. */
.carzon-vehicle-sold {
    background-color: var(--very-light-gray);
    border: 1px solid var(--extra-medium-gray);
    border-radius: 6px;
    padding: var(--cz-space-sm);
}

/* =========================================================================
   READY STOCK — orientation layer                                (CZN-14b)
   =========================================================================
   Breadcrumbs, the results bar, the vehicle header and the sticky CTA. Added
   after the pages had been walked and found hard to navigate: the information
   was right, but nothing said where you were or how to get back.

   Same prefix rule as the block above, and the same section rule — no
   padding-top or padding-bottom utilities in the markup, because .page-layout
   owns section rhythm globally. */

/* ---- breadcrumbs --------------------------------------------------------
   One line, always. A trail ending in a full car title wraps to three lines
   on a phone, which is the failure NN/g's mobile guideline names explicitly,
   so it scrolls sideways instead. The scrollbar is hidden because the trail
   is short enough to read at a glance on every width we support. */
.carzon-breadcrumb {
    margin-bottom: var(--cz-space-xs);
    overflow-x: auto;
    scrollbar-width: none;
}
.carzon-breadcrumb::-webkit-scrollbar { display: none; }

.carzon-breadcrumb ol {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
    white-space: nowrap;
    font-family: var(--alt-font);
    font-size: 14px;
}

.carzon-breadcrumb li { display: flex; align-items: center; gap: 8px; }

/* On a phone a four-level trail ending in a full car title clips mid-word at the
   viewport edge, with no hint that it scrolls. NN/g's mobile guideline is to show
   the final levels rather than the whole trail, and here the dropped crumb is the
   page's own name — which the h1 two lines below already states.

   The selector reads "last child, and at least the fourth": /vehicles has a
   two-level trail whose last crumb is Ready Stock, and dropping that would leave
   the word Home on its own. */
@media (max-width: 767px) {
    .carzon-breadcrumb li:nth-last-child(1):nth-child(n+4) { display: none; }
}

/* The separator belongs to the list, not the markup — a literal character in
   the template would be read aloud by a screen reader between every level. */
.carzon-breadcrumb li:not(:first-child)::before {
    content: '/';
    opacity: .45;
}

.carzon-breadcrumb a { transition: color .3s ease; }

/* The last crumb is never a link (it renders as a span), so styling the span
   is what marks "you are here". */
.carzon-breadcrumb-light a           { color: var(--medium-gray); }
.carzon-breadcrumb-light a:hover,
.carzon-breadcrumb-light a:focus-visible { color: var(--base-color); }
.carzon-breadcrumb-light span        { color: var(--dark-gray); font-weight: 600; }
.carzon-breadcrumb-light li::before  { color: var(--medium-gray); }

.carzon-breadcrumb-dark a            { color: rgb(255 255 255 / 65%); }
.carzon-breadcrumb-dark a:hover,
.carzon-breadcrumb-dark a:focus-visible { color: #fff; }
.carzon-breadcrumb-dark span         { color: #fff; font-weight: 600; }
.carzon-breadcrumb-dark li::before   { color: rgb(255 255 255 / 45%); }

/* The dark trail sits above the animated title block inside the page-title
   band, which already pays the header's height in padding. */
.carzon-page-title .carzon-breadcrumb { margin-bottom: var(--cz-space-sm); }

/* ---- sort ---------------------------------------------------------------
   The one control that belongs to the results rather than to the filters, so
   it sits on top of them instead of in the rail.

   It replaces a bar that pinned a running "Showing 1-12 of 76 vehicles" under
   the header for the whole scroll. The count was answering a question nobody
   had asked and charging a strip of the viewport to do it; the per-option
   counts in the rail say the same thing at the moment it is useful. */
/* The rule underneath is the same one the rail's heading carries, at the same
   height, so the two columns open on one line across the page instead of on
   two edges that nearly agree. It is also what keeps the row from reading as a
   control floating in the margin now that there is no count beside it. */
.carzon-vehicle-sort {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    height: 58px;
    margin-bottom: var(--cz-space-sm);
    border-bottom: 1px solid var(--extra-medium-gray);
}

/* Auto width here, against the .carzon-vehicle-input width:100% the rail
   needs. Without it the select eats the whole row. */
.carzon-vehicle-sort .carzon-vehicle-input {
    width: auto;
    height: 42px;
    font-size: 14px;
}

/* ---- applied-filter chips ----------------------------------------------
   The thing that was missing when results came back rather than not: a way to
   see what is narrowing them, and to drop one without hunting for the control
   that set it. */
.carzon-vehicle-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: var(--cz-space-xs);
}

.carzon-vehicle-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 5px 12px;
    border: 1px solid var(--base-color);
    border-radius: 50px;
    background-color: #eef3fa;
    color: var(--base-color);
    font-family: var(--alt-font);
    font-size: 13px;
    font-weight: 600;
    line-height: 20px;
    transition: background-color .3s ease, color .3s ease;
}
.carzon-vehicle-chip:hover,
.carzon-vehicle-chip:focus-visible {
    background-color: var(--base-color);
    color: #fff;
}
.carzon-vehicle-chip i { font-size: 13px; }

.carzon-vehicle-chip-clear {
    background: none;
    border: 0;
    padding: 5px 4px;
    font-family: var(--alt-font);
    font-size: 13px;
    font-weight: 600;
    color: var(--medium-gray);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.carzon-vehicle-chip-clear:hover { color: var(--dark-gray); }

/* The count beside a body-type pill. Quieter than the label it qualifies. */
.carzon-pill-count { opacity: .6; font-weight: 500; }
.carzon-pill-active .carzon-pill-count { opacity: .75; }

/* ---- card fact row ------------------------------------------------------
   Three equal columns with nowrap content, and at card width the mileage value
   fills its column exactly: "38,000 km" ended flush against the neighbouring
   transmission icon with no space at all between them. Shrinking the value a
   step and letting the columns size to their content buys the gap back without
   dropping either the icons or a field. */
/* `flex-wrap` is the safety net. The card renders at four widths now -- the
   two-across grid, the three-across related and recently-viewed rails, the
   homepage rail and a full-width phone -- and a third fact that has run out of
   room should drop to a second line rather than collide with its neighbour
   the way "38,000 km" once did with the transmission icon. */
.carzon-vehicle-card .content .row {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
/* 12px, down from 20. `justify-content: space-between` hands any surplus back,
   so the gap only ever binds on the narrowest card -- and at 20 it bound at
   1440, where the three facts need 226px of a 263px measure and the wrap
   dropped Transmission onto a line of its own. */
    gap: 12px;
}
/* `width: auto` matters: Bootstrap sets `.row > * { width: 100% }` and relies on
   `.col`'s zero flex-basis to override it. Take the basis away without the width
   and all three columns claim the full row and stack. */
.carzon-vehicle-card .content .row > .col { flex: 0 1 auto; width: auto; }
.carzon-vehicle-card .content .row .alt-font { font-size: 15px; }

/* ---- card additions -----------------------------------------------------
   Back-to-results lands on the card by fragment, so it has to clear the fixed
   header or the target sits underneath it. It used to pay another 90px for
   the sticky results bar; that bar is gone, and the extra offset would now
   just drop the card 90px below where it was aimed. */
.carzon-vehicle-card { scroll-margin-top: calc(var(--cz-header-h) + 20px); }

/* ---- pagination ---------------------------------------------------------
   The theme's row does not wrap, and seven pages plus two arrows is 495px --
   wider than a phone, so the row hung 50px off both edges and put the whole
   document into horizontal scroll. It is centred, which is what hid it: the
   overflow was symmetrical and looked like a deliberate bleed. */
.page-layout .pagination-style-01 {
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 10px;
}

.carzon-vehicle-meta { color: var(--medium-gray); }
.carzon-vehicle-meta-dot { margin: 0 8px; opacity: .5; }

/* Photo count over the thumbnail. Bottom-right, opposite the Reserved badge,
   so the two can never collide on one card. */
.carzon-vehicle-shots {
    position: absolute;
    right: 20px;
    bottom: 20px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 50px;
    background-color: rgb(14 20 32 / 75%);
    color: #fff;
    font-family: var(--alt-font);
    font-size: 12px;
    font-weight: 600;
    line-height: 20px;
}

/* ---- vehicle header -----------------------------------------------------
   Replaces the dark PageTitle band on the detail page. Light, because CZN-22
   made the site chrome solid dark and lifted the constraint that every page
   open on a dark section. */
/* This is the first section on the page, and the header is fixed — so it pays
   the header's height itself, exactly as .carzon-page-title does for every
   other inner page. Without it the breadcrumb renders underneath the navbar
   and the page appears to have no trail at all.

   No bottom padding: the gallery immediately below belongs to this block, and
   two full section paddings back to back put a hole between a car's title and
   its photographs. */
.page-layout section.carzon-vehicle-header {
    padding-top: calc(var(--cz-header-h) + var(--cz-space-sm));
    padding-bottom: 0;
}

.carzon-vehicle-header { background-color: #fff; }

.carzon-vehicle-header-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--cz-space-xs);
    margin-bottom: var(--cz-space-sm);
    flex-wrap: wrap;
}

.carzon-vehicle-back {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--alt-font);
    font-size: 15px;
    font-weight: 600;
    color: var(--base-color);
}
.carzon-vehicle-back:hover,
.carzon-vehicle-back:focus-visible { color: var(--dark-gray); }

.carzon-vehicle-step {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    font-family: var(--alt-font);
    font-size: 14px;
    font-weight: 600;
}
.carzon-vehicle-step a { color: var(--dark-gray); }
.carzon-vehicle-step a:hover,
.carzon-vehicle-step a:focus-visible { color: var(--base-color); }

/* The edges of the result set render as text rather than disappearing, so the
   control does not change width as you step through it. */
.carzon-vehicle-step-off { color: var(--extra-medium-gray); }
.carzon-vehicle-step-rule {
    width: 1px;
    height: 14px;
    background-color: var(--extra-medium-gray);
}

.carzon-vehicle-headline {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--cz-space-sm);
    flex-wrap: wrap;
}

.carzon-vehicle-headline h1 { font-size: clamp(28px, 22px + 1.9vw, 42px); line-height: 1.15; }

/* ---- share --------------------------------------------------------------
   Two actions, not a row of networks. Carzon's demand already moves by
   forwarded link. */
.carzon-vehicle-share { display: flex; gap: 10px; flex-shrink: 0; }

.carzon-vehicle-share-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border: 1px solid var(--extra-medium-gray);
    border-radius: 50px;
    background-color: #fff;
    color: var(--dark-gray);
    font-family: var(--alt-font);
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    transition: border-color .3s ease, color .3s ease;
}
.carzon-vehicle-share-btn:hover,
.carzon-vehicle-share-btn:focus-visible {
    border-color: var(--base-color);
    color: var(--base-color);
}

/* ---- gallery additions --------------------------------------------------
   The frame is the positioning context for the count and the View-all
   control; the main image keeps its own aspect handling above. */
.carzon-gallery-frame { position: relative; }

.carzon-gallery-count {
    position: absolute;
    left: 20px;
    bottom: 20px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 14px;
    border-radius: 50px;
    background-color: rgb(14 20 32 / 75%);
    color: #fff;
    font-family: var(--alt-font);
    font-size: 13px;
    font-weight: 600;
    pointer-events: none;
}

.carzon-gallery-all {
    position: absolute;
    right: 20px;
    bottom: 20px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border: 0;
    border-radius: 50px;
    background-color: rgb(255 255 255 / 92%);
    color: var(--dark-gray);
    font-family: var(--alt-font);
    font-size: 13px;
    font-weight: 600;
    transition: background-color .3s ease;
}
.carzon-gallery-all:hover,
.carzon-gallery-all:focus-visible { background-color: #fff; }

/* ---- sticky enquiry bar -------------------------------------------------
   Below lg only. The enquiry panel is a col-lg-4 that stacks under a
   full-width gallery on a phone, which put the price and the CTA several
   screens down; AppLayout suppresses the global floating button on this route
   so this is the one persistent CTA, and unlike that one it names the car. */
.carzon-vehicle-cta-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--cz-space-xs);
    padding: 12px 20px;
    background-color: #fff;
    border-top: 1px solid var(--extra-medium-gray);
    box-shadow: 0 -4px 20px rgb(14 20 32 / 10%);
    /* Clears the home indicator on iOS, and collapses to nothing elsewhere. */
    padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}

.carzon-vehicle-cta-bar-price { display: flex; flex-direction: column; min-width: 0; }

.carzon-vehicle-cta-bar-label {
    font-family: var(--alt-font);
    font-size: 12px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--medium-gray);
}

.carzon-vehicle-cta-bar-value {
    font-family: var(--alt-font);
    font-size: 20px;
    font-weight: 700;
    color: var(--dark-gray);
    line-height: 1.2;
}

/* "Price on enquiry" is a phrase, not a figure, and reads wrong at price size. */
.carzon-vehicle-cta-bar-value-quiet { font-size: 16px; font-weight: 600; }

/* The bar overlays the footer otherwise, and the last thing on the page is
   the related rail a customer is meant to be able to reach. */
@media (max-width: 991px) {
    .page-layout { padding-bottom: 76px; }
}

/* On desktop the panel travels with the gallery instead. The offset clears the
   fixed header; the gallery is taller than the panel at every width, so there
   is always something to travel against. */
@media (min-width: 992px) {
    .carzon-vehicle-cta {
        position: sticky;
        top: calc(var(--cz-header-h) + 20px);
    }
}

/* ---- recently viewed ----------------------------------------------------
   No rules of its own. It renders the same VehicleCard as the grid and the
   related rail, in the same three-across row, because three copies of a card
   drift and the bespoke tile that used to live here read as an afterthought
   beside them -- it was smaller, and it could not show a price, because the
   prices were never stored. They are fetched now (VehicleController::
   recentlyViewed), so there is nothing left for this section to style. */
