/**
 * listing-card.css — THE single source of listing-card + card-slider styling.
 *
 * Used by every context (homepage sliders, category page, search, nearby, recommended, featured,
 * popular, vendor, related). Page stylesheets (home.css / category-page.css / search-page.css) must
 * NOT redefine card visuals — only page-specific layout may live there.
 */

/* ── Card slider (native scroll-snap — the project's production slider) ── */
.lbai-slider {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 4px 12px 12px 4px;   /* trailing padding lets the next card peek cleanly */
    scroll-padding-left: 4px;
    margin: 0;
    max-width: 100%;
}
.lbai-slider::-webkit-scrollbar { display: none; }

/* ── Card ── */
.lbai-card {
    /* CONTAINER-RELATIVE width => a CONSISTENT "one full card + ~40-50% of the next card" at every
       mobile viewport (320/360/375/390/412/428/480). The basis is a percentage of the SLIDER's
       content box (not the viewport), so section/page padding can no longer shift the ratio the way
       the old `vw` clamp did. ~66% leaves ~45% of the next card visible across the whole range.
       The >=768px rule below overrides the basis with a fixed multi-card width for desktop. */
    flex: 0 0 66%;
    max-width: 66%;
    scroll-snap-align: start;
    scroll-snap-stop: always;     /* mobile: one card per swipe (relaxed to `normal` on desktop below) */
    scroll-margin-left: 4px;      /* keyboard focus / programmatic scroll lands cleanly at the rail start */
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 14px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    box-shadow: 0 2px 10px rgba(15, 23, 42, 0.06);
    transition: box-shadow .2s ease, transform .2s ease;
    box-sizing: border-box;
}
.lbai-card:hover { box-shadow: 0 10px 26px rgba(15, 23, 42, 0.10); transform: translateY(-2px); }

/* Media */
.lbai-card__media { position: relative; height: 112px; background: #e2e8f0; }
.lbai-card__media-link { display: block; width: 100%; height: 100%; }
.lbai-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.lbai-card__badges { position: absolute; top: 8px; left: 8px; display: flex; gap: 6px; flex-wrap: wrap; }
.lbai-card__badge {
    font-size: 10px; font-weight: 800; letter-spacing: .3px; text-transform: uppercase;
    padding: 3px 8px; border-radius: 999px; color: #fff; background: var(--primary-color, #6366f1); line-height: 1.4;
}
.lbai-card__badge.is-premium  { background: var(--secondary-color, #7c3aed); }
.lbai-card__badge.is-sponsored{ background: var(--accent-color, #0ea5e9); }
.lbai-card__badge.is-open     { background: var(--success-color, #16a34a); }
.lbai-card__badge.is-closed   { background: var(--muted-color, #6b7280); }

.lbai-card__fav {
    position: absolute; top: 8px; right: 8px; width: 32px; height: 32px; border: none; cursor: pointer;
    border-radius: 50%; background: rgba(255,255,255,.92); box-shadow: 0 1px 3px rgba(0,0,0,.10);
    font-size: 15px; line-height: 32px; text-align: center; padding: 0;
}

/* Body */
.lbai-card__body { padding: 12px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.lbai-card__cat { font-size: 11px; font-weight: 700; color: var(--primary-color, #6366f1); text-transform: uppercase; letter-spacing: .3px; }
.lbai-card__title-link { text-decoration: none; color: inherit; }
.lbai-card__title {
    margin: 0; font-size: 15px; font-weight: 800; color: #0f172a; line-height: 1.3;
    display: flex; flex-wrap: wrap; align-items: center; column-gap: 6px; row-gap: 3px; min-width: 0;   /* [Title][ticks] on line 1; business badges wrap to line 2 */
}
.lbai-card__title-text { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Shared Progress / Score component — the ONE progress bar used by Trust Score, Visibility,
   and any future 0–100 metric (rendered via LBAI_Listing_Card::score_bar()). No duplicate
   progress implementations anywhere. Fill width ALWAYS equals the real percentage (inline
   --ail-fill); the animation only grows it from 0 → that width on paint. Pure CSS, no JS,
   AJAX-safe, reduced-motion aware. */
.ail-score { flex: 1; min-width: 0; }
.ail-score__top { display: flex; justify-content: space-between; font-size: 11px; font-weight: 700; margin-bottom: 4px; }
.ail-score__lbl { color: var(--s-text-2, #6b7280); }
.ail-score__val { color: var(--s-text, #1f2937); }
.ail-score__track { height: 6px; background: #eef0f5; border-radius: 4px; overflow: hidden; }
.ail-score__fill {
    height: 100%;
    width: var(--ail-fill, 0%);          /* real percentage — the resting/true width */
    border-radius: 4px;
    transform-origin: left center;
    animation: ail-score-fill 900ms ease-out both;   /* grow 0 → real width on paint */
}
.ail-score__fill.trust { background: var(--s-green, #16a34a); }
.ail-score__fill.vis   { background: var(--s-primary, #6C3BFF); }
@keyframes ail-score-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) {
    .ail-score__fill { animation: none; }   /* falls back to the true width (var(--ail-fill)) */
}

.lbai-card__rating { display: flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 700; color: #0f172a; }
.lbai-card__stars { color: var(--rating-color, #f59e0b); display: inline-flex; }
.lbai-card__stars svg { width: 15px; height: 15px; fill: var(--rating-color, #f59e0b); stroke: var(--rating-color, #f59e0b); }
.lbai-card__reviews { color: #64748b; font-weight: 600; }

.lbai-card__loc { display: flex; align-items: center; gap: 4px; font-size: 12px; color: #64748b; min-width: 0; }
.lbai-card__loc svg { width: 13px; height: 13px; flex: 0 0 auto; }
.lbai-card__loc span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.lbai-card__actions { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.lbai-card__ic {
    width: 36px; height: 36px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center;
    color: #fff; flex: 0 0 auto; text-decoration: none;
    border: 0; padding: 0; cursor: pointer; font: inherit;   /* normalize the guest <button> variant to match the <a> */
}
.lbai-card__ic svg { width: 17px; height: 17px; }
.lbai-card__ic.is-call { background: var(--success-color, #16a34a); }
.lbai-card__ic.is-wa   { background: var(--whatsapp-color, #22c55e); }
.lbai-card__cta {
    flex: 1 1 auto; text-align: center; text-decoration: none; font-weight: 800; font-size: 13px;
    padding: 9px 12px; border-radius: 10px; background: var(--button-bg, #6366f1); color: var(--button-text, #fff); white-space: nowrap;
}
.lbai-card__cta:hover { background: var(--button-hover, #4f46e5); }

/* ── Tablet / desktop: fixed card width, multi-card rows (same component) ── */
@media (min-width: 768px) {
    .lbai-slider {
        gap: 16px;
        /* Trailing gutter (right = start gutter) lets the LAST card rest flush at the rail's right
           edge with no excess empty space; scrollWidth stays correct. */
        padding: 4px 16px 14px 4px;
        /* PROXIMITY (not mandatory): the browser no longer force-snaps away from the end, so the
           final card is always fully reachable — the permanent fix for the "last card clipped" bug.
           Keeps snap feel for wheel/trackpad while preserving keyboard/focus navigation. */
        scroll-snap-type: x proximity;
    }
    .lbai-card {
        flex: 0 0 260px;          /* override the mobile % basis with a fixed desktop width */
        max-width: 260px;
        scroll-snap-stop: normal; /* desktop: allow multi-card scroll (no forced one-per-swipe) */
    }
    .lbai-card__media { height: 115px; }
}

/* ── Guest Action Guard: immediate visual feedback (never a dead click) ── */
[data-requires-login].is-guard-pressed {
    transform: scale(0.94);
    opacity: 0.7;
    transition: transform 0.1s ease, opacity 0.1s ease;
}
[data-requires-login][aria-busy="true"] { pointer-events: none; }

/* ── Resume-after-login: briefly highlight the card whose action is being resumed ── */
.lbai-card.lbai-resume-highlight {
    outline: 2px solid #6366f1;
    outline-offset: 2px;
    transition: outline-color 0.3s ease;
}

/* ── Respect reduced-motion for programmatic smooth scrolling ── */
@media (prefers-reduced-motion: reduce) {
    .lbai-slider { scroll-behavior: auto; }
    [data-requires-login].is-guard-pressed { transition: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   SHARED BADGE RENDERER — LBAI_Listing_Card::badges()
   ONE primary badge after the title + "+N More" that expands to a popover (desktop) or a bottom
   sheet (mobile). Identical output on every surface. .lbai-badges is flex:0 0 auto wherever it is
   placed, so it never pushes, overlaps, hides or clips the title (title-priority).
   ══════════════════════════════════════════════════════════════════════════ */
/* Title ticks — green/blue verification indicators shown INLINE beside the title (icon-only, so the
   two "Verified"-labelled ticks can never read as duplicate text). */
.lbai-badges__ticks { display: inline-flex; align-items: center; gap: 3px; flex: 0 0 auto; }
.lbai-tick { display: inline-flex; align-items: center; }
.lbai-tick svg { width: 1.05em; height: 1.05em; display: block; }
.lbai-tick--green_tick { color: #00B14F; }
.lbai-tick--blue_tick  { color: #1DA1F2; }

/* Business badge cluster — sits on its OWN row beneath the title (Title -> Primary -> +More). */
.lbai-badges { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; flex: 0 0 100%; line-height: 1; margin-top: 3px; }
.lbai-badges__primary { display: inline-flex; align-items: center; }
.lbai-badge { display: inline-flex; align-items: center; gap: 4px; color: var(--lbai-badge-color, #64748b); max-width: 100%; }
.lbai-badge__icon { width: 1.05em; height: 1.05em; flex: 0 0 auto; display: block; }
.lbai-badge__label { font-size: 12px; font-weight: 700; color: #334155; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The badge cluster sits on its OWN row beneath the title (Title -> Primary -> +More), so the
   primary badge always shows its full label and never competes with the title for width. */

/* "+N More" pill */
.lbai-badges__more {
    display: inline-flex; align-items: center; gap: 3px; flex: 0 0 auto;
    font-family: inherit; font-size: 11px; font-weight: 800; line-height: 1; white-space: nowrap;
    padding: 3px 8px; border-radius: 999px; cursor: pointer;
    color: #475569; background: #f1f5f9; border: 1px solid #e2e8f0;
}
.lbai-badges__more:hover { background: #e2e8f0; }
.lbai-badges__more:focus-visible { outline: 2px solid var(--primary-color, #6366f1); outline-offset: 1px; }

/* Expand panel — position:fixed so the card's overflow:hidden can never clip it. badges.js positions
   it beneath the trigger on desktop; the media query turns it into a bottom sheet on mobile. */
.lbai-badges__panel {
    position: fixed; z-index: 100000; width: 260px; max-width: calc(100vw - 24px);
    padding: 12px; background: #fff; border: 1px solid #e5e7eb; border-radius: 12px;
    box-shadow: 0 14px 40px rgba(15, 23, 42, .18);
    opacity: 0; transform: translateY(-6px); transition: opacity .18s ease, transform .18s ease;
}
.lbai-badges.is-open .lbai-badges__panel,
.lbai-badges__panel.is-open { opacity: 1; transform: translateY(0); }
.lbai-badges__panel[hidden] { display: none; }
.lbai-badges__panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 12px; font-weight: 800; color: #0f172a; text-transform: uppercase; letter-spacing: .3px; margin-bottom: 10px; }
.lbai-badges__close { border: 0; background: transparent; font-size: 20px; line-height: 1; cursor: pointer; color: #94a3b8; padding: 0 2px; }
.lbai-badges__close:hover { color: #0f172a; }
.lbai-badges__list { display: flex; flex-direction: column; gap: 10px; }
.lbai-badges__item { display: flex; }
.lbai-badges__item .lbai-badge { font-size: 14px; }
.lbai-badges__item .lbai-badge__label { font-size: 13px; font-weight: 700; white-space: normal; }

/* Mobile: bottom sheet + backdrop; keep cards ultra-compact (primary = icon only, labels in panel). */
@media (max-width: 768px) {
    .lbai-badges__panel {
        position: fixed; left: 0; right: 0; bottom: 0; top: auto !important; width: 100%; max-width: none;
        border-radius: 16px 16px 0 0; padding: 16px 18px calc(18px + env(safe-area-inset-bottom, 0px));
        transform: translateY(100%); box-shadow: 0 -14px 40px rgba(15, 23, 42, .24);
    }
    .lbai-badges.is-open .lbai-badges__panel,
    .lbai-badges__panel.is-open { transform: translateY(0); }
    .lbai-badges.is-open::after {
        content: ""; position: fixed; inset: 0; z-index: 99999; background: rgba(15, 23, 42, .45);
    }
    .lbai-badges__list { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
}
html.lbai-badges-lock, html.lbai-badges-lock body { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
    .lbai-badges__panel { transition: none; }
}

/* Single-listing hero: the badge row sits on its own line beneath the H1 (Title -> Primary -> +More). */
.lbai-badges--single { margin-top: 8px; }
.lbai-badges--single .lbai-badge__label { font-size: 13px; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   RC1 UI HOTFIX — WAVE 1
   Every RC1 UI Polish rule for this stylesheet lives in this one section, after the original
   badge rules, so the base component above is left exactly as it was and this section is the
   only place to look for the hotfix. Presentation only: no badge eligibility, priority,
   permission or data path is touched — those live in LPCF and LBAI_Listing_Card::badges().

   ISSUE 2 — Badge popup mobile behaviour.

   PASS 1 (this block): positioning, edges, max-height, overflow, scrolling, touch spacing and
   badge wrapping only, as instructed. Portaling is NOT used here; it is applied separately in
   badges.js only because the measurement below proves pass 1 cannot be sufficient on its own.

   Defects these rules remove:
     1. badges.js writes inline left/top for the desktop popover and nothing cleared them, so a
        stale inline left survived a breakpoint change and beat the sheet's own left:0, pushing
        it off-screen. Forced here and also cleared in badges.js.
     2. the panel had no max-height and the list had no overflow, so a tall badge grid grew
        upward past the top of the viewport and carried the head — and the close button — out
        of reach. The panel is now a bounded flex column: the head is fixed, the list scrolls.
     3. grid-template-columns:1fr 1fr with default min-width:auto let a long label force its
        track wider than its share, overflowing the grid horizontally at 320px.
     4. the close control computed to roughly 13x20px, far below a 44x44 touch target.
     5. the backdrop was generated from .lbai-badges, which sits inside the card and inside the
        slider; it is now generated from <html>, which is never transformed.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

@media (max-width: 768px) {

    /* ── Positioning: pin the sheet to three viewport edges ───────────────────────────────
       left/right are forced because an inline left from the desktop popover would otherwise
       win the cascade. top is already forced by the base rule and is kept that way. */
    .lbai-badges__panel {
        position: fixed;
        left: 0 !important;
        right: 0 !important;
        bottom: 0;
        top: auto !important;
        width: auto !important;
        max-width: none;

        /* ── Height and overflow: never taller than the viewport ──────────────────────────
           The panel becomes a column so the head can stay put while only the list scrolls. */
        display: flex;
        flex-direction: column;
        max-height: min(72vh, 560px);

        /* Safe-area on all three exposed edges, not just the bottom. */
        padding: 16px max(18px, env(safe-area-inset-right, 0px))
                 calc(18px + env(safe-area-inset-bottom, 0px))
                 max(18px, env(safe-area-inset-left, 0px));
    }

    /* The head never scrolls, so the close button is always reachable. */
    .lbai-badges__panel-head {
        flex: 0 0 auto;
        margin-bottom: 12px;
    }

    /* ── Scrolling: the list is the only scroller ─────────────────────────────────────────
       overscroll-behavior:contain stops a swipe at the end of the list from scrolling the
       page behind the sheet. */
    .lbai-badges__list {
        flex: 1 1 auto;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;

        /* ── Badge wrapping: let the grid choose its own column count ─────────────────────
           auto-fit + minmax means one column when there is no room for two, instead of
           forcing two and overflowing. */
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
        gap: 12px;
    }

    /* A grid item defaults to min-width:auto and cannot shrink below its content; these three
       rules are what stop the longest label ("Quick Responder") widening its track. */
    .lbai-badges__list > .lbai-badges__item { min-width: 0; }
    .lbai-badges__item .lbai-badge { max-width: 100%; min-width: 0; }
    .lbai-badges__item .lbai-badge__label {
        white-space: normal;
        overflow-wrap: anywhere;
    }

    /* ── Touch spacing: a real 44x44 target, visually unchanged ───────────────────────────
       Negative margins absorb the added box so the head keeps its original height. */
    .lbai-badges__close {
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        margin: -10px -10px -10px 0;
    }

    /* ── Backdrop: generated from <html> instead of from inside the card ───────────────────
       .lbai-badges sits inside the card and inside .swiper-wrapper, which Swiper transforms at
       runtime; a position:fixed pseudo-element there resolves against that transformed box
       rather than the viewport. <html> is never transformed. The original backdrop is
       neutralised rather than edited, so the base rules above stay untouched. */
    .lbai-badges.is-open::after { content: none; }

    html.lbai-badges-lock::before {
        content: "";
        position: fixed;
        inset: 0;
        z-index: 99999;
        background: rgba(15, 23, 42, .45);
    }
}

/* ── Narrow phones 320–360px ───────────────────────────────────────────────────────────────
   One badge per row: at this width a two-column grid gives each label about 132px, which wraps
   "Quick Responder" onto two lines. A single column keeps every label on one line, so nothing
   is cramped and nothing is clipped. The sheet is allowed slightly more height because the
   single column is taller. */
@media (max-width: 360px) {
    .lbai-badges__list { grid-template-columns: 1fr; gap: 10px; }
    .lbai-badges__panel { max-height: 78vh; }
}
/* ═══════════════════════════════ END RC1 UI HOTFIX — WAVE 1 ══════════════════════════════ */
