/**
 * AragShopView — فروشگاه آبلیموی شیراز
 * PDP · ویدیو hero · گالری · نظرات · مسیریابی slug
 * Landing فعلاً فقط محصول آبلیمو (lemon / ablime)
 */
const CART_KEY      = 'acc_arag_cart';
const CART_SESS_KEY = 'acc_arag_cart_session';
const TOKEN_KEY     = 'acc_token';
const WISHLIST_KEY  = 'acc_arag_wish';
const COUPON_KEY    = 'acc_arag_coupon';

export default class AragShopView {

    constructor() {
        this.root = null;
        this.step = 'families';
        this.family = null;
        this.variant = null;
        this.cart = this._loadCart();
        this.token = sessionStorage.getItem(TOKEN_KEY) || '';
        this.user = null;
        this._pkgQtys = {};
        this._currentPkgs = [];
        this._paymentMethods = [];
        this._shippingMethods = [];
        this._familiesCache = null;
        this._search = '';
        this._searchResults = [];
        this._searchTimer = null;
        this._settings = null;
        this._pdp = null;
        this._galleryIdx = 0;
        this._selVariant = null;
        this._pdpQtys = {};
        this._popBound = false;
        this._wishlist = this._loadWishlist();
        this._coupon = null;
        this._couponCode = localStorage.getItem(COUPON_KEY) || '';
        this._qvOpen = false;
        this._qvData = null;
        this._shellBound = false;
        this._docClickHandler = null;
        this._escHandler = null;
        this._cartSession = localStorage.getItem(CART_SESS_KEY) || '';
        this._lastOrder = null;
    }

    async render(root) {
        this.root = root;
        document.body.classList.add('sp-body');
        if (!this._popBound) {
            window.addEventListener('popstate', () => this._onPopState());
            this._popBound = true;
        }
        await this._parseRoute();
        const urlParams = new URLSearchParams(window.location.search);
        const refCode = urlParams.get('ref');
        if (refCode) {
            this._couponCode = refCode.toUpperCase();
            localStorage.setItem(COUPON_KEY, this._couponCode);
            const u = new URL(window.location.href);
            u.searchParams.delete('ref');
            history.replaceState({}, '', u.pathname + (u.search || ''));
        }
        const successParams = urlParams;
        const successId = successParams.get('order_success');
        const paymentRef = successParams.get('ref');
        const paymentErr = successParams.get('payment');
        if (successId) {
            this.step = 'success';
            const orderKey = successParams.get('ok') || sessionStorage.getItem('arag_last_order_key') || '';
            this._lastOrder = { id: successId, ref_id: paymentRef || '', order_key: orderKey };
            this.cart = [];
            this._saveCart();
            this._updateBadge();
            const url = new URL(window.location.href);
            url.searchParams.delete('order_success');
            url.searchParams.delete('ref');
            url.searchParams.delete('ok');
            history.replaceState({}, '', url.pathname + (url.search || ''));
            try {
                const qs = orderKey ? `?order_key=${encodeURIComponent(orderKey)}` : '';
                const rec = await this._get(`/public/arag/orders/${successId}/receipt${qs}`);
                if (rec.data) this._lastOrder = { ...this._lastOrder, ...rec.data };
            } catch {}
        } else if (paymentErr) {
            this._toast(paymentErr === 'cancelled' ? 'پرداخت لغو شد' : paymentErr === 'failed' ? 'پرداخت ناموفق بود' : 'خطا در پرداخت');
            const url = new URL(window.location.href);
            url.searchParams.delete('payment');
            url.searchParams.delete('order');
            history.replaceState({}, '', url.pathname + (url.search || ''));
        }
        await this._loadPaymentMethods();
        await this._render();
        this._syncCartFromServer();
    }

    _siteUrl() {
        const base = window.ACC_SHOP_CFG?.baseUrl || '/acc-engine/';
        return base.endsWith('/') ? base : base + '/';
    }

    _api() {
        return (window.ACC_SHOP_CFG?.api || '/acc-engine/api.php/acc/v1').replace(/\/$/, '');
    }

    _familyImg(f) {
        const raw = f?.image_url || f?.bottle_image_url || '';
        const slug = String(f?.slug || '').toLowerCase();
        const name = String(f?.name || '');
        const isLemon = slug.includes('lemon') || slug.includes('ablime')
            || name.includes('آبلیمو') || name.includes('لیمو');
        if (isLemon) return '/acc-engine/assets/img/li/p1.png';
        return raw;
    }

    _variantImg(variant, familyOrPdp) {
        const fallback = this._familyImg(familyOrPdp) || familyOrPdp?.bottle_image_url || '';
        return variant?.image_url || fallback;
    }

    _pdpGallery(p, variant) {
        const fallback = p.bottle_image_url || '';
        const vImg = this._variantImg(variant, p);
        const familyGallery = (p.gallery?.length ? p.gallery : (fallback ? [fallback] : []))
            .filter(url => url && url !== vImg);
        return vImg ? [vImg, ...familyGallery] : familyGallery;
    }

    async _loadSettings() {
        if (this._settings) return this._settings;
        try {
            const res = await this._get('/public/arag/shop/settings');
            this._settings = res.data || {};
        } catch {
            this._settings = {};
        }
        return this._settings;
    }

    _applyBranding() {
        const s = this._settings || {};
        const root = document.documentElement;
        if (s.primary_color) {
            root.style.setProperty('--ax-accent-deep', s.primary_color);
            root.style.setProperty('--ax-ink', s.primary_color);
        }
        if (s.accent_color) root.style.setProperty('--ax-accent', s.accent_color);
        const brand = s.brand_name || 'آبلیمو';
        document.title = 'آبلیموی شیراز — فروشگاه آبلیمو';
        if (s.favicon_url) {
            let link = document.querySelector('link[rel="icon"]');
            if (!link) { link = document.createElement('link'); link.rel = 'icon'; document.head.appendChild(link); }
            link.href = s.favicon_url;
        }
    }

    _brandName() {
        return this._esc(this._settings?.brand_name || 'آبلیمو');
    }

    /** Landing/catalog: only lemon juice SKUs for now */
    _isLemonProduct(f) {
        const slug = String(f?.slug || '').toLowerCase();
        const name = String(f?.name || '');
        if (['lemon', 'ablime', 'ablimo', 'ab-limoo', 'ablimoo', 'ablimu'].includes(slug)) return true;
        return /آبلیمو|لیمو/.test(name);
    }

    _landingFamilies(list) {
        const all = list || [];
        const lemon = all.filter(f => this._isLemonProduct(f));
        return lemon.length ? lemon : all.slice(0, 1);
    }

    async _parseRoute() {
        const params = new URLSearchParams(window.location.search);
        const slug = params.get('p');
        if (!slug) return;
        if (params.get('step') === 'models') {
            await this._openFamilyChooser(slug, false);
        } else {
            await this._openPdp(slug, false);
        }
    }

    async _onPopState() {
        const slug = new URLSearchParams(window.location.search).get('p');
        if (!slug) {
            this.step = 'families';
            this._pdp = null;
            this.family = null;
            this.variant = null;
        } else {
            await this._parseRoute();
        }
        await this._render();
    }

    _pushChooserUrl(slug) {
        const url = new URL(window.location.href);
        url.searchParams.set('p', slug);
        url.searchParams.set('step', 'models');
        history.pushState({ chooser: slug }, '', url);
    }

    _pushUrl(slug) {
        const url = new URL(window.location.href);
        url.searchParams.set('p', slug);
        url.searchParams.delete('step');
        history.pushState({ pdp: slug }, '', url);
    }

    _clearUrl() {
        const url = new URL(window.location.href);
        url.searchParams.delete('p');
        url.searchParams.delete('step');
        history.replaceState({}, '', url.pathname + (url.search || ''));
    }

    async _openFamilyChooser(slug, pushUrl = true) {
        try {
            const res = await this._get(`/public/arag/families/slug/${encodeURIComponent(slug)}`);
            const data = res.data;
            this._pdp = null;
            this.family = {
                id: data.id,
                name: data.name,
                slug: data.slug,
                tagline: data.tagline,
                description_short: data.description_short,
                bottle_image_url: data.bottle_image_url,
                image_url: data.bottle_image_url,
                rating_avg: data.rating_avg,
                rating_count: data.rating_count,
                variants: data.variants || [],
            };
            this.variant = null;
            this.step = 'variants';
            if (pushUrl) this._pushChooserUrl(slug);
        } catch {
            this._toast('محصول یافت نشد');
            this.step = 'families';
            this.family = null;
            this._clearUrl();
        }
    }

    async _openPdp(slug, pushUrl = true, variantId = null) {
        try {
            const res = await this._get(`/public/arag/families/slug/${encodeURIComponent(slug)}`);
            this._pdp = res.data;
            this._selVariant = variantId
                ? (this._pdp.variants?.find(v => v.id === variantId) || this._pdp.variants?.[0] || null)
                : (this._pdp.variants?.[0] || null);
            this._pdpQtys = {};
            this._galleryIdx = 0;
            this.step = 'pdp';
            this.family = {
                id: this._pdp.id,
                name: this._pdp.name,
                slug: this._pdp.slug,
                image_url: this._pdp.bottle_image_url,
            };
            if (pushUrl) this._pushUrl(slug);
        } catch {
            this._toast('محصول یافت نشد');
            this.step = 'families';
            this._pdp = null;
            this._clearUrl();
        }
    }

    _tileHtml(f, i) {
        const img = this._familyImg(f);
        const fb = i % 8;
        const imgTag = img
            ? `<img class="sp-tile__img" src="${img}" alt="${this._esc(f.name)}" loading="lazy" decoding="async" onerror="this.remove()">`
            : '';
        return `
        <div class="sp-tile-wrap sp-tile-wrap--photo">
            <button class="sp-tile__qv sp-tile__qv--solo" type="button" data-qv="${f.id}" aria-label="مشاهده سریع" title="مشاهده سریع">
                ${this._icon('eye')}<span>مشاهده سریع</span>
            </button>
            <button class="sp-tile" type="button" data-family="${f.id}" data-slug="${this._esc(f.slug)}">
                <div class="sp-tile__media">
                    <div class="sp-tile__fallback sp-tile__fb--${fb}"></div>
                    ${imgTag}
                </div>
            </button>
        </div>`;
    }

    _icon(name) {
        const icons = {
            portal:  '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6.5 12 3l8 3.5V18l-8 3.5L4 18V6.5Z" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M12 3v18M4 6.5l8 4 8-4" stroke="currentColor" stroke-width="1.5" fill="none"/></svg>',
            service: '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
            erp:     '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 19V5M4 19h16M8 15v-3M12 15V9M16 15v-5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
            acct:    '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 4h12v16H6z" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M8 8h8M8 12h8M8 16h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
            search:  '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="6.5" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M16 16l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
            user:    '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="8" r="3.5" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M5 20c0-3.5 3.1-6 7-6s7 2.5 7 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none"/></svg>',
            cart:    '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6h15l-1.5 9H8L6 6Z" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linejoin="round"/><path d="M6 6 5 3H2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="9.5" cy="19" r="1.25" fill="currentColor"/><circle cx="17.5" cy="19" r="1.25" fill="currentColor"/></svg>',
            back:    '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14 6 8 12l6 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>',
            heart:   '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21C12 21 3 14.5 3 8.5a4.5 4.5 0 0 1 9-1 4.5 4.5 0 0 1 9 1C21 14.5 12 21 12 21Z" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linejoin="round"/></svg>',
            heartFill:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21C12 21 3 14.5 3 8.5a4.5 4.5 0 0 1 9-1 4.5 4.5 0 0 1 9 1C21 14.5 12 21 12 21Z" fill="#e11d48" stroke="#e11d48" stroke-width="1.5" stroke-linejoin="round"/></svg>',
            eye:     '<svg viewBox="0 0 24 24" aria-hidden="true"><ellipse cx="12" cy="12" rx="9" ry="6" stroke="currentColor" stroke-width="1.5" fill="none"/><circle cx="12" cy="12" r="2.5" fill="currentColor"/></svg>',
        };
        return icons[name] || '';
    }

    /* ── Announcement Bar ── */
    _announcementBarHtml() {
        const msgs = this._settings?.announcements?.length
            ? this._settings.announcements
            : [
                '🚚 ارسال رایگان برای خرید بالای ۵۰۰ هزار تومان',
                '🍋 آبلیموی ۱۰۰٪ طبیعی · بدون افزودنی مصنوعی',
            ];
        if (sessionStorage.getItem('sp_ann_closed')) return '';
        return `
        <div class="sp-ann" id="sp-ann">
            <div class="sp-ann__track" id="sp-ann-track">
                ${msgs.map(m => `<span class="sp-ann__msg">${m}</span>`).join('')}
                ${msgs.map(m => `<span class="sp-ann__msg" aria-hidden="true">${m}</span>`).join('')}
            </div>
            <button class="sp-ann__close" id="sp-ann-close" aria-label="بستن">×</button>
        </div>`;
    }

    /* ── Wishlist Helpers ── */
    _loadWishlist() {
        try { return JSON.parse(localStorage.getItem(WISHLIST_KEY) || '[]'); } catch { return []; }
    }
    _saveWishlist() { localStorage.setItem(WISHLIST_KEY, JSON.stringify(this._wishlist)); }
    _inWishlist(id) { return this._wishlist.some(w => w.id == id); }
    _toggleWishlist(fam) {
        const idx = this._wishlist.findIndex(w => w.id == fam.id);
        if (idx >= 0) { this._wishlist.splice(idx, 1); this._toast('از لیست علاقه‌مندی حذف شد'); }
        else { this._wishlist.push({ id: fam.id, name: fam.name, slug: fam.slug, img: fam.image_url || fam.img || '' }); this._toast('❤ به لیست علاقه‌مندی اضافه شد'); }
        this._saveWishlist();
    }
    _wishlistDrawerHtml() {
        if (!this._wishlist.length) return `<div class="sp-empty"><p>لیست خالی است</p><small>روی آیکون ❤ روی محصولات کلیک کنید</small></div>`;
        return this._wishlist.map(w => `
        <div class="sp-wish-item">
            ${w.img ? `<img class="sp-wish-item__img" src="${this._esc(w.img)}" alt="">` : '<div class="sp-wish-item__img sp-wish-item__img--ph">🌿</div>'}
            <div class="sp-wish-item__info">
                <div class="sp-wish-item__name">${this._esc(w.name)}</div>
            </div>
            <div class="sp-wish-item__actions">
                <button class="sp-btn sp-btn--xs" data-wish-go="${this._esc(w.slug || '')}">مشاهده</button>
                <button class="sp-wish-item__rm" data-wish-rm="${w.id}">✕</button>
            </div>
        </div>`).join('');
    }

    /* ── Order Tracking ── */
    _trackFormHtml() {
        return `
        <div class="sp-track-form" id="sp-track-form-wrap">
            <div class="sp-field"><label>شماره سفارش</label>
                <input id="sp-track-id" type="text" dir="ltr" placeholder="مثال: 1023" inputmode="numeric">
            </div>
            <div class="sp-field"><label>موبایل (اختیاری)</label>
                <input id="sp-track-phone" type="tel" dir="ltr" placeholder="09123456789" maxlength="11" inputmode="tel">
            </div>
            <button class="sp-btn sp-btn--block" id="sp-track-submit" type="button">پیگیری سفارش</button>
            <div id="sp-track-result" class="sp-track-result" hidden></div>
        </div>`;
    }

    async _render() {
        this._resetPageLock();
        await this._loadSettings();
        this._applyBranding();
        const site = this._siteUrl();
        const cartN = this._cartCount();
        const onHome = this.step === 'families';
        const showBack = !onHome && !['cart', 'otp', 'checkout', 'success'].includes(this.step);

        const wishN = this._wishlist.length;
        this.root.innerHTML = `
        <div class="sp-wrap ba-applied${onHome ? ' ba-applied--home' : ''}">
            ${onHome ? `
            <div class="ba-util">
                <a href="${site}">ACC Engine</a>
                <a href="${site}service.php">خدمات HVAC</a>
                <a href="${site}shop-marketer.php">بازاریاب</a>
                <a href="${site}shop-accounting.php">حسابداری فروش</a>
                <a href="${site}shop-erp.php">ERP</a>
                <a href="#ba-story" class="ba-util__eco">خواص آبلیمو</a>
            </div>` : ''}
            <header class="ba-header" id="ba-header">
                ${showBack ? `<button class="sp-header__back" id="sp-back" type="button">${this._icon('back')}<span>بازگشت</span></button>` : `
                <a href="${site}shop.php" class="ba-brand">
                    <span class="ba-brand__mark">آ</span>
                    <span class="ba-brand__text">
                        <span class="ba-brand__name">آبلیموی شیراز</span>
                    </span>
                </a>
                <nav class="ba-nav">
                    <a href="#sp-catalog">محصول</a>
                    <a href="${site}shop-mizaj.php">تست مزاج</a>
                    <a href="#ba-story">خواص</a>
                    <a href="${site}account.php">پیگیری</a>
                    <a href="${site}shop-marketer.php">بازاریاب</a>
                </nav>`}
                <div class="ba-header__actions">
                    ${onHome ? `
                    <div class="sp-search-wrap" id="sp-search-container">
                        <label class="sp-search">
                            <span class="sp-search__icon">${this._icon('search')}</span>
                            <input class="sp-search__input" id="sp-search" type="search" placeholder="جستجوی آبلیمو…" autocomplete="off" value="${this._esc(this._search)}">
                        </label>
                        <div class="sp-search-dropdown" id="sp-search-dropdown" hidden></div>
                    </div>` : `<a href="${site}shop.php" class="ba-brand" style="margin-left:auto">
                        <span class="ba-brand__mark">آ</span>
                        <span class="ba-brand__text">
                            <span class="ba-brand__name">آبلیموی شیراز</span>
                        </span>
                    </a>`}
                    <button class="ba-icon-btn" id="sp-wish-btn" type="button" aria-label="علاقه‌مندی‌ها">
                        ${this._icon('heart')}<span class="label">دل‌خواه</span>
                        ${wishN ? `<span class="sp-badge sp-badge--wish">${wishN}</span>` : ''}
                    </button>
                    <a href="${site}account.php" class="ba-icon-btn" aria-label="حساب کاربری">
                        ${this._icon('user')}<span class="label">حساب</span>
                    </a>
                    <button class="ba-icon-btn" id="sp-cart-btn" type="button" aria-label="سبد خرید">
                        ${this._icon('cart')}<span class="label">سبد</span>
                        <span class="sp-badge" id="sp-cart-badge">${cartN || ''}</span>
                    </button>
                    ${onHome ? `<button type="button" class="ba-header__cta" id="sp-scroll-catalog-top">مشاهده محصول</button>` : ''}
                </div>
            </header>
            <main class="sp-main" id="sp-main">${await this._bodyHtml()}</main>
            ${onHome ? this._footerHtml(site) : ''}
            <div class="sp-overlay" id="sp-overlay"></div>
            <div class="sp-drawer" id="sp-drawer">
                <div class="sp-drawer__head">
                    <h2>سبد خرید</h2>
                    <button class="sp-drawer__close" id="sp-drawer-close" type="button" aria-label="بستن">×</button>
                </div>
                <div class="sp-drawer__body" id="sp-drawer-body"></div>
                <div class="sp-drawer__foot" id="sp-drawer-foot"></div>
            </div>
            <!-- Wishlist Drawer -->
            <div class="sp-drawer sp-wish-drawer" id="sp-wish-drawer">
                <div class="sp-drawer__head">
                    <h2>❤ لیست علاقه‌مندی‌ها</h2>
                    <button class="sp-drawer__close" id="sp-wish-close" type="button">×</button>
                </div>
                <div class="sp-drawer__body" id="sp-wish-body">${this._wishlistDrawerHtml()}</div>
            </div>
            <!-- Quick View Modal -->
            <div class="sp-qv-backdrop" id="sp-qv-backdrop" aria-hidden="true">
                <div class="sp-qv-modal" id="sp-qv-modal">
                    <button class="sp-qv-close" id="sp-qv-close">×</button>
                    <div id="sp-qv-content"></div>
                </div>
            </div>
            <!-- Order Tracking Widget -->
            <div class="sp-track-float" id="sp-track-float" title="پیگیری سفارش">
                <span class="sp-track-float__icon">📦</span>
            </div>
            <div class="sp-track-modal" id="sp-track-modal" hidden>
                <div class="sp-track-box">
                    <div class="sp-track-box__head">
                        <h3>پیگیری سفارش</h3>
                        <button id="sp-track-close" type="button">×</button>
                    </div>
                    ${this._trackFormHtml()}
                </div>
            </div>
            <div class="sp-toast" id="sp-toast"></div>
        </div>`;

        this._bindShell();
        this._renderDrawer();
    }

    _footerHtml(site) {
        const story = this._settings?.brand_story || 'آبلیموی طبیعی از لیموی تازه — تازگی در مبدأ، خلوص در طعم.';
        return `
        <footer class="sp-footer">
            <div class="sp-footer__inner">
                <p class="sp-footer__line">
                    <span class="sp-footer__brand sp-serif">آبلیموی شیراز</span>
                    <span class="sp-footer__sep" aria-hidden="true">—</span>
                    <span class="sp-footer__text">${this._esc(story)}</span>
                </p>
                <nav class="sp-footer__nav" aria-label="پیوندهای فوتر">
                    <a href="${site}shop.php">محصول</a>
                    <a href="${site}account.php">پیگیری سفارش</a>
                    <a href="${site}service.php">خدمات</a>
                    <a href="${site}">ACC Engine</a>
                    <a href="${site}shop-marketer.php" class="sp-footer__link--dim">بازاریاب</a>
                    <a href="${site}shop-admin.php" class="sp-footer__link--dim">مدیریت</a>
                </nav>
                <div class="sp-footer__bar">
                    <span>© ۱۴۰۴ آبلیموی شیراز</span>
                    <span>ACC Engine</span>
                </div>
            </div>
        </footer>`;
    }

    async _bodyHtml() {
        switch (this.step) {
            case 'families':  return this._familiesHtml();
            case 'pdp':       return this._pdpHtml();
            case 'variants':  return this._variantsHtml();
            case 'packages':  return this._packagesHtml();
            case 'cart':      return this._cartPageHtml();
            case 'otp':       return this._otpHtml();
            case 'checkout':  return this._checkoutHtml();
            case 'success':   return this._successHtml();
            default:          return this._familiesHtml();
        }
    }

    async _familiesHtml() {
        const s = await this._loadSettings();
        const site = this._siteUrl();
        if (!this._familiesCache) {
            const res = await this._get('/public/arag/families');
            this._familiesCache = res.data || [];
        }
        let items = this._landingFamilies(this._familiesCache);
        const q = this._search.trim().toLowerCase();
        if (q) items = items.filter(f => (f.name || '').toLowerCase().includes(q) || (f.tagline || '').toLowerCase().includes(q));

        return `
        <section class="ba-hero">
            ${s.hero_video_url ? `
            <div class="ba-hero__media ba-hero__media--video" aria-hidden="true">
                <video autoplay muted loop playsinline poster="${this._esc(s.hero_poster_url || '/acc-engine/assets/img/li/p1.png')}">
                    <source src="${this._esc(s.hero_video_url)}" type="video/mp4">
                </video>
            </div>` : `<div class="ba-hero__media" role="img" aria-label="آبلیموی شیراز"></div>`}
            <div class="ba-hero__content">
                <h1 class="ba-hero__place">آبلیموی شیراز</h1>
                <div class="ba-hero__actions">
                    <button class="ba-btn ba-btn--primary" type="button" id="sp-scroll-catalog">مشاهده محصول</button>
                    <a href="#sp-catalog" class="ba-btn ba-btn--ghost">سفارش آبلیمو</a>
                </div>
            </div>
        </section>

        <section class="ba-section ba-reveal">
            <div class="ba-section__head">
                <span class="ba-kicker">آبلیموی شیراز</span>
                <h2>چهار اصل فروشگاه</h2>
                <p>معیارهای فروشگاه آبلیموی شیراز: کیفیت محصول، استاندارد فرایند، تنوع بسته‌بندی و ارسال مطمئن.</p>
            </div>
            <div class="ba-pillars">
                <article class="ba-pillar"><strong>کیفیت</strong><span>انتخاب سخت‌گیرانه محصول — آنچه به دست شما می‌رسد باید شایسته اعتماد و تکرار خرید باشد.</span></article>
                <article class="ba-pillar"><strong>استاندارد</strong><span>فرآیند مشخص، کنترل مرحله‌به‌مرحله، و تعهد به معیارهای قابل‌سنجش در هر سفارش.</span></article>
                <article class="ba-pillar"><strong>بسته‌بندی</strong><span>تنوع در حجم و نوع بسته‌بندی — از مصرف روزمره تا هدیه، گزینه مناسب دارید.</span></article>
                <article class="ba-pillar"><strong>ارسال</strong><span>پست پیشتاز و تیپاکس با پیگیری لحظه‌ای سفارش تا تحویل سالم به درب منزل.</span></article>
            </div>
        </section>

        <section class="sp-section sp-section--catalog ba-reveal" id="sp-catalog">
            <div class="sp-catalog sp-catalog--single">
                ${items.length ? items.map((f, i) => this._tileHtml(f, i)).join('') : `<div class="sp-empty" style="grid-column:1/-1;padding:60px"><p>محصولی یافت نشد</p></div>`}
            </div>
        </section>

        <section class="ba-section ba-section--mist ba-reveal" id="ba-story">
            <div class="ba-props ba-reveal">
                <div class="ba-section__head" style="margin-inline:auto;text-align:center">
                    <span class="ba-kicker">خواص</span>
                    <h2>خواص آبلیمو</h2>
                    <p>فواید شناخته‌شده آبلیموی تازه برای سلامتی روزمره — مکمل یک سبک زندگی سالم، نه جایگزین درمان پزشکی.</p>
                </div>
                <div class="ba-props__grid">
                    <article class="ba-prop" data-n="۰۱"><span class="ba-prop__icon" aria-hidden="true">💇</span><strong>تقویت موی سر</strong></article>
                    <article class="ba-prop" data-n="۰۲"><span class="ba-prop__icon" aria-hidden="true">👁</span><strong>تقویت بینایی</strong></article>
                    <article class="ba-prop" data-n="۰۳"><span class="ba-prop__icon" aria-hidden="true">🍋</span><strong>بهبود هضم غذا</strong></article>
                    <article class="ba-prop" data-n="۰۴"><span class="ba-prop__icon" aria-hidden="true">✨</span><strong>جلوگیری از پیری زودرس</strong></article>
                    <article class="ba-prop" data-n="۰۵"><span class="ba-prop__icon" aria-hidden="true">🌡</span><strong>تب‌بر</strong></article>
                    <article class="ba-prop" data-n="۰۶"><span class="ba-prop__icon" aria-hidden="true">🛡</span><strong>درمان سرماخوردگی</strong></article>
                    <article class="ba-prop" data-n="۰۷"><span class="ba-prop__icon" aria-hidden="true">🌿</span><strong>از بین برنده جوش</strong></article>
                    <article class="ba-prop" data-n="۰۸"><span class="ba-prop__icon" aria-hidden="true">💚</span><strong>جلوگیری از رفلاکس معده</strong></article>
                </div>
                <div style="text-align:center;margin-top:28px">
                    <button type="button" class="ba-btn ba-btn--primary" id="sp-scroll-catalog-2">سفارش آبلیمو</button>
                </div>
            </div>
        </section>

        <section class="ba-help">
            <div class="ba-help__inner">
                <div>
                    <h2>چطور کمک کنیم؟</h2>
                    <p>سفارش آبلیمو، پیگیری مرسوله یا پشتیبانی آنلاین — مسیر درست را انتخاب کنید.</p>
                </div>
                <div class="ba-help__actions">
                    <button type="button" class="ba-btn ba-btn--solid" id="sp-scroll-catalog-3">سفارش آبلیمو</button>
                    <a href="${site}account.php" class="ba-btn">پیگیری سفارش</a>
                    <a href="${site}shop-accounting.php" class="ba-btn">حسابداری فروش</a>
                </div>
            </div>
        </section>`;
    }

    _starsHtml(rating, size = '') {
        const r = Math.round(+rating || 0);
        let s = '';
        for (let i = 1; i <= 5; i++) {
            s += `<span class="sp-star ${i <= r ? 'sp-star--on' : ''} ${size}">★</span>`;
        }
        return s;
    }

    _starPickerHtml(value = 5) {
        return [1, 2, 3, 4, 5].map(n => `
            <button type="button" class="sp-star-pick ${n <= value ? 'sp-star-pick--on' : ''}" data-star="${n}" aria-label="${n} ستاره">
                <span>★</span>
            </button>`).join('');
    }

    _reviewInitials(name) {
        const parts = (name || '').trim().split(/\s+/).filter(Boolean);
        if (parts.length >= 2) return parts[0].charAt(0) + parts[1].charAt(0);
        return (parts[0] || 'م').charAt(0);
    }

    _reviewDate(iso) {
        if (!iso) return '';
        try {
            const d = new Date(String(iso).replace(' ', 'T'));
            return d.toLocaleDateString('fa-IR', { year: 'numeric', month: 'long' });
        } catch {
            return '';
        }
    }

    _reviewBreakdown(reviews) {
        const counts = [0, 0, 0, 0, 0];
        (reviews || []).forEach(r => {
            const i = (+r.rating || 0) - 1;
            if (i >= 0 && i < 5) counts[i]++;
        });
        const total = reviews?.length || 0;
        return [5, 4, 3, 2, 1].map(star => {
            const count = counts[star - 1];
            return { star, count, pct: total ? Math.round((count / total) * 100) : 0 };
        });
    }

    _reviewCardHtml(r, featured = false) {
        const date = this._reviewDate(r.created_at);
        return `
            <article class="sp-review ${featured ? 'sp-review--featured' : ''}">
                <div class="sp-review__top">
                    <div class="sp-review__who">
                        <span class="sp-review__avatar" aria-hidden="true">${this._esc(this._reviewInitials(r.author_name))}</span>
                        <div>
                            <strong class="sp-review__name">${this._esc(r.author_name)}</strong>
                            ${r.author_city ? `<span class="sp-review__city">${this._esc(r.author_city)}</span>` : ''}
                            ${date ? `<time class="sp-review__date">${date}</time>` : ''}
                        </div>
                    </div>
                    <div class="sp-review__stars" aria-label="امتیاز ${r.rating} از ۵">${this._starsHtml(r.rating, 'sp-star--md')}</div>
                </div>
                <blockquote class="sp-review__body">${this._esc(r.body)}</blockquote>
                ${r.is_verified ? '<span class="sp-review__badge">خرید تأیید‌شده</span>' : ''}
            </article>`;
    }

    _reviewsSectionHtml(p) {
        const list = p.reviews || [];
        const breakdown = this._reviewBreakdown(list);
        const bars = breakdown.map(row => `
            <div class="sp-review-bar">
                <span class="sp-review-bar__label">${row.star.toLocaleString('fa-IR')}</span>
                <div class="sp-review-bar__track"><i style="width:${row.pct}%"></i></div>
                <span class="sp-review-bar__count">${row.count.toLocaleString('fa-IR')}</span>
            </div>`).join('');

        const cards = list.length
            ? list.map((r, i) => this._reviewCardHtml(r, i === 0 && r.rating >= 4)).join('')
            : `<div class="sp-reviews-empty">
                <p class="sp-serif">هنوز نظری ثبت نشده</p>
                <span>اولین کسی باشید که تجربه‌اش را با دیگران به اشتراک می‌گذارد.</span>
               </div>`;

        const avg = p.rating_avg ? p.rating_avg.toLocaleString('fa-IR', { minimumFractionDigits: 1, maximumFractionDigits: 1 }) : '—';

        return `
            <div class="sp-pdp__reviews" id="sp-reviews">
                <div class="sp-pdp__reviews-head">
                    <div>
                        <h2 class="sp-serif">تجربه مشتریان</h2>
                        <p class="sp-pdp__reviews-lead">نظرهای واقعی درباره عطر، بسته‌بندی و ارسال</p>
                    </div>
                </div>
                <div class="sp-pdp__reviews-layout">
                    <div class="sp-pdp__reviews-main">
                        <div class="sp-reviews-list">${cards}</div>
                    </div>
                    <aside class="sp-pdp__reviews-side">
                        <div class="sp-review-summary">
                            <div class="sp-review-summary__score">
                                <strong class="sp-serif">${avg}</strong>
                                <div class="sp-review-summary__stars">${this._starsHtml(p.rating_avg, 'sp-star--lg')}</div>
                                <span>${(p.rating_count || 0).toLocaleString('fa-IR')} نظر</span>
                            </div>
                            <div class="sp-review-summary__bars">${bars}</div>
                        </div>
                        <form class="sp-review-form" id="sp-review-form">
                            <h3 class="sp-serif">تجربه‌تان را بنویسید</h3>
                            <p class="sp-review-form__hint">از عطر، بسته‌بندی یا ارسال بگویید — نظرات محترمانه منتشر می‌شوند.</p>
                            <div class="sp-review-form__stars">
                                <span class="sp-review-form__label">امتیاز شما</span>
                                <div class="sp-star-picker" id="sp-star-picker" role="group" aria-label="انتخاب امتیاز">
                                    ${this._starPickerHtml(5)}
                                </div>
                                <input type="hidden" name="rating" id="sp-review-rating" value="5">
                            </div>
                            <div class="sp-review-prompts" id="sp-review-prompts">
                                <button type="button" class="sp-review-prompt" data-prompt="عطر طبیعی و پایدار بود">عطر عالی</button>
                                <button type="button" class="sp-review-prompt" data-prompt="بسته‌بندی سالم و محکم رسید">بسته‌بندی خوب</button>
                                <button type="button" class="sp-review-prompt" data-prompt="ارسال سریع و منظم بود">ارسال سریع</button>
                            </div>
                            <div class="sp-field sp-field--row">
                                <div class="sp-field"><label>نام</label><input name="author_name" required placeholder="مثلاً سارا احمدی"></div>
                                <div class="sp-field"><label>شهر</label><input name="author_city" placeholder="اختیاری"></div>
                            </div>
                            <div class="sp-field">
                                <label>نظر شما</label>
                                <textarea name="body" id="sp-review-body" rows="4" required minlength="15" maxlength="600"
                                    placeholder="مثلاً: طعم آبلیمو تازه و ترش طبیعی بود، بسته‌بندی سالم رسید."></textarea>
                                <span class="sp-review-form__count" id="sp-review-count">۰ / ۶۰۰</span>
                            </div>
                            <div class="sp-review-form__low" id="sp-review-low" hidden>
                                <label for="sp-review-improve">چه چیزی را بهتر کنیم؟</label>
                                <input id="sp-review-improve" name="improve_note" placeholder="مثلاً: سرعت ارسال یا حجم بسته‌بندی">
                            </div>
                            <button class="sp-btn sp-btn--block" type="submit">ارسال تجربه</button>
                            <div class="sp-msg" id="sp-review-msg" hidden></div>
                        </form>
                    </aside>
                </div>
            </div>`;
    }

    async _pdpHtml() {
        const p = this._pdp;
        if (!p) return '';
        const v = this._selVariant;
        const gallery = this._pdpGallery(p, v);
        const mainImg = gallery[this._galleryIdx] || gallery[0] || '';
        const pkgs = v?.packages || [];

        const thumbs = gallery.length > 1 ? gallery.map((url, i) => `
            <button type="button" class="sp-pdp__thumb ${i === this._galleryIdx ? 'sp-pdp__thumb--on' : ''}" data-gi="${i}">
                <img src="${this._esc(url)}" alt="" loading="lazy">
            </button>`).join('') : '';

        const variants = (p.variants || []).map(vr => `
            <button type="button" class="sp-pdp__variant ${v?.id === vr.id ? 'sp-pdp__variant--on' : ''}" data-vid="${vr.id}">
                ${this._esc(vr.name)}
            </button>`).join('');

        const skuRows = pkgs.map(pkg => {
            const q = this._pdpQtys[pkg.id] || 0;
            return `
            <div class="sp-pdp__pack ${q > 0 ? 'sp-pdp__pack--active' : ''}" data-pkg="${pkg.id}">
                <div class="sp-pdp__pack-top">
                    <span class="sp-pdp__pack-type">${this._esc(pkg.label)}</span>
                    <span class="sp-pdp__pack-vol">${this._esc(pkg.volume)}</span>
                </div>
                <div class="sp-pdp__pack-price">${this._fmt(pkg.price)}</div>
                <div class="sp-pdp__pack-qty">
                    <button type="button" class="sp-pdp__pack-btn" data-pdp-dec="${pkg.id}" ${q <= 0 ? 'disabled' : ''} aria-label="کم کردن">−</button>
                    <span class="sp-pdp__pack-val" id="pdp-qty-${pkg.id}">${q}</span>
                    <button type="button" class="sp-pdp__pack-btn" data-pdp-inc="${pkg.id}" aria-label="افزودن">+</button>
                </div>
            </div>`;
        }).join('');

        const ratingBlock = p.rating_count > 0
            ? `<div class="sp-pdp__rating">${this._starsHtml(p.rating_avg)} <span>${p.rating_avg.toLocaleString('fa-IR')} · ${p.rating_count.toLocaleString('fa-IR')} نظر</span></div>`
            : `<div class="sp-pdp__rating">${this._starsHtml(0)} <span>هنوز نظری ثبت نشده</span></div>`;

        const site = this._siteUrl();

        return `
        <section class="sp-pdp">
            <nav class="sp-pdp__crumb">
                <a href="${site}shop.php">فروشگاه</a>
                <span class="sp-pdp__crumb-sep">/</span>
                <span>${this._esc(p.name)}</span>
            </nav>
            <div class="sp-pdp__layout">
                <div class="sp-pdp__gallery-col">
                    <div class="sp-pdp__variant-visual">
                        ${mainImg
                            ? `<img class="sp-pdp__main" id="sp-pdp-main" src="${this._esc(mainImg)}" alt="${this._esc(v?.name || p.name)}" loading="lazy">`
                            : `<div class="sp-pdp__main sp-pdp__main--empty"></div>`}
                        ${v?.name ? `<span class="sp-pdp__variant-badge sp-serif">${this._esc(v.name)}</span>` : ''}
                    </div>
                    ${thumbs ? `<div class="sp-pdp__thumbs">${thumbs}</div>` : ''}
                </div>
                <div class="sp-pdp__buy-col">
                    <div class="sp-pdp__intro">
                        <h1 class="sp-pdp__title sp-serif">${this._esc(p.name)}</h1>
                        <div class="sp-pdp__meta">${ratingBlock}</div>
                    </div>
                    ${variants ? `
                    <div class="sp-pdp__block">
                        <span class="sp-pdp__label">انتخاب حجم</span>
                        <div class="sp-pdp__variant-row">${variants}</div>
                    </div>` : ''}
                    ${skuRows ? `
                    <div class="sp-pdp__block">
                        <span class="sp-pdp__label">${pkgs.length > 1 ? 'بسته‌بندی و تعداد' : 'تعداد'}</span>
                        <div class="sp-pdp__packs">${skuRows}</div>
                    </div>` : ''}
                    <div class="sp-pdp__purchase">
                        <div class="sp-pdp__purchase-sum">
                            <span>جمع انتخاب‌شده</span>
                            <strong id="sp-pdp-bar-total">${this._fmt(this._pdpTotal())}</strong>
                        </div>
                        <button class="sp-btn sp-pdp__atc" id="sp-pdp-add" type="button" ${this._pdpTotal() <= 0 ? 'disabled' : ''}>افزودن به سبد</button>
                    </div>
                    <ul class="sp-pdp__trust">
                        <li>آب‌گیری تازه</li>
                        <li>بدون اسانس مصنوعی</li>
                        <li>ارسال ۲–۵ روز کاری</li>
                        <li>بسته‌بندی ضد نور</li>
                    </ul>
                </div>
            </div>
            ${this._reviewsSectionHtml(p)}
            ${this._relatedProductsHtml(p)}
        </section>`;
    }

    _relatedProductsHtml(p) {
        const all = this._landingFamilies(this._familiesCache || []);
        const related = all.filter(f => f.id !== p.id).slice(0, 4);
        if (!related.length) return '';
        return `
        <div class="sp-related">
            <h2 class="sp-related__title sp-serif">شاید دوست داشته باشید</h2>
            <div class="sp-related__grid">
                ${related.map(f => {
                    const img = this._familyImg(f);
                    return `
                    <button class="sp-related__card" type="button" data-family="${f.id}" data-slug="${this._esc(f.slug)}">
                        ${img ? `<img class="sp-related__img" src="${this._esc(img)}" alt="${this._esc(f.name)}" loading="lazy">` : '<div class="sp-related__img sp-related__img--ph">🍋</div>'}
                        <div class="sp-related__info">
                            <span class="sp-related__name sp-serif">${this._esc(f.name)}</span>
                            ${f.tagline ? `<span class="sp-related__tag">${this._esc(f.tagline)}</span>` : ''}
                        </div>
                    </button>`;
                }).join('')}
            </div>
        </div>`;
    }

    _variantFromPrice(v) {
        const pkgs = v?.packages || [];
        if (!pkgs.length) return 0;
        return Math.min(...pkgs.map(p => +p.price));
    }

    async _variantsHtml() {
        if (!this.family) return '';
        const items = this.family.variants?.length
            ? this.family.variants
            : (await this._get(`/public/arag/families/${this.family.id}/variants`)).data || [];
        const img = this._familyImg(this.family);
        const site = this._siteUrl();

        const cards = items.map(v => {
            const from = this._variantFromPrice(v);
            const vImg = v.image_url || img;
            return `
            <button class="sp-chooser__card" type="button" data-variant="${v.id}" data-slug="${this._esc(this.family.slug)}">
                <div class="sp-chooser__card-visual">
                    ${vImg ? `<img src="${this._esc(vImg)}" alt="" loading="lazy" onerror="this.remove()">` : '<div class="sp-chooser__card-fb"></div>'}
                </div>
                <div class="sp-chooser__card-body">
                    <span class="sp-chooser__card-name sp-serif">${this._esc(v.name)}</span>
                    ${from ? `<span class="sp-chooser__card-price">از ${this._fmt(from)}</span>` : ''}
                    <span class="sp-chooser__card-cta">انتخاب ←</span>
                </div>
            </button>`;
        }).join('');

        return `
        <section class="sp-chooser">
            <nav class="sp-pdp__crumb">
                <a href="${site}shop.php">فروشگاه</a>
                <span class="sp-pdp__crumb-sep">/</span>
                <span>${this._esc(this.family.name)}</span>
            </nav>
            <div class="sp-chooser__head">
                <h1 class="sp-chooser__title sp-serif">${this._esc(this.family.name)}</h1>
            </div>
            <div class="sp-chooser__block">
                <span class="sp-pdp__label">انتخاب حجم</span>
                <p class="sp-chooser__hint">۱، ۲، ۴ یا ۱۰ لیتری را انتخاب کنید.</p>
                <div class="sp-chooser__grid">${cards || '<p class="sp-note">حجمی ثبت نشده است.</p>'}</div>
            </div>
        </section>`;
    }

    async _packagesHtml() {
        if (!this.variant) return '';
        const res = await this._get(`/public/arag/variants/${this.variant.id}/packages`);
        const pkgs = res.data || [];
        this._currentPkgs = pkgs;
        const v = res.variant || this.variant;
        const total = this._previewTotal(pkgs);
        const hasQty = total > 0;

        const multiPack = pkgs.length > 1;
        return `
        <section class="sp-section" style="padding-bottom:120px">
            <div class="sp-breadcrumb">${this._esc(v.family_name || '')} — ${this._esc(v.name)}</div>
            <h2 class="sp-step-title sp-serif">${multiPack ? 'انتخاب بسته‌بندی' : 'انتخاب تعداد'}</h2>
            ${multiPack ? '<p class="sp-chooser__hint" style="margin:0 0 16px">تک عدد یا بسته شل را انتخاب و تعداد را مشخص کنید.</p>' : ''}
            <div class="sp-sku-list">
                ${pkgs.map(p => {
                    const q = this._pkgQtys[p.id] || 0;
                    return `
                    <div class="sp-sku" data-pkg="${p.id}">
                        <div>
                            <div class="sp-sku__label">${this._esc(p.label)}</div>
                            <div class="sp-sku__vol">${this._esc(p.volume)}</div>
                            <div class="sp-sku__price">${this._fmt(p.price)}</div>
                        </div>
                        <div class="sp-stepper">
                            <button type="button" class="sp-stepper__btn" data-dec="${p.id}" ${q <= 0 ? 'disabled' : ''}>−</button>
                            <span class="sp-stepper__val" id="qty-${p.id}">${q}</span>
                            <button type="button" class="sp-stepper__btn" data-inc="${p.id}">+</button>
                        </div>
                    </div>`;
                }).join('')}
            </div>
        </section>
        <div class="sp-bar">
            <div class="sp-bar__sum">
                <span>جمع انتخاب‌شده</span>
                <strong id="sp-bar-total">${this._fmt(total)}</strong>
            </div>
            <button class="sp-btn" id="sp-add-cart" type="button" ${!hasQty ? 'disabled' : ''}>افزودن به سبد</button>
        </div>`;
    }

    _cartPageHtml() {
        if (!this.cart.length) {
            return `<section class="sp-section"><div class="sp-empty"><p>سبد خرید خالی است</p>
                <button class="sp-btn sp-btn--ghost" id="sp-go-shop" type="button" style="margin-top:24px">بازگشت به فروشگاه</button></div></section>`;
        }
        let total = 0;
        const rows = this.cart.map((item, idx) => {
            total += item.price * item.qty;
            return `
            <div class="sp-line-item">
                <div>
                    <div class="sp-line-item__name">${this._esc(item.label)}</div>
                    <div class="sp-line-item__meta">${item.qty} × ${this._fmt(item.price)}</div>
                </div>
                <button type="button" class="sp-line-item__rm" data-rm="${idx}">حذف</button>
            </div>`;
        }).join('');

        return `
        <section class="sp-section" style="padding-bottom:100px">
            <h2 class="sp-step-title sp-serif">سبد خرید</h2>
            ${rows}
            <div class="sp-total-row" style="margin-top:24px;padding-top:20px;border-top:1px solid var(--ax-line)">
                <span>جمع</span><strong>${this._fmt(total)}</strong>
            </div>
            <p class="sp-note" style="margin-top:12px">هزینه ارسال جداگانه · پس‌پرداخت</p>
        </section>
        <div class="sp-bar">
            <div class="sp-bar__sum"><span>مبلغ قابل پرداخت</span><strong>${this._fmt(total)}</strong></div>
            <button class="sp-btn" id="sp-checkout-start" type="button">تکمیل خرید</button>
        </div>`;
    }

    _otpHtml() {
        return `<section class="sp-section"><div class="sp-form">
            <h2 class="sp-step-title sp-serif">تأیید موبایل</h2>
            <p class="sp-note" style="margin-bottom:28px">برای ادامه، شماره موبایل خود را وارد کنید.</p>
            <div class="sp-field"><label>موبایل</label>
                <input id="sp-phone" type="tel" placeholder="09123456789" dir="ltr" maxlength="11" inputmode="tel"></div>
            <button class="sp-btn sp-btn--block" id="sp-send-otp" type="button" style="margin-bottom:16px">دریافت کد</button>
            <div id="sp-otp-section" hidden>
                <div class="sp-field"><label>کد ۶ رقمی</label>
                    <input id="sp-code" type="text" dir="ltr" maxlength="6" inputmode="numeric"></div>
                <div class="sp-hint" id="sp-demo-hint"></div>
                <button class="sp-btn sp-btn--block" id="sp-verify-otp" type="button">تأیید</button>
            </div>
            <div class="sp-msg" id="sp-otp-msg" hidden></div>
        </div></section>`;
    }

    _checkoutHtml() {
        const total = this._cartTotal();
        const payTotal = this._couponTotal(total);
        const ships = this._shippingMethods;
        const pays  = this._paymentMethods;
        const itemN = this.cart.reduce((s, i) => s + i.qty, 0);

        if (!this.cart.length) {
            return `<section class="sp-section"><div class="sp-empty"><p>سبد خرید خالی است</p>
                <button class="sp-btn" type="button" id="sp-success-home">بازگشت به فروشگاه</button></div></section>`;
        }

        return `<section class="sp-section sp-checkout-section">
        <div class="sp-acc-checkout">
            <div class="sp-acc-checkout__head">
                <div>
                    <h1 class="sp-serif">تکمیل سفارش</h1>
                    ${this.user ? `<p class="sp-acc-checkout__meta">سلام ${this._esc(this.user.name)} · ${itemN.toLocaleString('fa-IR')} قلم</p>` : `<p class="sp-acc-checkout__meta">${itemN.toLocaleString('fa-IR')} قلم در سبد</p>`}
                </div>
                <div class="sp-acc-checkout__head-total">
                    <small>مبلغ قابل پرداخت</small>
                    <strong id="ck-total">${this._fmt(payTotal)}</strong>
                </div>
            </div>
            <div class="sp-acc-checkout__grid">
                <div class="sp-acc-checkout__form">
                    <div class="sp-acc-checkout__section">
                        <h3>📍 اطلاعات گیرنده</h3>
                        <div class="sp-field"><label>نام و نام خانوادگی *</label>
                            <input id="ck-name" required value="${this._esc(this.user?.name || '')}" placeholder="نام گیرنده"></div>
                        <div class="sp-field"><label>موبایل *</label>
                            <input id="ck-phone" dir="ltr" required value="${this._esc(this.user?.phone || '')}" placeholder="09xxxxxxxxx"></div>
                        <div class="sp-field"><label>آدرس کامل *</label>
                            <input id="ck-address" required value="${this._esc(this.user?.address || '')}" placeholder="خیابان، پلاک، واحد"></div>
                        <div class="sp-field"><label>شهر *</label>
                            <input id="ck-city" required value="${this._esc(this.user?.city || '')}" placeholder="مثلاً تهران"></div>
                    </div>
                    <div class="sp-acc-checkout__section">
                        <h3>🚚 روش ارسال</h3>
                        ${ships.map((s, i) => `
                        <label class="sp-radio">
                            <input type="radio" name="shipping" value="${s.id}" ${i === 0 ? 'checked' : ''}>
                            <span>${this._esc(s.title)}</span><small>${this._esc(s.desc)}</small>
                        </label>`).join('')}
                    </div>
                    <div class="sp-acc-checkout__section">
                        <h3>💳 روش پرداخت</h3>
                        ${pays.map((p, i) => `
                        <label class="sp-radio ${p.id === 'demo' ? 'sp-radio--demo' : ''}">
                            <input type="radio" name="payment" value="${p.id}" ${i === 0 ? 'checked' : ''}>
                            <span>${p.icon ? p.icon + ' ' : ''}${this._esc(p.title)}</span>
                            <small>${this._esc(p.desc)}</small>
                        </label>`).join('')}
                    </div>
                    <div class="sp-acc-checkout__section">
                        <div class="sp-field"><label>یادداشت سفارش</label><textarea id="ck-note" rows="2" placeholder="اختیاری"></textarea></div>
                        <div class="sp-coupon-row">
                            <div class="sp-field" style="flex:1;margin:0">
                                <label>کد تخفیف</label>
                                <input id="ck-coupon" dir="ltr" placeholder="مثال: ARAG10" value="${this._esc(this._couponCode)}" autocomplete="off">
                            </div>
                            <button class="sp-btn sp-btn--outline" id="sp-apply-coupon" type="button">اعمال</button>
                        </div>
                        <div id="sp-coupon-msg" class="sp-msg" ${this._coupon ? '' : 'hidden'}>${this._coupon ? `✅ کد «${this._esc(this._coupon.code)}» اعمال شد — ${(+this._coupon.discount_pct).toLocaleString('fa-IR')}٪ تخفیف` : ''}</div>
                    </div>
                    <div class="sp-acc-checkout__submit">
                        <button class="sp-btn sp-btn--block sp-btn--pay" id="sp-place-order" type="button">
                            ✅ ثبت سفارش و پرداخت — <span id="ck-btn-total">${this._fmt(payTotal)}</span>
                        </button>
                        <div class="sp-msg" id="sp-checkout-msg" hidden></div>
                        <p class="sp-acc-checkout__note">با ثبت سفارش، شرایط ارسال و حریم خصوصی را می‌پذیرید.</p>
                    </div>
                </div>
                <aside class="sp-acc-checkout__summary">
                    <p class="sp-acc-checkout__label">🧾 خلاصه سفارش</p>
                    <div class="sp-acc-checkout__items">
                        ${this.cart.map(c => `
                        <div class="sp-acc-checkout__item">
                            <div class="sp-acc-checkout__item-info">
                                <div class="sp-acc-checkout__item-name">${this._esc(c.label)}</div>
                                <div class="sp-acc-checkout__item-qty">${c.qty.toLocaleString('fa-IR')} × ${this._fmt(c.price)}</div>
                            </div>
                            <strong>${this._fmt(c.price * c.qty)}</strong>
                        </div>`).join('')}
                    </div>
                    <div class="sp-acc-checkout__sum">
                        <span>جمع کالا</span><strong>${this._fmt(total)}</strong>
                    </div>
                    ${this._coupon ? `<div class="sp-acc-checkout__sum"><span>تخفیف</span><strong style="color:#16a34a">− ${this._fmt(total - payTotal)}</strong></div>` : ''}
                    <div class="sp-acc-checkout__sum" style="font-size:1.05rem;border-top:1px solid var(--ax-line, #e2e8f0);padding-top:10px;margin-top:6px">
                        <span>قابل پرداخت</span><strong id="ck-sum-total">${this._fmt(payTotal)}</strong>
                    </div>
                    <p class="sp-acc-checkout__note">🚚 هزینه ارسال جداگانه (پس‌پرداخت پست/تیپاکس)</p>
                </aside>
            </div>
        </div>
        </section>`;
    }

    _renderDrawer() {
        const body = this.root.querySelector('#sp-drawer-body');
        const foot = this.root.querySelector('#sp-drawer-foot');
        if (!body) return;

        if (!this.cart.length) {
            body.innerHTML = `<div class="sp-empty"><p>سبد خالی است</p></div>`;
            foot.innerHTML = '';
            return;
        }

        let total = 0;
        body.innerHTML = this.cart.map((item, idx) => {
            total += item.price * item.qty;
            return `
            <div class="sp-line-item">
                <div>
                    <div class="sp-line-item__name">${this._esc(item.label)}</div>
                    <div class="sp-line-item__meta">${item.qty} × ${this._fmt(item.price)}</div>
                </div>
                <button type="button" class="sp-line-item__rm" data-rm="${idx}">حذف</button>
            </div>`;
        }).join('');

        foot.innerHTML = `
            <div class="sp-total-row"><span>جمع</span><strong>${this._fmt(total)}</strong></div>
            <button class="sp-btn sp-btn--block" id="sp-drawer-checkout" type="button">تکمیل خرید</button>`;

        body.querySelectorAll('[data-rm]').forEach(btn => {
            btn.addEventListener('click', () => {
                this.cart.splice(+btn.dataset.rm, 1);
                this._saveCart();
                this._updateBadge();
                this._renderDrawer();
            });
        });
        foot.querySelector('#sp-drawer-checkout')?.addEventListener('click', () => {
            this._closeDrawer();
            this.step = 'cart';
            this._render();
        });
    }

    _resetPageLock() {
        document.body.style.overflow = '';
        document.body.classList.remove('sp-body--locked');
    }

    _closeAllPanels() {
        this._resetPageLock();
        if (!this.root) return;
        this.root.querySelector('#sp-overlay')?.classList.remove('sp-overlay--open');
        this.root.querySelector('#sp-drawer')?.classList.remove('sp-drawer--open');
        this.root.querySelector('#sp-wish-drawer')?.classList.remove('sp-drawer--open');
        const qv = this.root.querySelector('#sp-qv-backdrop');
        if (qv) {
            qv.classList.remove('sp-qv-backdrop--open');
            qv.setAttribute('aria-hidden', 'true');
        }
        const track = this.root.querySelector('#sp-track-modal');
        if (track) track.hidden = true;
        const searchDrop = this.root.querySelector('#sp-search-dropdown');
        if (searchDrop) searchDrop.hidden = true;
        this._qvOpen = false;
    }

    _openDrawer() {
        this._closeAllPanels();
        this.root.querySelector('#sp-overlay')?.classList.add('sp-overlay--open');
        this.root.querySelector('#sp-drawer')?.classList.add('sp-drawer--open');
        document.body.style.overflow = 'hidden';
        this._renderDrawer();
    }

    _closeDrawer() {
        this._closeAllPanels();
    }

    _openWishDrawer() {
        this._closeAllPanels();
        this.root.querySelector('#sp-wish-drawer')?.classList.add('sp-drawer--open');
        this.root.querySelector('#sp-overlay')?.classList.add('sp-overlay--open');
        document.body.style.overflow = 'hidden';
    }

    _closeWishDrawer() {
        this._closeAllPanels();
    }

    _bindWishActions() {}

    _couponTotal(base) {
        if (!this._coupon || !this._coupon.discount_pct) return base;
        return Math.round(base * (1 - this._coupon.discount_pct / 100));
    }

    _bindShell() {
        this.root.querySelector('#sp-back')?.addEventListener('click', () => this._goBack());
        this.root.querySelector('#sp-cart-btn')?.addEventListener('click', () => this._openDrawer());
        this.root.querySelector('#sp-drawer-close')?.addEventListener('click', () => this._closeDrawer());
        this.root.querySelector('#sp-overlay')?.addEventListener('click', () => this._closeAllPanels());

        const header = this.root.querySelector('#ba-header');
        if (header) {
            const onScroll = () => header.classList.toggle('ba-header--scrolled', window.scrollY > 12);
            onScroll();
            window.addEventListener('scroll', onScroll, { passive: true });
        }
        if ('IntersectionObserver' in window) {
            const io = new IntersectionObserver((entries) => {
                entries.forEach((e) => { if (e.isIntersecting) e.target.classList.add('is-in'); });
            }, { threshold: 0.12 });
            this.root.querySelectorAll('.ba-reveal').forEach((el) => io.observe(el));
        } else {
            this.root.querySelectorAll('.ba-reveal').forEach((el) => el.classList.add('is-in'));
        }
        const scrollCat = () => this.root.querySelector('#sp-catalog')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
        ['#sp-scroll-catalog', '#sp-scroll-catalog-top', '#sp-scroll-catalog-2', '#sp-scroll-catalog-3'].forEach((sel) => {
            this.root.querySelector(sel)?.addEventListener('click', scrollCat);
        });
        this.root.querySelectorAll('a[href^="#"]').forEach((a) => {
            a.addEventListener('click', (ev) => {
                const id = a.getAttribute('href');
                const t = id && this.root.querySelector(id);
                if (t) { ev.preventDefault(); t.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
            });
        });

        /* Announcement bar */
        this.root.querySelector('#sp-ann-close')?.addEventListener('click', () => {
            sessionStorage.setItem('sp_ann_closed', '1');
            this.root.querySelector('#sp-ann')?.remove();
        });

        /* Wishlist drawer */
        this.root.querySelector('#sp-wish-btn')?.addEventListener('click', () => this._openWishDrawer());
        this.root.querySelector('#sp-wish-close')?.addEventListener('click', () => this._closeWishDrawer());
        this.root.querySelectorAll('[data-wish-toggle]').forEach(btn => {
            btn.addEventListener('click', async e => {
                e.stopPropagation();
                const id = +btn.dataset.wishToggle;
                const fam = (this._familiesCache || []).find(f => f.id == id);
                if (!fam) return;
                this._toggleWishlist(fam);
                const inW = this._inWishlist(id);
                btn.innerHTML = inW ? this._icon('heartFill') : this._icon('heart');
                btn.classList.toggle('sp-tile__wish--on', inW);
                /* update badge in header */
                const b = this.root.querySelector('.sp-badge--wish');
                if (b) { b.textContent = this._wishlist.length || ''; if (!this._wishlist.length) b.remove(); }
            });
        });

        /* Quick View */
        this.root.querySelectorAll('[data-qv]').forEach(btn => {
            btn.addEventListener('click', async e => {
                e.stopPropagation();
                const id = +btn.dataset.qv;
                await this._openQuickView(id);
            });
        });
        this.root.querySelector('#sp-qv-close')?.addEventListener('click', () => this._closeQuickView());
        this.root.querySelector('#sp-qv-backdrop')?.addEventListener('click', e => {
            if (e.target === e.currentTarget) this._closeQuickView();
        });

        /* Wishlist drawer item actions */
        this.root.querySelector('#sp-wish-body')?.addEventListener('click', async e => {
            const rmBtn = e.target.closest('[data-wish-rm]');
            const goBtn = e.target.closest('[data-wish-go]');
            if (rmBtn) {
                const id = +rmBtn.dataset.wishRm;
                this._wishlist = this._wishlist.filter(w => w.id !== id);
                this._saveWishlist();
                this.root.querySelector('#sp-wish-body').innerHTML = this._wishlistDrawerHtml();
                this._bindWishActions();
            }
            if (goBtn) {
                const slug = goBtn.dataset.wishGo;
                if (slug) { this._closeWishDrawer(); await this._openFamilyChooser(slug); await this._render(); }
            }
        });

        /* Order Tracking float */
        this.root.querySelector('#sp-track-float')?.addEventListener('click', () => {
            this.root.querySelector('#sp-track-modal').hidden = false;
        });
        this.root.querySelector('#sp-track-close')?.addEventListener('click', () => {
            this.root.querySelector('#sp-track-modal').hidden = true;
        });
        this.root.querySelector('#sp-track-submit')?.addEventListener('click', () => this._trackOrder());

        this.root.querySelector('#sp-scroll-catalog')?.addEventListener('click', () => {
            this.root.querySelector('#sp-catalog')?.scrollIntoView({ behavior: 'smooth' });
        });

        /* Live search with dropdown */
        const searchInput = this.root.querySelector('#sp-search');
        const searchDrop  = this.root.querySelector('#sp-search-dropdown');
        if (searchInput && searchDrop) {
            searchInput.addEventListener('input', e => {
                clearTimeout(this._searchTimer);
                const q = e.target.value.trim();
                this._search = q;
                if (!q) { searchDrop.hidden = true; return; }
                this._searchTimer = setTimeout(() => this._showSearchDrop(q, searchDrop), 200);
            });
            searchInput.addEventListener('keydown', e => {
                if (e.key === 'Escape') { this._closeAllPanels(); searchInput.blur(); }
                if (e.key === 'Enter') { searchDrop.hidden = true; this._render(); }
            });
            if (!this._docClickHandler) {
                this._docClickHandler = e => {
                    const drop = this.root?.querySelector('#sp-search-dropdown');
                    if (drop && !e.target.closest('#sp-search-container')) drop.hidden = true;
                };
                document.addEventListener('click', this._docClickHandler);
            }
        }

        if (!this._escHandler) {
            this._escHandler = e => {
                if (e.key !== 'Escape') return;
                this._closeAllPanels();
            };
            document.addEventListener('keydown', this._escHandler);
        }

        /* Coupon code */
        this.root.querySelector('#sp-apply-coupon')?.addEventListener('click', () => this._applyCoupon());

        this._bindStepEvents();
        this._updateBadge();
    }

    _showSearchDrop(q, dropEl) {
        const all = this._landingFamilies(this._familiesCache || []);
        const ql = q.toLowerCase();
        const hits = all.filter(f => (f.name || '').toLowerCase().includes(ql) || (f.tagline || '').toLowerCase().includes(ql)).slice(0, 6);
        if (!hits.length) { dropEl.hidden = true; return; }
        dropEl.hidden = false;
        dropEl.innerHTML = hits.map(f => {
            const img = this._familyImg(f);
            return `<button class="sp-search-hit" type="button" data-family="${f.id}" data-slug="${this._esc(f.slug)}">
                ${img ? `<img class="sp-search-hit__img" src="${this._esc(img)}" alt="">` : '<span class="sp-search-hit__ph">🍋</span>'}
                <span class="sp-search-hit__name">${this._esc(f.name)}</span>
                ${f.tagline ? `<span class="sp-search-hit__tag">${this._esc(f.tagline)}</span>` : ''}
            </button>`;
        }).join('');
        dropEl.querySelectorAll('[data-family]').forEach(btn => {
            btn.addEventListener('click', async () => {
                dropEl.hidden = true;
                const slug = btn.dataset.slug;
                if (slug) await this._openFamilyChooser(slug);
                await this._render();
            });
        });
    }

    async _openQuickView(id) {
        const fam = (this._familiesCache || []).find(f => f.id == id);
        if (!fam) return;
        this._closeAllPanels();
        const backdrop = this.root.querySelector('#sp-qv-backdrop');
        const content  = this.root.querySelector('#sp-qv-content');
        if (!backdrop || !content) return;
        const img = this._familyImg(fam);
        content.innerHTML = `
        <div class="sp-qv-inner">
            <div class="sp-qv-img-col">
                ${img ? `<img src="${this._esc(img)}" alt="${this._esc(fam.name)}" loading="lazy">` : '<div class="sp-qv-img-col__ph">🌿</div>'}
            </div>
            <div class="sp-qv-info-col">
                ${fam.tagline ? `<p class="sp-pdp__eyebrow">${this._esc(fam.tagline)}</p>` : ''}
                <h2 class="sp-qv-title sp-serif">${this._esc(fam.name)}</h2>
                ${fam.description_short ? `<p class="sp-qv-desc">${this._esc(fam.description_short)}</p>` : ''}
                <div class="sp-qv-actions">
                    <button class="sp-btn" type="button" id="sp-qv-goto">مشاهده کامل محصول</button>
                    <button class="sp-btn sp-btn--outline sp-qv-wish ${this._inWishlist(id) ? 'sp-tile__wish--on' : ''}" type="button" id="sp-qv-wish">
                        ${this._inWishlist(id) ? this._icon('heartFill') : this._icon('heart')} علاقه‌مندی
                    </button>
                </div>
            </div>
        </div>`;
        backdrop.classList.add('sp-qv-backdrop--open');
        backdrop.setAttribute('aria-hidden', 'false');
        document.body.style.overflow = 'hidden';
        this._qvOpen = true;
        this.root.querySelector('#sp-qv-goto')?.addEventListener('click', async () => {
            this._closeQuickView();
            if (fam.slug) await this._openFamilyChooser(fam.slug);
            await this._render();
        });
        this.root.querySelector('#sp-qv-wish')?.addEventListener('click', e => {
            this._toggleWishlist(fam);
            const btn = e.currentTarget;
            const inW = this._inWishlist(id);
            btn.innerHTML = (inW ? this._icon('heartFill') : this._icon('heart')) + ' علاقه‌مندی';
            btn.classList.toggle('sp-tile__wish--on', inW);
        });
    }
    _closeQuickView() {
        const backdrop = this.root.querySelector('#sp-qv-backdrop');
        if (backdrop) {
            backdrop.classList.remove('sp-qv-backdrop--open');
            backdrop.setAttribute('aria-hidden', 'true');
        }
        this._qvOpen = false;
        this._resetPageLock();
    }

    async _trackOrder() {
        const orderId = this.root.querySelector('#sp-track-id')?.value?.trim();
        const phone   = this.root.querySelector('#sp-track-phone')?.value?.trim();
        const result  = this.root.querySelector('#sp-track-result');
        if (!orderId) { if (result) { result.hidden = false; result.innerHTML = '<div class="sp-msg sp-msg--err">شماره سفارش را وارد کنید</div>'; } return; }
        if (result) { result.hidden = false; result.innerHTML = '<div class="sp-track-loading">⏳ در حال بررسی…</div>'; }
        try {
            const params = new URLSearchParams({ order_id: orderId });
            if (phone) params.append('phone', phone);
            const res = await this._get(`/public/arag/orders/track?${params}`);
            const o = res.data || res;
            const st = o.order_status || o.status || 'pending';
            const statusMap = { pending: 'در انتظار', processing: 'در حال پردازش', shipped: 'ارسال شده', delivered: 'تحویل داده شده', cancelled: 'لغو شده', 'on-hold': 'در انتظار پرداخت', failed: 'ناموفق' };
            const statusColor = { pending: '#f59e0b', processing: '#3b82f6', shipped: '#8b5cf6', delivered: '#10b981', cancelled: '#ef4444', 'on-hold': '#f59e0b', failed: '#ef4444' };
            const payTotal = o.total || o.subtotal;
            result.innerHTML = `
            <div class="sp-track-card">
                <div class="sp-track-card__row"><span>شماره سفارش</span><strong>#${this._esc(String(o.order_number || o.id || orderId))}</strong></div>
                <div class="sp-track-card__row"><span>وضعیت</span>
                    <span class="sp-track-status" style="background:${statusColor[st]||'#6b7280'}20;color:${statusColor[st]||'#6b7280'}">${statusMap[st]||st}</span>
                </div>
                ${o.payment_status ? `<div class="sp-track-card__row"><span>پرداخت</span><span>${this._esc(o.payment_status)}</span></div>` : ''}
                ${o.billing?.name ? `<div class="sp-track-card__row"><span>نام</span><strong>${this._esc(o.billing.name)}</strong></div>` : ''}
                ${payTotal ? `<div class="sp-track-card__row"><span>مبلغ</span><strong>${this._fmt(payTotal)}</strong></div>` : ''}
                ${o.discount_amount > 0 ? `<div class="sp-track-card__row"><span>تخفیف</span><span>${this._fmt(o.discount_amount)}</span></div>` : ''}
                ${o.created_at ? `<div class="sp-track-card__row"><span>تاریخ</span><span>${this._esc(o.created_at)}</span></div>` : ''}
            </div>`;
        } catch (e) {
            if (result) result.innerHTML = `<div class="sp-msg sp-msg--err">${this._esc(e.message || 'سفارش یافت نشد')}</div>`;
        }
    }

    async _applyCoupon() {
        const code = this.root.querySelector('#ck-coupon')?.value?.trim();
        const msg  = this.root.querySelector('#sp-coupon-msg');
        if (!code) return;
        this._couponCode = code;
        localStorage.setItem(COUPON_KEY, code);
        try {
            const base = this._cartTotal();
            const res = await this._get(`/public/arag/coupons/check?code=${encodeURIComponent(code)}&subtotal=${base}`);
            this._coupon = res.data || res;
            if (msg) {
                msg.hidden = false;
                msg.textContent = `✅ کد «${code}» اعمال شد — ${(+this._coupon.discount_pct).toLocaleString('fa-IR')}٪ تخفیف`;
                msg.className = 'sp-msg sp-msg--ok';
            }
            const total = this.root.querySelector('#ck-total');
            if (total) total.textContent = this._fmt(this._couponTotal(base));
        } catch {
            /* If endpoint not available, apply a demo code locally */
            const demo = { ARAG10: 10, ARAG15: 15, WELCOME20: 20 };
            const pct = demo[code.toUpperCase()];
            if (pct) {
                this._coupon = { code, discount_pct: pct };
                if (msg) { msg.hidden = false; msg.textContent = `✅ کد «${code}» اعمال شد — ${pct}٪ تخفیف`; msg.className = 'sp-msg sp-msg--ok'; }
                const base = this._cartTotal();
                const total = this.root.querySelector('#ck-total');
                if (total) total.textContent = this._fmt(this._couponTotal(base));
            } else {
                this._coupon = null;
                if (msg) { msg.hidden = false; msg.textContent = 'کد تخفیف نامعتبر است'; msg.className = 'sp-msg sp-msg--err'; }
            }
        }
    }

    _bindStepEvents() {
        this.root.querySelectorAll('[data-family]').forEach(el => {
            el.addEventListener('click', async () => {
                const slug = el.dataset.slug;
                if (slug) await this._openFamilyChooser(slug);
                else {
                    const id = +el.dataset.family;
                    const f = (this._familiesCache || []).find(x => x.id == id);
                    if (f?.slug) await this._openFamilyChooser(f.slug);
                    else {
                        this.family = f;
                        this.step = 'variants';
                    }
                }
                await this._render();
            });
        });

        this.root.querySelectorAll('[data-gi]').forEach(btn => {
            btn.addEventListener('click', () => {
                this._galleryIdx = +btn.dataset.gi;
                const gallery = this._pdpGallery(this._pdp, this._selVariant);
                const main = this.root.querySelector('#sp-pdp-main');
                if (main && gallery[this._galleryIdx]) main.src = gallery[this._galleryIdx];
                this.root.querySelectorAll('.sp-pdp__thumb').forEach(t => {
                    t.classList.toggle('sp-pdp__thumb--on', +t.dataset.gi === this._galleryIdx);
                });
            });
        });

        this.root.querySelectorAll('[data-vid]').forEach(btn => {
            btn.addEventListener('click', async () => {
                const vid = +btn.dataset.vid;
                this._selVariant = this._pdp?.variants?.find(v => v.id === vid) || null;
                this._pdpQtys = {};
                this._galleryIdx = 0;
                await this._render();
            });
        });

        this.root.querySelectorAll('[data-pdp-inc]').forEach(btn => {
            btn.addEventListener('click', () => this._changePdpQty(+btn.dataset.pdpInc, 1));
        });
        this.root.querySelectorAll('[data-pdp-dec]').forEach(btn => {
            btn.addEventListener('click', () => this._changePdpQty(+btn.dataset.pdpDec, -1));
        });

        this.root.querySelector('#sp-pdp-add')?.addEventListener('click', () => this._addPdpToCart());

        this.root.querySelector('#sp-review-form')?.addEventListener('submit', e => this._submitReview(e));
        this._bindReviewForm();

        this.root.querySelectorAll('[data-variant]').forEach(el => {
            el.addEventListener('click', async () => {
                const id = +el.dataset.variant;
                const slug = el.dataset.slug || this.family?.slug || this._pdp?.slug;
                if (this.step === 'variants' && slug) {
                    await this._openPdp(slug, true, id);
                    await this._render();
                    return;
                }
                const res = await this._get(`/public/arag/families/${this.family.id}/variants`);
                this.variant = (res.data || []).find(v => v.id == id);
                this._pkgQtys = {};
                this.step = 'packages';
                await this._render();
            });
        });

        this.root.querySelectorAll('[data-inc]').forEach(btn => {
            btn.addEventListener('click', () => this._changeQty(+btn.dataset.inc, 1));
        });
        this.root.querySelectorAll('[data-dec]').forEach(btn => {
            btn.addEventListener('click', () => this._changeQty(+btn.dataset.dec, -1));
        });

        this.root.querySelector('#sp-add-cart')?.addEventListener('click', () => this._addPackagesToCart());
        this.root.querySelector('#sp-go-shop')?.addEventListener('click', async () => {
            this.step = 'families';
            this._clearUrl();
            await this._render();
        });

        this.root.querySelectorAll('[data-rm]').forEach(btn => {
            btn.addEventListener('click', async () => {
                this.cart.splice(+btn.dataset.rm, 1);
                this._saveCart();
                this._updateBadge();
                await this._render();
            });
        });

        this.root.querySelector('#sp-checkout-start')?.addEventListener('click', async () => {
            if (this.token) { this.step = 'checkout'; await this._loadUser(); }
            else this.step = 'otp';
            await this._render();
        });

        this.root.querySelector('#sp-send-otp')?.addEventListener('click', () => this._sendOtp());
        this.root.querySelector('#sp-verify-otp')?.addEventListener('click', () => this._verifyOtp());
        this.root.querySelector('#sp-place-order')?.addEventListener('click', () => this._placeOrder());
        this.root.querySelector('#sp-success-home')?.addEventListener('click', async () => {
            this.step = 'families';
            this._lastOrder = null;
            this._clearUrl();
            await this._render();
        });
    }

    _pdpFacts(p, paras = []) {
        const slugFacts = {
            lemon:    [ { label: 'منشأ', value: 'لیموی تازه' }, { label: 'روش', value: 'آب‌گیری تازه' }, { label: 'کاربرد', value: 'آشپزی و نوشیدنی' } ],
            ablime:   [ { label: 'منشأ', value: 'لیموی تازه' }, { label: 'روش', value: 'آب‌گیری تازه' }, { label: 'کاربرد', value: 'آشپزی و نوشیدنی' } ],
            ablimo:   [ { label: 'منشأ', value: 'لیموی تازه' }, { label: 'روش', value: 'آب‌گیری تازه' }, { label: 'کاربرد', value: 'آشپزی و نوشیدنی' } ],
            golab:    [ { label: 'منشأ', value: 'باغ‌های اصفهان' }, { label: 'روش', value: 'عرق‌گیری دو دیگی' }, { label: 'کاربرد', value: 'پذیرایی و طب سنتی' } ],
            bidmeshk: [ { label: 'رایحه', value: 'گلی ملایم' }, { label: 'روش', value: 'عرق‌گیری فصلی' }, { label: 'کاربرد', value: 'آرامش و پذیرایی' } ],
            kasni:    [ { label: 'بخش', value: 'ریشه و برگ تازه' }, { label: 'روش', value: 'بدون نگهدارنده' }, { label: 'کاربرد', value: 'سفره و طب خانگی' } ],
        };
        if (slugFacts[p.slug]) return slugFacts[p.slug];
        return paras.slice(0, 3).map((text, i) => ({
            label: [ 'ویژگی', 'کیفیت', 'پیشنهاد' ][i] || 'جزئیات',
            value: text.length > 48 ? text.slice(0, 45) + '…' : text,
        }));
    }

    _pdpTotal() {
        const v = this._selVariant;
        if (!v) return 0;
        return (v.packages || []).reduce((s, p) => s + (this._pdpQtys[p.id] || 0) * (+p.price), 0);
    }

    _updatePdpBar() {
        const total = this._pdpTotal();
        const barTotal = this.root.querySelector('#sp-pdp-bar-total');
        if (barTotal) barTotal.textContent = this._fmt(total);
        const btn = this.root.querySelector('#sp-pdp-add');
        if (btn) btn.disabled = total <= 0;
    }

    _changePdpQty(pkgId, delta) {
        this._pdpQtys[pkgId] = Math.max(0, (this._pdpQtys[pkgId] || 0) + delta);
        const el = this.root.querySelector(`#pdp-qty-${pkgId}`);
        if (el) el.textContent = this._pdpQtys[pkgId];
        const dec = this.root.querySelector(`[data-pdp-dec="${pkgId}"]`);
        if (dec) dec.disabled = this._pdpQtys[pkgId] <= 0;
        const pack = this.root.querySelector(`.sp-pdp__pack[data-pkg="${pkgId}"]`);
        if (pack) pack.classList.toggle('sp-pdp__pack--active', this._pdpQtys[pkgId] > 0);
        this._updatePdpBar();
    }

    async _addPdpToCart() {
        const v = this._selVariant;
        if (!v || !this._pdp) return;
        let added = 0;
        for (const p of v.packages || []) {
            const qty = this._pdpQtys[p.id] || 0;
            if (qty <= 0) continue;
            const label = `${this._pdp.name} — ${v.name} — ${p.label}`;
            const existing = this.cart.find(c => c.package_id === p.id);
            if (existing) existing.qty += qty;
            else this.cart.push({
                package_id: p.id, label, price: +p.price, qty,
                family_name: this._pdp.name, variant_name: v.name, package_label: p.label,
            });
            added += qty;
        }
        if (!added) {
            this._toast('حجم و تعداد را انتخاب کنید');
            return;
        }
        this._saveCart();
        this._updateBadge();
        this._toast(`${added.toLocaleString('fa-IR')} قلم به سبد اضافه شد`);
        this._openDrawer();
        this._pdpQtys = {};
        await this._render();
    }

    _bindReviewForm() {
        const picker = this.root.querySelector('#sp-star-picker');
        const ratingInput = this.root.querySelector('#sp-review-rating');
        const bodyEl = this.root.querySelector('#sp-review-body');
        const countEl = this.root.querySelector('#sp-review-count');
        const lowBox = this.root.querySelector('#sp-review-low');

        const setRating = (n) => {
            if (ratingInput) ratingInput.value = String(n);
            picker?.querySelectorAll('.sp-star-pick').forEach(btn => {
                btn.classList.toggle('sp-star-pick--on', +btn.dataset.star <= n);
            });
            if (lowBox) lowBox.hidden = n > 2;
        };

        picker?.querySelectorAll('.sp-star-pick').forEach(btn => {
            btn.addEventListener('click', () => setRating(+btn.dataset.star));
        });

        const updateCount = () => {
            if (!bodyEl || !countEl) return;
            const len = bodyEl.value.length;
            countEl.textContent = `${len.toLocaleString('fa-IR')} / ۶۰۰`;
            countEl.classList.toggle('sp-review-form__count--warn', len > 0 && len < 15);
        };
        bodyEl?.addEventListener('input', updateCount);
        updateCount();

        this.root.querySelectorAll('.sp-review-prompt').forEach(btn => {
            btn.addEventListener('click', () => {
                if (!bodyEl) return;
                const text = btn.dataset.prompt || '';
                if (!bodyEl.value.trim()) bodyEl.value = text;
                else if (!bodyEl.value.includes(text)) bodyEl.value = `${bodyEl.value.trim()} ${text}`;
                bodyEl.focus();
                updateCount();
            });
        });
    }

    _reviewLooksRude(text) {
        const t = (text || '').toLowerCase();
        return /کس|کیر|کون|جنده|حروم|لاشی|بیشرف|مادرجنده|خایه|گائید|گایید|fuck|shit|bitch/u.test(t);
    }

    async _submitReview(e) {
        e.preventDefault();
        const msg = this.root.querySelector('#sp-review-msg');
        const fd = new FormData(e.target);
        let bodyText = String(fd.get('body') || '').trim();
        const improve = String(fd.get('improve_note') || '').trim();
        if (improve && +fd.get('rating') <= 2) {
            bodyText = `${bodyText}\n\nپیشنهاد بهبود: ${improve}`;
        }
        const body = {
            author_name: fd.get('author_name'),
            author_city: fd.get('author_city'),
            rating: +fd.get('rating'),
            body: bodyText,
        };
        if (this._reviewLooksRude(bodyText) || this._reviewLooksRude(body.author_name)) {
            if (msg) {
                msg.hidden = false;
                msg.textContent = 'لطفاً نظر را با احترام و بدون توهین بنویسید.';
                msg.className = 'sp-msg sp-msg--err';
            }
            return;
        }
        try {
            const res = await this._post(`/public/arag/families/${this._pdp.id}/reviews`, body);
            await this._openPdp(this._pdp.slug, false);
            await this._render();
            this._toast(res.message || res.pending ? 'نظر شما ثبت شد — پس از تأیید نمایش داده می‌شود' : 'ممنون — تجربه‌تان ثبت شد');
            if (msg) { msg.hidden = true; }
        } catch (err) {
            if (msg) {
                msg.hidden = false;
                msg.textContent = err.message;
                msg.className = 'sp-msg sp-msg--err';
            }
        }
    }

    _changeQty(pkgId, delta) {
        this._pkgQtys[pkgId] = Math.max(0, (this._pkgQtys[pkgId] || 0) + delta);
        const el = this.root.querySelector(`#qty-${pkgId}`);
        if (el) el.textContent = this._pkgQtys[pkgId];
        const dec = this.root.querySelector(`[data-dec="${pkgId}"]`);
        if (dec) dec.disabled = this._pkgQtys[pkgId] <= 0;
        const total = this._previewTotal(this._currentPkgs);
        const barTotal = this.root.querySelector('#sp-bar-total');
        if (barTotal) barTotal.textContent = this._fmt(total);
        const btn = this.root.querySelector('#sp-add-cart');
        if (btn) btn.disabled = total <= 0;
    }

    async _addPackagesToCart() {
        if (!this.variant) return;
        const res = await this._get(`/public/arag/variants/${this.variant.id}/packages`);
        const pkgs = res.data || [];
        const v = res.variant || this.variant;
        let added = 0;

        for (const p of pkgs) {
            const qty = this._pkgQtys[p.id] || 0;
            if (qty <= 0) continue;
            const label = `${v.family_name} — ${v.name} — ${p.label}`;
            const existing = this.cart.find(c => c.package_id === p.id);
            if (existing) existing.qty += qty;
            else this.cart.push({ package_id: p.id, label, price: +p.price, qty,
                family_name: v.family_name, variant_name: v.name, package_label: p.label });
            added += qty;
        }

        if (!added) return;
        this._saveCart();
        this._updateBadge();
        this._toast(`${added} قلم اضافه شد`);
        this._openDrawer();
        this._pkgQtys = {};
        this.step = 'families';
        this.family = null;
        this.variant = null;
        this._clearUrl();
        await this._render();
    }

    async _goBack() {
        if (this.step === 'pdp') {
            const slug = this._pdp?.slug || this.family?.slug;
            if (slug) await this._openFamilyChooser(slug, true);
            else {
                this.step = 'families';
                this._pdp = null;
                this._clearUrl();
            }
        } else if (this.step === 'variants') {
            this.step = 'families';
            this.family = null;
            this._clearUrl();
        } else if (this.step === 'packages') {
            this.step = 'variants';
            this.variant = null;
        } else if (this.step === 'otp') {
            this.step = 'cart';
        } else if (this.step === 'checkout') {
            this.step = 'cart';
        }
        await this._render();
    }

    async _sendOtp() {
        const phone = this.root.querySelector('#sp-phone')?.value?.trim();
        const msg = this.root.querySelector('#sp-otp-msg');
        try {
            const res = await this._post('/public/arag/auth/send-otp', { phone });
            this.root.querySelector('#sp-otp-section').hidden = false;
            if (res.demo_code) {
                const hint = this.root.querySelector('#sp-demo-hint');
                if (hint) hint.textContent = `کد تست: ${res.demo_code}`;
            }
            if (msg) { msg.hidden = false; msg.textContent = res.message || 'کد ارسال شد'; msg.className = 'sp-msg sp-msg--ok'; }
        } catch (e) {
            if (msg) { msg.hidden = false; msg.textContent = e.message; msg.className = 'sp-msg sp-msg--err'; }
        }
    }

    async _verifyOtp() {
        const phone = this.root.querySelector('#sp-phone')?.value?.trim();
        const code  = this.root.querySelector('#sp-code')?.value?.trim();
        const msg   = this.root.querySelector('#sp-otp-msg');
        try {
            const res = await this._post('/public/arag/auth/verify-otp', { phone, code });
            this.token = res.token;
            this.user  = res.user;
            sessionStorage.setItem(TOKEN_KEY, res.token);
            this.step = 'checkout';
            await this._loadUser();
            await this._render();
        } catch (e) {
            if (msg) { msg.hidden = false; msg.textContent = e.message; msg.className = 'sp-msg sp-msg--err'; }
        }
    }

    async _loadUser() {
        if (!this.token) return;
        try {
            const res = await this._get('/public/arag/account/dashboard', true);
            this.user = res.user;
        } catch {}
    }

    async _loadPaymentMethods() {
        try {
            const res = await this._get('/public/arag/payment-methods');
            this._paymentMethods = res.data || [];
            this._shippingMethods = res.shipping || [];
        } catch {}
    }

    _successHtml() {
        const o = this._lastOrder || {};
        const site = this._siteUrl();
        const payLabel = { zarinpal: 'زرین‌پال', demo: 'آزمایشی (Sandbox)', cod: 'در محل', bank: 'کارت به کارت' }[o.payment_method] || o.payment_method || '';
        const paid = o.payment_status === 'paid' || o.payment_status === 'cod' || o.ref_id;
        return `
        <section class="sp-section sp-success">
            <div class="sp-success__icon">${paid ? '✅' : '📦'}</div>
            <h2 class="sp-serif sp-success__title">${paid ? 'پرداخت موفق — سفارش ثبت شد' : 'سفارش شما ثبت شد'}</h2>
            <p class="sp-note">${paid ? 'مبلغ با موفقیت دریافت شد و سفارش در صف پردازش است.' : 'جزئیات سفارش به زودی پیامک می‌شود.'}</p>
            ${o.order_number ? `<p class="sp-success__num">شماره سفارش: <strong dir="ltr">${this._esc(o.order_number)}</strong></p>` : ''}
            ${o.id ? `<p class="sp-success__num">کد پیگیری: <strong>#${this._esc(String(o.id))}</strong></p>` : ''}
            ${o.ref_id ? `<p class="sp-success__num">کد رهگیری پرداخت: <strong dir="ltr">${this._esc(o.ref_id)}</strong></p>` : ''}
            ${payLabel ? `<p class="sp-success__num">روش پرداخت: <strong>${this._esc(payLabel)}</strong></p>` : ''}
            ${o.total != null ? `<p class="sp-success__total">مبلغ: <strong>${this._fmt(o.total)}</strong></p>` : ''}
            ${(o.items || []).length ? `<ul class="sp-success__items">${o.items.map(i => `<li>${this._esc(i.label)} × ${i.qty}</li>`).join('')}</ul>` : ''}
            <div class="sp-success__actions">
                <button class="sp-btn" type="button" id="sp-success-home">ادامه خرید</button>
                <a href="${site}account.php#orders" class="sp-btn sp-btn--ghost" style="text-decoration:none">مشاهده در داشبورد</a>
            </div>
        </section>`;
    }

    async _placeOrder() {
        const msg = this.root.querySelector('#sp-checkout-msg');
        const btn = this.root.querySelector('#sp-place-order');
        const get = id => this.root.querySelector(id)?.value?.trim() ?? '';
        const name = get('#ck-name');
        const phone = get('#ck-phone') || this.user?.phone || '';
        const address = get('#ck-address');
        const city = get('#ck-city');

        if (!name || !phone || !address || !city) {
            if (msg) {
                msg.hidden = false;
                msg.textContent = 'لطفاً نام، موبایل، آدرس و شهر را کامل کنید.';
                msg.className = 'sp-msg sp-msg--err';
            }
            return;
        }
        if (!this.cart.length) {
            if (msg) { msg.hidden = false; msg.textContent = 'سبد خرید خالی است'; msg.className = 'sp-msg sp-msg--err'; }
            return;
        }

        const body = {
            items: this.cart.map(c => ({ package_id: c.package_id, qty: c.qty })),
            billing: { name, phone, address, city },
            shipping_method: this.root.querySelector('input[name=shipping]:checked')?.value || 'post',
            payment_method: this.root.querySelector('input[name=payment]:checked')?.value || 'demo',
            note: get('#ck-note'),
            user_id: this.user?.id || 0,
            coupon_code: this._coupon?.code || '',
            session_key: this._cartSession,
        };

        if (btn) { btn.disabled = true; btn.textContent = 'در حال ثبت و اتصال به درگاه…'; }
        try {
            const res = await this._post('/public/arag/orders/create', body, true);
            const data = res.data || {};
            this._lastOrder = data;

            /* زرین‌پال: سبد را تا تأیید نگه می‌داریم؛ بعد از redirect پاک می‌شود */
            const clearNow = data.payment_method !== 'zarinpal' || !data.payment_url || data.simulated;
            if (clearNow) {
                this.cart = [];
                this._saveCart();
                this._coupon = null;
                this._couponCode = '';
                localStorage.removeItem(COUPON_KEY);
                this._updateBadge();
            }

            if (data.payment_url) {
                /* روی localhost اگر simulate_url هم هست و کاربر sandbox است، مستقیم شبیه‌سازی */
                if (data.simulate_url && /localhost|127\.0\.0\.1/.test(location.hostname)) {
                    if (confirm('روی localhost کال‌بک زرین‌پال برنمی‌گردد.\n\nOK = پرداخت آزمایشی فوری\nCancel = رفتن به درگاه sandbox')) {
                        window.location.href = data.simulate_url;
                        return;
                    }
                }
                window.location.href = data.payment_url;
                return;
            }

            if (data.redirect_url && data.payment_status === 'paid') {
                this.cart = [];
                this._saveCart();
                this._updateBadge();
            }

            this.step = 'success';
            await this._render();
            if (data.order_id) {
                try {
                    if (data.order_key) sessionStorage.setItem('arag_last_order_key', data.order_key);
                    const qs = data.order_key ? `?order_key=${encodeURIComponent(data.order_key)}` : '';
                    const rec = await this._get(`/public/arag/orders/${data.order_id}/receipt${qs}`);
                    if (rec.data) this._lastOrder = { ...data, ...rec.data };
                    await this._render();
                } catch {}
            }
        } catch (e) {
            if (msg) { msg.hidden = false; msg.textContent = e.message; msg.className = 'sp-msg sp-msg--err'; }
            if (btn) {
                btn.disabled = false;
                btn.innerHTML = `✅ ثبت سفارش و پرداخت — <span id="ck-btn-total">${this._fmt(this._couponTotal(this._cartTotal()))}</span>`;
            }
        }
    }

    _toast(text) {
        const el = this.root.querySelector('#sp-toast');
        if (!el) return;
        el.textContent = text;
        el.classList.add('sp-toast--show');
        clearTimeout(this._toastTimer);
        this._toastTimer = setTimeout(() => el.classList.remove('sp-toast--show'), 2600);
    }

    _loadCart() {
        try { return JSON.parse(localStorage.getItem(CART_KEY) || '[]'); }
        catch { return []; }
    }
    _saveCart() {
        localStorage.setItem(CART_KEY, JSON.stringify(this.cart));
        this._pushCartToServer();
    }
    async _syncCartFromServer() {
        try {
            const headers = {};
            if (this._cartSession) headers['X-Cart-Session'] = this._cartSession;
            if (this.token) headers.Authorization = `Bearer ${this.token}`;
            const r = await fetch(this._api() + '/public/arag/cart', { headers });
            const j = await r.json().catch(() => ({}));
            if (j.session_key) {
                this._cartSession = j.session_key;
                localStorage.setItem(CART_SESS_KEY, j.session_key);
            }
            if (Array.isArray(j.data) && j.data.length) {
                this.cart = j.data;
                localStorage.setItem(CART_KEY, JSON.stringify(this.cart));
                this._updateBadge();
            }
        } catch {}
    }
    async _pushCartToServer() {
        if (!this.cart) return;
        try {
            const headers = { 'Content-Type': 'application/json' };
            if (this._cartSession) headers['X-Cart-Session'] = this._cartSession;
            if (this.token) headers.Authorization = `Bearer ${this.token}`;
            const r = await fetch(this._api() + '/public/arag/cart', {
                method: 'PUT',
                headers,
                body: JSON.stringify({ items: this.cart, session_key: this._cartSession }),
            });
            const j = await r.json().catch(() => ({}));
            if (j.session_key) {
                this._cartSession = j.session_key;
                localStorage.setItem(CART_SESS_KEY, j.session_key);
            }
        } catch {}
    }
    _cartCount() { return this.cart.reduce((s, i) => s + i.qty, 0); }
    _cartTotal() { return this.cart.reduce((s, i) => s + i.price * i.qty, 0); }
    _previewTotal(pkgs) {
        return (pkgs || this._currentPkgs).reduce((s, p) => s + (this._pkgQtys[p.id] || 0) * (+p.price), 0);
    }
    _updateBadge() {
        const n = this._cartCount();
        const b = this.root?.querySelector('#sp-cart-badge');
        if (b) b.textContent = n > 0 ? n : '';
    }

    async _get(path, auth = false) {
        const headers = {};
        if (auth && this.token) headers.Authorization = `Bearer ${this.token}`;
        const r = await fetch(this._api() + path, { headers });
        const j = await r.json().catch(() => ({}));
        if (!r.ok) throw new Error(j.message || `HTTP ${r.status}`);
        return j;
    }

    async _post(path, data, auth = false) {
        const headers = { 'Content-Type': 'application/json' };
        if (auth && this.token) headers.Authorization = `Bearer ${this.token}`;
        const r = await fetch(this._api() + path, { method: 'POST', headers, body: JSON.stringify(data) });
        const j = await r.json().catch(() => ({}));
        if (!r.ok) throw new Error(j.message || j.data?.message || `HTTP ${r.status}`);
        return j;
    }

    _fmt(n) { return (+n).toLocaleString('fa-IR') + ' تومان'; }
    _esc(s) {
        return String(s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
    }
}
