/**
 * Private search demo — styles.
 *
 * Loaded ONLY on the demo page (includes/search-demo.php enqueues it behind the
 * `vdb-search-demo` body class) and deliberately kept out of the webpack bundle:
 * a demo must not be able to change how the live pages look, and this way it ships
 * and disappears without rebuilding dist/.
 *
 * Every selector is scoped under `.vdb-search-demo`. The form fields, cards and
 * buttons keep the styles they already have in the main bundle — what is here is
 * the hero that now holds the search, the tightened spacing (client's point 5) and
 * the new results context block.
 */

/* ── Reminder that this is not the live page ─────────────────────────────── */
.vdb-search-demo .search-demo-flag {
    position: fixed;
    bottom: 1rem;
    left: 1rem;
    z-index: 9;
    padding: 0.35rem 0.75rem;
    border-radius: 999px;
    background: rgba(20, 22, 26, 0.85);
    color: #fff;
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    pointer-events: none;
}

/* ── Hero with the search inside ─────────────────────────────────────────── */
/* No z-index anywhere in this hero, on purpose. The Locations picker is a Bootstrap
   modal rendered INSIDE the search field (koble pairs a field with its checkboxes by
   DOM containment, so the modal cannot be moved to <body>). Any z-index here would
   make the hero a stacking context and trap that modal below the modal backdrop
   (level 9) and the header (level 8) — it opened behind a blurred white sheet.
   Without one, the modal reaches the root stacking context and its own level 10
   wins. The three hero layers therefore stack by DOM order alone: background,
   overlay, content. Do not add z-index back. */
.vdb-search-demo .search-hero {
    position: relative;
    display: flex;
    align-items: flex-end;
    min-height: 55vh;
    color: #fff;
}

@media (min-width: 992px) {
    .vdb-search-demo .search-hero {
        min-height: 68vh;
    }
}

/* Same trick as .hero-section: sit behind the transparent sticky header, then pad
   the content back down so it never hides under the navbar. */
.HEADER-OVERLAPS.vdb-search-demo .search-hero {
    margin-top: calc(var(--APP_HEADER_HEIGHT, 0px) * -1);
    padding-top: calc(var(--APP_HEADER_HEIGHT, 0px) * 1.1);
}

.vdb-search-demo .search-hero__bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 45%;
}

.vdb-search-demo .search-hero__overlay {
    position: absolute;
    inset: 0;
    /* Deeper through the middle than a decorative scrim would be: the value
       proposition is long copy sitting over whatever the photograph happens to be
       there, and on this hero that band is bright. */
    background: linear-gradient(180deg, rgba(0, 0, 0, 0.45) 0%, rgba(0, 0, 0, 0.42) 45%, rgba(0, 0, 0, 0.72) 100%);
}

.vdb-search-demo .search-hero__inner {
    position: relative;
    width: 100%;
    padding-top: 2rem;
    /* 20 Aug: the bar sits closer to the bottom edge of the photograph — this is the
       gap the client circled in red. */
    padding-bottom: 0.9rem;
}

@media (min-width: 992px) {
    .vdb-search-demo .search-hero__inner {
        padding-bottom: 1.25rem;
    }
}

/* No search bar (New Developments): the 0.9rem above was the gap between the BAR
   and the bottom edge of the photograph. With the copy as the last thing in the
   hero that reads as a crop, so it gets a paragraph's worth of air instead. */
.vdb-search-demo .search-hero--no-bar .search-hero__inner {
    padding-bottom: 2.5rem;
}

/* And on a phone it stops reserving 55vh. That height exists to give the search bar
   a stage; with no bar it is just empty photograph above the copy — 76px of it on a
   390pt screen, pushing the developments below the fold for nothing. The collapsed
   state is not an option here: it drops the photograph AND the copy, and on a page
   with no search there would be nothing left in the band. So the hero is exactly as
   tall as what it holds. Client, 3 Sep. */
@media (max-width: 991.98px) {
    .vdb-search-demo .search-hero--no-bar {
        min-height: 0;
    }
}

@media (min-width: 992px) {
    .vdb-search-demo .search-hero--no-bar .search-hero__inner {
        padding-bottom: 3.5rem;
    }
}

.vdb-search-demo .search-hero__eyebrow {
    margin: 0 0 0.5rem;
    font-size: 0.75rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    opacity: 0.85;
}

.vdb-search-demo .search-hero__title {
    margin: 0 0 0.5rem;
    max-width: 22ch;
    font-size: clamp(1.35rem, 5.4vw, 2.25rem);
    line-height: 1.15;
    text-wrap: balance;
}

/* The value proposition. Long copy over a photograph needs a measure and a little
   less contrast than the headline, or it competes with it. */
.vdb-search-demo .search-hero__lead {
    margin: 0 0 1.1rem;
    max-width: 52ch;
    font-size: clamp(0.875rem, 3.6vw, 1rem);
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.92);
}

/* Both clamps above are sized in vw, which is a mobile measure: they hit their
   ceiling at about 640px and then hold — 36px of title and 16px of copy on a
   photograph two thousand pixels wide, which is what the client photographed on
   3 Sep. From lg up the type takes a scale of its own, still viewport-relative so
   it keeps growing across the different desktop sizes rather than sitting at one
   fixed value. */
@media (min-width: 992px) {
    .vdb-search-demo .search-hero__title {
        font-size: clamp(2.25rem, 3.2vw, 3.5rem);
    }

    .vdb-search-demo .search-hero__lead {
        font-size: clamp(1rem, 1.15vw, 1.375rem);
        max-width: 58ch;
    }

    .vdb-search-demo .search-hero__eyebrow {
        font-size: clamp(0.75rem, 0.75vw, 0.9375rem);
    }
}

/* The search panel — three treatments, one per `?bar=` value.
   Common ground first. The fields are notched-outline pills whose floating label
   paints itself with `--field-bg` to punch through the top border (see
   src/styles/components/searchform/_fields.scss), so each variant only has to say
   what that colour is and what the surface behind it looks like.
   Padding equals the row gutter (1rem), so the gap between fields and the gap
   around them are the same measure. */
.vdb-search-demo .search-hero__form {
    position: relative;
    padding: 0.75rem;
    border-radius: 1.25rem;
}

/* 20 Aug: "slightly smaller" — the theme pins search fields at 3rem
   (_fields.scss). 2.75rem here, with the gutter cut to match, takes ~15% off the
   bar's height and still clears the 44px touch target. */
.vdb-search-demo .search-hero__form .row {
    --bs-gutter-x: 0.75rem;
    --bs-gutter-y: 0.75rem;
}

.vdb-search-demo .search-hero__form .form-floating {
    height: 2.75rem;
}

.vdb-search-demo .search-hero__form .form-floating > .form-control,
.vdb-search-demo .search-hero__form .form-floating > .form-select {
    line-height: 2.75rem;
    font-size: 0.9375rem;
}

.vdb-search-demo .search-hero__form-surface {
    position: absolute;
    inset: 0;
    border-radius: inherit;
}

/* The labels never punch a solid chip through the field's border: `--field-bg` (the
   theme's solid fill, see _fields.scss) is off, and the frosted pill is applied only
   once the label floats — see "Labels that actually float" further down. */
.vdb-search-demo .search-hero__form {
    --field-bg: transparent;
}

/* ①  ?bar=1 — translucent panel over transparent fields. */
.vdb-search-demo .search-hero--bar-glass .search-hero__form-surface {
    background: rgba(16, 18, 22, 0.34);
    border: 1px solid rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(16px) saturate(1.2);
}

/* ②  ?bar=2 — translucent panel, SOLID light fields. The panel keeps the
   photograph present; the fields are opaque, so the type inside them is as legible
   as on a white page. */
.vdb-search-demo .search-hero--bar-light .search-hero__form-surface {
    background: rgba(16, 18, 22, 0.34);
    border: 1px solid rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(16px) saturate(1.2);
}

/* ④  ?bar=4 — no panel at all: the same solid light fields straight over the
   photograph. The lightest footprint of the four; the shadow is what lifts the
   fields off the image. */
.vdb-search-demo .search-hero--bar-bare .search-hero__form {
    padding: 0;
}

.vdb-search-demo .search-hero--bar-bare .search-hero__form-surface {
    display: none;
}

/* Shared by ② and ④: opaque field pills, ink type, dark submit. */
.vdb-search-demo .search-hero--bar-light .search-hero__form,
.vdb-search-demo .search-hero--bar-bare .search-hero__form {
    color: #14161a;
}

.vdb-search-demo .search-hero--bar-light .search-hero__form .form-floating > .form-control,
.vdb-search-demo .search-hero--bar-bare .search-hero__form .form-floating > .form-control {
    background-color: #fff;
    border-color: rgba(20, 22, 26, 0.12);
    color: #14161a;
}

.vdb-search-demo .search-hero--bar-light .search-hero__form .form-floating > label,
.vdb-search-demo .search-hero--bar-bare .search-hero__form .form-floating > label,
.vdb-search-demo .search-hero--bar-light .search-hero__form .dropdown-toggle,
.vdb-search-demo .search-hero--bar-bare .search-hero__form .dropdown-toggle {
    color: #14161a;
}

.vdb-search-demo .search-hero--bar-bare .search-hero__form .form-floating > .form-control,
.vdb-search-demo .search-hero--bar-bare .search-hero__submit {
    box-shadow: 0 0.75rem 2rem rgba(0, 0, 0, 0.22);
}

/* ① keeps light type on transparent fields. */
.vdb-search-demo .search-hero--bar-glass .search-hero__form {
    color: #fff;
}

.vdb-search-demo .search-hero--bar-glass .search-hero__form .form-floating > .form-control {
    background-color: transparent;
    border-color: rgba(255, 255, 255, 0.42);
    color: #fff;
}

.vdb-search-demo .search-hero--bar-glass .search-hero__form .form-floating > label,
.vdb-search-demo .search-hero--bar-glass .search-hero__form .dropdown-toggle {
    color: #fff;
}

/* On the transparent-field bar the submit reads better inverted. */
.vdb-search-demo .search-hero--bar-glass .search-hero__submit {
    background-color: #fff;
    border-color: #fff;
    color: #14161a;
}

.vdb-search-demo .search-hero--bar-glass .search-hero__submit:hover {
    background-color: rgba(255, 255, 255, 0.88);
    border-color: rgba(255, 255, 255, 0.88);
    color: #14161a;
}

/* ③  ?bar=3 — the solid mist card: highest contrast, no transparency at all. */
.vdb-search-demo .search-hero--bar-solid .search-hero__form {
}

.vdb-search-demo .search-hero--bar-solid .search-hero__form-surface {
    background: #f9f8f7;
    box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.28);
}

.vdb-search-demo .search-hero--bar-solid .search-hero__form,
.vdb-search-demo .search-hero--bar-solid .search-hero__form .form-control,
.vdb-search-demo .search-hero--bar-solid .search-hero__form .form-floating > label,
.vdb-search-demo .search-hero--bar-solid .search-hero__form .dropdown-toggle {
    color: #14161a;
}

/* Search button: icon only on the narrowest phones, where the third column is
   too tight for a word. */
.vdb-search-demo .search-hero__submit {
    min-height: 2.75rem;
}

@media (max-width: 419px) {
    .vdb-search-demo .search-hero__submit-label {
        display: none;
    }
}

/* Search by map: a quiet entry point hanging off the bar, in both hero states. Every
   variant sits on a dark ground (photograph or the collapsed band), so it is white. */
.vdb-search-demo .search-hero__map {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.75rem;
    padding: 0;
    border: 0;
    background: none;
    color: #fff;
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: underline;
    text-underline-offset: 0.25em;
}

.vdb-search-demo .search-hero__map iconify-icon {
    font-size: 1rem;
    text-decoration: none;
}

.vdb-search-demo .search-hero__map:hover,
.vdb-search-demo .search-hero__map:focus-visible {
    color: rgba(255, 255, 255, 0.82);
}

/* Active search → no photograph, just the bar, so results start at the top of the
   screen. This is the answer to the open question in the client's document. */
.vdb-search-demo .search-hero--collapsed {
    min-height: 0;
    background: #14161a;
}

.vdb-search-demo .search-hero--collapsed .search-hero__inner {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

.HEADER-OVERLAPS.vdb-search-demo .search-hero--collapsed {
    padding-top: calc(var(--APP_HEADER_HEIGHT, 0px) * 1.05);
}

/* ── Headline under the search box (point 4) ─────────────────────────────── */
.vdb-search-demo .search-headline {
    /* Equal top and bottom (client, 3 Sep): the headline sits between the search bar
       and the results, and an uneven gap made it read as belonging to the bar. */
    padding-top: 1.75rem;
    padding-bottom: 1.75rem;
    text-align: center;
}

.vdb-search-demo .search-headline__title {
    margin: 0;
    font-size: clamp(1.25rem, 4.5vw, 1.875rem);
    line-height: 1.2;
    text-wrap: balance;
}

/* The H1 travels with the hero type, or the hierarchy inverts on a wide screen.
   Declared here rather than up with the hero block: same specificity, and the rule
   above would otherwise win on source order. */
@media (min-width: 992px) {
    .vdb-search-demo .search-headline__title {
        font-size: clamp(1.875rem, 2.2vw, 2.5rem);
    }
}

/* ── Results: context statement, then the grid ───────────────────────────── */
.vdb-search-demo .search-results {
    gap: 0.75rem;
    padding-top: 1rem;
    padding-bottom: 3rem;
}

.vdb-search-demo .search-results__context {
    padding-top: 0.5rem;
}

.vdb-search-demo .search-results__count {
    font-size: 0.8125rem;
    font-weight: 400;
    color: #5b6572;
}

.vdb-search-demo .search-results__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.vdb-search-demo .search-results__chip {
    padding: 0.25rem 0.7rem;
    border: 1px solid rgba(20, 22, 26, 0.18);
    border-radius: 999px;
    font-size: 0.8125rem;
    line-height: 1.4;
    white-space: nowrap;
}

.vdb-search-demo .search-results__clear {
    font-size: 0.8125rem;
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* ── Filter popup: Apply vs Clear vs All ─────────────────────────────────── */
/* The client's "smaller issue" — nobody can tell they have to press Apply — is not
   a design decision, it is a missing colour. koble's markup asks for `.btn-onyx`
   (Apply), `.btn-smoke` (Clear) and `.btn-pearl` (All), but the theme's
   $theme-colors map only defines primary/secondary/dark/light/soft, so Bootstrap
   never generates those three variants and all three controls render as bare
   uppercase text. Same for `.btn-outline-onyx` on "Save this search".
   Fixed here for the demo; the real fix is adding the variants to the SCSS.
   The !important flags are unavoidable: the markup also carries Bootstrap's
   `.rounded-0` and `.p-1`/`.p-2` utilities, which are !important themselves. */
.vdb-search-demo .cbpopup-modal .modal-footer {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 1.5rem;
    padding: 1rem 1.25rem 1.25rem !important;
}

/* The markup wraps these in `.row.row-cols-2`, which pins each link to 50% width
   and stacks them. Let them be links: Clear left, All right, Apply on its own row. */
.vdb-search-demo .cbpopup-modal .modal-footer .none {
    width: auto;
    margin-right: auto;
}

.vdb-search-demo .cbpopup-modal .modal-footer .all {
    width: auto;
}

.vdb-search-demo .cbpopup-modal .modal-footer .none,
.vdb-search-demo .cbpopup-modal .modal-footer .all {
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.04em;
    color: #5b6572;
    text-decoration: underline;
    text-underline-offset: 0.2em;
    background: none;
}

.vdb-search-demo .cbpopup-modal .modal-footer button[data-bs-dismiss="modal"] {
    background-color: #14161a;
    border-color: #14161a;
    color: #fff;
    border-radius: 5rem !important;
    padding: 0.95rem 2rem !important;
    margin-top: 0.75rem;
}

.vdb-search-demo .cbpopup-modal .modal-footer button[data-bs-dismiss="modal"]:hover,
.vdb-search-demo .cbpopup-modal .modal-footer button[data-bs-dismiss="modal"]:focus-visible {
    background-color: #2c3038;
    border-color: #2c3038;
    color: #fff;
}

/* The option rows are hit by the same missing-colour problem: the parent label asks
   for `.btn-outline-onyx` and the children for `.btn-smoke`, so both render as bare
   text and nothing looks selectable — or selected. Give them the pill treatment the
   markup expects, and a visible checked state. */
.vdb-search-demo .cbpopup-modal .option-group__parent-label,
.vdb-search-demo .cbpopup-modal .option-group__child-label {
    border-radius: 5rem;
    border: 1px solid rgba(20, 22, 26, 0.2);
    text-align: left;
}

.vdb-search-demo .cbpopup-modal .option-group__child-label {
    background-color: #f4f3f1;
    border-color: transparent;
    font-weight: 500;
}

.vdb-search-demo .cbpopup-modal .option-group__parent-label:has(input:checked),
.vdb-search-demo .cbpopup-modal .option-group__child-label:has(input:checked) {
    background-color: #14161a;
    border-color: #14161a;
    color: #fff;
}

/* "Save this search" reads as plain text for the same reason. */
.vdb-search-demo .save-search-btn {
    padding: 0.6rem 1.25rem;
    border: 1px solid rgba(20, 22, 26, 0.35);
    border-radius: 5rem;
}

/* ── Off-market module with a photograph ─────────────────────────────────── */
/* Only the module that leads the no-results state gets the photograph: there it is
   the first thing on the page and has to carry it. The copy inside the results grid
   stays the quiet panel, so it reads as one card among the properties.
   The shared template paints the panel with Bootstrap's `.bg-light`, whose
   background-color carries !important — hence the !important here rather than a
   deeper selector. The photo URL arrives as --offmarket-photo from the template. */
.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-inner {
    background-color: #14161a !important;
    background-image: linear-gradient(rgba(12, 14, 18, 0.7), rgba(12, 14, 18, 0.7)), var(--offmarket-photo);
    background-size: cover;
    background-position: center;
    color: #fff;
}

.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-heading,
.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-subheading,
.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-icon {
    color: #fff;
}

.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-subheading {
    max-width: 52ch;
}

.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-cta {
    border-color: #fff;
    color: #fff;
}

.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-cta:hover,
.vdb-search-demo .search-empty .property-card--offmarket .property-card__offmarket-cta:focus-visible {
    background-color: #fff;
    color: #14161a;
}

/* In the grid the module takes ONE property slot — third position on the first page,
   last on every page after it — so it reads as part of the listing. Property cards
   are never resized.
   Page sizes are odd (9), so `cards + module` is even and the two-column rows come
   out full on their own. The one exception is a final page that returns an even
   number of cards: then the module ends up alone in the last row, and only then does
   it take the whole width. Never a card. */
@media (min-width: 1200px) {
    .vdb-search-demo .property-listing__grid > .property-card--offmarket:last-child:nth-child(odd) {
        width: 100%;
    }
}

.vdb-search-demo .search-results__sortbar {
    padding-top: 0.5rem;
    padding-bottom: 0.75rem;
}

/* "Load more" reads as one more row of the grid, so it sits at the grid's own row
   distance from the cards above it AND from the closing module below it — the
   button belongs to the listing's rhythm, not dropped between two sections.
   `--results-gutter` is the grid's row gutter: `g-5` is 1.5rem on this theme's
   spacer scale (measured, not assumed — it is NOT Bootstrap's stock 3rem, and it
   does not change per breakpoint). The flex gap on .search-results already
   contributes 0.75rem of the distance, hence the subtraction. */
.vdb-search-demo .search-results {
    --results-gutter: 1.5rem;
}

.vdb-search-demo .property-listing__loadmore {
    margin-top: calc(var(--results-gutter) - 0.75rem);
    margin-bottom: calc(var(--results-gutter) - 0.75rem);
}

/* Last page: the wrapper still renders, empty, and would leave a double gap. */
.vdb-search-demo .property-listing__loadmore:empty {
    display: none;
}

/* ── No results: module first, then the message, then labelled suggestions ─ */
.vdb-search-demo .search-empty {
    gap: 2.25rem;
    padding-top: 0.5rem;
}

.vdb-search-demo .search-empty__message {
    max-width: 46ch;
    margin: 0 auto;
}

.vdb-search-demo .search-empty__suggestions-head {
    margin-bottom: 1.25rem;
    text-align: center;
}

/* ── Locations picker: proportions ───────────────────────────────────────────
   The template leans on Bootstrap utilities that were sized for a different
   context: the filter input carries `fs-3` (so "Filter by Locations…" arrives at
   ~1.75rem), the option labels are `btn-lg` with uppercase inherited from `.btn`,
   and the header/body paddings come from the modal defaults. Bring it back to one
   scale: a 1.0625rem field, 0.9375rem options, and paddings that all resolve to
   1.25rem — minimal, but sized like a form and not like a poster. */
.vdb-search-demo .cbpopup-modal .modal-content {
    border: 0;
}

@media (min-width: 992px) {
    .vdb-search-demo .cbpopup-modal .modal-content {
        border-radius: 1.25rem;
        overflow: hidden;
    }
}

.vdb-search-demo .cbpopup-modal .modal-header {
    padding: 1.25rem 3.25rem 1.25rem 1.25rem !important;
}

.vdb-search-demo .cbpopup-modal .search-popup {
    font-size: 1.0625rem !important;
    line-height: 1.4;
}

.vdb-search-demo .cbpopup-modal .search-popup::placeholder {
    color: rgba(20, 22, 26, 0.45);
}

.vdb-search-demo .cbpopup-modal .modal-body {
    padding: 1.25rem !important;
    gap: 0.5rem !important;
}

.vdb-search-demo .cbpopup-modal .option-group__parent-label,
.vdb-search-demo .cbpopup-modal .option-group__child-label {
    padding: 0.7rem 1rem !important;
    font-size: 0.9375rem;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    min-height: 2.75rem;
}

.vdb-search-demo .cbpopup-modal .option-group__child-label {
    font-size: 0.875rem;
}

.vdb-search-demo .cbpopup-modal .option-group__childs {
    padding-top: 0.5rem !important;
}

/* ── Locations picker: city vs neighbourhoods ─────────────────────────────────
   Client feedback (Andrés, 25 Aug): "it's unclear whether we have to click Barcelona
   city plus neighbourhoods or only neighbourhoods is enough". Both tiers rendered as
   identical pills with identical checked states, so they read as peers — nothing said
   the city IS the whole area rather than one more thing to add.
   The city row now reads "All <city>" (string comes from PHP, see
   page-search-demo.php), sits on its own line closed by a divider, and the
   neighbourhoods hang off a rail below it. Picking the city dims them and says they
   are included — the visible half of the mutual exclusion the JS already enforced
   silently. */
.vdb-search-demo .cbpopup-modal .option-group + .option-group {
    margin-top: 0.75rem;
}

/* The divider says "what follows belongs to this city", so only a city that HAS
   neighbourhoods gets one. */
.vdb-search-demo .cbpopup-modal .option-group:has(.option-group__child) .option-group__parent {
    padding-bottom: 0.5rem;
    border-bottom: 1px solid rgba(20, 22, 26, 0.1);
}

.vdb-search-demo .cbpopup-modal .option-group__parent-label {
    border-radius: 0.875rem;
    border-color: transparent;
    font-weight: 600;
}

/* The neighbourhoods, subordinated: indented off a rail instead of floating free. */
.vdb-search-demo .cbpopup-modal .option-group > .child {
    margin: 0.5rem 0 0 0.5rem;
    padding-left: 0.875rem;
    border-left: 2px solid rgba(20, 22, 26, 0.1);
}

.vdb-search-demo .cbpopup-modal .option-group__included {
    display: none;
    margin: 0;
    font-size: 0.8125rem;
    color: #5b6572;
}

.vdb-search-demo .cbpopup-modal .option-group--all .option-group__included {
    display: block;
}

/* Whole city picked → the neighbourhoods are already in the search, so they read as
   context rather than as choices. Dimmed but still clickable on purpose: clicking one
   drops "All <city>" and filters by that neighbourhood instead (the mutual exclusion),
   which is the natural way to change your mind. A dead zone would force a detour. */
.vdb-search-demo .cbpopup-modal .option-group--all .option-group__childs {
    opacity: 0.45;
}

.vdb-search-demo .cbpopup-modal .form-check-input {
    width: 1.125rem;
    height: 1.125rem;
    border-radius: 0.25rem;
}

.vdb-search-demo .cbpopup-modal .modal-footer button[data-bs-dismiss="modal"] {
    min-height: 3.25rem;
    font-size: 0.8125rem;
    letter-spacing: 0.08em;
}

/* ── Rooms / Price dropdowns: same grammar as the modal ──────────────────────
   Options are `.btn-outline-onyx` labels — another variant the theme never
   generates — so they arrive as bare text with no selected state. Give them the
   pill treatment, and lay the footer out as Clear (quiet link) + Apply (solid),
   which is the pairing the client asked for. */
.vdb-search-demo .search-hero__form .dropdown-menu {
    border: 0;
    box-shadow: 0 1rem 2.5rem rgba(0, 0, 0, 0.18);
}

.vdb-search-demo .search-hero__form .dropdown-body {
    padding: 0.75rem !important;
    gap: 0.375rem !important;
}

.vdb-search-demo .search-hero__form .option-group__parent-label {
    padding: 0.6rem 0.9rem !important;
    border: 1px solid rgba(20, 22, 26, 0.14);
    border-radius: 5rem;
    background-color: #fff;
    color: #14161a;
    font-size: 0.875rem;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    min-height: 2.5rem;
}

.vdb-search-demo .search-hero__form .option-group__parent-label:has(input:checked),
.vdb-search-demo .search-hero__form .option-group__parent-input:checked + .option-group__parent-label {
    background-color: #14161a;
    border-color: #14161a;
    color: #fff;
}

.vdb-search-demo .search-hero__form .dropdown-footer {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem !important;
}

/* The footer carries `.row.row-cols-1`, which pins every child to width:100% and
   would stack Clear above Apply. */
.vdb-search-demo .search-hero__form .dropdown-footer > * {
    flex: 0 0 auto;
    width: auto;
}

.vdb-search-demo .search-hero__form .dropdown-footer .none {
    margin-right: auto;
    padding: 0 !important;
    background: none;
    color: #5b6572;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-decoration: underline;
    text-underline-offset: 0.2em;
    text-transform: uppercase;
}

.vdb-search-demo .search-hero__form .dropdown-footer__apply {
    padding: 0.55rem 1.35rem;
    border-radius: 5rem;
    background-color: #14161a;
    border-color: #14161a;
    color: #fff;
    font-size: 0.75rem;
    letter-spacing: 0.08em;
}

.vdb-search-demo .search-hero__form .dropdown-footer__apply:hover,
.vdb-search-demo .search-hero__form .dropdown-footer__apply:focus-visible {
    background-color: #2c3038;
    border-color: #2c3038;
    color: #fff;
}

/* ②'s panel is dark and its submit is ink, so the button needs a hairline to
   separate from the surface behind it — otherwise it reads as a hole in the bar. */
.vdb-search-demo .search-hero--bar-light .search-hero__submit {
    border: 1px solid rgba(255, 255, 255, 0.45);
}

/* ── Labels that actually float ──────────────────────────────────────────────
   The theme pins every label to the top border in all states (see the override in
   _fields.scss: "the label stays pinned on the top border in every state"), which
   is why they read as permanent captions. Here they behave like floating labels:
   resting inside the field as its placeholder, rising to the border — and only then
   taking the frosted pill — once the field has a value or focus. */
.vdb-search-demo .search-hero__form .form-floating > label {
    top: 50%;
    left: 1.15rem;
    padding: 0;
    border-radius: 999px;
    background-color: transparent;
    backdrop-filter: none;
    font-size: 0.9375rem;
    transform: translateY(-50%);
    transition: top 0.16s ease, font-size 0.16s ease, background-color 0.16s ease, padding 0.16s ease;
}

.vdb-search-demo .search-hero__form .form-floating > .form-control:focus ~ label,
.vdb-search-demo .search-hero__form .form-floating > .form-control:not(:placeholder-shown) ~ label,
.vdb-search-demo .search-hero__form .form-floating > .form-select ~ label {
    top: -0.55rem;
    padding: 0 0.6rem;
    font-size: 0.8125rem;
    background-color: rgba(255, 255, 255, 0.16);
    backdrop-filter: blur(10px) saturate(1.3);
    transform: none;
}

/* On the two light-field variants the resting label sits on white, so it needs the
   muted ink of a placeholder rather than the crisp label colour. */
.vdb-search-demo .search-hero--bar-light .search-hero__form .form-floating > label,
.vdb-search-demo .search-hero--bar-bare .search-hero__form .form-floating > label,
.vdb-search-demo .search-hero--bar-solid .search-hero__form .form-floating > label {
    color: rgba(20, 22, 26, 0.55);
}

.vdb-search-demo .search-hero--bar-light .search-hero__form .form-floating > .form-control:focus ~ label,
.vdb-search-demo .search-hero--bar-light .search-hero__form .form-floating > .form-control:not(:placeholder-shown) ~ label,
.vdb-search-demo .search-hero--bar-bare .search-hero__form .form-floating > .form-control:focus ~ label,
.vdb-search-demo .search-hero--bar-bare .search-hero__form .form-floating > .form-control:not(:placeholder-shown) ~ label,
.vdb-search-demo .search-hero--bar-solid .search-hero__form .form-floating > .form-control:focus ~ label,
.vdb-search-demo .search-hero--bar-solid .search-hero__form .form-floating > .form-control:not(:placeholder-shown) ~ label {
    color: #14161a;
}

/* ── Price dropdown: room for a range ────────────────────────────────────────
   The menu inherits `w-100`, i.e. the width of its trigger — a third of the row on a
   phone, ~105px. No price range fits in that, so options wrapped unevenly. Give the
   menu its own width and anchor it to the field's right edge so it opens inwards and
   never leaves the viewport; keep every option on one line, with tabular figures so
   the numbers line up down the column. */
.vdb-search-demo .search-hero__form [data-price-range] .dropdown-menu {
    width: auto !important;
    min-width: 12.5rem;
    max-width: calc(100vw - 2.5rem);
    left: auto;
    right: 0;
}

.vdb-search-demo .search-hero__form [data-price-range] .option-group__parent-label {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* ── Rooms dropdown: room for the footer ─────────────────────────────────────
   Same problem as the price menu, reported on a phone: the menu inherits `w-100`
   from its `col-4` trigger — 160px at 390 — while its footer needs 185px (Clear +
   the injected Search + paddings + gap), and the menu's own `overflow: hidden`
   cut the Search button off at the right edge.
   Anchored LEFT, unlike the price menu: Rooms is the leftmost of the three
   columns, so pinning it to its right edge would push it off the other side. */
.vdb-search-demo .search-hero__form .one-option .dropdown-menu {
    width: auto !important;
    min-width: 13rem;
    max-width: calc(100vw - 1.5rem);
}

/* The selected bracket also has to fit the closed field. */
.vdb-search-demo .search-hero__form [data-price-range] .checkbox-dropdown__textfield {
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
}

/* The hero art is a <picture> now (a separate mobile crop), so the wrapper takes the
   absolute positioning and the <img> fills it. */
.vdb-search-demo .search-hero__bg-wrap {
    position: absolute;
    inset: 0;
}

/* ── Price: a range off one ladder ───────────────────────────────────────────
   Two bounds, one scale (client, 27 Aug). The rest of the bar speaks in pills, and
   this panel deliberately does not: a pill says "tag, pick several", while every rung
   here is one figure off an ordered scale. The pill treatment also rendered the
   neutral "No min" / "Unlimited" rows FILLED, so an untouched field read as two active
   filters.

   The register instead is the one the subject already uses for money — a price sheet:
   figures on a hairline grid, tabular numerals so they align down the column, no radius,
   no ornament. The only thing drawn is the pair of bounds themselves. */

.vdb-search-demo .search-hero__form [data-price-minmax] .dropdown-menu {
    width: auto !important;
    min-width: 20rem;
    padding: 0;
    border-radius: 0.5rem;
    left: auto;
    right: 0;
}

.vdb-search-demo .search-hero__form .price-minmax {
    display: grid;
    grid-template-columns: 1fr 1fr;
    /* No gap: the two columns are one band, and the divider below carries the seam. */
    gap: 0;
    padding: 0 !important;
}

.vdb-search-demo .search-hero__form .price-minmax__col {
    min-width: 0;
    padding: 1rem 0 0.5rem;
}

/* The seam between floor and ceiling, and the only rule inside the body. */
.vdb-search-demo .search-hero__form .price-minmax__col + .price-minmax__col {
    border-left: 1px solid rgba(20, 22, 26, 0.1);
}

.vdb-search-demo .search-hero__form .price-minmax__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin: 0 0 0.625rem;
    padding: 0 1rem;
    min-height: 1.125rem;
}

.vdb-search-demo .search-hero__form .price-minmax__head-label {
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #5b6572;
}

/* The live bound, so it stays readable once the list is scrolled past it. */
.vdb-search-demo .search-hero__form .price-minmax__head-value {
    font-size: 0.8125rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: #14161a;
}

.vdb-search-demo .search-hero__form .price-minmax__list {
    max-height: 15.5rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* A hairline top edge so the first rung reads as part of a grid, not floating. */
    border-top: 1px solid rgba(20, 22, 26, 0.06);
}

.vdb-search-demo .search-hero__form .price-minmax__row {
    position: relative;
}

.vdb-search-demo .search-hero__form .price-minmax__label {
    display: block;
    margin: 0;
    padding: 0.5rem 1rem;
    cursor: pointer;
    border-bottom: 1px solid rgba(20, 22, 26, 0.06);
    transition: background-color 0.12s ease, color 0.12s ease;
}

.vdb-search-demo .search-hero__form .price-minmax__figure {
    display: block;
    font-size: 0.875rem;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    line-height: 1.5;
    color: #14161a;
    /* Client, 31 Aug: both columns read left. The earlier mirrored alignment made the
       two sets of figures meet at the seam, but it also meant the eye had to change
       direction halfway across the panel; one reading edge wins. */
    text-align: left;
}

/* The reset rung is a way out, not a value: quiet, and never filled. */
.vdb-search-demo .search-hero__form .price-minmax__row--reset .price-minmax__figure {
    font-size: 0.75rem;
    letter-spacing: 0.02em;
    color: #5b6572;
}

.vdb-search-demo .search-hero__form .price-minmax__label:hover {
    background-color: #f4f3f1;
}

/* The chosen bound itself. Client, 31 Aug: the two picks carry the same weight as a
   selection anywhere else on the bar — solid ink, white figure. Client, 1 Sep: and they
   are the ONLY thing marked. The rungs between them used to be tinted to draw the range
   as one continuous band, but a grey that faint next to solid black read as a second,
   weaker kind of selection rather than as a span. Two solid ends say it on their own. */
.vdb-search-demo .search-hero__form .price-minmax__input:checked + .price-minmax__label {
    background-color: #14161a;
    box-shadow: none;
}

.vdb-search-demo .search-hero__form .price-minmax__input:checked + .price-minmax__label .price-minmax__figure {
    color: #fff;
    font-weight: 600;
}

/* A checked reset rung ("No min" / "Unlimited") means NO bound, and both are checked
   on an untouched field — filling them would show two active filters before the
   visitor has chosen anything. They stay quiet. */
.vdb-search-demo .search-hero__form .price-minmax__row--reset .price-minmax__input:checked + .price-minmax__label {
    background-color: transparent;
    box-shadow: none;
}

.vdb-search-demo .search-hero__form .price-minmax__row--reset .price-minmax__input:checked + .price-minmax__label .price-minmax__figure {
    color: #5b6572;
    font-weight: 400;
}

/* Out of reach because of the other bound. Dimmed rather than removed, so the ladder
   does not jump around as you pick. */
.vdb-search-demo .search-hero__form .price-minmax__row.is-disabled .price-minmax__label {
    background-color: transparent;
    cursor: not-allowed;
}

.vdb-search-demo .search-hero__form .price-minmax__row.is-disabled .price-minmax__figure {
    color: rgba(20, 22, 26, 0.28);
}

/* Keyboard focus has to survive the pill removal. */
.vdb-search-demo .search-hero__form .price-minmax__input:focus-visible + .price-minmax__label {
    outline: 2px solid #14161a;
    outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
    .vdb-search-demo .search-hero__form .price-minmax__label {
        transition: none;
    }
}

/* Phones: a bottom sheet, not a dropdown. Sixteen rungs in a menu hung off a
   third-of-a-row trigger ran off the left edge of the viewport and cut the Minimum
   column in half. The Locations picker on this same bar is already a full-screen modal
   on phones, so this matches it rather than inventing a third behaviour. */
@media (max-width: 575.98px) {
    .vdb-search-demo .search-hero__form [data-price-minmax] .dropdown-menu {
        position: fixed !important;
        inset: auto 0 0 0 !important;
        transform: none !important;
        width: 100% !important;
        min-width: 0;
        max-width: none;
        margin: 0 !important;
        border-radius: 1rem 1rem 0 0;
        box-shadow: 0 -1rem 3rem rgba(0, 0, 0, 0.22);
        z-index: 1060;
    }

    .vdb-search-demo .search-hero__form [data-price-minmax] .price-minmax__list {
        max-height: 42vh;
    }

    .vdb-search-demo .search-hero__form [data-price-minmax] .price-minmax__label {
        /* Comfortable thumb target once the panel owns the full width. */
        padding-top: 0.6875rem;
        padding-bottom: 0.6875rem;
    }
}

/* The closed field still has to hold "€1.25M – €2.5M" in a third of a row. */
.vdb-search-demo .search-hero__form [data-price-minmax] .checkbox-dropdown__textfield {
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
}
