/**
 * Real Estate Platform — Elementor Addons
 * Responsive search + listing styles.
 *
 * WHY THIS IS A SEPARATE FILE FROM widgets.css
 * widgets.css is a *cosmetic fallback* that is deliberately skipped when a
 * theme declares `add_theme_support('rep-widgets-style')`. Everything in this
 * file is *functional* (the mobile search layout, the AJAX results dropdown,
 * the animated placeholder, the two-column mobile grid) and must load on every
 * site regardless of that theme support flag — so it is enqueued
 * unconditionally on `wp_enqueue_scripts`. Keep cosmetic-only defaults in
 * widgets.css and behaviour-critical rules here.
 *
 * SPECIFICITY NOTE
 * The Firmtechcloud theme already restyles `.wd-find-select` at
 * `max-width: 1099px` (stacked column, pill inputs). Rules below are scoped
 * under `.repea-search` — one extra class — specifically so they win on
 * specificity rather than on load order, and without a single `!important`.
 *
 * BREAKPOINT NOTE
 * Mobile rules use `max-width: 767px` to match Elementor's own default mobile
 * breakpoint exactly, so the CSS custom properties Elementor writes from the
 * responsive "Columns" / "Gap" controls switch over on the same pixel.
 */

/* ══════════════════════════════════════════════════════════════════
   1. SEARCH FIELD SHELL  (all breakpoints — desktop stays untouched)
   ══════════════════════════════════════════════════════════════════ */

/* The keyword field becomes the positioning context for the dropdown and the
   animated placeholder. `display:block` keeps the desktop box model identical
   to the original markup, where the input was a direct child. */
/* Positioning context for the animated placeholder and the AJAX dropdown's
   anchor point lives on `.repea-kw-field` below, not here — `.repea-kw`
   itself no longer needs to establish one. */
.repea-search .repea-kw-inner {
    position: relative;
    display: block;
}

.repea-search .repea-kw-field {
    position: relative;
    display: block;
    min-width: 0;
    flex: 1 1 auto;
}

/* Icon-only submit that becomes the magnifier inside the mobile pill.
   Hidden on desktop, where the original full-width "Search" button stands. */
.repea-search .repea-kw-submit {
    display: none;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    background: none;
    color: #161e2d;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

/* Clear ("×") button — shown on every breakpoint, but only once the field
   actually has a value (JS toggles `.is-visible`). */
.repea-search .repea-kw-clear {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    display: none;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #e9edf1;
    color: #56606e;
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
}

.repea-search .repea-kw-clear.is-visible {
    display: flex;
}

.repea-search .repea-kw-clear:hover {
    background: #dbe1e8;
}

/* Keep room for the clear button so long queries never slide underneath it.
   Driven by a JS-toggled class rather than `:has()` / a sibling combinator,
   both of which would fail here (the button follows the input in the DOM,
   and `:has()` is unsupported on older mobile Safari). */
.repea-search .repea-kw-field.has-value .form-control {
    padding-right: 30px;
}

/* Two elements exist purely to serve the phone layout and must leave the
   desktop design byte-for-byte as it was:
     - `.repea-kw--mobile-only` — the keyword field in "Compact" layout, which
       has no desktop counterpart but still has to own the single `name="s"`.
     - `.repea-adv--mobile-only` — the filter button/panel rendered when the
       Advanced panel is switched off, existing only to host the relocated
       Type and Location controls. */
@media only screen and (min-width: 768px) {
    .repea-search .repea-kw--mobile-only,
    .repea-search .repea-adv--mobile-only {
        display: none;
    }
}

/* The relocation slot is only ever populated on phones. */
.repea-search .repea-mobile-fields:empty {
    display: none;
}

/* Defensive only: `.repea-results` sits inside `.form-sl` → `.tab-pane` →
   `.tab-content`, the same ancestors `.wd-search-form` (the Advanced panel)
   already relies on for its own overflow — proven safe by that panel already
   working. `.wd-find-select` / `.inner-group` are no longer ancestors of the
   dropdown (see the DOM-sibling note above `.repea-results`), so they are
   deliberately left out here rather than carried over unnecessarily. */
.repea-search .form-sl,
.repea-search .tab-content,
.repea-search .tab-pane {
    overflow: visible;
}

/* ══════════════════════════════════════════════════════════════════
   2. ANIMATED PLACEHOLDER
   ══════════════════════════════════════════════════════════════════ */

/* Sits over the input, never intercepts taps/clicks, and is removed from the
   accessibility tree — the input keeps a real `placeholder` attribute until
   JS confirms it can animate, so screen readers and no-JS visitors are
   unaffected. */
.repea-search .repea-anim-ph {
    position: absolute;
    top: 50%;
    left: 0;
    transform: translateY(-50%);
    display: none;
    align-items: center;
    max-width: 100%;
    overflow: hidden;
    color: #a3abb0;
    font-weight: 400;
    white-space: nowrap;
    pointer-events: none;
    opacity: 1;
    transition: opacity .15s ease;
}

/* Only ever displayed once JS has taken over and cleared the real
   placeholder, which prevents the two from ever doubling up. */
.repea-search .repea-anim-ph.is-active {
    display: flex;
}

.repea-search .repea-anim-ph.is-hidden {
    opacity: 0;
}

.repea-search .repea-anim-ph__static {
    flex: 0 0 auto;
    white-space: pre;
}

.repea-search .repea-anim-ph__viewport {
    display: block;
    height: 1.5em;
    overflow: hidden;
}

.repea-search .repea-anim-ph__track {
    display: block;
    will-change: transform;
    transition: transform .55s cubic-bezier(.22, .61, .36, 1);
}

.repea-search .repea-anim-ph__item {
    display: block;
    height: 1.5em;
    line-height: 1.5em;
}

/* Respect the OS "reduce motion" setting: the list stops sliding and simply
   shows the first entry as a plain static placeholder. */
@media (prefers-reduced-motion: reduce) {
    .repea-search .repea-anim-ph__track {
        transition: none;
    }
}

/* ══════════════════════════════════════════════════════════════════
   3. AJAX RESULTS DROPDOWN
   ══════════════════════════════════════════════════════════════════ */

/**
 * `.repea-results` is now a DOM sibling of `.wd-search-form` (the Advanced
 * panel) — see SearchFormWidget::render(). Deliberately NOT setting `top` or
 * `left` here: `.wd-search-form` sets neither either, so with no inset
 * properties `position: absolute` keeps each element at the position it
 * would have occupied in normal flow — i.e. immediately after
 * `.wd-find-select`. Because both sit at that same point in the markup, this
 * is what guarantees they open at the identical width and position, without
 * the two ever having to be kept in sync by hand.
 */
.repea-results {
    position: absolute;
    z-index: 11;
    width: 100%;
    margin-top: 5px;
    padding: 8px;
    border: 1px solid #e4e4e4;
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 16px 40px rgba(22, 30, 45, .14);
    max-height: min(62vh, 440px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    text-align: left;
}

.repea-results[hidden] {
    display: none;
}

.repea-results__group {
    margin: 4px 8px 6px;
    color: #a3abb0;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.repea-results__state {
    padding: 18px 12px;
    color: #a3abb0;
    font-size: 14px;
    text-align: center;
}

.repea-result {
    display: flex;
    gap: 12px;
    align-items: center;
    padding: 9px 10px;
    border-radius: 12px;
    color: inherit;
    text-decoration: none;
}

/* `.is-active` is the keyboard cursor (arrow keys); hover covers the mouse. */
.repea-result:hover,
.repea-result:focus-visible,
.repea-result.is-active {
    background: #f3f6f9;
    color: inherit;
    text-decoration: none;
    outline: none;
}

.repea-result__thumb {
    flex: 0 0 auto;
    width: 52px;
    height: 52px;
    border-radius: 10px;
    object-fit: cover;
    background: #eef1f4;
}

/* `min-width:0` is what actually lets the ellipsis work inside a flex row. */
.repea-result__body {
    flex: 1 1 auto;
    min-width: 0;
}

.repea-result__title {
    display: block;
    color: #161e2d;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.repea-result__meta {
    display: block;
    margin-top: 2px;
    color: #a3abb0;
    font-size: 12px;
    line-height: 1.4;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.repea-result__price {
    flex: 0 0 auto;
    align-self: center;
    color: #161e2d;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}

.repea-result--term .repea-result__title {
    font-weight: 500;
}

.repea-results__all {
    display: block;
    margin-top: 4px;
    padding: 11px 10px;
    border-top: 1px solid #eef1f4;
    color: #1563df;
    font-size: 13px;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
}

.repea-results__all:hover,
.repea-results__all.is-active {
    background: #f3f6f9;
    color: #1563df;
    text-decoration: none;
}

/* ══════════════════════════════════════════════════════════════════
   4. MOBILE SEARCH PILL  (≤767px — Screenshot 1)
   ══════════════════════════════════════════════════════════════════ */

@media only screen and (max-width: 767px) {

    /* The white card, its padding and its radius all belong to the pill and
       the filter button now, not to the form shell. */
    .repea-search--mobile .wd-find-select {
        flex-direction: row;
        align-items: center;
        gap: 10px;
        padding: 0;
        border-radius: 0;
        background: transparent;
        box-shadow: none;
    }

    .repea-search--mobile .wd-find-select .inner-group {
        flex: 1 1 auto;
        gap: 0;
        min-width: 0;
        padding: 0;
    }

    /* Type + Location are relocated into the filter panel by JS (see
       rep-search.js → relocateFields). They are hidden only while still
       parented to `.inner-group`, and shown again once moved — a child
       selector, so a single DOM move flips both rules at once and there is
       never a duplicated `name=` in the submitted form. */
    .repea-search--mobile .inner-group > .form-group-1,
    .repea-search--mobile .inner-group > .form-group-2 {
        display: none;
    }

    .repea-search--mobile .repea-kw > label {
        display: none;
    }

    .repea-search--mobile .repea-kw {
        width: 100%;
    }

    /* The pill itself. */
    .repea-search--mobile .repea-kw-inner {
        display: flex;
        align-items: center;
        gap: 10px;
        min-height: 52px;
        padding: 6px 16px;
        border: 1px solid #e4e4e4;
        border-radius: 99px;
        background: #fff;
    }

    .repea-search--mobile .repea-kw-submit {
        display: flex;
    }

    /* Strip the border/padding the theme's ≤1099px rule puts on the input —
       the pill wrapper owns those now. Scoped to `.repea-kw` so the Location
       and Type controls keep their own pill styling inside the panel. */
    .repea-search--mobile .wd-find-select .inner-group .repea-kw .form-control {
        padding: 0;
        border: 0;
        border-radius: 0;
        background: transparent;
        font-size: 15px;
        font-weight: 400;
        line-height: 1.5;
        box-shadow: none;
    }

    .repea-search--mobile .wd-find-select .inner-group .repea-kw .form-control::placeholder {
        color: #a3abb0;
    }

    .repea-search--mobile .repea-anim-ph {
        font-size: 15px;
    }

    /* Square filter button on the right of the pill. */
    .repea-search--mobile .box-btn-advanced {
        flex: 0 0 auto;
        gap: 8px;
    }

    .repea-search--mobile .box-btn-advanced .btn-search {
        display: none;
    }

    .repea-search--mobile .box-btn-advanced .box-filter {
        width: auto;
    }

    .repea-search--mobile .wd-find-select .box-btn-advanced .box-filter .filter-advanced {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 52px;
        min-width: 52px;
        height: 52px;
        min-height: 52px;
        padding: 0;
        gap: 0;
        border: 1px solid #e4e4e4;
        border-radius: 14px;
        background: #fff;
        color: #161e2d;
    }

    .repea-search--mobile .wd-find-select .box-btn-advanced .box-filter .filter-advanced .text-1 {
        display: none;
    }

    .repea-search--mobile .wd-find-select .box-btn-advanced .box-filter .filter-advanced .icon {
        font-size: 22px;
    }

    .repea-search--mobile .wd-find-select .box-btn-advanced .box-filter .filter-advanced.active {
        border-color: #161e2d;
    }

    /* Optional: hide the Rent/Sale tabs on mobile (widget control). */
    .repea-search--mobile.repea-search--no-mobile-tabs .nav-tab-form {
        display: none;
    }

    /* Relocated Type/Location inside the filter panel. Because they are no
       longer descendants of `.inner-group`, none of the theme's field rules
       reach them any more — so their pill styling is restated here. */
    .repea-search--mobile .repea-mobile-fields {
        display: grid;
        gap: 14px;
        margin-bottom: 18px;
    }

    .repea-search--mobile .repea-mobile-fields > .form-style {
        width: 100%;
        border-right: 0;
    }

    .repea-search--mobile .repea-mobile-fields label {
        display: block;
        margin-bottom: 8px;
        color: #a3abb0;
        font-weight: 600;
    }

    .repea-search--mobile .repea-mobile-fields .group-ip {
        position: relative;
    }

    .repea-search--mobile .repea-mobile-fields .group-ip .icon {
        position: absolute;
        top: 50%;
        right: 16px;
        transform: translateY(-50%);
        font-size: 18px;
        pointer-events: none;
    }

    .repea-search--mobile .repea-mobile-fields .form-control,
    .repea-search--mobile .repea-mobile-fields select,
    .repea-search--mobile .repea-mobile-fields .nice-select {
        width: 100%;
        padding: 11px 16px;
        border: 1px solid #e4e4e4;
        border-radius: 99px;
        background: #fff;
        font-size: 15px;
        font-weight: 400;
    }

    /* Position/width are intentionally NOT overridden here — the dropdown
       shares `.wd-search-form`'s geometry at every breakpoint by design (see
       the comment above `.repea-results`), including on mobile. Only the
       thumbnail size shrinks to fit the narrower phone layout. */
    .repea-search--mobile .repea-result__thumb {
        width: 46px;
        height: 46px;
    }
}

/* ══════════════════════════════════════════════════════════════════
   5. TWO-COLUMN MOBILE PROPERTY GRID  (≤767px — Screenshot 2)
   ══════════════════════════════════════════════════════════════════ */

/* The inline location line is phone-only; above 768px the card keeps the
   original overlay on the image. Declared here rather than as an inline
   `style` attribute on the element, which would outrank the media query
   below and could never be switched back on. */
.rep-card-location {
    display: none;
}

/* ── BUG FIX: widget grid column count at ALL widths ──────────────────
   `.rep-grid` is `display:flex` with a `gap`, while each card carries a
   Bootstrap `col-md-6`/`col-lg-4` width. Those two are incompatible: two
   50%-wide children plus a 24px gap exceed 100%, so a "Columns: 2" grid
   wrapped to ONE card per row on desktop. (Reproducible on the unmodified
   plugin — it is not a regression from the mobile work.)

   Driving the width from the same `--rep-cols` / `--rep-gap` custom
   properties the mobile layout uses makes the Columns control authoritative
   at every breakpoint and removes the conflict. The Bootstrap classes stay
   on the markup, harmlessly, so nothing else that targets them breaks.

   Fallbacks are written as `var(--x, fallback)` rather than as declarations
   on this selector on purpose: declaring `--rep-cols` here would tie on
   specificity with Elementor's own generated rule and could beat the value
   the editor set, depending on enqueue order. */
.rep-grid.rep-grid--responsive {
    --bs-gutter-x: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--rep-gap, 24px);
    margin-right: 0;
    margin-left: 0;
}

.rep-grid.rep-grid--responsive > [class*="col-"] {
    flex: 0 0 calc((100% - var(--rep-gap, 24px) * (var(--rep-cols, 2) - 1)) / var(--rep-cols, 2));
    max-width: calc((100% - var(--rep-gap, 24px) * (var(--rep-cols, 2) - 1)) / var(--rep-cols, 2));
    min-width: 0;
    padding-right: 0;
    padding-left: 0;
}

@media only screen and (max-width: 767px) {

    /*
     * `.rep-grid.rep-grid--responsive` (the Elementor widget's own grid) and
     * `.rep-property-grid` (the theme's separate, non-Elementor archive and
     * "Similar properties" grids) are split into their own rules below
     * because, as of this fix, they source their column count differently:
     *
     * The widget grid now reads `--rep-cols-mobile` / `--rep-gap-mobile`,
     * written as an inline style by ListingWidgetBase::mobileGridStyle() —
     * NOT the plain `--rep-cols` / `--rep-gap` Elementor's own Columns/Gap
     * responsive controls write via `selectors`. Those ARE still what sets
     * the value on desktop (the base, non-media-query rule above this
     * block); the problem is specifically a mobile one: `--rep-cols` is an
     * inheriting custom property, and if Elementor's mobile-tier CSS for a
     * given widget instance is for any reason not generated (caching, a
     * regeneration lag, a version quirk — something this plugin can't
     * control or verify), mobile does not fall back to this stylesheet's
     * `var(--rep-cols, 2)` default; a `var()` fallback only ever applies
     * when a property is undefined, never when it's merely INHERITED from a
     * wider breakpoint. It would instead silently inherit the DESKTOP
     * column count — 4 tiny columns squeezed into a phone screen, if that's
     * what Desktop Columns was set to, which reads exactly as "squashed,
     * tiny thumbnails." Reading the value directly in PHP and writing it as
     * an inline style sidesteps that dependency entirely, at the one
     * breakpoint where it mattered.
     *
     * The theme's own `.rep-property-grid` was never affected by that: it
     * predates this plugin, has no Elementor control behind it, and never
     * had `--rep-cols` / `--rep-gap` set by anything — `var(..., fallback)`
     * has always been the only value in play for it, unchanged here.
     */
    .rep-grid.rep-grid--responsive {
        --bs-gutter-x: 0;
        display: flex;
        flex-wrap: wrap;
        gap: var(--rep-gap-mobile, 12px);
        margin-right: 0;
        margin-left: 0;
    }

    .rep-grid.rep-grid--responsive > [class*="col-"] {
        flex: 0 0 calc((100% - var(--rep-gap-mobile, 12px) * (var(--rep-cols-mobile, 2) - 1)) / var(--rep-cols-mobile, 2));
        max-width: calc((100% - var(--rep-gap-mobile, 12px) * (var(--rep-cols-mobile, 2) - 1)) / var(--rep-cols-mobile, 2));
        min-width: 0;
        padding-right: 0;
        padding-left: 0;
    }

    /* Bootstrap's gutter is zeroed so that spacing is controlled solely by
       `gap` — otherwise cards would sit 12px padding + gap apart and two
       columns would not fit comfortably on a 360px screen. */
    .rep-property-grid:not(.rep-list-layout) {
        --bs-gutter-x: 0;
        display: flex;
        flex-wrap: wrap;
        gap: var(--rep-gap, 12px);
        margin-right: 0;
        margin-left: 0;
    }

    .rep-property-grid:not(.rep-list-layout) > [class*="col-"] {
        flex: 0 0 calc((100% - var(--rep-gap, 12px) * (var(--rep-cols, 2) - 1)) / var(--rep-cols, 2));
        max-width: calc((100% - var(--rep-gap, 12px) * (var(--rep-cols, 2) - 1)) / var(--rep-cols, 2));
        min-width: 0;
        padding-right: 0;
        padding-left: 0;
    }

    /* ── Card proportions at half width ───────────────────────────── */

    .rep-grid--responsive .homelengo-box,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box {
        height: 100%;
        display: flex;
        flex-direction: column;
        border-radius: 14px;
        overflow: hidden;
    }

    .rep-grid--responsive .homelengo-box .images-style img,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .images-style img {
        width: 100%;
        height: auto;
        aspect-ratio: 4 / 3;
        object-fit: cover;
        display: block;
    }

    .rep-grid--responsive .homelengo-box .archive-bottom,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .archive-bottom {
        flex: 1 1 auto;
        display: flex;
        flex-direction: column;
        padding: 12px;
    }

    /* Two-line clamp: long titles grow downwards instead of pushing the
       price out of the card or forcing a mid-word break. */
    .rep-grid--responsive .homelengo-box .content-top h6,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .content-top h6 {
        margin-bottom: 6px;
        font-size: 14px;
        line-height: 1.35;
    }

    .rep-grid--responsive .homelengo-box .content-top h6 .link,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .content-top h6 .link {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        overflow-wrap: anywhere;
        white-space: normal;
    }

    .rep-grid--responsive .homelengo-box .flag-tag,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .flag-tag {
        padding: 3px 9px;
        font-size: 11px;
    }

    /* The location line that normally sits over the image is swapped for an
       inline one under the title — at half width the overlay is unreadable
       and it is the layout shown in the reference screenshot. */
    .rep-grid--responsive .rep-card-location,
    .rep-property-grid:not(.rep-list-layout) .rep-card-location {
        display: flex;
        align-items: center;
        gap: 5px;
        min-width: 0;
        margin-bottom: 8px;
        color: #a3abb0;
        font-size: 12px;
        line-height: 1.4;
    }

    .rep-grid--responsive .rep-card-location span,
    .rep-property-grid:not(.rep-list-layout) .rep-card-location span {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }

    .rep-grid--responsive .rep-card-location svg,
    .rep-property-grid:not(.rep-list-layout) .rep-card-location svg {
        flex: 0 0 auto;
    }

    .rep-grid--responsive .homelengo-box .archive-top .bottom,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .archive-top .bottom {
        display: none;
    }

    /* The theme paints a dark gradient over the foot of the image purely so
       that white overlay text stays legible. With that text moved below the
       image, the gradient is left darkening the photo for no reason — so it
       goes too. */
    .rep-grid--responsive .homelengo-box .images-group::after,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .images-group::after {
        display: none;
    }

    .rep-grid--responsive .homelengo-box .price,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .price {
        margin: 0;
        font-size: 14px;
        line-height: 1.3;
        overflow-wrap: anywhere;
    }

    .rep-grid--responsive .homelengo-box .content-bottom,
    .rep-property-grid:not(.rep-list-layout) .homelengo-box .content-bottom {
        margin-top: auto;
        padding-top: 8px;
    }

    /* ── Compact variant (default) ─────────────────────────────────
       Drops the beds/baths/sqft row and the agent byline, which cannot be
       read at half width, leaving title → location → price as in the
       reference screenshot. Turn off via the widget's "Mobile Card Style"
       control (or the `rep-mobile-compact` class) to keep them. */
    .rep-grid--responsive.rep-mobile-compact .homelengo-box .meta-list,
    .rep-property-grid.rep-mobile-compact:not(.rep-list-layout) .homelengo-box .meta-list {
        display: none;
    }

    .rep-grid--responsive.rep-mobile-compact .homelengo-box .content-bottom > .d-flex,
    .rep-property-grid.rep-mobile-compact:not(.rep-list-layout) .homelengo-box .content-bottom > .d-flex {
        display: none !important; /* overrides Bootstrap's own `.d-flex` utility, which is equally specific */
    }

    .rep-grid--responsive.rep-mobile-compact .homelengo-box .content-bottom,
    .rep-property-grid.rep-mobile-compact:not(.rep-list-layout) .homelengo-box .content-bottom {
        display: block;
        border-top: 0;
        padding-top: 0;
    }

    /* With the meta row hidden, the theme's divider under `.content-top` has
       nothing left to divide — it would just float between the location and
       the price. */
    .rep-grid--responsive.rep-mobile-compact .homelengo-box .content-top,
    .rep-property-grid.rep-mobile-compact:not(.rep-list-layout) .homelengo-box .content-top {
        margin-bottom: 0;
        padding-bottom: 0;
        border-bottom: 0;
    }

    .rep-grid--responsive.rep-mobile-compact .rep-card-location,
    .rep-property-grid.rep-mobile-compact:not(.rep-list-layout) .rep-card-location {
        margin-bottom: 10px;
    }

    /* ── Non-compact variant ───────────────────────────────────────
       Keeps the meta row but lets it wrap and shrinks the agent avatar. */
    .rep-grid--responsive:not(.rep-mobile-compact) .homelengo-box .meta-list,
    .rep-property-grid:not(.rep-mobile-compact):not(.rep-list-layout) .homelengo-box .meta-list {
        flex-wrap: wrap;
        gap: 4px 10px;
        margin: 4px 0 8px;
        font-size: 11px;
    }

    .rep-grid--responsive:not(.rep-mobile-compact) .homelengo-box .content-bottom,
    .rep-property-grid:not(.rep-mobile-compact):not(.rep-list-layout) .homelengo-box .content-bottom {
        flex-wrap: wrap;
        gap: 6px;
        font-size: 12px;
    }

    .rep-grid--responsive:not(.rep-mobile-compact) .homelengo-box .avatar.avt-40,
    .rep-property-grid:not(.rep-mobile-compact):not(.rep-list-layout) .homelengo-box .avatar.avt-40 {
        width: 26px;
        height: 26px;
    }
}

/* Very narrow phones (≤360px): one card per row reads better than two
   ~150px-wide ones. Opt out with the `rep-keep-2-col` class. */
@media only screen and (max-width: 360px) {
    /*
     * `!important` is required here specifically because the widget grid's
     * column count is now set via an INLINE style
     * (ListingWidgetBase::mobileGridStyle()) rather than a stylesheet rule —
     * see the block above. An inline style always wins over any stylesheet
     * declaration regardless of selector specificity or source order, so
     * without `!important` this override would silently do nothing on very
     * small phones. The theme's own `.rep-property-grid`, which has no
     * inline style to out-rank, doesn't need it and doesn't get it, keeping
     * `!important` scoped to the one selector that actually requires it.
     */
    .rep-grid.rep-grid--responsive:not(.rep-keep-2-col) {
        --rep-cols-mobile: 1 !important;
    }

    .rep-property-grid:not(.rep-list-layout):not(.rep-keep-2-col) {
        --rep-cols: 1;
    }
}

/* ══════════════════════════════════════════════════════════════════
   6. MOBILE LIST-VIEW LAYOUT — compact horizontal row
   ══════════════════════════════════════════════════════════════════ */

/**
 * Scoped to `.rep-list` — the wrapper the Elementor listing widgets (Property,
 * Agent, Agency, Hotel, Handyman) use for their own "List" layout setting.
 * Deliberately NOT touching `.rep-list-layout`, the theme's own unrelated
 * class for its property archive page's List/Grid toggle — that page's own
 * behaviour is untouched by anything below.
 *
 * WHY THIS OVERRIDE EXISTS: below 576px the theme's own CSS
 * (`.homelengo-box.list-style-1 { display: block; }`) intentionally reverts
 * a list card to a full stacked layout — sensible for the theme's own
 * archive page, but for this widget it meant "List" and "Grid" became
 * visually indistinguishable on a phone: full-width image on top, content
 * stacked below, exactly like a single-column grid card. Below overrides
 * that specifically for `.rep-list` with a compact horizontal row (small
 * thumbnail + stacked text, side by side) — the layout an actual "list
 * view" implies — while leaving the theme's own ≥768px horizontal split
 * alone entirely (nothing here applies above 767px).
 *
 * SPECIFICITY NOTE: every selector below repeats `.homelengo-box.list-style-1`
 * (3 classes deep, one more than the theme's own `.homelengo-box.list-style-1
 * .archive-top` rules) specifically so these win on specificity regardless of
 * stylesheet load order, matching this file's usual approach — no
 * `!important` needed.
 */
@media only screen and (max-width: 767px) {
    .rep-list .homelengo-box.list-style-1 {
        display: flex;
        flex-direction: row;
        /* Was `stretch`: with `.meta-list` now shown (see below), the
           content column can run taller than a single title line, and
           stretching a 96px-wide thumbnail to match would draw a tall,
           narrow strip rather than a photo. `flex-start` keeps the
           thumbnail a fixed, proportionate square regardless of how tall
           the text beside it grows. */
        align-items: flex-start;
        gap: 12px;
        padding: 10px;
        border-radius: 14px;
    }

    .rep-list .homelengo-box.list-style-1 .archive-top {
        width: 96px;
        height: 96px;
        flex: 0 0 96px;
    }

    .rep-list .homelengo-box.list-style-1 .images-group,
    .rep-list .homelengo-box.list-style-1 .images-style {
        height: 100%;
    }

    .rep-list .homelengo-box.list-style-1 .images-style img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        border-radius: 10px;
    }

    /* The badge row and image-overlay location line both assume a full-size
       photo; at 96px square neither is legible, so both are dropped in
       favour of the inline location line already rendered below the title
       (`.archive-bottom .location`, present whenever `$layout === 'list'` —
       see PropertyWidget/HotelWidget/etc. renderCard()). */
    .rep-list .homelengo-box.list-style-1 .archive-top .top,
    .rep-list .homelengo-box.list-style-1 .archive-top .bottom {
        display: none;
    }

    .rep-list .homelengo-box.list-style-1 .archive-bottom {
        display: flex;
        flex: 1 1 auto;
        flex-direction: column;
        justify-content: flex-start;
        min-width: 0;
        padding: 2px 0;
    }

    /* `.content-top`'s divider (24px padding + 24px margin + a border) is
       sized for the theme's spacious desktop list row — at this width it
       reads as a gap, not a divider, so it's dropped rather than shrunk;
       the container's own 12px gap already separates the thumbnail from the
       text column clearly enough, and the rows of text below use their own
       small margins to separate themselves from each other. */
    .rep-list .homelengo-box.list-style-1 .content-top {
        padding-bottom: 0;
        margin-bottom: 0;
        border-bottom: 0;
    }

    .rep-list .homelengo-box.list-style-1 .archive-bottom .location {
        margin-top: 4px;
    }

    .rep-list .homelengo-box.list-style-1 .content-top h6 {
        margin-bottom: 2px;
        font-size: 14px;
        line-height: 1.35;
    }

    .rep-list .homelengo-box.list-style-1 .content-top h6 .link {
        display: -webkit-box;
        -webkit-line-clamp: 1;
        line-clamp: 1;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    /*
     * Previously hidden outright as "too much detail for a compact row" —
     * restored per explicit request: rating, check-in, beds/baths/sqft etc.
     * are meaningful listing details visitors expect List view to show, the
     * same as desktop already does. Shrunk (smaller gap, font, icon) rather
     * than hidden, and left `flex-wrap: wrap` (the theme's own default for
     * this element) so 2–3 items still fit legibly in a ~240px-wide content
     * column without needing to hide any of them. Property's own list-mode
     * location line (`.content-top .location`, rendered only when
     * $layout === 'list') sits just below it; Hotel has no equivalent here,
     * its location lives in `.content-bottom` instead, handled below.
     */
    .rep-list .homelengo-box.list-style-1 .meta-list {
        margin-top: 4px;
        gap: 4px 10px;
        font-size: 11px;
    }

    .rep-list .homelengo-box.list-style-1 .meta-list .item .icon {
        font-size: 12px;
    }

    .rep-list .homelengo-box.list-style-1 .content-top .location {
        display: flex;
        align-items: center;
        gap: 5px;
        margin-bottom: 0;
        color: #a3abb0;
        font-size: 12px;
    }

    .rep-list .homelengo-box.list-style-1 .content-top .location span {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }

    /*
     * `.content-bottom`'s first child differs by widget: Property puts the
     * agent avatar + name there, Hotel puts a location icon + address —
     * different enough that hiding one specifically (rather than sizing
     * both down generically) would need distinguishing the two structurally,
     * which plain CSS can't do here without `:has()` (unsupported on older
     * mobile Safari — avoided everywhere in this file for that reason, see
     * the search-widget rules above). Sized down and allowed to wrap
     * instead: correct either way, and an agent's name in a compact row is
     * a defensible, not a broken, list view.
     */
    .rep-list .homelengo-box.list-style-1 .content-bottom {
        flex-wrap: wrap;
        gap: 4px 10px;
        margin-top: 8px;
        padding-top: 0;
        border-top: 0;
        font-size: 12px;
    }

    .rep-list .homelengo-box.list-style-1 .content-bottom .avatar.avt-40 {
        width: 20px;
        height: 20px;
    }

    .rep-list .homelengo-box.list-style-1 .price {
        margin: 0;
        font-size: 13px;
    }
}

/* ══════════════════════════════════════════════════════════════════
   7. FAVORITE ("HEART") BUTTON — property grid cards
   ══════════════════════════════════════════════════════════════════ */

/* `.images-group` (the <a> wrapping the photo) already establishes
   `position: relative` for the theme's own badge/location overlays.
   `.archive-top` itself does not — added here, scoped to this selector only,
   so the heart (a SIBLING of that <a>, not a descendant — see
   PropertyWidget::renderCard() for why) can anchor to the same visual box
   without touching how the existing overlays position themselves. A bare
   `position: relative` with no offsets changes nothing else about the
   element's layout. */
.homelengo-box .archive-top {
    position: relative;
}

.repea-favorite-toggle {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .92);
    color: #161e2d;
    cursor: pointer;
    box-shadow: 0 2px 6px rgba(22, 30, 45, .12);
    transition: transform .15s ease, color .15s ease;
}

.repea-favorite-toggle:hover {
    transform: scale(1.08);
}

.repea-favorite-toggle svg path {
    transition: fill .15s ease, stroke .15s ease;
}

/* Filled red heart once favourited — either from the start (server-rendered
   initial state, see rep_property_is_favorited in the theme) or the instant
   a toggle click succeeds (rep-favorites.js). */
.repea-favorite-toggle.is-active {
    color: #e63946;
}

.repea-favorite-toggle.is-active svg path {
    fill: #e63946;
    stroke: #e63946;
}

.repea-favorite-toggle.is-loading {
    cursor: default;
    opacity: .6;
}

.repea-favorite-toggle.is-loading:hover {
    transform: none;
}

/* ══════════════════════════════════════════════════════════════════
   8. SKELETON LOADING — async listing widgets
   ══════════════════════════════════════════════════════════════════ */

/* The skeleton grid reuses the SAME grid classes (.rep-grid, --rep-cols,
   --rep-gap, .rep-grid--responsive, .rep-mobile-compact) the real content
   renders with — see ListingWidgetBase::gridClass(), shared by both
   renderSkeleton() and renderListingHtml() specifically so the column count
   and spacing are identical from the very first paint, and swapping the
   skeleton for real content causes no layout shift. */

.repea-listing[aria-busy="true"] {
    min-height: 120px;
}

.repea-skeleton-col {
    margin-bottom: var(--rep-gap, 24px);
}

/**
 * Belt-and-suspenders fix for a "tiny, squashed thumbnail" report that
 * persisted after the `--rep-cols-mobile` inline-style fix elsewhere in this
 * plugin (see ListingWidgetBase::mobileGridStyle()). That fix relies on TWO
 * things holding at once: the `[class*="col-"]` attribute selector matching
 * this element (it does — `renderSkeletonCard()` always includes a Bootstrap
 * `col-*` class), and nothing else on the page out-specificity-ing or
 * out-ordering the rule that reads the custom property. Both SHOULD hold,
 * but neither is something this plugin can fully guarantee on every theme
 * and page-builder combination it might run inside.
 *
 * This rule removes both of those as points of failure for the skeleton
 * specifically: it targets `.repea-skeleton-col` by its own class rather
 * than the generic attribute selector, and uses `!important` so nothing
 * else can out-rank it regardless of specificity or stylesheet order. The
 * skeleton is entirely this plugin's own markup with no real card content
 * inside it and no theme styling depending on it, so there is no
 * legitimate competing rule an `!important` here could ever wrongly
 * override — a guarantee the equivalent rule for REAL card columns
 * (further up this file) deliberately does not make, since real cards
 * carry theme markup this plugin doesn't fully control.
 */
@media only screen and (max-width: 767px) {
    /* Scoped to `.rep-grid.rep-grid--responsive` specifically — `.repea-
       skeleton-col` is shared with the Carousel skeleton track further down
       this file, which sizes itself completely differently (a fixed
       280px-wide slide, not a `--rep-cols`-based grid column) and must not
       be caught by this `!important` override. */
    .rep-grid.rep-grid--responsive .repea-skeleton-col {
        flex: 0 0 calc((100% - var(--rep-gap-mobile, 12px) * (var(--rep-cols-mobile, 2) - 1)) / var(--rep-cols-mobile, 2)) !important;
        max-width: calc((100% - var(--rep-gap-mobile, 12px) * (var(--rep-cols-mobile, 2) - 1)) / var(--rep-cols-mobile, 2)) !important;
        min-width: 0 !important;
        margin-bottom: var(--rep-gap-mobile, 12px) !important;
    }
}

.repea-skeleton-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    border-radius: 16px;
    background: #fff;
}

/**
 * List-layout skeleton, sized to match the REAL list card
 * (.homelengo-box.list-style-1/2) it stands in for — measured at roughly a
 * 35/65 image/content split and ~350px tall on desktop. The previous
 * 160×160px fixed thumbnail bore no relation to that and read as visibly
 * squeezed/broken next to actual content once it loaded.
 */
.repea-skeleton-card--list {
    flex-direction: row;
    min-height: 220px;
}

.repea-skeleton-media {
    aspect-ratio: 4 / 3;
    width: 100%;
    background: #eceff2;
}

.repea-skeleton-card--list .repea-skeleton-media {
    aspect-ratio: auto;
    width: 36%;
    flex: 0 0 36%;
    align-self: stretch;
}

.repea-skeleton-card--list .repea-skeleton-body {
    justify-content: space-between;
    padding: 20px;
}

.repea-skeleton-body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 10px;
    padding: 16px;
}

.repea-skeleton-line {
    height: 12px;
    border-radius: 6px;
    background: #eceff2;
}

.repea-skeleton-line--title {
    width: 80%;
    height: 16px;
}

.repea-skeleton-line--sub {
    width: 55%;
}

.repea-skeleton-line--price {
    width: 40%;
    margin-top: auto;
}

/**
 * Below 767px, real `.rep-list` content switches to the compact horizontal
 * row defined in section 6 above (96px square thumbnail, single row). The
 * desktop list skeleton's 36%-width media block doesn't match that shape —
 * without this override the skeleton would show one (wide, short) proportion
 * and then jump to a visibly different (narrow, square) one the instant real
 * content loads. Matches section 6's dimensions exactly.
 */
@media only screen and (max-width: 767px) {
    .repea-skeleton-card--list {
        min-height: 96px;
        gap: 12px;
        padding: 10px;
        border-radius: 14px;
    }

    .repea-skeleton-card--list .repea-skeleton-media {
        width: 96px;
        height: 96px;
        flex: 0 0 96px;
        border-radius: 10px;
    }

    .repea-skeleton-card--list .repea-skeleton-body {
        gap: 8px;
        padding: 2px 0;
    }
}

/* Carousel skeleton: a static row of cards roughly matching Swiper's own
   "several partial slides" look, since Swiper itself never initialises on a
   placeholder that's about to be discarded. */
.repea-skeleton-track {
    display: flex;
    gap: 24px;
    overflow: hidden;
}

.repea-skeleton-track .repea-skeleton-col {
    flex: 0 0 280px;
    margin-bottom: 0;
}

/* Shimmer sweep. `prefers-reduced-motion` gets a plain static block instead
   of motion — still clearly a placeholder, just not an animated one. */
@media (prefers-reduced-motion: no-preference) {
    .repea-skeleton-media,
    .repea-skeleton-line {
        position: relative;
        overflow: hidden;
    }

    .repea-skeleton-media::after,
    .repea-skeleton-line::after {
        position: absolute;
        inset: 0;
        content: "";
        background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, .55) 50%, rgba(255, 255, 255, 0) 100%);
        animation: repea-shimmer 1.6s ease-in-out infinite;
        transform: translateX(-100%);
    }
}

@keyframes repea-shimmer {
    100% {
        transform: translateX(100%);
    }
}

/* Error fallback after a failed fetch (see rep-listing-loader.js). Reuses
   `.rep-empty`, the theme's own existing "no results" message style, so it
   never introduces a visual style nothing else on the site already has. */
.repea-listing--error {
    min-height: 0;
}

/* ══════════════════════════════════════════════════════════════════
   9. MOBILE TITLE CHARACTER LIMIT
   ══════════════════════════════════════════════════════════════════ */

/**
 * ListingWidgetBase::titleMarkup() only emits these two spans at all when a
 * limit is actually set AND the title exceeds it — the common case (no
 * limit, or a short title) is a single plain string with none of this
 * markup, so most cards never pay for this toggle at all. Desktop-first:
 * `.repea-title-mobile` stays out of the layout above 767px by default,
 * `.repea-title-full` is what's hidden below it. Applies uniformly across
 * Grid, List and Carousel — none of the five listing widgets' title markup
 * needs its own copy of this rule.
 */
.repea-title-mobile {
    display: none;
}

@media only screen and (max-width: 767px) {
    .repea-title-full {
        display: none;
    }

    .repea-title-mobile {
        display: inline;
    }
}
