/* ============================================================
   BizPortal — Visual Enhancement Layer
   Loaded AFTER style.css. Pure CSS, zero dependencies, zero
   external assets (no images/fonts added). Everything here is
   additive: it upgrades existing components (business-card,
   category-card/tile, navbar, btn, hero-search-pill) with richer
   motion and depth, and adds a small set of new utility classes
   (.reveal-stagger, .tilt, .skeleton, .glow-ring) that the page
   templates or assets/js/enhance.js can opt into.

   Nothing in this file removes or overrides layout/structure —
   only visual polish (shadow, gradient, transform, transition).
   Safe to delete this one file to fully revert the visual layer.
   ============================================================ */

:root {
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    --teal-glow: rgba(42, 157, 143, 0.35);
    --amber-glow: rgba(244, 162, 97, 0.35);
    --card-radius: 14px;
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
    .tilt { transform: none !important; }
}

/* ---------------- Scroll-reveal stagger ----------------
   assets/js/enhance.js adds .in-view + sets --stagger-i on each
   item inside a .reveal-stagger container via IntersectionObserver.
   No JS? Everything below shows immediately (no opacity:0 default
   outside the .js-armed state), so this degrades safely. */
.reveal-stagger.js-armed > * {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 0.55s var(--ease-out), transform 0.55s var(--ease-out);
    transition-delay: calc(var(--stagger-i, 0) * 60ms);
}
.reveal-stagger.js-armed > *.in-view {
    opacity: 1;
    transform: translateY(0);
}

/* ---------------- Buttons: sheen sweep ---------------- */
@media (prefers-reduced-motion: no-preference) {
    .btn {
        position: relative;
        overflow: hidden;
        isolation: isolate;
        transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out), background 0.2s ease;
    }
    .btn::after {
        content: '';
        position: absolute;
        inset: 0;
        z-index: -1;
        background: linear-gradient(115deg, transparent 20%, rgba(255,255,255,0.35) 40%, transparent 60%);
        transform: translateX(-120%);
        transition: transform 0.6s var(--ease-out);
    }
    .btn:hover::after { transform: translateX(120%); }
    .btn-primary:hover, .btn-nav-solid:hover {
        box-shadow: 0 8px 20px -6px var(--teal-glow);
        transform: translateY(-2px);
    }
    .btn-amber:hover {
        box-shadow: 0 8px 20px -6px var(--amber-glow);
        transform: translateY(-2px);
    }
    .btn:active { transform: translateY(0) scale(0.97) !important; }
}

/* ---------------- Navbar: animated underline ---------------- */
@media (prefers-reduced-motion: no-preference) {
    .navbar-links > a:not(.btn-nav-solid):not(.btn-nav-outline) {
        position: relative;
        transition: opacity 0.2s ease;
    }
    .navbar-links > a:not(.btn-nav-solid):not(.btn-nav-outline)::after {
        content: '';
        position: absolute;
        left: 0; right: 0; bottom: -6px;
        height: 2px;
        background: var(--amber-500);
        transform: scaleX(0);
        transform-origin: left;
        transition: transform 0.3s var(--ease-out);
        border-radius: 2px;
    }
    .navbar-links > a:not(.btn-nav-solid):not(.btn-nav-outline):hover::after {
        transform: scaleX(1);
    }
    .navbar-dropdown-caret { transition: transform 0.25s var(--ease-out); }
    .navbar-dropdown:hover .navbar-dropdown-caret { transform: rotate(180deg); }

    .navbar-mega-menu {
        transform-origin: top center;
        animation: megaIn 0.28s var(--ease-out) both;
    }
    @keyframes megaIn {
        from { opacity: 0; transform: translateY(-8px) scale(0.98); }
        to   { opacity: 1; transform: translateY(0) scale(1); }
    }
    .mega-col a {
        transition: background 0.18s ease, transform 0.18s var(--ease-out), color 0.18s ease;
    }
    .mega-col a:hover {
        transform: translateX(3px);
    }
}

/* ---------------- Business card: name/rating moved off the image ----------------
   The card used to overlay the business name and star rating directly on
   top of the photo/placeholder image, with a dark scrim behind it for
   contrast. Per request, the media area now shows only the image — name
   and rating live in this white content block underneath instead. */
.business-card-body {
    padding: 14px 14px 4px;
}
.business-card-body h4 {
    margin: 0 0 8px;
    font-size: 1.05rem;
    line-height: 1.3;
    color: var(--navy-950);
}
.business-card-rating {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    color: var(--ink-soft);
}
.business-card-rating .star-rating i:not(.filled) { color: var(--line); }
.business-card-rating .muted { color: var(--ink-soft); }
.business-card-footer {
    border-top: 1px solid var(--line);
    margin-top: 4px;
}

/* ---------------- Business card: premium hover ---------------- */
.business-card {
    border-radius: var(--card-radius);
    transition: transform 0.4s var(--ease-out), box-shadow 0.4s var(--ease-out);
}
@media (prefers-reduced-motion: no-preference) {
    .business-card {
        will-change: transform;
    }
    .business-card:hover {
        transform: translateY(-6px);
        box-shadow: 0 24px 48px -16px rgba(15, 27, 45, 0.32), 0 0 0 1px rgba(42,157,143,0.15);
    }
    .business-card-media img {
        transition: transform 0.6s var(--ease-out), filter 0.4s ease;
    }
    .business-card:hover .business-card-media img {
        transform: scale(1.12) rotate(0.3deg);
        filter: saturate(1.08);
    }
    .business-card-chip {
        transition: transform 0.3s var(--ease-spring);
    }
    .business-card:hover .business-card-chip {
        transform: translateY(-2px);
    }
    .business-card-overlay h4 {
        transition: transform 0.35s var(--ease-out);
    }
    .business-card:hover .business-card-overlay h4 {
        transform: translateY(-2px);
    }
    /* Featured badge: gentle shimmer sweep instead of a static gold pill */
    .business-card-featured {
        position: relative;
        overflow: hidden;
    }
    .business-card-featured::after {
        content: '';
        position: absolute;
        top: 0; left: -60%;
        width: 40%; height: 100%;
        background: linear-gradient(115deg, transparent, rgba(255,255,255,0.55), transparent);
        animation: featuredShimmer 2.8s ease-in-out infinite;
    }
    @keyframes featuredShimmer {
        0%   { left: -60%; }
        45%  { left: 130%; }
        100% { left: 130%; }
    }
}

/* ---------------- Feed card (mobile list) ----------------
   FIX: style.css has zero rules for .feed-card/.feed-thumb/.feed-body/
   .feed-cat/.feed-loc/.feed-meta — the mobile listing view (rendered by
   render_feed_card() and shown via ".feed-list.mobile-only" in
   listing.php/categories pages) was rendering as fully unstyled browser
   defaults on every phone visit. This section is the actual base layout
   for that component, not just polish on top of it. */
/* FIX: this rule used to be unconditional "display: flex", which has the
   same CSS specificity as style.css's ".mobile-only { display: none; }" —
   and because this file loads AFTER style.css, it was WINNING, showing the
   feed-list at every screen width alongside the desktop grid at the same
   time (the "2 types of cards / double showing" bug). style.css's own
   comment above .mobile-only says the mobile view "only appears if
   mobile-app.css is loaded" — that file doesn't exist anywhere in this
   codebase, so the swap below was never actually wired up. This restores
   hidden-by-default and only reveals the feed-list (and hides the desktop
   grid) under the same max-width:760px breakpoint style.css already uses
   elsewhere for mobile behavior. Filter sheet / mobile app-bar / WhatsApp
   fab are untouched here — those need their own missing CSS + JS and are
   a separate, bigger fix. */
.feed-list.mobile-only { display: none; }
@media (max-width: 760px) {
    .grid.desktop-only { display: none; }
    .feed-list.mobile-only { display: flex; }
}
.feed-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.feed-card {
    display: flex;
    align-items: center;
    gap: 14px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 10px;
    text-decoration: none;
    color: inherit;
    box-shadow: 0 1px 4px rgba(15,27,45,0.06);
}
.feed-thumb {
    width: 72px;
    height: 72px;
    flex-shrink: 0;
    border-radius: 10px;
    object-fit: cover;
    background: var(--paper-dim);
}
.feed-thumb.no-image {
    display: flex;
    align-items: center;
    justify-content: center;
    /* Fixed, dark colours — same reasoning as the desktop card fix above:
       a placeholder tile shouldn't shift with the theme's brand colour. */
    background: linear-gradient(150deg, #16233A 0%, #1B2A41 55%, #0F3B36 100%);
}
.feed-thumb.no-image i { color: rgba(255,255,255,0.95); font-size: 1.6rem; }
.feed-body { flex: 1; min-width: 0; }
.feed-cat {
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--teal-600);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 2px;
}
.feed-body h4 {
    margin: 0 0 5px;
    font-size: 0.96rem;
    line-height: 1.25;
    color: var(--navy-950);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.feed-loc {
    font-size: 0.8rem;
    color: var(--ink-soft);
    display: flex;
    align-items: center;
    gap: 5px;
    margin-bottom: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.feed-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.82rem;
}
@media (prefers-reduced-motion: no-preference) {
    .feed-card {
        transition: background 0.2s ease, transform 0.2s var(--ease-out), box-shadow 0.2s ease;
    }
    .feed-card:active { transform: scale(0.98); }
    .feed-card:hover { box-shadow: 0 6px 16px -6px rgba(15,27,45,0.16); }
    .feed-thumb {
        transition: transform 0.4s var(--ease-out);
    }
    .feed-card:hover .feed-thumb { transform: scale(1.06); }
}

/* ---------------- Category card / tile ---------------- */
@media (prefers-reduced-motion: no-preference) {
    .category-card {
        transition: transform 0.35s var(--ease-out), box-shadow 0.35s var(--ease-out), border-color 0.3s ease;
    }
    .category-card:hover {
        transform: translateY(-6px) scale(1.015);
        box-shadow: 0 20px 40px -18px rgba(15,27,45,0.3);
    }
    .category-card i {
        transition: transform 0.4s var(--ease-spring);
    }
    .category-card:hover i {
        transform: scale(1.15) rotate(-6deg);
    }

    .category-tile {
        background-size: 160% 160% !important;
        transition: transform 0.4s var(--ease-out), background-position 0.6s ease, box-shadow 0.4s var(--ease-out);
    }
    .category-tile:hover {
        transform: translateY(-7px) scale(1.02);
        background-position: 100% 100% !important;
    }
    .category-tile-icon {
        transition: transform 0.4s var(--ease-spring);
    }
    .category-tile:hover .category-tile-icon {
        transform: scale(1.15) rotate(6deg);
    }
}

/* ---------------- Hero: ambient motion + focus glow ---------------- */
.hero-home .hero-glow {
    animation: heroGlowDrift 12s ease-in-out infinite alternate;
}
@keyframes heroGlowDrift {
    from { transform: translate(0, 0) scale(1); }
    to   { transform: translate(-2%, 3%) scale(1.08); }
}
@media (prefers-reduced-motion: reduce) {
    .hero-home .hero-glow { animation: none; }
}

.hero-search-pill {
    transition: box-shadow 0.3s var(--ease-out), transform 0.3s var(--ease-out);
}
.hero-search-pill:focus-within {
    box-shadow: 0 0 0 4px var(--teal-glow), 0 12px 32px -12px rgba(15,27,45,0.35);
    transform: translateY(-2px);
}
.hero-chip {
    transition: transform 0.25s var(--ease-spring), background 0.2s ease, color 0.2s ease;
}
.hero-chip:hover { transform: translateY(-2px) scale(1.04); }

/* ---------------- Stat / info cards ---------------- */
@media (prefers-reduced-motion: no-preference) {
    .stat-card, .info-card {
        transition: transform 0.35s var(--ease-out), box-shadow 0.35s var(--ease-out);
    }
    .stat-card:hover, .info-card:hover {
        transform: translateY(-4px);
        box-shadow: 0 16px 32px -16px rgba(15,27,45,0.25);
    }
}

/* ---------------- Skeleton loading shimmer (utility) ----------------
   Opt-in: add class="skeleton" to any placeholder block (e.g. an image
   wrapper) while content is loading; remove once loaded. Not wired to
   anything automatically — safe no-op until a template uses it. */
.skeleton {
    position: relative;
    overflow: hidden;
    background: var(--paper-dim);
}
.skeleton::after {
    content: '';
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent);
}
@media (prefers-reduced-motion: no-preference) {
    .skeleton::after { animation: skeletonSweep 1.4s ease-in-out infinite; }
}
@keyframes skeletonSweep {
    100% { transform: translateX(100%); }
}

/* ---------------- Pagination: wrap safety net ---------------- */
.pagination { flex-wrap: wrap; }

/* ---------------- FIX: uploaded logos/photos were being cropped ----------------
   .business-card-media img and .feed-thumb used object-fit: cover, which
   crops whatever doesn't fit the card's fixed aspect ratio — fine for wide
   photos, but it chops the edges off square/portrait logos. Switching to
   contain shows the whole uploaded image; the neutral backdrop keeps the
   letterboxed edges (when the image's aspect ratio doesn't match the
   frame) looking intentional instead of like empty space. */
.business-card-media {
    background: #fff;
}
.business-card-media img {
    object-fit: contain !important;
    padding: 10px;
    box-sizing: border-box;
}
.feed-thumb:not(.no-image) {
    background: #fff;
    object-fit: contain !important;
    padding: 4px;
    box-sizing: border-box;
    border: 1px solid var(--line);
}

/* ---------------- Pagination: livelier active state ---------------- */
@media (prefers-reduced-motion: no-preference) {
    .pagination a {
        transition: transform 0.2s var(--ease-spring), background 0.2s ease, color 0.2s ease;
    }
    .pagination a:hover { transform: translateY(-2px); }
    .pagination a.active { box-shadow: 0 6px 16px -6px var(--teal-glow); }
}

/* ---------------- Business detail page: gallery + tab polish ----------------
   These selectors are best-effort — they only apply where the class
   already exists in business_details.php, so this is a safe no-op
   anywhere the class name differs. */
@media (prefers-reduced-motion: no-preference) {
    .gallery-thumb, .business-gallery img, .biz-gallery-item {
        transition: transform 0.3s var(--ease-out), filter 0.3s ease;
    }
    .gallery-thumb:hover, .business-gallery img:hover, .biz-gallery-item:hover {
        transform: scale(1.04);
        filter: brightness(1.05);
    }
    .tab-btn, .biz-tab {
        transition: color 0.2s ease, border-color 0.25s var(--ease-out);
    }
}

/* ---------------- FIX: washed-out "no photo" card tile ----------------
   .business-card-media-fallback previously used var(--teal-600), which
   includes/functions.php (render_theme_style_block) lets the admin's
   theme-color picker override. If that override ever resolves to a pale
   colour, the fallback tile washes out toward white with a barely-visible
   icon, and the white business-name text (which relies on the scrim below
   it for contrast) becomes unreadable. Placeholder tiles are a neutral
   design-system element, not a brand surface — pin them to fixed, dark
   colours so they can never wash out no matter what theme is picked. */
.business-card-media-fallback {
    background: linear-gradient(150deg, #16233A 0%, #1B2A41 55%, #0F3B36 100%) !important;
}
.business-card-media-fallback i {
    color: rgba(255, 255, 255, 0.95) !important;
}
/* Belt-and-braces: guarantee legible text on the overlay even if the scrim
   above it is ever weakened by a future theme change. */
.business-card-overlay h4 {
    text-shadow: 0 1px 3px rgba(0,0,0,0.9), 0 2px 10px rgba(0,0,0,0.6) !important;
}
.business-card-overlay-meta {
    text-shadow: 0 1px 3px rgba(0,0,0,0.85);
}

/* ---------------- Cursor-follow tilt (opt-in via JS) ----------------
   assets/js/enhance.js adds .tilt to business-card / category-tile on
   pointer:fine devices and sets --tilt-x/--tilt-y on mousemove. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .tilt {
        transform: perspective(800px)
                   rotateX(var(--tilt-y, 0deg))
                   rotateY(var(--tilt-x, 0deg))
                   translateY(var(--tilt-lift, 0px));
        transition: transform 0.15s ease-out;
    }
}
