/* --- START OF FILE script-classic.js --- */

import { 
    initCore, 
    state, 
    getEl, 
    addProductToCart,
    getCartQuantity, 
    decreaseProductFromCart, 
    handleCheckoutSubmit, 
    trackPixelEvent, 
    showToast, 
    captureLiveInput,
    getLandingPageUrlForProduct,
    applyCheckoutAddressMode,
    applyProductIdQueryParamAsHash,
    getCurrentClientId,
    getClientContextDebug,
    getMenuCategories,
    tryDismissBootLoadingOverlay
} from './shop-core.js';
import { getResponsiveImageSpec, ensureImagePreconnects, collectImageOrigins } from './image-delivery.js';

// Global DOC object to hold DOM elements
const doc = {};

/** Dedupe Search pixel when handleRouter re-runs for same hash */
let lastClassicSearchHashForPixel = '';
let initialAtomicRenderCommitted = false;

const isBuyNowDebugEnabled = () => {
    try {
        const q = new URLSearchParams(window.location.search);
        if (q.get('debugBuyNow') === '1') return true;
        const hash = window.location.hash || '';
        if (hash.includes('?debugBuyNow=1') || hash.includes('&debugBuyNow=1')) return true;
        return localStorage.getItem('sb_debug_buy_now') === '1';
    } catch (e) {
        return false;
    }
};

const logBuyNowDebug = (eventName, payload = {}) => {
    if (!isBuyNowDebugEnabled()) return;
    const entry = {
        event: eventName,
        ts: new Date().toISOString(),
        href: window.location.href,
        hash: window.location.hash || '',
        ...payload
    };
    try {
        window.__sbBuyNowDebugLogs = window.__sbBuyNowDebugLogs || [];
        window.__sbBuyNowDebugLogs.push(entry);
    } catch (e) { /* ignore */ }
    console.log('[SB][BuyNowDebug]', entry);
};

/** Bump when deploying shop-classic.html + script-classic.js together (must match meta classic-store-build in HTML). */
const CLASSIC_STORE_BUILD_ID = '2026.05.01-2';

const isLayoutDebugEnabled = () => {
    try {
        const q = new URLSearchParams(window.location.search);
        if (q.get('layoutDebug') === '1') return true;
        const h = window.location.hash || '';
        return h.includes('layoutDebug=1');
    } catch (e) {
        return false;
    }
};

const exposeClassicStoreBuild = () => {
    try {
        const meta = document.querySelector('meta[name="classic-store-build"]');
        const htmlBuild = meta ? String(meta.getAttribute('content') || '').trim() : '';
        window.__CLASSIC_STORE_BUILD__ = {
            scriptBuild: CLASSIC_STORE_BUILD_ID,
            htmlMetaBuild: htmlBuild || null,
            match: !htmlBuild || htmlBuild === CLASSIC_STORE_BUILD_ID
        };
        if (htmlBuild && htmlBuild !== CLASSIC_STORE_BUILD_ID) {
            console.warn('[classic-store] HTML/script build mismatch (cache or partial deploy):', {
                scriptBuild: CLASSIC_STORE_BUILD_ID,
                htmlMetaBuild: htmlBuild
            });
        }
    } catch (e) { /* ignore */ }
};

let classicLayoutDebugPanel = null;
let classicLayoutDebugRaf = 0;

const refreshClassicLayoutDebugPanel = () => {
    if (!classicLayoutDebugPanel || !isLayoutDebugEnabled()) return;
    const root = document.documentElement;
    const csRoot = window.getComputedStyle(root);
    const gapVar = (csRoot.getPropertyValue('--desktop-content-side-gap') || '').trim();
    const shellW = (csRoot.getPropertyValue('--pixel-home-shell-width') || '').trim();
    const gutterResolved = (csRoot.getPropertyValue('--desktop-side-gutter') || '').trim();
    const layout = state.siteSettings?.layout || {};
    const savedRaw = layout.desktopContentSideGapPx;
    const mq1024 = window.matchMedia('(min-width: 1024px)').matches;
    const hero = document.getElementById('classic-pc-hero-stack');
    let heroPadL = '—';
    let heroPadR = '—';
    let approxOuterEach = '—';
    if (hero) {
        const hcs = window.getComputedStyle(hero);
        heroPadL = hcs.paddingLeft;
        heroPadR = hcs.paddingRight;
        const r = hero.getBoundingClientRect();
        approxOuterEach = `${Math.round((window.innerWidth - r.width) / 2)}px`;
    }
    const build = window.__CLASSIC_STORE_BUILD__ || {};
    classicLayoutDebugPanel.innerHTML = `
<div style="display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:6px;">
  <strong>Layout debug</strong>
  <button type="button" data-close="1" style="font:inherit;padding:2px 8px;border-radius:4px;border:1px solid #555;background:#333;color:#fff;cursor:pointer">Close</button>
</div>
<pre style="margin:0;white-space:pre-wrap;word-break:break-word;font-size:11px;line-height:1.45;">viewport: ${window.innerWidth}px  (≥1024 desktop rules: ${mq1024 ? 'yes' : 'no'})
build: script=${String(build.scriptBuild || '')}  htmlMeta=${build.htmlMetaBuild != null ? String(build.htmlMetaBuild) : '(none)'}  match=${build.match !== false ? 'ok' : 'MISMATCH'}
settings layout.desktopContentSideGapPx: ${savedRaw == null || savedRaw === '' ? '(null/empty)' : JSON.stringify(savedRaw)}
settings layout.desktopShellMaxWidthPx: ${(layout.desktopShellMaxWidthPx == null || layout.desktopShellMaxWidthPx === '') ? '(null/empty)' : JSON.stringify(layout.desktopShellMaxWidthPx)}
computed --desktop-content-side-gap: ${gapVar || '(unset)'}
computed --pixel-home-shell-width: ${shellW || '(unset)'}
computed --desktop-side-gutter: ${gutterResolved || '(unset)'}
#classic-pc-hero-stack padding L/R: ${heroPadL} / ${heroPadR}
approx margin viewport→hero box (each side): ${approxOuterEach}
Outer margin ≈ (viewport − centered shell width) / 2; dashboard gap is padding inside that shell.</pre>`.trim();
    const closeBtn = classicLayoutDebugPanel.querySelector('button[data-close="1"]');
    if (closeBtn) {
        closeBtn.onclick = () => {
            try {
                const u = new URL(window.location.href);
                u.searchParams.delete('layoutDebug');
                window.history.replaceState({}, '', u.pathname + u.search + u.hash);
            } catch (e) { /* ignore */ }
            classicLayoutDebugPanel.remove();
            classicLayoutDebugPanel = null;
        };
    }
};

const scheduleClassicLayoutDebugRefresh = () => {
    if (!isLayoutDebugEnabled() || !classicLayoutDebugPanel) return;
    if (classicLayoutDebugRaf) cancelAnimationFrame(classicLayoutDebugRaf);
    classicLayoutDebugRaf = requestAnimationFrame(() => {
        refreshClassicLayoutDebugPanel();
        classicLayoutDebugRaf = 0;
    });
};

const ensureClassicLayoutDebugOverlay = () => {
    if (!isLayoutDebugEnabled()) return;
    exposeClassicStoreBuild();
    if (!classicLayoutDebugPanel) {
        const el = document.createElement('div');
        el.setAttribute('role', 'region');
        el.setAttribute('aria-label', 'Classic layout debug');
        el.style.cssText = [
            'position:fixed', 'right:8px', 'bottom:8px', 'z-index:99999', 'max-width:min(420px,calc(100vw - 16px))',
            'padding:10px 12px', 'background:rgba(17,24,39,.94)', 'color:#f9fafb', 'border-radius:8px',
            'box-shadow:0 4px 24px rgba(0,0,0,.35)', 'font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace',
            'pointer-events:auto', 'text-align:left'
        ].join(';');
        document.body.appendChild(el);
        classicLayoutDebugPanel = el;
        window.addEventListener('resize', scheduleClassicLayoutDebugRefresh, { passive: true });
        document.addEventListener('storeDataRefreshed', scheduleClassicLayoutDebugRefresh);
        window.addEventListener('hashchange', scheduleClassicLayoutDebugRefresh);
    }
    scheduleClassicLayoutDebugRefresh();
};

const getElementBrief = (el) => {
    if (!el) return null;
    const id = el.id ? `#${el.id}` : '';
    const cls = (el.className && typeof el.className === 'string')
        ? '.' + el.className.trim().split(/\s+/).filter(Boolean).slice(0, 3).join('.')
        : '';
    return `${String(el.tagName || '').toLowerCase()}${id}${cls}`;
};

const getFreezeBlockerSnapshot = () => {
    const selectors = [
        '#cart-overlay',
        '#full-screen-search-overlay',
        '#quick-view-modal',
        '#compare-modal',
        '#mobile-nav-drawer',
        '#sb-ip-blocked-overlay',
        '#loading-overlay'
    ];
    const layers = selectors.map((selector) => {
        const el = document.querySelector(selector);
        if (!el) return { selector, exists: false };
        const cs = window.getComputedStyle(el);
        const rect = el.getBoundingClientRect();
        const opacityNum = Number(cs.opacity);
        const opacity = Number.isFinite(opacityNum) ? opacityNum : 1;
        const displayed = cs.display !== 'none' && rect.width > 0 && rect.height > 0;
        const coversViewport = rect.width >= (window.innerWidth * 0.9) && rect.height >= (window.innerHeight * 0.9);
        const interceptsPointer = displayed && coversViewport && cs.pointerEvents !== 'none';
        const visuallyHidden = cs.visibility === 'hidden' || opacity <= 0.05 || el.classList.contains('hidden');
        return {
            selector,
            exists: true,
            display: cs.display,
            visibility: cs.visibility,
            opacity: cs.opacity,
            pointerEvents: cs.pointerEvents,
            zIndex: cs.zIndex,
            classHidden: el.classList.contains('hidden'),
            displayed,
            coversViewport,
            interceptsPointer,
            visuallyHidden,
            potentialInvisibleBlocker: interceptsPointer && visuallyHidden
        };
    });
    const cx = Math.floor((window.innerWidth || 0) / 2);
    const cy = Math.floor((window.innerHeight || 0) / 2);
    const centerEl = (cx > 0 && cy > 0) ? document.elementFromPoint(cx, cy) : null;
    return {
        activeElement: getElementBrief(document.activeElement),
        centerElement: getElementBrief(centerEl),
        scrollY: window.scrollY || 0,
        docOverflow: document.documentElement ? document.documentElement.style.overflow || '' : '',
        bodyOverflow: document.body ? document.body.style.overflow || '' : '',
        layers
    };
};

const normalizeOverlayState = (reason, options = {}) => {
    const forceClose = options.forceClose === true;
    const before = getFreezeBlockerSnapshot();
    const hasInvisibleBlocker = before.layers.some((l) => l && l.potentialInvisibleBlocker);
    if (!forceClose && !hasInvisibleBlocker) return false;

    const cartOverlay = getEl('cart-overlay');
    const cartDrawer = getEl('cart-drawer');
    const mobileDrawer = getEl('mobile-nav-drawer');
    const searchOverlay = getEl('full-screen-search-overlay');
    const quickModal = getEl('quick-view-modal');
    const compareModal = getEl('compare-modal');
    const ipBlockedOverlay = getEl('sb-ip-blocked-overlay');

    if (cartOverlay) cartOverlay.style.display = 'none';
    if (cartDrawer) cartDrawer.classList.remove('open');
    if (mobileDrawer) mobileDrawer.classList.remove('open');
    if (searchOverlay) searchOverlay.classList.add('hidden');
    if (quickModal) quickModal.classList.add('hidden');
    if (compareModal) compareModal.classList.add('hidden');
    if (doc.categoryFilterSheet) closeCategoryFilterSheet();

    if (!ipBlockedOverlay) {
        document.documentElement.style.overflow = '';
        document.body.style.overflow = '';
    }

    const after = getFreezeBlockerSnapshot();
    logBuyNowDebug('overlay_state_normalized', {
        reason,
        forceClose,
        hadInvisibleBlocker: hasInvisibleBlocker,
        before,
        after
    });
    return true;
};

// WhatsApp number for wa.me: digits only; 01XXXXXXXXX -> 8801XXXXXXXXX
const normalizeWhatsAppNumber = (raw) => {
    const digits = (raw || '').replace(/\D/g, '');
    if (digits.length === 11 && digits.startsWith('0')) return '880' + digits.slice(1);
    return digits;
};

// Global Timer Variable for FOMO Engine
let fomoInterval = null;

// Global Swiper Instance for Thumbnails (New)
let thumbSwiper = null;

// Global Sorting State for Category View
let currentCategorySort = 'default';

// Chaldal-style category card pastel background colors
const CHALDAL_PASTEL_COLORS = ['#dbeafe', '#fce7f3', '#fef9c3', '#f3e8ff', '#dcfce7', '#fce7f3'];

const productInCategory = (p, catName) => (p.categories && p.categories.includes(catName)) || p.category === catName;

/** One increment per product per distinct category name (matches productInCategory semantics for counts). */
const buildCategoryProductCountsMap = () => {
    const m = new Map();
    for (const p of state.allProducts) {
        const names = new Set();
        if (Array.isArray(p.categories)) p.categories.forEach((c) => { if (c) names.add(c); });
        if (p.category) names.add(p.category);
        names.forEach((c) => m.set(c, (m.get(c) || 0) + 1));
    }
    return m;
};
const productInSubcategory = (p, subName) => (p.subcategories && p.subcategories.includes(subName)) || p.subcategory === subName;

/** @returns {{ name: string, bgColor: string, textColor: string }[]} */
const getSubcategoryEntries = (cat) => {
    const sub = cat && cat.subcategories;
    if (sub == null) return [];
    const norm = (raw) => {
        if (raw == null) return null;
        if (typeof raw === 'string') {
            const name = String(raw).trim();
            return name ? { name, bgColor: '', textColor: '' } : null;
        }
        if (typeof raw === 'object' && raw.name) {
            const name = String(raw.name).trim();
            if (!name) return null;
            const bgColor = (raw.bgColor && String(raw.bgColor).trim()) || '';
            const textColor = (raw.textColor && String(raw.textColor).trim()) || '';
            return { name, bgColor, textColor };
        }
        return null;
    };
    const list = Array.isArray(sub)
        ? sub.map(norm).filter(Boolean)
        : (typeof sub === 'object' ? Object.values(sub).map(norm).filter(Boolean) : []);
    // Keep first occurrence order, skip empty/duplicate names for stable flyout UI.
    const seen = new Set();
    return list.filter((entry) => {
        const key = String(entry.name || '').trim().toLowerCase();
        if (!key || seen.has(key)) return false;
        seen.add(key);
        return true;
    });
};

const subcategoryEntryStyleAttr = (entry) => {
    if (!entry) return '';
    const st = [];
    if (entry.bgColor && /^#[0-9A-Fa-f]{3,8}$/i.test(entry.bgColor)) st.push(`background-color:${entry.bgColor}`);
    if (entry.textColor && /^#[0-9A-Fa-f]{3,8}$/i.test(entry.textColor)) st.push(`color:${entry.textColor}`);
    return st.length ? ` style="${st.join(';')}"` : '';
};

const getSubcategoryNames = (cat) => getSubcategoryEntries(cat).map((e) => e.name);

/**
 * Top `limit` products per menu category name; one pass over `allProducts`.
 * Matches `productInCategory` via `p.category` / `p.categories` only for names in `menuCats`.
 */
const buildMenuCategoryProductPreviewMap = (menuCats, allProducts, limit = 5) => {
    const namesInMenu = new Set((menuCats || []).map((c) => c && c.name).filter(Boolean));
    const buckets = new Map();
    namesInMenu.forEach((n) => buckets.set(n, []));
    for (const p of allProducts || []) {
        if (!p) continue;
        const matched = new Set();
        if (p.category && namesInMenu.has(p.category)) matched.add(p.category);
        if (Array.isArray(p.categories)) {
            for (const cn of p.categories) {
                if (cn && namesInMenu.has(cn)) matched.add(cn);
            }
        }
        for (const catName of matched) {
            const arr = buckets.get(catName);
            if (arr.length < limit) arr.push(p);
        }
    }
    return buckets;
};

const hideCategorySubnav = () => {
    if (doc.categorySubnavBar) doc.categorySubnavBar.classList.add('hidden');
    if (doc.categorySubnavInner) doc.categorySubnavInner.innerHTML = '';
};

/** Shared subcategory link HTML for horizontal subnav or mobile filter sheet. */
const buildCategorySubcategoryLinkItems = (categoryName, linkClass) => {
    const cat = (state.allCategories || []).find((c) => c.name === categoryName);
    const entries = cat ? getSubcategoryEntries(cat) : [];
    if (!entries.length) return { html: '', hasSubs: false };
    const subParam = new URLSearchParams(window.location.hash.split('?')[1] || '').get('sub');
    const selectedSub = subParam ? decodeURIComponent(subParam) : '';
    const baseHash = `#/category/${encodeURIComponent(categoryName)}`;
    const esc = (s) => String(s).replace(/</g, '&lt;');
    const allActive = !selectedSub ? ' is-active' : '';
    const links = [
        `<a href="${baseHash}" class="${linkClass}${allActive}">All</a>`
    ].concat(
        entries.map((entry) => {
            const subName = entry.name;
            const active = selectedSub === subName ? ' is-active' : '';
            const href = `${baseHash}?sub=${encodeURIComponent(subName)}`;
            const sty = subcategoryEntryStyleAttr(entry);
            return `<a href="${href}" class="${linkClass}${active}"${sty}>${esc(subName)}</a>`;
        })
    );
    return { html: links.join(''), hasSubs: true };
};

/** Fixed-position subcategory flyouts beside Shwapno PC sidebar (avoids overflow clipping). */
const bindShwapnoDesktopSidebarFlyouts = (asideEl) => {
    if (!asideEl) return;
    if (window.innerWidth < 768) return;
    const margin = 10;
    const pad = 2;
    const reposition = (row, fly) => {
        const rr = row.getBoundingClientRect();
        fly.style.maxHeight = `${Math.min(420, window.innerHeight - margin * 2)}px`;
        fly.style.left = `${Math.round(rr.right + pad)}px`;
        fly.style.top = `${Math.round(rr.top)}px`;
        void fly.offsetHeight;
        const fr = fly.getBoundingClientRect();
        let top = fr.top;
        const fh = fr.height;
        if (top + fh > window.innerHeight - margin) {
            top = Math.max(margin, window.innerHeight - margin - fh);
            fly.style.top = `${Math.round(top)}px`;
        }
        const fr2 = fly.getBoundingClientRect();
        if (fr2.right > window.innerWidth - margin) {
            const left = Math.max(margin, window.innerWidth - margin - fr2.width);
            fly.style.left = `${Math.round(left)}px`;
        }
    };
    asideEl.querySelectorAll('.shwapno-cat-row').forEach((row) => {
        const fly = row.querySelector('.shwapno-flyout');
        if (!fly) return;
        let closeTimer = 0;
        let touchPanelOpen = false;
        const rowLink = row.querySelector('.shwapno-cat');
        const open = () => {
            if (closeTimer) {
                clearTimeout(closeTimer);
                closeTimer = 0;
            }
            fly.classList.add('is-visible');
            touchPanelOpen = true;
            requestAnimationFrame(() => reposition(row, fly));
        };
        const scheduleClose = () => {
            if (closeTimer) clearTimeout(closeTimer);
            closeTimer = window.setTimeout(() => {
                fly.classList.remove('is-visible');
                touchPanelOpen = false;
                closeTimer = 0;
            }, 120);
        };
        row.addEventListener('mouseenter', open);
        row.addEventListener('mouseleave', scheduleClose);
        row.addEventListener('focusin', open);
        row.addEventListener('focusout', (ev) => {
            const next = ev.relatedTarget;
            if (next && (row.contains(next) || fly.contains(next))) return;
            scheduleClose();
        });
        row.addEventListener('pointerdown', (ev) => {
            if (!ev.isPrimary || ev.pointerType !== 'touch') return;
            if (!rowLink) return;
            // Touch laptop support: first tap opens panel, second tap follows link.
            if (!touchPanelOpen) {
                ev.preventDefault();
                open();
            }
        });
        fly.addEventListener('mouseenter', () => {
            if (closeTimer) {
                clearTimeout(closeTimer);
                closeTimer = 0;
            }
        });
        fly.addEventListener('mouseleave', scheduleClose);
        fly.addEventListener('focusin', () => {
            if (closeTimer) {
                clearTimeout(closeTimer);
                closeTimer = 0;
            }
        });
        fly.addEventListener('focusout', (ev) => {
            const next = ev.relatedTarget;
            if (next && (fly.contains(next) || row.contains(next))) return;
            scheduleClose();
        });
        fly.querySelectorAll('.shwapno-flyout-link').forEach((lnk) => {
            lnk.addEventListener('click', () => {
                fly.classList.remove('is-visible');
                touchPanelOpen = false;
            });
        });
    });
    const list = asideEl.querySelector('.shwapno-sidebar-list');
    if (list) {
        list.addEventListener(
            'scroll',
            () => {
                asideEl.querySelectorAll('.shwapno-flyout.is-visible').forEach((fly) => {
                    const row = fly.closest('.shwapno-cat-row');
                    if (row) reposition(row, fly);
                });
            },
            { passive: true }
        );
    }
};

const updateCategorySubnav = (categoryName) => {
    if (!doc.categorySubnavBar || !doc.categorySubnavInner) return;
    const { html, hasSubs } = buildCategorySubcategoryLinkItems(categoryName, 'category-subnav-link');
    if (!hasSubs) {
        hideCategorySubnav();
        return;
    }
    doc.categorySubnavInner.innerHTML = html;
    doc.categorySubnavBar.classList.remove('hidden');
};

const closeCategoryFilterSheet = () => {
    if (!doc.categoryFilterSheet) return;
    doc.categoryFilterSheet.classList.remove('is-open');
    if (doc.categoryFilterOpenBtn) doc.categoryFilterOpenBtn.setAttribute('aria-expanded', 'false');
    document.body.style.overflow = '';
};

const openCategoryFilterSheet = () => {
    if (!doc.categoryFilterSheet) return;
    doc.categoryFilterSheet.classList.add('is-open');
    if (doc.categoryFilterOpenBtn) doc.categoryFilterOpenBtn.setAttribute('aria-expanded', 'true');
    document.body.style.overflow = 'hidden';
};

const updateCategoryFilterSheet = (categoryName, baseProducts = []) => {
    if (!doc.categoryFilterSheetInner) return;
    const { html, hasSubs } = buildCategorySubcategoryLinkItems(categoryName, 'category-filter-sheet-link');
    const allCatLink = '<a href="#/categories" class="category-filter-sheet-link category-filter-sheet-link--all">All categories</a>';
    let subPart = '';
    if (hasSubs) {
        subPart = `<p class="category-filter-sheet-muted">Subcategories</p>${html}<div class="mt-4 pt-2 border-t" style="border-color:var(--card-border)">${allCatLink}</div>`;
    } else {
        subPart = `<p class="category-filter-sheet-muted">No subcategories for this category.</p><div class="mt-2 pt-2 border-t" style="border-color:var(--card-border)">${allCatLink}</div>`;
    }
    const facets = collectCategoryFacets(baseProducts);
    const facetMob = buildCategoryFacetSectionHTML(facets, true);
    const facetSection = facetMob
        ? `<div class="mt-5 pt-4 border-t" style="border-color:var(--card-border)"><p class="category-filter-sheet-muted mb-3">Filters</p>${facetMob}</div>`
        : '';
    doc.categoryFilterSheetInner.innerHTML = subPart + facetSection;
    doc.categoryFilterSheetInner.querySelectorAll('a.category-filter-sheet-link').forEach((a) => {
        a.addEventListener('click', () => closeCategoryFilterSheet());
    });
};

const resetCategoryListingChrome = () => {
    closeCategoryFilterSheet();
    if (doc.categoryView) doc.categoryView.classList.remove('category-view--listing');
    if (doc.categoryHeroBanner) {
        doc.categoryHeroBanner.classList.remove('is-visible');
        doc.categoryHeroBanner.setAttribute('aria-hidden', 'true');
    }
    if (doc.categoryHeroBannerImg) {
        doc.categoryHeroBannerImg.removeAttribute('src');
        doc.categoryHeroBannerImg.alt = '';
    }
    if (doc.catDescription) {
        doc.catDescription.textContent = '';
        doc.catDescription.classList.add('hidden');
    }
};

// --- Category page facet filters (PC sidebar + mobile filter sheet) ---
let categoryFacetFilterContextKey = '';
const activeCategoryFilters = {
    deliveryTimes: new Set(),
    express: new Set(),
    freeShipping: new Set(),
    tags: new Set(),
    /** null = full range (no price narrowing) */
    priceRange: { min: null, max: null },
};

const resetActiveCategoryFilters = () => {
    activeCategoryFilters.deliveryTimes.clear();
    activeCategoryFilters.express.clear();
    activeCategoryFilters.freeShipping.clear();
    activeCategoryFilters.tags.clear();
    activeCategoryFilters.priceRange = { min: null, max: null };
};

/** List/card price: minimum variant sale or product salePrice (matches category sort). */
const getCategoryProductListPrice = (p) => {
    if (!p) return NaN;
    if (p.hasVariants && p.variants && typeof p.variants === 'object') {
        const vars = Object.values(p.variants).filter((v) => v && v.salePrice != null);
        if (vars.length === 0) return Number(p.salePrice) || 0;
        return Math.min(...vars.map((v) => Number(v.salePrice)));
    }
    return Number(p.salePrice) || 0;
};

const escapeFacetHtml = (s) => String(s)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');

const collectCategoryFacets = (baseProducts) => {
    const deliveryCounts = new Map();
    let expressYes = 0;
    let expressNo = 0;
    let freeYes = 0;
    let freeNo = 0;
    const tagCounts = new Map();
    let priceMin = Infinity;
    let priceMax = -Infinity;
    for (const p of baseProducts) {
        const listPx = getCategoryProductListPrice(p);
        if (Number.isFinite(listPx)) {
            priceMin = Math.min(priceMin, listPx);
            priceMax = Math.max(priceMax, listPx);
        }
        const d = String(p.filterDeliveryTime || '').trim();
        if (d) deliveryCounts.set(d, (deliveryCounts.get(d) || 0) + 1);
        if (p.filterExpressDelivery === true) expressYes += 1;
        else expressNo += 1;
        if (p.filterFreeShipping === true) freeYes += 1;
        else freeNo += 1;
        const tags = Array.isArray(p.filterTags) ? p.filterTags : [];
        for (const raw of tags) {
            const t = String(raw).trim();
            if (!t) continue;
            const key = t.toLowerCase();
            if (!tagCounts.has(key)) tagCounts.set(key, { display: t, count: 0 });
            tagCounts.get(key).count += 1;
        }
    }
    if (!Number.isFinite(priceMin) || !Number.isFinite(priceMax)) {
        priceMin = 0;
        priceMax = 0;
    }
    const productCount = baseProducts.length;
    return { deliveryCounts, expressYes, expressNo, freeYes, freeNo, tagCounts, priceMin, priceMax, productCount };
};

const applyCategoryFacetFilters = (products) => {
    let list = products;
    const f = activeCategoryFilters;
    const pr = f.priceRange;
    if (pr && (pr.min != null || pr.max != null)) {
        const prices = products.map(getCategoryProductListPrice).filter((n) => Number.isFinite(n));
        const gLo = prices.length ? Math.min(...prices) : 0;
        const gHi = prices.length ? Math.max(...prices) : 0;
        const lo = pr.min != null ? pr.min : gLo;
        const hi = pr.max != null ? pr.max : gHi;
        list = list.filter((p) => {
            const x = getCategoryProductListPrice(p);
            return Number.isFinite(x) && x >= lo && x <= hi;
        });
    }
    if (f.deliveryTimes.size > 0) {
        list = list.filter((p) => {
            const d = String(p.filterDeliveryTime || '').trim();
            return f.deliveryTimes.has(d);
        });
    }
    if (f.express.size > 0 && f.express.size < 2) {
        if (f.express.has('yes')) list = list.filter((p) => p.filterExpressDelivery === true);
        else if (f.express.has('no')) list = list.filter((p) => p.filterExpressDelivery !== true);
    }
    if (f.freeShipping.size > 0 && f.freeShipping.size < 2) {
        if (f.freeShipping.has('yes')) list = list.filter((p) => p.filterFreeShipping === true);
        else if (f.freeShipping.has('no')) list = list.filter((p) => p.filterFreeShipping !== true);
    }
    if (f.tags.size > 0) {
        const want = Array.from(f.tags).map((t) => t.toLowerCase());
        list = list.filter((p) => {
            const tags = Array.isArray(p.filterTags) ? p.filterTags : [];
            const norm = tags.map((t) => String(t).trim().toLowerCase()).filter(Boolean);
            return want.some((w) => norm.includes(w));
        });
    }
    return list;
};

const TAGS_VISIBLE_DEFAULT = 8;

const buildCategoryFacetSectionHTML = (facets, isMobile) => {
    const { deliveryCounts, expressYes, expressNo, freeYes, freeNo, tagCounts, priceMin, priceMax, productCount } = facets;
    const esc = escapeFacetHtml;
    const pr = activeCategoryFilters.priceRange;
    const curLo = pr.min != null ? pr.min : priceMin;
    const curHi = pr.max != null ? pr.max : priceMax;
    const scope = isMobile ? 'mob' : 'desk';
    let priceHtml = '';
    if (productCount > 0 && Number.isFinite(priceMin) && Number.isFinite(priceMax)) {
        const pmin = Math.round(priceMin);
        const pmax = Math.round(priceMax);
        const vLo = Math.round(Math.min(curLo, curHi));
        const vHi = Math.round(Math.max(curLo, curHi));
        const loClamped = Math.min(pmax, Math.max(pmin, vLo));
        const hiClamped = Math.max(pmin, Math.min(pmax, vHi));
        priceHtml = `<div class="cat-facet-block cat-facet-block--price${isMobile ? ' cat-facet-block--mob' : ''}"><h5 class="cat-facet-heading">Price range</h5>
<div class="cat-price-dual-labels flex justify-between text-xs font-semibold mb-1" style="color: var(--text-secondary);"><span>Min: ৳${loClamped}</span><span>Max: ৳${hiClamped}</span></div>
<div class="cat-price-dual-wrap" data-price-scope="${scope}">
<div class="cat-price-dual-track" aria-hidden="true"></div>
<input type="range" class="cat-price-range cat-price-range--min" min="${pmin}" max="${pmax}" value="${loClamped}" step="1" aria-label="Minimum price">
<input type="range" class="cat-price-range cat-price-range--max" min="${pmin}" max="${pmax}" value="${hiClamped}" step="1" aria-label="Maximum price">
</div>
<div class="flex justify-between gap-2 mt-2 text-xs font-mono" style="color: var(--text-primary);"><span class="cat-price-dual-readout-min">${loClamped}</span><span class="cat-price-dual-readout-max">${hiClamped}</span></div></div>`;
    }
    const dtEntries = [...deliveryCounts.entries()].sort((a, b) => a[0].localeCompare(b[0]));
    const tagEntries = [...tagCounts.entries()]
        .map(([k, v]) => ({ key: k, display: v.display, count: v.count }))
        .sort((a, b) => b.count - a.count || a.display.localeCompare(b.display));

    let deliveryHtml = '';
    if (dtEntries.length > 0) {
        deliveryHtml = `<div class="cat-facet-block cat-facet-block--delivery${isMobile ? ' cat-facet-block--mob' : ''}"><h5 class="cat-facet-heading">Delivery time</h5><div class="cat-facet-list">${dtEntries.map(([label, count]) => {
            const enc = encodeURIComponent(label);
            const checked = activeCategoryFilters.deliveryTimes.has(label) ? ' checked' : '';
            return `<label class="cat-facet-row"><input type="checkbox" class="cat-facet-cb" data-facet="delivery" data-val="${enc}"${checked}><span class="cat-facet-label">${esc(label)}</span><span class="cat-facet-count">(${count})</span></label>`;
        }).join('')}</div></div>`;
    }

    const expressHtml = `<div class="cat-facet-block cat-facet-block--express${isMobile ? ' cat-facet-block--mob' : ''}"><h5 class="cat-facet-heading">Express delivery</h5><div class="cat-facet-list">
<label class="cat-facet-row"><input type="checkbox" class="cat-facet-cb" data-facet="express" data-val="yes"${activeCategoryFilters.express.has('yes') ? ' checked' : ''}><span class="cat-facet-label">Yes</span><span class="cat-facet-count">(${expressYes})</span></label>
<label class="cat-facet-row"><input type="checkbox" class="cat-facet-cb" data-facet="express" data-val="no"${activeCategoryFilters.express.has('no') ? ' checked' : ''}><span class="cat-facet-label">No</span><span class="cat-facet-count">(${expressNo})</span></label>
</div></div>`;

    const freeHtml = `<div class="cat-facet-block cat-facet-block--freeship${isMobile ? ' cat-facet-block--mob' : ''}"><h5 class="cat-facet-heading">Free shipping</h5><div class="cat-facet-list">
<label class="cat-facet-row"><input type="checkbox" class="cat-facet-cb" data-facet="freeShipping" data-val="yes"${activeCategoryFilters.freeShipping.has('yes') ? ' checked' : ''}><span class="cat-facet-label">Yes</span><span class="cat-facet-count">(${freeYes})</span></label>
<label class="cat-facet-row"><input type="checkbox" class="cat-facet-cb" data-facet="freeShipping" data-val="no"${activeCategoryFilters.freeShipping.has('no') ? ' checked' : ''}><span class="cat-facet-label">No</span><span class="cat-facet-count">(${freeNo})</span></label>
</div></div>`;

    let tagsHtml = '';
    if (tagEntries.length > 0) {
        const rows = tagEntries.map(({ key, display, count }, idx) => {
            const extraClass = idx >= TAGS_VISIBLE_DEFAULT ? ' cat-facet-tag-item--extra hidden' : '';
            const checked = activeCategoryFilters.tags.has(key) ? ' checked' : '';
            return `<label class="cat-facet-row cat-facet-tag-item${extraClass}"><input type="checkbox" class="cat-facet-cb" data-facet="tags" data-val="${encodeURIComponent(key)}"${checked}><span class="cat-facet-label">${esc(display)}</span><span class="cat-facet-count">(${count})</span></label>`;
        }).join('');
        const moreBtn = tagEntries.length > TAGS_VISIBLE_DEFAULT
            ? '<button type="button" class="cat-facet-tags-more text-red-600 text-sm font-semibold mt-2 hover:underline">+ See more</button>'
            : '';
        tagsHtml = `<div class="cat-facet-block cat-facet-block--tags${isMobile ? ' cat-facet-block--mob' : ''}"><div class="flex items-center justify-between gap-2 mb-2"><h5 class="cat-facet-heading cat-facet-heading--inline">Tag</h5><i class="fa-solid fa-magnifying-glass text-gray-400 text-sm" aria-hidden="true"></i></div><input type="search" class="cat-facet-tag-search w-full text-sm border rounded px-2 py-1 mb-2" style="border-color: var(--card-border); background: var(--card-bg); color: var(--text-primary);" placeholder="Search tags" autocomplete="off" aria-label="Search tags"><div class="cat-facet-tag-list">${rows}</div>${moreBtn}</div>`;
    }

    const clearBtn = '<button type="button" class="cat-facet-clear w-full mt-4 text-sm py-2 rounded border font-medium" style="border-color: var(--card-border); color: var(--text-primary);">Clear filters</button>';

    const hasPriceBlock = priceHtml.length > 0;
    const hasFacets = hasPriceBlock || dtEntries.length > 0 || tagEntries.length > 0 || (expressYes + expressNo) > 0;
    if (!hasFacets) return '';
    return `<div class="cat-facet-wrap${isMobile ? ' cat-facet-wrap--mob' : ''}">${priceHtml}${deliveryHtml}${expressHtml}${freeHtml}${tagsHtml}${clearBtn}</div>`;
};

const buildCategorySidebarHTML = (categoryName, baseProducts) => {
    const categoriesPart = state.allCategories.length > 0
        ? `<h4 class="font-bold mb-4 uppercase text-xs tracking-wider text-gray-500">Categories</h4><div class="cat-side-list flex flex-col gap-1 mb-5 pb-5 border-b" style="border-color: var(--card-border);">${state.allCategories.map((cat) => {
            const catName = String(cat?.name || '').trim();
            if (!catName) return '';
            const safeName = escapeFacetHtml(catName);
            const catHref = `#/category/${encodeURIComponent(catName)}`;
            const isActive = catName === categoryName;
            const subs = getSubcategoryEntries(cat);
            const hasSubs = subs.length > 0;
            const subsHtml = hasSubs
                ? `<div class="cat-side-flyout" role="region" aria-label="${safeName} subcategories"><div class="cat-side-flyout-title">${safeName}</div><div class="cat-side-flyout-grid">${subs.map((entry) => {
                    const href = `${catHref}?sub=${encodeURIComponent(entry.name)}`;
                    const sty = subcategoryEntryStyleAttr(entry);
                    return `<a class="cat-side-flyout-link" href="${href}"${sty}>${escapeFacetHtml(entry.name)}</a>`;
                }).join('')}</div></div>`
                : '';
            return `<div class="cat-side-row${hasSubs ? ' has-flyout' : ''}"><a href="${catHref}" class="cat-side-link text-sm py-2 px-3 rounded hover:bg-gray-100 flex items-center justify-between group ${isActive ? 'bg-gray-100 font-bold text-red-600' : 'text-gray-700'}"><span>${safeName}</span><i class="fa-solid fa-chevron-right text-[10px] cat-side-chev${hasSubs ? '' : ' cat-side-chev-muted'}" aria-hidden="true"></i></a>${subsHtml}</div>`;
        }).join('')}</div>`
        : '';
    const facets = collectCategoryFacets(baseProducts);
    const facetPart = buildCategoryFacetSectionHTML(facets, false);
    if (!categoriesPart && !facetPart) return '<p class="text-sm text-gray-500">No filters</p>';
    return categoriesPart + (facetPart || '');
};

const bindCategorySidebarFlyouts = (sidebarEl) => {
    if (!sidebarEl) return;
    if (window.innerWidth < 1024) return;
    const margin = 10;
    const pad = 8;
    const reposition = (row, fly) => {
        const rr = row.getBoundingClientRect();
        fly.style.maxHeight = `${Math.min(420, window.innerHeight - margin * 2)}px`;
        fly.style.left = `${Math.round(rr.right + pad)}px`;
        fly.style.top = `${Math.round(rr.top)}px`;
        void fly.offsetHeight;
        const fr = fly.getBoundingClientRect();
        if (fr.right > window.innerWidth - margin) {
            fly.style.left = `${Math.max(margin, window.innerWidth - margin - fr.width)}px`;
        }
        const fr2 = fly.getBoundingClientRect();
        if (fr2.bottom > window.innerHeight - margin) {
            fly.style.top = `${Math.max(margin, window.innerHeight - margin - fr2.height)}px`;
        }
    };
    sidebarEl.querySelectorAll('.cat-side-row.has-flyout').forEach((row) => {
        const fly = row.querySelector('.cat-side-flyout');
        const link = row.querySelector('.cat-side-link');
        if (!fly || !link) return;
        let closeTimer = 0;
        const open = () => {
            if (closeTimer) {
                clearTimeout(closeTimer);
                closeTimer = 0;
            }
            fly.classList.add('is-visible');
            requestAnimationFrame(() => reposition(row, fly));
        };
        const scheduleClose = () => {
            if (closeTimer) clearTimeout(closeTimer);
            closeTimer = window.setTimeout(() => {
                fly.classList.remove('is-visible');
                closeTimer = 0;
            }, 120);
        };
        row.addEventListener('mouseenter', open);
        row.addEventListener('mouseleave', scheduleClose);
        row.addEventListener('focusin', open);
        row.addEventListener('focusout', (ev) => {
            if (row.contains(ev.relatedTarget)) return;
            scheduleClose();
        });
        fly.addEventListener('mouseenter', () => {
            if (closeTimer) {
                clearTimeout(closeTimer);
                closeTimer = 0;
            }
        });
        fly.addEventListener('mouseleave', scheduleClose);
    });
};

const syncCategoryPriceDualUI = (wrap) => {
    if (!wrap) return;
    const minR = wrap.querySelector('.cat-price-range--min');
    const maxR = wrap.querySelector('.cat-price-range--max');
    if (!minR || !maxR) return;
    const pmin = Number(minR.min);
    const pmax = Number(minR.max);
    let lo = Number(minR.value);
    let hi = Number(maxR.value);
    if (lo > hi) {
        const x = lo;
        lo = hi;
        hi = x;
        minR.value = String(lo);
        maxR.value = String(hi);
    }
    lo = Math.min(pmax, Math.max(pmin, lo));
    hi = Math.max(pmin, Math.min(pmax, hi));
    minR.value = String(lo);
    maxR.value = String(hi);
    const span = pmax - pmin || 1;
    const leftPct = ((lo - pmin) / span) * 100;
    const rightPct = ((pmax - hi) / span) * 100;
    wrap.style.setProperty('--cat-price-left', `${leftPct}%`);
    wrap.style.setProperty('--cat-price-right', `${rightPct}%`);
    const block = wrap.closest('.cat-facet-block--price');
    if (block) {
        const labels = block.querySelectorAll('.cat-price-dual-labels span');
        if (labels[0]) labels[0].textContent = `Min: ৳${lo}`;
        if (labels[1]) labels[1].textContent = `Max: ৳${hi}`;
        const r0 = block.querySelector('.cat-price-dual-readout-min');
        const r1 = block.querySelector('.cat-price-dual-readout-max');
        if (r0) r0.textContent = String(lo);
        if (r1) r1.textContent = String(hi);
    }
};

let categoryFacetListenersBound = false;
const bindCategoryFacetListeners = () => {
    if (categoryFacetListenersBound || !doc.categoryView) return;
    categoryFacetListenersBound = true;
    doc.categoryView.addEventListener('change', (e) => {
        const t = e.target;
        if (!t || !t.classList || !t.classList.contains('cat-facet-cb')) return;
        const facet = t.getAttribute('data-facet');
        const val = facet === 'express' || facet === 'freeShipping' ? t.getAttribute('data-val') : decodeURIComponent(t.getAttribute('data-val') || '');
        const checked = t.checked;
        if (facet === 'delivery') {
            if (checked) activeCategoryFilters.deliveryTimes.add(val);
            else activeCategoryFilters.deliveryTimes.delete(val);
        } else if (facet === 'express') {
            if (checked) activeCategoryFilters.express.add(val);
            else activeCategoryFilters.express.delete(val);
        } else if (facet === 'freeShipping') {
            if (checked) activeCategoryFilters.freeShipping.add(val);
            else activeCategoryFilters.freeShipping.delete(val);
        } else if (facet === 'tags') {
            const tagKey = decodeURIComponent(t.getAttribute('data-val') || '');
            if (checked) activeCategoryFilters.tags.add(tagKey);
            else activeCategoryFilters.tags.delete(tagKey);
        }
        const hash = window.location.hash;
        if (!hash.startsWith('#/category/')) return;
        const catSlug = (hash.replace(/^#\/category\//, '').split('?')[0] || '').trim();
        renderCategoryView(decodeURIComponent(catSlug));
    });
    doc.categoryView.addEventListener('click', (e) => {
        const clearBtn = e.target.closest('.cat-facet-clear');
        if (clearBtn) {
            resetActiveCategoryFilters();
            const hash = window.location.hash;
            if (hash.startsWith('#/category/')) {
                const catSlug = (hash.replace(/^#\/category\//, '').split('?')[0] || '').trim();
                renderCategoryView(decodeURIComponent(catSlug));
            }
            return;
        }
        const more = e.target.closest('.cat-facet-tags-more');
        if (more) {
            const block = more.closest('.cat-facet-block--tags');
            if (!block) return;
            block.dataset.tagsExpanded = '1';
            block.querySelectorAll('.cat-facet-tag-item--extra').forEach((el) => el.classList.remove('hidden'));
            more.classList.add('hidden');
        }
    });
    doc.categoryView.addEventListener('input', (e) => {
        const inp = e.target;
        if (inp.classList.contains('cat-price-range')) {
            const wrap = inp.closest('.cat-price-dual-wrap');
            if (!wrap) return;
            const minR = wrap.querySelector('.cat-price-range--min');
            const maxR = wrap.querySelector('.cat-price-range--max');
            if (!minR || !maxR) return;
            if (inp.classList.contains('cat-price-range--min') && Number(minR.value) > Number(maxR.value)) {
                maxR.value = minR.value;
            }
            if (inp.classList.contains('cat-price-range--max') && Number(maxR.value) < Number(minR.value)) {
                minR.value = maxR.value;
            }
            syncCategoryPriceDualUI(wrap);
            const pmin = Number(minR.min);
            const pmax = Number(maxR.max);
            const lo = Number(minR.value);
            const hi = Number(maxR.value);
            if (lo <= pmin && hi >= pmax) {
                activeCategoryFilters.priceRange = { min: null, max: null };
            } else {
                activeCategoryFilters.priceRange = { min: lo, max: hi };
            }
            const hash = window.location.hash;
            if (!hash.startsWith('#/category/')) return;
            const catSlug = (hash.replace(/^#\/category\//, '').split('?')[0] || '').trim();
            renderCategoryView(decodeURIComponent(catSlug));
            return;
        }
        if (!inp.classList.contains('cat-facet-tag-search')) return;
        const block = inp.closest('.cat-facet-block--tags');
        if (!block) return;
        const q = String(inp.value || '').trim().toLowerCase();
        const expanded = block.dataset.tagsExpanded === '1';
        block.querySelectorAll('.cat-facet-tag-item').forEach((label) => {
            const text = (label.querySelector('.cat-facet-label')?.textContent || '').toLowerCase();
            const isExtra = label.classList.contains('cat-facet-tag-item--extra');
            if (q.length > 0) {
                label.classList.remove('hidden');
                label.style.display = text.includes(q) ? '' : 'none';
            } else {
                label.style.display = '';
                if (isExtra && !expanded) label.classList.add('hidden');
                else if (isExtra && expanded) label.classList.remove('hidden');
            }
        });
    });
};

const syncCategorySortSelects = (val) => {
    if (doc.catSortSelect) doc.catSortSelect.value = val;
    if (doc.catSortSelectMobile) doc.catSortSelectMobile.value = val;
};

// --- STATE MANAGEMENT FOR WISHLIST & COMPARE ---
let wishlistState = JSON.parse(localStorage.getItem('site_wishlist') || '[]');
let compareState = JSON.parse(localStorage.getItem('site_compare') || '[]');

// --- NEW: USER PROFILE STATE ---
const getBrowserName = () => {
    const agent = navigator.userAgent;
    if (agent.includes("Chrome")) return "Chrome";
    if (agent.includes("Firefox")) return "Firefox";
    if (agent.includes("Safari")) return "Safari";
    if (agent.includes("Edg")) return "Edge";
    return "Unknown Browser";
};

const getDeviceType = () => {
    const agent = navigator.userAgent;
    if (/Android/i.test(agent)) return "Android Mobile";
    if (/iPhone|iPad|iPod/i.test(agent)) return "iOS Device";
    if (/Windows/i.test(agent)) return "Windows PC";
    if (/Mac/i.test(agent)) return "Macintosh";
    return "Desktop";
};

// Initialize Profile Data
let userProfile = JSON.parse(localStorage.getItem('site_user_profile')) || {
    id: `GST-${Math.floor(1000 + Math.random() * 9000)}`,
    name: "Guest User",
    joinDate: new Date().toLocaleDateString(),
    visits: 0,
    views: 0,
    orders: 0,
    device: getDeviceType(),
    browser: getBrowserName()
};

// Increment Visit Count on Load
if (!sessionStorage.getItem('visit_counted')) {
    userProfile.visits += 1;
    userProfile.device = getDeviceType(); 
    userProfile.browser = getBrowserName();
    localStorage.setItem('site_user_profile', JSON.stringify(userProfile));
    sessionStorage.setItem('visit_counted', 'true');
}

const updateProfileActivity = (type) => {
    if (type === 'view') userProfile.views += 1;
    if (type === 'order') userProfile.orders += 1;
    localStorage.setItem('site_user_profile', JSON.stringify(userProfile));
};

// --- LOCAL HELPER: FORCE ENGLISH PRICE FORMAT ---
const formatPrice = (amount) => {
    return new Intl.NumberFormat('en-US', {
        minimumFractionDigits: 0,
        maximumFractionDigits: 0
    }).format(amount) + ' ৳';
};

// --- Product price for display: sale + regular (for strikethrough). Same logic everywhere.
const getProductDisplayPrices = (p) => {
    let displayPrice = p != null && (p.salePrice != null) ? Number(p.salePrice) : 0;
    let regularPrice = p != null && p.regularPrice != null && p.regularPrice > 0 ? Number(p.regularPrice) : 0;
    if (p && p.hasVariants && p.variants && typeof p.variants === 'object') {
        const vars = Object.values(p.variants).filter(v => v && (v.salePrice != null));
        if (vars.length > 0) {
            const minSale = Math.min(...vars.map(v => Number(v.salePrice)));
            if (!Number.isNaN(minSale)) displayPrice = minSale;
            const prices = vars.map(v => (v.regularPrice != null && Number(v.regularPrice) > Number(v.salePrice)) ? Number(v.regularPrice) : Number(v.salePrice));
            const maxRegular = Math.max(...prices);
            if (!Number.isNaN(maxRegular) && maxRegular > displayPrice) regularPrice = maxRegular;
        }
    }
    return { displayPrice: Number.isNaN(displayPrice) ? 0 : displayPrice, regularPrice: Number.isNaN(regularPrice) ? 0 : regularPrice };
};

// --- Build price HTML: red strikethrough old, then sale price (when regular > sale)
const getPriceHtml = (p, saleClass = 'text-[#f20c33] font-bold') => {
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    if (regularPrice > displayPrice) {
        return `<span class="text-red-500 line-through text-sm mr-1">${formatPrice(regularPrice)}</span><span class="${saleClass}">${formatPrice(displayPrice)}</span>`;
    }
    return `<span class="${saleClass}">${formatPrice(displayPrice)}</span>`;
};

/** Compact product-list flyout for Shwapno PC `#desktop-category-sidebar` (desktop hover). */
const buildShwapnoDesktopProductFlyoutHtml = (catName, products, escAttr, escText) => {
    if (!products || !products.length) return '';
    const rows = products
        .map((p) => {
            const navUrl = getLandingPageUrlForProduct(p) || `#/product/${p.id}`;
            const ext = /^https?:\/\//i.test(navUrl) ? ' target="_blank" rel="noopener noreferrer"' : '';
            const img = escAttr(String((p.imageUrl || '').trim()));
            const name = escText(p.name || '');
            const priceInner = getPriceHtml(p, 'shwapno-flyout-price-sale');
            return `<a class="shwapno-flyout-link shwapno-flyout-product-row" href="${escAttr(navUrl)}"${ext}><span class="shwapno-flyout-product-thumb"><img src="${img}" alt="" loading="lazy" decoding="async"></span><span class="shwapno-flyout-product-meta"><span class="shwapno-flyout-product-name">${name}</span><span class="shwapno-flyout-product-price">${priceInner}</span></span></a>`;
        })
        .join('');
    return `<div class="shwapno-flyout shwapno-flyout--products" role="region" aria-label="${escAttr(`${catName} products`)}"><div class="shwapno-flyout-title">${escText(catName)}</div><div class="shwapno-flyout-products">${rows}</div></div>`;
};

// --- NEW: YOUTUBE ID EXTRACTOR HELPER ---
const extractVideoID = (url) => {
    const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
    const match = url.match(regExp);
    return (match && match[2].length === 11) ? match[2] : null;
};

// ============================================================
// 0. DATA LAYER & GTM HELPERS
// ============================================================

const initGTM = (gtmId) => {
    if (!gtmId) return;
    (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer',gtmId);
};

const pushToDataLayer = (eventName, data) => {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({ ecommerce: null });
    const payload = { event: eventName, ecommerce: data };
    window.dataLayer.push(payload);
};

// ============================================================
// 0.1 INJECT ACTION MODALS
// ============================================================
const injectActionModals = () => {
    if (!document.getElementById('full-screen-search-overlay')) {
        const searchHtml = `
        <div id="full-screen-search-overlay" class="fixed inset-0 bg-white z-[9999] hidden flex flex-col animate-[fadeIn_0.2s_ease-out]">
            <div style="background-color: var(--btn-primary-bg); padding: 15px 15px 25px 15px;" class="shadow-md">
                <div class="flex justify-between items-center mb-3">
                    <p class="text-white text-xs font-medium">Type a few things below to search</p>
                    <button id="close-search-overlay" class="text-white hover:text-gray-200 w-8 h-8 flex items-center justify-center rounded-full active:bg-black/20 transition">
                        <i class="fa-solid fa-xmark text-xl"></i>
                    </button>
                </div>
                <div class="relative w-full">
                    <i class="fa-solid fa-magnifying-glass absolute left-3 top-1/2 -translate-y-1/2 text-gray-500 z-10 pointer-events-none" aria-hidden="true"></i>
                    <input type="text" id="real-mobile-search-input" placeholder="Search for products..." 
                        class="w-full pl-10 pr-4 py-3 rounded-md border-none outline-none text-sm font-medium text-gray-800 shadow-inner focus:ring-2 ring-green-300 transition" autocomplete="off">
                </div>
            </div>
            <div class="p-5 flex-grow overflow-y-auto bg-gray-50">
                <p class="text-xs text-gray-500 font-bold mb-6 border-b pb-2">Out of a total of <span id="total-products-count" class="text-green-600">0</span> products:</p>
                <div id="default-search-view">
                    <p class="text-sm font-bold text-gray-800 mb-3">Trending:</p>
                    <div id="trending-tags-container" class="flex flex-wrap gap-2 mb-6"></div>
                </div>
                <div id="live-search-results" class="hidden space-y-2"></div>
            </div>
        </div>`;
        document.body.insertAdjacentHTML('beforeend', searchHtml);
    }

    if (!document.getElementById('quick-view-modal')) {
        const qvHtml = `
        <div id="quick-view-modal" class="fixed inset-0 z-[10000] hidden flex items-center justify-center p-4" style="background-color: rgba(0,0,0,0.6); backdrop-filter: blur(3px);">
            <div class="bg-white rounded-lg shadow-2xl w-full max-w-3xl overflow-hidden relative animate-[fadeIn_0.2s_ease-out]">
                <button onclick="document.getElementById('quick-view-modal').classList.add('hidden')" class="absolute top-2 right-2 w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center hover:bg-red-50 hover:text-red-500 transition z-10"><i class="fa-solid fa-xmark"></i></button>
                <div class="grid md:grid-cols-2">
                    <div class="bg-gray-50 p-6 flex items-center justify-center border-r"><img id="qv-img" class="max-h-[300px] object-contain mix-blend-multiply"></div>
                    <div class="p-6 flex flex-col justify-center">
                        <h3 id="qv-title" class="text-xl font-bold mb-2 text-gray-800"></h3>
                        <p id="qv-price" class="text-2xl font-extrabold text-[#f20c33] mb-4"></p>
                        <p id="qv-desc" class="text-sm text-gray-500 mb-6 line-clamp-3"></p>
                        <button id="qv-add-btn" class="w-full py-3 text-white font-bold rounded hover:opacity-90 transition" style="background-color: var(--btn-primary-bg);">Add to Cart</button>
                        <button id="qv-details-btn" class="w-full mt-3 py-2 border border-gray-300 font-bold rounded hover:bg-gray-50 transition">View Full Details</button>
                    </div>
                </div>
            </div>
        </div>`;
        document.body.insertAdjacentHTML('beforeend', qvHtml);
    }

    if (!document.getElementById('compare-modal')) {
        const compareHtml = `
        <div id="compare-modal" class="fixed inset-0 z-[10000] hidden flex items-center justify-center p-4" style="background-color: rgba(0,0,0,0.6); backdrop-filter: blur(3px);">
            <div class="bg-white rounded-lg shadow-2xl w-full max-w-4xl max-h-[90vh] overflow-hidden flex flex-col animate-[fadeIn_0.2s_ease-out]">
                <div class="p-4 border-b flex justify-between items-center bg-gray-50">
                    <h3 class="font-bold text-lg"><i class="fa-solid fa-scale-balanced mr-2"></i>Product Comparison</h3>
                    <button onclick="document.getElementById('compare-modal').classList.add('hidden')" class="w-8 h-8 bg-white border rounded-full hover:bg-red-50 hover:text-red-500 transition"><i class="fa-solid fa-xmark"></i></button>
                </div>
                <div class="p-0 overflow-hidden flex-grow relative">
                    <div id="compare-content" class="w-full h-full overflow-auto bg-gray-50"></div>
                </div>
            </div>
        </div>`;
        document.body.insertAdjacentHTML('beforeend', compareHtml);
    }
};

// ============================================================
// 1. DOM INITIALIZATION
// ============================================================
const initDOM = () => {
    injectActionModals();

    // Main Views
    doc.homeView = getEl('home-view');
    doc.detailView = getEl('product-detail-view');
    doc.checkoutView = getEl('checkout-view');
    doc.thankYouView = getEl('thank-you-view');
    doc.categoryView = getEl('category-view');
    doc.profileView = getEl('profile-view');
    
    // Policy & Content View Elements
    doc.policyView = getEl('policy-view');
    doc.policyTitle = getEl('policy-title');
    doc.policyContent = getEl('policy-content');

    // Category Elements
    doc.categoryGrid = getEl('category-products-grid');
    doc.catHeaderTitle = getEl('cat-header-title');
    doc.catBreadcrumb = getEl('cat-breadcrumb-name');
    doc.catCount = getEl('cat-product-count');
    doc.catSortSelect = getEl('category-sort-select');
    doc.catSidebar = getEl('category-sidebar');
    doc.categorySubnavBar = getEl('category-subnav-bar');
    doc.categorySubnavInner = getEl('category-subnav-inner');
    doc.catDescription = getEl('cat-description');
    doc.categoryHeroBanner = getEl('category-hero-banner');
    doc.categoryHeroBannerImg = getEl('category-hero-banner-img');
    doc.categoryFilterSheet = getEl('category-filter-sheet');
    doc.categoryFilterSheetInner = getEl('category-filter-sheet-inner');
    doc.categoryFilterSheetBackdrop = getEl('category-filter-sheet-backdrop');
    doc.categoryFilterSheetClose = getEl('category-filter-sheet-close');
    doc.categoryFilterOpenBtn = getEl('category-filter-open-btn');
    doc.catSortSelectMobile = getEl('category-sort-select-mobile');

    // Home Sections
    doc.pcHeroSection = getEl('pc-hero-section'); 
    doc.mobileHeroSection = getEl('mobile-hero-section');
    doc.catRowsContainer = getEl('category-rows-container');
    doc.mainProductGrid = getEl('main-product-grid');
    doc.justForYouSection = getEl('just-for-you-section');
    doc.flashSection = getEl('flash-sale-section');
    doc.promoBanner1 = getEl('promo-banner-middle-1'); 
    doc.promoBanner2 = getEl('promo-banner-middle-2'); 
    doc.homepageFeaturesSectionMobile = getEl('homepage-features-section-mobile');
    doc.homepageFeaturesGridMobile = getEl('homepage-features-grid-mobile');
    doc.homepageFeaturesSectionDesktop = getEl('homepage-features-section-desktop');
    doc.homepageFeaturesGridDesktop = getEl('homepage-features-grid-desktop');
    doc.recommendedForYouSectionDesktop = getEl('recommended-for-you-section-desktop');
    doc.recommendedForYouSectionMobile = getEl('recommended-for-you-section-mobile');
    doc.recommendedForYouTitleDesktop = getEl('recommended-for-you-title-desktop');
    doc.recommendedForYouTitleMobile = getEl('recommended-for-you-title-mobile');
    doc.recommendedForYouWrapperDesktop = getEl('recommended-for-you-wrapper-desktop');
    doc.recommendedForYouWrapperMobile = getEl('recommended-for-you-wrapper-mobile');
    doc.recommendedForYouSwiperDesktop = getEl('recommended-for-you-swiper-desktop');
    doc.recommendedForYouSwiperMobile = getEl('recommended-for-you-swiper-mobile');
    doc.categoryBannerSectionDesktop = getEl('category-banner-section-desktop');
    doc.categoryBannerSectionMobile = getEl('category-banner-section-mobile');
    doc.categoryBannerTitleWrapDesktop = getEl('category-banner-title-wrap-desktop');
    doc.categoryBannerTitleWrapMobile = getEl('category-banner-title-wrap-mobile');
    doc.categoryBannerSectionTitleDesktop = getEl('category-banner-section-title-desktop');
    doc.categoryBannerSectionTitleMobile = getEl('category-banner-section-title-mobile');
    doc.categoryBannerAsideDesktop = getEl('category-banner-aside-desktop');
    doc.categoryBannerAsideMobile = getEl('category-banner-aside-mobile');
    doc.categoryBannerLinkDesktop = getEl('category-banner-link-desktop');
    doc.categoryBannerLinkMobile = getEl('category-banner-link-mobile');
    doc.categoryBannerImgDesktop = getEl('category-banner-img-desktop');
    doc.categoryBannerImgMobile = getEl('category-banner-img-mobile');
    doc.homeAnnouncementStrip = getEl('home-announcement-strip');
    doc.homeAnnouncementStripMobile = getEl('home-announcement-strip-mobile');
    doc.homeNewArrivalBandMobile = getEl('home-new-arrival-band-mobile');
    doc.homeNewArrivalCategoryGridMobile = getEl('home-new-arrival-category-grid-mobile');
    doc.homeFabrilifePostGridBanners = getEl('home-fabrilife-post-grid-banners');
    
    // Swiper Wrappers
    doc.desktopSidebar = getEl('desktop-category-sidebar');
    doc.pcBannerWrapper = getEl('pc-banner-wrapper');
    doc.pcCategoryWrapper = getEl('pc-category-wrapper');
    doc.pcSliderArea = getEl('pc-slider-area');
    doc.pcSmallBanners = getEl('pc-small-banners');
    
    doc.mobileBannerWrapper = getEl('mobile-banner-wrapper');
    doc.mobileCategoryWrapper = getEl('mobile-category-wrapper');
    doc.mobileSliderArea = getEl('mobile-slider-area');
    doc.mobileSmallBanners = getEl('mobile-small-banners');
    
    // Drawers & Nav
    doc.mobileDrawer = getEl('mobile-nav-drawer');
    doc.mobileDrawerContent = getEl('mobile-drawer-content');
    doc.cartDrawer = getEl('cart-drawer');
    doc.overlay = getEl('cart-overlay'); 
    doc.bottomNav = getEl('bottom-nav-classic'); 
    doc.allCategoriesBtn = document.querySelector('.all-categories-btn');
    
    // Header Inputs & Badges
    doc.desktopSearchInput = getEl('desktop-search-input');
    doc.desktopSearchResults = getEl('desktop-search-results');
    doc.desktopSearchBtn = document.querySelector('.desktop-search-btn'); 
    doc.headerWishlistCount = getEl('header-wishlist-count'); 
    doc.headerCompareCount = getEl('header-compare-count'); 
    
    // Header Interactive
    doc.headerLocationBtn = getEl('header-location-btn');
    doc.headerLocationText = getEl('header-location-text');
    doc.locationIcon = getEl('location-icon');
    doc.locationSpinner = getEl('location-spinner');
    doc.desktopCategoryDropdown = getEl('desktop-category-dropdown');
    doc.btnBrowseCategories = getEl('btn-browse-categories');
    doc.desktopNavContainer = getEl('desktop-nav-container'); // NEW Container
    doc.desktopFabrilifeInlineNav = getEl('desktop-fabrilife-inline-nav');

    // Mobile Search
    doc.mobileSearchInput = getEl('mobile-search-input');
    doc.mobileSearchResults = getEl('mobile-search-results');
    doc.mobileSearchBtn = document.querySelector('.mobile-search-box button'); 
    
    doc.searchOverlay = getEl('full-screen-search-overlay');
    doc.realSearchInput = getEl('real-mobile-search-input');
    doc.closeSearchBtn = getEl('close-search-overlay');
    doc.totalProductsCount = getEl('total-products-count');
    doc.trendingContainer = getEl('trending-tags-container');
    doc.defaultSearchView = getEl('default-search-view');
    doc.liveSearchResults = getEl('live-search-results');
    
    doc.flashContainer = getEl('flash-products-container');
    
    // Product Detail Elements
    doc.detailMainImg = getEl('detail-main-img');
    doc.detailVideoPlayer = getEl('detail-video-player'); 
    doc.zoomContainer = document.querySelector('.zoom-container');
    doc.detailThumbnails = getEl('detail-thumbnails');
    doc.detailTitle = getEl('detail-title');
    doc.detailPriceBox = getEl('detail-price-box');
    doc.detailDesc = getEl('detail-description');
    doc.detailVariants = getEl('detail-variants');
    doc.relatedContainer = getEl('related-products-container');
    doc.detailSku = getEl('detail-sku');
    doc.detailBrand = getEl('detail-brand');
    doc.detailShortDesc = getEl('detail-short-desc');
    doc.detailSelectedVarName = getEl('detail-selected-variant-name');
    doc.detailVariantLabel = getEl('detail-variant-label');
    
    doc.sizeChartModal = getEl('size-chart-modal');
    doc.sizeChartImg = getEl('size-chart-img');
    doc.closeSizeChartBtn = getEl('close-size-chart-btn');
    doc.sizeChartTriggerBtn = getEl('size-chart-trigger-btn');
    
    doc.fomoContainer = getEl('fomo-container');
    doc.fomoText = getEl('fomo-text');
    doc.fomoBar = getEl('fomo-stock-bar');
    
    doc.scrollTopBtn = getEl('scroll-top-btn');
    
    doc.detailQtyInput = getEl('detail-qty-input');
    doc.detailQtyMinus = getEl('detail-qty-minus');
    doc.detailQtyPlus = getEl('detail-qty-plus');
    doc.detailCtaBar = getEl('detail-cta-bar');
    
    doc.btnCall = getEl('btn-call-now');
    doc.btnWhatsapp = getEl('btn-whatsapp');
    doc.btnMessenger = getEl('btn-messenger');
    
    doc.checkoutForm = getEl('checkout-form');
    doc.shippingContainer = getEl('shipping-options-container');
    doc.orderSummary = getEl('checkout-order-summary');
    doc.mobileCheckoutBar = getEl('mobile-checkout-bar');
    doc.mobileCheckoutTotal = getEl('mobile-checkout-total');
    doc.inputName = getEl('customer-name');
    doc.inputPhone = getEl('customer-phone');
    doc.inputAddress = getEl('customer-address');
    doc.loadingOverlay = getEl('loading-overlay');
};

// Progressive product load: first batch on screen, rest on scroll
const HOME_BATCH_SIZE = 8;
const CATEGORY_BATCH_SIZE = 12;
/** First N product cards in a grid/list get eager + fetchpriority=high (tune with Lighthouse). */
const STORE_GRID_PRIORITY_COUNT = 6;
/** First N home category icons (global index) get eager + high priority. */
const STORE_CAT_ICON_PRIORITY_COUNT = 5;
const getStorefrontConnectionHint = () => {
    try {
        const c = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
        return {
            saveData: !!(c && c.saveData),
            effectiveType: String((c && c.effectiveType) || '').toLowerCase(),
            deviceMemory: Number(navigator.deviceMemory || 0)
        };
    } catch (_) {
        return { saveData: false, effectiveType: '', deviceMemory: 0 };
    }
};

const shouldUseLeanAboveFoldMode = (settings) => {
    const mode = String(settings?.layout?.instantLoadLeanMode || 'auto').toLowerCase();
    if (mode === 'off' || mode === 'disabled') return false;
    if (mode === 'on' || mode === 'enabled') return true;
    const hint = getStorefrontConnectionHint();
    const slowNetwork = hint.saveData || hint.effectiveType.includes('2g') || hint.effectiveType.includes('3g');
    const lowMemory = hint.deviceMemory > 0 && hint.deviceMemory <= 2;
    return slowNetwork || lowMemory;
};

let homeProductList = [];
let homeProductRenderedCount = 0;
let homeGridObserver = null;
let recommendedSwiperDesktop = null;
let recommendedSwiperMobile = null;
let categoryBannerSwiperDesktop = null;
let categoryBannerSwiperMobile = null;
let categoryBannerTabDelegateBound = false;
/** Rebuilt each `renderCategoryBannerSectionHome` for delegated tab clicks. */
let categoryBannerRuntime = null;
/** Home manual category rows (layout.homeCategoryRowsSection.mode === manualTabs). */
let homeManualCatRowsSwiper = null;
let homeManualCatRowsDelegateBound = false;
let homeManualCatRowsRuntime = null;
let categoryProductList = [];
let categoryProductRenderedCount = 0;
let categoryGridObserver = null;
let homeDeferredHydrationTimer = null;
let homeDeferredHydrationPending = false;

const cancelDeferredHomeHydration = () => {
    if (homeDeferredHydrationTimer) {
        clearTimeout(homeDeferredHydrationTimer);
        homeDeferredHydrationTimer = null;
    }
    homeDeferredHydrationPending = false;
};

const scheduleDeferredHomeHydration = () => {
    if (homeDeferredHydrationPending) return;
    homeDeferredHydrationPending = true;
    let done = false;
    const runHydration = () => {
        if (done) return;
        done = true;
        homeDeferredHydrationPending = false;
        homeDeferredHydrationTimer = null;
        const h = window.location.hash || '';
        if (h !== '#/shop' && h !== '') return;
        renderHome({ forceFull: true });
    };
    if (typeof window.requestIdleCallback === 'function') {
        window.requestIdleCallback(runHydration, { timeout: 1600 });
        homeDeferredHydrationTimer = setTimeout(runHydration, 1800);
    } else {
        homeDeferredHydrationTimer = setTimeout(runHydration, 900);
    }
};

// ============================================================
// 1.1 ACTION FUNCTIONS
// ============================================================

const hideAllViews = () => {
    closeCategoryFilterSheet();
    // List of all main containers
    const views = [
        doc.homeView, 
        doc.detailView, 
        doc.checkoutView, 
        doc.thankYouView, 
        doc.categoryView, 
        doc.profileView, 
        doc.policyView
    ];
    
    // Force hide all
    views.forEach(el => {
        if(el) el.classList.add('hidden');
    });

    // Explicitly hide Home Components
    if(doc.pcHeroSection) doc.pcHeroSection.classList.add('hidden');
    if(doc.mobileHeroSection) doc.mobileHeroSection.classList.add('hidden');
    if(doc.catRowsContainer) doc.catRowsContainer.classList.add('hidden');
    if(doc.flashSection) doc.flashSection.classList.add('hidden');
    if(doc.promoBanner1) doc.promoBanner1.classList.add('hidden');
    if(doc.promoBanner2) doc.promoBanner2.classList.add('hidden');
    if(doc.justForYouSection) doc.justForYouSection.classList.add('hidden');
    
    // Hide search overlays
    if(doc.searchOverlay) doc.searchOverlay.classList.add('hidden');
    if(doc.desktopSearchResults) doc.desktopSearchResults.classList.add('hidden');
};

/** On home route: show only PC hero on desktop, only mobile hero on mobile (viewport < 768px). */
const applyHomeHeroVisibility = () => {
    if (!doc.pcHeroSection || !doc.mobileHeroSection) return;
    if (isClassicHomeCatalogWaiting()) {
        doc.pcHeroSection.classList.add('hidden');
        doc.mobileHeroSection.classList.add('hidden');
        return;
    }
    const isMobile = window.matchMedia('(max-width: 767px)').matches;
    doc.pcHeroSection.classList.toggle('hidden', isMobile);
    doc.mobileHeroSection.classList.toggle('hidden', !isMobile);
};

const updateHeaderBadges = () => {
    document.querySelectorAll('.header-wishlist-badge').forEach((el) => { el.textContent = wishlistState.length; });
    if(doc.headerCompareCount) doc.headerCompareCount.textContent = compareState.length;
};

/** Empty location CTA on PC header (Shwapno uses Swapno-style copy). */
const getHeaderLocationEmptyLabel = () => (
    state.siteSettings?.layout?.headerDesign === 'shwapno'
        ? 'Select your delivery location'
        : 'Select Location'
);

/** After reverse geocode: Shwapno shows short line; default uses "Deliver to:" prefix. */
const formatHeaderResolvedLocation = (locationName) => {
    const name = String(locationName || '').trim();
    if (state.siteSettings?.layout?.headerDesign === 'shwapno') {
        return name.length > 36 ? `${name.slice(0, 33)}…` : name;
    }
    return `Deliver to: ${name}`;
};

// OpenStreetMap Location Service
const initLocationService = () => {
    const savedLocation = localStorage.getItem('site_user_location');
    if(savedLocation && doc.headerLocationText) {
        doc.headerLocationText.textContent = savedLocation;
    }

    if (doc.headerLocationBtn) {
        doc.headerLocationBtn.addEventListener('click', () => {
            if (!navigator.geolocation) {
                showToast("Geolocation not supported", "error");
                return;
            }
            if(doc.locationIcon) doc.locationIcon.classList.add('hidden');
            if(doc.locationSpinner) doc.locationSpinner.classList.remove('hidden');
            doc.headerLocationText.textContent = "Locating...";

            navigator.geolocation.getCurrentPosition(
                async (position) => {
                    const { latitude, longitude } = position.coords;
                    try {
                        const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}`);
                        const data = await response.json();
                        const city = data.address.city || data.address.town || data.address.village || data.address.state_district;
                        const suburb = data.address.suburb || data.address.neighbourhood;
                        const locationName = suburb ? `${suburb}, ${city}` : city;

                        doc.headerLocationText.textContent = formatHeaderResolvedLocation(locationName);
                        localStorage.setItem('site_user_location', locationName);
                        showToast(`Location set to ${locationName}`, "success");
                    } catch (error) {
                        doc.headerLocationText.textContent = getHeaderLocationEmptyLabel();
                        showToast("Failed to fetch address", "error");
                    } finally {
                        if(doc.locationIcon) doc.locationIcon.classList.remove('hidden');
                        if(doc.locationSpinner) doc.locationSpinner.classList.add('hidden');
                    }
                },
                () => {
                    doc.headerLocationText.textContent = getHeaderLocationEmptyLabel();
                    if(doc.locationIcon) doc.locationIcon.classList.remove('hidden');
                    if(doc.locationSpinner) doc.locationSpinner.classList.add('hidden');
                    showToast("Permission denied", "error");
                }
            );
        });
    }
};

const initDarkMode = () => {
    const isDark = localStorage.getItem('site_theme') === 'dark';
    if(isDark) document.documentElement.classList.add('dark-mode');
};

// NEW: Render Desktop Menu – either Sections (Home, Products…) or Category names (from Customization)
const renderDesktopMenu = () => {
    const settings = state.siteSettings || {};
    const layout = settings.layout || {};
    const isCenterTrade = layout.headerDesign === 'centerTrade';
    const menuConfig = layout.menuConfig ? layout.menuConfig : {};
    const headerNavType = (menuConfig.headerNavType === 'sections')
        ? 'sections'
        : (menuConfig.headerNavType === 'customCategories' ? 'customCategories' : 'categories');
    /** Strip links: legacy string entries, or `{ label, target }` where label is shown and target is the inventory category name for the URL. */
    const normalizeMenuCustomCategories = (raw) => {
        if (raw == null) return [];
        const arr = Array.isArray(raw) ? raw : (typeof raw === 'object' ? Object.values(raw) : [raw]);
        const out = [];
        arr.forEach((item) => {
            if (typeof item === 'string') {
                const t = String(item).trim();
                if (t) out.push({ label: t, hrefName: t });
                return;
            }
            if (item && typeof item === 'object') {
                const target = String(item.target ?? item.category ?? item.hrefName ?? '').trim();
                const labelRaw = item.label != null ? String(item.label).trim() : '';
                if (!target && !labelRaw) return;
                const hrefName = target || labelRaw;
                const label = labelRaw || target;
                out.push({ label, hrefName });
            }
        });
        return out;
    };
    const customCategoryLinks = normalizeMenuCustomCategories(menuConfig.customCategories);

    const sections = [
        { label: 'Home', href: '#/shop', icon: 'fa-house' },
        { label: 'Products', href: '#/shop', icon: 'fa-bag-shopping' },
        { label: 'Featured', href: '#/featured', icon: 'fa-star' },
        { label: 'Categories', href: '#/categories', icon: 'fa-th-large' }
    ];

    const inlineEl = doc.desktopFabrilifeInlineNav || getEl('desktop-fabrilife-inline-nav');

    if (isCenterTrade) {
        if (doc.desktopNavContainer) doc.desktopNavContainer.innerHTML = '';
        if (inlineEl) {
            if (headerNavType === 'sections') {
                inlineEl.innerHTML = sections.map((s) => `
                <a href="${s.href}" class="desktop-fabrilife-nav-link">${String(s.label).replace(/</g, '&lt;')}</a>
            `).join('');
            } else if (headerNavType === 'customCategories' && customCategoryLinks.length > 0) {
                inlineEl.innerHTML = customCategoryLinks.map((link) => `
                <a href="#/category/${encodeURIComponent(link.hrefName)}" class="desktop-fabrilife-nav-link">${String(link.label).replace(/</g, '&lt;')}</a>
            `).join('');
            } else if (headerNavType === 'categories' && getMenuCategories().length > 0) {
                const categoriesToShow = getMenuCategories().slice(0, 8);
                inlineEl.innerHTML = categoriesToShow.map((cat) => `
                <a href="#/category/${encodeURIComponent(cat.name)}" class="desktop-fabrilife-nav-link">${String(cat.name).replace(/</g, '&lt;')}</a>
            `).join('');
            } else {
                inlineEl.innerHTML = '';
            }
        }
    } else {
        if (inlineEl) inlineEl.innerHTML = '';
        if (doc.desktopNavContainer) {
            if (headerNavType === 'sections') {
                doc.desktopNavContainer.innerHTML = sections.map((s) => `
                <a href="${s.href}" class="menu-bar-link whitespace-nowrap flex items-center gap-1 hover:text-gray-900 transition text-[14px] font-semibold text-[var(--menu-text)]">
                    <i class="fa-solid ${s.icon} text-xs opacity-70"></i> ${s.label}
                </a>
            `).join('');
            } else if (headerNavType === 'customCategories' && customCategoryLinks.length > 0) {
                doc.desktopNavContainer.innerHTML = customCategoryLinks.map((link) => `
                <a href="#/category/${encodeURIComponent(link.hrefName)}" class="menu-bar-link whitespace-nowrap flex items-center gap-1 hover:text-gray-900 transition text-[14px] font-semibold text-[var(--menu-text)]">
                    ${String(link.label).replace(/</g, '&lt;')}
                </a>
            `).join('');
            } else if (headerNavType === 'categories' && getMenuCategories().length > 0) {
                const categoriesToShow = getMenuCategories().slice(0, 8);
                doc.desktopNavContainer.innerHTML = categoriesToShow.map((cat) => `
                <a href="#/category/${encodeURIComponent(cat.name)}" class="menu-bar-link whitespace-nowrap flex items-center gap-1 hover:text-gray-900 transition text-[14px] font-semibold text-[var(--menu-text)]">
                    ${String(cat.name).replace(/</g, '&lt;')}
                </a>
            `).join('');
            } else {
                doc.desktopNavContainer.innerHTML = '';
            }
        }
    }

    if ((state.siteSettings?.layout?.headerDesign) === 'shwapno') renderShwapnoCategoryPills();
};

const initPCDropdown = () => {
    if(!doc.btnBrowseCategories || !doc.desktopCategoryDropdown) return;
    
    // Clear and populate
    const menuCats = getMenuCategories();
    if (menuCats.length > 0) {
        const escAttrMenu = (s) => String(s ?? '')
            .replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
        doc.desktopCategoryDropdown.innerHTML = menuCats.map(cat => `
            <div class="flex items-center gap-3 p-3 hover:bg-gray-50 cursor-pointer border-b last:border-0 transition"
                 onclick="window.location.hash='#/category/${cat.name}'; document.getElementById('desktop-category-dropdown').classList.add('hidden');">
                <img src="${escAttrMenu(cat.iconUrl || cat.imageUrl)}" class="w-6 h-6 object-contain">
                <span class="text-sm font-medium text-gray-700">${cat.name}</span>
            </div>
        `).join('');
    }

    // Toggle Logic
    doc.btnBrowseCategories.onclick = (e) => {
        e.stopPropagation();
        e.preventDefault();
        doc.desktopCategoryDropdown.classList.toggle('hidden');
        doc.desktopCategoryDropdown.classList.toggle('flex');
    };

    // Close on click outside
    document.addEventListener('click', (e) => {
        if(!doc.btnBrowseCategories.contains(e.target) && !doc.desktopCategoryDropdown.contains(e.target)) {
            doc.desktopCategoryDropdown.classList.add('hidden');
            doc.desktopCategoryDropdown.classList.remove('flex');
        }
    });
};

window.toggleWishlist = (id) => {
    const index = wishlistState.indexOf(id);
    if (index === -1) {
        wishlistState.push(id);
        showToast("Added to Wishlist", "success");
        try {
            const pid = String(id);
            const product = (state.allProducts || []).find((p) => String(p.id) === pid);
            if (product) {
                trackPixelEvent('AddToWishlist', {
                    content_ids: [pid],
                    content_name: product.name,
                    content_type: 'product',
                    value: Number(product.salePrice) || 0,
                    currency: 'BDT'
                });
            } else {
                trackPixelEvent('AddToWishlist', { content_ids: [pid], content_type: 'product', currency: 'BDT' });
            }
        } catch (_) { /* noop */ }
    } else {
        wishlistState.splice(index, 1);
        showToast("Removed from Wishlist", "error");
    }
    localStorage.setItem('site_wishlist', JSON.stringify(wishlistState));
    updateHeaderBadges();
    
    document.querySelectorAll(`.wishlist-btn-${id}`).forEach(btn => {
        if(index === -1) {
            btn.classList.remove('text-gray-600', 'bg-white');
            btn.classList.add('text-white', 'bg-[#f20c33]', 'border-[#f20c33]');
        } else {
            btn.classList.add('text-gray-600', 'bg-white');
            btn.classList.remove('text-white', 'bg-[#f20c33]', 'border-[#f20c33]');
        }
    });
    if(window.location.hash === '#/wishlist') renderWishlistPage();
};

window.addToCompare = (id) => {
    if (compareState.includes(id)) {
        showToast("Already in compare list", "error");
        renderCompareModal();
        return;
    }
    if (compareState.length >= 4) {
        showToast("Max 4 products allowed", "error");
        renderCompareModal();
        return;
    }
    compareState.push(id);
    localStorage.setItem('site_compare', JSON.stringify(compareState));
    updateHeaderBadges();
    renderCompareModal();
};

window.removeFromCompare = (id) => {
    compareState = compareState.filter(item => item !== id);
    localStorage.setItem('site_compare', JSON.stringify(compareState));
    updateHeaderBadges();
    renderCompareModal();
};

const renderCompareModal = () => {
    const modal = document.getElementById('compare-modal');
    const content = document.getElementById('compare-content');
    modal.classList.remove('hidden');

    if (compareState.length === 0) {
        content.innerHTML = '<div class="flex flex-col items-center justify-center h-64 text-gray-500"><i class="fa-solid fa-scale-unbalanced text-4xl mb-3"></i><p>No items to compare.</p></div>';
        return;
    }

    const products = state.allProducts.filter(p => compareState.includes(p.id));
    const renderRow = (label, dataFn, isHeader = false) => {
        const cellClass = isHeader ? "" : "bg-white";
        const stickyClass = "sticky left-0 z-20 bg-gray-50 border-r border-gray-200 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)]";
        return `
        <tr class="border-b border-gray-100 last:border-0 hover:bg-gray-50 transition">
            <td class="p-3 align-middle text-sm font-bold text-gray-700 min-w-[120px] max-w-[120px] ${stickyClass}">${label}</td>
            ${products.map(p => `<td class="p-3 align-middle text-center min-w-[180px] md:min-w-[220px] border-r border-gray-100 last:border-0 ${cellClass}">${dataFn(p)}</td>`).join('')}
        </tr>`;
    };

    const tableHtml = `
    <div class="overflow-x-auto w-full h-full pb-4 custom-scrollbar bg-white">
        <table class="w-full border-collapse">
            ${renderRow('', p => `<button onclick="removeFromCompare(${p.id})" class="text-red-400 hover:text-red-600 text-xs font-bold uppercase tracking-wider"><i class="fa-solid fa-trash mr-1"></i> Remove</button>`)}
            ${renderRow('Image', p => `<div class="h-24 w-24 mx-auto p-1 bg-white border rounded"><img src="${p.imageUrl}" class="w-full h-full object-contain"></div>`)}
            ${renderRow('Name', p => `<h4 class="font-bold text-sm text-gray-800 line-clamp-2 leading-tight" title="${p.name}">${p.name}</h4>`)}
            ${renderRow('Price', p => getPriceHtml(p, 'text-[#f20c33] font-extrabold text-lg'))}
            ${renderRow('Action', p => `<button onclick="document.getElementById('compare-modal').classList.add('hidden'); addProductToCart(${p.id}, null, true); if(document.getElementById('cart-drawer')) { document.getElementById('cart-drawer').classList.add('open'); document.getElementById('cart-overlay').style.display='block'; }" class="text-white px-4 py-2 rounded shadow-sm text-xs font-bold hover:opacity-90 w-full transition" style="background-color: var(--btn-primary-bg);">Add to Cart</button>`)}
            ${renderRow('Brand', p => `<span class="text-gray-600 text-xs uppercase tracking-wide font-medium">${p.brand || 'Generic'}</span>`)}
            ${renderRow('Category', p => `<span class="text-gray-500 text-xs bg-gray-100 px-2 py-1 rounded">${(p.categories && p.categories.length) ? p.categories.join(', ') : (p.category || '')}</span>`)}
            ${renderRow('Availability', p => p.id % 5 === 0 ? '<span class="text-red-500 font-bold text-xs"><i class="fa-solid fa-circle-xmark mr-1"></i>Out of Stock</span>' : '<span class="text-green-600 font-bold text-xs"><i class="fa-solid fa-circle-check mr-1"></i>In Stock</span>')}
            ${renderRow('Description', p => `<p class="text-xs text-gray-500 line-clamp-3 text-left leading-relaxed">${p.description ? p.description.replace(/<[^>]*>?/gm, '') : 'No description.'}</p>`)}
        </table>
    </div>`;
    content.innerHTML = tableHtml;
};

window.openQuickView = (id) => {
    const p = state.allProducts.find(item => item.id === id);
    if(!p) return;
    document.getElementById('qv-img').src = p.imageUrl;
    document.getElementById('qv-title').textContent = p.name;
    document.getElementById('qv-price').innerHTML = getPriceHtml(p, 'text-2xl font-extrabold text-[#f20c33]');
    document.getElementById('qv-desc').innerHTML = p.description ? p.description.replace(/<[^>]*>?/gm, '').substring(0, 150) + '...' : 'No description.';
    const addBtn = document.getElementById('qv-add-btn');
    addBtn.onclick = () => {
        addProductToCart(p.id, null, false);
        document.getElementById('quick-view-modal').classList.add('hidden');
        if(doc.cartDrawer) { doc.cartDrawer.classList.add('open'); doc.overlay.style.display = 'block'; }
    };
    const detailBtn = document.getElementById('qv-details-btn');
    detailBtn.onclick = () => {
        document.getElementById('quick-view-modal').classList.add('hidden');
        const landingUrl = getLandingPageUrlForProduct(p);
        if (landingUrl) window.location.href = landingUrl;
        else window.location.hash = `#/product/${p.id}`;
    };
    document.getElementById('quick-view-modal').classList.remove('hidden');
};

// Defaults for Classic theme (used when admin color is empty or not saved) – neutral so header/search use admin-set color
const THEME_COLOR_DEFAULTS = {
    body_bg: '#f9fafb', text_primary: '#111827', text_secondary: '#6b7280', accent_color: '#4b5563',
    header_bg: '#ffffff', header_text: '#1f2937', header_icon_color: '#374151', search_icon_color: '#ffffff', search_btn_bg: '#ffd400', search_btn_text: '#111111', menu_bg: '#ffffff', menu_text: '#374151',
    category_pill_text: '#000000', category_pill_bg: '#ffffff', category_card_label_text: '#000000', category_card_label_bg: '#facc15',
    cbs_tab_active_bg: '#facc15', cbs_tab_active_text: '#111827', cbs_tab_inactive_bg: '#ffffff', cbs_tab_inactive_text: '#374151',
    top_bar_bg: '#f3f4f6', top_bar_text: '#374151',
    btn_primary_bg: '#4b5563', btn_primary_text: '#ffffff', btn_secondary_bg: '#111827', btn_secondary_text: '#ffffff',
    card_bg: '#ffffff', card_border: '#e5e7eb', price_text: '#1f2937', section_title_color: '#111827',
    footer_bg: '#111827', footer_text: '#e5e7eb', footer_accent: '#4b5563'
};

/** Dashboard → Customization → Typography: set CSS variables from layout.typography (PC vs mobile by viewport). */
const applyTypographyVars = (settings) => {
    if (!settings) return;
    const root = document.documentElement;
    const typo = settings.layout && settings.layout.typography ? settings.layout.typography : {};
    const isMob = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(max-width: 767px)').matches;
    const num = (v) => {
        if (v == null || v === '') return null;
        const n = Number(v);
        return Number.isFinite(n) && n >= 8 && n <= 40 ? n : null;
    };
    const pick = (g) => {
        const o = typo[g] || {};
        const v = isMob ? o.mobile : o.pc;
        const n = num(v);
        return n != null ? `${n}px` : '';
    };
    const map = {
        '--font-body': 'body',
        '--font-heading': 'heading',
        '--font-button': 'button',
        '--font-product-title': 'productTitle',
        '--font-product-price': 'productPrice',
        '--font-nav': 'nav',
        '--font-sidebar-category': 'sidebarCategory',
        '--font-sidebar-category-icon': 'sidebarCategoryIcon',
        '--font-sidebar-header': 'sidebarHeader',
        '--font-footer': 'footer',
        '--font-top-bar': 'topBar',
        '--font-category-pill': 'categoryPill',
        '--font-card-description': 'cardDescription',
        '--font-badge': 'badge',
        '--font-cart-drawer': 'cartDrawer'
    };
    Object.entries(map).forEach(([cssVar, group]) => {
        const val = pick(group);
        if (val) root.style.setProperty(cssVar, val);
        else root.style.removeProperty(cssVar);
    });
};

let typographyResizeTimer = null;
const scheduleTypographyVarsReapply = () => {
    if (typeof window === 'undefined') return;
    clearTimeout(typographyResizeTimer);
    typographyResizeTimer = window.setTimeout(() => {
        try {
            applyTypographyVars(state.siteSettings);
        } catch (_) { /* ignore */ }
    }, 150);
};

if (typeof window !== 'undefined') {
    window.addEventListener('resize', scheduleTypographyVarsReapply, { passive: true });
}

const applyThemeColors = (settings) => {
    if (!settings) return;
    const colors = settings.colors || {};
    const root = document.documentElement;
    const get = (key) => (colors[key] && colors[key].trim()) ? colors[key].trim() : THEME_COLOR_DEFAULTS[key];
    const set = (varName, value) => { if (value) root.style.setProperty(varName, value); };
    set('--body-bg', get('body_bg')); set('--text-primary', get('text_primary')); set('--text-secondary', get('text_secondary')); set('--accent-color', get('accent_color')); set('--header-bg', get('header_bg')); set('--header-text', get('header_text')); set('--header-icon', get('header_icon_color')); set('--search-icon-color', get('search_icon_color')); set('--search-btn-bg', get('search_btn_bg')); set('--search-btn-text', get('search_btn_text')); set('--menu-bg', get('menu_bg')); set('--menu-text', get('menu_text')); set('--category-pill-text', get('category_pill_text')); set('--category-pill-bg', get('category_pill_bg')); set('--category-shwapno-label-text', get('category_card_label_text')); set('--category-shwapno-label-bg', get('category_card_label_bg')); set('--cbs-tab-active-bg', get('cbs_tab_active_bg')); set('--cbs-tab-active-text', get('cbs_tab_active_text')); set('--cbs-tab-inactive-bg', get('cbs_tab_inactive_bg')); set('--cbs-tab-inactive-text', get('cbs_tab_inactive_text')); set('--top-bar-bg', get('top_bar_bg')); set('--top-bar-text', get('top_bar_text')); set('--btn-primary-bg', get('btn_primary_bg')); set('--btn-primary-text', get('btn_primary_text')); set('--btn-secondary-bg', get('btn_secondary_bg')); set('--btn-secondary-text', get('btn_secondary_text')); set('--card-bg', get('card_bg')); set('--card-border', get('card_border')); set('--price-text', get('price_text')); set('--section-title', get('section_title_color'));     set('--footer-bg', get('footer_bg')); set('--footer-text', get('footer_text')); set('--footer-accent', get('footer_accent'));
    const layout = settings.layout || {};
    const ocBg = String(layout.orderCallOrderNowBg || '').trim();
    const ocTx = String(layout.orderCallOrderNowText || '').trim();
    set('--order-call-order-bg', ocBg || get('btn_primary_bg'));
    set('--order-call-order-text', ocTx || get('btn_primary_text'));
    applyTypographyVars(settings);
};

const applyProductGridConfig = (settings) => {
    const root = document.documentElement;
    const layout = settings && settings.layout ? settings.layout : {};
    const pg = layout.productGridConfig || {};
    const colsDesktop = Math.min(8, Math.max(2, parseInt(pg.columnsDesktop, 10) || 5));
    const colsMobile = Math.min(5, Math.max(2, parseInt(pg.columnsMobile, 10) || 3));
    root.style.setProperty('--product-grid-cols-desktop', String(colsDesktop));
    root.style.setProperty('--product-grid-cols-mobile', String(colsMobile));
};

/** Apply product grid column count to a specific container (so Featured, Category, Wishlist, Related all use same setting as Just For You). */
const applyProductGridToElement = (el) => {
    if (!el) return;
    const layout = state.siteSettings?.layout || {};
    const pg = layout.productGridConfig || {};
    const colsDesktop = Math.min(8, Math.max(2, parseInt(pg.columnsDesktop, 10) || 5));
    const colsMobile = Math.min(5, Math.max(2, parseInt(pg.columnsMobile, 10) || 3));
    el.style.setProperty('--product-grid-cols-desktop', String(colsDesktop));
    el.style.setProperty('--product-grid-cols-mobile', String(colsMobile));
};

const renderMainProductGridSkeleton = (el, cards = 8) => {
    if (!el) return;
    const safeCards = Math.min(16, Math.max(4, Number(cards) || 8));
    const blocks = Array.from({ length: safeCards }).map(() => `
        <div class="rounded-xl border border-gray-100 bg-white p-3 shadow-sm animate-pulse">
            <div class="aspect-square w-full rounded-lg bg-gray-200 mb-3"></div>
            <div class="h-4 bg-gray-200 rounded w-4/5 mb-2"></div>
            <div class="h-3 bg-gray-100 rounded w-3/5 mb-3"></div>
            <div class="h-9 bg-gray-200 rounded"></div>
        </div>
    `).join('');
    el.innerHTML = blocks;
};

// --- NEW: LOGO SETTINGS APPLICATOR ---
const LOGO_PLACEHOLDER = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

const applyLogoSettings = (settings) => {
    const desktopLogo = getEl('desktop-logo');
    const mobileLogo = getEl('mobile-logo');
    const mobileLogoShwapno = getEl('mobile-logo-shwapno');
    const mobileLogoCenterTrade = getEl('mobile-logo-center-trade');
    const config = settings.logoConfig || { desktopHeight: 50, mobileHeight: 40 };
    const logoUrl = settings.logoUrl && String(settings.logoUrl).trim() ? settings.logoUrl : '';

    if (desktopLogo) {
        desktopLogo.src = logoUrl || LOGO_PLACEHOLDER;
        desktopLogo.style.height = logoUrl ? `${config.desktopHeight}px` : '';
        desktopLogo.removeAttribute('width');
        desktopLogo.removeAttribute('height');
        desktopLogo.removeAttribute('fetchpriority');
    }

    if (mobileLogo) {
        mobileLogo.src = logoUrl || LOGO_PLACEHOLDER;
        mobileLogo.style.height = logoUrl ? `${config.mobileHeight}px` : '';
        mobileLogo.removeAttribute('width');
        mobileLogo.removeAttribute('height');
        mobileLogo.removeAttribute('fetchpriority');
    }
    if (mobileLogoShwapno) {
        mobileLogoShwapno.src = logoUrl || LOGO_PLACEHOLDER;
        mobileLogoShwapno.style.height = logoUrl ? `${config.mobileHeight}px` : '';
        mobileLogoShwapno.removeAttribute('width');
        mobileLogoShwapno.removeAttribute('height');
    }
    if (mobileLogoCenterTrade) {
        mobileLogoCenterTrade.src = logoUrl || LOGO_PLACEHOLDER;
        mobileLogoCenterTrade.style.height = logoUrl ? `${config.mobileHeight}px` : '';
        mobileLogoCenterTrade.removeAttribute('width');
        mobileLogoCenterTrade.removeAttribute('height');
    }

    const footerLogo = getEl('footer-logo-img');
    if (footerLogo) {
        const flCfg = settings.footerLogoConfig || {};
        const flShow = flCfg.show !== false;
        if (!flShow) {
            footerLogo.style.display = 'none';
        } else {
            footerLogo.style.display = '';
            const footerUrlRaw = settings.footerLogoUrl && String(settings.footerLogoUrl).trim()
                ? String(settings.footerLogoUrl).trim()
                : '';
            const footerSrc = footerUrlRaw || logoUrl || '';
            footerLogo.src = footerSrc || LOGO_PLACEHOLDER;
            const fh = Math.min(120, Math.max(16, parseInt(flCfg.height, 10) || 40));
            footerLogo.style.height = footerSrc || logoUrl ? `${fh}px` : '';
            const inv = flCfg.invert !== false;
            ['brightness-0', 'invert', 'opacity-80'].forEach((cls) => footerLogo.classList.toggle(cls, inv));
        }
    }
};

// --- Shwapno header: fill category pills below header (mobile bar; desktop uses desktop-nav-container)
const renderShwapnoCategoryPills = () => {
    const container = getEl('shwapno-category-pills-mobile');
    if (!container) return;
    const cats = getMenuCategories();
    const list = cats.slice(0, 12);
    container.innerHTML = list.map(cat => `<a href="#/category/${encodeURIComponent(cat.name)}" class="shwapno-pill">${String(cat.name).replace(/</g, '&lt;')}</a>`).join('');
};

/** Mobile home only: equal-width text tabs (categoryConfig.mobileHeroEqualTabsEnabled) takes priority over slanted tabs (centerTrade + slantedTabNavEnabled). */
const renderMobileHeroCategoryBar = () => {
    const nav = getEl('slanted-tab-nav');
    if (!nav) return;
    const layout = state.siteSettings?.layout || {};
    const cc = layout.categoryConfig || {};
    const equalOn = !!cc.mobileHeroEqualTabsEnabled;

    nav.classList.remove('slanted-tab-nav--visible', 'mobile-hero-tab-nav--equal', 'mobile-hero-tab-nav--slanted');

    let raw = (window.location.hash || '').slice(1);
    if (!raw) raw = 'shop';
    const h = raw.startsWith('/') ? raw : `/${raw}`;
    const isHomeRoute = h === '/shop' || h === '/';
    if (!isHomeRoute) {
        nav.classList.add('hidden');
        nav.innerHTML = '';
        return;
    }

    const esc = (s) => String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;');

    if (equalOn) {
        const n = Math.min(8, Math.max(1, Number(cc.mobileHeroEqualTabsCategoryCount) || 4));
        const firstLabel = (cc.mobileHeroEqualTabsFirstLabel && String(cc.mobileHeroEqualTabsFirstLabel).trim()) ? String(cc.mobileHeroEqualTabsFirstLabel).trim() : 'Shop';
        const cats = (state.allCategories || []).slice(0, n);
        let html = '<div class="hero-equal-tabs-track">';
        html += `<a href="#/shop" class="hero-equal-tab-item is-active">${esc(firstLabel)}</a>`;
        cats.forEach((cat) => {
            const name = cat && cat.name != null ? String(cat.name) : '';
            if (!name) return;
            html += `<a href="#/category/${encodeURIComponent(name)}" class="hero-equal-tab-item">${esc(name)}</a>`;
        });
        html += '</div>';
        nav.innerHTML = html;
        nav.classList.remove('hidden');
        nav.classList.add('slanted-tab-nav--visible', 'mobile-hero-tab-nav--equal');
        return;
    }

    const slantedOn = layout.headerDesign === 'centerTrade' && layout.slantedTabNavEnabled;
    if (!slantedOn) {
        nav.classList.add('hidden');
        nav.innerHTML = '';
        return;
    }

    nav.classList.remove('hidden');
    nav.classList.add('slanted-tab-nav--visible', 'mobile-hero-tab-nav--slanted');
    const firstLabel = (layout.slantedTabFirstLabel && String(layout.slantedTabFirstLabel).trim()) ? String(layout.slantedTabFirstLabel).trim() : 'Shop';
    const cats = (state.allCategories || []).slice(0, 6);
    const shopActive = isHomeRoute;
    let html = '<div class="slanted-tab-nav-track">';
    html += `<a href="#/shop" class="slanted-tab-item${shopActive ? ' is-active' : ''}">${esc(firstLabel)}</a>`;
    cats.forEach((cat) => {
        const name = cat && cat.name != null ? String(cat.name) : '';
        if (!name) return;
        html += `<a href="#/category/${encodeURIComponent(name)}" class="slanted-tab-item">${esc(name)}</a>`;
    });
    html += '</div>';
    nav.innerHTML = html;
};

// --- Category shape/size CSS so saved "Square" in dashboard shows on site (fixes round showing when square saved)
const applyCategoryShapeFromSettings = (settings) => {
    const cc = settings?.layout?.categoryConfig || {};
    const catShape = cc.shape === 'square' ? 'square' : 'round';
    const catRadiusPc = catShape === 'square' ? '8px' : '50%';
    const catSizePc = Math.min(250, Math.max(100, Number(cc.sizeDesktop) || 170));
    document.documentElement.style.setProperty('--cat-radius-pc', catRadiusPc);
    document.documentElement.style.setProperty('--cat-size-pc', catSizePc + 'px');
};

/** Classic shop home: boxed (banner + categories + products in same container) vs full width (edge-to-edge). */
const applyClassicHomeLayoutMode = (settings) => {
    const layout = settings?.layout || {};
    const mode = layout.homeLayoutMode === 'boxed' ? 'boxed' : 'full';
    const home = getEl('home-view');
    if (home) {
        home.classList.toggle('layout-home-boxed', mode === 'boxed');
        home.classList.toggle('layout-home-full', mode === 'full');
    }
    const stack = getEl('classic-pc-hero-stack');
    const below = getEl('classic-pc-below-slider');
    if (stack) {
        stack.className = mode === 'boxed' ? 'w-full pt-2 md:pt-4' : 'w-full home-hero-shell pt-2 md:pt-4';
    }
    if (below) {
        below.className = 'w-full';
    }
    const main = getEl('classic-home-main-content');
    if (main) {
        main.className = mode === 'boxed' ? 'container mx-auto mt-6' : 'w-full max-w-none mt-6 px-2 sm:px-3 md:px-4';
    }
    const mobileHero = getEl('mobile-hero-section');
    if (mobileHero) {
        mobileHero.className = mode === 'boxed' ? 'md:hidden container mt-4 px-4' : 'md:hidden w-full max-w-none mt-4 px-2 sm:px-3';
    }
};

// --- Section designs: header, footer, section headers, small banners, promo banners
const applySectionDesigns = (settings) => {
    const layout = settings?.layout || {};
    const root = document.documentElement;
    const setHeaderLayoutVarPx = (layoutKey, cssVar, minPx, maxPx) => {
        const raw = layout[layoutKey];
        const n = raw != null && raw !== '' ? Number(raw) : NaN;
        if (Number.isFinite(n) && n >= minPx && n <= maxPx) {
            root.style.setProperty(cssVar, `${n}px`);
        } else {
            root.style.removeProperty(cssVar);
        }
    };
    setHeaderLayoutVarPx('headerMainGapPx', '--header-gap-main', 4, 64);
    setHeaderLayoutVarPx('headerNavGapPx', '--header-gap-nav', 4, 64);
    setHeaderLayoutVarPx('headerIconGapPx', '--header-gap-icons', 4, 64);
    setHeaderLayoutVarPx('headerIconSizePcPx', '--header-icon-size-pc', 10, 48);
    setHeaderLayoutVarPx('headerIconSizeMobilePx', '--header-icon-size-mobile', 10, 48);
    setHeaderLayoutVarPx('shwapnoGapMainPx', '--shwapno-gap-main', 4, 64);
    setHeaderLayoutVarPx('shwapnoGapAppPx', '--shwapno-gap-app', 4, 64);
    setHeaderLayoutVarPx('shwapnoGapLangPx', '--shwapno-gap-lang', 4, 64);
    setHeaderLayoutVarPx('shwapnoGapAuthPx', '--shwapno-gap-auth', 0, 48);
    setHeaderLayoutVarPx('shwapnoGapLogoLocPx', '--shwapno-gap-logo-loc', 0, 64);
    setHeaderLayoutVarPx('shwapnoGapRightPx', '--shwapno-gap-right', 0, 48);
    setHeaderLayoutVarPx('shwapnoAuthFontSizePx', '--shwapno-auth-font-size', 10, 24);
    (function setShwapnoAuthIconSize() {
        const raw = layout.shwapnoAuthFontSizePx;
        const n = raw != null && raw !== '' ? Number(raw) : NaN;
        if (Number.isFinite(n) && n >= 10 && n <= 24) {
            root.style.setProperty('--shwapno-auth-icon-size', `${n + 1}px`);
        } else {
            root.style.removeProperty('--shwapno-auth-icon-size');
        }
    })();
    setHeaderLayoutVarPx('searchBarWidth', '--search-max-width', 200, 1200);
    setHeaderLayoutVarPx('desktopContentSideGapPx', '--desktop-content-side-gap', 0, 120);
    setHeaderLayoutVarPx('desktopShellMaxWidthPx', '--pixel-home-shell-width', 1100, 1800);

    const safeShwapnoAppImgUrl = (raw) => {
        const s = String(raw || '').trim();
        if (!s) return '';
        if (/^https?:\/\//i.test(s)) return s;
        if (s.startsWith('/') && !s.startsWith('//')) return s;
        return '';
    };
    const applyShwapnoAppDesktopSlot = () => {
        const a = getEl('header-shwapno-app-desktop');
        if (!a) return;
        const imgUrl = safeShwapnoAppImgUrl(layout.shwapnoAppImgUrl);
        const linkRaw = String(layout.shwapnoAppLinkUrl || '').trim();
        const defaultPillHtml = '<i class="fa-solid fa-mobile-screen-button" aria-hidden="true"></i><span>Download App Now</span>';
        if (imgUrl) {
            a.classList.remove('shwapno-header-app-pill');
            a.classList.add('header-shwapno-app-img-link');
            a.innerHTML = '';
            const img = document.createElement('img');
            img.className = 'header-shwapno-app-img';
            img.alt = 'App';
            img.src = imgUrl;
            img.loading = 'lazy';
            img.decoding = 'async';
            a.appendChild(img);
            a.href = linkRaw || '#';
            a.removeAttribute('onclick');
            if (/^https?:\/\//i.test(linkRaw)) {
                a.target = '_blank';
                a.rel = 'noopener noreferrer';
            } else {
                a.removeAttribute('target');
                a.removeAttribute('rel');
            }
        } else {
            a.classList.add('shwapno-header-app-pill');
            a.classList.remove('header-shwapno-app-img-link');
            a.innerHTML = defaultPillHtml;
            a.href = '#';
            a.setAttribute('onclick', 'return false;');
            a.removeAttribute('target');
            a.removeAttribute('rel');
        }
    };
    applyShwapnoAppDesktopSlot();

    const headerEl = getEl('desktop-header');
    const footerEl = getEl('desktop-footer');
    if (headerEl) {
        headerEl.classList.remove('header--default', 'header--minimal', 'header--shwapno', 'header--centerTrade');
        const hd = layout.headerDesign || 'default';
        if (hd === 'shwapno') headerEl.classList.add('header--shwapno');
        else if (hd === 'minimal') headerEl.classList.add('header--minimal');
        else if (hd === 'centerTrade') headerEl.classList.add('header--centerTrade');
        else headerEl.classList.add('header--default');
        const topRow = headerEl.querySelector('.header-el-top-row');
        if (topRow) {
            const dh = layout.headerHeight;
            const dhNum = dh != null && dh !== '' ? Number(dh) : NaN;
            if (Number.isFinite(dhNum) && dhNum >= 48 && dhNum <= 200) {
                topRow.style.boxSizing = 'border-box';
                topRow.style.minHeight = dhNum + 'px';
                topRow.style.height = dhNum + 'px';
            } else {
                topRow.style.boxSizing = '';
                topRow.style.minHeight = '';
                topRow.style.height = '';
            }
        }
    }
    const mobileSearchSection = getEl('mobile-search-section');
    const mobileHeaderShwapno = getEl('mobile-header-shwapno');
    const mobileHeaderCenterTrade = getEl('mobile-header-center-trade');
    const isShwapno = (layout.headerDesign === 'shwapno');
    const isCenterTrade = (layout.headerDesign === 'centerTrade');
    const showDefaultMobileRow = !isShwapno && !isCenterTrade;
    if (mobileSearchSection) mobileSearchSection.style.display = showDefaultMobileRow ? '' : 'none';
    if (mobileHeaderShwapno) {
        if (isShwapno) mobileHeaderShwapno.classList.add('header-style-active');
        else mobileHeaderShwapno.classList.remove('header-style-active');
    }
    if (mobileHeaderCenterTrade) {
        if (isCenterTrade) mobileHeaderCenterTrade.classList.add('header-style-active');
        else mobileHeaderCenterTrade.classList.remove('header-style-active');
    }
    const mh = layout.mobileHeaderHeight;
    const mhNum = mh != null && mh !== '' ? Number(mh) : NaN;
    const mobileBarPx = (Number.isFinite(mhNum) && mhNum >= 36 && mhNum <= 120) ? mhNum : null;
    const setMobileHeaderBarHeight = (el) => {
        if (!el) return;
        if (mobileBarPx != null) {
            el.style.boxSizing = 'border-box';
            el.style.minHeight = mobileBarPx + 'px';
            el.style.height = mobileBarPx + 'px';
        } else {
            el.style.boxSizing = '';
            el.style.minHeight = '';
            el.style.height = '';
        }
    };
    setMobileHeaderBarHeight(document.querySelector('#mobile-search-section .container'));
    setMobileHeaderBarHeight(document.querySelector('#mobile-header-shwapno .shwapno-row1'));
    setMobileHeaderBarHeight(document.querySelector('#mobile-header-center-trade .center-trade-row1'));
    const desktopSearchInput = getEl('desktop-search-input');
    if (desktopSearchInput) {
        desktopSearchInput.placeholder = isCenterTrade
            ? 'Search'
            : (isShwapno ? 'Search your products' : 'Search for products...');
    }
    const locIconEl = getEl('location-icon');
    if (locIconEl) {
        const spinHidden = !doc.locationSpinner || doc.locationSpinner.classList.contains('hidden');
        const iconClass = isShwapno ? 'fa-solid fa-truck' : 'fa-solid fa-location-dot';
        locIconEl.className = iconClass + (spinHidden ? '' : ' hidden');
    }
    if (doc.headerLocationText) {
        const t = doc.headerLocationText.textContent.trim();
        if (isShwapno && t === 'Select Location') doc.headerLocationText.textContent = getHeaderLocationEmptyLabel();
        if (!isShwapno && t === 'Select your delivery location') doc.headerLocationText.textContent = 'Select Location';
    }
    if (isShwapno) {
        renderShwapnoCategoryPills();
        const social = settings.socialLinks || {};
        const contact = settings.contactInfo || {};
        const waNum = normalizeWhatsAppNumber(contact.whatsappNumber);
        const whatsappUrl = waNum.length >= 10 ? `https://wa.me/${waNum}` : '#';
        const fbEl = getEl('header-social-fb');
        const igEl = getEl('header-social-ig');
        const waEl = getEl('header-social-wa');
        if (fbEl) { const u = String(social.facebook || '').trim(); fbEl.href = u ? u : '#'; fbEl.style.display = (fbEl.href === '#') ? 'none' : ''; }
        if (igEl) { const u = String(social.instagram || '').trim(); igEl.href = u ? u : '#'; igEl.style.display = (igEl.href === '#') ? 'none' : ''; }
        if (waEl) { waEl.href = whatsappUrl; waEl.style.display = (waEl.href === '#') ? 'none' : ''; }
    }
    if (footerEl) {
        footerEl.classList.remove('footer--columns', 'footer--centered');
        footerEl.classList.add(layout.footerDesign === 'centered' ? 'footer--centered' : 'footer--columns');
    }
    const sectionHeaderDesign = layout.sectionHeaderDesign || 'default';
    document.body.classList.remove('section-header-style--default', 'section-header-style--centered', 'section-header-style--underline');
    document.body.classList.add('section-header-style--' + (['default','centered','underline'].includes(sectionHeaderDesign) ? sectionHeaderDesign : 'default'));
    const sbc = layout.smallBannerConfig || {};
    const smallCount = (sbc.count === 1 || sbc.count === 2) ? sbc.count : 2;
    const smallHDesktop = Math.min(300, Math.max(80, Number(sbc.desktopHeight) || 150));
    const smallHMobile = Math.min(180, Math.max(60, Number(sbc.mobileHeight) || 80));
    document.documentElement.style.setProperty('--small-banner-height-desktop', smallHDesktop + 'px');
    document.documentElement.style.setProperty('--small-banner-height-mobile', smallHMobile + 'px');
    [doc.pcSmallBanners, doc.mobileSmallBanners].forEach(container => {
        if (!container) return;
        container.classList.remove('small-banners--equal', 'small-banners--big-small', 'small-banners--count-1', 'small-banners--count-2');
        container.classList.add((layout.smallBannersLayout === 'bigSmall') ? 'small-banners--big-small' : 'small-banners--equal');
        container.classList.add('small-banners--count-' + smallCount);
        const children = container.children;
        for (let i = 0; i < children.length; i++) {
            children[i].style.display = i < smallCount ? '' : 'none';
        }
    });
    const pbc = layout.promoBannerConfig || {};
    const promoHDesktop = Math.min(400, Math.max(80, Number(pbc.desktopHeight) || 150));
    const promoHMobile = Math.min(250, Math.max(60, Number(pbc.mobileHeight) || 120));
    document.documentElement.style.setProperty('--promo-banner-height-desktop', promoHDesktop + 'px');
    document.documentElement.style.setProperty('--promo-banner-height-mobile', promoHMobile + 'px');
    const promoDesign = (['default','fullBleed','card'].includes(layout.promoBannerDesign) ? layout.promoBannerDesign : 'default');
    [doc.promoBanner1, doc.promoBanner2].forEach(el => {
        if (el) {
            el.classList.remove('promo-banner--default', 'promo-banner--full-bleed', 'promo-banner--card');
            el.classList.add('promo-banner--' + promoDesign);
        }
    });
    if (doc.flashSection) {
        doc.flashSection.classList.remove('featured-section--default', 'featured-section--compact', 'featured-section--grid');
        const fd = ['default','compact','grid'].includes(layout.featuredSectionDesign) ? layout.featuredSectionDesign : 'default';
        doc.flashSection.classList.add('featured-section--' + fd);
    }
    if (doc.catRowsContainer) {
        doc.catRowsContainer.classList.remove('category-rows--default', 'category-rows--card', 'category-rows--minimal');
        const crd = ['default','card','minimal'].includes(layout.categoryRowsDesign) ? layout.categoryRowsDesign : 'default';
        doc.catRowsContainer.classList.add('category-rows--' + crd);
    }
    const isBottomNavDisabled = layout.bottomNavEnabled === false || layout.bottomNavDesign === 'hidden';
    document.body.classList.toggle('mobile-bottom-nav-hidden', isBottomNavDisabled);
    if (doc.bottomNav) {
        doc.bottomNav.classList.remove('bottom-nav--default', 'bottom-nav--center-prominent', 'bottom-nav--icons-only', 'bottom-nav--hidden');
        if (isBottomNavDisabled) {
            doc.bottomNav.classList.add('bottom-nav--hidden');
        } else {
            const bnd = ['default','centerProminent','iconsOnly'].includes(layout.bottomNavDesign) ? layout.bottomNavDesign : 'default';
            const bndClass = { default: 'default', centerProminent: 'center-prominent', iconsOnly: 'icons-only' }[bnd] || 'default';
            doc.bottomNav.classList.add('bottom-nav--' + bndClass);
        }
    }
    if (doc.cartDrawer) {
        doc.cartDrawer.classList.remove('cart-drawer--default', 'cart-drawer--sheet', 'cart-drawer--minimal');
        const cdd = ['default','sheet','minimal'].includes(layout.cartDrawerDesign) ? layout.cartDrawerDesign : 'default';
        doc.cartDrawer.classList.add('cart-drawer--' + cdd);
    }
    const groceryCartActive = (layout.cartIconStyle === 'groceryCart');
    document.body.classList.toggle('cart-icon--grocery', groceryCartActive);
    const groceryWidget = getEl('grocery-cart-widget');
    const groceryTop = getEl('grocery-cart-top');
    const groceryBottom = getEl('grocery-cart-bottom');
    if (groceryWidget) {
        if (groceryCartActive) {
            groceryWidget.classList.remove('hidden');
            groceryWidget.classList.add('grocery-cart-widget--active');
            const topColor = (layout.groceryCartTopColor && String(layout.groceryCartTopColor).trim()) ? String(layout.groceryCartTopColor).trim() : '#dc2626';
            const bottomColor = (layout.groceryCartBottomColor && String(layout.groceryCartBottomColor).trim()) ? String(layout.groceryCartBottomColor).trim() : '#1f2937';
            if (groceryTop) groceryTop.style.backgroundColor = topColor;
            if (groceryBottom) groceryBottom.style.backgroundColor = bottomColor;
        } else {
            groceryWidget.classList.add('hidden');
            groceryWidget.classList.remove('grocery-cart-widget--active');
        }
    }
    renderMobileHeroCategoryBar();
    applyClassicHomeLayoutMode(settings);
};

// ============================================================
// 3. REUSABLE HTML GENERATORS
// ============================================================

const generateProductCard = (p, isHighlight = false, opts = {}) => {
    const categoryListing = !!(opts && opts.categoryListing);
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    let oldPriceHtml = '';
    let badgeHtml = '';

    if (regularPrice > displayPrice) {
        oldPriceHtml = categoryListing
            ? `<span class="classic-old-price text-sm">${formatPrice(regularPrice)}</span>`
            : `<span class="text-red-500 line-through text-sm">${formatPrice(regularPrice)}</span>`;
        const discount = Math.round(((regularPrice - displayPrice) / regularPrice) * 100);
        badgeHtml = `<div class="discount-badge"><span>${categoryListing ? `${discount}%` : `-${discount}%`}</span></div>`;
    }

    const mainImgAttrs = storefrontImgAttrsFromGridIndex(opts.gridIndex);
    let hoverImgHtml = '';
    if (p.galleryImageUrls && p.galleryImageUrls.length > 0) {
        hoverImgHtml = `<img src="${p.galleryImageUrls[0]}" class="img-secondary" loading="lazy" decoding="async" alt="${p.name}">`;
    }

    const isOutOfStock = p.id % 5 === 0; 
    const stockQty = Math.floor(Math.random() * 500) + 50;
    let stockHtml = '';
    let buttonHtml = '';

    if (categoryListing) {
        stockHtml = '';
        buttonHtml = isOutOfStock
            ? `<button class="card-order-btn product-card-link rounded-md w-full" data-id="${p.id}" style="background-color: var(--btn-primary-bg); padding: 10px 0; margin-top: 6px; font-size: 13px; font-weight: bold;">Read more <i class="fa-solid fa-cart-shopping ml-1"></i></button>`
            : `<button class="card-order-btn rounded-md w-full" data-id="${p.id}" style="background-color: var(--btn-primary-bg); padding: 10px 0; margin-top: 6px; font-size: 13px; font-weight: bold;">Add to cart</button>`;
    } else if (isOutOfStock) {
        stockHtml = `<span class="text-[10px] font-bold text-red-600 block mb-0.5">Out of stock</span>`;
        buttonHtml = `<button class="card-order-btn product-card-link rounded-md w-full" data-id="${p.id}" style="background-color: var(--btn-primary-bg); padding: 10px 0; margin-top: 6px; font-size: 13px; font-weight: bold;">Read more <i class="fa-solid fa-cart-shopping ml-1"></i></button>`;
    } else {
        stockHtml = `<span class="text-[10px] font-bold text-green-600 block mb-0.5">${stockQty} in stock</span>`;
        buttonHtml = `<button class="card-order-btn rounded-md w-full" data-id="${p.id}" style="background-color: var(--btn-primary-bg); padding: 10px 0; margin-top: 6px; font-size: 13px; font-weight: bold;">Add to cart</button>`;
    }

    const isWishlisted = wishlistState.includes(p.id);
    const heartClass = isWishlisted ? 'bg-[#f20c33] text-white border-[#f20c33]' : 'bg-white text-gray-600 border-gray-100';
    const borderClass = isHighlight ? 'border-[#f20c33]' : 'border-gray-200';

    const layout = state.siteSettings?.layout || {};
    let classicCardClass = '';
    let classicCardStyle = '';
    let classicImgWrapperStyle = '';
    const pw = layout.classicCardWidthPx != null && layout.classicCardWidthPx !== '' ? parseInt(layout.classicCardWidthPx, 10) : NaN;
    const ph = layout.classicCardHeightPx != null && layout.classicCardHeightPx !== '' ? parseInt(layout.classicCardHeightPx, 10) : NaN;
    const hasPx = !isNaN(pw) && !isNaN(ph) && pw >= 80 && pw <= 500 && ph >= 100 && ph <= 600;
    if (hasPx) {
        classicCardClass = 'classic-card--custom';
        classicCardStyle = `style="max-width:${pw}px;"`;
        classicImgWrapperStyle = `style="height:${ph}px; aspect-ratio: auto;"`;
    } else {
        const classicSize = (layout.classicCardSize && ['small','medium','large'].includes(layout.classicCardSize)) ? layout.classicCardSize : 'medium';
        classicCardClass = `classic-card--${classicSize}`;
    }

    return `
        <div class="classic-card ${classicCardClass} cursor-pointer group h-full product-card-link border ${borderClass} rounded-xl overflow-hidden" data-id="${p.id}" ${classicCardStyle}>
            ${badgeHtml}
            <div class="classic-img-wrapper relative p-2" ${classicImgWrapperStyle}>
                <img src="${p.imageUrl}" class="classic-img" width="300" height="300" alt="${p.name}"${mainImgAttrs}>
                ${hoverImgHtml}
                <div class="absolute top-2 right-2 flex flex-col gap-2 z-10">
                    <button class="btn-wishlist-action wishlist-btn-${p.id} w-7 h-7 rounded-full shadow-md border flex items-center justify-center hover:text-white transition ${heartClass}" data-id="${p.id}" title="Add to Wishlist"><i class="fa-regular fa-heart text-xs"></i></button>
                    <button class="btn-quickview-action w-7 h-7 rounded-full bg-white shadow-md border border-gray-100 flex items-center justify-center text-gray-600 hover:text-white transition" data-id="${p.id}" title="Quick View"><i class="fa-solid fa-eye text-xs"></i></button>
                    <button class="btn-compare-action w-7 h-7 rounded-full bg-white shadow-md border border-gray-100 flex items-center justify-center text-gray-600 hover:text-white transition" data-id="${p.id}" title="Compare"><i class="fa-solid fa-scale-balanced text-xs"></i></button>
                </div>
            </div>
            <div class="card-content p-2">
                ${stockHtml} 
                <h3 class="font-bold text-gray-900 text-xs leading-tight mb-1 line-clamp-2 min-h-[32px]" title="${p.name}">${p.name}</h3>
                <div class="price-row mb-0 items-center gap-2">
                    ${oldPriceHtml}
                    <span class="text-[#f20c33] font-bold text-sm">${formatPrice(displayPrice)}</span>
                </div>
                ${buttonHtml}
            </div>
        </div>`;
};

// --- App-style card size map (from settings: small / medium / large)
const getAppStyleCardSize = () => {
    const layout = state.siteSettings?.layout || {};
    const h = layout.appStyleCardHeight || 'medium';
    const w = layout.appStyleCardWidth || 'medium';
    const heightMap = { small: '180px', medium: '220px', large: '260px' };
    const widthMap = { small: '100px', medium: '120px', large: '145px' };
    return { minHeight: heightMap[h] || heightMap.medium, maxWidth: widthMap[w] || widthMap.medium };
};

// --- App-style product card: compact (image, price, name, unit, delivery, + button niche)
const generateProductCardAppStyle = (p, cardOpts = {}) => {
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    let priceHtml = '';
    if (regularPrice > displayPrice) {
        priceHtml = `<span class="text-red-500 line-through text-xs mr-1">${formatPrice(regularPrice)}</span><span class="text-[#f20c33] font-bold text-sm">${formatPrice(displayPrice)}</span>`;
    } else {
        priceHtml = `<span class="text-[#f20c33] font-bold text-sm">${formatPrice(displayPrice)}</span>`;
    }
    const unit = (p.unit && String(p.unit).trim()) ? p.unit : 'each';
    const deliveryText = state.siteSettings?.deliveryTimeText || '1 hr';
    const size = getAppStyleCardSize();
    const sizeStyle = `min-height:${size.minHeight}; max-width:${size.maxWidth};`;
    const imgA = productCardMainImgAttrs(cardOpts);
    const imgSpec = productCardMainImgSpec(p.imageUrl);
    return `
        <div class="app-style-card cursor-pointer product-card-link border border-gray-200 rounded-xl overflow-hidden bg-white h-full flex flex-col" data-id="${p.id}" style="${sizeStyle}">
            <div class="relative flex-shrink-0 aspect-square bg-gray-50">
                <img src="${imgSpec.src}"${imgSpec.srcset ? ` srcset="${imgSpec.srcset}" sizes="${imgSpec.sizes}"` : ''} class="w-full h-full object-cover" width="200" height="200" alt="${p.name}"${imgA}>
            </div>
            <div class="p-2 flex-grow flex flex-col">
                <div class="price-row mb-0.5">${priceHtml}</div>
                <h3 class="font-bold text-gray-900 text-xs leading-tight line-clamp-2 min-h-[32px]" title="${p.name}">${p.name}</h3>
                <p class="text-[10px] text-gray-500 mt-0.5">${unit}</p>
                <p class="text-[10px] text-gray-500">Delivery: ${deliveryText}</p>
                <button class="card-order-btn mt-2 w-8 h-8 rounded-full text-white shadow-md flex items-center justify-center hover:opacity-90 transition flex-shrink-0" data-id="${p.id}" title="Add to cart" style="background-color: var(--btn-primary-bg);"><i class="fa-solid fa-plus text-sm"></i></button>
            </div>
        </div>`;
};

// --- Minimal card: image + name + price + Add to cart only (no wishlist/quickview/compare)
const generateProductCardMinimal = (p, isHighlight = false, cardOpts = {}) => {
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    let oldPriceHtml = regularPrice > displayPrice ? `<span class="text-red-500 line-through text-xs mr-1">${formatPrice(regularPrice)}</span>` : '';
    const borderClass = isHighlight ? 'border-[#f20c33]' : 'border-gray-200';
    const isOutOfStock = p.id % 5 === 0;
    const imgA = productCardMainImgAttrs(cardOpts);
    const imgSpec = productCardMainImgSpec(p.imageUrl);
    const buttonHtml = isOutOfStock
        ? `<button class="card-order-btn product-card-link rounded-md w-full mt-2 py-2 text-sm font-bold" data-id="${p.id}" style="background-color: var(--btn-primary-bg);">Read more</button>`
        : `<button class="card-order-btn rounded-md w-full mt-2 py-2 text-sm font-bold" data-id="${p.id}" style="background-color: var(--btn-primary-bg);">Add to cart</button>`;
    return `
        <div class="product-card product-card--minimal cursor-pointer product-card-link border ${borderClass} rounded-xl overflow-hidden bg-white h-full flex flex-col" data-id="${p.id}">
            <div class="minimal-card-img aspect-[1/1] overflow-hidden bg-gray-50 flex items-center justify-center">
                <img src="${imgSpec.src}"${imgSpec.srcset ? ` srcset="${imgSpec.srcset}" sizes="${imgSpec.sizes}"` : ''} class="w-full h-full object-contain" width="200" height="200" alt="${p.name}"${imgA}>
            </div>
            <div class="p-3 flex-grow flex flex-col">
                <h3 class="font-bold text-gray-900 text-sm leading-tight line-clamp-2 mb-1" title="${p.name}">${p.name}</h3>
                <div class="price-row items-center gap-2 mt-auto">${oldPriceHtml}<span class="text-[#f20c33] font-bold text-sm">${formatPrice(displayPrice)}</span></div>
                ${buttonHtml}
            </div>
        </div>`;
};

// --- Image focus card: large image area, compact content
const generateProductCardImageFocus = (p, isHighlight = false, cardOpts = {}) => {
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    let oldPriceHtml = regularPrice > displayPrice ? `<span class="text-red-500 line-through text-xs">${formatPrice(regularPrice)}</span>` : '';
    const borderClass = isHighlight ? 'border-[#f20c33]' : 'border-gray-200';
    const isOutOfStock = p.id % 5 === 0;
    const imgA = productCardMainImgAttrs(cardOpts);
    const imgSpec = productCardMainImgSpec(p.imageUrl);
    const buttonHtml = isOutOfStock
        ? `<button class="card-order-btn product-card-link w-full py-2 text-xs font-bold rounded" data-id="${p.id}" style="background-color: var(--btn-primary-bg);">Read more</button>`
        : `<button class="card-order-btn w-full py-2 text-xs font-bold rounded" data-id="${p.id}" style="background-color: var(--btn-primary-bg);">Add to cart</button>`;
    return `
        <div class="product-card product-card--image-focus cursor-pointer product-card-link border ${borderClass} rounded-xl overflow-hidden bg-white h-full flex flex-col" data-id="${p.id}">
            <div class="image-focus-card-img flex-shrink-0" style="height: 65%; min-height: 160px;">
                <img src="${imgSpec.src}"${imgSpec.srcset ? ` srcset="${imgSpec.srcset}" sizes="${imgSpec.sizes}"` : ''} class="w-full h-full object-contain bg-gray-50" width="300" height="300" alt="${p.name}"${imgA}>
            </div>
            <div class="p-2 flex-grow flex flex-col min-h-0">
                <h3 class="font-bold text-gray-900 text-xs leading-tight line-clamp-2 mb-0.5" title="${p.name}">${p.name}</h3>
                <div class="price-row items-center gap-1 flex-wrap">${oldPriceHtml}<span class="text-[#f20c33] font-bold text-xs">${formatPrice(displayPrice)}</span></div>
                ${buttonHtml}
            </div>
        </div>`;
};

// --- Chaldal style: white card, dotted border, image + circular + button at bottom-right of image (overlapping down), price then name below
const generateProductCardChaldal = (p, isHighlight = false, cardOpts = {}) => {
    const { displayPrice } = getProductDisplayPrices(p);
    const borderClass = isHighlight ? 'border-2 border-[#f20c33]' : 'chaldal-card-border';
    const isOutOfStock = p.id % 5 === 0;
    const btn = isOutOfStock
        ? `<button class="chaldal-card-plus product-card-link w-11 h-11 rounded-full border-2 flex items-center justify-center bg-white shadow-sm transition" data-id="${p.id}" title="View" style="border-color: var(--btn-primary-bg); color: var(--btn-primary-bg);"><i class="fa-solid fa-arrow-right text-sm"></i></button>`
        : `<button class="chaldal-card-plus card-order-btn w-11 h-11 rounded-full border-2 flex items-center justify-center bg-white shadow-sm transition hover:text-white" data-id="${p.id}" title="Add to cart" style="border-color: var(--btn-primary-bg); color: var(--btn-primary-bg);"><i class="fa-solid fa-plus text-xl font-bold"></i></button>`;
    const imgA = productCardMainImgAttrs(cardOpts);
    const imgSpec = productCardMainImgSpec(p.imageUrl);
    return `
        <div class="product-card product-card--chaldal cursor-pointer product-card-link rounded-xl bg-white h-full flex flex-col border ${borderClass}" data-id="${p.id}">
            <div class="chaldal-card-img-wrap relative aspect-square bg-gray-50 flex items-center justify-center overflow-visible">
                <img src="${imgSpec.src}"${imgSpec.srcset ? ` srcset="${imgSpec.srcset}" sizes="${imgSpec.sizes}"` : ''} class="w-full h-full object-contain" width="200" height="200" alt="${p.name}"${imgA}>
                <div class="absolute right-2 bottom-0 translate-y-1/2 z-10">${btn}</div>
            </div>
            <div class="p-3 flex-grow flex flex-col relative">
                <p class="text-gray-900 font-bold text-base mb-0.5">${formatPrice(displayPrice)}</p>
                <h3 class="text-gray-700 text-sm font-normal leading-tight line-clamp-2" title="${p.name}">${p.name}</h3>
            </div>
        </div>`;
};

// --- Daraz style: card with shadow, seller, title, price, rating/location
const generateProductCardDaraz = (p, isHighlight = false, cardOpts = {}) => {
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    const borderClass = isHighlight ? 'border-[#f20c33]' : 'border-gray-200';
    let oldPriceHtml = '';
    if (regularPrice > displayPrice) oldPriceHtml = `<del class="text-gray-400 text-sm mr-1">${formatPrice(regularPrice)}</del>`;
    const sellerName = (p.sellerName && String(p.sellerName).trim()) ? p.sellerName : (state.siteSettings?.siteName || 'Store');
    const imgA = productCardMainImgAttrs(cardOpts);
    const imgSpec = productCardMainImgSpec(p.imageUrl);
    return `
        <div class="product-card product-card--daraz cursor-pointer product-card-link border ${borderClass} rounded-xl overflow-hidden bg-white h-full flex flex-col shadow-sm hover:shadow-md transition-shadow" data-id="${p.id}">
            <div class="daraz-card-img aspect-[1/1] bg-gray-50 overflow-hidden">
                <img src="${imgSpec.src}"${imgSpec.srcset ? ` srcset="${imgSpec.srcset}" sizes="${imgSpec.sizes}"` : ''} class="w-full h-full object-contain" width="200" height="200" alt="${p.name}"${imgA}>
            </div>
            <div class="p-3 flex-grow flex flex-col">
                <p class="text-xs font-medium mb-1 flex items-center gap-1" style="color: var(--btn-primary-bg);"><i class="fa-solid fa-store text-[10px]"></i>${sellerName}</p>
                <h3 class="font-medium text-gray-900 text-sm leading-tight line-clamp-2 mb-1" title="${p.name}">${p.name}</h3>
                <div class="flex items-center gap-1 flex-wrap mb-1">${oldPriceHtml}<span class="text-orange-500 font-bold text-sm">${formatPrice(displayPrice)}</span></div>
                <div class="flex items-center gap-2 text-xs text-gray-500 mt-auto">
                    <span class="flex items-center gap-0.5 text-amber-500"><i class="fa-solid fa-star text-[10px]"></i>4.0</span>
                    <span class="flex items-center gap-0.5"><i class="fa-solid fa-location-dot text-[10px]"></i>BD</span>
                </div>
            </div>
        </div>`;
};

// --- Shwapno card: action area is either "+ Add to Bag" or [−] qty [+]
const getShwapnoCardActionHtml = (productId) => {
    const qty = getCartQuantity(productId);
    if (qty === 0) return `<button class="card-order-btn shwapno-add-btn w-full py-2.5 rounded-full text-white font-bold text-sm transition flex items-center justify-center gap-1" data-id="${productId}" style="background-color: var(--btn-primary-bg);"><i class="fa-solid fa-plus"></i> Add to Bag</button>`;
    return `<div class="flex items-center justify-center gap-2 w-full py-1"><button type="button" class="shwapno-card-minus w-8 h-8 rounded-full flex items-center justify-center font-bold text-gray-700 border border-gray-300 hover:bg-gray-100 transition" data-id="${productId}" aria-label="Decrease">−</button><span class="shwapno-card-qty font-bold min-w-[28px] text-center text-sm">${qty}</span><button type="button" class="shwapno-card-plus w-8 h-8 rounded-full flex items-center justify-center font-bold text-white transition" data-id="${productId}" style="background-color: var(--btn-primary-bg);" aria-label="Increase">+</button></div>`;
};

const updateShwapnoCardActions = () => {
    document.querySelectorAll('.shwapno-card-actions').forEach(el => {
        const id = el.dataset.id;
        if (!id) return;
        const qty = getCartQuantity(id);
        el.innerHTML = qty === 0 ? getShwapnoCardActionHtml(id) : getShwapnoCardActionHtml(id);
    });
};

// --- Shwapno style: white card, centered; image → delivery → name → price + unit → "+ Add to Bag" or +/- quantity
const generateProductCardShwapno = (p, isHighlight = false, cardOpts = {}) => {
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    const hasDiscount = regularPrice > displayPrice;
    const saveRounded = hasDiscount ? Math.round(regularPrice - displayPrice) : 0;
    const showRibbon = hasDiscount && saveRounded > 0;
    const borderClass = isHighlight ? 'border-2 border-[#f20c33]' : 'border-gray-200';
    const deliveryText = state.siteSettings?.deliveryTimeText ? `Delivery ${state.siteSettings.deliveryTimeText}` : 'Delivery 1-2 hours';
    const unit = (p.unit && String(p.unit).trim()) ? String(p.unit).trim() : 'Per piece';
    const isOutOfStock = p.id % 5 === 0;
    const actionHtml = isOutOfStock
        ? `<button class="card-order-btn product-card-link w-full py-2.5 rounded-full text-white font-bold text-sm mt-3 transition" data-id="${p.id}" style="background-color: var(--btn-primary-bg);"><i class="fa-solid fa-arrow-right mr-1"></i>View</button>`
        : `<div class="shwapno-card-actions mt-3 w-full" data-id="${p.id}">${getShwapnoCardActionHtml(p.id)}</div>`;
    const imgA = productCardMainImgAttrs(cardOpts);
    const imgSpec = productCardMainImgSpec(p.imageUrl);
    const ribbonHtml = showRibbon
        ? `<div class="shwapno-discount-ribbon" aria-label="Save ${formatPrice(saveRounded)}"><span class="shwapno-discount-ribbon__amount">${formatPrice(saveRounded)}</span><span class="shwapno-discount-ribbon__off">OFF</span></div>`
        : '';
    const priceRowHtml = hasDiscount
        ? `<div class="shwapno-price-row flex items-center justify-center gap-2 flex-wrap mb-0.5">
                <span class="shwapno-price-mrp line-through text-gray-400 text-sm">${formatPrice(regularPrice)}</span>
                <span class="text-red-600 font-bold text-base">${formatPrice(displayPrice)}</span>
                <span class="text-xs text-gray-500">${unit.replace(/</g, '&lt;')}</span>
            </div>`
        : `<div class="flex items-center justify-center gap-1.5 flex-wrap mb-0.5">
                <span class="text-red-600 font-bold text-base">${formatPrice(displayPrice)}</span>
                <span class="text-xs text-gray-500">${unit.replace(/</g, '&lt;')}</span>
            </div>`;
    return `
        <div class="product-card product-card--shwapno cursor-pointer product-card-link border ${borderClass} rounded-xl overflow-hidden bg-white h-full flex flex-col items-center text-center p-4" data-id="${p.id}">
            <div class="shwapno-card-img-wrap w-full aspect-square bg-gray-50 rounded-lg overflow-hidden flex items-center justify-center mb-2 relative">
                ${ribbonHtml}
                <img src="${imgSpec.src}"${imgSpec.srcset ? ` srcset="${imgSpec.srcset}" sizes="${imgSpec.sizes}"` : ''} class="w-full h-full object-contain relative z-[1]" width="200" height="200" alt="${p.name.replace(/"/g, '&quot;')}"${imgA}>
            </div>
            <p class="shwapno-card-delivery text-xs text-gray-500 mb-1 italic">${deliveryText}</p>
            <h3 class="font-bold text-gray-900 text-sm leading-tight line-clamp-2 mb-1" title="${p.name.replace(/"/g, '&quot;')}">${p.name.replace(/</g, '&lt;')}</h3>
            ${priceRowHtml}
            ${actionHtml}
        </div>`;
};

// --- Order + Call: Order now goes to checkout; Call uses admin contact phone / hotline
const generateProductCardOrderCall = (p, isHighlight = false, cardOpts = {}) => {
    const { displayPrice, regularPrice } = getProductDisplayPrices(p);
    const oldPriceHtml = regularPrice > displayPrice ? `<span class="text-red-500 line-through text-xs mr-1">${formatPrice(regularPrice)}</span>` : '';
    const borderClass = isHighlight ? 'border-[#f20c33]' : 'border-gray-200';
    const contact = state.siteSettings?.contactInfo || {};
    const phoneRaw = String(contact.phoneNumber || contact.hotlineNumber || '').trim();
    const telHref = phoneRaw ? `tel:${phoneRaw.replace(/\s/g, '')}` : '';
    const callBtnHtml = telHref
        ? `<a href="${telHref}" class="card-call-btn flex items-center justify-center gap-1 rounded-md px-2 py-2 text-sm font-bold border border-gray-300 text-gray-700 hover:bg-gray-50 flex-shrink-0 min-w-[2.75rem]" title="Call"><i class="fa-solid fa-phone"></i></a>`
        : `<button type="button" disabled class="rounded-md px-2 py-2 text-sm font-bold border border-gray-200 text-gray-400 cursor-not-allowed flex-shrink-0 min-w-[2.75rem]" title="Set phone number in admin"><i class="fa-solid fa-phone"></i></button>`;
    const safeNameAttr = String(p.name || '').replace(/"/g, '&quot;');
    const safeNameHtml = String(p.name || '').replace(/</g, '&lt;');
    const imgA = productCardMainImgAttrs(cardOpts);
    const imgSpec = productCardMainImgSpec(p.imageUrl);
    return `
        <div class="product-card product-card--order-call border ${borderClass} rounded-xl overflow-hidden bg-white h-full flex flex-col">
            <div class="product-card-link cursor-pointer flex flex-col flex-1 min-h-0" data-id="${p.id}">
                <div class="aspect-[1/1] overflow-hidden bg-gray-50 flex items-center justify-center">
                    <img src="${imgSpec.src}"${imgSpec.srcset ? ` srcset="${imgSpec.srcset}" sizes="${imgSpec.sizes}"` : ''} class="w-full h-full object-contain" width="200" height="200" alt="${safeNameAttr}"${imgA}>
                </div>
                <div class="p-3 flex-grow flex flex-col">
                    <h3 class="font-bold text-gray-900 text-sm leading-tight line-clamp-2 mb-1" title="${safeNameAttr}">${safeNameHtml}</h3>
                    <div class="price-row items-center gap-2 flex-wrap">${oldPriceHtml}<span class="text-[#f20c33] font-bold text-sm">${formatPrice(displayPrice)}</span></div>
                </div>
            </div>
            <div class="p-3 pt-0 flex gap-2">
                <button type="button" class="card-order-now-btn flex-1 rounded-md py-2 text-sm font-bold hover:opacity-90 transition" style="background-color: var(--order-call-order-bg); color: var(--order-call-order-text);" data-id="${p.id}">Order now</button>
                ${callBtnHtml}
            </div>
        </div>`;
};

// --- Pick card by site setting: classic | app | minimal | imageFocus | chaldal | daraz | shwapno | orderCall
const getProductCard = (p, isHighlight = false, cardOpts) => {
    const style = state.siteSettings?.layout?.productDisplayStyle;
    const opts = cardOpts || {};
    if (style === 'app') return generateProductCardAppStyle(p, opts);
    if (style === 'minimal') return generateProductCardMinimal(p, isHighlight, opts);
    if (style === 'imageFocus') return generateProductCardImageFocus(p, isHighlight, opts);
    if (style === 'chaldal') return generateProductCardChaldal(p, isHighlight, opts);
    if (style === 'daraz') return generateProductCardDaraz(p, isHighlight, opts);
    if (style === 'shwapno') return generateProductCardShwapno(p, isHighlight, opts);
    if (style === 'orderCall') return generateProductCardOrderCall(p, isHighlight, opts);
    return generateProductCard(p, isHighlight, opts);
};

// ============================================================
// 4. ADVANCED CART UI
// ============================================================

const renderCartFreeShippingBar = (subtotal) => {
    const bar = getEl('cart-free-shipping-bar');
    if (!bar) return;
    const threshold = Number(state.siteSettings?.freeShippingThreshold) || 0;
    if (threshold <= 0) {
        bar.classList.add('hidden');
        bar.innerHTML = '';
        return;
    }
    bar.classList.remove('hidden');
    if (subtotal >= threshold) {
        bar.innerHTML = `
            <div class="flex items-center gap-2 text-sm font-semibold text-emerald-800">
                <i class="fa-solid fa-circle-check text-emerald-600"></i>
                <span>You unlocked <strong>FREE delivery</strong> on this order!</span>
            </div>`;
        return;
    }
    const pct = Math.min(100, Math.round((subtotal / threshold) * 100));
    const remaining = Math.max(0, threshold - subtotal);
    bar.innerHTML = `
        <p class="text-xs font-semibold text-gray-700 mb-1.5">Add <strong>${formatPrice(remaining)}</strong> more for <span class="text-emerald-700">FREE delivery</span></p>
        <div class="h-2 rounded-full bg-gray-200 overflow-hidden">
            <div class="h-full rounded-full bg-gradient-to-r from-emerald-400 to-emerald-600 transition-all duration-300" style="width: ${pct}%"></div>
        </div>
        <p class="text-[10px] text-gray-500 mt-1">Cart: ${formatPrice(subtotal)} / ${formatPrice(threshold)}</p>`;
};

const getCartUpsellProducts = (items, limit = 6) => {
    const cartIds = new Set(items.map((i) => String(i.id)));
    const cats = new Set();
    items.forEach((i) => {
        const p = state.allProducts.find((x) => String(x.id) === String(i.id));
        if (!p) return;
        if (Array.isArray(p.categories)) p.categories.forEach((c) => { if (c) cats.add(c); });
        if (p.category) cats.add(p.category);
    });
    if (!cats.size) return [];
    return state.allProducts.filter((p) => {
        if (cartIds.has(String(p.id))) return false;
        return [...cats].some((c) => productInCategory(p, c));
    }).slice(0, limit);
};

const renderAdvancedCartDrawer = (items, total) => {
    const cartBody = getEl('cart-body');
    const totalEls = document.querySelectorAll('.cart-total-price');
    const countEls = document.querySelectorAll('.cart-count');
    const checkoutBtn = getEl('checkout-btn');

    const count = items.reduce((acc, item) => acc + item.quantity, 0);
    countEls.forEach(el => el.textContent = count);
    totalEls.forEach(el => el.textContent = formatPrice(total));
    renderCartFreeShippingBar(total);

    if (doc.checkoutView && !doc.checkoutView.classList.contains('hidden')) updateOrderSummary();

    const footerElement = doc.cartDrawer ? doc.cartDrawer.lastElementChild : null;
    if (footerElement && footerElement.classList.contains('border-t')) {
        footerElement.innerHTML = `
            <div class="flex justify-between items-center mb-4">
                <span class="font-bold text-gray-700">Subtotal:</span>
                <span class="cart-total-price font-extrabold text-[#f20c33] text-lg">${formatPrice(total)}</span>
            </div>
            <div class="space-y-3">
                <button onclick="document.getElementById('cart-drawer').classList.remove('open'); document.getElementById('cart-overlay').style.display='none'; window.location.hash='#/checkout'; setTimeout(function(){ if(window.sbClassicSyncRouteAfterHash)window.sbClassicSyncRouteAfterHash(); }, 0);" class="w-full py-2.5 rounded-md border border-gray-300 font-bold text-gray-700 bg-white hover:bg-gray-50 transition">View cart</button>
                <button id="checkout-btn" onclick="document.getElementById('cart-drawer').classList.remove('open'); document.getElementById('cart-overlay').style.display='none'; window.location.hash='#/checkout'; setTimeout(function(){ if(window.sbClassicSyncRouteAfterHash)window.sbClassicSyncRouteAfterHash(); }, 0);" class="w-full py-2.5 rounded-md font-bold text-white hover:opacity-90 transition shadow-sm" style="background-color: var(--btn-primary-bg);">Checkout</button>
            </div>`;
    }

    if (items.length === 0) {
        cartBody.innerHTML = `
            <div class="flex flex-col items-center justify-center h-full text-gray-500">
                <div class="w-20 h-20 bg-gray-100 rounded-full flex items-center justify-center mb-4"><i class="fa-solid fa-basket-shopping text-3xl text-gray-400"></i></div>
                <p class="text-lg font-bold text-gray-700">Your cart is empty!</p>
                <p class="text-sm text-gray-400 mb-6">Add items to start ordering</p>
                <button onclick="document.getElementById('cart-overlay').click()" class="text-white px-8 py-2.5 rounded-full font-bold transition shadow-lg" style="background-color: var(--accent-color);">Start Shopping</button>
            </div>`;
        if(checkoutBtn) { checkoutBtn.disabled = true; checkoutBtn.classList.add('opacity-50', 'cursor-not-allowed'); }
        if (doc.checkoutView && !doc.checkoutView.classList.contains('hidden') && !isReplayMode()) { window.location.hash = '#/shop'; showToast("Your cart is empty!", "error"); }
    } else {
        cartBody.innerHTML = items.map(item => {
            const id = item.variantId ? `${item.id}_${item.variantId}` : item.id;
            return `
            <div class="flex gap-3 mb-4 border-b border-gray-100 pb-4 last:border-0 animate-[fadeIn_0.2s_ease-out]">
                <div class="w-16 h-16 flex-shrink-0 border rounded-md overflow-hidden bg-gray-50"><img src="${item.image}" class="w-full h-full object-contain" loading="lazy" decoding="async"></div>
                <div class="flex-grow flex flex-col justify-between">
                    <div><h4 class="font-bold text-sm text-gray-800 line-clamp-1" title="${item.name}">${item.name}</h4>${item.variantName ? `<p class="text-xs text-gray-500 bg-gray-100 inline-block px-1 rounded mt-1">${item.variantName}</p>` : ''}</div>
                    <div class="flex justify-between items-end mt-2">
                        <div class="flex items-center border border-gray-300 rounded overflow-hidden h-7">
                            <button class="decrease-qty-btn w-7 h-full flex items-center justify-center bg-gray-50 hover:bg-gray-200 transition text-gray-600" data-id="${id}"><i class="fa-solid fa-minus text-[10px]"></i></button>
                            <span class="w-8 h-full flex items-center justify-center text-sm font-bold text-gray-800 bg-white border-l border-r border-gray-300">${item.quantity}</span>
                            <button class="increase-qty-btn w-7 h-full flex items-center justify-center bg-gray-50 hover:bg-gray-200 transition text-gray-600" data-id="${id}"><i class="fa-solid fa-plus text-[10px]"></i></button>
                        </div>
                        <div class="text-right"><p class="font-bold text-sm" style="color: var(--accent-color);">${formatPrice(item.price * item.quantity)}</p></div>
                    </div>
                </div>
                <div class="flex flex-col justify-start"><button class="remove-from-cart-btn w-6 h-6 flex items-center justify-center rounded-full hover:bg-red-50 text-gray-300 hover:text-red-500 transition" data-id="${id}"><i class="fa-solid fa-xmark text-sm"></i></button></div>
            </div>`;
        }).join('');
        if(checkoutBtn) { checkoutBtn.disabled = false; checkoutBtn.classList.remove('opacity-50', 'cursor-not-allowed'); }
        const upsellProducts = getCartUpsellProducts(items, 6);
        const upsellHtml = upsellProducts.length
            ? `
            <div class="mt-5 pt-4 border-t border-dashed border-gray-200">
                <p class="text-xs font-bold text-gray-500 uppercase tracking-wide mb-3">You may also like</p>
                <div class="space-y-2 max-h-[220px] overflow-y-auto pr-1 custom-scrollbar">
                    ${upsellProducts.map((p) => {
                        const displayPrice = p.hasVariants && p.variants
                            ? Math.min(...Object.values(p.variants).map((v) => Number(v.salePrice) || 0))
                            : Number(p.salePrice) || 0;
                        const name = String(p.name || '').replace(/</g, '&lt;');
                        return `
                        <div class="flex gap-2 items-center p-2 rounded-lg border border-gray-100 bg-gray-50/80">
                            <img src="${p.imageUrl}" alt="" class="w-12 h-12 object-contain rounded border bg-white flex-shrink-0" loading="lazy" decoding="async">
                            <div class="flex-grow min-w-0">
                                <p class="text-xs font-semibold text-gray-800 line-clamp-2">${name}</p>
                                <p class="text-xs font-bold mt-0.5" style="color: var(--accent-color);">${formatPrice(displayPrice)}</p>
                            </div>
                            <button type="button" class="cart-upsell-add-btn flex-shrink-0 px-2 py-1.5 rounded-md text-xs font-bold text-white" style="background-color: var(--btn-primary-bg);" data-id="${p.id}">Add</button>
                        </div>`;
                    }).join('')}
                </div>
            </div>`
            : '';
        cartBody.insertAdjacentHTML('beforeend', upsellHtml);
    }
};

// ============================================================
// 5. RENDER FUNCTIONS
// ============================================================

const applyIconConfig = () => {
    const iconConfig = state.siteSettings?.layout?.iconConfig || {};
    document.querySelectorAll('[data-icon-slot]').forEach(el => {
        const slot = el.getAttribute('data-icon-slot');
        const cfg = iconConfig[slot];
        if (!cfg || !cfg.value) return;
        if (cfg.type === 'custom') {
            const img = document.createElement('img');
            img.src = cfg.value;
            img.alt = '';
            img.className = (el.className || '').replace(/\bfa[-\w]*/g, '').trim() || 'w-5 h-5 object-contain';
            img.setAttribute('data-icon-slot', slot);
            if (el.parentNode) el.parentNode.replaceChild(img, el);
        } else {
            el.className = (el.className || '').replace(/\bfa[-a-z0-9]+\s*/g, '').trim() + ' ' + (cfg.value || '').trim();
        }
    });
};

// --- NEW FUNCTION: Render Mobile Drawer Content ---
const renderMobileDrawerContent = (toggleMobileMenuFn) => {
    if (!doc.mobileDrawerContent) return;
    
    const settings = state.siteSettings || {};
    const contact = settings.contactInfo || {};
    const social = settings.socialLinks || {};
    const showCategoriesInMenu = !!(settings.layout && settings.layout.menuConfig && settings.layout.menuConfig.showCategoriesInMenu);
    const waNum = normalizeWhatsAppNumber(contact.whatsappNumber);
    const whatsappUrl = waNum.length >= 10 ? `https://wa.me/${waNum}` : '#';
    const facebookUrl = (social.facebook && social.facebook.trim()) ? social.facebook.trim() : '#';
    const youtubeUrl = (social.youtube && social.youtube.trim()) ? social.youtube.trim() : '#';
    const instagramUrl = (social.instagram && social.instagram.trim()) ? social.instagram.trim() : '#';

    const menuCategories = getMenuCategories();
    const categoriesBlock = showCategoriesInMenu && menuCategories && menuCategories.length > 0
        ? `
            <p class="text-xs font-bold text-gray-400 uppercase tracking-wider mb-2 mt-2">ক্যাটাগরি</p>
            <a href="#/shop" class="flex items-center gap-3 p-2 rounded-md hover:bg-gray-100 transition text-gray-700 font-medium drawer-link border-b border-gray-100"><i class="fa-solid fa-th-large w-5"></i> সকল পণ্য</a>
            ${menuCategories.map(cat => `<a href="#/category/${encodeURIComponent(cat.name)}" class="flex items-center gap-3 p-2 rounded-md hover:bg-gray-100 transition text-gray-700 font-medium drawer-link">${cat.name}</a>`).join('')}
            <hr class="my-3 border-gray-100">
        `
        : '';

    const hm = (settings.layout && settings.layout.hamburgerLinks) || {};
    const showShop = hm.shop !== false;
    const showFeatured = hm.featured !== false;
    const showWishlist = hm.wishlist !== false;
    const showAccount = hm.account !== false;
    const showSupport = hm.support !== false;
    const quickParts = [];
    if (showShop) quickParts.push('<a href="#/shop" class="flex items-center gap-3 p-2 rounded-md hover:bg-gray-100 transition text-gray-700 font-medium drawer-link"><i class="fa-solid fa-store w-5"></i> Shop</a>');
    if (showFeatured) quickParts.push('<a href="#/featured" class="flex items-center gap-3 p-2 rounded-md hover:bg-gray-100 transition text-gray-700 font-medium drawer-link"><i class="fa-solid fa-fire w-5 text-red-500"></i> Featured</a>');
    if (showWishlist) quickParts.push('<a href="#/wishlist" class="flex items-center gap-3 p-2 rounded-md hover:bg-gray-100 transition text-gray-700 font-medium drawer-link"><i class="fa-regular fa-heart w-5"></i> My Wishlist</a>');
    if (showAccount) quickParts.push('<a href="#/profile" class="flex items-center gap-3 p-2 rounded-md hover:bg-gray-100 transition text-gray-700 font-medium drawer-link"><i class="fa-regular fa-user w-5"></i> My Account</a>');
    if (showSupport) quickParts.push('<a href="#/page/contact" class="flex items-center gap-3 p-2 rounded-md hover:bg-gray-100 transition text-gray-700 font-medium drawer-link"><i class="fa-solid fa-headset w-5"></i> Support / Contact</a>');
    const quickLinksBlock = quickParts.length > 0
        ? `<p class="text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Quick Links</p>${quickParts.join('')}`
        : '';

    const html = `
        <div class="flex flex-col space-y-1 p-4">
            ${quickLinksBlock}
            ${categoriesBlock}

            <hr class="my-3 border-gray-100">

            <p class="text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Customer Care</p>
            <a href="#/policy/shipping" class="block p-2 text-sm text-gray-600 hover:text-green-600 drawer-link">Shipping Policy</a>
            <a href="#/policy/refund" class="block p-2 text-sm text-gray-600 hover:text-green-600 drawer-link">Return & Refund</a>
            <a href="#/policy/terms" class="block p-2 text-sm text-gray-600 hover:text-green-600 drawer-link">Terms & Conditions</a>
            <a href="#/policy/privacy" class="block p-2 text-sm text-gray-600 hover:text-green-600 drawer-link">Privacy Policy</a>

            <hr class="my-3 border-gray-100">

            <div class="mt-2">
                <p class="text-xs font-bold text-gray-400 uppercase tracking-wider mb-3">Contact Info</p>
                ${contact.phoneNumber ? `<a href="tel:${contact.phoneNumber}" class="flex items-center gap-2 text-sm text-gray-700 mb-2"><i class="fa-solid fa-phone text-green-600"></i> ${contact.phoneNumber}</a>` : ''}
                ${contact.address ? `<p class="flex items-start gap-2 text-sm text-gray-700"><i class="fa-solid fa-location-dot text-green-600 mt-1"></i> ${contact.address}</p>` : ''}
            </div>

            <div class="flex gap-4 mt-6">
                 <a href="${facebookUrl}" ${facebookUrl !== '#' ? 'target="_blank" rel="noopener noreferrer"' : ''} class="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-blue-600 hover:text-white transition"><i class="fa-brands fa-facebook-f"></i></a>
                 <a href="${whatsappUrl}" ${whatsappUrl !== '#' ? 'target="_blank" rel="noopener noreferrer"' : ''} class="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-green-500 hover:text-white transition"><i class="fa-brands fa-whatsapp"></i></a>
                 <a href="${youtubeUrl}" ${youtubeUrl !== '#' ? 'target="_blank" rel="noopener noreferrer"' : ''} class="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-red-500 hover:text-white transition"><i class="fa-brands fa-youtube"></i></a>
                 ${instagramUrl !== '#' ? `<a href="${instagramUrl}" target="_blank" rel="noopener noreferrer" class="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 hover:bg-pink-500 hover:text-white transition"><i class="fa-brands fa-instagram"></i></a>` : ''}
            </div>
        </div>
    `;
    doc.mobileDrawerContent.innerHTML = html;

    // Drawer links: hash links -> preventDefault, close drawer, then set hash so navigation always works (production-level)
    doc.mobileDrawerContent.querySelectorAll('.drawer-link').forEach(link => {
        link.addEventListener('click', (e) => {
            const href = link.getAttribute('href');
            if (href && href.startsWith('#')) {
                e.preventDefault();
                toggleMobileMenuFn(false);
                window.location.hash = href;
            } else {
                toggleMobileMenuFn(false);
            }
        });
    });
};

/** Optional banner destination: in-app hash/relative or http(s) (new tab + noopener). */
const applyStorefrontBannerLink = (anchorEl, hrefRaw) => {
    if (!anchorEl || anchorEl.tagName !== 'A') return;
    const h = String(hrefRaw || '').trim();
    anchorEl.classList.remove('pointer-events-none', 'cursor-default', 'cursor-pointer');
    anchorEl.removeAttribute('href');
    anchorEl.removeAttribute('target');
    anchorEl.removeAttribute('rel');
    if (!h) {
        anchorEl.classList.add('pointer-events-none', 'cursor-default');
        return;
    }
    anchorEl.setAttribute('href', h);
    anchorEl.classList.add('cursor-pointer');
    if (/^https?:\/\//i.test(h)) {
        anchorEl.setAttribute('target', '_blank');
        anchorEl.setAttribute('rel', 'noopener noreferrer');
    }
};

/** Fill one announcement strip root (desktop or mobile) from siteSettings.homeAnnouncementStrip */
const applyHomeAnnouncementStripTo = (stripRoot, settings) => {
    if (!stripRoot) return;
    const stripCfg = settings.homeAnnouncementStrip || {};
    const titleT = String(stripCfg.title || '').trim();
    const bodyT = String(stripCfg.body || '').trim();
    const ctaText = String(stripCfg.ctaText || '').trim();
    const ctaUrl = String(stripCfg.ctaUrl || '').trim();
    const hasContent = !!(titleT || bodyT || ctaText);
    const showStrip = !!stripCfg.enabled && hasContent;
    const elTitle = stripRoot.querySelector('.home-announcement-strip__title');
    const elBody = stripRoot.querySelector('.home-announcement-strip__body');
    const elCta = stripRoot.querySelector('.home-announcement-strip__cta');
    if (showStrip) {
        stripRoot.classList.remove('hidden');
        if (elTitle) {
            if (titleT) { elTitle.textContent = titleT; elTitle.classList.remove('hidden'); }
            else { elTitle.textContent = ''; elTitle.classList.add('hidden'); }
        }
        if (elBody) {
            if (bodyT) { elBody.textContent = bodyT; elBody.classList.remove('hidden'); }
            else { elBody.textContent = ''; elBody.classList.add('hidden'); }
        }
        if (elCta) {
            if (ctaText) {
                elCta.textContent = ctaText;
                elCta.classList.remove('hidden', 'is-disabled');
                applyStorefrontBannerLink(elCta, ctaUrl);
                if (!ctaUrl) elCta.classList.add('is-disabled');
            } else {
                elCta.textContent = '';
                elCta.classList.add('hidden');
                applyStorefrontBannerLink(elCta, '');
            }
        }
    } else {
        stripRoot.classList.add('hidden');
        if (elTitle) { elTitle.textContent = ''; elTitle.classList.add('hidden'); }
        if (elBody) { elBody.textContent = ''; elBody.classList.add('hidden'); }
        if (elCta) {
            elCta.textContent = '';
            elCta.classList.add('hidden');
            applyStorefrontBannerLink(elCta, '');
        }
    }
};

/** Mobile home: cream band under event strip (siteSettings.homeNewArrivalBand) */
const applyHomeNewArrivalBand = (settings) => {
    const el = doc.homeNewArrivalBandMobile;
    const annMob = doc.homeAnnouncementStripMobile;
    if (annMob) {
        annMob.classList.remove('mb-0');
        if (!annMob.classList.contains('mb-3')) annMob.classList.add('mb-3');
    }
    if (!el) return;
    const cfg = settings.homeNewArrivalBand && typeof settings.homeNewArrivalBand === 'object' ? settings.homeNewArrivalBand : {};
    const enabled = !!cfg.enabled;
    const raw = cfg.label != null ? String(cfg.label).trim() : '';
    const label = raw || 'NEW ARRIVAL';
    const textEl = el.querySelector('.home-new-arrival-band__text');
    if (enabled) {
        el.classList.remove('hidden');
        if (textEl) textEl.textContent = label;
        if (annMob) {
            annMob.classList.remove('mb-3');
            annMob.classList.add('mb-0');
        }
    } else {
        el.classList.add('hidden');
        if (textEl) textEl.textContent = '';
    }
};

const escAttrNar = (s) => String(s ?? '').replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');

/** Mobile: 2-col image-only categories under NEW ARRIVAL band (siteSettings.homeNewArrivalBand) */
const applyHomeNewArrivalCategoryGrid = (settings) => {
    const root = doc.homeNewArrivalCategoryGridMobile;
    if (!root) return;
    const cfg = settings.homeNewArrivalBand && typeof settings.homeNewArrivalBand === 'object' ? settings.homeNewArrivalBand : {};
    if (!cfg.fabrilifeCategoryGridEnabled) {
        root.classList.add('hidden');
        root.innerHTML = '';
        return;
    }
    const limit = Math.min(24, Math.max(4, parseInt(cfg.fabrilifeCategoryGridLimit, 10) || 8));
    const cats = (state.allCategories || []).filter((c) => c && String(c.name || '').trim()).slice(0, limit);
    if (!cats.length) {
        root.classList.add('hidden');
        root.innerHTML = '';
        return;
    }
    root.classList.remove('hidden');
    root.innerHTML = cats.map((cat) => {
        const name = String(cat.name || '').trim();
        const nameEsc = escAttrNar(name);
        const img = String(cat.imageUrl || '').trim();
        const inner = img
            ? `<img src="${escAttrNar(img)}" alt="${nameEsc}" width="120" height="120" loading="lazy">`
            : `<div class="home-nar-cat-grid__placeholder" role="img" aria-label="${nameEsc}"></div>`;
        return `<a href="#/category/${encodeURIComponent(name)}" class="home-nar-cat-grid__card" title="${nameEsc}" aria-label="${nameEsc}"><div class="home-nar-cat-grid__img-wrap">${inner}</div></a>`;
    }).join('');
};

/** Mobile: full-width Fabrilife-style banners after NAR category grid (siteSettings.homeNewArrivalBand) */
const applyHomeFabrilifePostGridBanners = (settings) => {
    const root = doc.homeFabrilifePostGridBanners;
    if (!root) return;
    const cfg = settings.homeNewArrivalBand && typeof settings.homeNewArrivalBand === 'object' ? settings.homeNewArrivalBand : {};
    if (!cfg.fabrilifePostGridBannersEnabled) {
        root.classList.add('hidden');
        root.innerHTML = '';
        return;
    }
    const raw = Array.isArray(cfg.fabrilifePostGridBanners) ? cfg.fabrilifePostGridBanners : [];
    const slots = [0, 1].map((i) => {
        const x = raw[i] && typeof raw[i] === 'object' ? raw[i] : {};
        return {
            imageUrl: String(x.imageUrl || '').trim(),
            linkUrl: String(x.linkUrl || '').trim(),
            caption: String(x.caption || '').trim()
        };
    });
    const withImage = slots.filter((s) => s.imageUrl);
    if (!withImage.length) {
        root.classList.add('hidden');
        root.innerHTML = '';
        return;
    }
    root.classList.remove('hidden');
    root.innerHTML = withImage.map((s, idx) => {
        const alt = escAttrNar(s.caption || 'Banner');
        const capHtml = s.caption ? `<span class="home-fab-post-banners__caption">${escAttrNar(s.caption)}</span>` : '';
        const imgAttrs = idx === 0 ? 'loading="eager" fetchpriority="high" decoding="async"' : 'loading="lazy" decoding="async"';
        return `<a class="home-fab-post-banners__item"><img src="${escAttrNar(s.imageUrl)}" alt="${alt}" width="800" height="500" ${imgAttrs}>${capHtml}</a>`;
    }).join('');
    root.querySelectorAll('a.home-fab-post-banners__item').forEach((a, idx) => {
        const link = withImage[idx] ? withImage[idx].linkUrl : '';
        applyStorefrontBannerLink(a, link);
    });
};

const storefrontImgAttrsFromGridIndex = (gridIndex) => {
    const gi = Number(gridIndex);
    if (Number.isFinite(gi) && gi >= 0 && gi < STORE_GRID_PRIORITY_COUNT) {
        return ' loading="eager" fetchpriority="high" decoding="async"';
    }
    return ' loading="lazy" decoding="async"';
};

const storefrontCategoryIconImgAttrs = (globalIndex) => {
    const g = Number(globalIndex);
    if (Number.isFinite(g) && g >= 0 && g < STORE_CAT_ICON_PRIORITY_COUNT) {
        return ' loading="eager" fetchpriority="high" decoding="async"';
    }
    return ' loading="lazy" decoding="async"';
};

const productCardMainImgAttrs = (cardOpts) => storefrontImgAttrsFromGridIndex(cardOpts && cardOpts.gridIndex);
const productCardMainImgSpec = (url) => getResponsiveImageSpec(url, {
    widths: [240, 420, 640, 920],
    fallbackWidth: 420,
    quality: 78,
    sizes: '(max-width: 768px) 50vw, (max-width: 1024px) 33vw, 25vw'
});

/** Inject preconnect/dns-prefetch for external image origins from settings (logo, banners, optional layout.imageCdnOrigin). */
const applyStorefrontImageHints = (settings) => {
    const s = settings || {};
    const urls = [];
    const add = (u) => {
        const t = (u != null && String(u).trim()) ? String(u).trim() : '';
        if (/^https?:\/\//i.test(t)) urls.push(t);
    };
    add(s.logoUrl);
    add(s.footerLogoUrl);
    const layout = s.layout || {};
    add(layout.imageCdnOrigin);
    if (s.imageCdnOrigin) add(s.imageCdnOrigin);
    const slides = (s.bannerSlides && s.bannerSlides.length)
        ? s.bannerSlides
        : (s.bannerUrls && s.bannerUrls.length)
            ? s.bannerUrls.map((url) => ({ imageUrl: url }))
            : [];
    slides.slice(0, 3).forEach((sl) => add(sl && sl.imageUrl));
    const sm = s.smallBanners;
    if (Array.isArray(sm)) sm.slice(0, 2).forEach((u) => add(u));
    add(s.promoBanner1Url);
    add(s.promoBanner2Url);
    const origins = new Set();
    urls.forEach((url) => {
        try {
            const o = new URL(url).origin;
            if (o.startsWith('http')) origins.add(o);
        } catch (e) { /* ignore invalid URL */ }
    });
    origins.forEach((origin) => {
        const id = 'sf-preconnect-' + origin.replace(/^https?:\/\//, '').replace(/[^a-z0-9]+/gi, '-').slice(0, 100);
        if (document.getElementById(id)) return;
        const pc = document.createElement('link');
        pc.id = id;
        pc.rel = 'preconnect';
        pc.href = origin;
        pc.crossOrigin = '';
        document.head.appendChild(pc);
        const df = document.createElement('link');
        df.rel = 'dns-prefetch';
        df.href = origin;
        document.head.appendChild(df);
    });
    ensureImagePreconnects(collectImageOrigins(settings));
};

const applyCategoryListingBannerHeights = (settings) => {
    const cc = settings && settings.layout && settings.layout.categoryConfig ? settings.layout.categoryConfig : {};
    const m = Math.min(600, Math.max(80, Number(cc.listingBannerMaxHeightMobile) || 200));
    const d = Math.min(800, Math.max(100, Number(cc.listingBannerMaxHeightDesktop) || 240));
    document.documentElement.style.setProperty('--category-listing-banner-max-mobile', `${m}px`);
    document.documentElement.style.setProperty('--category-listing-banner-max-desktop', `${d}px`);
};

const applyClassicProductSpacing = (settings) => {
    const cc = settings && settings.layout && settings.layout.categoryConfig ? settings.layout.categoryConfig : {};
    const enabled = cc.productSpacingEnabled === true;
    if (!enabled) {
        document.documentElement.style.removeProperty('--classic-product-side-padding');
        document.documentElement.style.removeProperty('--classic-product-gap-mobile');
        document.documentElement.style.removeProperty('--classic-product-gap-desktop');
        return;
    }
    const sidePadding = Math.min(80, Math.max(0, Number(cc.productSidePaddingPx) || 0));
    const cardGap = Math.min(40, Math.max(0, Number(cc.productCardGapPx) || 10));
    document.documentElement.style.setProperty('--classic-product-side-padding', `${sidePadding}px`);
    document.documentElement.style.setProperty('--classic-product-gap-mobile', `${cardGap}px`);
    document.documentElement.style.setProperty('--classic-product-gap-desktop', `${cardGap}px`);
};

const HOMEPAGE_FEATURE_DEFAULTS = [
    { icon: 'fa-solid fa-truck-fast', title: '60 Mins Delivery', subtitle: 'Free shipping over 1500tk' },
    { icon: 'fa-solid fa-shield-halved', title: 'Authorized Products', subtitle: 'Within 30 days for an exchange' },
    { icon: 'fa-solid fa-headset', title: 'Customer Service Support', subtitle: '8am to 10pm' },
    { icon: 'fa-solid fa-credit-card', title: 'Flexible Payments', subtitle: 'Pay with multiple credit cards' }
];

const escapeHomepageFeatureHtml = (value) => String(value ?? '')
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');

const sanitizeHomepageFeatureIcon = (value, fallback) => {
    const cleaned = String(value || '').trim().replace(/[^a-zA-Z0-9\-\s]/g, '');
    return cleaned || fallback;
};

const pickFeatureText = (rawValue, fallback) => {
    const text = String(rawValue == null ? '' : rawValue).trim();
    return text || fallback;
};

const HOMEPAGE_FEATURE_ROOT_VAR_NAMES = [
    '--optional-feature-card-bg',
    '--optional-feature-card-border',
    '--optional-feature-card-shadow',
    '--optional-feature-icon-bg',
    '--optional-feature-icon-border',
    '--optional-feature-icon-color',
    '--optional-feature-title-color',
    '--optional-feature-subtitle-color',
    '--optional-feature-grid-gap',
];

function clearHomepageFeatureRootVars() {
    const root = document.documentElement.style;
    HOMEPAGE_FEATURE_ROOT_VAR_NAMES.forEach((name) => root.removeProperty(name));
}

function normalizeHomepageFeatureCssColor(raw) {
    const s = String(raw == null ? '' : raw).trim();
    if (!s) return null;
    const lower = s.toLowerCase();
    if (lower === 'transparent') return 'transparent';
    let hex = s.startsWith('#') ? s.slice(1) : s;
    if (/^[0-9a-f]{3}$/i.test(hex)) {
        hex = hex.split('').map((c) => c + c).join('');
    }
    if (/^[0-9a-f]{6}$/i.test(hex)) return `#${hex.toLowerCase()}`;
    return null;
}

function normalizeHomepageFeatureShadow(raw) {
    const s = String(raw == null ? '' : raw).trim();
    if (!s || s.length > 200) return null;
    const lower = s.toLowerCase();
    if (lower.includes('url(') || lower.includes('<') || lower.includes('expression') || lower.includes('@import')) return null;
    return s;
}

function normalizeHomepageFeatureGapPx(raw) {
    const n = Number(raw);
    if (!Number.isFinite(n)) return null;
    const i = Math.round(n);
    if (i < 0 || i > 48) return null;
    return `${i}px`;
}

function applyHomepageFeatureStyles(settings) {
    clearHomepageFeatureRootVars();
    const config = settings && settings.layout && settings.layout.homepageFeatures ? settings.layout.homepageFeatures : {};
    const styles = config.styles && typeof config.styles === 'object' ? config.styles : {};
    const root = document.documentElement.style;
    const setColor = (cssName, key) => {
        const v = normalizeHomepageFeatureCssColor(styles[key]);
        if (v) root.setProperty(cssName, v);
    };
    setColor('--optional-feature-card-bg', 'cardBg');
    setColor('--optional-feature-card-border', 'cardBorder');
    const shadow = normalizeHomepageFeatureShadow(styles.cardShadow);
    if (shadow) root.setProperty('--optional-feature-card-shadow', shadow);
    setColor('--optional-feature-icon-bg', 'iconBg');
    setColor('--optional-feature-icon-border', 'iconBorder');
    setColor('--optional-feature-icon-color', 'iconColor');
    setColor('--optional-feature-title-color', 'titleColor');
    setColor('--optional-feature-subtitle-color', 'subtitleColor');
    const gap = normalizeHomepageFeatureGapPx(styles.gridGapPx);
    if (gap) root.setProperty('--optional-feature-grid-gap', gap);
}

const renderHomepageFeatures = (settings) => {
    const config = settings && settings.layout && settings.layout.homepageFeatures ? settings.layout.homepageFeatures : {};
    const enabled = config.enabled === true;
    if (!enabled) {
        clearHomepageFeatureRootVars();
    }
    const slots = [
        { section: doc.homepageFeaturesSectionMobile, grid: doc.homepageFeaturesGridMobile },
        { section: doc.homepageFeaturesSectionDesktop, grid: doc.homepageFeaturesGridDesktop },
    ].filter((s) => s.section && s.grid);
    if (slots.length === 0) return;
    const items = Array.isArray(config.items) ? config.items : [];
    const clearAll = () => {
        slots.forEach(({ section, grid }) => {
            section.classList.add('hidden');
            grid.innerHTML = '';
        });
    };
    if (!enabled) {
        clearAll();
        return;
    }
    applyHomepageFeatureStyles(settings);
    const html = HOMEPAGE_FEATURE_DEFAULTS.map((defaults, idx) => {
        const item = items[idx] && typeof items[idx] === 'object' ? items[idx] : {};
        const icon = sanitizeHomepageFeatureIcon(item.icon, defaults.icon);
        const title = pickFeatureText(item.title, defaults.title);
        const subtitle = pickFeatureText(item.subtitle, defaults.subtitle);
        return `
            <article class="homepage-feature-card">
                <span class="homepage-feature-icon"><i class="${escapeHomepageFeatureHtml(icon)}" aria-hidden="true"></i></span>
                <div>
                    <p class="homepage-feature-title">${escapeHomepageFeatureHtml(title)}</p>
                    <p class="homepage-feature-subtitle">${escapeHomepageFeatureHtml(subtitle)}</p>
                </div>
            </article>
        `;
    });
    const htmlStr = html.join('');
    slots.forEach(({ section, grid }) => {
        grid.innerHTML = htmlStr;
        section.classList.remove('hidden');
    });
};

/**
 * Thumbnail strip below home banner (PC + mobile): optional subset from siteSettings.layout.categoryConfig.homeThumbnailCategoryNames.
 * Empty or missing list keeps legacy behavior (all categories). Order follows the saved name list.
 */
function resolveHomeThumbnailCategories(allCategories, categoryConfig) {
    const all = Array.isArray(allCategories) ? allCategories : [];
    const raw = categoryConfig && Array.isArray(categoryConfig.homeThumbnailCategoryNames)
        ? categoryConfig.homeThumbnailCategoryNames
        : [];
    const names = raw.map((n) => String(n || '').trim()).filter(Boolean);
    if (names.length === 0) return all;
    const byName = new Map(
        all.map((c) => [String(c?.name || '').trim(), c]).filter(([k]) => k)
    );
    const out = [];
    names.forEach((name) => {
        const cat = byName.get(name);
        if (cat) out.push(cat);
    });
    return out;
}

const destroyRecommendedForYouSwipers = () => {
    if (recommendedSwiperDesktop) {
        try {
            recommendedSwiperDesktop.destroy(true, true);
        } catch (_) { /* noop */ }
        recommendedSwiperDesktop = null;
    }
    if (recommendedSwiperMobile) {
        try {
            recommendedSwiperMobile.destroy(true, true);
        } catch (_) { /* noop */ }
        recommendedSwiperMobile = null;
    }
};

/** Same rule as main `#flash-sale-section` featured strip (on sale, no variants), max 10. */
const getFlashFeaturedProductList = () =>
    (state.allProducts || [])
        .filter((p) => p && !p.hasVariants && p.regularPrice > p.salePrice)
        .slice(0, 10);

const resetRecommendedHeroSectionHeaders = () => {
    const hd = doc.recommendedForYouSectionDesktop?.querySelector('.section-header');
    const hm = doc.recommendedForYouSectionMobile?.querySelector('.section-header');
    if (hd) {
        hd.innerHTML =
            '<h3 id="recommended-for-you-title-desktop" class="section-title recommended-for-you-title">Recommended For You</h3>';
    }
    if (hm) {
        hm.innerHTML =
            '<h3 id="recommended-for-you-title-mobile" class="section-title recommended-for-you-title">Recommended For You</h3>';
    }
    doc.recommendedForYouTitleDesktop = getEl('recommended-for-you-title-desktop');
    doc.recommendedForYouTitleMobile = getEl('recommended-for-you-title-mobile');
};

const applyRecommendedFeaturedFallbackHeaders = (titleText) => {
    const t = escapeHomepageFeatureHtml(titleText);
    const row = `<div class="flex justify-between items-center mb-3 px-1 cursor-pointer" role="link" tabindex="0" onclick="window.location.hash='#/featured'"><h3 class="section-title recommended-for-you-title text-lg md:text-xl font-bold text-gray-900">${t}</h3><button type="button" class="w-7 h-7 rounded-full bg-gray-100 flex items-center justify-center hover:bg-gray-200 transition text-gray-600" aria-label="View featured products"><i class="fa-solid fa-chevron-right text-xs" aria-hidden="true"></i></button></div>`;
    const hd = doc.recommendedForYouSectionDesktop?.querySelector('.section-header');
    const hm = doc.recommendedForYouSectionMobile?.querySelector('.section-header');
    if (hd) hd.innerHTML = row;
    if (hm) hm.innerHTML = row;
};

/** Curated or featured-fallback carousel under service strip (`layout.recommendedSection`). */
const renderRecommendedForYouHome = (settings) => {
    const rs = settings && settings.layout && settings.layout.recommendedSection ? settings.layout.recommendedSection : {};
    const sectionD = doc.recommendedForYouSectionDesktop;
    const sectionM = doc.recommendedForYouSectionMobile;
    const wrapD = doc.recommendedForYouWrapperDesktop;
    const wrapM = doc.recommendedForYouWrapperMobile;
    const swiperElD = doc.recommendedForYouSwiperDesktop;
    const swiperElM = doc.recommendedForYouSwiperMobile;

    const hideAll = () => {
        destroyRecommendedForYouSwipers();
        resetRecommendedHeroSectionHeaders();
        if (wrapD) wrapD.innerHTML = '';
        if (wrapM) wrapM.innerHTML = '';
        if (sectionD) sectionD.classList.add('hidden');
        if (sectionM) sectionM.classList.add('hidden');
    };

    const bindFeaturedHeaderKey = () => {
        [sectionD, sectionM].forEach((sec) => {
            if (!sec) return;
            const hdr = sec.querySelector('.section-header .flex.justify-between');
            if (!hdr || hdr.dataset.featuredHeaderBound) return;
            hdr.dataset.featuredHeaderBound = '1';
            hdr.addEventListener('keydown', (ev) => {
                if (ev.key === 'Enter' || ev.key === ' ') {
                    ev.preventDefault();
                    window.location.hash = '#/featured';
                }
            });
        });
    };

    const showSwiperWithProducts = (products) => {
        destroyRecommendedForYouSwipers();
        const slidesHtml = products
            .map((p, i) => `<div class="swiper-slide h-auto">${getProductCard(p, false, { gridIndex: i })}</div>`)
            .join('');
        if (wrapD) wrapD.innerHTML = slidesHtml;
        if (wrapM) wrapM.innerHTML = slidesHtml;
        const pg = settings.layout?.productGridConfig || {};
        const colsMobile = Math.min(5, Math.max(2, parseInt(pg.columnsMobile, 10) || 3));
        const colsDesktop = Math.min(8, Math.max(2, parseInt(pg.columnsDesktop, 10) || 5));
        const swiperOpts = {
            slidesPerView: colsMobile,
            spaceBetween: 10,
            autoplay: { delay: 3200, disableOnInteraction: false },
            speed: 800,
            observer: true,
            observeParents: true,
            breakpoints: { 768: { slidesPerView: colsDesktop } }
        };
        if (sectionD) sectionD.classList.remove('hidden');
        if (sectionM) sectionM.classList.remove('hidden');
        try {
            if (swiperElD) recommendedSwiperDesktop = new Swiper(swiperElD, swiperOpts);
        } catch (_) { /* noop */ }
        try {
            if (swiperElM) recommendedSwiperMobile = new Swiper(swiperElM, swiperOpts);
        } catch (_) { /* noop */ }
    };

    const featuredList = getFlashFeaturedProductList();

    if (rs.enabled === true) {
        const rawIds = Array.isArray(rs.productIds) ? rs.productIds.map((x) => String(x || '').trim()).filter(Boolean) : [];
        const uniqueIds = [...new Set(rawIds)].slice(0, 24);
        const maxItems = Math.min(24, Math.max(1, parseInt(rs.maxItems, 10) || 12));
        const idSlice = uniqueIds.slice(0, maxItems);
        const catalog = state.allProducts || [];
        const products = idSlice
            .map((id) => catalog.find((p) => String(p.id) === String(id)))
            .filter(Boolean);
        if (products.length === 0) {
            hideAll();
            return;
        }
        resetRecommendedHeroSectionHeaders();
        const titleText = (rs.title && String(rs.title).trim()) || 'Recommended For You';
        if (doc.recommendedForYouTitleDesktop) doc.recommendedForYouTitleDesktop.textContent = titleText;
        if (doc.recommendedForYouTitleMobile) doc.recommendedForYouTitleMobile.textContent = titleText;
        showSwiperWithProducts(products);
        return;
    }

    if (rs.fallbackWhenDisabled === 'featuredProducts' && featuredList.length > 0) {
        const fbTitle = (rs.fallbackTitle && String(rs.fallbackTitle).trim()) || 'Featured Products';
        applyRecommendedFeaturedFallbackHeaders(fbTitle);
        showSwiperWithProducts(featuredList);
        bindFeaturedHeaderKey();
        return;
    }

    hideAll();
};

const destroyCategoryBannerSwipers = () => {
    if (categoryBannerSwiperDesktop) {
        try {
            categoryBannerSwiperDesktop.destroy(true, true);
        } catch (_) { /* noop */ }
        categoryBannerSwiperDesktop = null;
    }
    if (categoryBannerSwiperMobile) {
        try {
            categoryBannerSwiperMobile.destroy(true, true);
        } catch (_) { /* noop */ }
        categoryBannerSwiperMobile = null;
    }
};

const hideCategoryBannerSectionHome = () => {
    categoryBannerRuntime = null;
    destroyCategoryBannerSwipers();
    if (doc.categoryBannerSectionDesktop) doc.categoryBannerSectionDesktop.classList.add('hidden');
    if (doc.categoryBannerSectionMobile) doc.categoryBannerSectionMobile.classList.add('hidden');
};

const buildCategoryBannerTabsHtml = (orderedNames, activeName) =>
    orderedNames
        .map((name) => {
            const active = name === activeName;
            const enc = encodeURIComponent(name);
            const base = 'cbs-tab shrink-0 whitespace-nowrap';
            const activeCls = active ? ' is-active' : '';
            return `<button type="button" class="${base}${activeCls}" role="tab" aria-selected="${active ? 'true' : 'false'}" data-cbs-tab="${enc}">${escapeHomepageFeatureHtml(
                name
            )}</button>`;
        })
        .join('');

const ensureCategoryBannerTabDelegation = () => {
    if (categoryBannerTabDelegateBound) return;
    if (!doc.categoryBannerSectionDesktop || !doc.categoryBannerSectionMobile) return;
    categoryBannerTabDelegateBound = true;
    const onRootClick = (root) => (e) => {
        const btn = e.target.closest('[data-cbs-tab]');
        if (!btn || !root.contains(btn)) return;
        if (!categoryBannerRuntime) return;
        let name = '';
        try {
            name = decodeURIComponent(btn.getAttribute('data-cbs-tab') || '');
        } catch (_) {
            return;
        }
        if (!name || !categoryBannerRuntime.ordered.includes(name)) return;
        categoryBannerRuntime.activate(root, name);
    };
    doc.categoryBannerSectionDesktop.addEventListener('click', onRootClick(doc.categoryBannerSectionDesktop));
    doc.categoryBannerSectionMobile.addEventListener('click', onRootClick(doc.categoryBannerSectionMobile));
};

/** Recommended-পরবর্তী: বাম ব্যানার + ক্যাটাগরি ট্যাব + পণ্য সোয়াইপার (Classic)। */
const renderCategoryBannerSectionHome = (settings) => {
    ensureCategoryBannerTabDelegation();
    const cfg =
        settings && settings.layout && settings.layout.categoryBannerSection && typeof settings.layout.categoryBannerSection === 'object'
            ? settings.layout.categoryBannerSection
            : {};

    if (cfg.enabled !== true) {
        hideCategoryBannerSectionHome();
        return;
    }

    const catalogNames = new Set(
        (state.allCategories || [])
            .map((c) => String(c?.name || '').trim())
            .filter(Boolean)
    );
    const rawOrder = Array.isArray(cfg.categoryNames) ? cfg.categoryNames : [];
    const ordered = [...new Set(rawOrder.map((n) => String(n || '').trim()).filter((n) => catalogNames.has(n)))];
    if (ordered.length === 0) {
        hideCategoryBannerSectionHome();
        return;
    }

    const maxN = Math.min(24, Math.max(1, parseInt(cfg.maxProductsPerCategory, 10) || 10));
    const hideWhenNoProducts = cfg.hideWhenNoProducts !== false;
    const productsByName = {};
    ordered.forEach((nm) => {
        productsByName[nm] = (state.allProducts || []).filter((p) => productInCategory(p, nm)).slice(0, maxN);
    });

    const def = String(cfg.defaultCategoryName || '').trim();
    let active = null;
    if (def && ordered.includes(def)) {
        if (!hideWhenNoProducts || (productsByName[def] || []).length > 0) active = def;
    }
    if (!active && hideWhenNoProducts) {
        active = ordered.find((n) => (productsByName[n] || []).length > 0) || null;
    }
    if (!active && !hideWhenNoProducts) active = ordered[0];
    if (!active) {
        hideCategoryBannerSectionHome();
        return;
    }

    const pg = settings.layout?.productGridConfig || {};
    const colsMobile = Math.min(5, Math.max(2, parseInt(pg.columnsMobile, 10) || 3));
    const colsDesktop = Math.min(8, Math.max(2, parseInt(pg.columnsDesktop, 10) || 5));
    const swiperOptsBase = {
        slidesPerView: colsMobile,
        spaceBetween: 10,
        autoplay: { delay: 2800, disableOnInteraction: false },
        speed: 800,
        observer: true,
        observeParents: true,
        breakpoints: { 768: { slidesPerView: colsDesktop } }
    };

    const fillSurface = (root, catName) => {
        if (!root) return;
        const isDesktop = root === doc.categoryBannerSectionDesktop;
        const tablist = root.querySelector('[role="tablist"]');
        if (tablist) tablist.innerHTML = buildCategoryBannerTabsHtml(ordered, catName);
        const swiperEl = root.querySelector('[data-cbs-swiper]');
        const wrap = root.querySelector('[data-cbs-products-wrap]');
        if (!swiperEl || !wrap) return;
        if (isDesktop && categoryBannerSwiperDesktop) {
            try {
                categoryBannerSwiperDesktop.destroy(true, true);
            } catch (_) { /* noop */ }
            categoryBannerSwiperDesktop = null;
        }
        if (!isDesktop && categoryBannerSwiperMobile) {
            try {
                categoryBannerSwiperMobile.destroy(true, true);
            } catch (_) { /* noop */ }
            categoryBannerSwiperMobile = null;
        }
        const list = productsByName[catName] || [];
        const slidesHtml =
            list.length > 0
                ? list
                    .map((p, i) => `<div class="swiper-slide h-auto">${getProductCard(p, false, { gridIndex: i })}</div>`)
                    .join('')
                : '<div class="swiper-slide h-auto"><p class="text-sm text-gray-500 py-6 px-2">এই ক্যাটাগরিতে কোনো পণ্য নেই।</p></div>';
        wrap.innerHTML = slidesHtml;
        try {
            const sw = new Swiper(swiperEl, swiperOptsBase);
            if (isDesktop) categoryBannerSwiperDesktop = sw;
            else categoryBannerSwiperMobile = sw;
        } catch (_) { /* noop */ }
    };

    const title = String(cfg.title || '').trim();
    const imgUrl = String(cfg.bannerImageUrl || '').trim();
    const linkUrl = String(cfg.bannerLinkUrl || '').trim();
    const alt = String(cfg.bannerAlt || '').trim();

    const applyBannerSide = (isDesktop) => {
        const aside = isDesktop ? doc.categoryBannerAsideDesktop : doc.categoryBannerAsideMobile;
        const aEl = isDesktop ? doc.categoryBannerLinkDesktop : doc.categoryBannerLinkMobile;
        const im = isDesktop ? doc.categoryBannerImgDesktop : doc.categoryBannerImgMobile;
        if (!aside || !aEl || !im) return;
        if (imgUrl) {
            aside.classList.remove('hidden');
            im.src = imgUrl;
            im.alt = alt || 'Banner';
            applyStorefrontBannerLink(aEl, linkUrl);
        } else {
            aside.classList.add('hidden');
            im.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
            im.alt = '';
            applyStorefrontBannerLink(aEl, '');
        }
    };

    const applyTitleSide = (isDesktop) => {
        const wrap = isDesktop ? doc.categoryBannerTitleWrapDesktop : doc.categoryBannerTitleWrapMobile;
        const h = isDesktop ? doc.categoryBannerSectionTitleDesktop : doc.categoryBannerSectionTitleMobile;
        if (!wrap || !h) return;
        if (title) {
            h.textContent = title;
            wrap.classList.remove('hidden');
        } else {
            wrap.classList.add('hidden');
            h.textContent = '';
        }
    };

    if (doc.categoryBannerSectionDesktop) doc.categoryBannerSectionDesktop.classList.remove('hidden');
    if (doc.categoryBannerSectionMobile) doc.categoryBannerSectionMobile.classList.remove('hidden');

    applyTitleSide(true);
    applyTitleSide(false);
    applyBannerSide(true);
    applyBannerSide(false);

    categoryBannerRuntime = {
        ordered,
        activate(root, catName) {
            fillSurface(root, catName);
        }
    };

    fillSurface(doc.categoryBannerSectionDesktop, active);
    fillSurface(doc.categoryBannerSectionMobile, active);
};

const destroyHomeManualCatRowsSwiper = () => {
    if (homeManualCatRowsSwiper) {
        try {
            homeManualCatRowsSwiper.destroy(true, true);
        } catch (_) { /* noop */ }
        homeManualCatRowsSwiper = null;
    }
};

/** @returns {{ tabs: Array, byId: Map, defaultManualTabId: string, manualTitle: string }|null} */
const normalizeHomeManualTabsFromLayout = (layout) => {
    const hcr = layout && layout.homeCategoryRowsSection;
    if (!hcr || hcr.mode !== 'manualTabs' || !Array.isArray(hcr.manualTabs)) return null;
    const tabs = hcr.manualTabs
        .map((t, i) => ({
            id: String(t && t.id != null ? t.id : '').trim() || `tab_${i}`,
            label: String(t && t.label != null ? t.label : '').trim(),
            productIds: Array.isArray(t && t.productIds)
                ? t.productIds.map((x) => String(x || '').trim()).filter(Boolean)
                : [],
            maxItems: (() => {
                const n = parseInt(t && t.maxItems, 10);
                return Number.isFinite(n) ? Math.min(24, Math.max(1, n)) : 10;
            })()
        }))
        .filter((t) => t.id && t.label);
    if (!tabs.length) return null;
    const catalog = state.allProducts || [];
    const byId = new Map(catalog.map((p) => [String(p.id), p]));
    let defId = String(hcr.defaultManualTabId || '').trim();
    if (!tabs.some((t) => t.id === defId)) defId = tabs[0].id;
    return {
        tabs,
        byId,
        defaultManualTabId: defId,
        manualTitle: String(hcr.manualTitle || '').trim()
    };
};

const buildHomeManualCatRowsTabsHtml = (tabs, activeId) =>
    tabs
        .map((t) => {
            const active = t.id === activeId;
            return `<button type="button" class="home-manual-tab${active ? ' is-active' : ''}" role="tab" aria-selected="${active ? 'true' : 'false'}" data-home-manual-tab="${encodeURIComponent(t.id)}">${escapeHomepageFeatureHtml(t.label)}</button>`;
        })
        .join('');

const mountHomeManualCatRowsProducts = (settings, spec, activeId) => {
    destroyHomeManualCatRowsSwiper();
    const wrap = document.getElementById('home-manual-cat-rows-wrap');
    if (!wrap) return;
    const tab = spec.tabs.find((t) => t.id === activeId) || spec.tabs[0];
    const list = [];
    for (const pid of tab.productIds) {
        const p = spec.byId.get(String(pid));
        if (p) list.push(p);
        if (list.length >= tab.maxItems) break;
    }
    const slides =
        list.length > 0
            ? list
                .map((p, idx) => `<div class="swiper-slide h-auto">${getProductCard(p, true, { gridIndex: idx })}</div>`)
                .join('')
            : '<div class="swiper-slide h-auto"><p class="text-sm text-gray-500 py-6 px-2">এই ট্যাবে কোনো পণ্য নির্বাচিত নেই।</p></div>';
    wrap.innerHTML = slides;
    const swiperEl = document.querySelector('#category-rows-container .home-manual-tab-swiper');
    const pg = (settings && settings.layout && settings.layout.productGridConfig) || {};
    const cm = Math.min(5, Math.max(2, parseInt(pg.columnsMobile, 10) || 3));
    const cd = Math.min(8, Math.max(2, parseInt(pg.columnsDesktop, 10) || 5));
    if (swiperEl) {
        try {
            homeManualCatRowsSwiper = new Swiper(swiperEl, {
                slidesPerView: cm,
                spaceBetween: 10,
                freeMode: true,
                autoplay: { delay: 3000, disableOnInteraction: false },
                speed: 800,
                observer: true,
                observeParents: true,
                breakpoints: { 768: { slidesPerView: cd } }
            });
        } catch (_) { /* noop */ }
    }
};

const renderHomeCategoryRowsManualBlock = (container, settings, spec) => {
    if (!container || !spec) return;
    const titleHtml = spec.manualTitle
        ? `<div class="mb-3"><h3 class="section-title">${escapeHomepageFeatureHtml(spec.manualTitle)}</h3></div>`
        : '';
    const activeId = spec.defaultManualTabId;
    const tabsHtml = `<div class="home-manual-tabs-scroll mb-3" role="tablist">${buildHomeManualCatRowsTabsHtml(spec.tabs, activeId)}</div>`;
    const swiperHtml =
        '<div class="swiper home-manual-tab-swiper flash-swiper pl-1"><div class="swiper-wrapper" id="home-manual-cat-rows-wrap"></div></div>';
    container.innerHTML = `<div class="home-manual-cat-rows-root w-full">${titleHtml}${tabsHtml}${swiperHtml}</div>`;
    mountHomeManualCatRowsProducts(settings, spec, activeId);
    homeManualCatRowsRuntime = {
        spec,
        activeId,
        setActive(id) {
            if (!this.spec.tabs.some((t) => t.id === id)) return;
            this.activeId = id;
            container.querySelectorAll('[data-home-manual-tab]').forEach((btn) => {
                const bid = decodeURIComponent(btn.getAttribute('data-home-manual-tab') || '');
                const on = bid === id;
                btn.classList.toggle('is-active', on);
                btn.setAttribute('aria-selected', on ? 'true' : 'false');
            });
            const curSettings = state.siteSettings || settings || {};
            mountHomeManualCatRowsProducts(curSettings, this.spec, id);
        }
    };
};

const ensureHomeManualCatRowsTabDelegation = () => {
    if (homeManualCatRowsDelegateBound || !doc.catRowsContainer) return;
    homeManualCatRowsDelegateBound = true;
    doc.catRowsContainer.addEventListener('click', (e) => {
        const btn = e.target.closest('[data-home-manual-tab]');
        if (!btn || !doc.catRowsContainer.contains(btn)) return;
        if (!homeManualCatRowsRuntime) return;
        const id = decodeURIComponent(btn.getAttribute('data-home-manual-tab') || '');
        if (!id) return;
        homeManualCatRowsRuntime.setActive(id);
    });
};

/** True while Firebase catalog not yet applied (empty products + loading/idle). */
const isClassicHomeCatalogWaiting = () => {
    const st = state.storeCatalogFetchStatus || 'idle';
    const n = (state.allProducts && state.allProducts.length) || 0;
    return n === 0 && (st === 'loading' || st === 'idle');
};

/** Hide home chrome that would look like skeletons until catalog is ready. */
const applyClassicHomeSilentShell = (settings) => {
    const s = settings || {};
    const pcCat = getEl('pc-category-section');
    const mobCat = getEl('mobile-category-section');
    if (pcCat) pcCat.innerHTML = '';
    if (mobCat) {
        mobCat.innerHTML = '';
        const narEarly = s.homeNewArrivalBand && typeof s.homeNewArrivalBand === 'object' ? s.homeNewArrivalBand : {};
        const fabNarEarly = !!narEarly.fabrilifeCategoryGridEnabled;
        if ((s.layout?.categoryConfig || {}).mobileHeroEqualTabsEnabled || fabNarEarly) mobCat.classList.add('mobile-cat-strip--suppressed-mobile');
        else mobCat.classList.remove('mobile-cat-strip--suppressed-mobile');
    }
    if (doc.flashSection) doc.flashSection.classList.add('hidden');
    destroyRecommendedForYouSwipers();
    if (doc.recommendedForYouSectionDesktop) doc.recommendedForYouSectionDesktop.classList.add('hidden');
    if (doc.recommendedForYouSectionMobile) doc.recommendedForYouSectionMobile.classList.add('hidden');
    hideCategoryBannerSectionHome();
    destroyHomeManualCatRowsSwiper();
    homeManualCatRowsRuntime = null;
    if (doc.catRowsContainer) doc.catRowsContainer.innerHTML = '';
    if (doc.justForYouSection) doc.justForYouSection.classList.add('hidden');
    if (doc.mainProductGrid) {
        doc.mainProductGrid.classList.remove('border', 'border-gray-200', 'rounded-lg', 'p-4', 'bg-white', 'shadow-sm');
        doc.mainProductGrid.innerHTML = '';
        doc.mainProductGrid.style.minHeight = '40vh';
    }
    if (doc.pcBannerWrapper) doc.pcBannerWrapper.innerHTML = '';
    if (doc.mobileBannerWrapper) doc.mobileBannerWrapper.innerHTML = '';
    if (shouldUseLeanAboveFoldMode(s)) cancelDeferredHomeHydration();
};

/** Screen-reader hint while home catalog is still empty (no visible skeleton). */
const syncClassicHomeAriaBusy = () => {
    const hv = doc.homeView || getEl('home-view');
    if (!hv) return;
    const h = (window.location.hash || '').split('?')[0];
    const onHome = h === '' || h === '#/' || h === '#/shop' || h.startsWith('#/shop');
    if (!onHome || hv.classList.contains('hidden')) {
        hv.removeAttribute('aria-busy');
        return;
    }
    const waiting = isClassicHomeCatalogWaiting();
    hv.setAttribute('aria-busy', waiting ? 'true' : 'false');
};

const renderHome = (opts = {}) => {
    const settings = state.siteSettings || {};
    if (isClassicHomeCatalogWaiting()) {
        applyClassicHomeSilentShell(settings);
        syncClassicHomeAriaBusy();
        return;
    }
    const forceFull = !!opts.forceFull;
    const leanAboveFold = !forceFull && shouldUseLeanAboveFoldMode(settings);
    renderHomepageFeatures(settings);
    applyClassicProductSpacing(settings);
    applyStorefrontImageHints(settings);
    applyCategoryListingBannerHeights(settings);
    const visibility = { mainSlider: true, smallBanners: true, promoBanner1: true, promoBanner2: true, ...(settings.bannerVisibility || {}) };
    if (leanAboveFold) {
        visibility.smallBanners = false;
        visibility.promoBanner1 = false;
        visibility.promoBanner2 = false;
    }
    const bannerSlides = (settings.bannerSlides && settings.bannerSlides.length > 0)
        ? settings.bannerSlides
        : (settings.bannerUrls && settings.bannerUrls.length > 0)
            ? settings.bannerUrls.map(url => ({ imageUrl: url, title: '', subtitle: '', linkUrl: '' }))
            : [{ imageUrl: '', title: '', subtitle: '', linkUrl: '' }];
    const smallBanners = (settings.smallBanners && settings.smallBanners.length === 3) ? settings.smallBanners : [];
    const smallBannerLinks = (settings.smallBannerLinks && Array.isArray(settings.smallBannerLinks) && settings.smallBannerLinks.length === 3)
        ? settings.smallBannerLinks.map((x) => String(x || '').trim())
        : ['', '', ''];
    const promo1 = (settings.promoBanner1Url || '').trim();
    const promo2 = (settings.promoBanner2Url || '').trim();

    // LCP: preload first banner image so browser discovers it early
    const firstBannerUrl = (bannerSlides[0]?.imageUrl || '').trim();
    if (firstBannerUrl && firstBannerUrl.startsWith('http')) {
        let preload = document.getElementById('lcp-banner-preload');
        if (!preload) {
            preload = document.createElement('link');
            preload.id = 'lcp-banner-preload';
            preload.rel = 'preload';
            preload.as = 'image';
            document.head.appendChild(preload);
        }
        preload.href = firstBannerUrl;
    }

    const bannerConfig = settings.layout?.bannerConfig || {};
    const layoutForHome = settings.layout || {};
    const rawDesktopGap = layoutForHome.desktopContentSideGapPx;
    const effectiveDesktopGapPx = (rawDesktopGap != null && String(rawDesktopGap).trim() !== '' && Number.isFinite(Number(rawDesktopGap)))
        ? Math.min(120, Math.max(0, Number(rawDesktopGap)))
        : null;
    const hasDesktopGap = rawDesktopGap != null
        && String(rawDesktopGap).trim() !== ''
        && Number.isFinite(Number(rawDesktopGap));
    const forceDesktopFullBleed = hasDesktopGap && Number(rawDesktopGap) === 0
        && layoutForHome.homeLayoutMode !== 'boxed';
    const fabrilifeHeroPreset = bannerConfig.mainHeroPreset === 'fabrilife';
    const isCenterTradePcHero = layoutForHome.headerDesign === 'centerTrade';
    if (doc.pcSliderArea) {
        const baseDesktopH = (bannerConfig.desktopHeight != null && bannerConfig.desktopHeight !== '')
            ? Number(bannerConfig.desktopHeight)
            : 420;
        const desktopHeightCap = leanAboveFold ? 460 : 800;
        if (isCenterTradePcHero) {
            doc.pcSliderArea.classList.add('pc-slider-area--center-trade');
            const vhBlend = Math.round(window.innerHeight * 0.55);
            const effectivePcH = Math.min(desktopHeightCap, Math.max(baseDesktopH, vhBlend));
            doc.pcSliderArea.style.height = `${effectivePcH}px`;
        } else {
            doc.pcSliderArea.classList.remove('pc-slider-area--center-trade');
            if (bannerConfig.desktopHeight) {
                const targetDesktopH = leanAboveFold
                    ? Math.min(desktopHeightCap, Number(bannerConfig.desktopHeight) || baseDesktopH)
                    : Number(bannerConfig.desktopHeight);
                if (Number.isFinite(targetDesktopH)) doc.pcSliderArea.style.height = `${targetDesktopH}px`;
            }
        }
        const pcFullBleed = forceDesktopFullBleed || fabrilifeHeroPreset || bannerConfig.desktopMainSliderLayout === 'fullBleed';
        if (pcFullBleed) {
            doc.pcSliderArea.classList.add('pc-slider-area--full-bleed');
            doc.pcSliderArea.style.width = '100%';
            doc.pcSliderArea.style.marginLeft = doc.pcSliderArea.style.marginRight = '0px';
        } else {
            doc.pcSliderArea.classList.remove('pc-slider-area--full-bleed');
            const pcSpace = effectiveDesktopGapPx != null
                ? effectiveDesktopGapPx
                : ((bannerConfig.sideSpacingDesktop != null && bannerConfig.sideSpacingDesktop !== '') ? Number(bannerConfig.sideSpacingDesktop) : 32);
            doc.pcSliderArea.style.width = `calc(100% - ${pcSpace * 2}px)`;
            doc.pcSliderArea.style.marginLeft = doc.pcSliderArea.style.marginRight = `${pcSpace}px`;
        }
        const pcTop = (bannerConfig.topSpacingDesktop != null && bannerConfig.topSpacingDesktop !== '') ? Number(bannerConfig.topSpacingDesktop) : 0;
        const pcBottom = (bannerConfig.bottomSpacingDesktop != null && bannerConfig.bottomSpacingDesktop !== '') ? Number(bannerConfig.bottomSpacingDesktop) : 0;
        doc.pcSliderArea.style.marginTop = `${pcTop}px`;
        doc.pcSliderArea.style.marginBottom = `${pcBottom}px`;
    }
    if (doc.mobileSliderArea) {
        if (bannerConfig.mobileHeight) {
            const mobileCap = leanAboveFold ? 300 : 520;
            const targetMobileH = leanAboveFold
                ? Math.min(mobileCap, Number(bannerConfig.mobileHeight) || mobileCap)
                : Number(bannerConfig.mobileHeight);
            if (Number.isFinite(targetMobileH)) doc.mobileSliderArea.style.height = `${targetMobileH}px`;
        }
        const mobFullBleed = fabrilifeHeroPreset || bannerConfig.mobileMainSliderLayout === 'fullBleed';
        if (mobFullBleed) {
            doc.mobileSliderArea.classList.add('mobile-slider-area--full-bleed');
            doc.mobileSliderArea.style.marginLeft = doc.mobileSliderArea.style.marginRight = '0px';
        } else {
            doc.mobileSliderArea.classList.remove('mobile-slider-area--full-bleed');
            const mobSpace = (bannerConfig.sideSpacingMobile != null && bannerConfig.sideSpacingMobile !== '') ? Number(bannerConfig.sideSpacingMobile) : 12;
            doc.mobileSliderArea.style.marginLeft = doc.mobileSliderArea.style.marginRight = `${mobSpace}px`;
        }
    }

    const hamburgerStyle = settings.layout?.hamburgerMenuStyle || 'default';
    const pcLayoutStyle = settings.layout?.pcLayoutStyle || 'default';
    /** Shwapno-style vertical category column beside PC hero: explicit PC layout OR legacy hamburger "Shwapno PC view" */
    const showShwapnoPcCategoryMenu = pcLayoutStyle === 'shwapnoLeftMenu' || hamburgerStyle === 'shwapnoPcView';
    if (doc.pcSliderArea) {
        doc.pcSliderArea.classList.toggle('pc-layout-shwapno-left', !!showShwapnoPcCategoryMenu);
    }
    if (doc.desktopSidebar) {
        if (showShwapnoPcCategoryMenu) {
            doc.desktopSidebar.classList.remove('hidden');
            doc.desktopSidebar.classList.add('sidebar--shwapno-pc', 'shwapno-sidebar-wrap');
            const escShAttr = (s) =>
                String(s ?? '')
                    .replace(/&/g, '&amp;')
                    .replace(/"/g, '&quot;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;');
            const escShText = (s) => String(s ?? '').replace(/</g, '&lt;');
            const menuCats = getMenuCategories();
            const categoryProductPreviewMap = buildMenuCategoryProductPreviewMap(menuCats, state.allProducts, 5);
            const rowsHtml = menuCats.map((cat) => {
                const subs = getSubcategoryEntries(cat);
                const previewProducts = categoryProductPreviewMap.get(cat.name) || [];
                let flyoutType = 'none';
                let flyoutHtml = '';
                const baseHash = `#/category/${encodeURIComponent(cat.name)}`;
                if (subs.length > 0) {
                    flyoutType = 'subcategories';
                    flyoutHtml = `<div class="shwapno-flyout" role="region" aria-label="${escShAttr(cat.name)} subcategories">
                <div class="shwapno-flyout-title">${escShText(cat.name)}</div>
                <div class="shwapno-flyout-grid">
                    ${subs
                        .map((entry) => {
                            const href = `${baseHash}?sub=${encodeURIComponent(entry.name)}`;
                            const sty = subcategoryEntryStyleAttr(entry);
                            return `<a class="shwapno-flyout-link" href="${href}"${sty}>${escShText(entry.name)}</a>`;
                        })
                        .join('')}
                </div>
           </div>`;
                } else if (previewProducts.length > 0) {
                    flyoutType = 'products';
                    flyoutHtml = buildShwapnoDesktopProductFlyoutHtml(cat.name, previewProducts, escShAttr, escShText);
                }
                const hasInteractiveFlyout = flyoutType !== 'none';
                const chevMutedClass = flyoutType === 'none' ? ' is-muted' : '';
                const trimmedImg = (cat.iconUrl || cat.imageUrl || '').trim();
                const iconHtml = trimmedImg
                    ? `<img src="${escShAttr(trimmedImg)}" alt="" class="shwapno-cat-ico-img" loading="lazy" decoding="async">`
                    : `<i class="fa-solid fa-table-cells shwapno-cat-ico-fa" aria-hidden="true"></i>`;
                return `<div class="shwapno-cat-row${hasInteractiveFlyout ? ' has-flyout' : ''}">
        <a class="shwapno-cat" href="${baseHash}">
            <span class="shwapno-cat-ico">${iconHtml}</span>
            <span class="shwapno-cat-name">${escShText(cat.name)}</span>
            <i class="fa-solid fa-chevron-right shwapno-cat-chev${chevMutedClass}" aria-hidden="true"></i>
        </a>${flyoutHtml}
    </div>`;
            }).join('');
            doc.desktopSidebar.innerHTML = `<div class="shwapno-sidebar-list">${rowsHtml}</div>`;
            bindShwapnoDesktopSidebarFlyouts(doc.desktopSidebar);
        } else {
            doc.desktopSidebar.classList.add('hidden');
            doc.desktopSidebar.classList.remove('sidebar--shwapno-pc', 'shwapno-sidebar-wrap');
            const menuCats = getMenuCategories();
            if (menuCats.length > 0) {
                const escAttrMenu = (s) => String(s ?? '')
                    .replace(/&/g, '&amp;')
                    .replace(/"/g, '&quot;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;');
                doc.desktopSidebar.innerHTML = menuCats.map(cat => `
                    <a href="#/category/${encodeURIComponent(cat.name)}" class="flex items-center gap-3 py-3 px-5 border-b border-gray-100 text-sm text-gray-700 hover:bg-gray-50 hover:pl-6 transition-all bg-white cursor-pointer group">
                        <img src="${escAttrMenu(cat.iconUrl || cat.imageUrl)}" alt="${cat.name}" class="object-contain" style="width: var(--font-sidebar-category-icon, 20px); height: var(--font-sidebar-category-icon, 20px);" loading="lazy" decoding="async">
                        <span class="flex-grow font-medium">${String(cat.name).replace(/</g, '&lt;')}</span>
                        <i class="fa-solid fa-chevron-right text-[10px] text-gray-300"></i>
                    </a>
                `).join('');
            }
        }
    }

    if (doc.pcSliderArea) doc.pcSliderArea.classList.remove('hidden');
    if (doc.pcBannerWrapper && visibility.mainSlider) {
        const esc = (s) => String(s || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
        const wrapImgLink = (hrefRaw, innerImgHtml) => {
            const h = String(hrefRaw || '').trim();
            if (!h) return innerImgHtml;
            const ext = /^https?:\/\//i.test(h) ? ' target="_blank" rel="noopener noreferrer"' : '';
            return `<a class="block w-full h-full cursor-pointer"${ext} href="${esc(h)}">${innerImgHtml}</a>`;
        };
        const bannerDesign = settings.layout?.bannerDesign || 'full';
        const pcSlidesHtml = bannerDesign === 'split'
            ? bannerSlides.map((slide, i) => {
                const imgUrl = (slide.imageUrl || '').trim();
                const title = esc(slide.title || '');
                const subtitle = esc(slide.subtitle || '');
                const pri = i === 0 ? ' fetchpriority="high" loading="eager" decoding="async"' : ' loading="lazy" decoding="async"';
                const ctaHref = String(slide.linkUrl || '').trim() || '#/shop';
                const ctaExt = /^https?:\/\//i.test(ctaHref) ? ' target="_blank" rel="noopener noreferrer"' : '';
                const heroSpec = getResponsiveImageSpec(imgUrl, { widths: [640, 960, 1280, 1600, 1920], fallbackWidth: 1280, quality: 80, sizes: '(max-width: 1024px) 100vw, 1200px' });
                const imgHtml = `<img src="${esc(heroSpec.src || imgUrl)}"${heroSpec.srcset ? ` srcset="${esc(heroSpec.srcset)}" sizes="${esc(heroSpec.sizes)}"` : ''} alt="${title}" width="1200" height="450"${pri}>`;
                const imageCol = wrapImgLink(slide.linkUrl, imgHtml);
                return `<div class="swiper-slide w-full h-full banner-slide-split"><div class="banner-text-side"><h2 class="banner-title">${title}</h2><p class="banner-subtitle">${subtitle}</p><a href="${esc(ctaHref)}"${ctaExt} class="inline-block mt-3 px-5 py-2 rounded-lg font-bold text-white bg-white/20 hover:bg-white/30 transition">Shop Now</a></div><div class="banner-image-side">${imageCol}</div></div>`;
            }).join('')
            : bannerSlides.map((slide, i) => {
                const imgUrl = (slide.imageUrl || '').trim();
                const pri = i === 0 ? ' fetchpriority="high" loading="eager" decoding="async"' : ' loading="lazy" decoding="async"';
                const heroSpec = getResponsiveImageSpec(imgUrl, { widths: [640, 960, 1280, 1600, 1920], fallbackWidth: 1280, quality: 80, sizes: '(max-width: 1024px) 100vw, 1200px' });
                const imgTag = `<img src="${esc(heroSpec.src || imgUrl)}"${heroSpec.srcset ? ` srcset="${esc(heroSpec.srcset)}" sizes="${esc(heroSpec.sizes)}"` : ''} class="w-full h-full" alt="Banner" width="1200" height="450"${pri}>`;
                const inner = wrapImgLink(slide.linkUrl, imgTag);
                return `<div class="swiper-slide w-full h-full">${inner}</div>`;
            }).join('');
        doc.pcBannerWrapper.innerHTML = pcSlidesHtml;
        try {
            const prevBtn = document.querySelector('.main-swiper-wrapper .main-swiper-nav.prev');
            const nextBtn = document.querySelector('.main-swiper-wrapper .main-swiper-nav.next');
            new Swiper('.main-swiper', {
                loop: true,
                effect: 'fade',
                autoplay: { delay: 4000 },
                pagination: { el: '.main-swiper .swiper-pagination', clickable: true },
                navigation: prevBtn && nextBtn ? { nextEl: nextBtn, prevEl: prevBtn } : {},
                observer: true,
                observeParents: true
            });
        } catch (e) { }
    }
    if (doc.mobileSliderArea) doc.mobileSliderArea.classList.remove('hidden');
    if (doc.mobileBannerWrapper && visibility.mainSlider) {
        const bannerDesignMob = settings.layout?.bannerDesign || 'full';
        const escM = (s) => String(s || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
        const wrapImgLinkM = (hrefRaw, innerImgHtml) => {
            const h = String(hrefRaw || '').trim();
            if (!h) return innerImgHtml;
            const ext = /^https?:\/\//i.test(h) ? ' target="_blank" rel="noopener noreferrer"' : '';
            return `<a class="block w-full h-full cursor-pointer"${ext} href="${escM(h)}">${innerImgHtml}</a>`;
        };
        doc.mobileBannerWrapper.innerHTML = bannerDesignMob === 'split'
            ? bannerSlides.map((s, i) => {
                const imgUrl = (s.imageUrl || '').trim();
                const title = escM(s.title || '');
                const subtitle = escM(s.subtitle || '');
                const pri = i === 0 ? ' fetchpriority="high" loading="eager" decoding="async"' : ' loading="lazy" decoding="async"';
                const ctaHref = String(s.linkUrl || '').trim() || '#/shop';
                const ctaExt = /^https?:\/\//i.test(ctaHref) ? ' target="_blank" rel="noopener noreferrer"' : '';
                const mobileHeroSpec = getResponsiveImageSpec(imgUrl, { widths: [360, 480, 640, 860], fallbackWidth: 640, quality: 78, sizes: '100vw' });
                const imgHtml = `<img src="${escM(mobileHeroSpec.src || imgUrl)}"${mobileHeroSpec.srcset ? ` srcset="${escM(mobileHeroSpec.srcset)}" sizes="${escM(mobileHeroSpec.sizes)}"` : ''} class="w-full h-full object-cover" alt="${title}" width="600" height="450"${pri}>`;
                const imageCol = wrapImgLinkM(s.linkUrl, imgHtml);
                return `<div class="swiper-slide w-full h-full flex flex-col"><div class="banner-text-side flex-1 flex flex-col justify-center p-4"><h2 class="banner-title text-lg">${title}</h2><p class="banner-subtitle text-sm">${subtitle}</p><a href="${escM(ctaHref)}"${ctaExt} class="inline-block mt-2 px-4 py-2 rounded-lg font-bold text-white bg-white/20 text-sm">Shop Now</a></div><div class="banner-image-side flex-1 min-h-0">${imageCol}</div></div>`;
            }).join('')
            : bannerSlides.map((s, i) => {
                const imgUrl = (s.imageUrl || '').trim();
                const pri = i === 0 ? ' fetchpriority="high" loading="eager" decoding="async"' : ' loading="lazy" decoding="async"';
                const mobileHeroSpec = getResponsiveImageSpec(imgUrl, { widths: [360, 480, 640, 860], fallbackWidth: 640, quality: 78, sizes: '100vw' });
                const imgTag = `<img src="${escM(mobileHeroSpec.src || imgUrl)}"${mobileHeroSpec.srcset ? ` srcset="${escM(mobileHeroSpec.srcset)}" sizes="${escM(mobileHeroSpec.sizes)}"` : ''} class="w-full h-full object-cover rounded-xl" alt="Banner" width="600" height="350"${pri}>`;
                const inner = wrapImgLinkM(s.linkUrl, imgTag);
                return `<div class="swiper-slide w-full h-full flex items-center justify-center bg-gray-100">${inner}</div>`;
            }).join('');
        try {
            new Swiper('.mobile-banner-swiper', { loop: true, autoplay: { delay: 3500 }, pagination: { el: '.mobile-banner-swiper .swiper-pagination', clickable: true }, observer: true, observeParents: true });
        } catch (e) { }
    }

    const hasSmallBanners = visibility.smallBanners && smallBanners.some(u => (u || '').trim());
    if (doc.pcSmallBanners) { hasSmallBanners ? doc.pcSmallBanners.classList.remove('hidden') : doc.pcSmallBanners.classList.add('hidden'); }
    if (doc.mobileSmallBanners) { hasSmallBanners ? doc.mobileSmallBanners.classList.remove('hidden') : doc.mobileSmallBanners.classList.add('hidden'); }
    [doc.pcSmallBanners, doc.mobileSmallBanners].forEach(el => {
        if (!el) return;
        el.querySelectorAll('img[data-small-banner]').forEach((img, i) => {
            const url = (smallBanners[i] || '').trim();
            const link = (smallBannerLinks[i] || '').trim();
            const a = img.closest('a.small-banner-link');
            if (url) {
                img.loading = 'lazy';
                img.decoding = 'async';
                img.src = url;
                img.alt = 'Banner';
                img.classList.remove('object-cover');
                img.classList.add('object-fill');
            } else {
                img.removeAttribute('src');
                img.alt = '';
            }
            applyStorefrontBannerLink(a, link);
        });
    });

    if (doc.promoBanner1) {
        if (visibility.promoBanner1 && promo1) {
            doc.promoBanner1.classList.remove('hidden');
            const im = doc.promoBanner1.querySelector('img');
            const pa = doc.promoBanner1.querySelector('a.promo-banner-link');
            if (im) { im.loading = 'lazy'; im.decoding = 'async'; im.src = promo1; im.alt = 'Promo'; }
            applyStorefrontBannerLink(pa, settings.promoBanner1Link);
        } else {
            doc.promoBanner1.classList.add('hidden');
            applyStorefrontBannerLink(doc.promoBanner1.querySelector('a.promo-banner-link'), '');
        }
    }
    if (doc.promoBanner2) {
        if (visibility.promoBanner2 && promo2) {
            doc.promoBanner2.classList.remove('hidden');
            const im = doc.promoBanner2.querySelector('img');
            const pa = doc.promoBanner2.querySelector('a.promo-banner-link');
            if (im) { im.loading = 'lazy'; im.decoding = 'async'; im.src = promo2; im.alt = 'Promo'; }
            applyStorefrontBannerLink(pa, settings.promoBanner2Link);
        } else {
            doc.promoBanner2.classList.add('hidden');
            applyStorefrontBannerLink(doc.promoBanner2.querySelector('a.promo-banner-link'), '');
        }
    }

    applyHomeAnnouncementStripTo(doc.homeAnnouncementStrip, settings);
    applyHomeAnnouncementStripTo(doc.homeAnnouncementStripMobile, settings);
    applyHomeNewArrivalBand(settings);
    applyHomeNewArrivalCategoryGrid(settings);
    applyHomeFabrilifePostGridBanners(settings);

    const catProductCounts = buildCategoryProductCountsMap();

    const categoryConfig = settings.layout?.categoryConfig || {};
    const layoutType = categoryConfig.layoutType === 'grid' ? 'grid' : 'swiper';
    const cardStyle = (categoryConfig.cardStyle === 'chaldal' || categoryConfig.cardStyle === 'shwapno') ? categoryConfig.cardStyle : 'default';
    const catShape = categoryConfig.shape === 'square' ? 'square' : 'round';
    const catSizePc = Math.min(250, Math.max(100, Number(categoryConfig.sizeDesktop) || 170));
    const catSizeMob = Math.min(140, Math.max(56, Number(categoryConfig.sizeMobile) || 96));
    const catSpace = Math.min(40, Math.max(0, Number(categoryConfig.spaceBetween) ?? 10));
    const rowsDesktop = Math.min(5, Math.max(1, Number(categoryConfig.rowsDesktop) || 1));
    const rowsMobile = Math.min(5, Math.max(1, Number(categoryConfig.rowsMobile) || 1));
    const perRowDesktop = Math.min(8, Math.max(2, (typeof categoryConfig.categoriesPerRowDesktop !== 'undefined' ? Number(categoryConfig.categoriesPerRowDesktop) : NaN) || 4));
    const perRowMobile = Math.min(6, Math.max(1, (typeof categoryConfig.categoriesPerRowMobile !== 'undefined' ? Number(categoryConfig.categoriesPerRowMobile) : NaN) || 3));
    const catRadiusPc = catShape === 'square' ? '8px' : '50%';
    const catRadiusMob = catShape === 'square' ? 'rounded-lg' : 'rounded-full';
    document.documentElement.style.setProperty('--cat-size-pc', catSizePc + 'px');
    document.documentElement.style.setProperty('--cat-radius-pc', catRadiusPc);

    const stripCategories = resolveHomeThumbnailCategories(state.allCategories, categoryConfig);

    const chunkCategories = (arr, N) => {
        if (!arr.length || N <= 1) return [arr];
        const perRow = Math.ceil(arr.length / N);
        const chunks = [];
        for (let r = 0; r < N; r++) chunks.push(arr.slice(r * perRow, (r + 1) * perRow));
        return chunks.filter(c => c.length > 0);
    };

    const renderCatsToWrapper = (wrapper, isMobile, categoriesSubset, catStripStartIndex = 0) => {
        if (!wrapper || !categoriesSubset.length) return;
        const w = isMobile ? catSizeMob : catSizePc;
        const isShwapno = cardStyle === 'shwapno';
        wrapper.innerHTML = categoriesSubset.map((cat, idx) => {
            const imgPri = storefrontCategoryIconImgAttrs(catStripStartIndex + idx);
            const count = catProductCounts.get(cat.name) || 0;
            const nameEsc = String(cat.name || '').replace(/</g, '&lt;');
            if (isShwapno) {
                return `<div class="swiper-slide"><div class="category-grid-card category-card-shwapno flex flex-col cursor-pointer h-full transition active:scale-[0.98]" onclick="window.location.hash='#/category/${encodeURIComponent(cat.name)}'" title="${nameEsc}"><div class="category-card-shwapno-img"><img src="${cat.imageUrl || ''}" alt="${nameEsc}"${imgPri}></div><div class="category-card-shwapno-label">${nameEsc}</div></div></div>`;
            }
            if (isMobile) {
                return `<div class="swiper-slide"><div class="flex flex-col items-center justify-start h-auto pt-2 cursor-pointer group" onclick="window.location.hash='#/category/${cat.name}'"><div class="w-full max-w-full overflow-hidden border border-gray-100 bg-white shadow-sm mb-2 group-active:scale-95 transition ${catRadiusMob}" style="aspect-ratio:1;width:100%"><img src="${cat.imageUrl}" alt="${cat.name}" width="${w}" height="${w}" class="w-full h-full object-cover"${imgPri}></div><span class="block text-center text-sm font-bold text-gray-800 leading-tight mb-0.5 w-full">${cat.name}</span><span class="block text-center text-[10px] text-gray-500 w-full">${count} Products</span></div></div>`;
            }
            return `<div class="swiper-slide"><div class="cat-card group h-full flex flex-col" onclick="window.location.hash='#/category/${cat.name}'"><div class="w-full overflow-hidden" style="aspect-ratio:1"><img src="${cat.imageUrl}" alt="${cat.name}" width="${w}" height="${w}" class="w-full h-full object-cover"${imgPri}></div><span class="block text-center group-hover:text-gray-900 transition mt-1">${cat.name}</span></div></div>`;
        }).join('');
    };

    const renderCategoryGrid = (section, isMobile, categories) => {
        if (!section || !categories.length) return;
        const isChaldal = cardStyle === 'chaldal' && isMobile;
        const isShwapno = cardStyle === 'shwapno';
        const minCols = isMobile ? 1 : 2;
        const maxCols = isMobile ? 6 : 8;
        let perRow = Math.max(minCols, Math.min(maxCols, isMobile ? perRowMobile : perRowDesktop));
        if (isChaldal) perRow = 2;
        const radius = isMobile ? catRadiusMob : (catShape === 'square' ? 'rounded-lg' : 'rounded-full');
        const gap = Math.max(0, Number.isFinite(catSpace) ? catSpace : 10);
        const chaldalHeight = isMobile ? catSizeMob : catSizePc;
        const imgSize = isMobile ? catSizeMob : catSizePc;
        let gridCards;
        if (isShwapno) {
            gridCards = categories.map((cat, idx) => {
                const nameEsc = String(cat.name || '').replace(/</g, '&lt;');
                const imgPri = storefrontCategoryIconImgAttrs(idx);
                return `<div class="category-grid-card category-card-shwapno flex flex-col cursor-pointer overflow-hidden transition active:scale-[0.98] bg-white" onclick="window.location.hash='#/category/${encodeURIComponent(cat.name)}'" title="${nameEsc}"><div class="category-card-shwapno-img"><img src="${cat.imageUrl || ''}" alt="${nameEsc}"${imgPri}></div><div class="category-card-shwapno-label">${nameEsc}</div></div>`;
            }).join('');
        } else if (isChaldal) {
            gridCards = categories.map((cat, idx) => {
                const imgPri = storefrontCategoryIconImgAttrs(idx);
                return `<div class="category-grid-card category-card-chaldal flex cursor-pointer overflow-hidden rounded-xl border border-gray-200 shadow-sm hover:shadow-md transition active:scale-[0.98] bg-gray-100" style="height:${chaldalHeight}px" onclick="window.location.hash='#/category/${encodeURIComponent(cat.name)}'" title="${cat.name}"><img src="${cat.imageUrl}" alt="${cat.name}" width="${chaldalHeight}" height="${chaldalHeight}" class="w-full h-full object-cover"${imgPri}></div>`;
            }).join('');
        } else {
            gridCards = categories.map((cat, idx) => {
                const imgPri = storefrontCategoryIconImgAttrs(idx);
                return `<div class="category-grid-card flex flex-col items-center justify-center cursor-pointer group bg-white border border-gray-100 overflow-hidden shadow-sm hover:shadow-md transition active:scale-[0.98]" onclick="window.location.hash='#/category/${encodeURIComponent(cat.name)}'" title="${cat.name}"><div class="w-full overflow-hidden ${radius}" style="aspect-ratio:1;width:100%"><img src="${cat.imageUrl}" alt="${cat.name}" width="${imgSize}" height="${imgSize}" class="w-full h-full object-cover"${imgPri}></div></div>`;
            }).join('');
        }
        const allCatLink = `<a href="#/categories" class="all-categories-link inline-block mt-4 text-base font-bold hover:underline" style="color: var(--accent-color);">All Categories</a>`;
        section.innerHTML = `<div class="category-grid-inner w-full ${isChaldal ? 'category-grid--chaldal' : ''}" style="display:grid; grid-template-columns: repeat(${perRow}, minmax(0,1fr)); gap: ${gap}px;">${gridCards}</div><div class="text-center">${allCatLink}</div>`;
        section.querySelectorAll('.all-categories-link').forEach(el => { el.onclick = (e) => { e.preventDefault(); window.location.hash = '#/categories'; }; });
    };

    const pcSection = getEl('pc-category-section');
    const mobileSection = getEl('mobile-category-section');
    const swiperSlidesPc = Math.max(2, Math.min(8, perRowDesktop));
    const swiperSlidesMob = Math.max(1, Math.min(6, perRowMobile));
    const swiperOptsPc = { slidesPerView: swiperSlidesPc, spaceBetween: catSpace, loop: true, autoplay: { delay: 2000, disableOnInteraction: false }, speed: 800, observer: true, observeParents: true };
    const swiperOptsMob = { slidesPerView: swiperSlidesMob, spaceBetween: catSpace, loop: true, autoplay: { delay: 2500, disableOnInteraction: false }, freeMode: false, observer: true, observeParents: true };

    if (pcSection) {
        if (stripCategories.length > 0) {
            if (layoutType === 'grid') {
                const pcCount = Math.max(1, rowsDesktop * perRowDesktop);
                renderCategoryGrid(pcSection, false, stripCategories.slice(0, pcCount));
            } else if (rowsDesktop === 1) {
                pcSection.innerHTML = '<div class="swiper category-swiper w-full"><div class="swiper-wrapper" id="pc-category-wrapper"></div></div>';
                const wrapper = getEl('pc-category-wrapper');
                if (wrapper) { renderCatsToWrapper(wrapper, false, stripCategories, 0); try { new Swiper(pcSection.querySelector('.category-swiper'), swiperOptsPc); } catch (e) { } }
            } else {
                pcSection.innerHTML = '';
                const chunksPc = chunkCategories(stripCategories, rowsDesktop);
                let catStripOffsetPc = 0;
                chunksPc.forEach((chunk, r) => {
                    const swiperEl = document.createElement('div');
                    swiperEl.className = 'swiper category-swiper w-full' + (r > 0 ? ' mt-3' : '');
                    const wrapperEl = document.createElement('div');
                    wrapperEl.className = 'swiper-wrapper';
                    swiperEl.appendChild(wrapperEl);
                    pcSection.appendChild(swiperEl);
                    renderCatsToWrapper(wrapperEl, false, chunk, catStripOffsetPc);
                    catStripOffsetPc += chunk.length;
                    try { new Swiper(swiperEl, swiperOptsPc); } catch (e) { }
                });
            }
        } else {
            pcSection.innerHTML = '';
        }
    }
    const homeNarBandCfg = settings.homeNewArrivalBand && typeof settings.homeNewArrivalBand === 'object' ? settings.homeNewArrivalBand : {};
    const fabNarGridOn = !!homeNarBandCfg.fabrilifeCategoryGridEnabled;
    if (stripCategories.length > 0 && mobileSection && !fabNarGridOn) {
        if (layoutType === 'grid') {
            const mobCount = Math.max(1, rowsMobile * perRowMobile);
            renderCategoryGrid(mobileSection, true, stripCategories.slice(0, mobCount));
        } else if (rowsMobile === 1) {
            mobileSection.innerHTML = '<div class="swiper mobile-cat-swiper" style="overflow:hidden"><div class="swiper-wrapper" id="mobile-category-wrapper"></div></div>';
            const wrapper = getEl('mobile-category-wrapper');
            if (wrapper) { renderCatsToWrapper(wrapper, true, stripCategories, 0); try { new Swiper(mobileSection.querySelector('.mobile-cat-swiper'), swiperOptsMob); } catch (e) { } }
        } else {
            mobileSection.innerHTML = '';
            const chunksMob = chunkCategories(stripCategories, rowsMobile);
            let catStripOffsetMob = 0;
            chunksMob.forEach((chunk, r) => {
                const swiperEl = document.createElement('div');
                swiperEl.className = 'swiper mobile-cat-swiper' + (r > 0 ? ' mt-3' : '');
                swiperEl.style.overflow = 'hidden';
                const wrapperEl = document.createElement('div');
                wrapperEl.className = 'swiper-wrapper';
                swiperEl.appendChild(wrapperEl);
                mobileSection.appendChild(swiperEl);
                renderCatsToWrapper(wrapperEl, true, chunk, catStripOffsetMob);
                catStripOffsetMob += chunk.length;
                try { new Swiper(swiperEl, swiperOptsMob); } catch (e) { }
            });
        }
    } else if (mobileSection && fabNarGridOn) {
        mobileSection.innerHTML = '';
        mobileSection.classList.add('mobile-cat-strip--suppressed-mobile');
    } else if (mobileSection && !fabNarGridOn) {
        mobileSection.innerHTML = '';
    }
    const mobileStripEl = getEl('mobile-category-section');
    if (mobileStripEl) {
        if (categoryConfig.mobileHeroEqualTabsEnabled || fabNarGridOn) mobileStripEl.classList.add('mobile-cat-strip--suppressed-mobile');
        else mobileStripEl.classList.remove('mobile-cat-strip--suppressed-mobile');
    }

    const rsRec = settings.layout?.recommendedSection || {};
    const flashProducts = getFlashFeaturedProductList();
    const heroFeaturedFallbackActive =
        rsRec.enabled !== true &&
        rsRec.fallbackWhenDisabled === 'featuredProducts' &&
        flashProducts.length > 0;
    const suppressMainFlashWhenRecommendedFallback =
        rsRec.suppressMainFlashWhenRecommendedFallback !== false &&
        heroFeaturedFallbackActive;
    const featuredDesign = settings.layout?.featuredSectionDesign || 'default';
    if (doc.flashSection) {
        if (leanAboveFold) {
            doc.flashSection.classList.add('hidden');
            doc.flashSection.innerHTML = '';
        } else
        if (suppressMainFlashWhenRecommendedFallback) {
            doc.flashSection.classList.add('hidden');
            doc.flashSection.innerHTML = '';
        } else if (flashProducts.length > 0) {
            doc.flashSection.classList.remove('hidden');
            if (featuredDesign === 'grid') {
                doc.flashSection.innerHTML = `<div class="flex justify-between items-center mb-3 px-1 cursor-pointer" onclick="window.location.hash='#/featured'"><h3 class="text-lg md:text-xl font-bold text-gray-900 hover:text-gray-900 transition">Featured Products</h3><button class="w-7 h-7 rounded-full bg-gray-100 flex items-center justify-center hover:bg-gray-200 transition text-gray-600"><i class="fa-solid fa-chevron-right text-xs"></i></button></div><div id="flash-products-container" class="products-grid border rounded-xl p-4 shadow-sm" style="background-color: var(--card-bg); border-color: var(--card-border);">${flashProducts.map((p, i) => getProductCard(p, false, { gridIndex: i })).join('')}</div>`;
                const flashGrid = getEl('flash-products-container');
                if (flashGrid) applyProductGridToElement(flashGrid);
            } else {
                const flashPg = settings.layout?.productGridConfig || {};
                const flashColsMobile = Math.min(5, Math.max(2, parseInt(flashPg.columnsMobile, 10) || 3));
                const flashColsDesktop = Math.min(8, Math.max(2, parseInt(flashPg.columnsDesktop, 10) || 5));
                doc.flashSection.innerHTML = `<div class="flex justify-between items-center mb-3 px-1 cursor-pointer" onclick="window.location.hash='#/featured'"><h3 class="text-lg md:text-xl font-bold text-gray-900 hover:text-gray-900 transition">Featured Products</h3><button class="w-7 h-7 rounded-full bg-gray-100 flex items-center justify-center hover:bg-gray-200 transition text-gray-600"><i class="fa-solid fa-chevron-right text-xs"></i></button></div><div class="swiper flash-swiper pl-1"><div class="swiper-wrapper" id="flash-products-container">${flashProducts.map((p, i) => `<div class="swiper-slide h-auto">${getProductCard(p, false, { gridIndex: i })}</div>`).join('')}</div></div>`;
                try { new Swiper('.flash-swiper', { slidesPerView: flashColsMobile, spaceBetween: 10, autoplay: { delay: 2500, disableOnInteraction: false }, speed: 800, observer: true, observeParents: true, breakpoints: { 768: { slidesPerView: flashColsDesktop } } }); } catch (e) { }
            }
        }
    }

    destroyHomeManualCatRowsSwiper();
    homeManualCatRowsRuntime = null;
    const manualRowsSpec = leanAboveFold ? null : normalizeHomeManualTabsFromLayout(settings.layout);
    if (doc.catRowsContainer) {
        if (manualRowsSpec) {
            ensureHomeManualCatRowsTabDelegation();
            renderHomeCategoryRowsManualBlock(doc.catRowsContainer, settings, manualRowsSpec);
        } else {
            if (leanAboveFold) {
                doc.catRowsContainer.innerHTML = '';
            } else
            doc.catRowsContainer.innerHTML = state.allCategories.map((cat, index) => {
                const catProducts = state.allProducts.filter(p => productInCategory(p, cat.name)).slice(0, 10);
                if (catProducts.length === 0) return '';
                return `<div class="category-row"><div class="section-header"><h3 class="section-title">${cat.name}</h3><button class="view-more-btn" onclick="window.location.hash='#/category/${cat.name}'">View More <i class="fa-solid fa-arrow-right"></i></button></div><div class="swiper cat-row-swiper-${index} flash-swiper"><div class="swiper-wrapper">${catProducts.map((p, idx) => `<div class="swiper-slide h-auto">${getProductCard(p, true, { gridIndex: idx })}</div>`).join('')}</div></div></div>`;
            }).join('');
        }
    }
    const pg = state.siteSettings?.layout?.productGridConfig || {};
    const catRowColsMobile = Math.min(5, Math.max(2, parseInt(pg.columnsMobile, 10) || 3));
    const catRowColsDesktop = Math.min(8, Math.max(2, parseInt(pg.columnsDesktop, 10) || 5));
    if (!manualRowsSpec && !leanAboveFold) {
        state.allCategories.forEach((_, i) => {
            try { new Swiper(`.cat-row-swiper-${i}`, { slidesPerView: catRowColsMobile, spaceBetween: 10, freeMode: true, autoplay: { delay: 3000, disableOnInteraction: false }, speed: 800, observer: true, observeParents: true, breakpoints: { 768: { slidesPerView: catRowColsDesktop } } }); } catch (e) { }
        });
    }

    if (leanAboveFold) {
        destroyRecommendedForYouSwipers();
        if (doc.recommendedForYouSectionDesktop) doc.recommendedForYouSectionDesktop.classList.add('hidden');
        if (doc.recommendedForYouSectionMobile) doc.recommendedForYouSectionMobile.classList.add('hidden');
        hideCategoryBannerSectionHome();
    } else {
        renderRecommendedForYouHome(settings);
        renderCategoryBannerSectionHome(settings);
    }

    if (doc.mainProductGrid) {
        doc.mainProductGrid.classList.add('border', 'border-gray-200', 'rounded-lg', 'p-4', 'bg-white', 'shadow-sm');
        applyProductGridToElement(doc.mainProductGrid);
        const products = state.allProducts || [];
        const fetchStatus = state.storeCatalogFetchStatus || 'idle';
        if (products.length === 0) {
            if (fetchStatus === 'error') {
                doc.mainProductGrid.style.minHeight = '';
                doc.mainProductGrid.innerHTML = '<div class="col-span-full text-center py-12 px-4 text-gray-600 font-medium">পণ্য লোড করা যায়নি। নেটওয়ার্ক বা নিয়ম চেক করে পেজ রিফ্রেশ করুন।</div>';
                syncClassicHomeAriaBusy();
                return;
            }
            doc.mainProductGrid.style.minHeight = '';
            doc.mainProductGrid.innerHTML = '<div class="col-span-full text-center py-12 text-gray-500 font-medium">এই স্টোরে এখন কোনো পণ্য নেই।</div>';
            syncClassicHomeAriaBusy();
            return;
        }
        doc.mainProductGrid.style.minHeight = '';
        const existingSentinel = document.getElementById('main-product-grid-sentinel');
        if (existingSentinel) existingSentinel.remove();
        if (homeGridObserver) { homeGridObserver.disconnect(); homeGridObserver = null; }
        homeProductList = [...products].slice(0, 15);
        homeProductRenderedCount = 0;
        const firstBatch = homeProductList.slice(0, HOME_BATCH_SIZE).map((p, i) => getProductCard(p, false, { gridIndex: i })).join('');
        doc.mainProductGrid.innerHTML = firstBatch;
        homeProductRenderedCount = HOME_BATCH_SIZE;
        if (homeProductRenderedCount < homeProductList.length && doc.mainProductGrid.parentElement) {
            const sentinel = document.createElement('div');
            sentinel.id = 'main-product-grid-sentinel';
            sentinel.style.cssText = 'height:1px;visibility:hidden;pointer-events:none';
            doc.mainProductGrid.parentElement.appendChild(sentinel);
            homeGridObserver = new IntersectionObserver((entries) => {
                if (!entries[0]?.isIntersecting) return;
                const nextEnd = Math.min(homeProductRenderedCount + HOME_BATCH_SIZE, homeProductList.length);
                const nextBatch = homeProductList.slice(homeProductRenderedCount, nextEnd).map((p, i) => getProductCard(p, false, { gridIndex: homeProductRenderedCount + i })).join('');
                if (doc.mainProductGrid && nextBatch) doc.mainProductGrid.insertAdjacentHTML('beforeend', nextBatch);
                homeProductRenderedCount = nextEnd;
                if (homeProductRenderedCount >= homeProductList.length && sentinel.parentNode) {
                    sentinel.remove();
                    if (homeGridObserver) { homeGridObserver.disconnect(); homeGridObserver = null; }
                }
            }, { rootMargin: '120px' });
            homeGridObserver.observe(sentinel);
        }
    }

    if (leanAboveFold) scheduleDeferredHomeHydration();
    else cancelDeferredHomeHydration();
    syncClassicHomeAriaBusy();
};

const renderCategoryView = (categoryName) => {
    if (!doc.categoryGrid) return;
    applyStorefrontImageHints(state.siteSettings || {});
    applyCategoryListingBannerHeights(state.siteSettings || {});
    if (doc.categoryView) doc.categoryView.classList.add('category-view--listing');
    closeCategoryFilterSheet();
    const catObj = (state.allCategories || []).find((c) => c.name === categoryName);
    const categoryPageBannerEnabled = state.siteSettings?.layout?.categoryConfig?.categoryPageBannerEnabled !== false;
    const perCategoryBannerOk = catObj && catObj.listingBannerEnabled !== false;
    const listingBannerTrim = catObj && String(catObj.listingBannerUrl || '').trim();
    const bannerSrc = categoryPageBannerEnabled && perCategoryBannerOk
        ? listingBannerTrim
        : '';
    if (doc.categoryHeroBanner && doc.categoryHeroBannerImg) {
        const url = bannerSrc;
        if (url) {
            doc.categoryHeroBannerImg.src = url;
            doc.categoryHeroBannerImg.alt = categoryName || 'Category';
            doc.categoryHeroBanner.classList.add('is-visible');
            doc.categoryHeroBanner.setAttribute('aria-hidden', 'false');
        } else {
            doc.categoryHeroBannerImg.removeAttribute('src');
            doc.categoryHeroBanner.classList.remove('is-visible');
            doc.categoryHeroBanner.setAttribute('aria-hidden', 'true');
        }
    }
    if (doc.catDescription) {
        const showCategoryDescription = state.siteSettings?.layout?.categoryConfig?.showCategoryDescription !== false;
        const categoryDescription = catObj && String(catObj.description || '').trim();
        if (showCategoryDescription && categoryDescription) {
            doc.catDescription.textContent = categoryDescription;
            doc.catDescription.classList.remove('hidden');
        } else {
            doc.catDescription.textContent = '';
            doc.catDescription.classList.add('hidden');
        }
    }
    applyProductGridToElement(doc.categoryGrid);
    const subParam = new URLSearchParams(window.location.hash.split('?')[1] || '').get('sub');
    const selectedSub = subParam ? decodeURIComponent(subParam) : '';
    const filterContextKey = `${categoryName}\u0000${selectedSub}`;
    if (categoryFacetFilterContextKey !== filterContextKey) {
        resetActiveCategoryFilters();
        categoryFacetFilterContextKey = filterContextKey;
    }

    let baseProducts = state.allProducts.filter((p) => productInCategory(p, categoryName));
    if (selectedSub) {
        baseProducts = baseProducts.filter((p) => productInSubcategory(p, selectedSub));
    }
    let filteredProducts = applyCategoryFacetFilters(baseProducts);

    if (currentCategorySort === 'low-high') filteredProducts.sort((a, b) => a.salePrice - b.salePrice);
    else if (currentCategorySort === 'high-low') filteredProducts.sort((a, b) => b.salePrice - a.salePrice);
    else if (currentCategorySort === 'a-z') filteredProducts.sort((a, b) => a.name.localeCompare(b.name));
    else if (currentCategorySort === 'z-a') filteredProducts.sort((a, b) => b.name.localeCompare(a.name));
    else filteredProducts.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));

    if (doc.catHeaderTitle) doc.catHeaderTitle.textContent = selectedSub ? `${categoryName} / ${selectedSub}` : categoryName;
    if (doc.catBreadcrumb) doc.catBreadcrumb.textContent = categoryName;
    if (doc.catCount) doc.catCount.textContent = `${filteredProducts.length} items found`;

    if (filteredProducts.length === 0) {
        doc.categoryGrid.innerHTML = `<div class="col-span-full flex flex-col items-center justify-center py-20 text-gray-400"><i class="fa-solid fa-box-open text-6xl mb-4"></i><p class="text-lg font-bold">No products found in this category</p><button onclick="window.location.hash='#/shop'" class="mt-4 px-6 py-2 bg-gray-800 text-white rounded hover:bg-black transition">Back to Shop</button></div>`;
    } else {
        const existingCatSentinel = document.getElementById('category-grid-sentinel');
        if (existingCatSentinel) existingCatSentinel.remove();
        if (categoryGridObserver) { categoryGridObserver.disconnect(); categoryGridObserver = null; }
        categoryProductList = filteredProducts;
        categoryProductRenderedCount = 0;
        const firstBatch = categoryProductList.slice(0, CATEGORY_BATCH_SIZE).map((p, i) => getProductCard(p, false, { categoryListing: true, gridIndex: i })).join('');
        doc.categoryGrid.innerHTML = firstBatch;
        categoryProductRenderedCount = CATEGORY_BATCH_SIZE;
        if (categoryProductRenderedCount < categoryProductList.length && doc.categoryGrid.parentElement) {
            const sentinel = document.createElement('div');
            sentinel.id = 'category-grid-sentinel';
            sentinel.style.cssText = 'height:1px;visibility:hidden;pointer-events:none';
            doc.categoryGrid.parentElement.appendChild(sentinel);
            categoryGridObserver = new IntersectionObserver((entries) => {
                if (!entries[0]?.isIntersecting) return;
                const nextEnd = Math.min(categoryProductRenderedCount + CATEGORY_BATCH_SIZE, categoryProductList.length);
                const nextBatch = categoryProductList.slice(categoryProductRenderedCount, nextEnd).map((p, i) => getProductCard(p, false, { categoryListing: true, gridIndex: categoryProductRenderedCount + i })).join('');
                if (doc.categoryGrid && nextBatch) doc.categoryGrid.insertAdjacentHTML('beforeend', nextBatch);
                categoryProductRenderedCount = nextEnd;
                if (categoryProductRenderedCount >= categoryProductList.length && sentinel.parentNode) {
                    sentinel.remove();
                    if (categoryGridObserver) { categoryGridObserver.disconnect(); categoryGridObserver = null; }
                }
            }, { rootMargin: '120px' });
            categoryGridObserver.observe(sentinel);
        }
    }

    if (doc.catSidebar) {
        doc.catSidebar.innerHTML = buildCategorySidebarHTML(categoryName, baseProducts);
        bindCategorySidebarFlyouts(doc.catSidebar);
    }
    updateCategorySubnav(categoryName);
    updateCategoryFilterSheet(categoryName, baseProducts);
    syncCategorySortSelects(currentCategorySort);
    if (doc.categoryView) {
        doc.categoryView.querySelectorAll('.cat-price-dual-wrap').forEach((w) => syncCategoryPriceDualUI(w));
    }
};

const renderAllCategoriesPage = () => {
    if (!doc.categoryGrid || !doc.categoryView) return;
    resetCategoryListingChrome();
    const categoryConfig = state.siteSettings?.layout?.categoryConfig || {};
    const cardStyle = (categoryConfig.cardStyle === 'chaldal' || categoryConfig.cardStyle === 'shwapno') ? categoryConfig.cardStyle : 'default';
    const catShape = categoryConfig.shape === 'square' ? 'square' : 'round';
    const catSpace = Math.min(40, Math.max(0, Number(categoryConfig.spaceBetween) ?? 10));
    let perRowDesktop = Math.min(8, Math.max(2, parseInt(categoryConfig.categoriesPerRowDesktop, 10) || 4));
    let perRowMobile = Math.min(6, Math.max(1, parseInt(categoryConfig.categoriesPerRowMobile, 10) || 3));
    const radius = catShape === 'square' ? 'rounded-lg' : 'rounded-full';
    if (doc.catHeaderTitle) doc.catHeaderTitle.textContent = 'All Categories';
    if (doc.catBreadcrumb) doc.catBreadcrumb.textContent = 'All Categories';
    if (doc.catCount) doc.catCount.textContent = state.allCategories.length ? `${state.allCategories.length} categories` : '0 categories';
    if (state.allCategories.length === 0) {
        doc.categoryGrid.innerHTML = `<div class="col-span-full flex flex-col items-center justify-center py-20 text-gray-400"><i class="fa-solid fa-folder-open text-6xl mb-4"></i><p class="text-lg font-bold">No categories yet</p><button onclick="window.location.hash='#/shop'" class="mt-4 px-6 py-2 bg-gray-800 text-white rounded hover:bg-black transition">Back to Shop</button></div>`;
    } else {
        const chaldalHeightMob = Math.min(140, Math.max(56, Number(categoryConfig.sizeMobile) || 96));
        const chaldalVars = `--chaldal-h-mob:${chaldalHeightMob}px;`;
        const sizePc = Math.min(250, Math.max(100, Number(categoryConfig.sizeDesktop) || 170));
        const defaultCards = state.allCategories.map(cat => `<div class="category-grid-card flex flex-col items-center justify-center cursor-pointer group bg-white border border-gray-100 overflow-hidden shadow-sm hover:shadow-md transition active:scale-[0.98]" onclick="window.location.hash='#/category/${encodeURIComponent(cat.name)}'" title="${cat.name}"><div class="w-full overflow-hidden ${radius}" style="aspect-ratio:1;width:100%"><img src="${cat.imageUrl}" alt="${cat.name}" width="${sizePc}" height="${sizePc}" class="w-full h-full object-cover" loading="lazy"></div></div>`).join('');
        const chaldalCards = state.allCategories.map((cat) => `<div class="category-grid-card category-card-chaldal category-card-chaldal--all flex cursor-pointer overflow-hidden rounded-xl border border-gray-200 shadow-sm hover:shadow-md transition active:scale-[0.98] bg-gray-100" onclick="window.location.hash='#/category/${encodeURIComponent(cat.name)}'" title="${cat.name}"><img src="${cat.imageUrl}" alt="${cat.name}" width="${chaldalHeightMob}" height="${chaldalHeightMob}" class="w-full h-full object-cover" loading="lazy"></div>`).join('');
        const shwapnoCards = state.allCategories.map(cat => {
            const nameEsc = String(cat.name || '').replace(/</g, '&lt;');
            return `<div class="category-grid-card category-card-shwapno flex flex-col cursor-pointer overflow-hidden transition active:scale-[0.98] bg-white" onclick="window.location.hash='#/category/${encodeURIComponent(cat.name)}'" title="${nameEsc}"><div class="category-card-shwapno-img"><img src="${cat.imageUrl || ''}" alt="${nameEsc}" loading="lazy"></div><div class="category-card-shwapno-label">${nameEsc}</div></div>`;
        }).join('');
        const allCatLink = `<a href="#/categories" class="all-categories-link inline-block mt-4 text-base font-bold hover:underline" style="color: var(--accent-color);">All Categories</a>`;
        if (cardStyle === 'shwapno') {
            doc.categoryGrid.innerHTML = `<div class="hidden md:block"><div class="all-categories-grid" style="--per-row-desk:${perRowDesktop};display:grid;gap:${catSpace}px;grid-template-columns:repeat(${perRowDesktop}, 1fr);">${shwapnoCards}</div><div class="text-center">${allCatLink}</div></div><div class="block md:hidden"><div class="all-categories-grid" style="--per-row-mob:${perRowMobile};display:grid;gap:${catSpace}px;grid-template-columns:repeat(${perRowMobile}, 1fr);">${shwapnoCards}</div><div class="text-center">${allCatLink}</div></div>`;
        } else if (cardStyle === 'chaldal') {
            doc.categoryGrid.innerHTML = `<div class="hidden md:block"><div class="all-categories-grid" style="--per-row-desk:${perRowDesktop};display:grid;gap:${catSpace}px;grid-template-columns:repeat(${perRowDesktop}, 1fr);">${defaultCards}</div><div class="text-center">${allCatLink}</div></div><div class="block md:hidden"><div class="all-categories-grid category-grid--chaldal" style="--per-row-mob:2;${chaldalVars}display:grid;gap:${catSpace}px;grid-template-columns:repeat(2, 1fr);">${chaldalCards}</div><div class="text-center">${allCatLink}</div></div>`;
        } else {
            doc.categoryGrid.innerHTML = `<div class="all-categories-grid" style="--per-row-mob:${perRowMobile};--per-row-desk:${perRowDesktop};display:grid;gap:${catSpace}px;grid-template-columns:repeat(${perRowMobile}, 1fr);">${defaultCards}</div><div class="text-center">${allCatLink}</div>`;
        }
        doc.categoryGrid.querySelectorAll('.all-categories-link').forEach(el => { el.onclick = (e) => { e.preventDefault(); window.location.hash = '#/categories'; }; });
    }
    if (doc.catSidebar && state.allCategories.length > 0) {
        doc.catSidebar.innerHTML = buildCategorySidebarHTML('', []);
        bindCategorySidebarFlyouts(doc.catSidebar);
    }
};

const renderWishlistPage = () => {
    resetCategoryListingChrome();
    if(doc.categoryView) doc.categoryView.classList.add('hidden');
    if(doc.homeView) doc.homeView.classList.add('hidden');
    const container = document.getElementById('category-products-grid'); 
    const wrapper = document.getElementById('category-view');
    if(container && wrapper) {
        applyProductGridToElement(container);
        wrapper.classList.remove('hidden');
        if(doc.catHeaderTitle) doc.catHeaderTitle.textContent = "My Wishlist";
        if(doc.catBreadcrumb) doc.catBreadcrumb.textContent = "Wishlist";
        if(doc.catCount) doc.catCount.textContent = `${wishlistState.length} items`;
        if(doc.catSidebar) doc.catSidebar.innerHTML = '<p class="text-sm text-gray-500">Your saved items.</p>';
        if (wishlistState.length === 0) {
            container.innerHTML = `<div class="col-span-full flex flex-col items-center justify-center py-20 text-gray-400"><i class="fa-regular fa-heart text-6xl mb-4"></i><p class="text-lg font-bold">Your wishlist is empty</p><button onclick="window.location.hash='#/shop'" class="mt-4 px-6 py-2 bg-gray-800 text-white rounded hover:bg-black transition">Start Shopping</button></div>`;
        } else {
            const products = state.allProducts.filter(p => wishlistState.includes(p.id));
            container.innerHTML = products.map((p, i) => getProductCard(p, false, { gridIndex: i })).join('');
        }
    }
};

const renderProfileView = () => {
    if(doc.profileName) doc.profileName.textContent = userProfile.name;
    if(doc.profileId) doc.profileId.textContent = `ID: ${userProfile.id}`;
    if(doc.statViewed) doc.statViewed.textContent = userProfile.views;
    if(doc.statOrders) doc.statOrders.textContent = userProfile.orders;
    if(doc.statWishlist) doc.statWishlist.textContent = wishlistState.length;
    if(doc.profDevice) doc.profDevice.textContent = userProfile.device;
    if(doc.profBrowser) doc.profBrowser.textContent = userProfile.browser;
    if(doc.profLastVisit) doc.profLastVisit.textContent = userProfile.joinDate;
};

// --- NEW: RENDER CONTENT PAGES (POLICIES, CONTACT, ABOUT) ---
const renderContentPage = (slug) => {
    if(!doc.policyView) return;

    // Define content mapping logic
    let title = 'Page not found';
    let content = 'Content coming soon...';

    // Check Policies first
    const policies = state.siteSettings?.policies || {};
    const policyMap = {
        'privacy': 'Privacy Policy',
        'terms': 'Terms & Conditions',
        'refund': 'Return & Refund Policy',
        'shipping': 'Shipping Policy'
    };

    if (policyMap[slug]) {
        title = policyMap[slug];
        content = policies[slug] || 'Policy details not yet updated by admin.';
    } 
    // Check Other Pages
    else if (slug === 'contact') {
        title = 'Contact Us';
        const contact = state.siteSettings?.contactInfo || {};
        content = `
            <div class="space-y-4">
                <p><strong>Hotline:</strong> ${contact.hotlineNumber || 'N/A'}</p>
                <p><strong>Phone:</strong> ${contact.phoneNumber || 'N/A'}</p>
                <p><strong>Address:</strong> ${contact.address || 'Address not set'}</p>
                <p><strong>WhatsApp:</strong> ${contact.whatsappNumber || 'N/A'}</p>
                <p>We are available every day from 9:00 AM to 8:00 PM.</p>
            </div>
        `;
    } else if (slug === 'about') {
        title = 'About Us';
        content = state.siteSettings?.textContent?.aboutDescription || 'About us content coming soon.';
    }

    // Render
    if(doc.policyTitle) doc.policyTitle.textContent = title;
    if(doc.policyContent) doc.policyContent.innerHTML = content.replace(/\n/g, '<br>');
};

const renderTrendingTags = () => {
    if (!doc.trendingContainer || !state.allProducts.length) return;
    const tags = state.allProducts.slice(0, 6).map(p => p.name.split(' ').slice(0, 3).join(' '));
    doc.trendingContainer.innerHTML = tags.map(tag => `<button class="px-3 py-1.5 bg-white border border-gray-200 rounded-full text-xs font-medium text-gray-600 hover:bg-green-50 hover:text-green-700 hover:border-green-200 transition" onclick="document.getElementById('real-mobile-search-input').value='${tag}'; document.getElementById('real-mobile-search-input').dispatchEvent(new Event('input'));">${tag}</button>`).join('');
};

// ============================================================
// 7. DETAIL VIEW LOGIC (UPDATED WITH UNIFIED SWIPER)
// ============================================================

const decodeHtmlEntities = (str) => {
    if (!str || typeof str !== 'string') return str;
    const div = document.createElement('div');
    div.innerHTML = str;
    return div.textContent || div.innerText || str;
};

/**
 * Classic detail view: usable variant rows only (Firebase / imports may leave hasVariants=true with empty keys).
 * Prevents crashes on variantsArr[0] and .name helpers when payloads are malformed.
 */
const normalizeDetailVariantsForClassic = (product) => {
    if (!product || !product.hasVariants || !product.variants || typeof product.variants !== 'object') return [];
    try {
        const rows = [];
        for (const [k, val] of Object.entries(product.variants)) {
            if (!k || !val || typeof val !== 'object') continue;
            const salePrice = Number(val.salePrice);
            const nameRaw = val.name != null ? String(val.name) : '';
            const name = nameRaw.trim();
            if (!name || !Number.isFinite(salePrice) || salePrice <= 0) continue;
            let regularPrice = null;
            if (val.regularPrice != null) {
                const reg = Number(val.regularPrice);
                regularPrice = Number.isFinite(reg) ? reg : null;
            }
            rows.push({
                id: k,
                name,
                salePrice,
                regularPrice,
                stock: val.stock,
                image: val.image || null,
                barcode: val.barcode
            });
        }
        return rows;
    } catch (err) {
        console.warn('[normalizeDetailVariantsForClassic]', err);
        return [];
    }
};

/** Defaults match previous hardcoded Classic product page CTAs */
const resolveMobileBottomBar = (siteSettings) => {
    const d = {
        captionAbove: '',
        buttonCount: 2,
        primaryLabel: 'Add to Cart',
        primaryAction: 'addToCart',
        secondaryLabel: 'Buy Now',
        secondaryAction: 'buyNow'
    };
    const mb = siteSettings && siteSettings.mobileBottomBar;
    if (!mb || typeof mb !== 'object') return d;
    const resolved = {
        captionAbove: String(mb.captionAbove || '').trim(),
        buttonCount: Number(mb.buttonCount) === 1 ? 1 : 2,
        primaryLabel: (mb.primaryLabel != null && String(mb.primaryLabel).trim()) ? String(mb.primaryLabel).trim() : d.primaryLabel,
        primaryAction: mb.primaryAction === 'buyNow' ? 'buyNow' : 'addToCart',
        secondaryLabel: (mb.secondaryLabel != null && String(mb.secondaryLabel).trim()) ? String(mb.secondaryLabel).trim() : d.secondaryLabel,
        secondaryAction: mb.secondaryAction === 'addToCart' ? 'addToCart' : 'buyNow'
    };
    if (resolved.buttonCount === 2 && resolved.primaryAction === resolved.secondaryAction) {
        resolved.secondaryAction = resolved.primaryAction === 'buyNow' ? 'addToCart' : 'buyNow';
        logBuyNowDebug('cta_action_normalized', {
            reason: 'both_actions_same',
            resolvedActions: { primary: resolved.primaryAction, secondary: resolved.secondaryAction },
            clientContext: getClientContextDebug()
        });
    }
    return resolved;
};

const renderDetailCtaBar = (ctaBarEl, mb, addToCartWithQty) => {
    if (!ctaBarEl || typeof addToCartWithQty !== 'function') return;
    ctaBarEl.innerHTML = '';
    ctaBarEl.classList.remove('grid-cols-1', 'grid-cols-2');
    ctaBarEl.classList.add(mb.buttonCount === 1 ? 'grid-cols-1' : 'grid-cols-2');

    if (mb.captionAbove) {
        const cap = document.createElement('p');
        cap.id = 'detail-cta-caption';
        cap.className = 'col-span-full text-center text-xs font-semibold mb-1 px-1';
        cap.style.color = 'var(--text-secondary)';
        cap.textContent = mb.captionAbove;
        ctaBarEl.appendChild(cap);
    }

    const mkBtn = (label, action) => {
        const isBuy = action === 'buyNow';
        const btn = document.createElement('button');
        btn.type = 'button';
        btn.className = isBuy
            ? 'btn-buy-now w-full py-3.5 sm:py-4 rounded-lg font-bold shadow transition flex justify-center items-center gap-2 text-sm sm:text-base leading-tight'
            : 'btn-add-cart w-full py-3.5 sm:py-4 rounded-lg font-bold transition flex justify-center items-center gap-2 text-sm sm:text-base leading-tight';
        btn.textContent = label;
        btn.addEventListener('click', () => {
            const freezeSnapshot = getFreezeBlockerSnapshot();
            logBuyNowDebug('cta_click', {
                clickedAction: action,
                clickedLabel: label,
                isBuyNow: isBuy,
                cartCountBeforeClick: state.cartItems.length,
                currentClientId: getCurrentClientId(),
                clientContext: getClientContextDebug(),
                freezeSnapshot,
                ctaConfig: {
                    buttonCount: mb.buttonCount,
                    primaryLabel: mb.primaryLabel,
                    primaryAction: mb.primaryAction,
                    secondaryLabel: mb.secondaryLabel,
                    secondaryAction: mb.secondaryAction
                }
            });
            addToCartWithQty(isBuy);
        });
        return btn;
    };

    ctaBarEl.appendChild(mkBtn(mb.primaryLabel, mb.primaryAction));
    if (mb.buttonCount === 2) {
        ctaBarEl.appendChild(mkBtn(mb.secondaryLabel, mb.secondaryAction));
    }
};

/** 2×2 grid: Add to cart, Buy now, WhatsApp, Call — used only for mobileCommerceV2 */
const renderDetailFourActionGrid = (gridEl, mb, addToCartWithQty, ph, wa, product) => {
    if (!gridEl || typeof addToCartWithQty !== 'function') return;
    gridEl.innerHTML = '';
    gridEl.classList.remove('hidden');

    const esc = (s) => String(s == null ? '' : s)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/"/g, '&quot;');

    const runCommerceClick = (isBuy, label, action) => {
        logBuyNowDebug('cta_click', {
            clickedAction: action,
            clickedLabel: label,
            isBuyNow: isBuy,
            cartCountBeforeClick: state.cartItems.length,
            currentClientId: getCurrentClientId(),
            clientContext: getClientContextDebug(),
            freezeSnapshot: getFreezeBlockerSnapshot(),
            ctaConfig: {
                buttonCount: mb.buttonCount,
                primaryLabel: mb.primaryLabel,
                primaryAction: mb.primaryAction,
                secondaryLabel: mb.secondaryLabel,
                secondaryAction: mb.secondaryAction
            }
        });
        addToCartWithQty(isBuy);
    };

    const mkCommerce = (label, action) => {
        const isBuy = action === 'buyNow';
        const btn = document.createElement('button');
        btn.type = 'button';
        btn.className = isBuy
            ? 'btn-buy-now w-full py-3.5 rounded-lg font-bold shadow transition flex flex-col justify-center items-center gap-1 text-xs sm:text-sm leading-tight text-center min-h-[4.5rem]'
            : 'btn-add-cart w-full py-3.5 rounded-lg font-bold transition flex flex-col justify-center items-center gap-1 text-xs sm:text-sm leading-tight text-center min-h-[4.5rem]';
        /* Reference: bag icon on Add to cart only; Buy now is text-only */
        if (isBuy) {
            btn.innerHTML = `<span class="font-extrabold uppercase tracking-wide">${esc(label)}</span>`;
        } else {
            btn.innerHTML = `<i class="fa-solid fa-bag-shopping text-lg" aria-hidden="true"></i><span class="font-extrabold uppercase tracking-wide">${esc(label)}</span>`;
        }
        btn.addEventListener('click', () => runCommerceClick(isBuy, label, action));
        return btn;
    };

    if (mb.buttonCount === 2) {
        const addLabel = mb.primaryAction === 'addToCart' ? mb.primaryLabel : mb.secondaryLabel;
        const buyLabel = mb.primaryAction === 'buyNow' ? mb.primaryLabel : mb.secondaryLabel;
        gridEl.appendChild(mkCommerce(addLabel, 'addToCart'));
        gridEl.appendChild(mkCommerce(buyLabel, 'buyNow'));
    } else {
        const btn = mkCommerce(mb.primaryLabel, mb.primaryAction);
        btn.classList.add('col-span-2');
        gridEl.appendChild(btn);
    }

    const waBtn = document.createElement('button');
    waBtn.type = 'button';
    waBtn.className = 'btn-whatsapp w-full py-3.5 rounded-lg font-bold shadow transition flex flex-col justify-center items-center gap-1 text-xs sm:text-sm min-h-[4.5rem]';
    waBtn.innerHTML = '<i class="fa-brands fa-whatsapp text-2xl" aria-hidden="true"></i><span class="font-extrabold tracking-wide">Order On WhatsApp</span>';
    waBtn.addEventListener('click', () => {
        if (wa.length >= 10) {
            window.open(`https://wa.me/${wa}?text=${encodeURIComponent('I want to buy ' + product.name)}`, '_blank');
        } else {
            showToast('WhatsApp number not set.', 'error');
        }
    });

    const callBtn = document.createElement('button');
    callBtn.type = 'button';
    callBtn.className = 'btn-detail-call-v2 w-full py-3.5 rounded-lg font-bold shadow transition flex flex-col justify-center items-center gap-1 text-xs sm:text-sm min-h-[4.5rem]';
    callBtn.innerHTML = '<i class="fa-solid fa-phone text-lg" aria-hidden="true"></i><span class="font-extrabold tracking-wide">Call For Order</span>';
    callBtn.addEventListener('click', () => {
        window.location.href = `tel:${ph}`;
    });

    gridEl.appendChild(waBtn);
    gridEl.appendChild(callBtn);
};

const renderDetailView = (productId) => {
    const product = state.allProducts.find(p => String(p.id) === String(productId));
    if (!product) {
        if (state.storeCatalogFetchStatus === 'loading') return;
        window.location.hash = '';
        return;
    }

    if (fomoInterval) { clearInterval(fomoInterval); fomoInterval = null; }
    updateProfileActivity('view');
    state.currentViewingProduct = product;

    const rawDetailLayout = state.siteSettings?.layout?.productDetailLayout;
    const productDetailLayout =
        rawDetailLayout === 'mobileCommerceV1' || rawDetailLayout === 'mobileCommerceV2'
            ? rawDetailLayout
            : 'standard';

    // --- ENSURE DETAIL REFS (from document or from inside detail view so content always shows) ---
    const detailRoot = getEl('product-detail-view');
    if (detailRoot) {
        detailRoot.dataset.detailLayout = productDetailLayout;
        detailRoot.classList.remove('detail-layout--standard', 'detail-layout--mobileCommerceV1', 'detail-layout--mobileCommerceV2');
        if (productDetailLayout === 'standard') {
            detailRoot.classList.add('detail-layout--standard');
        } else {
            detailRoot.classList.add(`detail-layout--${productDetailLayout}`);
        }
    }
    const byId = (id) => getEl(id) || (detailRoot ? detailRoot.querySelector(`#${id}`) : null);
    if (!doc.detailDesc) doc.detailDesc = byId('detail-description');
    if (!doc.detailShortDesc) doc.detailShortDesc = byId('detail-short-desc');
    if (!doc.detailTitle) doc.detailTitle = byId('detail-title');
    if (!doc.detailPriceBox) doc.detailPriceBox = byId('detail-price-box');
    if (!doc.detailSku) doc.detailSku = byId('detail-sku');
    if (!doc.detailBrand) doc.detailBrand = byId('detail-brand');
    if (!doc.detailVariants) doc.detailVariants = byId('detail-variants');
    if (!doc.detailCtaBar) doc.detailCtaBar = byId('detail-cta-bar');
    if (!doc.btnCall) doc.btnCall = byId('btn-call-now');
    if (!doc.btnWhatsapp) doc.btnWhatsapp = byId('btn-whatsapp');
    if (!doc.btnMessenger) doc.btnMessenger = byId('btn-messenger');
    if (!doc.relatedContainer) doc.relatedContainer = byId('related-products-container');
    if (!doc.detailQtyInput) doc.detailQtyInput = byId('detail-qty-input');
    if (!doc.detailQtyPlus) doc.detailQtyPlus = byId('detail-qty-plus');
    if (!doc.detailQtyMinus) doc.detailQtyMinus = byId('detail-qty-minus');

    const fourGridEl = byId('detail-four-action-grid');
    if (fourGridEl && productDetailLayout !== 'mobileCommerceV2') {
        fourGridEl.classList.add('hidden');
        fourGridEl.innerHTML = '';
    }

    // --- SHOW IMAGE IMMEDIATELY (before Swiper/thumb logic) ---
    if (doc.detailMainImg) {
        doc.detailMainImg.src = product.imageUrl;
        doc.detailMainImg.alt = decodeHtmlEntities(product.name) || 'Product';
        doc.detailMainImg.classList.remove('hidden');
    }
    if (doc.detailVideoPlayer) {
        doc.detailVideoPlayer.src = '';
        doc.detailVideoPlayer.classList.add('hidden');
    }
    if (doc.detailTitle) doc.detailTitle.textContent = decodeHtmlEntities(product.name);
    
    // --- 1. UNIFIED MEDIA LOGIC ---
    const mediaList = [];
    const videoID = product.videoUrl ? extractVideoID(product.videoUrl) : null;
    if (videoID) {
        mediaList.push({ type: 'video', id: videoID, thumb: `https://img.youtube.com/vi/${videoID}/0.jpg` });
    }
    mediaList.push({ type: 'image', src: product.imageUrl });
    if (product.galleryImageUrls && Array.isArray(product.galleryImageUrls)) {
        product.galleryImageUrls.forEach(url => mediaList.push({ type: 'image', src: url }));
    }

    // --- 2. KEEP MAIN IMAGE IN SYNC (video may override later) ---
    pushToDataLayer('view_item', { currency: "BDT", value: product.salePrice, items: [{ item_id: product.id, item_name: product.name, price: product.salePrice, item_category: product.category, quantity: 1 }] });

    // --- 3. GENERATE SWIPER SLIDES ---
    // Active slide index logic: If video exists (index 0), standard image is index 1. 
    // We start with standard image active in main view, but thumb index 1 should be active.
    // If no video, index 0 is main image.
    let initialActiveIndex = videoID ? 1 : 0; 

    const slidesHtml = mediaList.map((media, index) => {
        const isActive = index === initialActiveIndex ? 'swiper-slide-thumb-active' : '';
        if (media.type === 'video') {
            return `
                <div class="swiper-slide swiper-slide-thumb ${isActive}" data-index="${index}" data-type="video" data-id="${media.id}">
                    <img src="${media.thumb}" alt="Product Video" loading="lazy" decoding="async">
                    <div class="video-badge"><i class="fa-solid fa-play"></i></div>
                </div>
            `;
        } else {
            return `
                <div class="swiper-slide swiper-slide-thumb ${isActive}" data-index="${index}" data-type="image" data-src="${media.src}">
                    <img src="${media.src}" alt="Product Image" loading="lazy" decoding="async">
                </div>
            `;
        }
    }).join('');

    if (doc.detailThumbnails) doc.detailThumbnails.innerHTML = slidesHtml;

    const getThumbSlides = () =>
        doc.detailThumbnails
            ? doc.detailThumbnails.querySelectorAll('.swiper-slide-thumb')
            : document.querySelectorAll('.swiper-slide-thumb');

    const fireVariantPixel = (variantLabel) => {
        try {
            trackPixelEvent('VariantSelected', {
                content_name: product.name,
                content_ids: [String(product.id)],
                variant: String(variantLabel || '').slice(0, 200),
            });
        } catch (_) { /* noop */ }
    };
    let detailGallerySwipedSent = false;
    const fireImageGallerySwipedOnce = () => {
        if (detailGallerySwipedSent) return;
        detailGallerySwipedSent = true;
        try {
            trackPixelEvent('ImageGallerySwiped', { content_name: product.name, content_ids: [String(product.id)] });
        } catch (_) { /* noop */ }
    };

    // --- 4. INIT THUMBNAIL SWIPER (only when container exists) ---
    if (doc.detailThumbnails) {
        if (thumbSwiper) {
            thumbSwiper.destroy(true, true);
            thumbSwiper = null;
        }
        const thumbEl = document.querySelector('.thumb-swiper');
        if (thumbEl) {
            const isV2 = productDetailLayout === 'mobileCommerceV2';
            thumbSwiper = new Swiper('.thumb-swiper', isV2 ? {
                direction: 'vertical',
                spaceBetween: 8,
                slidesPerView: 4,
                slidesPerGroup: 1,
                freeMode: true,
                watchSlidesProgress: true,
                navigation: { nextEl: '.thumb-next', prevEl: '.thumb-prev' },
                observer: true,
                observeParents: true,
                resizeObserver: true
            } : {
                spaceBetween: 10,
                slidesPerView: 4,
                freeMode: true,
                watchSlidesProgress: true,
                navigation: { nextEl: '.thumb-next', prevEl: '.thumb-prev' },
                breakpoints: { 320: { slidesPerView: 4 }, 480: { slidesPerView: 5 }, 640: { slidesPerView: 5 }, 1024: { slidesPerView: 5 } }
            });
            if (isV2 && thumbSwiper) {
                requestAnimationFrame(() => {
                    try { thumbSwiper.update(); } catch (_) { /* noop */ }
                });
            }
            const slides = getThumbSlides();
            const updateMainView = (media) => {
                if (media.type === 'video') {
                    if (doc.detailMainImg) doc.detailMainImg.classList.add('hidden');
                    if (doc.detailVideoPlayer) { doc.detailVideoPlayer.classList.remove('hidden'); doc.detailVideoPlayer.src = `https://www.youtube.com/embed/${media.id}?autoplay=1&rel=0`; }
                } else {
                    if (doc.detailVideoPlayer) { doc.detailVideoPlayer.classList.add('hidden'); doc.detailVideoPlayer.src = ""; }
                    if (doc.detailMainImg) { doc.detailMainImg.classList.remove('hidden'); doc.detailMainImg.src = media.src; }
                }
            };
            slides.forEach((slide, idx) => {
                slide.addEventListener('click', () => {
                    slides.forEach(s => s.classList.remove('swiper-slide-thumb-active'));
                    slide.classList.add('swiper-slide-thumb-active');
                    const m = mediaList[idx];
                    if (m) updateMainView(m);
                    fireImageGallerySwipedOnce();
                });
            });
        }
    }

    // --- REST OF DETAIL VIEW LOGIC (null-safe so description & buttons always run) ---
    if (doc.detailSku) doc.detailSku.textContent = product.sku || `SKU-${Math.floor(100000 + Math.random() * 900000)}`;
    if (doc.detailBrand) doc.detailBrand.textContent = product.brand || "Generic";
    const plainDesc = product.description ? product.description.replace(/<[^>]*>?/gm, '') : '';
    const shortDescText = plainDesc.length > 180 ? decodeHtmlEntities(plainDesc).substring(0, 150) + '...' : '';
    if (doc.detailShortDesc) { doc.detailShortDesc.textContent = shortDescText; if (doc.detailShortDesc.parentElement) doc.detailShortDesc.parentElement.style.display = shortDescText ? '' : 'none'; }
    if (doc.detailDesc) doc.detailDesc.innerHTML = (product.description || 'No description available.').replace(/&amp;/g, '&');

    const ph = state.siteSettings?.contactInfo?.phoneNumber || '';
    const wa = normalizeWhatsAppNumber(state.siteSettings?.contactInfo?.whatsappNumber);
    
    if(doc.btnCall) doc.btnCall.onclick = () => window.location.href = `tel:${ph}`;
    if(doc.btnWhatsapp) doc.btnWhatsapp.onclick = () => wa.length >= 10 ? window.open(`https://wa.me/${wa}?text=${encodeURIComponent('I want to buy ' + product.name)}`, '_blank') : showToast('WhatsApp number not set.', 'error');
    if(doc.btnMessenger) doc.btnMessenger.onclick = () => window.open(`https://m.me/`, '_blank'); 

    if(doc.sizeChartTriggerBtn) { doc.sizeChartTriggerBtn.classList.add('hidden'); doc.sizeChartTriggerBtn.onclick = null; }
    if (product.sizeChartUrl && doc.sizeChartTriggerBtn) {
        doc.sizeChartTriggerBtn.classList.remove('hidden');
        doc.sizeChartTriggerBtn.onclick = () => {
            if(doc.sizeChartImg) doc.sizeChartImg.src = product.sizeChartUrl;
            if(doc.sizeChartModal) doc.sizeChartModal.classList.remove('hidden');
        };
    }

    let currentQty = 1;
    /** Set when mobile-commerce FBT bundle is rendered; no-op otherwise */
    let refreshDetailFbtBundleUi = null;
    const updateQty = (val) => {
        currentQty = val < 1 ? 1 : val;
        if (doc.detailQtyInput) doc.detailQtyInput.value = currentQty;
        if (typeof refreshDetailFbtBundleUi === 'function') refreshDetailFbtBundleUi();
    };
    if (doc.detailQtyInput) doc.detailQtyInput.value = 1;
    if (doc.detailQtyPlus && doc.detailQtyMinus) {
        const newPlus = doc.detailQtyPlus.cloneNode(true); const newMinus = doc.detailQtyMinus.cloneNode(true);
        doc.detailQtyPlus.parentNode.replaceChild(newPlus, doc.detailQtyPlus); doc.detailQtyMinus.parentNode.replaceChild(newMinus, doc.detailQtyMinus);
        doc.detailQtyPlus = newPlus; doc.detailQtyMinus = newMinus;
        doc.detailQtyPlus.addEventListener('click', () => updateQty(currentQty + 1)); doc.detailQtyMinus.addEventListener('click', () => updateQty(currentQty - 1));
    }

    let selectedVariantId = null; let selectedColor = null; let selectedSize = null;
    const setPriceDisplay = (p) => {
        const reg = p.regularPrice != null && p.regularPrice > p.salePrice ? p.regularPrice : 0;
        let html = reg > 0
            ? `<span class="text-red-500 line-through text-xl mr-2">${formatPrice(reg)}</span><span class="text-3xl font-extrabold" style="color: var(--price-text);">${formatPrice(p.salePrice)}</span>`
            : `<span class="text-3xl font-extrabold" style="color: var(--price-text);">${formatPrice(p.salePrice)}</span>`;
        if ((productDetailLayout === 'mobileCommerceV1' || productDetailLayout === 'mobileCommerceV2') && reg > 0) {
            const pct = Math.round((1 - Number(p.salePrice) / Number(reg)) * 100);
            if (pct > 0 && pct < 100) {
                html += `<span class="detail-save-pct-badge">Save ${pct}%</span>`;
            }
        }
        if (doc.detailPriceBox) doc.detailPriceBox.innerHTML = html;
        if (typeof refreshDetailFbtBundleUi === 'function') refreshDetailFbtBundleUi();
    };
    if (doc.detailVariants) doc.detailVariants.innerHTML = '';

    let requiresVariantSelection = false;

    const detailUsableVariants = normalizeDetailVariantsForClassic(product);
    const useVariantUi = !!(doc.detailVariants && detailUsableVariants.length > 0);

    const applyDetailVariantFallback = () => {
        requiresVariantSelection = false;
        selectedVariantId = null;
        if (doc.detailVariantLabel) doc.detailVariantLabel.textContent = 'Select option:';
        setPriceDisplay(product);
        if (doc.detailVariants) doc.detailVariants.innerHTML = '<p class="text-sm text-gray-500 italic">No options available.</p>';
        if (doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = 'Default';
    };

    // Handle Variants (Color/Size) — show only what admin configured (variantAttributes)
    if (useVariantUi) {
        requiresVariantSelection = true;
        try {
            const variantsArr = detailUsableVariants;
        const attrs = product.variantAttributes || [];
        const hasColorAttr = attrs.includes('color');
        const hasSizeAttr = attrs.includes('size');
        const isComposite = variantsArr.length > 0 && variantsArr.every(v => typeof v.name === 'string' && v.name.includes(' - '));
        // Use variantAttributes if set; else fallback: composite names → both, else single list
        const showBoth = hasColorAttr && hasSizeAttr ? true : (attrs.length === 0 && isComposite);

        if (doc.detailVariantLabel) {
            if (showBoth) doc.detailVariantLabel.textContent = 'Select Color & Size:';
            else if (hasSizeAttr) doc.detailVariantLabel.textContent = 'Select Your Size:';
            else if (hasColorAttr) doc.detailVariantLabel.textContent = 'Select Your Color:';
            else doc.detailVariantLabel.textContent = 'Select option:';
        }

        if (showBoth) {
            const attributes = {};
            variantsArr.forEach(v => {
                const parts = (v.name || '').split(' - ');
                const color = (parts[0] || '').trim();
                const size = (parts[1] || '').trim();
                if (!color || !size) return;
                if (!attributes[color]) attributes[color] = [];
                attributes[color].push({ ...v, sizeLabel: size });
            });

            const colorKeys = Object.keys(attributes);
            if (!colorKeys.length) throw new Error('detail_variant_composite_empty');

            const container = doc.detailVariants;
            container.innerHTML = `<div class="w-full mb-3"><p class="text-xs font-bold text-gray-500 uppercase mb-2">Colors</p><div id="smart-color-container" class="flex flex-wrap gap-2"></div></div><div class="w-full"><p class="text-xs font-bold text-gray-500 uppercase mb-2">Sizes</p><div id="smart-size-container" class="flex flex-wrap gap-2"><span class="text-sm text-gray-400 italic">Select a color first</span></div></div>`;

            const colorContainer = document.getElementById('smart-color-container');
            const sizeContainer = document.getElementById('smart-size-container');

            colorKeys.forEach((color, idx) => {
                const btn = document.createElement('button'); btn.className = `variant-btn ${idx === 0 ? 'active' : ''}`; btn.textContent = color; btn.onclick = () => { fireVariantPixel(color); selectColor(color); }; colorContainer.appendChild(btn);
            });

            const selectColor = (color) => {
                selectedColor = color; selectedSize = null; selectedVariantId = null;
                Array.from(colorContainer.children).forEach(b => b.classList.toggle('active', b.textContent === color));
                const sizes = attributes[color];
                if (!sizes || !sizes.length) return;
                sizeContainer.innerHTML = '';
                sizes.forEach((v, idx) => {
                    const btn = document.createElement('button'); btn.className = `variant-btn ${idx === 0 ? 'active' : ''}`; btn.textContent = v.sizeLabel; btn.onclick = () => { fireVariantPixel(v.sizeLabel); selectSize(v); }; sizeContainer.appendChild(btn);
                    if (idx === 0) selectSize(v);
                });

                const variantWithImage = sizes.find(s => s.image);
                if (variantWithImage) {
                    doc.detailMainImg.src = variantWithImage.image;
                    doc.detailMainImg.classList.remove('hidden');
                    doc.detailVideoPlayer.classList.add('hidden');
                    doc.detailVideoPlayer.src = '';
                    getThumbSlides().forEach(s => s.classList.remove('swiper-slide-thumb-active'));
                }
                if (doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = `${color}`;
            };

            const selectSize = (variant) => {
                selectedSize = variant.sizeLabel; selectedVariantId = variant.id;
                Array.from(sizeContainer.children).forEach(b => b.classList.toggle('active', b.textContent === variant.sizeLabel));
                setPriceDisplay(variant);
                if (doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = `${selectedColor} - ${selectedSize}`;
            };
            selectColor(colorKeys[0]);
        } else if (hasColorAttr) {
            // Only Color: one section "Color"
            const container = doc.detailVariants;
            container.innerHTML = `<div class="w-full mb-3"><p class="text-xs font-bold text-gray-500 uppercase mb-2">Color</p><div id="smart-single-container" class="flex flex-wrap gap-2"></div></div>`;
            const singleContainer = document.getElementById('smart-single-container');
            variantsArr.forEach((v, index) => {
                const btn = document.createElement('button'); btn.className = `variant-btn ${index === 0 ? 'active' : ''}`; btn.textContent = v.name;
                btn.onclick = () => { 
                    fireVariantPixel(v.name);
                    Array.from(singleContainer.children).forEach(b => b.classList.remove('active')); 
                    btn.classList.add('active'); 
                    selectedVariantId = v.id; 
                    setPriceDisplay(v); 
                    if(v.image) {
                        doc.detailMainImg.src = v.image;
                        doc.detailMainImg.classList.remove('hidden');
                        doc.detailVideoPlayer.classList.add('hidden');
                        doc.detailVideoPlayer.src = "";
                        getThumbSlides().forEach(s => s.classList.remove('swiper-slide-thumb-active'));
                    } 
                    if(doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = v.name; 
                };
                singleContainer.appendChild(btn);
            });
            selectedVariantId = variantsArr[0].id; setPriceDisplay(variantsArr[0]); if(doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = variantsArr[0].name;
        } else if (hasSizeAttr) {
            // Only Size: one section "Size"
            const container = doc.detailVariants;
            container.innerHTML = `<div class="w-full mb-3"><p class="text-xs font-bold text-gray-500 uppercase mb-2">Size</p><div id="smart-single-container" class="flex flex-wrap gap-2"></div></div>`;
            const singleContainer = document.getElementById('smart-single-container');
            variantsArr.forEach((v, index) => {
                const btn = document.createElement('button'); btn.className = `variant-btn ${index === 0 ? 'active' : ''}`; btn.textContent = v.name;
                btn.onclick = () => { 
                    fireVariantPixel(v.name);
                    Array.from(singleContainer.children).forEach(b => b.classList.remove('active')); 
                    btn.classList.add('active'); 
                    selectedVariantId = v.id; 
                    setPriceDisplay(v); 
                    if(v.image) {
                        doc.detailMainImg.src = v.image;
                        doc.detailMainImg.classList.remove('hidden');
                        doc.detailVideoPlayer.classList.add('hidden');
                        doc.detailVideoPlayer.src = "";
                        getThumbSlides().forEach(s => s.classList.remove('swiper-slide-thumb-active'));
                    } 
                    if(doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = v.name; 
                };
                singleContainer.appendChild(btn);
            });
            selectedVariantId = variantsArr[0].id; setPriceDisplay(variantsArr[0]); if(doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = variantsArr[0].name;
        } else {
            // Legacy: no variantAttributes — single list of options
            variantsArr.forEach((v, index) => {
                const btn = document.createElement('button'); btn.className = `variant-btn ${index === 0 ? 'active' : ''}`; btn.textContent = v.name;
                btn.onclick = () => { 
                    fireVariantPixel(v.name);
                    Array.from(doc.detailVariants.children).forEach(b => b.classList.remove('active')); 
                    btn.classList.add('active'); 
                    selectedVariantId = v.id; 
                    setPriceDisplay(v); 
                    if(v.image) {
                        doc.detailMainImg.src = v.image;
                        doc.detailMainImg.classList.remove('hidden');
                        doc.detailVideoPlayer.classList.add('hidden');
                        doc.detailVideoPlayer.src = "";
                        getThumbSlides().forEach(s => s.classList.remove('swiper-slide-thumb-active'));
                    } 
                    if(doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = v.name; 
                };
                doc.detailVariants.appendChild(btn);
            });
            selectedVariantId = variantsArr[0].id; setPriceDisplay(variantsArr[0]); if(doc.detailSelectedVarName) doc.detailSelectedVarName.textContent = variantsArr[0].name;
        }
        } catch (err) {
            console.error('[renderDetailView] variant UI failed:', err);
            applyDetailVariantFallback();
        }
    } else {
        applyDetailVariantFallback();
    }

    const addToCartWithQty = (isBuyNow) => {
        const beforeCount = state.cartItems.length;
        if (isBuyNow) {
            normalizeOverlayState('buy_now_preflight', { forceClose: false });
        }
        logBuyNowDebug('add_to_cart_with_qty_start', {
            isBuyNow,
            productId: product.id,
            productName: product.name,
            selectedVariantId: selectedVariantId || null,
            currentQty,
            cartCountBefore: beforeCount,
            currentClientId: getCurrentClientId(),
            freezeSnapshot: getFreezeBlockerSnapshot()
        });
        if (requiresVariantSelection && !selectedVariantId) { showToast("Please select options.", false); return; }

        const upsellContainerEl = getEl('product-bundle-container');
        const upsellGloballyOn = state.siteSettings?.layout?.upsellEnabled !== false;
        const upsellChecks = (upsellGloballyOn && upsellContainerEl)
            ? Array.from(upsellContainerEl.querySelectorAll('.upsell-checkbox:checked'))
            : [];

        let variantInfo = {};
        let price = product.salePrice;
        if (product.hasVariants && selectedVariantId && product.variants[selectedVariantId]) {
            variantInfo = product.variants[selectedVariantId];
            price = variantInfo.salePrice;
        }

        const upsellDl = [];
        upsellChecks.forEach((el) => {
            const pid = el.getAttribute('data-product-id');
            const up = state.allProducts.find((x) => String(x.id) === String(pid));
            if (!up || String(up.id) === String(product.id)) return;
            let vprice = Number(up.salePrice);
            let vname = null;
            if (up.hasVariants && up.variants) {
                const keys = Object.keys(up.variants);
                const vk = keys[0];
                if (!vk) return;
                vprice = Number(up.variants[vk]?.salePrice);
                vname = up.variants[vk]?.name || null;
            }
            if (Number.isNaN(vprice) || vprice <= 0) return;
            upsellDl.push({ item_id: up.id, item_name: up.name, item_variant: vname, price: vprice, quantity: 1 });
        });

        const mainLine = { item_id: product.id, item_name: product.name, item_variant: variantInfo.name || null, price: price, quantity: currentQty };
        const dlValue = mainLine.price * mainLine.quantity + upsellDl.reduce((s, i) => s + i.price * i.quantity, 0);
        pushToDataLayer('add_to_cart', { currency: "BDT", value: dlValue, items: [mainLine, ...upsellDl] });

        for (let i = 0; i < currentQty; i++) { addProductToCart(product.id, selectedVariantId, isBuyNow ? true : (i !== currentQty - 1)); }

        upsellChecks.forEach((el) => {
            const pid = el.getAttribute('data-product-id');
            const up = state.allProducts.find((x) => String(x.id) === String(pid));
            if (!up || String(up.id) === String(product.id)) return;
            const vid = up.hasVariants && up.variants ? Object.keys(up.variants)[0] : null;
            if (up.hasVariants && !vid) return;
            addProductToCart(up.id, vid, false, {});
        });

        const afterCount = state.cartItems.length;
        logBuyNowDebug('add_to_cart_with_qty_end', {
            isBuyNow,
            productId: product.id,
            cartCountBefore: beforeCount,
            cartCountAfter: afterCount,
            didCartChange: afterCount !== beforeCount
        });
        if (isBuyNow) {
            normalizeOverlayState('before_buy_now_redirect', { forceClose: true });
            logBuyNowDebug('buy_now_hash_set', {
                fromHash: window.location.hash || '',
                toHash: '#/checkout',
                cartCountAtRedirect: state.cartItems.length,
                freezeSnapshot: getFreezeBlockerSnapshot()
            });
            window.location.hash = '#/checkout';
            scheduleClassicRouteSync();
            setTimeout(() => {
                if (window.location.hash !== '#/checkout' && state.cartItems.length > 0) {
                    normalizeOverlayState('before_buy_now_hash_retry', { forceClose: true });
                    logBuyNowDebug('buy_now_hash_retry', {
                        reason: 'hash_changed_before_checkout',
                        currentHash: window.location.hash || '',
                        cartCount: state.cartItems.length,
                        freezeSnapshot: getFreezeBlockerSnapshot()
                    });
                    window.location.hash = '#/checkout';
                    scheduleClassicRouteSync();
                }
            }, 150);
        }
    };
    const detailCtaBarEl = byId('detail-cta-bar') || getEl('detail-cta-bar');
    const resolvedMb = resolveMobileBottomBar(state.siteSettings);
    if (productDetailLayout === 'mobileCommerceV2') {
        if (detailCtaBarEl) {
            detailCtaBarEl.innerHTML = '';
            detailCtaBarEl.classList.remove('grid-cols-1');
            detailCtaBarEl.classList.add('grid-cols-2');
        }
        renderDetailFourActionGrid(fourGridEl, resolvedMb, addToCartWithQty, ph, wa, product);
    } else {
        renderDetailCtaBar(detailCtaBarEl, resolvedMb, addToCartWithQty);
    }
    logBuyNowDebug('detail_cta_rendered', {
        productId: product.id,
        productName: product.name,
        currentClientId: getCurrentClientId(),
        clientContext: getClientContextDebug(),
        ctaConfig: {
            buttonCount: resolvedMb.buttonCount,
            primaryLabel: resolvedMb.primaryLabel,
            primaryAction: resolvedMb.primaryAction,
            secondaryLabel: resolvedMb.secondaryLabel,
            secondaryAction: resolvedMb.secondaryAction
        },
        productDetailLayout
    });

    const upsellGloballyOn = state.siteSettings?.layout?.upsellEnabled !== false;
    const bundleContainer = getEl('product-bundle-container');
    if (bundleContainer) {
        if (!upsellGloballyOn || product.enableUpsellCrossSell === false) {
            bundleContainer.innerHTML = '';
            bundleContainer.classList.add('hidden');
            refreshDetailFbtBundleUi = null;
            bundleContainer._fbtRefreshFn = null;
            bundleContainer._fbtAddFn = null;
        } else {
            const manualIds = Array.isArray(product.upsellProductIds) ? product.upsellProductIds.filter(Boolean) : [];
            const upsellProducts = manualIds.map((id) => state.allProducts.find((p) => String(p.id) === String(id))).filter(Boolean);
            if (!upsellProducts.length) {
                bundleContainer.innerHTML = '';
                bundleContainer.classList.add('hidden');
                refreshDetailFbtBundleUi = null;
                bundleContainer._fbtRefreshFn = null;
                bundleContainer._fbtAddFn = null;
            } else {
                bundleContainer.classList.remove('hidden');
                const esc = (s) => String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
                const escAttr = (s) => String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
                const upsellPricePair = (p) => {
                    let sale = Number(p.salePrice);
                    let reg = p.regularPrice != null && p.regularPrice > p.salePrice ? Number(p.regularPrice) : sale;
                    if (p.hasVariants && p.variants) {
                        const vals = Object.values(p.variants).map((v) => Number(v.salePrice)).filter((n) => !Number.isNaN(n) && n > 0);
                        if (vals.length) sale = Math.min(...vals);
                        const regs = Object.values(p.variants)
                            .map((v) => (v.regularPrice != null && v.regularPrice > v.salePrice ? Number(v.regularPrice) : Number(v.salePrice)))
                            .filter((n) => !Number.isNaN(n) && n > 0);
                        if (regs.length) reg = Math.max(...regs);
                    }
                    if (Number.isNaN(sale)) sale = 0;
                    if (Number.isNaN(reg)) reg = sale;
                    return { sale, reg };
                };
                if (productDetailLayout === 'mobileCommerceV1') {
                    const rowsMc = upsellProducts.map((p) => {
                        const { sale: displayPrice } = upsellPricePair(p);
                        const pid = escAttr(p.id);
                        return `
                        <div class="mobile-commerce-fbt-card">
                            <a href="#/product/${pid}" class="block"><img src="${escAttr(p.imageUrl || '')}" alt="" class="w-full h-16 object-contain rounded" loading="lazy"></a>
                            <a href="#/product/${pid}" class="block text-[11px] font-bold leading-tight mt-1 line-clamp-3 hover:underline" style="color: var(--text-primary);">${esc(p.name || '')}</a>
                            <p class="text-xs font-extrabold mt-1" style="color: var(--price-text);">${formatPrice(displayPrice)}</p>
                            <input type="checkbox" class="upsell-checkbox fbt-card-check" checked data-product-id="${pid}">
                        </div>`;
                    }).join('');
                    bundleContainer.innerHTML = `
                    <div class="mobile-commerce-fbt max-md:mb-2">
                        <h4>Frequently bought together</h4>
                        <div class="mobile-commerce-fbt-grid">${rowsMc}</div>
                        <div class="mobile-commerce-fbt-footer">
                            <div>
                                <div class="fbt-total-line"></div>
                                <div class="fbt-save-line"></div>
                            </div>
                            <button type="button" class="fbt-add-bundle-btn">Add to cart</button>
                        </div>
                    </div>`;
                    refreshDetailFbtBundleUi = () => {
                        const root = bundleContainer.querySelector('.mobile-commerce-fbt');
                        if (!root) return;
                        let mainSale = Number(product.salePrice);
                        let mainReg = product.regularPrice != null && product.regularPrice > product.salePrice ? Number(product.regularPrice) : mainSale;
                        if (product.hasVariants && selectedVariantId && product.variants[selectedVariantId]) {
                            const v = product.variants[selectedVariantId];
                            mainSale = Number(v.salePrice);
                            mainReg = v.regularPrice != null && v.regularPrice > v.salePrice ? Number(v.regularPrice) : mainSale;
                        }
                        if (Number.isNaN(mainSale)) mainSale = 0;
                        if (Number.isNaN(mainReg)) mainReg = mainSale;
                        let total = mainSale * currentQty;
                        let regTotal = mainReg * currentQty;
                        const checks = bundleContainer.querySelectorAll('.upsell-checkbox:checked');
                        checks.forEach((el) => {
                            const pid = el.getAttribute('data-product-id');
                            const up = state.allProducts.find((x) => String(x.id) === String(pid));
                            if (!up || String(up.id) === String(product.id)) return;
                            const { sale, reg } = upsellPricePair(up);
                            total += sale;
                            regTotal += reg;
                        });
                        const totalEl = root.querySelector('.fbt-total-line');
                        const saveEl = root.querySelector('.fbt-save-line');
                        const btn = root.querySelector('.fbt-add-bundle-btn');
                        if (totalEl) totalEl.textContent = formatPrice(total);
                        const saveAmt = Math.max(0, regTotal - total);
                        if (saveEl) {
                            saveEl.textContent = saveAmt > 0 ? `Save ${formatPrice(saveAmt)}` : '';
                            saveEl.style.display = saveAmt > 0 ? 'block' : 'none';
                        }
                        const n = 1 + checks.length;
                        if (btn) btn.textContent = `Add ${n} item${n === 1 ? '' : 's'} to cart`;
                    };
                    if (!bundleContainer.dataset.fbtDeleg) {
                        bundleContainer.dataset.fbtDeleg = '1';
                        bundleContainer.addEventListener('change', (e) => {
                            const t = e.target;
                            if (!t || !t.classList || !t.classList.contains('upsell-checkbox')) return;
                            const fn = bundleContainer._fbtRefreshFn;
                            if (typeof fn === 'function') fn();
                        });
                        bundleContainer.addEventListener('click', (e) => {
                            if (!e.target.closest('.fbt-add-bundle-btn')) return;
                            const fn = bundleContainer._fbtAddFn;
                            if (typeof fn === 'function') fn();
                        });
                    }
                    bundleContainer._fbtRefreshFn = refreshDetailFbtBundleUi;
                    bundleContainer._fbtAddFn = () => addToCartWithQty(false);
                    refreshDetailFbtBundleUi();
                } else {
                    refreshDetailFbtBundleUi = null;
                    bundleContainer._fbtRefreshFn = null;
                    bundleContainer._fbtAddFn = null;
                    const rows = upsellProducts.map((p) => {
                        const cat = (p.categories && p.categories[0]) || p.category || '';
                        let displayPrice = Number(p.salePrice);
                        if (p.hasVariants && p.variants) {
                            const vals = Object.values(p.variants).map((v) => Number(v.salePrice)).filter((n) => !Number.isNaN(n) && n > 0);
                            if (vals.length) displayPrice = Math.min(...vals);
                        }
                        if (Number.isNaN(displayPrice)) displayPrice = 0;
                        const pid = escAttr(p.id);
                        return `
                    <div class="flex items-start gap-3 p-2.5 rounded-xl border transition hover:shadow-sm" style="border-color: var(--card-border); background: var(--card-bg);">
                        <input type="checkbox" class="upsell-checkbox mt-1.5 h-4 w-4 rounded border-gray-300 flex-shrink-0 accent-indigo-600" data-product-id="${pid}">
                        <div class="flex gap-3 flex-1 min-w-0">
                            <a href="#/product/${pid}" class="flex-shrink-0"><img src="${escAttr(p.imageUrl || '')}" alt="" class="w-14 h-14 object-contain rounded-lg border bg-white" loading="lazy"></a>
                            <div class="min-w-0 flex-1">
                                <a href="#/product/${pid}" class="text-sm font-bold leading-tight block hover:underline" style="color: var(--text-primary);">${esc(p.name || '')}</a>
                                <p class="text-xs mt-0.5 truncate" style="color: var(--text-secondary);">${esc(cat)}</p>
                                <p class="text-sm font-extrabold mt-1" style="color: var(--price-text);">${formatPrice(displayPrice)}</p>
                            </div>
                        </div>
                    </div>`;
                    }).join('');
                    bundleContainer.innerHTML = `
                <div class="rounded-xl border p-4 shadow-sm max-md:mb-2" style="border-color: var(--card-border); background: linear-gradient(180deg, var(--card-bg) 0%, rgba(99,102,241,0.06) 100%);">
                    <h4 class="font-bold text-sm mb-1 flex items-center gap-2" style="color: var(--text-primary);">
                        <i class="fa-solid fa-heart text-rose-500"></i> Products you may love
                    </h4>
                    <p class="text-xs mb-3" style="color: var(--text-secondary);">Tick any item to add it with your order (qty 1 each), then use <strong>Add to cart</strong> or <strong>Buy now</strong>.</p>
                    <div class="space-y-2 max-h-64 overflow-y-auto pr-1">${rows}</div>
                </div>`;
                }
            }
        }
    }

    // Related products: shared category or subcategory (align with script-default.js)
    const productCats = product.categories || (product.category ? [product.category] : []);
    const productSubcats = product.subcategories || (product.subcategory ? [product.subcategory] : []);
    const related = state.allProducts
        .filter(
            (p) =>
                p.id !== product.id &&
                (productCats.some((c) => productInCategory(p, c)) || productSubcats.some((s) => productInSubcategory(p, s)))
        )
        .slice(0, 5);
    if (doc.relatedContainer) { applyProductGridToElement(doc.relatedContainer); doc.relatedContainer.innerHTML = related.map((p, i) => getProductCard(p, false, { gridIndex: i })).join(''); }
    
    if(doc.fomoContainer) {
        doc.fomoContainer.classList.remove('hidden');
        const rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
        let phase = 0;
        const messages = [
            { text: `👁️ ${rand(18, 45)} people are viewing this right now`, isFire: false, showBar: false },
            { text: `🔥 ${rand(8, 25)} sold in last ${rand(2, 6)} hours`, isFire: true, showBar: false },
            { text: `⚡ Hurry! Only ${rand(3, 9)} items left in stock`, isFire: true, showBar: true }
        ];

        const updateFomo = () => {
            if (!doc.fomoText) return;
            doc.fomoText.style.opacity = '0';
            doc.fomoText.style.transition = 'opacity 0.5s ease';
            setTimeout(() => {
                const msg = messages[phase];
                doc.fomoText.innerHTML = msg.text;
                if(msg.isFire) doc.fomoText.classList.add('fire-text');
                else doc.fomoText.classList.remove('fire-text');
                if(msg.showBar) {
                    if(doc.fomoBar) {
                        doc.fomoBar.parentElement.style.display = 'block';
                        doc.fomoBar.style.width = '100%';
                        setTimeout(() => doc.fomoBar.style.width = `${rand(15, 40)}%`, 50);
                    }
                } else {
                    if(doc.fomoBar) doc.fomoBar.parentElement.style.display = 'none';
                }
                doc.fomoText.style.opacity = '1';
                phase = (phase + 1) % messages.length;
            }, 500);
        };
        updateFomo();
        fomoInterval = setInterval(updateFomo, 4500);
    }
    // --- Ensure info column (title, price, description, buttons) always visible below image ---
    const detailViewEl = getEl('product-detail-view');
    if (detailViewEl) detailViewEl.classList.remove('hidden');
    const infoCol = getEl('product-detail-info-column');
    if (infoCol) {
        infoCol.style.display = 'flex';
        infoCol.style.visibility = 'visible';
        infoCol.classList.remove('hidden');
    }
    const descEl = getEl('detail-description');
    if (descEl) { descEl.style.display = ''; descEl.style.visibility = ''; }
    const ctaBarVis = getEl('detail-cta-bar');
    if (ctaBarVis) {
        ctaBarVis.querySelectorAll('button').forEach((btn) => {
            btn.classList.remove('hidden'); btn.style.display = ''; btn.style.visibility = '';
        });
        const capVis = ctaBarVis.querySelector('#detail-cta-caption');
        if (capVis) { capVis.classList.remove('hidden'); capVis.style.display = ''; capVis.style.visibility = ''; }
    }
    ['btn-call-now', 'btn-whatsapp', 'btn-messenger'].forEach((id) => {
        const btn = getEl(id);
        if (!btn) return;
        if ((productDetailLayout === 'mobileCommerceV1' || productDetailLayout === 'mobileCommerceV2') && id === 'btn-messenger') {
            btn.classList.add('hidden');
            btn.style.display = 'none';
            return;
        }
        btn.classList.remove('hidden');
        btn.style.display = '';
        btn.style.visibility = '';
    });
    trackPixelEvent('ViewContent', { content_name: product.name, content_ids: [product.id], value: product.salePrice, currency: 'BDT' });
};

// ============================================================
// 8. CHECKOUT LOGIC
// ============================================================

const initCheckoutPage = () => {
    applyCheckoutAddressMode(state.siteSettings);
    renderShippingOptions();
    updateOrderSummary();
    if(doc.inputName) doc.inputName.addEventListener('input', (e) => captureLiveInput('name', e.target.value));
    if(doc.inputPhone) doc.inputPhone.addEventListener('input', (e) => captureLiveInput('phone', e.target.value));
    if(doc.inputAddress) doc.inputAddress.addEventListener('input', (e) => captureLiveInput('address', e.target.value));
    
    const subtotal = state.cartItems.reduce((s, i) => s + (i.price * i.quantity), 0);
    pushToDataLayer('begin_checkout', { currency: "BDT", value: subtotal, items: state.cartItems.map(i => ({ item_id: i.id, item_name: i.name, price: i.price, quantity: i.quantity, item_variant: i.variantName || null })) });
    trackPixelEvent('InitiateCheckout', { value: subtotal, currency: 'BDT', content_ids: state.cartItems.map(i => i.id), num_items: state.cartItems.length });
};

const renderShippingOptions = () => {
    if (!doc.shippingContainer) return;
    const options = state.siteSettings.shippingOptions || [{ label: 'Inside Dhaka', cost: 70 }, { label: 'Outside Dhaka', cost: 130 }];
    doc.shippingContainer.innerHTML = options.map((opt, index) => `
        <label class="shipping-option ${index === 0 ? 'active' : ''}">
            <input type="radio" name="shipping" value="${opt.cost}" data-label="${opt.label}" class="hidden" ${index === 0 ? 'checked' : ''}>
            <div class="flex items-center gap-3"><i class="fa-solid fa-truck text-gray-400"></i><span class="font-medium text-gray-700">${opt.label}</span></div>
            <div class="flex items-center gap-2"><span class="font-bold text-gray-900">৳${opt.cost}</span><span class="checkmark"><i class="fa-solid fa-circle-check"></i></span></div>
        </label>`).join('');
    
    doc.shippingContainer.querySelectorAll('.shipping-option').forEach(option => {
        option.addEventListener('click', function() {
            doc.shippingContainer.querySelectorAll('.shipping-option').forEach(el => el.classList.remove('active')); this.classList.add('active');
            this.querySelector('input').checked = true; updateOrderSummary();
        });
    });
};

const updateOrderSummary = () => {
    if (!doc.orderSummary) return;
    const subtotal = state.cartItems.reduce((sum, item) => sum + (item.price * item.quantity), 0);
    const shippingInput = document.querySelector('input[name="shipping"]:checked');
    const baseShipping = shippingInput ? Number(shippingInput.value) : 0;
    const threshold = Number(state.siteSettings?.freeShippingThreshold) || 0;
    const freeShipping = threshold > 0 && subtotal >= threshold;
    const shippingCost = freeShipping ? 0 : baseShipping;
    const total = subtotal + shippingCost;

    const itemsHtml = state.cartItems.map(item => {
        const id = item.variantId ? `${item.id}_${item.variantId}` : item.id;
        return `
        <div class="flex gap-3 py-3 border-b last:border-0 border-gray-100">
            <div class="relative w-14 h-14 flex-shrink-0"><img src="${item.image}" class="w-full h-full object-cover rounded border" loading="lazy" decoding="async"></div>
            <div class="flex-grow"><p class="text-sm font-medium line-clamp-2">${item.name}</p>${item.variantName ? `<p class="text-xs text-gray-500">${item.variantName}</p>` : ''}<div class="flex items-center mt-2"><div class="flex items-center border border-gray-300 rounded h-6"><button class="decrease-qty-btn w-6 h-full flex items-center justify-center hover:bg-gray-100 text-gray-600" data-id="${id}"><i class="fa-solid fa-minus text-[10px]"></i></button><span class="px-2 text-xs font-bold text-gray-800 border-l border-r border-gray-300">${item.quantity}</span><button class="increase-qty-btn w-6 h-full flex items-center justify-center hover:bg-gray-100 text-gray-600" data-id="${id}"><i class="fa-solid fa-plus text-[10px]"></i></button></div></div></div>
            <div class="flex flex-col justify-between items-end"><p class="text-sm font-bold">${formatPrice(item.price * item.quantity)}</p><button class="remove-from-cart-btn text-red-500 text-xs hover:underline" data-id="${id}">Remove</button></div>
        </div>`}).join('');

    const freeNote = freeShipping && threshold > 0
        ? `<p class="text-xs text-emerald-700 font-medium mb-2"><i class="fa-solid fa-truck-fast mr-1"></i>Free shipping applied (orders ${formatPrice(threshold)}+)</p>`
        : '';

    doc.orderSummary.innerHTML = `
        <h3 class="font-bold text-lg mb-4 text-gray-800">Your Order</h3><div class="mb-4 max-h-[300px] overflow-y-auto pr-1 custom-scrollbar">${itemsHtml}</div>
        <div class="space-y-3 pt-4 border-t border-dashed border-gray-300">
            ${freeNote}
            <div class="flex justify-between text-gray-600"><span>Subtotal</span><span>${formatPrice(subtotal)}</span></div>
            <div class="flex justify-between text-gray-600"><span>Shipping Cost</span><span>${freeShipping ? '<span class="text-emerald-700 font-bold">FREE</span>' : formatPrice(shippingCost)}</span></div>
            <div class="flex justify-between text-xl font-bold text-gray-900 pt-2 border-t"><span>Total</span><span style="color: var(--accent-color);">${formatPrice(total)}</span></div>
        </div>
        <button type="submit" form="checkout-form" class="checkout-submit-btn w-full text-white font-bold py-3.5 px-4 rounded-lg mt-6 hidden lg:flex justify-center items-center gap-2 transition shadow-lg" style="background-color: var(--btn-primary-bg);"><span>Confirm Order</span><i class="fa-solid fa-spinner fa-spin button-spinner hidden"></i></button>`;
    if(doc.mobileCheckoutTotal) doc.mobileCheckoutTotal.textContent = formatPrice(total);
};

// ============================================================
// 9. ROUTING & INIT (FIXED EVENT DELEGATION)
// ============================================================

const isReplayMode = () => { try { const p = new URLSearchParams(window.location.search); return p.get('replay') === '1'; } catch (e) { return false; } };

const handleRoute = () => {
    const hash = window.location.hash;
    hideCategorySubnav();
    try {
        if (window.parent && window.parent !== window) {
            window.parent.postMessage({ type: 'routeChange', hash: hash }, "*");
        }
    } catch (e) { }

    if (fomoInterval) { clearInterval(fomoInterval); fomoInterval = null; }
    const routeIsHome = hash === '#/shop' || hash === '';
    if (!routeIsHome) cancelDeferredHomeHydration();
    // Header menu (sections vs categories) – always sync with current state so admin change reflects after refresh/cache update
    renderDesktopMenu();

    const forceOverlayClose = hash === '#/checkout' || hash.startsWith('#/product/') || hash === '#/shop' || hash === '';
    normalizeOverlayState('handle_route_entry', { forceClose: forceOverlayClose });

    // Hide all views explicitly
    hideAllViews();
    
    if(doc.searchOverlay) doc.searchOverlay.classList.add('hidden');
    window.scrollTo(0,0);

    const toggleHomeElements = (show) => {
        const catalogWait = show && isClassicHomeCatalogWaiting();
        if (show) applyHomeHeroVisibility();
        else {
            if (doc.pcHeroSection) doc.pcHeroSection.classList.add('hidden');
            if (doc.mobileHeroSection) doc.mobileHeroSection.classList.add('hidden');
        }
        const homeChromeOk = show && !catalogWait;
        if(doc.catRowsContainer) homeChromeOk ? doc.catRowsContainer.classList.remove('hidden') : doc.catRowsContainer.classList.add('hidden');
        const vis = { mainSlider: true, smallBanners: true, promoBanner1: true, promoBanner2: true, ...(state.siteSettings?.bannerVisibility || {}) };
        const settings = state.siteSettings || {};
        if (shouldUseLeanAboveFoldMode(settings)) {
            vis.smallBanners = false;
            vis.promoBanner1 = false;
            vis.promoBanner2 = false;
        }
        const smallBannersArr = (settings.smallBanners && settings.smallBanners.length === 3) ? settings.smallBanners : [];
        const hasSmallBannersUrl = smallBannersArr.some(u => (u || '').trim());
        const promo1Url = (settings.promoBanner1Url || '').trim();
        const promo2Url = (settings.promoBanner2Url || '').trim();
        if(doc.pcSliderArea) (homeChromeOk && vis.mainSlider) ? doc.pcSliderArea.classList.remove('hidden') : doc.pcSliderArea.classList.add('hidden');
        if(doc.mobileSliderArea) (homeChromeOk && vis.mainSlider) ? doc.mobileSliderArea.classList.remove('hidden') : doc.mobileSliderArea.classList.add('hidden');
        if(doc.pcSmallBanners) (homeChromeOk && vis.smallBanners && hasSmallBannersUrl) ? doc.pcSmallBanners.classList.remove('hidden') : doc.pcSmallBanners.classList.add('hidden');
        if(doc.mobileSmallBanners) (homeChromeOk && vis.smallBanners && hasSmallBannersUrl) ? doc.mobileSmallBanners.classList.remove('hidden') : doc.mobileSmallBanners.classList.add('hidden');
        if(doc.promoBanner1) (homeChromeOk && vis.promoBanner1 && promo1Url) ? doc.promoBanner1.classList.remove('hidden') : doc.promoBanner1.classList.add('hidden');
        if(doc.promoBanner2) (homeChromeOk && vis.promoBanner2 && promo2Url) ? doc.promoBanner2.classList.remove('hidden') : doc.promoBanner2.classList.add('hidden');
        if (doc.homeAnnouncementStrip && !show) doc.homeAnnouncementStrip.classList.add('hidden');
        if (doc.homeAnnouncementStripMobile && !show) doc.homeAnnouncementStripMobile.classList.add('hidden');
        if (doc.homeNewArrivalBandMobile && !show) doc.homeNewArrivalBandMobile.classList.add('hidden');
        if (doc.homeNewArrivalCategoryGridMobile && !show) doc.homeNewArrivalCategoryGridMobile.classList.add('hidden');
        if (doc.homeFabrilifePostGridBanners && !show) doc.homeFabrilifePostGridBanners.classList.add('hidden');
        if (doc.homepageFeaturesSectionMobile && !show) doc.homepageFeaturesSectionMobile.classList.add('hidden');
        if (doc.homepageFeaturesSectionDesktop && !show) doc.homepageFeaturesSectionDesktop.classList.add('hidden');
        if (doc.recommendedForYouSectionMobile && !show) doc.recommendedForYouSectionMobile.classList.add('hidden');
        if (doc.recommendedForYouSectionDesktop && !show) doc.recommendedForYouSectionDesktop.classList.add('hidden');
        if (!show) destroyRecommendedForYouSwipers();
        if (doc.categoryBannerSectionMobile && !show) doc.categoryBannerSectionMobile.classList.add('hidden');
        if (doc.categoryBannerSectionDesktop && !show) doc.categoryBannerSectionDesktop.classList.add('hidden');
        if (!show) destroyCategoryBannerSwipers();
        if(doc.justForYouSection) homeChromeOk ? doc.justForYouSection.classList.remove('hidden') : doc.justForYouSection.classList.add('hidden');
    };

    const hideBottomNav = hash === '#/checkout' || hash.startsWith('#/product/');
    if (doc.bottomNav) { doc.bottomNav.style.transform = hideBottomNav ? 'translateY(100%)' : 'translateY(0)'; }
    if (doc.mobileCheckoutBar) { (hash === '#/checkout') ? doc.mobileCheckoutBar.classList.remove('translate-y-full') : doc.mobileCheckoutBar.classList.add('translate-y-full'); }

    if (hash.startsWith('#/product/')) {
        const productId = (hash.replace(/^#\/product\//, '').split('?')[0] || '').trim();
        const routedProduct = productId ? state.allProducts.find(p => String(p.id) === String(productId)) : null;
        const routedLanding = routedProduct && getLandingPageUrlForProduct(routedProduct);
        if (routedLanding) {
            window.location.href = routedLanding;
            return;
        }
        if(doc.detailView) doc.detailView.classList.remove('hidden');
        toggleHomeElements(false);
        renderDetailView(productId);
    } else if (hash.startsWith('#/category/')) {
        const catSlug = (hash.replace(/^#\/category\//, '').split('?')[0] || '').trim();
        const catName = decodeURIComponent(catSlug);
        if(doc.categoryView) {
            doc.categoryView.classList.remove('hidden');
            renderCategoryView(catName);
        } else {
            if(doc.homeView) doc.homeView.classList.remove('hidden');
            toggleHomeElements(false);
            updateCategorySubnav(catName);
            const subParam = new URLSearchParams(hash.split('?')[1] || '').get('sub');
            const selectedSub = subParam ? decodeURIComponent(subParam) : '';
            let filtered = state.allProducts.filter(p => productInCategory(p, catName));
            if (selectedSub) filtered = filtered.filter((p) => productInSubcategory(p, selectedSub));
            const grid = getEl('main-product-grid');
            if(grid) {
                applyProductGridToElement(grid);
                grid.innerHTML = filtered.length ? filtered.map((p, i) => getProductCard(p, false, { gridIndex: i })).join('') : '<p class="col-span-full text-center py-10">No products found.</p>';
                const titleEl = grid.previousElementSibling; if(titleEl) titleEl.querySelector('.section-title').textContent = selectedSub ? `${catName} / ${selectedSub}` : catName;
            }
        }
    } else if (hash === '#/categories') {
        toggleHomeElements(false);
        if (doc.categoryView) {
            doc.categoryView.classList.remove('hidden');
            renderAllCategoriesPage();
        } else {
            window.location.hash = '#/shop';
        }
    } else if (hash === '#/featured') {
        // --- FEATURED PRODUCTS ROUTE ---
        if(doc.categoryView) {
            doc.categoryView.classList.remove('hidden');
            resetCategoryListingChrome();
            if (doc.catHeaderTitle) doc.catHeaderTitle.textContent = "Featured Products";
            if (doc.catBreadcrumb) doc.catBreadcrumb.textContent = "Featured";
            let featured = state.allProducts.filter(p => !p.hasVariants && p.regularPrice > p.salePrice);
            if (currentCategorySort === 'low-high') featured.sort((a, b) => a.salePrice - b.salePrice);
            else if (currentCategorySort === 'high-low') featured.sort((a, b) => b.salePrice - a.salePrice);
            else if (currentCategorySort === 'a-z') featured.sort((a, b) => a.name.localeCompare(b.name));
            else if (currentCategorySort === 'z-a') featured.sort((a, b) => b.name.localeCompare(a.name));
            if (doc.catCount) doc.catCount.textContent = `${featured.length} items found`;
            if (doc.categoryGrid) {
                applyProductGridToElement(doc.categoryGrid);
                if (featured.length === 0) {
                    doc.categoryGrid.innerHTML = `<div class="col-span-full flex flex-col items-center justify-center py-20 text-gray-400"><i class="fa-solid fa-star text-6xl mb-4"></i><p class="text-lg font-bold">No featured products right now</p><button onclick="window.location.hash='#/shop'" class="mt-4 px-6 py-2 bg-gray-800 text-white rounded hover:bg-black transition">Back to Shop</button></div>`;
                } else {
                    doc.categoryGrid.innerHTML = featured.map((p, i) => getProductCard(p, false, { gridIndex: i })).join('');
                }
            }
            if(doc.catSidebar) doc.catSidebar.innerHTML = '<p class="text-sm text-gray-500">Handpicked items with special discounts.</p>';
        }
    } else if (hash.startsWith('#/search/')) {
        const query = decodeURIComponent(hash.replace(/^#\/search\//, ''));
        const fullHash = window.location.hash;
        if (fullHash !== lastClassicSearchHashForPixel && query) {
            lastClassicSearchHashForPixel = fullHash;
            try {
                trackPixelEvent('Search', { search_string: query });
            } catch (_) { /* noop */ }
        }
        if(doc.homeView) doc.homeView.classList.remove('hidden');
        toggleHomeElements(false);
        if(doc.mainProductGrid) doc.mainProductGrid.parentElement.classList.remove('hidden');
        const results = state.allProducts.filter(p => p.name.toLowerCase().includes(query.toLowerCase()) || (p.categories && p.categories.some(c => c.toLowerCase().includes(query.toLowerCase()))) || (p.category && p.category.toLowerCase().includes(query.toLowerCase())));
        const grid = getEl('main-product-grid');
        applyProductGridToElement(grid);
        const titleEl = grid.previousElementSibling; if(titleEl) titleEl.querySelector('.section-title').innerHTML = `Search Results: <span style="color: var(--accent-color); font-weight: bold;">"${query}"</span> (${results.length})`;
        grid.innerHTML = results.length > 0 ? results.map((p, i) => getProductCard(p, false, { gridIndex: i })).join('') : '<div class="col-span-full text-center py-20"><i class="fa-solid fa-magnifying-glass text-4xl text-gray-300 mb-4"></i><p class="text-gray-500 font-bold">No products found for "' + query + '"</p><button onclick="window.location.hash=\'#/shop\'" class="mt-4 px-6 py-2 text-white rounded font-bold transition" style="background-color: var(--btn-secondary-bg);">Back to Shop</button></div>';
    } else if (hash === '#/wishlist') {
        if(doc.categoryView) {
            doc.categoryView.classList.remove('hidden');
            renderWishlistPage();
        } else {
            window.location.hash = '#/shop';
        }
    } else if (hash === '#/profile') {
        if(doc.profileView) {
            doc.profileView.classList.remove('hidden');
            renderProfileView();
        }
    } else if (hash.startsWith('#/policy/') || hash.startsWith('#/page/')) {
        // --- NEW: UNIFIED CONTENT PAGE ROUTE ---
        const type = (hash.match(/#\/policy\/(.+)/) || hash.match(/#\/page\/(.+)/))?.[1] || '';
        if(doc.policyView) {
            doc.policyView.classList.remove('hidden');
            toggleHomeElements(false); // Double ensure home elements are gone
            renderContentPage(type);
        }
    } else if (hash === '#/checkout') {
        const emptyCart = state.cartItems.length === 0;
        logBuyNowDebug('route_checkout_enter', {
            emptyCart,
            cartCount: state.cartItems.length,
            isReplayMode: isReplayMode(),
            currentClientId: getCurrentClientId(),
            clientContext: getClientContextDebug(),
            freezeSnapshot: getFreezeBlockerSnapshot()
        });
        if (!isReplayMode() && emptyCart) {
            logBuyNowDebug('route_checkout_redirected_to_shop', {
                reason: 'empty_cart_guard',
                cartCount: state.cartItems.length
            });
            return window.location.hash = '#/shop';
        }
        if(doc.checkoutView) doc.checkoutView.classList.remove('hidden');
        toggleHomeElements(false);
        initCheckoutPage();
    } else if (hash === '#/thank-you') {
        if(doc.thankYouView) doc.thankYouView.classList.remove('hidden');
        updateProfileActivity('order');
        toggleHomeElements(false);
    } else {
        if(doc.homeView) doc.homeView.classList.remove('hidden');
        toggleHomeElements(true);
        const grid = getEl('main-product-grid');
        const titleEl = grid.previousElementSibling; if(titleEl) titleEl.querySelector('.section-title').textContent = "Just For You";
        renderHome();
    }
    renderMobileHeroCategoryBar();
};

/** FB in-app browser: programmatic #/checkout may not fire hashchange (?fbclid=...) — force SPA sync */
const scheduleClassicRouteSync = () => {
    setTimeout(() => {
        try {
            handleRoute();
        } catch (e) {
            console.warn('[scheduleClassicRouteSync]', e);
        }
    }, 0);
};
if (typeof window !== 'undefined') {
    window.sbClassicSyncRouteAfterHash = scheduleClassicRouteSync;
}

const enableImageZoom = () => {
    const container = doc.zoomContainer; const img = doc.detailMainImg; if (!container || !img) return;
    container.addEventListener('mousemove', (e) => { if (window.matchMedia("(hover: hover)").matches) { const rect = container.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; img.style.transformOrigin = `${(x/rect.width)*100}% ${(y/rect.height)*100}%`; img.style.transform = 'scale(2)'; } });
    container.addEventListener('mouseleave', () => { img.style.transform = 'scale(1)'; setTimeout(() => { img.style.transformOrigin = 'center center'; }, 100); });
    container.addEventListener('touchmove', (e) => { if (e.touches.length === 1) { e.preventDefault(); const rect = container.getBoundingClientRect(); const touch = e.touches[0]; const x = touch.clientX - rect.left; const y = touch.clientY - rect.top; if (x >= 0 && x <= rect.width && y >= 0 && y <= rect.height) { img.style.transformOrigin = `${(x/rect.width)*100}% ${(y/rect.height)*100}%`; img.style.transform = 'scale(2)'; } } }, { passive: false });
    container.addEventListener('touchend', () => { img.style.transform = 'scale(1)'; setTimeout(() => { img.style.transformOrigin = 'center center'; }, 100); });
};

const init = async () => {
    document.addEventListener('cartUpdated', (e) => { renderAdvancedCartDrawer(e.detail.items, e.detail.total); updateShwapnoCardActions(); });
    initDOM();
    applyProductIdQueryParamAsHash();
    // Overlay thakbe jotokhon na data load + renderHome/handleRoute complete – niche hide hobe
    updateHeaderBadges(); 
    enableImageZoom();
    initLocationService();
    initDarkMode();
    
    // Dropdown init (Call here for listeners, but populate after data)
    initPCDropdown();
    bindCategoryFacetListeners();

    if(doc.closeSizeChartBtn) doc.closeSizeChartBtn.onclick = () => doc.sizeChartModal.classList.add('hidden');
    if(doc.sizeChartModal) doc.sizeChartModal.onclick = (e) => { if(e.target === doc.sizeChartModal) doc.sizeChartModal.classList.add('hidden'); }

    const onCategorySortChange = (e) => {
        currentCategorySort = e.target.value;
        syncCategorySortSelects(currentCategorySort);
        const hash = window.location.hash;
        if (hash.startsWith('#/category/')) {
            const catSlug = (hash.replace(/^#\/category\//, '').split('?')[0] || '').trim();
            renderCategoryView(decodeURIComponent(catSlug));
        } else if (hash === '#/featured' && doc.categoryView && !doc.categoryView.classList.contains('hidden') && doc.categoryGrid) {
            let featured = state.allProducts.filter((p) => !p.hasVariants && p.regularPrice > p.salePrice);
            if (currentCategorySort === 'low-high') featured.sort((a, b) => a.salePrice - b.salePrice);
            else if (currentCategorySort === 'high-low') featured.sort((a, b) => b.salePrice - a.salePrice);
            else if (currentCategorySort === 'a-z') featured.sort((a, b) => a.name.localeCompare(b.name));
            else if (currentCategorySort === 'z-a') featured.sort((a, b) => b.name.localeCompare(a.name));
            else featured.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
            if (doc.catCount) doc.catCount.textContent = `${featured.length} items found`;
            applyProductGridToElement(doc.categoryGrid);
            if (featured.length === 0) {
                doc.categoryGrid.innerHTML = `<div class="col-span-full flex flex-col items-center justify-center py-20 text-gray-400"><i class="fa-solid fa-star text-6xl mb-4"></i><p class="text-lg font-bold">No featured products right now</p><button onclick="window.location.hash='#/shop'" class="mt-4 px-6 py-2 bg-gray-800 text-white rounded hover:bg-black transition">Back to Shop</button></div>`;
            } else {
                doc.categoryGrid.innerHTML = featured.map((p, i) => getProductCard(p, false, { gridIndex: i })).join('');
            }
        }
    };
    if (doc.catSortSelect) doc.catSortSelect.addEventListener('change', onCategorySortChange);
    if (doc.catSortSelectMobile) doc.catSortSelectMobile.addEventListener('change', onCategorySortChange);

    if (doc.categoryFilterOpenBtn) {
        doc.categoryFilterOpenBtn.addEventListener('click', () => openCategoryFilterSheet());
    }
    if (doc.categoryFilterSheetBackdrop) {
        doc.categoryFilterSheetBackdrop.addEventListener('click', () => closeCategoryFilterSheet());
    }
    if (doc.categoryFilterSheetClose) {
        doc.categoryFilterSheetClose.addEventListener('click', () => closeCategoryFilterSheet());
    }
    syncCategorySortSelects(currentCategorySort);

    // Top Bar Link Actions
    if(doc.linkAbout) doc.linkAbout.onclick = (e) => { e.preventDefault(); window.location.hash = '#/page/about'; };
    if(doc.linkContact) doc.linkContact.onclick = (e) => { e.preventDefault(); window.location.hash = '#/page/contact'; };
    if(doc.linkFaq) doc.linkFaq.onclick = (e) => { e.preventDefault(); showToast("FAQ section coming soon", "info"); };

    if(doc.scrollTopBtn) {
        window.addEventListener('scroll', () => {
            if (window.scrollY > 300) {
                doc.scrollTopBtn.classList.add('show-scroll-btn');
            } else {
                doc.scrollTopBtn.classList.remove('show-scroll-btn');
            }
        }, { passive: true });
        doc.scrollTopBtn.addEventListener('click', () => {
            window.scrollTo({ top: 0, behavior: 'smooth' });
        });
    }

    if(doc.closeSearchBtn && doc.searchOverlay) {
        doc.closeSearchBtn.addEventListener('click', () => {
            doc.searchOverlay.classList.add('hidden');
        });
    }
    
    const openSearchOverlay = (e) => {
        if (e) e.preventDefault();
        if (doc.searchOverlay) {
            doc.searchOverlay.classList.remove('hidden');
            if (doc.realSearchInput) doc.realSearchInput.focus();
        }
    };
    const footerSearchBtn = document.getElementById('footer-search-trigger');
    if (footerSearchBtn) footerSearchBtn.addEventListener('click', openSearchOverlay);
    const centerTradeSearchBtn = document.getElementById('center-trade-search-trigger');
    if (centerTradeSearchBtn) centerTradeSearchBtn.addEventListener('click', openSearchOverlay);

    // Register storeDataRefreshed BEFORE initCore so we never miss the event when cache exists and background fetch completes (fixes theme/button colors not updating)
    let classicStoreDataRefreshRaf = 0;
    document.addEventListener('storeDataRefreshed', () => {
        if (classicStoreDataRefreshRaf) cancelAnimationFrame(classicStoreDataRefreshRaf);
        classicStoreDataRefreshRaf = requestAnimationFrame(() => {
            classicStoreDataRefreshRaf = 0;
            try {
                if (!initialAtomicRenderCommitted && state.storeCatalogFetchStatus === 'loading') {
                    const hasProducts = Array.isArray(state.allProducts) && state.allProducts.length > 0;
                    if (!hasProducts) return;
                }
                if (doc.totalProductsCount) doc.totalProductsCount.textContent = (state.allProducts && state.allProducts.length) || 0;
                renderTrendingTags();
                renderDesktopMenu();
                applyThemeColors(state.siteSettings);
                applyProductGridConfig(state.siteSettings);
                applySectionDesigns(state.siteSettings);
                applyCategoryShapeFromSettings(state.siteSettings);
                if (state.siteSettings?.logoUrl) applyLogoSettings(state.siteSettings);
                applyCheckoutAddressMode(state.siteSettings);
                applyProductGridToElement(doc.mainProductGrid);
                applyProductGridToElement(doc.categoryGrid);
                applyProductGridToElement(doc.relatedContainer);
                const flashGrid = getEl('flash-products-container');
                if (flashGrid) applyProductGridToElement(flashGrid);
                handleRoute();
                ensureClassicLayoutDebugOverlay();
                tryDismissBootLoadingOverlay();
                syncClassicHomeAriaBusy();
            } catch (e) {
                console.error('storeDataRefreshed handler failed:', e);
            }
        });
    });

    // Fast first paint: hide overlay as soon as we have data, then critical path, then defer rest
    const data = await initCore({ bootMode: 'instantHome' });
    if (!data) {
        tryDismissBootLoadingOverlay({ force: true });
        showToast('স্টোর লোড হয়নি। পুনরায় চেষ্টা করুন।', 'error');
    } else {
        tryDismissBootLoadingOverlay();
        if (data.settings) {
            applyThemeColors(data.settings);
            applyProductGridConfig(data.settings);
            applySectionDesigns(data.settings);
            applyCategoryShapeFromSettings(data.settings);
            applyCheckoutAddressMode(data.settings);
        }
        handleRoute();
        initialAtomicRenderCommitted = true;
        syncClassicHomeAriaBusy();
        setTimeout(() => {
            try {
                if (data && data.settings) {
                    if (data.settings.logoUrl) applyLogoSettings(data.settings);
                    if (data.settings.gtmId) initGTM(data.settings.gtmId);
                    if (data.settings.contactInfo) {
                        if (getEl('footer-phone-display')) {
                            getEl('footer-phone-display').textContent = data.settings.contactInfo.phoneNumber;
                            getEl('footer-phone-display').parentElement.parentElement.onclick = () => window.location.hash = '#/page/contact';
                            getEl('footer-phone-display').parentElement.parentElement.classList.add('cursor-pointer', 'footer-contact-hover');
                        }
                        if (getEl('footer-address-display') && data.settings.contactInfo.address) {
                            getEl('footer-address-display').textContent = data.settings.contactInfo.address;
                            const addrParent = getEl('footer-address-display').closest('p');
                            if (addrParent) {
                                addrParent.onclick = () => window.location.hash = '#/page/contact';
                                addrParent.classList.add('cursor-pointer', 'footer-contact-hover', 'transition');
                            }
                        } else if (getEl('footer-address-display')) {
                            getEl('footer-address-display').textContent = "Address not set";
                        }
                        const waForFooter = normalizeWhatsAppNumber(data.settings.contactInfo.whatsappNumber);
                        if (waForFooter.length >= 10) document.querySelectorAll('.message-toggle, .fa-whatsapp').forEach(btn => { const anchor = btn.closest('a'); if (anchor) { anchor.href = `https://wa.me/${waForFooter}`; anchor.target = "_blank"; } });
                    }
                    if (data.settings.socialLinks) {
                        const socialMap = { facebook: 'social-link-fb', instagram: 'social-link-ig', youtube: 'social-link-yt', tiktok: 'social-link-tt' };
                        Object.entries(socialMap).forEach(([key, id]) => {
                            const el = getEl(id);
                            const link = String((data.settings.socialLinks[key]) || '').trim();
                            if (el) {
                                if (link !== "") { el.href = link; el.classList.remove('hidden'); }
                                else el.classList.add('hidden');
                            }
                        });
                    }
                    if (data.settings.textContent && getEl('footer-copyright-text')) getEl('footer-copyright-text').textContent = data.settings.textContent.copyright;
                }
                applyIconConfig();
                if (doc.totalProductsCount) doc.totalProductsCount.textContent = (state.allProducts && state.allProducts.length) || 0;
                renderTrendingTags();
                renderDesktopMenu();
                const menuCats = getMenuCategories();
                if (menuCats.length > 0 && doc.desktopCategoryDropdown) {
                    const escAttrMenu = (s) => String(s ?? '')
                        .replace(/&/g, '&amp;')
                        .replace(/"/g, '&quot;')
                        .replace(/</g, '&lt;')
                        .replace(/>/g, '&gt;');
                    doc.desktopCategoryDropdown.innerHTML = menuCats.map(cat => `
                        <div class="flex items-center gap-3 p-3 hover:bg-gray-50 cursor-pointer border-b last:border-0 transition"
                             onclick="window.location.hash='#/category/${cat.name}'; document.getElementById('desktop-category-dropdown').classList.add('hidden');">
                            <img src="${escAttrMenu(cat.iconUrl || cat.imageUrl)}" class="w-6 h-6 object-contain" loading="lazy" decoding="async">
                            <span class="text-sm font-medium text-gray-700">${cat.name}</span>
                        </div>
                    `).join('');
                }
            } catch (e) { console.error('Deferred init failed:', e); }
        }, 0);
    }
    window.addEventListener('hashchange', (e) => {
        normalizeOverlayState('hashchange', { forceClose: false });
        logBuyNowDebug('hash_change', {
            oldUrl: e.oldURL || null,
            newUrl: e.newURL || null,
            cartCount: state.cartItems.length,
            currentClientId: getCurrentClientId(),
            freezeSnapshot: getFreezeBlockerSnapshot()
        });
        handleRoute();
    });
    window.addEventListener('resize', () => {
        const h = window.location.hash;
        if (h === '#/shop' || h === '') applyHomeHeroVisibility();
    });
    
    const toggleMobileMenu = (show) => { 
        doc.overlay.style.display = show ? 'block' : 'none'; 
        if(show) doc.mobileDrawer.classList.add('open'); 
        else doc.mobileDrawer.classList.remove('open'); 
    };
    
    // RENDER MOBILE DRAWER CONTENT
    renderMobileDrawerContent(toggleMobileMenu);

    document.querySelectorAll('.mobile-menu-toggle').forEach(b => b.onclick = () => toggleMobileMenu(true));
    
    if(doc.allCategoriesBtn) doc.allCategoriesBtn.addEventListener('click', (e) => { 
        if (window.innerWidth < 768) { 
            toggleMobileMenu(true); 
        } 
    });

    const loginBtn = document.querySelector('a[href="#"].text-sm.font-bold'); if (loginBtn) loginBtn.addEventListener('click', (e) => { e.preventDefault(); showToast('User registration is currently disabled.', 'error'); });
    doc.overlay.onclick = () => { toggleMobileMenu(false); if(doc.cartDrawer) doc.cartDrawer.classList.remove('open'); };
    document.querySelectorAll('.close-drawer').forEach(b => { b.onclick = () => { toggleMobileMenu(false); if(doc.cartDrawer) doc.cartDrawer.classList.remove('open'); doc.overlay.style.display = 'none'; }; });
    const drawerCheckoutBtn = getEl('checkout-btn'); if(drawerCheckoutBtn) { drawerCheckoutBtn.onclick = () => { if(doc.cartDrawer) doc.cartDrawer.classList.remove('open'); doc.overlay.style.display = 'none'; normalizeOverlayState('drawer_checkout_click', { forceClose: true }); window.location.hash = '#/checkout'; scheduleClassicRouteSync(); }; }
    if(doc.checkoutForm) { doc.checkoutForm.addEventListener('submit', handleCheckoutSubmit); }
    
    const handleLiveSearch = (val, container) => { 
        if(val.length < 2) { 
            container.classList.add('hidden'); 
            if(doc.defaultSearchView) doc.defaultSearchView.classList.remove('hidden');
            return; 
        } 
        if(doc.defaultSearchView) doc.defaultSearchView.classList.add('hidden');
        const results = state.allProducts.filter(p => p.name.toLowerCase().includes(val.toLowerCase())).slice(0, 10); 
        container.classList.remove('hidden'); 
        container.innerHTML = results.length ? results.map(p => {
            const navUrl = getLandingPageUrlForProduct(p) || `#/product/${p.id}`;
            return `<div class="flex items-center gap-3 p-3 bg-white border rounded shadow-sm hover:shadow-md cursor-pointer transition" onclick="window.location.href=${JSON.stringify(navUrl)}; document.getElementById('full-screen-search-overlay').classList.add('hidden');"><img src="${p.imageUrl}" class="w-12 h-12 object-cover rounded border"><div class="flex-grow"><p class="font-bold text-sm text-gray-800 line-clamp-1">${p.name}</p><p class="text-xs font-bold text-green-600">${getPriceHtml(p, 'text-green-600 font-bold')}</p></div><i class="fa-solid fa-chevron-right text-gray-300 text-xs"></i></div>`;
        }).join('') : '<div class="p-4 text-sm text-gray-500 text-center font-medium bg-white rounded border">No products found for this query</div>'; 
    };

    const triggerSearch = (inputId) => { const val = getEl(inputId).value.trim(); if(val) { window.location.hash = `#/search/${encodeURIComponent(val)}`; if(doc.desktopSearchResults) doc.desktopSearchResults.classList.add('hidden'); if(doc.mobileSearchResults) doc.mobileSearchResults.classList.add('hidden'); if(doc.searchOverlay) doc.searchOverlay.classList.add('hidden'); } };
    
    if(doc.desktopSearchInput) { doc.desktopSearchInput.addEventListener('input', (e) => handleLiveSearch(e.target.value, doc.desktopSearchResults)); doc.desktopSearchInput.addEventListener('keypress', (e) => { if(e.key === 'Enter') triggerSearch('desktop-search-input'); }); }
    if(doc.desktopSearchBtn) doc.desktopSearchBtn.addEventListener('click', () => triggerSearch('desktop-search-input'));
    
    if(doc.realSearchInput) { 
        doc.realSearchInput.addEventListener('input', (e) => handleLiveSearch(e.target.value, doc.liveSearchResults)); 
        doc.realSearchInput.addEventListener('keypress', (e) => { if(e.key === 'Enter') triggerSearch('real-mobile-search-input'); }); 
    }
    const shwapnoSearch = getEl('shwapno-mobile-search');
    if (shwapnoSearch) shwapnoSearch.addEventListener('keypress', (e) => { if (e.key === 'Enter') triggerSearch('shwapno-mobile-search'); });
    const shwapnoSearchBtn = getEl('shwapno-mobile-search-btn');
    if (shwapnoSearchBtn) shwapnoSearchBtn.addEventListener('click', () => triggerSearch('shwapno-mobile-search'));

    // --- Keyboard support for role="button" (accessibility) ---
    document.body.addEventListener('keydown', (e) => {
        const btn = e.target.closest('[role="button"]');
        if (btn && (e.key === 'Enter' || e.key === ' ')) {
            e.preventDefault();
            btn.click();
        }
    });

    // --- GLOBAL EVENT DELEGATION (FIXED) ---
    document.body.addEventListener('click', (e) => {
        if(!e.target.closest('.desktop-search-box') && doc.desktopSearchResults) doc.desktopSearchResults.classList.add('hidden');
        if(!e.target.closest('.mobile-search-box') && doc.mobileSearchResults) doc.mobileSearchResults.classList.add('hidden');
        
        if (e.target.closest('.cart-toggle')) { 
            if(doc.cartDrawer) doc.cartDrawer.classList.add('open'); 
            doc.overlay.style.display = 'block'; 
        }

        // 1. Wishlist Action
        const wishlistBtn = e.target.closest('.btn-wishlist-action');
        if (wishlistBtn) {
            e.preventDefault(); e.stopPropagation();
            toggleWishlist(wishlistBtn.dataset.id);
            return;
        }

        // 2. Compare Action
        const compareBtn = e.target.closest('.btn-compare-action');
        if (compareBtn) {
            e.preventDefault(); e.stopPropagation();
            addToCompare(compareBtn.dataset.id);
            return;
        }

        // 3. Quick View Action
        const qvBtn = e.target.closest('.btn-quickview-action');
        if (qvBtn) {
            e.preventDefault(); e.stopPropagation();
            openQuickView(qvBtn.dataset.id);
            return;
        }

        // 3b. Shwapno card: +/- quantity (no drawer open)
        const shwapnoPlus = e.target.closest('.shwapno-card-plus');
        if (shwapnoPlus) {
            e.preventDefault(); e.stopPropagation();
            const id = shwapnoPlus.dataset.id;
            if (id) {
                const product = state.allProducts.find(p => String(p.id) === String(id));
                if (product) pushToDataLayer('add_to_cart', { currency: "BDT", value: product.salePrice, items: [{ item_id: product.id, item_name: product.name, price: product.salePrice, quantity: 1 }] });
                addProductToCart(id, null, false);
                const actionsEl = shwapnoPlus.closest('.shwapno-card-actions');
                if (actionsEl) actionsEl.innerHTML = getShwapnoCardActionHtml(id);
            }
            return;
        }
        const shwapnoMinus = e.target.closest('.shwapno-card-minus');
        if (shwapnoMinus) {
            e.preventDefault(); e.stopPropagation();
            const id = shwapnoMinus.dataset.id;
            if (id) {
                decreaseProductFromCart(id);
                const actionsEl = shwapnoMinus.closest('.shwapno-card-actions');
                if (actionsEl) actionsEl.innerHTML = getShwapnoCardActionHtml(id);
            }
            return;
        }

        // 3c. Order + Call style: go to checkout with item in cart (no drawer)
        const orderNowBtn = e.target.closest('.card-order-now-btn');
        if (orderNowBtn) {
            e.preventDefault();
            e.stopPropagation();
            const id = orderNowBtn.dataset.id;
            if (id) {
                const product = state.allProducts.find(pr => String(pr.id) === String(id));
                if (product) {
                    pushToDataLayer('add_to_cart', { currency: 'BDT', value: product.salePrice, items: [{ item_id: product.id, item_name: product.name, price: product.salePrice, quantity: 1 }] });
                    trackPixelEvent('AddToCart', { content_name: product.name, content_ids: [product.id], value: product.salePrice, currency: 'BDT' });
                }
                addProductToCart(id, null, false);
                normalizeOverlayState('card_order_now_before_checkout', { forceClose: true });
                window.location.hash = '#/checkout';
                scheduleClassicRouteSync();
            }
            return;
        }

        // 4. Add to Cart (Card Btn)
        const cardBtn = e.target.closest('.card-order-btn');
        if (cardBtn) { 
            e.preventDefault(); e.stopPropagation(); 
            const id = cardBtn.dataset.id; 
            if (id) { 
                const product = state.allProducts.find(p => p.id === id);
                const isShwapnoAddBag = cardBtn.closest('.product-card--shwapno') && cardBtn.classList.contains('shwapno-add-btn');
                if (product) {
                    pushToDataLayer('add_to_cart', { currency: "BDT", value: product.salePrice, items: [{ item_id: product.id, item_name: product.name, price: product.salePrice, quantity: 1 }] });
                }
                addProductToCart(id, null, true); 
                if (isShwapnoAddBag) {
                    const actionsEl = cardBtn.closest('.shwapno-card-actions');
                    if (actionsEl) actionsEl.innerHTML = getShwapnoCardActionHtml(id);
                } else {
                    if(doc.cartDrawer) { doc.cartDrawer.classList.add('open'); doc.overlay.style.display = 'block'; }
                }
            } 
            return;
        }

        // 5. Card Navigation (Fallback)
        const cardLink = e.target.closest('.product-card-link');
        if (cardLink) {
            const id = cardLink.dataset.id;
            if (id) {
                if (doc.searchOverlay) doc.searchOverlay.classList.add('hidden');
                const product = state.allProducts.find(pr => String(pr.id) === String(id));
                const landingUrl = product && getLandingPageUrlForProduct(product);
                if (landingUrl) window.location.href = landingUrl;
                else window.location.hash = `#/product/${id}`;
            }
        }
    });
    ensureClassicLayoutDebugOverlay();
};

exposeClassicStoreBuild();
document.addEventListener('DOMContentLoaded', init);