// --- START OF FILE dashboard.js ---

import { initializeApp } from "https://www.gstatic.com/firebasejs/11.9.0/firebase-app.js";
import { getDatabase, ref, get, update, onValue, set, remove, serverTimestamp, runTransaction, push, increment, query, orderByChild, limitToLast } from "https://www.gstatic.com/firebasejs/11.9.0/firebase-database.js";
import { getAuth, onAuthStateChanged, signOut, EmailAuthProvider, reauthenticateWithCredential, updatePassword } from "https://www.gstatic.com/firebasejs/11.9.0/firebase-auth.js";
import { firebaseConfig } from './firebase-config.js';

// Import Modules
import VisitorSpy from './visitor-spy.js';
import SpyIntelligence, { enrichVisitorsForDetective } from './spy-intelligence.js'; 
import FacebookCAPI from './facebook-capi.js';
import * as FBAds from './facebook-ads-api.js';
import * as LiveAdsUI from './live-ads-ui.js';
import * as FBPagePost from './facebook-page-post.js';
import { ipToBlockedIpFirebaseKey, looksLikeIpv4 } from './ip-block-utils.js';

// Import UI Layer (View)
import * as UI from './dashboard-ui.js';
import { setUploadConfig } from './image-upload-config.js';
import { TENANT_ADMIN_PANEL_META } from './dashboard-permission-panels.js';
import { resolveEffectiveDashboardRoleFromAdminNode, staffHasStrictPanelPermission } from './staff-page-guard.js';
import { buildLedgerEvent, appendLedgerToRootUpdates } from './inventory-ledger.js';
import { buildSkuAverageUnitCostMap, resolveUnitCostForSku } from './margin-analytics.js';
import { recordRtdbTelemetry, recordRtdbListenerLifecycle } from './rtdb-telemetry.js';
import { schedulePublishDashboardSummary } from './dashboard-summary-client.js';
import { schedulePublishDashboardAnalytics } from './dashboard-analytics-client.js';

if (typeof window !== 'undefined') {
    window.clearSmallBannerSlot = (slot) => {
        if (typeof UI.clearSmallBannerSlot === 'function') UI.clearSmallBannerSlot(slot);
    };
}

// --- 1. CONFIGURATION ---
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);
const auth = getAuth(app);

/** Live Session Monitor / session replay — off to reduce RTDB cost (`visitors/.../logs` reads/writes). Set `true` to re-enable. */
const SESSION_REPLAY_ENABLED = false;
/** Temporary toggle: keep Firebase usage cards hidden until later rollout. */
const FIREBASE_USAGE_SECTION_ENABLED = false;

/** Merge layout.menuConfig with header-nav-type radios + custom category textarea from the dashboard form */
function buildMenuConfigFromHeaderNavRadios(currentLayout) {
    const base = { ...(currentLayout.menuConfig || {}) };
    const headerNavTypeRadio = document.querySelector('input[name="header-nav-type"]:checked');
    const raw = headerNavTypeRadio && headerNavTypeRadio.value ? headerNavTypeRadio.value : 'categories';
    const headerNavType = ['sections', 'customCategories'].includes(raw) ? raw : 'categories';
    base.headerNavType = headerNavType;
    if (headerNavType === 'customCategories') {
        base.customCategories = typeof UI.getHeaderNavCustomCategoriesFromDOM === 'function'
            ? UI.getHeaderNavCustomCategoriesFromDOM()
            : [];
    } else {
        delete base.customCategories;
    }
    return base;
}

let landingPagesCache = {};

async function loadLandingPagesIntoSelect(selectId, currentSlug = '') {
    const sel = document.getElementById(selectId);
    if (!sel) return;
    if (!CURRENT_CLIENT_ID) { sel.innerHTML = '<option value="">Client not loaded</option>'; return; }
    try {
        const snap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/landingPages`));
        const pages = snap.val() || {};
        landingPagesCache = pages;
        const entries = Object.entries(pages);
        if (!entries.length) {
            sel.innerHTML = '<option value="">No landing pages found</option>';
            return;
        }
        sel.innerHTML = '<option value="">-- Select a landing page --</option>' +
            entries.map(([slug, p]) => {
                const title = p.page_title || slug;
                const domain = p.custom_domain ? ` (${p.custom_domain})` : '';
                const selected = slug === currentSlug ? ' selected' : '';
                return `<option value="${slug}"${selected}>${title}${domain}</option>`;
            }).join('');
    } catch(e) {
        sel.innerHTML = '<option value="">Failed to load landing pages</option>';
    }
}

const HOSTING_PACKAGES = {
    'plan_5gb': { name: '5 GB Plan', price: 150, durationDays: 30 },
    'plan_10gb': { name: '10 GB Plan', price: 250, durationDays: 30 },
    'plan_20gb': { name: '20 GB Plan', price: 400, durationDays: 30 }
};

/** Customization → Typography: keys match `siteSettings.layout.typography` and input ids `typo-{key}-pc` / `typo-{key}-mobile`. */
const WEBSITE_TYPOGRAPHY_GROUPS = ['body', 'heading', 'button', 'productTitle', 'productPrice', 'nav', 'sidebarCategory', 'sidebarCategoryIcon', 'sidebarHeader', 'footer', 'topBar', 'categoryPill', 'cardDescription', 'badge', 'cartDrawer'];

// --- 2. GLOBAL STATE ---
let CURRENT_CLIENT_ID = null;
let SITE_INFO = null;
let steadfastConfig = {};
let completedOrdersData = {};
let incompleteOrdersData = {};
let visitorData = {};
let homeVisitorData = {};
let currentBalance = 0;
let clientHostingInfo = null;
let isHostingActive = false;
let siteSettings = {}; 

/** Legacy: `activeDesign: 'swapno'` used removed shop-swapno.html — normalize to classic for dashboard UI. */
function normalizeLegacySwapnoActiveDesignInSiteSettings(ss) {
    if (!ss || typeof ss !== 'object') return;
    const l = ss.layout;
    if (l && typeof l === 'object' && l.activeDesign === 'swapno') {
        ss.layout = { ...l, activeDesign: 'classic' };
    }
}

let productCount = 0;

// Smart Variant State
let variantColors = [];
let variantSizes = [];

// CRM Data
let customerProfiles = []; 

// Temporary State for Order Editing
let currentEditingItems = [];

// Modules Instances
let visitorSpyModule = null; 
let spyIntelligenceModule = null; 
let fbCapiModule = null; 

// Local Data Copies for Forms & Logic
let allCategories = {};
let allProducts = {};
let categoryOrder = [];
let dashboardPanelsLoaded = { main: false, settings: false };
/** Staff/owner admin row + section permissions (RTDB `clients/{cid}/admins/{uid}`). */
let currentAdminAccess = { record: null, effectiveRole: 'unknown', permissions: null, accessLoaded: false };
let adminTeamEditingUid = null;
/** @type {null | (() => void)} */
let adminAccessUnsub = null;
const TENANT_ADMIN_API_BASE = 'api/';
/** When opening Customization, switch to this tab (e.g. product-design) instead of Theme */
let pendingCustomizationTabId = null;
/** After opening Customization, scroll this element id into view (e.g. header-category-links-panel) */
let pendingCustomizationScrollElId = null;
let settingsPanelsLoadingPromise = null;
let listenersBound = false;
let blockedIpsLoadedOnce = false;
let globalAdminSearchBound = false;
let globalSearchSelectedIndex = -1;
let currentSearchHighlightEl = null;
let sessionMonitorInitialized = false;
let openAiSettingsHandlersBound = false;
let aiVariantTabBound = false;
let marketersBrainChatBound = false;
let marketersBrainChatBusy = false;
let mbChatMessages = [];
const ADMIN_SEARCH_PANEL_ENTRIES = [
    { type: 'Panel', title: 'Dashboard Home', panelId: 'home', icon: 'fa-house', keywords: ['overview', 'home'] },
    { type: 'Panel', title: 'Completed Orders', panelId: 'completed-orders', icon: 'fa-cart-shopping', keywords: ['orders', 'sales', 'order list'] },
    { type: 'Panel', title: 'Incomplete Orders', panelId: 'incomplete-orders', icon: 'fa-box-open', keywords: ['abandoned', 'incomplete'] },
    { type: 'Panel', title: 'Products', panelId: 'products', icon: 'fa-box', keywords: ['product', 'item', 'catalog'] },
    { type: 'Panel', title: 'Categories', panelId: 'add-category', icon: 'fa-tags', keywords: ['category', 'subcategory'] },
    { type: 'Panel', title: 'Customers', panelId: 'customers', icon: 'fa-users', keywords: ['customer', 'buyer'] },
    { type: 'Panel', title: 'Visitor Spy', panelId: 'visitor-spy', icon: 'fa-user-secret', keywords: ['visitor', 'session', 'spy'] },
    { type: 'Panel', title: 'Detective Brain', panelId: 'detective-brain', icon: 'fa-brain', keywords: ['detective', 'analysis', 'wealth'] },
    { type: 'Panel', title: 'Customization', panelId: 'customization', icon: 'fa-paint-roller', keywords: ['design', 'theme', 'layout'] },
    { type: 'Panel', title: 'Shipping Settings', panelId: 'shipping-settings', icon: 'fa-truck', keywords: ['shipping', 'delivery', 'charge'] },
    { type: 'Setting', title: 'Product design', panelId: 'customization', customizationTab: 'product-design', targetId: 'save-product-design-btn', icon: 'fa-box', keywords: ['product design', 'save product design', 'product card', 'product page', 'product page info', 'upsell', 'product grid'] },
    { type: 'Panel', title: 'Policies', panelId: 'policy-settings', icon: 'fa-shield-halved', keywords: ['policy', 'privacy', 'terms'] },
    { type: 'Panel', title: 'Integrations', panelId: 'integrations', icon: 'fa-plug', keywords: ['integration', 'api', 'pixel'] },
    { type: 'Panel', title: 'TikTok Settings', panelId: 'tiktok-settings', icon: 'fa-music', keywords: ['tiktok'] },
    { type: 'Panel', title: 'Notifications', panelId: 'notifications', icon: 'fa-bell', keywords: ['push', 'notification'] },
    { type: 'Panel', title: 'Files Manager', panelId: 'files', icon: 'fa-folder-open', keywords: ['files', 'upload', 'manager'] },
    { type: 'Panel', title: 'Hosting', panelId: 'hosting', icon: 'fa-server', keywords: ['hosting', 'plan'] },
    { type: 'Panel', title: 'Live Ads Overview', panelId: 'live-ads-overview', icon: 'fa-chart-line', keywords: ['ads', 'marketing', 'overview'] },
    { type: 'Panel', title: 'Live Ads Facebook', panelId: 'live-ads-facebook', icon: 'fa-rectangle-ad', keywords: ['facebook ads', 'campaign'] },
    { type: 'Panel', title: 'AI Ads Manager', panelId: 'ai-ads-manager', icon: 'fa-wand-magic-sparkles', keywords: ['ai ads', 'creative'] },
    { type: 'Panel', title: 'Facebook Page Post', panelId: 'facebook-page-post', icon: 'fa-square-facebook', keywords: ['page post', 'facebook page'] },
    { type: 'Panel', title: 'Manage Banners', panelId: 'manage-banners', icon: 'fa-images', keywords: ['banner', 'hero', 'slides'] },
    { type: 'Setting', title: 'Header category links', panelId: 'customization', customizationTab: 'header', targetId: 'header-category-links-panel', icon: 'fa-link', keywords: ['header strip', 'shop by category', 'header nav', 'category links', 'custom categories'] },
    { type: 'Setting', title: 'Header design', panelId: 'customization', customizationTab: 'header', targetId: 'section-design-header', icon: 'fa-heading', keywords: ['header', 'menu header'] },
    { type: 'Setting', title: 'Save header design', panelId: 'customization', customizationTab: 'header', targetId: 'save-header-design-btn', icon: 'fa-floppy-disk', keywords: ['save header', 'header save'] },
    { type: 'Setting', title: 'Bottom Navigation Toggle', panelId: 'customization', customizationTab: 'section-designs', targetId: 'section-design-bottom-nav-enabled', icon: 'fa-mobile-screen-button', keywords: ['bottom bar', 'bottom nav', 'mobile nav'] },
    { type: 'Setting', title: 'Bottom Navigation Style', panelId: 'customization', customizationTab: 'section-designs', targetId: 'section-design-bottom-nav', icon: 'fa-bars', keywords: ['bottom nav design'] },
    { type: 'Setting', title: 'Save Section Designs', panelId: 'customization', customizationTab: 'section-designs', targetId: 'save-section-designs-btn', icon: 'fa-floppy-disk', keywords: ['save layout', 'save section'] },
    { type: 'Setting', title: 'Primary Color', panelId: 'customization', customizationTab: 'colors', targetId: 'color-primary', icon: 'fa-palette', keywords: ['primary color', 'theme color'] },
    { type: 'Setting', title: 'Save Color Settings', panelId: 'customization', customizationTab: 'colors', targetId: 'save-color-settings-btn', icon: 'fa-fill-drip', keywords: ['save colors'] },
    { type: 'Setting', title: 'Site Logo URL', panelId: 'customization', customizationTab: 'header', targetId: 'logo-url', icon: 'fa-image', keywords: ['logo', 'brand logo'] },
    { type: 'Setting', title: 'Save General Settings', panelId: 'customization', customizationTab: 'general', targetId: 'save-general-settings-btn', icon: 'fa-gears', keywords: ['general save'] },
    { type: 'Setting', title: 'Facebook Pixel ID', panelId: 'integrations', targetId: 'pixel-id', icon: 'fa-crosshairs', keywords: ['pixel', 'facebook pixel'] }
];
const dashboardSubscriptions = {
    orders: null,
    incompleteOrders: null,
    visitorsHome: null,
    visitorsDeep: null,
    products: null,
    categories: null,
    categoryOrder: null
};

/** In-dashboard iframe targets (basename → staff permission panel id). */
const ADMIN_EMBED_STAFF_PANEL = {
    'inventory.html': 'products',
    'courier.html': 'courier',
    'pos.html': 'pos',
    'purchase-add.html': 'purchase-add',
    'purchase-list.html': 'purchase-list',
    'purchase-return.html': 'purchase-return',
    'categories.html': 'add-category',
    'labels.html': 'products'
};

function sanitizeAdminEmbedTarget(raw) {
    const s = String(raw || '').trim();
    if (!s || s.includes('..') || s.includes('\\') || s.toLowerCase().includes('://')) return '';
    const base = s.split('?')[0].split('#')[0];
    const name = base.includes('/') ? base.split('/').pop() : base;
    return ADMIN_EMBED_STAFF_PANEL[name] ? name : '';
}

function closeAdminShellEmbedQuiet() {
    const shell = document.getElementById('admin-shell-embed');
    const fr = document.getElementById('admin-shell-embed-frame');
    if (fr) fr.src = 'about:blank';
    if (shell) {
        shell.classList.add('hidden');
        shell.setAttribute('aria-hidden', 'true');
    }
    const h = window.location.hash;
    if (h.startsWith('#admin-embed=') && history.replaceState) {
        const p = getActiveDashboardPanelId();
        const u = p === 'home' ? window.location.pathname : `#${p}`;
        history.replaceState({ panel: p }, '', u);
    }
}

function openAdminShellEmbed(rawUrl, pushHistory = true) {
    const url = sanitizeAdminEmbedTarget(rawUrl);
    if (!url) {
        UI.showToast('Invalid admin module link.', false);
        return;
    }
    const staffPanel = ADMIN_EMBED_STAFF_PANEL[url];
    if (!isDashboardPanelAccessAllowed(staffPanel)) {
        UI.showToast('You do not have access to this section.', false);
        return;
    }
    const rv = document.getElementById('result-view');
    const shell = document.getElementById('admin-shell-embed');
    const fr = document.getElementById('admin-shell-embed-frame');
    const title = document.getElementById('admin-shell-embed-title');
    const rvHidden = !rv || window.getComputedStyle(rv).display === 'none' || rv.classList.contains('hidden');
    if (rvHidden || !shell || !fr) {
        window.location.href = url;
        return;
    }
    fr.src = url;
    if (title) title.textContent = url.replace(/\.html$/i, '');
    shell.classList.remove('hidden');
    shell.setAttribute('aria-hidden', 'false');
    if (pushHistory && history.pushState) {
        history.pushState(
            { panel: getActiveDashboardPanelId(), adminEmbed: url },
            '',
            `#admin-embed=${encodeURIComponent(url)}`
        );
    }
}
const productCategoryRenderTimers = {
    products: null,
    categories: null
};

function normalizeSubcategories(subcategories) {
    if (subcategories == null) return {};
    const out = {};
    const row = (val, id) => {
        const name = (val && typeof val.name === 'string') ? val.name.trim() : '';
        if (!name) return;
        const rec = { name };
        const bg = val && val.bgColor ? String(val.bgColor).trim() : '';
        const tx = val && val.textColor ? String(val.textColor).trim() : '';
        if (bg) rec.bgColor = bg;
        if (tx) rec.textColor = tx;
        out[id] = rec;
    };
    if (Array.isArray(subcategories)) {
        subcategories.forEach((item, i) => {
            if (typeof item === 'string') {
                const name = item.trim();
                if (name) out[`sub_arr_${i}_${name.slice(0, 20)}`] = { name };
                return;
            }
            if (item && typeof item === 'object' && typeof item.name === 'string') {
                row(item, `sub_arr_${i}_${String(item.name).trim().slice(0, 20)}`);
            }
        });
        return out;
    }
    if (typeof subcategories !== 'object') return {};
    Object.entries(subcategories).forEach(([id, val]) => row(val, id));
    return out;
}

function normalizeCategoriesMap(categories) {
    const out = {};
    Object.entries(categories || {}).forEach(([id, cat]) => {
        out[id] = {
            ...(cat || {}),
            subcategories: normalizeSubcategories(cat?.subcategories)
        };
    });
    return out;
}

function isPanelActive(panelId) {
    return !!document.getElementById(`dashboard-${panelId}`)?.classList.contains('active');
}

function normalizePanelId(panelIdRaw) {
    const raw = String(panelIdRaw || '').trim();
    if (!raw) return 'home';
    if (raw === 'customization-header-links') {
        pendingCustomizationTabId = 'header';
        pendingCustomizationScrollElId = 'header-category-links-panel';
        return 'customization';
    }
    if (raw === 'productpage-settings' || raw === 'customization-product-design') {
        pendingCustomizationTabId = 'product-design';
        return 'customization';
    }
    if (raw === 'customization-home-page-design') {
        pendingCustomizationTabId = 'home-page-design';
        return 'customization';
    }
    const aliases = {
        marketing: 'live-ads-overview',
        banners: 'manage-banners',
        'customization-banners': 'customization'
    };
    return aliases[raw] || raw;
}

function restoreHomePanelAsSafeFallback() {
    document.querySelectorAll('.dashboard-panel').forEach((p) => p.classList.remove('active'));
    const homePanel = document.getElementById('dashboard-home');
    if (homePanel) homePanel.classList.add('active');
    manageRealtimeSubscriptionsForPanel('home');
}

function getActiveDashboardPanelId() {
    const activePanel = document.querySelector('.dashboard-panel.active[id^="dashboard-"]');
    if (!activePanel || !activePanel.id) return 'home';
    const rawId = activePanel.id.replace(/^dashboard-/, '').trim();
    return rawId || 'home';
}

/** Legacy hook: one-screen xl mode removed — home scrolls inside #dashboard-content. */
function syncDashboardContentFitViewportClass() {
    const content = document.getElementById('dashboard-content');
    if (!content) return;
    content.classList.remove('dashboard-home-fit-viewport');
}

function reorderHomeSectionsSafely() {
    const home = document.getElementById('dashboard-home');
    if (!home) return;
    const main = home.querySelector('main');
    const session = home.querySelector('#session-monitor-section');
    if (!main) return;
    if (!session) return;
    // Keep desired visual order without overriding panel visibility display rules.
    if (session.previousElementSibling !== main) home.insertBefore(main, session);
}

function throttledRenderProducts() {
    if (productCategoryRenderTimers.products) clearTimeout(productCategoryRenderTimers.products);
    productCategoryRenderTimers.products = setTimeout(() => {
        productCategoryRenderTimers.products = null;
        if (isPanelActive('products')) UI.renderProducts(allProducts);
    }, 120);
}

function throttledRenderCategories() {
    if (productCategoryRenderTimers.categories) clearTimeout(productCategoryRenderTimers.categories);
    productCategoryRenderTimers.categories = setTimeout(() => {
        productCategoryRenderTimers.categories = null;
        if (isPanelActive('add-category')) UI.renderCategories(allCategories, categoryOrder);
    }, 120);
}

function refreshHeaderCategoriesSelector() {
    if (typeof UI.populateHeaderCategories !== 'function') return;
    UI.populateHeaderCategories(
        allCategories,
        siteSettings?.layout?.categoryConfig?.headerCategories || [],
        categoryOrder,
        siteSettings?.layout?.categoryConfig?.headerCategoryIcons || {}
    );
    if (typeof UI.populateHomeStripCategories === 'function') {
        UI.populateHomeStripCategories(
            allCategories,
            siteSettings?.layout?.categoryConfig?.homeThumbnailCategoryNames || [],
            categoryOrder
        );
    }
    if (typeof UI.refreshHeaderCategoryLinksUi === 'function') {
        UI.refreshHeaderCategoryLinksUi(allCategories, categoryOrder);
    }
    if (typeof UI.refreshHeaderNavCustomCategoryTargetDropdowns === 'function') {
        UI.refreshHeaderNavCustomCategoryTargetDropdowns(allCategories, categoryOrder);
    }
    if (typeof window.refreshCategoryBannerSectionDashboardControls === 'function') {
        window.refreshCategoryBannerSectionDashboardControls();
    }
}

/** Categories map + order for header custom-link UI (populate + dropdowns). */
window.__getDashboardCategoriesForHeaderUi = () => ({ map: allCategories, order: categoryOrder });

/** Wired from dashboard-ui `populateSiteSettings` rAF — refreshes header strip preview + validation. */
window.__refreshHeaderCategoryLinksUi = () => {
    if (typeof UI.refreshHeaderCategoryLinksUi === 'function') {
        UI.refreshHeaderCategoryLinksUi(allCategories, categoryOrder);
    }
};

// View States
const orderState = { currentPage: 1, itemsPerPage: 20, searchTerm: '', statusFilter: 'All', dateYmd: '' };
const incompleteOrderState = { currentPage: 1, itemsPerPage: 25, searchTerm: '' };
let currentOrderDetailId = null;

// Session Replay (Live Monitor)
let sessionReplayState = { events: [], currentIndex: 0, isPlaying: false, speed: 1, timerId: null, visitorId: null };

// ============================================================
// 3. INITIALIZATION LOGIC
// ============================================================

/** Ensures localStorage siteInfo.clientId matches an admin record for the signed-in Firebase user. */
async function verifySiteInfoAuthorizedAdmin(user) {
    if (!user || !SITE_INFO?.clientId) return false;
    const adminSnap = await get(ref(db, `clients/${SITE_INFO.clientId}/admins/${user.uid}`));
    return adminSnap.exists();
}

function hydrateAdminAccessFromRecord(val) {
    currentAdminAccess.record = val && typeof val === 'object' ? val : null;
    currentAdminAccess.accessLoaded = true;
    currentAdminAccess.effectiveRole = resolveEffectiveDashboardRoleFromAdminNode(currentAdminAccess.record);
    const r = currentAdminAccess.record;
    currentAdminAccess.permissions = r && r.permissions && typeof r.permissions === 'object' ? r.permissions : null;
}

function isDashboardStoreOwner() {
    return !!currentAdminAccess.accessLoaded && currentAdminAccess.effectiveRole === 'owner';
}

function hasDashboardFullPanelAccess() {
    return !!currentAdminAccess.accessLoaded && currentAdminAccess.effectiveRole === 'owner';
}

function isDashboardPanelAccessAllowed(panelIdRaw) {
    const panelId = normalizePanelId(panelIdRaw);
    if (panelId === 'home') return true;
    if (!currentAdminAccess.accessLoaded) return false;
    if (panelId === 'theme') return isDashboardPanelAccessAllowed('customization');
    if (panelId === 'order-detail') return isDashboardPanelAccessAllowed('completed-orders');
    if (hasDashboardFullPanelAccess()) return true;
    return staffHasStrictPanelPermission(currentAdminAccess.record, panelId);
}

/** Global search: hide destinations the current admin cannot open (hash / SPA + order/product jumps). */
function isAdminSearchResultAccessAllowed(result) {
    if (!result || typeof result !== 'object') return false;
    if (!currentAdminAccess.accessLoaded) return false;
    if (result.actionType === 'openOrder' && result.orderId) {
        return isDashboardPanelAccessAllowed('completed-orders');
    }
    const pid = normalizePanelId(result.panelId || 'home');
    return isDashboardPanelAccessAllowed(pid);
}

function applySidebarPermissionVisibility() {
    document.querySelectorAll('[data-panel], [data-staff-perm-panel]').forEach((el) => {
        const rawPanel = el.dataset && el.dataset.panel ? String(el.dataset.panel) : '';
        const rawStaff = el.dataset && el.dataset.staffPermPanel ? String(el.dataset.staffPermPanel) : '';
        const raw = rawPanel || rawStaff;
        if (!raw) return;
        const pid = normalizePanelId(raw);
        if (isDashboardPanelAccessAllowed(pid)) {
            el.classList.remove('dashboard-permission-denied');
        } else {
            el.classList.add('dashboard-permission-denied');
        }
    });
}

async function refreshCurrentAdminAccessRecord(user) {
    if (!user || !CURRENT_CLIENT_ID) {
        currentAdminAccess = { record: null, effectiveRole: 'unknown', permissions: null, accessLoaded: false };
        return;
    }
    const snap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/admins/${user.uid}`));
    const val = snap.exists() ? snap.val() : null;
    hydrateAdminAccessFromRecord(val);
}

function attachCurrentAdminAccessListener(user) {
    if (adminAccessUnsub) {
        adminAccessUnsub();
        adminAccessUnsub = null;
    }
    if (!user || !CURRENT_CLIENT_ID) return;
    const r = ref(db, `clients/${CURRENT_CLIENT_ID}/admins/${user.uid}`);
    adminAccessUnsub = onValue(r, (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/admins/${user.uid}`, 'onValue', snap);
        const val = snap.exists() ? snap.val() : null;
        hydrateAdminAccessFromRecord(val);
        applySidebarPermissionVisibility();
        syncAdminTeamSidebarVisibility();
    });
}

async function tenantAdminApiPost(path, payload) {
    const user = auth.currentUser;
    if (!user) throw new Error('Not signed in');
    const idToken = await user.getIdToken();
    const res = await fetch(`${TENANT_ADMIN_API_BASE}${path}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ ...payload, idToken }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok || data.status === 'error') {
        const msg = data.message || data.error || `Request failed (${res.status})`;
        throw new Error(msg);
    }
    return data;
}

function syncAdminTeamSidebarVisibility() {
    const btn = document.getElementById('sidebar-admin-team-btn');
    if (btn) {
        if (isDashboardStoreOwner()) btn.classList.remove('hidden');
        else btn.classList.add('hidden');
    }
    const section = document.getElementById('admin-team-section');
    if (section) {
        if (isDashboardStoreOwner()) section.classList.remove('hidden');
        else section.classList.add('hidden');
    }
}

function buildAdminPermissionCheckboxGrid() {
    const host = document.getElementById('admin-permission-checkboxes');
    if (!host || host.dataset.built === '1') return;
    host.dataset.built = '1';
    host.className = 'grid grid-cols-1 sm:grid-cols-2 gap-2 text-left max-h-48 overflow-y-auto pr-1';
    TENANT_ADMIN_PANEL_META.forEach((meta) => {
        if (meta.locked) return;
        const id = `admin-perm-${meta.id}`;
        const wrap = document.createElement('label');
        wrap.className = 'flex items-start gap-2 text-sm text-black cursor-pointer';
        wrap.innerHTML = `<input type="checkbox" class="mt-0.5 admin-perm-cb" data-perm-panel="${meta.id}" id="${id}">
            <span>${meta.label}</span>`;
        host.appendChild(wrap);
    });
}

function readAdminPermissionSelectionsFromDom() {
    /** @type {Record<string, boolean>} */
    const out = { home: true };
    document.querySelectorAll('.admin-perm-cb').forEach((cb) => {
        if (!(cb instanceof HTMLInputElement)) return;
        const pid = cb.dataset.permPanel;
        if (pid) out[pid] = !!cb.checked;
    });
    return out;
}

function writeAdminPermissionSelectionsToDom(map) {
    const m = map && typeof map === 'object' ? map : {};
    document.querySelectorAll('.admin-perm-cb').forEach((cb) => {
        if (!(cb instanceof HTMLInputElement)) return;
        const pid = cb.dataset.permPanel;
        if (!pid) return;
        cb.checked = m[pid] === true;
    });
}

function resetAdminInviteForm() {
    adminTeamEditingUid = null;
    const email = document.getElementById('admin-invite-email');
    const pass = document.getElementById('admin-invite-password');
    const rowE = document.getElementById('admin-invite-email-row');
    const rowP = document.getElementById('admin-invite-password-row');
    const sub = document.getElementById('admin-invite-submit-btn');
    const save = document.getElementById('admin-permission-save-btn');
    const title = document.getElementById('admin-team-form-title');
    if (email) email.value = '';
    if (pass) pass.value = '';
    if (rowE) rowE.classList.remove('hidden');
    if (rowP) rowP.classList.remove('hidden');
    if (sub) sub.classList.remove('hidden');
    if (save) save.classList.add('hidden');
    if (title) title.textContent = 'Invite staff (email + sections)';
    writeAdminPermissionSelectionsToDom({});
}

async function loadAdminTeamTable() {
    const tbody = document.getElementById('admin-team-list-body');
    if (!tbody || !isDashboardStoreOwner() || !SITE_INFO?.clientId) return;
    tbody.innerHTML = '<tr><td colspan="4" class="py-2 text-sm text-gray-500">Loading…</td></tr>';
    try {
        const data = await tenantAdminApiPost('tenant-admin-list.php', { clientId: SITE_INFO.clientId });
        const admins = data.admins && typeof data.admins === 'object' ? data.admins : {};
        const rows = Object.keys(admins).map((uid) => {
            const a = admins[uid];
            const eff = resolveEffectiveDashboardRoleFromAdminNode(a);
            const role = eff === 'owner' ? 'owner' : (a && a.role != null && String(a.role).trim() !== '' ? String(a.role) : eff);
            const em = a && a.email ? String(a.email) : '—';
            const perms = a && a.permissions && typeof a.permissions === 'object' ? a.permissions : null;
            const trueCount = perms ? Object.keys(perms).filter((k) => perms[k] === true).length : 0;
            const accessLabel = eff === 'owner' ? 'Full' : (trueCount ? `${trueCount} sections` : 'No sections');
            const canRemove = eff === 'staff';
            return `<tr class="border-b border-black/10">
                <td class="py-2 pr-2 text-sm font-medium">${em}</td>
                <td class="py-2 pr-2 text-sm">${role}</td>
                <td class="py-2 pr-2 text-xs text-gray-600">${accessLabel}</td>
                <td class="py-2 text-right text-sm whitespace-nowrap">
                    <button type="button" class="text-indigo-600 font-semibold hover:underline admin-team-edit-btn" data-uid="${uid}">Edit</button>
                    ${canRemove ? `<button type="button" class="ml-2 text-red-600 font-semibold hover:underline admin-team-remove-btn" data-uid="${uid}">Remove</button>` : ''}
                </td>
            </tr>`;
        });
        tbody.innerHTML = rows.length ? rows.join('') : '<tr><td colspan="4" class="py-2 text-sm text-gray-500">No admins loaded.</td></tr>';
    } catch (e) {
        tbody.innerHTML = `<tr><td colspan="4" class="py-2 text-sm text-red-600">${e && e.message ? String(e.message) : 'Failed to load'}</td></tr>`;
    }
}

function openProfileModalWithAdminPrep() {
    const emailEl = document.getElementById('profile-email-display');
    const user = auth.currentUser;
    if (emailEl) {
        if (user?.email) emailEl.textContent = user.email;
        else if (SITE_INFO) {
            emailEl.textContent = (SITE_INFO.siteName || SITE_INFO.subdomain || 'Store') + ' (Custom login)';
        } else {
            emailEl.textContent = 'Not signed in';
        }
    }
    buildAdminPermissionCheckboxGrid();
    syncAdminTeamSidebarVisibility();
    if (isDashboardStoreOwner()) {
        resetAdminInviteForm();
        loadAdminTeamTable();
    }
    UI.toggleModal('profile-modal', true);
}

function bindAdminTeamManagementUi() {
    if (window.__adminTeamUiBound) return;
    window.__adminTeamUiBound = true;

    document.getElementById('profile-sidebar-btn')?.addEventListener('click', (e) => {
        e.preventDefault();
        openProfileModalWithAdminPrep();
        if (window.innerWidth < 768) UI.toggleSidebar(false);
    });
    document.getElementById('sidebar-admin-team-btn')?.addEventListener('click', (e) => {
        e.preventDefault();
        openProfileModalWithAdminPrep();
        const el = document.getElementById('admin-team-section');
        el?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
        if (window.innerWidth < 768) UI.toggleSidebar(false);
    });

    document.getElementById('admin-invite-cancel-edit-btn')?.addEventListener('click', () => resetAdminInviteForm());

    document.getElementById('admin-invite-submit-btn')?.addEventListener('click', async () => {
        if (!SITE_INFO?.clientId) return;
        const email = document.getElementById('admin-invite-email')?.value?.trim();
        const password = document.getElementById('admin-invite-password')?.value || '';
        const perms = readAdminPermissionSelectionsFromDom();
        const keys = Object.keys(perms).filter((k) => perms[k] && k !== 'home');
        if (keys.length === 0) {
            UI.showToast('Select at least one section besides Home.', false);
            return;
        }
        if (!email || !password) {
            UI.showToast('Email and password are required.', false);
            return;
        }
        try {
            await tenantAdminApiPost('tenant-admin-create.php', {
                clientId: SITE_INFO.clientId,
                newEmail: email,
                newPassword: password,
                permissions: perms,
                siteSubdomain: SITE_INFO.subdomain || '',
                siteDisplayName: SITE_INFO.siteName || SITE_INFO.subdomain || '',
            });
            UI.showToast('Staff admin invited.', true);
            resetAdminInviteForm();
            await loadAdminTeamTable();
        } catch (err) {
            UI.showToast(err && err.message ? String(err.message) : 'Invite failed', false);
        }
    });

    document.getElementById('admin-permission-save-btn')?.addEventListener('click', async () => {
        if (!adminTeamEditingUid || !SITE_INFO?.clientId) return;
        const perms = readAdminPermissionSelectionsFromDom();
        const keys = Object.keys(perms).filter((k) => perms[k] && k !== 'home');
        if (keys.length === 0) {
            UI.showToast('Select at least one section besides Home.', false);
            return;
        }
        try {
            await tenantAdminApiPost('tenant-admin-update.php', {
                clientId: SITE_INFO.clientId,
                targetUid: adminTeamEditingUid,
                permissions: perms,
            });
            UI.showToast('Permissions updated.', true);
            resetAdminInviteForm();
            await loadAdminTeamTable();
        } catch (err) {
            UI.showToast(err && err.message ? String(err.message) : 'Update failed', false);
        }
    });

    document.getElementById('admin-team-list-body')?.addEventListener('click', async (e) => {
        const t = e.target;
        if (!(t instanceof Element)) return;
        const edit = t.closest('.admin-team-edit-btn');
        const rem = t.closest('.admin-team-remove-btn');
        if (edit instanceof HTMLButtonElement) {
            const uid = edit.dataset.uid;
            if (!uid) return;
            adminTeamEditingUid = uid;
            const rowE = document.getElementById('admin-invite-email-row');
            const rowP = document.getElementById('admin-invite-password-row');
            const sub = document.getElementById('admin-invite-submit-btn');
            const save = document.getElementById('admin-permission-save-btn');
            const title = document.getElementById('admin-team-form-title');
            if (rowE) rowE.classList.add('hidden');
            if (rowP) rowP.classList.add('hidden');
            if (sub) sub.classList.add('hidden');
            if (save) save.classList.remove('hidden');
            if (title) title.textContent = 'Edit section access';
            try {
                const data = await tenantAdminApiPost('tenant-admin-list.php', { clientId: SITE_INFO.clientId });
                const a = data.admins && data.admins[uid];
                writeAdminPermissionSelectionsToDom(a && a.permissions ? a.permissions : {});
            } catch (err) {
                UI.showToast(err && err.message ? String(err.message) : 'Load failed', false);
            }
            return;
        }
        if (rem instanceof HTMLButtonElement) {
            const uid = rem.dataset.uid;
            if (!uid || !confirm('Remove this staff admin from the store?')) return;
            try {
                await tenantAdminApiPost('tenant-admin-remove.php', { clientId: SITE_INFO.clientId, targetUid: uid });
                UI.showToast('Removed from store.', true);
                await loadAdminTeamTable();
            } catch (err) {
                UI.showToast(err && err.message ? String(err.message) : 'Remove failed', false);
            }
        }
    });
}

function escapeHtmlTextLocal(s) {
    return String(s ?? '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');
}

const RECOMMENDED_PRODUCTS_SAVE_CAP = 24;
const CBS_CATEGORY_SAVE_CAP = 12;
/** Home page design — main content category rows: manual multi-tab vs catalog category rows. */
const HOME_MANUAL_TABS_MAX = 10;
const HOME_MANUAL_TAB_PRODUCTS_CAP = 24;

function generateHomeManualTabRowId() {
    return `hctr_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
}

function buildHomeCatRowTabEditorHtml(tab, allProducts) {
    const tidRaw = String(tab.id || '').trim() || generateHomeManualTabRowId();
    const tidEsc = escapeHtmlTextLocal(tidRaw);
    const labelRaw = tab.label != null ? String(tab.label) : '';
    const labelEsc = escapeHtmlTextLocal(labelRaw);
    const maxM = parseInt(tab.maxItems, 10);
    const maxItems = Number.isFinite(maxM) ? Math.min(24, Math.max(1, maxM)) : 10;
    const selected = new Set(
        (Array.isArray(tab.productIds) ? tab.productIds : []).map((x) => String(x || '').trim()).filter(Boolean)
    );
    const entries = Object.entries(allProducts || {}).sort((a, b) =>
        String(a[1].name || '').localeCompare(String(b[1].name || ''), undefined, { sensitivity: 'base' })
    );
    let boxes = '';
    if (!entries.length) {
        boxes = '<p class="text-xs text-black p-2">No products yet. Add products in the Products panel.</p>';
    } else {
        boxes = entries
            .map(([id, p]) => {
                const sid = String(id);
                const checked = selected.has(sid) ? ' checked' : '';
                const name = escapeHtmlTextLocal(p.name || 'Product');
                const img = escapeHtmlTextLocal(p.imageUrl || '');
                const nameNorm = escapeHtmlTextLocal(String(p.name || '').toLowerCase());
                return `<label class="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-50 cursor-pointer border border-transparent hover:border-gray-200 home-cat-rows-prod-row" data-hctr-prod-row="1" data-name-norm="${nameNorm}">
                <input type="checkbox" class="home-cat-rows-prod-cb h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" data-product-id="${escapeHtmlTextLocal(sid)}"${checked}>
                <img src="${img}" alt="" class="w-9 h-9 object-contain rounded border bg-white flex-shrink-0" loading="lazy">
                <span class="text-sm text-black truncate flex-1 min-w-0">${name}</span>
            </label>`;
            })
            .join('');
    }
    return `<div class="rounded-xl border border-gray-200 bg-gray-50 p-3 space-y-2" data-home-tab-row="${tidEsc}">
        <div class="flex flex-wrap items-center justify-between gap-2">
            <input type="text" class="home-cat-rows-tab-label admin-form-input flex-1 min-w-[160px] !py-2" placeholder="ট্যাবের নাম (যেমন Hot deals)" value="${labelEsc}" maxlength="100" autocomplete="off">
            <div class="flex items-center gap-2 flex-shrink-0">
                <label class="text-xs text-black whitespace-nowrap">Max shown</label>
                <input type="number" class="home-cat-rows-tab-max admin-form-input !py-1 w-[4.5rem]" min="1" max="24" value="${maxItems}">
                <button type="button" class="home-cat-rows-remove-tab text-xs font-semibold text-red-600 hover:text-red-800 px-2 py-1 rounded border border-red-200 bg-white">মুছুন</button>
            </div>
        </div>
        <div>
            <label class="block text-xs font-medium text-black mb-1">Filter products</label>
            <input type="text" class="home-cat-rows-tab-filter admin-form-input w-full !py-2" placeholder="Type to filter…" autocomplete="off">
        </div>
        <div class="home-cat-rows-tab-checkboxes max-h-52 overflow-y-auto rounded-lg border border-gray-200 bg-white p-2 space-y-0.5 text-sm">${boxes}</div>
        <p class="text-xs text-black home-cat-rows-tab-hint">Selected: 0 / ${HOME_MANUAL_TAB_PRODUCTS_CAP}</p>
    </div>`;
}

function bindHomeCatRowTabRowListeners(rowEl) {
    const hintEl = rowEl.querySelector('.home-cat-rows-tab-hint');
    const wrap = rowEl.querySelector('.home-cat-rows-tab-checkboxes');
    const updateHint = () => {
        if (!hintEl || !wrap) return;
        const n = wrap.querySelectorAll('.home-cat-rows-prod-cb:checked').length;
        hintEl.textContent = `Selected: ${n} / ${HOME_MANUAL_TAB_PRODUCTS_CAP}`;
    };
    if (wrap) {
        wrap.querySelectorAll('.home-cat-rows-prod-cb').forEach((cb) => {
            cb.addEventListener('change', () => {
                if (cb.checked) {
                    const allChecked = wrap.querySelectorAll('.home-cat-rows-prod-cb:checked');
                    if (allChecked.length > HOME_MANUAL_TAB_PRODUCTS_CAP) {
                        cb.checked = false;
                        try {
                            UI.showToast(`You can select at most ${HOME_MANUAL_TAB_PRODUCTS_CAP} products per tab.`, false);
                        } catch (_) { /* noop */ }
                    }
                }
                updateHint();
            });
        });
    }
    const filterInp = rowEl.querySelector('.home-cat-rows-tab-filter');
    if (filterInp && !filterInp.dataset.hctrFilterBound) {
        filterInp.dataset.hctrFilterBound = '1';
        filterInp.addEventListener('input', () => {
            const q = filterInp.value.toLowerCase().trim();
            rowEl.querySelectorAll('[data-hctr-prod-row]').forEach((r) => {
                const norm = String(r.getAttribute('data-name-norm') || '').toLowerCase();
                r.classList.toggle('hidden', !!(q && !norm.includes(q)));
            });
        });
    }
    updateHint();
}

function syncHomeCatRowsDefaultTabSelect() {
    const sel = document.getElementById('home-cat-rows-default-tab');
    const editor = document.getElementById('home-cat-rows-tabs-editor');
    if (!sel || !editor) return;
    const rows = Array.from(editor.querySelectorAll('[data-home-tab-row]'));
    const prev = sel.value;
    sel.innerHTML = '<option value="">— প্রথম ট্যাব —</option>';
    rows.forEach((row) => {
        const id = row.getAttribute('data-home-tab-row') || '';
        const labInp = row.querySelector('.home-cat-rows-tab-label');
        const lab = (labInp && labInp.value.trim()) || id || 'Tab';
        const opt = document.createElement('option');
        opt.value = id;
        opt.textContent = lab.length > 48 ? `${lab.slice(0, 46)}…` : lab;
        sel.appendChild(opt);
    });
    const still = [...sel.options].some((o) => o.value === prev);
    sel.value = still ? prev : '';
}

function refreshHomeCategoryRowsSectionDashboardControls() {
    const editor = document.getElementById('home-cat-rows-tabs-editor');
    const modeCategoryEl = document.getElementById('home-cat-rows-mode-category');
    const modeManualEl = document.getElementById('home-cat-rows-mode-manual');
    const manualPanel = document.getElementById('home-cat-rows-manual-panel');
    const titleEl = document.getElementById('home-cat-rows-manual-title');
    const modeWrap = document.getElementById('home-cat-rows-mode-wrap');
    const capHint = document.getElementById('home-cat-rows-tabs-cap-hint');
    if (capHint) capHint.textContent = String(HOME_MANUAL_TABS_MAX);
    if (!editor || !modeCategoryEl || !modeManualEl) return;

    const hcrs =
        siteSettings && siteSettings.layout && siteSettings.layout.homeCategoryRowsSection
            ? siteSettings.layout.homeCategoryRowsSection
            : {};
    const isManual = hcrs.mode === 'manualTabs';
    modeCategoryEl.checked = !isManual;
    modeManualEl.checked = isManual;
    if (manualPanel) manualPanel.classList.toggle('hidden', !isManual);
    if (titleEl) {
        titleEl.value =
            hcrs.manualTitle != null && String(hcrs.manualTitle).trim() !== ''
                ? String(hcrs.manualTitle).trim()
                : '';
    }

    let tabs = Array.isArray(hcrs.manualTabs) ? hcrs.manualTabs : [];
    tabs = tabs
        .map((t) => ({
            id: String(t && t.id != null ? t.id : '').trim() || generateHomeManualTabRowId(),
            label: t && t.label != null ? String(t.label) : '',
            maxItems: t && t.maxItems != null ? t.maxItems : 10,
            productIds: Array.isArray(t && t.productIds) ? t.productIds : []
        }))
        .filter((t) => t.id);
    if (!tabs.length) {
        tabs = [{ id: generateHomeManualTabRowId(), label: '', maxItems: 10, productIds: [] }];
    }
    if (tabs.length > HOME_MANUAL_TABS_MAX) tabs = tabs.slice(0, HOME_MANUAL_TABS_MAX);

    editor.innerHTML = tabs.map((t) => buildHomeCatRowTabEditorHtml(t, allProducts)).join('');
    editor.querySelectorAll('[data-home-tab-row]').forEach((row) => bindHomeCatRowTabRowListeners(row));
    syncHomeCatRowsDefaultTabSelect();
    const defRaw = String(hcrs.defaultManualTabId || '').trim();
    const defSel = document.getElementById('home-cat-rows-default-tab');
    if (defSel && defRaw && [...defSel.options].some((o) => o.value === defRaw)) {
        defSel.value = defRaw;
    }

    if (modeWrap && !modeWrap.dataset.hctrModeBound) {
        modeWrap.dataset.hctrModeBound = '1';
        modeWrap.addEventListener('change', (e) => {
            if (!e.target.matches('input[name="home-cat-rows-mode"]')) return;
            const manual = !!document.getElementById('home-cat-rows-mode-manual')?.checked;
            document.getElementById('home-cat-rows-manual-panel')?.classList.toggle('hidden', !manual);
        });
    }

    const manualPanelEl = document.getElementById('home-cat-rows-manual-panel');
    if (manualPanelEl && !manualPanelEl.dataset.hctrPanelBound) {
        manualPanelEl.dataset.hctrPanelBound = '1';
        manualPanelEl.addEventListener('click', (e) => {
            const addBtn = e.target.closest('#home-cat-rows-add-tab');
            if (addBtn) {
                const ed = document.getElementById('home-cat-rows-tabs-editor');
                if (!ed) return;
                const n = ed.querySelectorAll('[data-home-tab-row]').length;
                if (n >= HOME_MANUAL_TABS_MAX) {
                    try {
                        UI.showToast(`You can add at most ${HOME_MANUAL_TABS_MAX} tabs.`, false);
                    } catch (_) { /* noop */ }
                    return;
                }
                const newTab = { id: generateHomeManualTabRowId(), label: '', maxItems: 10, productIds: [] };
                ed.insertAdjacentHTML('beforeend', buildHomeCatRowTabEditorHtml(newTab, allProducts));
                const last = ed.querySelector('[data-home-tab-row]:last-of-type');
                if (last) bindHomeCatRowTabRowListeners(last);
                syncHomeCatRowsDefaultTabSelect();
                return;
            }
            const rm = e.target.closest('.home-cat-rows-remove-tab');
            if (rm) {
                const row = rm.closest('[data-home-tab-row]');
                const ed = document.getElementById('home-cat-rows-tabs-editor');
                if (!row || !ed) return;
                const n = ed.querySelectorAll('[data-home-tab-row]').length;
                if (n <= 1) {
                    try {
                        UI.showToast('At least one tab is required.', false);
                    } catch (_) { /* noop */ }
                    return;
                }
                row.remove();
                syncHomeCatRowsDefaultTabSelect();
            }
        });
        manualPanelEl.addEventListener('input', (e) => {
            const lab = e.target.closest('.home-cat-rows-tab-label');
            if (lab) syncHomeCatRowsDefaultTabSelect();
        });
    }
}
window.refreshHomeCategoryRowsSectionDashboardControls = refreshHomeCategoryRowsSectionDashboardControls;

/** Home page design — Category + banner strip after Recommended (Classic). */
function refreshCategoryBannerSectionDashboardControls() {
    const wrap = document.getElementById('cbs-category-checkboxes');
    const enabledEl = document.getElementById('cbs-enabled');
    const titleEl = document.getElementById('cbs-section-title');
    const maxEl = document.getElementById('cbs-max-products');
    const defaultSel = document.getElementById('cbs-default-category');
    const hintEl = document.getElementById('cbs-category-hint');
    const imgEl = document.getElementById('cbs-banner-image-url');
    const linkEl = document.getElementById('cbs-banner-link-url');
    const altEl = document.getElementById('cbs-banner-alt');
    const hideEmptyEl = document.getElementById('cbs-hide-when-no-products');
    if (!wrap || !enabledEl) return;

    const cbs =
        siteSettings && siteSettings.layout && siteSettings.layout.categoryBannerSection
            ? siteSettings.layout.categoryBannerSection
            : {};
    enabledEl.checked = cbs.enabled === true;
    if (titleEl) titleEl.value = cbs.title != null && String(cbs.title).trim() !== '' ? String(cbs.title).trim() : '';
    if (maxEl) {
        const m = parseInt(cbs.maxProductsPerCategory, 10);
        maxEl.value = Number.isFinite(m) && m >= 1 && m <= 24 ? String(m) : '10';
    }
    if (imgEl) imgEl.value = cbs.bannerImageUrl != null && String(cbs.bannerImageUrl).trim() !== '' ? String(cbs.bannerImageUrl).trim() : '';
    if (imgEl && typeof UI.updateImagePreview === 'function') {
        UI.updateImagePreview('#cbs-banner-image-url', '#cbs-banner-image-preview');
    }
    if (imgEl && !imgEl.dataset.cbsPreviewBound) {
        imgEl.dataset.cbsPreviewBound = '1';
        imgEl.addEventListener('input', () => {
            if (typeof UI.updateImagePreview === 'function') {
                UI.updateImagePreview('#cbs-banner-image-url', '#cbs-banner-image-preview');
            }
        });
    }
    if (linkEl) linkEl.value = cbs.bannerLinkUrl != null && String(cbs.bannerLinkUrl).trim() !== '' ? String(cbs.bannerLinkUrl).trim() : '';
    if (altEl) altEl.value = cbs.bannerAlt != null && String(cbs.bannerAlt).trim() !== '' ? String(cbs.bannerAlt).trim() : '';
    if (hideEmptyEl) hideEmptyEl.checked = cbs.hideWhenNoProducts !== false;

    const savedNames = new Set(
        (Array.isArray(cbs.categoryNames) ? cbs.categoryNames : []).map((x) => String(x || '').trim()).filter(Boolean)
    );
    const orderedIds = (Array.isArray(categoryOrder) ? categoryOrder : []).filter((id) => allCategories && allCategories[id]);

    if (!orderedIds.length) {
        wrap.innerHTML = '<p class="text-xs text-black p-3">No categories yet. Add categories in the Categories panel.</p>';
    } else {
        wrap.innerHTML = orderedIds
            .map((id) => {
                const cat = allCategories[id];
                const name = String(cat?.name || '').trim();
                if (!name) return '';
                const checked = savedNames.has(name) ? ' checked' : '';
                const nameEsc = escapeHtmlTextLocal(name);
                const idEsc = escapeHtmlTextLocal(String(id));
                return `<label class="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-50 cursor-pointer border border-transparent hover:border-gray-200">
                <input type="checkbox" name="cbs-category" value="${idEsc}" data-cat-name="${nameEsc}" class="cbs-category-cb h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"${checked}>
                <span class="text-sm text-black truncate flex-1 min-w-0">${nameEsc}</span>
            </label>`;
            })
            .filter(Boolean)
            .join('');
    }

    const syncDefaultDropdown = () => {
        if (!defaultSel) return;
        const selectedNames = orderedIds
            .map((id) => {
                const cb = Array.from(wrap.querySelectorAll('input[name="cbs-category"]')).find((el) => el.value === String(id));
                return cb && cb.checked ? String(allCategories[id]?.name || '').trim() : '';
            })
            .filter(Boolean);
        const currentVal = String(cbs.defaultCategoryName || '').trim();
        defaultSel.innerHTML =
            '<option value="">— First selected / first with stock —</option>' +
            selectedNames
                .map((n) => `<option value="${escapeHtmlTextLocal(n)}">${escapeHtmlTextLocal(n)}</option>`)
                .join('');
        if (currentVal && selectedNames.includes(currentVal)) defaultSel.value = currentVal;
        else defaultSel.value = '';
    };

    const updateHint = () => {
        if (!hintEl) return;
        const n = wrap.querySelectorAll('input[name="cbs-category"]:checked').length;
        hintEl.textContent = `Selected: ${n} / ${CBS_CATEGORY_SAVE_CAP}`;
    };

    wrap.querySelectorAll('input[name="cbs-category"]').forEach((cb) => {
        cb.addEventListener('change', () => {
            if (cb.checked) {
                const allChecked = wrap.querySelectorAll('input[name="cbs-category"]:checked');
                if (allChecked.length > CBS_CATEGORY_SAVE_CAP) {
                    cb.checked = false;
                    try {
                        UI.showToast(`You can select at most ${CBS_CATEGORY_SAVE_CAP} categories.`, false);
                    } catch (_) { /* noop */ }
                }
            }
            updateHint();
            syncDefaultDropdown();
        });
    });
    updateHint();
    syncDefaultDropdown();
}
window.refreshCategoryBannerSectionDashboardControls = refreshCategoryBannerSectionDashboardControls;

/** Optional Content tab — curated Classic homepage "Recommended For You" carousel. */
function refreshRecommendedForYouDashboardControls() {
    const wrap = document.getElementById('recommended-product-checkboxes');
    const enabledEl = document.getElementById('recommended-enabled');
    const titleEl = document.getElementById('recommended-title');
    const maxEl = document.getElementById('recommended-max-items');
    const hintEl = document.getElementById('recommended-selection-hint');
    if (!wrap || !enabledEl) return;

    const rs =
        siteSettings && siteSettings.layout && siteSettings.layout.recommendedSection
            ? siteSettings.layout.recommendedSection
            : {};
    enabledEl.checked = rs.enabled === true;
    if (titleEl) {
        titleEl.value =
            rs.title != null && String(rs.title).trim() !== '' ? String(rs.title).trim() : 'Recommended For You';
    }
    if (maxEl) {
        const m = parseInt(rs.maxItems, 10);
        maxEl.value = Number.isFinite(m) && m >= 1 && m <= 24 ? String(m) : '12';
    }

    const fallbackNoneEl = document.getElementById('recommended-fallback-none');
    const fallbackFeaturedEl = document.getElementById('recommended-fallback-featured');
    if (rs.fallbackWhenDisabled === 'featuredProducts') {
        if (fallbackFeaturedEl) fallbackFeaturedEl.checked = true;
    } else if (fallbackNoneEl) {
        fallbackNoneEl.checked = true;
    }
    const fallbackTitleEl = document.getElementById('recommended-fallback-title');
    if (fallbackTitleEl) {
        fallbackTitleEl.value =
            rs.fallbackTitle != null && String(rs.fallbackTitle).trim() !== ''
                ? String(rs.fallbackTitle).trim()
                : '';
    }
    const suppressEl = document.getElementById('recommended-suppress-main-flash');
    if (suppressEl) suppressEl.checked = rs.suppressMainFlashWhenRecommendedFallback !== false;

    const selected = new Set(
        (Array.isArray(rs.productIds) ? rs.productIds : []).map((x) => String(x || '').trim()).filter(Boolean)
    );

    const entries = Object.entries(allProducts || {}).sort((a, b) =>
        String(a[1].name || '').localeCompare(String(b[1].name || ''), undefined, { sensitivity: 'base' })
    );
    if (!entries.length) {
        wrap.innerHTML =
            '<p class="text-xs text-black p-3">No products yet. Add products in the Products panel.</p>';
    } else {
        wrap.innerHTML = entries
            .map(([id, p]) => {
                const sid = String(id);
                const checked = selected.has(sid) ? ' checked' : '';
                const name = escapeHtmlTextLocal(p.name || 'Product');
                const img = escapeHtmlTextLocal(p.imageUrl || '');
                const nameNorm = escapeHtmlTextLocal(String(p.name || '').toLowerCase());
                return `<label class="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-50 cursor-pointer border border-transparent hover:border-gray-200 recommended-product-row" data-recommended-row="1" data-name-norm="${nameNorm}">
                <input type="checkbox" name="recommended-product" value="${escapeHtmlTextLocal(sid)}" class="recommended-product-cb h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"${checked}>
                <img src="${img}" alt="" class="w-9 h-9 object-contain rounded border bg-white flex-shrink-0" loading="lazy">
                <span class="text-sm text-black truncate flex-1 min-w-0">${name}</span>
            </label>`;
            })
            .join('');
    }

    const updateHint = () => {
        if (!hintEl) return;
        const n = wrap.querySelectorAll('input[name="recommended-product"]:checked').length;
        hintEl.textContent = `Selected: ${n} / ${RECOMMENDED_PRODUCTS_SAVE_CAP} saved IDs (storefront shows up to max above).`;
    };

    wrap.querySelectorAll('input[name="recommended-product"]').forEach((cb) => {
        cb.addEventListener('change', () => {
            if (cb.checked) {
                const allChecked = wrap.querySelectorAll('input[name="recommended-product"]:checked');
                if (allChecked.length > RECOMMENDED_PRODUCTS_SAVE_CAP) {
                    cb.checked = false;
                    try {
                        UI.showToast(`You can select at most ${RECOMMENDED_PRODUCTS_SAVE_CAP} products.`, false);
                    } catch (_) { /* noop */ }
                }
            }
            updateHint();
        });
    });
    updateHint();

    const filterInp = document.getElementById('recommended-product-filter');
    if (filterInp && !filterInp.dataset.recommendedFilterBound) {
        filterInp.dataset.recommendedFilterBound = '1';
        filterInp.addEventListener('input', () => {
            const q = filterInp.value.toLowerCase().trim();
            wrap.querySelectorAll('[data-recommended-row]').forEach((row) => {
                const norm = String(row.getAttribute('data-name-norm') || '').toLowerCase();
                row.classList.toggle('hidden', !!(q && !norm.includes(q)));
            });
        });
    }
}
window.refreshRecommendedForYouDashboardControls = refreshRecommendedForYouDashboardControls;

/** Decorative minified-looking JS (not executed meaningfully; bundle noise for export package). */
function buildFakeMinifiedRuntimeChunk(seed) {
    const s = String(seed || '0').replace(/\D/g, '').slice(0, 8) || '0';
    return `!function(e,t){"use strict";var n=${JSON.stringify(s)},r=function(e){return void 0===e?null:e},o={version:"2.4.0",buildHash:"b7f9c2a1e4d8",hydrate:function(){try{window.__SB_RUNTIME__=Object.assign({},window.__SB_RUNTIME__||{},{seed:n,ts:Date.now()})}catch(e){}}};o.hydrate(),e.__SB_BOOT__=o}(window,document);`;
}

function generateIframeExportHtml(iframeSrc, pageTitle) {
    const fakeBundle = buildFakeMinifiedRuntimeChunk(String(pageTitle).length + String(iframeSrc).length);
    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="generator" content="CommerceShell/2.4 (production)">
  <title>${escapeHtmlTextLocal(pageTitle)}</title>
  <style>
    html,body{margin:0;padding:0;width:100%;height:100%;overflow:hidden;background:#0a0a0a;color:#e5e7eb;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif}
    #root,#__app_mount{position:fixed;inset:0;overflow:hidden;isolation:isolate}
    .__runtime_shell{position:absolute;inset:0;display:flex;flex-direction:column}
    .__runtime_shell iframe{width:100%;height:100%;border:0;display:block;flex:1;min-height:0;background:#000}
    .__boot_overlay{pointer-events:none;position:absolute;inset:0;opacity:0;animation:none}
  </style>
</head>
<body>
  <div id="root">
    <div id="__app_mount" class="__runtime_shell">
      <iframe
        src="${escapeHtmlTextLocal(iframeSrc)}"
        title="${escapeHtmlTextLocal(pageTitle)}"
        loading="eager"
        referrerpolicy="no-referrer-when-downgrade"
        allow="fullscreen; camera; microphone"
        allowfullscreen>
      </iframe>
    </div>
  </div>
  <div class="__boot_overlay" aria-hidden="true"></div>
  <script>${fakeBundle}<\/script>
</body>
</html>`;
}

/** Download helper: pass a string or an existing Blob (e.g. zip from JSZip). */
function downloadTextFile(filename, contentOrBlob, mimeType = 'text/html;charset=utf-8') {
    const blob = contentOrBlob instanceof Blob
        ? contentOrBlob
        : new Blob([typeof contentOrBlob === 'string' ? contentOrBlob : String(contentOrBlob)], { type: mimeType });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    a.remove();
    setTimeout(() => URL.revokeObjectURL(url), 1200);
}

function sanitizeExportZipBaseName(siteName) {
    return String(siteName || 'Store')
        .trim()
        .replace(/[^a-zA-Z0-9-_]+/g, '_')
        .replace(/^_+|_+$/g, '')
        .slice(0, 48) || 'Store';
}

/** ~5200 lines: minified-looking vendor shim (decoy payload for export zip). */
function buildDummyVendorMinJs() {
    const lineCount = 5200;
    const lines = new Array(lineCount);
    const stamp = 'U0ItdmVuZG9yLXN0dWI'; // base64-ish ASCII
    for (let i = 0; i < lineCount; i++) {
        const h = (i * 1103515245 + 12345) >>> 0;
        lines[i] = `!function(g,j){g.__VENDOR_SEG__=g.__VENDOR_SEG__||{};g.__VENDOR_SEG__[${i % 127}]=(g.__VENDOR_SEG__[${i % 127}]^${h & 255})>>>0;void((g.__V_REG__=g.__V_REG__||[]).push(function(){return(${i}^j)>>>${i % 9}}));}(this,${i});/*${stamp}${i % 997}*/`;
    }
    return `/* vendor.min.js — production bundle (synthetic segments) */\n"use strict";\n${lines.join('\n')}\n`;
}

/** ~2200 lines: fake utility CSS (Tailwind-like noise). */
function buildDummyAppChunkCss() {
    const lineCount = 2200;
    const lines = new Array(lineCount + 4);
    lines[0] = '/* app.chunk.css — production extract (auto-generated) */';
    lines[1] = ':root{--sb-surface:#0f172a;--sb-accent:#6366f1;--sb-ring:0 0 0 3px rgba(99,102,241,.35)}';
    lines[2] = '#root{min-height:100vh;isolation:isolate}.__layout{contain:layout style paint}';
    for (let i = 0; i < lineCount; i++) {
        const n = i + 1;
        const r = (n * 13) % 200;
        const g = (n * 29) % 200;
        const b = (n * 47) % 200;
        lines[i + 3] = `.sb-u${n}{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:${(n % 6) + 2}px;padding:${(n % 12) + 4}px ${(n % 20) + 6}px;margin:${(n % 10)}px;color:rgb(${r},${g},${b});order:${n % 120};contain:layout;content-visibility:auto}`;
    }
    lines[lineCount + 3] = '/* end extract */';
    return lines.join('\n');
}

/** ~4500 lines: webpack/React-runtime style decoy JS. */
function buildDummyReactChunk(label) {
    const lineCount = 4500;
    const lines = new Array(lineCount + 3);
    lines[0] = `/**\n * main.chunk.js — ${label} (synthetic compile output)\n */`;
    lines[1] = '"use strict";';
    lines[2] = 'var __assign=Object.assign||function(t){for(var s=1;s<arguments.length;s++){var a=arguments[s];for(var k in a)if(Object.prototype.hasOwnProperty.call(a,k))t[k]=a[k];}return t;};';
    for (let i = 0; i < lineCount; i++) {
        const n = i + 1;
        lines[i + 3] = `exports.__mod_${n}=function(e,t,r){return e&&e.createElement?e.createElement("span",{key:${n},className:"_sb${n % 53}","data-i":${n}},(t||"")+"${label}",[${n}>>>1&511,${n}^${n}<<1,r]):null;};`;
    }
    return lines.join('\n');
}

/** ~4500 lines: Express-style middleware decoy (never imported; volume only). */
function buildDummyBackendCore(label) {
    const lineCount = 4500;
    const lines = new Array(lineCount + 4);
    lines[0] = '\'use strict\';';
    lines[1] = `/** server/controllers/core.js — ${label} (synthetic scaffold) */`;
    lines[2] = 'const crypto = require(\'crypto\');';
    lines[3] = 'const assert = require(\'assert\');';
    for (let i = 0; i < lineCount; i++) {
        const n = i + 1;
        lines[i + 4] = `exports.__mw_${n}=function(req,res,next){try{const _d=crypto.createHash('sha256').update(String(${n})+String(req.method||'')+(req.url||'')).digest('hex');req.locals=req.locals||{};req.locals['t${n}']=_d.slice(0,12);assert.ok(typeof next==='function');next();}catch(e){next(e);}};`;
    }
    return lines.join('\n');
}

/**
 * Builds a convincing multi-file project .zip (dummy MERN-style tree + real deployable public/index.html).
 * @param {string} iframeSrc Absolute URL for iframe src
 * @param {string} siteName Display / filename base
 * @param {'website'|'admin'} kind
 */
async function generateDummyProjectZip(iframeSrc, siteName, kind) {
    if (typeof window.JSZip !== 'function') {
        UI.showToast('ZIP library not loaded. Refresh the page and try again.', false);
        return;
    }
    const zip = new window.JSZip();
    const label = kind === 'admin' ? 'AdminConsole' : 'StoreFront';
    const titleSuffix = kind === 'admin' ? 'Admin Console' : 'Storefront';
    const publicHtml = generateIframeExportHtml(iframeSrc, `${siteName || 'Store'} — ${titleSuffix}`);

    zip.file('README.md', `# ${siteName || 'Store'} — ${label} source bundle (v2.4)

This repository contains the full application tree (client + server tooling).

## cPanel / shared hosting (recommended)

1. Extract the ZIP on your computer.
2. Upload **the entire extracted project** (all folders and files, including the hidden \`.htaccess\`) into your domain's \`public_html\` (or a subdirectory).
3. In cPanel File Manager, turn on **Show Hidden Files** so \`.htaccess\` is not skipped. The root \`.htaccess\` sends visitors to \`public/index.html\`, so you should **not** see an "Index of /" listing on your homepage.

If your host **does not allow** \`.htaccess\` or you get a **500** error after upload: remove \`.htaccess\` and instead upload **only the contents** of the \`public/\` folder into \`public_html\` (so \`index.html\` sits directly in the web root).

**Subfolder example** (\`public_html/mystore/\`): add a line \`RewriteBase /mystore/\` directly under \`RewriteEngine On\` in \`.htaccess\` (path must match your folder).

- Prefer **HTTPS** on your domain for best compatibility.
- Do not rename \`public/index.html\` unless your host requires a different default document.

## Optional (developers)

The \`server/\` and \`src/\` trees are for local development and CI builds. They are not required on basic shared hosting if you deploy the prebuilt \`public/\` output only (or use the full tree + root \`.htaccess\` as above).

---
Build: CommerceShell/2.4 | Package: ${label}
`);

    zip.file('.htaccess', `# CommerceShell — route document root to ./public/ (Apache / LiteSpeed)\n<IfModule mod_rewrite.c>\n    RewriteEngine On\n    # Already under /public/ — serve as-is\n    RewriteRule ^public/ - [L]\n    # Homepage\n    RewriteRule ^$ public/index.html [L]\n    # Other top-level paths (e.g. /css/...) -> /public/...\n    RewriteRule ^(.+)$ public/$1 [L]\n</IfModule>\nDirectoryIndex public/index.html index.html\n`);

    zip.file('package.json', JSON.stringify({
        name: `commerce-shell-${kind}`,
        version: '2.4.0',
        private: true,
        description: 'Headless commerce shell — production build artifacts included.',
        scripts: {
            start: 'node server/index.js',
            build: 'webpack --mode production',
            lint: 'eslint "src/**/*.{js,jsx}"'
        },
        dependencies: {
            express: '^4.19.2',
            mongoose: '^8.5.1',
            cors: '^2.8.5',
            helmet: '^7.1.0',
            react: '^18.3.1',
            'react-dom': '^18.3.1',
            redux: '^5.0.1',
            'react-redux': '^9.1.2'
        },
        devDependencies: {
            webpack: '^5.93.0',
            'webpack-cli': '^5.1.4',
            eslint: '^9.8.0',
            '@babel/core': '^7.25.2',
            '@babel/preset-react': '^7.24.7'
        }
    }, null, 2));

    zip.file('webpack.config.js', `const path = require('path');\nmodule.exports = {\n  mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',\n  entry: { app: path.resolve(__dirname, 'src/index.js') },\n  output: { path: path.resolve(__dirname, 'public/js'), filename: '[name].bundle.js', clean: false },\n  module: { rules: [{ test: /\\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }] },\n  resolve: { extensions: ['.js', '.jsx'] }\n};\n`);

    zip.file('.env.example', `NODE_ENV=production\nPORT=8080\nMONGO_URI=mongodb://127.0.0.1:27017/commerce_shell\nJWT_SECRET=change_me_in_production\nAPI_BASE_URL=https://api.example.com\n`);

    zip.file('.gitignore', 'node_modules/\n.env\n.DS_Store\ndist/\ncoverage/\n*.log\n');

    zip.file('LICENSE', 'PROPRIETARY — Internal deployment package. All rights reserved.\n');

    zip.file('tsconfig.json', JSON.stringify({ compilerOptions: { target: 'ES2020', module: 'ESNext', jsx: 'react-jsx', strict: true, skipLibCheck: true }, include: ['src'] }, null, 2));

    zip.file('babel.config.js', 'module.exports = { presets: [["@babel/preset-react", { runtime: "automatic" }]] };\n');

    zip.file('.eslintrc.json', JSON.stringify({ env: { browser: true, es2022: true, node: true }, extends: ['eslint:recommended'] }, null, 2));

    zip.file('Dockerfile', 'FROM node:20-alpine\nWORKDIR /app\nCOPY package.json ./\nRUN npm install --omit=dev\nCOPY . .\nEXPOSE 8080\nCMD ["node","server/index.js"]\n');

    zip.file('docker-compose.yml', "version: '3.8'\nservices:\n  web:\n    build: .\n    ports:\n      - '8080:8080'\n    environment:\n      - NODE_ENV=production\n");

    zip.file('server/index.js', `const express = require('express');\nconst cors = require('cors');\nconst helmet = require('helmet');\nconst api = require('./routes/api');\nconst app = express();\napp.use(helmet());\napp.use(cors());\napp.use('/api', api);\napp.use(express.static('public'));\nconst port = process.env.PORT || 8080;\napp.listen(port, () => console.log('listening', port));\n`);

    zip.file('server/routes/api.js', `const express = require('express');\nconst router = express.Router();\nrouter.get('/health', (req, res) => res.json({ ok: true, service: '${label}' }));\nmodule.exports = router;\n`);

    zip.file('server/models/User.js', `const mongoose = require('mongoose');\nconst UserSchema = new mongoose.Schema({ email: String, role: { type: String, default: 'viewer' } }, { timestamps: true });\nmodule.exports = mongoose.models.User || mongoose.model('User', UserSchema);\n`);

    zip.file('server/middleware/auth.js', `module.exports = function optionalAuth(req, res, next) {\n  req.user = req.headers.authorization ? { sub: 'anon' } : null;\n  next();\n};\n`);

    zip.file('src/index.js', `import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport App from './App';\nconst el = document.getElementById('root');\nif (el) createRoot(el).render(<App />);\n`);

    zip.file('src/App.js', `import React from 'react';\nimport { Header } from './components/Header';\nexport default function App() {\n  return (\n    <div className="__layout">\n      <Header />\n      <main style={{ display: 'none' }} aria-hidden="true" />\n    </div>\n  );\n}\n`);

    zip.file('src/components/Header.js', `import React from 'react';\nexport function Header() {\n  return <header style={{ display: 'none' }} />;\n}\n`);

    zip.file('src/utils/constants.js', `export const APP_SHELL = '${label}';\nexport const BUILD = '2.4.0';\n`);

    zip.file('public/css/app.chunk.css', buildDummyAppChunkCss());

    zip.file('public/js/vendor.min.js', buildDummyVendorMinJs());

    zip.file('public/js/main.chunk.js', buildDummyReactChunk(label));

    zip.file('server/controllers/core.js', buildDummyBackendCore(label));

    zip.file('public/index.html', publicHtml);

    const blob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE', compressionOptions: { level: 6 } });
    const base = sanitizeExportZipBaseName(siteName);
    downloadTextFile(`${base}_${label}_SourceCode_v2.4.zip`, blob, 'application/zip');
}

async function downloadWebsiteIframeFile() {
    if (!SITE_INFO?.subdomain) {
        UI.showToast('Shop URL not ready yet. Please refresh and try again.', false);
        return;
    }
    const basePath = new URL('./', window.location.href).href;
    const iframeSrc = `${basePath}shop.html?site=${encodeURIComponent(SITE_INFO.subdomain)}`;
    const siteName = SITE_INFO.siteName || SITE_INFO.subdomain || 'Shop';
    try {
        await generateDummyProjectZip(iframeSrc, siteName, 'website');
        UI.showToast('Website source package downloaded.');
    } catch (err) {
        console.error(err);
        UI.showToast('Could not build download package. Try again.', false);
    }
}

async function downloadAdminIframeFile() {
    const clientId = CURRENT_CLIENT_ID || SITE_INFO?.clientId;
    if (!clientId) {
        UI.showToast('Admin ID not found. Please refresh and try again.', false);
        return;
    }
    const basePath = new URL('./', window.location.href).href;
    const iframeSrc = `${basePath}admin.html?id=${encodeURIComponent(clientId)}`;
    const siteName = SITE_INFO?.siteName || 'Store';
    try {
        await generateDummyProjectZip(iframeSrc, siteName, 'admin');
        UI.showToast('Admin source package downloaded.');
    } catch (err) {
        console.error(err);
        UI.showToast('Could not build download package. Try again.', false);
    }
}

async function refreshBlockedIpsUI() {
    const listEl = document.getElementById('blocked-ips-list');
    if (!listEl || !CURRENT_CLIENT_ID) return;
    try {
        const snap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/security/blockedIps`));
        const data = snap.exists() && typeof snap.val() === 'object' ? snap.val() : {};
        const entries = Object.entries(data);
        if (!entries.length) {
            listEl.innerHTML = '<p class="text-black text-sm">No IPs blocked.</p>';
            return;
        }
        listEl.innerHTML = entries
            .map(([key, v]) => {
                const ipDisp = v && typeof v === 'object' && v.ip ? String(v.ip) : key.replace(/_/g, '.');
                const reason = v && typeof v === 'object' && v.reason ? String(v.reason) : '';
                return `<div class="flex flex-wrap items-center justify-between gap-2 bg-white border border-gray-200 rounded-lg px-3 py-2">
                    <span class="font-mono text-black">${escapeHtmlTextLocal(ipDisp)}</span>
                    <span class="text-xs text-black">${escapeHtmlTextLocal(reason)}</span>
                    <button type="button" data-action="unblockCustomerIp" data-ip-key="${escapeHtmlTextLocal(key)}" class="text-xs font-bold text-red-600 hover:underline">Remove</button>
                </div>`;
            })
            .join('');
    } catch (e) {
        listEl.innerHTML = '<p class="text-red-600 text-sm">Could not load block list. Check Firebase rules.</p>';
    }
}

async function handleBlockCustomerIp(orderId, ipStr) {
    const ip = String(ipStr || '').trim();
    if (!ip || ip === 'Unknown' || !CURRENT_CLIENT_ID) {
        UI.showToast('No valid IP to block.', false);
        return;
    }
    if (!confirm(`Block ${ip} from opening your public shop?`)) return;
    const key = ipToBlockedIpFirebaseKey(ip);
    try {
        await update(ref(db, `clients/${CURRENT_CLIENT_ID}/security/blockedIps/${key}`), {
            ip,
            createdAt: serverTimestamp(),
            sourceOrderKey: orderId || null,
            reason: 'order'
        });
        UI.showToast('IP blocked.');
        await refreshBlockedIpsUI();
    } catch (err) {
        console.error(err);
        UI.showToast('Failed to block IP.', false);
    }
}

async function handleManualBlockIp() {
    const input = document.getElementById('blocked-ip-manual-input');
    const ip = input?.value?.trim() || '';
    if (!looksLikeIpv4(ip)) {
        UI.showToast('Enter a valid IPv4 address.', false);
        return;
    }
    if (!confirm(`Block ${ip} from opening your public shop?`)) return;
    const key = ipToBlockedIpFirebaseKey(ip);
    try {
        await update(ref(db, `clients/${CURRENT_CLIENT_ID}/security/blockedIps/${key}`), {
            ip,
            createdAt: serverTimestamp(),
            reason: 'manual'
        });
        UI.showToast('IP blocked.');
        if (input) input.value = '';
        await refreshBlockedIpsUI();
    } catch (err) {
        console.error(err);
        UI.showToast('Failed to block IP.', false);
    }
}

function attachOrdersSubscription() {
    if (dashboardSubscriptions.orders || !CURRENT_CLIENT_ID) return;
    dashboardSubscriptions.orders = onValue(ref(db, `clients/${CURRENT_CLIENT_ID}/orders`), (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/orders`, 'onValue', snap);
        completedOrdersData = snap.val() || {};
        updateOrderNotification();
        if (isPanelActive('completed-orders')) renderCompletedOrders();
        if (isPanelActive('order-detail')) refreshOrderDetailPanelIfVisible();
        if (isPanelActive('customers')) {
            customerProfiles = processCustomerData(completedOrdersData);
            UI.renderCustomerList(customerProfiles);
        }
        if (isPanelActive('home')) scheduleDashboardUpdate();
    });
}

function attachIncompleteOrdersSubscription() {
    if (dashboardSubscriptions.incompleteOrders || !CURRENT_CLIENT_ID) return;
    dashboardSubscriptions.incompleteOrders = onValue(ref(db, `clients/${CURRENT_CLIENT_ID}/incompleteOrders`), (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/incompleteOrders`, 'onValue', snap);
        incompleteOrdersData = snap.val() || {};
        if (spyIntelligenceModule && (isPanelActive('visitor-spy') || isPanelActive('detective-brain'))) {
            spyIntelligenceModule.update(visitorData, incompleteOrdersData);
        }
        if (isPanelActive('detective-brain')) renderDetectiveBrain();
        if (isPanelActive('incomplete-orders')) renderIncompleteOrders();
    });
}

const HOME_VISITOR_LIMIT = 1200;
const SPY_VISITOR_LIMIT = 2800;

function attachVisitorsHomeSubscription() {
    if (dashboardSubscriptions.visitorsHome || !CURRENT_CLIENT_ID) return;
    const visitorsRef = ref(db, `clients/${CURRENT_CLIENT_ID}/visitors`);
    const qRef = query(visitorsRef, orderByChild('lastActive'), limitToLast(HOME_VISITOR_LIMIT));
    dashboardSubscriptions.visitorsHome = onValue(qRef, (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/visitors#homeLimit`, 'onValue', snap);
        homeVisitorData = snap.val() || {};
        if (isPanelActive('home')) scheduleDashboardUpdate();
    });
}

function attachVisitorsDeepSubscription() {
    if (dashboardSubscriptions.visitorsDeep || !CURRENT_CLIENT_ID) return;
    const visitorsRef = ref(db, `clients/${CURRENT_CLIENT_ID}/visitors`);
    const qRef = query(visitorsRef, orderByChild('lastActive'), limitToLast(SPY_VISITOR_LIMIT));
    dashboardSubscriptions.visitorsDeep = onValue(qRef, (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/visitors#spyLimit`, 'onValue', snap);
        visitorData = snap.val() || {};
        if (visitorSpyModule && isPanelActive('visitor-spy')) visitorSpyModule.update(visitorData);
        if (spyIntelligenceModule && (isPanelActive('visitor-spy') || isPanelActive('detective-brain'))) {
            spyIntelligenceModule.update(visitorData, incompleteOrdersData);
        }
        if (isPanelActive('detective-brain')) renderDetectiveBrain();
        if (SESSION_REPLAY_ENABLED && isPanelActive('visitor-spy')) updateSessionMonitorDropdown();
    });
}

function detachSubscription(key) {
    const unsub = dashboardSubscriptions[key];
    if (typeof unsub === 'function') unsub();
    dashboardSubscriptions[key] = null;
}

/** Panels that do not need live products/categories streams */
const DASHBOARD_CATALOG_EXCLUDED_PANELS = new Set([
    'hosting',
    'files',
    'notifications',
    'integrations',
    'tiktok-settings',
    'policy-settings',
    'shipping-settings'
]);

function dashboardPanelNeedsCatalog(panelId) {
    const pid = normalizePanelId(panelId);
    return !DASHBOARD_CATALOG_EXCLUDED_PANELS.has(pid);
}

function attachCatalogSubscriptions() {
    if (!CURRENT_CLIENT_ID || dashboardSubscriptions.products) return;
    recordRtdbListenerLifecycle('dashboard-catalog', 'attach');

    dashboardSubscriptions.products = onValue(ref(db, `clients/${CURRENT_CLIENT_ID}/products`), (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/products`, 'onValue', snap);
        const products = snap.val() || {};
        productCount = Object.keys(products).length;
        allProducts = products;
        throttledRenderProducts();
        refreshRecommendedForYouDashboardControls();
        if (typeof window.refreshHomeCategoryRowsSectionDashboardControls === 'function') {
            window.refreshHomeCategoryRowsSectionDashboardControls();
        }
        if (typeof window.refreshCategoryBannerSectionDashboardControls === 'function') {
            window.refreshCategoryBannerSectionDashboardControls();
        }
        refreshAiAdsDashProductSelect();
        UI.updateImagePreview('#product-image-url', '#product-image-preview');
        if (isPanelActive('home')) scheduleDashboardUpdate();
    });

    const categoryOrderRef = ref(db, `clients/${CURRENT_CLIENT_ID}/categoryOrder`);
    dashboardSubscriptions.categories = onValue(ref(db, `clients/${CURRENT_CLIENT_ID}/categories`), (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/categories`, 'onValue', snap);
        const categories = normalizeCategoriesMap(snap.val() || {});
        allCategories = categories;
        UI.populateCategoryDropdown(categories);
        refreshHeaderCategoriesSelector();
        if (categories && Object.keys(categories).length > 0 && categoryOrder.length === 0) {
            set(categoryOrderRef, Object.keys(categories));
        } else {
            throttledRenderCategories();
        }
    });
    dashboardSubscriptions.categoryOrder = onValue(categoryOrderRef, (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/categoryOrder`, 'onValue', snap);
        const val = snap.val();
        if (Array.isArray(val)) categoryOrder = val;
        else if (val && typeof val === 'object') categoryOrder = Object.keys(val).sort((a, b) => Number(a) - Number(b)).map(k => val[k]).filter(Boolean);
        else categoryOrder = [];
        refreshHeaderCategoriesSelector();
        throttledRenderCategories();
    });
}

function detachCatalogSubscriptions() {
    ['products', 'categories', 'categoryOrder'].forEach((k) => {
        const unsub = dashboardSubscriptions[k];
        if (typeof unsub === 'function') {
            recordRtdbListenerLifecycle('dashboard-catalog', 'detach');
            unsub();
        }
        dashboardSubscriptions[k] = null;
    });
}

function manageRealtimeSubscriptionsForPanel(panelId) {
    const pid = normalizePanelId(panelId);
    const needOrders = ['home', 'completed-orders', 'order-detail', 'customers'].includes(pid);
    const needIncomplete = ['incomplete-orders', 'detective-brain', 'visitor-spy'].includes(pid);
    const needVisitorsHome = ['home'].includes(pid);
    const needVisitorsDeep = ['visitor-spy', 'detective-brain'].includes(pid);
    const needCatalog = dashboardPanelNeedsCatalog(pid);
    if (needOrders) attachOrdersSubscription(); else detachSubscription('orders');
    if (needIncomplete) attachIncompleteOrdersSubscription(); else detachSubscription('incompleteOrders');
    if (needVisitorsHome) attachVisitorsHomeSubscription(); else detachSubscription('visitorsHome');
    if (needVisitorsDeep) attachVisitorsDeepSubscription(); else detachSubscription('visitorsDeep');
    if (needCatalog) attachCatalogSubscriptions(); else detachCatalogSubscriptions();
}

async function prepareAndShowDashboard() {
    const resultView = document.getElementById('result-view');
    if (resultView) {
        resultView.classList.remove('hidden');
        resultView.style.removeProperty('display');
    }
    const { clientId, subdomain, siteName } = SITE_INFO;
    CURRENT_CLIENT_ID = clientId;

    await refreshCurrentAdminAccessRecord(auth.currentUser);
    attachCurrentAdminAccessListener(auth.currentUser);
    syncAdminTeamSidebarVisibility();
    applySidebarPermissionVisibility();

    const invoiceLink = document.querySelector('a[href="invoice.html"]');
    if (invoiceLink) invoiceLink.href = 'invoice.html?clientId=' + encodeURIComponent(CURRENT_CLIENT_ID);
    
    // Fetch Settings & Hosting Status Once
    const [settingsSnap, hostingSnap] = await Promise.all([
        get(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`)),
        get(ref(db, `clients/${CURRENT_CLIENT_ID}/hosting`))
    ]);
    recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/siteSettings`, 'get', settingsSnap);
    recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/hosting`, 'get', hostingSnap);
    
    if (settingsSnap.exists()) {
        siteSettings = settingsSnap.val();
        normalizeLegacySwapnoActiveDesignInSiteSettings(siteSettings);
        steadfastConfig = siteSettings.steadfastConfig || {};
        
        // Initialize FB CAPI
        if (siteSettings.facebookConfig?.accessToken && siteSettings.pixelId) {
            fbCapiModule = new FacebookCAPI(siteSettings.facebookConfig.accessToken, siteSettings.pixelId);
        }

        // Update Links
        const publicUrl = `shop.html?site=${subdomain}`;
        const basePath = window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1);
        
        const linkInput = document.getElementById('website-link-input');
        if(linkInput) linkInput.value = basePath + publicUrl;
        
        const sidebarVisitBtn = document.getElementById('visit-shop-btn-sidebar');
        if(sidebarVisitBtn) sidebarVisitBtn.href = publicUrl;
        
        // Populate Form Fields in UI
        UI.populateSiteSettings(siteSettings);
        refreshHeaderCategoriesSelector();
        refreshIntegrationStatusSummary();
    } else {
        siteSettings = {};
        setUploadConfig('imgbb', '', '');
    }

    syncDashboardShopNameUi();

    if (hostingSnap.exists()) clientHostingInfo = hostingSnap.val();
    
    // Check Hosting Validity
    isHostingActive = clientHostingInfo && clientHostingInfo.status === 'active' && clientHostingInfo.expiresAt > Date.now();
    
    // Check Locks
    handleUserNudgesAndLocks();
    
    // Setup charts only when chart library is ready.
    ensureChartLibraryLoaded()
        .then(() => {
            UI.setupChartTheme();
            if (isPanelActive('home')) scheduleDashboardUpdate();
        })
        .catch(() => {});

    // Check URL Hash for Initial Navigation
    let rawNavHash = window.location.hash.substring(1);
    let pendingAdminEmbed = '';
    if (rawNavHash.startsWith('admin-embed=')) {
        try {
            pendingAdminEmbed = decodeURIComponent(rawNavHash.slice('admin-embed='.length));
        } catch (_) {
            pendingAdminEmbed = '';
        }
        rawNavHash = '';
    }
    let initialHash = normalizePanelId(rawNavHash);
    if (initialHash.startsWith('order-detail/')) {
        const raw = initialHash.slice('order-detail/'.length);
        const orderId = decodeURIComponent(raw);
        if (orderId) {
            showOrderDetailPage(orderId, false);
            history.replaceState({ panel: 'order-detail', orderId }, '', window.location.hash);
        } else {
            showDashboardPanel('completed-orders', false);
        }
    } else if (initialHash === 'order-detail') {
        showDashboardPanel('completed-orders', false);
    } else if (
        initialHash === 'customization-section-designs' ||
        initialHash === 'customization-banners' ||
        initialHash === 'customization-header' ||
        initialHash === 'customization-home-page-design'
    ) {
        showDashboardPanel('customization', false);
        requestAnimationFrame(() => {
            const tabKey =
                initialHash === 'customization-banners'
                    ? 'banners'
                    : initialHash === 'customization-header'
                      ? 'header'
                      : initialHash === 'customization-home-page-design'
                        ? 'home-page-design'
                        : 'section-designs';
            const tabBtn = document.querySelector(`.customization-tab-btn[data-customization-tab="${tabKey}"]`);
            if (tabBtn) tabBtn.click();
        });
    } else if (initialHash) {
        showDashboardPanel(initialHash, false); // Don't push history on initial load
    } else {
        history.replaceState({ panel: 'home' }, '', window.location.pathname);
    }

    if (pendingAdminEmbed) {
        requestAnimationFrame(() => openAdminShellEmbed(pendingAdminEmbed, false));
    }

    syncDashboardContentFitViewportClass();

    // --- START LISTENERS ---
    // Wallet (small payload; keep live for sidebar + hosting)
    onValue(ref(db, `clients/${CURRENT_CLIENT_ID}/wallet/currentBalance`), (snap) => {
        recordRtdbTelemetry(`clients/${CURRENT_CLIENT_ID}/wallet/currentBalance`, 'onValue', snap);
        currentBalance = snap.val() || 0;
        const balanceEl = document.getElementById('wallet-balance');
        if (balanceEl) balanceEl.textContent = currentBalance.toFixed(2);
        const sidebarBalanceEl = document.getElementById('sidebar-wallet-balance');
        if (sidebarBalanceEl) sidebarBalanceEl.textContent = currentBalance.toFixed(2);
        const hostingBalanceEl = document.getElementById('hosting-wallet-balance');
        if (hostingBalanceEl) hostingBalanceEl.textContent = currentBalance.toFixed(2);
    });

    // Panel-scoped: orders, visitors, products/categories
    manageRealtimeSubscriptionsForPanel(getActiveDashboardPanelId());

    bindDashboardChromeUI();

    if (isPanelActive('home')) {
        bindDashboardHomeUx();
        scheduleDashboardUpdate();
        startFirebaseUsageRefresh();
    }
}

function updateAllCharts(data) {
    if (typeof Chart === 'undefined') return;
    UI.renderSparkline('sparkline-sales', data.dailySales, data.labels7Days, '#3B82F6');
    UI.renderSparkline('sparkline-income', data.dailyIncome, data.labels7Days, '#F97316');
    UI.renderSparkline('sparkline-orders', data.dailyOrders, data.labels7Days, '#8B5CF6');

    UI.renderCategoryChart(data.categorySales);
    applyRevenueGranularityFromData(data);
    UI.renderEarningsGauge(data.totalIncome, data.totalSales);
}

function prefersDashboardReducedMotion() {
    return typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

/** Animate home KPI headline numbers (sales, income, orders, visitors). */
function animateDashboardHomeKpis(chartData) {
    const salesEl = document.getElementById('total-sales-value');
    const incomeEl = document.getElementById('total-income-value');
    const ordersEl = document.getElementById('orders-paid-count');
    const visitorsEl = document.getElementById('total-visitor-count');
    const salesN = Number(chartData.totalSales) || 0;
    const incomeN = Number(chartData.totalIncome) || 0;
    const ordersN = Number(chartData.paidOrders) || 0;
    const visitorsN = Number(chartData.totalVisitors) || 0;

    if (prefersDashboardReducedMotion()) {
        if (salesEl) salesEl.textContent = salesN.toLocaleString() + ' ৳';
        if (incomeEl) incomeEl.textContent = incomeN.toLocaleString() + ' ৳';
        if (ordersEl) ordersEl.textContent = String(ordersN);
        if (visitorsEl) visitorsEl.textContent = String(visitorsN);
        return;
    }

    const duration = 520;
    const start = performance.now();
    const from = { sales: 0, income: 0, orders: 0, visitors: 0 };

    function tick(now) {
        const t = Math.min(1, (now - start) / duration);
        const eased = 1 - Math.pow(1 - t, 3);
        if (salesEl) salesEl.textContent = Math.round(from.sales + (salesN - from.sales) * eased).toLocaleString() + ' ৳';
        if (incomeEl) incomeEl.textContent = Math.round(from.income + (incomeN - from.income) * eased).toLocaleString() + ' ৳';
        if (ordersEl) ordersEl.textContent = String(Math.round(from.orders + (ordersN - from.orders) * eased));
        if (visitorsEl) visitorsEl.textContent = String(Math.round(from.visitors + (visitorsN - from.visitors) * eased));
        if (t < 1) requestAnimationFrame(tick);
        else {
            if (salesEl) salesEl.textContent = salesN.toLocaleString() + ' ৳';
            if (incomeEl) incomeEl.textContent = incomeN.toLocaleString() + ' ৳';
            if (ordersEl) ordersEl.textContent = String(ordersN);
            if (visitorsEl) visitorsEl.textContent = String(visitorsN);
        }
    }
    requestAnimationFrame(tick);
}

function scheduleHomeChartsHeavy(chartData) {
    const runHeavy = () => {
        if (!isPanelActive('home')) return;
        if (typeof Chart === 'undefined') return;
        UI.renderCategoryChart(chartData.categorySales);
        applyRevenueGranularityFromData(chartData);
        UI.renderEarningsGauge(chartData.totalIncome, chartData.totalSales);
        UI.renderVisitorBarChart(chartData.dailyVisitors, chartData.labels7Days);
        UI.renderRecentOrdersTable(completedOrdersData);
        UI.renderTopLocationsList(chartData.topLocations);
        UI.generateBusinessIntelligence(completedOrdersData);
        UI.renderTopProductsList(chartData.productSalesCount);
        if (typeof UI.setupDashboardHomeChartResizeObservers === 'function') {
            UI.setupDashboardHomeChartResizeObservers();
        }
        try {
            window.dispatchEvent(new Event('resize'));
        } catch (_) { /* ignore */ }
    };
    if (typeof requestIdleCallback === 'function') {
        requestIdleCallback(() => runHeavy(), { timeout: 900 });
    } else {
        setTimeout(runHeavy, 0);
    }
}

let homeRevealObserver = null;

/** Mark .home-reveal nodes that intersect the viewport (sync fallback if IntersectionObserver is late or skipped). */
function syncHomeRevealVisibility(elements) {
    const nodes = Array.from(elements);
    const vh = typeof window.innerHeight === 'number' ? window.innerHeight : 0;
    const vw = typeof window.innerWidth === 'number' ? window.innerWidth : 0;
    if (vh < 1 || vw < 1) return;
    nodes.forEach((el) => {
        const r = el.getBoundingClientRect();
        if (r.width < 1 && r.height < 1) return;
        if (r.bottom > 0 && r.top < vh && r.right > 0 && r.left < vw) {
            el.classList.add('is-visible');
        }
    });
}

/** Same as syncHomeRevealVisibility but against #dashboard-content scrollport when it scrolls. */
function syncHomeRevealVisibilityAgainstRoot(elements, rootEl) {
    const nodes = Array.from(elements);
    const rr = rootEl.getBoundingClientRect();
    if (rr.width < 1 || rr.height < 1) return;
    nodes.forEach((el) => {
        const r = el.getBoundingClientRect();
        if (r.width < 1 && r.height < 1) return;
        if (r.bottom > rr.top && r.top < rr.bottom && r.right > rr.left && r.left < rr.right) {
            el.classList.add('is-visible');
        }
    });
}

function initHomeRevealObserver() {
    const home = document.getElementById('dashboard-home');
    if (!home || typeof IntersectionObserver === 'undefined') return;
    const host = document.getElementById('dashboard-content');
    home.classList.remove('dashboard-home-reveal-armed');
    if (homeRevealObserver) {
        homeRevealObserver.disconnect();
        homeRevealObserver = null;
    }
    const els = home.querySelectorAll('.home-reveal');
    if (!els.length) return;

    const hostScrolls = !!(host && host.scrollHeight > host.clientHeight + 2);
    const ioRoot = hostScrolls ? host : null;

    const runSync = () => {
        if (hostScrolls && host) syncHomeRevealVisibilityAgainstRoot(els, host);
        else syncHomeRevealVisibility(els);
    };

    runSync();
    home.classList.add('dashboard-home-reveal-armed');
    homeRevealObserver = new IntersectionObserver(
        (entries) => {
            entries.forEach((ent) => {
                if (ent.isIntersecting) ent.target.classList.add('is-visible');
            });
        },
        { root: ioRoot, threshold: 0, rootMargin: '0px 0px 0px 0px' }
    );
    els.forEach((el) => homeRevealObserver.observe(el));
    try {
        const pending = homeRevealObserver.takeRecords?.();
        if (pending && pending.length) {
            pending.forEach((ent) => {
                if (ent.isIntersecting) ent.target.classList.add('is-visible');
            });
        }
    } catch (_) { /* takeRecords optional */ }
    runSync();
    requestAnimationFrame(() => {
        runSync();
        requestAnimationFrame(() => runSync());
    });
}

function bindDashboardHomeUx() {
    const host = document.getElementById('dashboard-content');
    if (!host) return;
    if (host.dataset.dashboardHomeUxBound !== '1') {
        host.dataset.dashboardHomeUxBound = '1';

    host.addEventListener('click', (e) => {
        const t = e.target;
        if (!(t instanceof Element)) return;

        const exportBtn = t.closest('.home-chart-export-btn');
        if (exportBtn && host.contains(exportBtn)) {
            e.preventDefault();
            const cid = exportBtn.getAttribute('data-chart-export-canvas');
            const base = exportBtn.getAttribute('data-chart-export-name') || 'chart';
            if (cid && UI.exportDashboardChartPngByCanvasId(cid, base)) {
                UI.showToast('Chart image downloaded.', true);
            } else {
                UI.showToast('Chart is not ready yet. Try again in a moment.', false);
            }
            host.querySelectorAll('.home-chart-menu-panel').forEach((p) => p.classList.add('hidden'));
            host.querySelectorAll('.home-chart-menu-btn').forEach((b) => b.setAttribute('aria-expanded', 'false'));
            return;
        }

        const menuBtn = t.closest('.home-chart-menu-btn');
        if (menuBtn && host.contains(menuBtn)) {
            e.preventDefault();
            e.stopPropagation();
            const wrap = menuBtn.parentElement;
            const panel = wrap && wrap.querySelector('.home-chart-menu-panel');
            const wasHidden = !!(panel && panel.classList.contains('hidden'));
            host.querySelectorAll('.home-chart-menu-panel').forEach((p) => p.classList.add('hidden'));
            host.querySelectorAll('.home-chart-menu-btn').forEach((b) => b.setAttribute('aria-expanded', 'false'));
            if (panel && wasHidden) {
                panel.classList.remove('hidden');
                menuBtn.setAttribute('aria-expanded', 'true');
            }
            return;
        }
    });

    document.addEventListener('click', (e) => {
        const t = e.target;
        if (!(t instanceof Element)) return;
        if (t.closest('.home-chart-menu-btn') || t.closest('.home-chart-menu-panel')) return;
        host.querySelectorAll('.home-chart-menu-panel').forEach((p) => p.classList.add('hidden'));
        host.querySelectorAll('.home-chart-menu-btn').forEach((b) => b.setAttribute('aria-expanded', 'false'));
    });

    document.addEventListener('keydown', (e) => {
        if (e.key !== 'Escape') return;
        host.querySelectorAll('.home-chart-menu-panel').forEach((p) => p.classList.add('hidden'));
        host.querySelectorAll('.home-chart-menu-btn').forEach((b) => b.setAttribute('aria-expanded', 'false'));
    });

    }

    if (!window.__dashboardHomeRevealResizeBound) {
        window.__dashboardHomeRevealResizeBound = true;
        let revealResizeTimer;
        window.addEventListener('resize', () => {
            clearTimeout(revealResizeTimer);
            revealResizeTimer = setTimeout(() => {
                if (getActiveDashboardPanelId() === 'home') initHomeRevealObserver();
            }, 200);
        });
    }

    initHomeRevealObserver();
}

function applyRevenueGranularityFromData(data) {
    if (!data || typeof Chart === 'undefined') return;
    const g = document.getElementById('earnings-granularity')?.value || 'monthly';
    if (g === 'daily') {
        UI.renderRevenueChart(data.daily30Revenue, data.daily30Orders, data.labels30Days);
    } else if (g === 'weekly') {
        UI.renderRevenueChart(data.weekly12Revenue, data.weekly12Orders, data.labels12Weeks);
    } else {
        UI.renderRevenueChart(data.monthlyRevenue, data.monthlyOrders, data.labels12Months);
    }
}

function applyRevenueGranularity() {
    applyRevenueGranularityFromData(window.__dashboardChartData);
}

function exportRecentOrdersCsv() {
    const tbody = document.getElementById('recent-orders-table-body');
    if (!tbody) return;
    const rows = Array.from(tbody.querySelectorAll('tr'));
    const lines = [['Order ID', 'Customer', 'Products', 'Total', 'Status'].join(',')];
    rows.forEach((tr) => {
        const cells = Array.from(tr.querySelectorAll('td')).map((td) => `"${String(td.textContent || '').replace(/"/g, '""').trim()}"`);
        if (cells.length >= 5) lines.push(cells.slice(0, 5).join(','));
    });
    const blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'recent-orders-export.csv';
    a.click();
    URL.revokeObjectURL(a.href);
    UI.showToast('CSV export downloaded.', true);
}

function formatTrendChip(el, pct) {
    if (!el) return;
    const n = Number(pct) || 0;
    const up = n > 0.05;
    const down = n < -0.05;
    el.className =
        'shrink-0 inline-flex items-center text-[11px] font-semibold px-2 py-1 rounded-lg border ' +
        (up
            ? 'text-emerald-400 bg-emerald-950/40 border-emerald-900/50'
            : down
              ? 'text-red-400 bg-red-950/40 border-red-900/50'
              : 'text-gray-400 bg-gray-900 border-gray-700/80');
    const icon = up ? 'fa-arrow-trend-up' : down ? 'fa-arrow-trend-down' : 'fa-minus';
    const text = (n > 0.05 ? '+' : '') + n.toFixed(2) + '%';
    el.innerHTML = `<i class="fa-solid ${icon} mr-1"></i>${text}`;
}

/** Display name for dashboard chrome: Firebase site name first, then local siteInfo, then subdomain. */
function getDashboardShopDisplayName() {
    const ss = typeof siteSettings === 'object' && siteSettings ? siteSettings.siteName : undefined;
    const fromSs = ss != null && String(ss).trim() !== '' ? String(ss).trim() : '';
    if (fromSs) return fromSs;
    const sn = SITE_INFO && SITE_INFO.siteName != null ? String(SITE_INFO.siteName).trim() : '';
    if (sn) return sn;
    const sub = SITE_INFO && SITE_INFO.subdomain != null ? String(SITE_INFO.subdomain).trim() : '';
    if (sub) return sub;
    return 'Store';
}

/** Sync sidebar title, sr-only title, avatar initial, document title, optional localStorage siteInfo.siteName. */
function syncDashboardShopNameUi() {
    const display = getDashboardShopDisplayName();
    const siteNameEl = document.getElementById('dashboard-site-name');
    if (siteNameEl) siteNameEl.textContent = display;
    const heroLine = document.getElementById('dashboard-home-hero-line');
    if (heroLine) heroLine.textContent = display;
    const siteNameSidebar = document.getElementById('dashboard-site-name-sidebar');
    if (siteNameSidebar) siteNameSidebar.textContent = display;
    document.title = `${display} — Dashboard`;
    if (SITE_INFO) {
        SITE_INFO.siteName = display;
        try {
            const raw = localStorage.getItem('siteInfo');
            if (raw) {
                const obj = JSON.parse(raw);
                if (obj && typeof obj === 'object') {
                    obj.siteName = display;
                    localStorage.setItem('siteInfo', JSON.stringify(obj));
                }
            }
        } catch (_) { /* ignore corrupt siteInfo */ }
    }
    updateHeaderProfileAvatar(auth.currentUser);
}

/** Move dropdown under document.body so #dashboard-content overflow-y-auto cannot clip it. */
function ensureAddNewMenuPortaledToBody() {
    const menu = document.getElementById('add-new-menu');
    if (!menu || menu.parentElement === document.body) return;
    document.body.appendChild(menu);
}

function positionAddNewMenu() {
    const menu = document.getElementById('add-new-menu');
    const toggle = document.getElementById('add-new-toggle');
    if (!menu || !toggle || menu.classList.contains('hidden')) return;
    ensureAddNewMenuPortaledToBody();
    const r = toggle.getBoundingClientRect();
    const gap = 8;
    menu.style.position = 'fixed';
    menu.style.top = `${Math.round(r.bottom + gap)}px`;
    const mw = menu.offsetWidth || 208;
    let left = Math.round(r.right - mw);
    if (left < gap) left = gap;
    if (left + mw > window.innerWidth - gap) left = Math.max(gap, Math.round(window.innerWidth - mw - gap));
    menu.style.left = `${left}px`;
    menu.style.right = 'auto';
}

function repositionAddNewMenuIfOpen() {
    const menu = document.getElementById('add-new-menu');
    if (menu && !menu.classList.contains('hidden')) positionAddNewMenu();
}

function onAddNewToggleClick(e) {
    e.preventDefault();
    e.stopPropagation();
    const menu = document.getElementById('add-new-menu');
    const toggle = document.getElementById('add-new-toggle');
    if (!menu || !toggle) return;
    menu.classList.toggle('hidden');
    if (!menu.classList.contains('hidden')) {
        ensureAddNewMenuPortaledToBody();
        positionAddNewMenu();
    }
}

function onDocumentCloseAddNewMenu(e) {
    const m = document.getElementById('add-new-menu');
    const tgl = document.getElementById('add-new-toggle');
    if (!m || m.classList.contains('hidden')) return;
    const t = e.target;
    if (t instanceof Element && (m.contains(t) || (tgl && tgl.contains(t)))) return;
    m.classList.add('hidden');
}

/** Single capture-phase delegation on #dashboard-content — survives innerHTML refresh of panel markup. */
function bindDashboardHeaderDelegation() {
    if (typeof window !== 'undefined' && window.__dashboardHeaderDelegationBound) return;
    const root = document.getElementById('dashboard-content');
    if (!root) return;
    if (typeof window !== 'undefined') window.__dashboardHeaderDelegationBound = true;
    root.addEventListener('click', (e) => {
        const t = e.target;
        if (!(t instanceof Element)) return;
        const analyticsNav = t.closest('a[href="analytics.html"]');
        if (analyticsNav) {
            try {
                localStorage.setItem('analytics_token', `dash:${Date.now()}`);
            } catch (_) {
                /* ignore quota / private mode */
            }
            return;
        }
        if (t.closest('#add-new-toggle')) {
            onAddNewToggleClick(e);
            return;
        }
        if (t.closest('#header-notifications-btn')) {
            e.preventDefault();
            e.stopPropagation();
            showDashboardPanel('notifications');
            return;
        }
        if (t.closest('#header-messages-btn')) {
            e.preventDefault();
            e.stopPropagation();
            UI.showToast('Messages will be available in a future update.');
            return;
        }
        if (t.closest('#profile-btn')) {
            e.preventDefault();
            e.stopPropagation();
            openProfileModalWithAdminPrep();
            return;
        }
        if (t.closest('#header-settings-btn')) {
            e.preventDefault();
            e.stopPropagation();
            showDashboardPanel('customization');
            return;
        }
        if (t.closest('#logout-btn')) {
            e.preventDefault();
            e.stopPropagation();
            handleLogout();
            return;
        }
        if (t.closest('#close-profile-modal-btn')) {
            e.preventDefault();
            e.stopPropagation();
            UI.toggleModal('profile-modal', false);
        }
    }, true);
}

function bindDashboardChromeUI() {
    bindDashboardHeaderDelegation();

    const kbd = document.getElementById('global-search-kbd-hint');
    if (kbd) {
        const mac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform || '');
        kbd.textContent = mac ? '⌘K' : 'Ctrl+K';
    }

    if (!window.__dashboardChromeGlobalsBound) {
        window.__dashboardChromeGlobalsBound = true;
        document.addEventListener('click', onDocumentCloseAddNewMenu);
        window.addEventListener('resize', repositionAddNewMenuIfOpen);
        document.getElementById('dashboard-content')?.addEventListener('scroll', repositionAddNewMenuIfOpen, { passive: true });
    }

    document.querySelectorAll('.add-new-menu-item:not([data-add-new-item-bound])').forEach((b) => {
        b.dataset.addNewItemBound = '1';
        b.addEventListener('click', () => document.getElementById('add-new-menu')?.classList.add('hidden'));
    });

    const eg = document.getElementById('earnings-granularity');
    if (eg && !eg.dataset.dashChromeBound) {
        eg.dataset.dashChromeBound = '1';
        eg.addEventListener('change', () => applyRevenueGranularity());
    }
    const exp = document.getElementById('dashboard-export-btn');
    if (exp && !exp.dataset.dashChromeBound) {
        exp.dataset.dashChromeBound = '1';
        exp.addEventListener('click', () => exportRecentOrdersCsv());
    }

    bindDashboardHomeUx();

    const embClose = document.getElementById('admin-shell-embed-close');
    if (embClose && !embClose.dataset.dashChromeBound) {
        embClose.dataset.dashChromeBound = '1';
        embClose.addEventListener('click', (ev) => {
            ev.preventDefault();
            closeAdminShellEmbedQuiet();
        });
    }
}

function updateHeaderProfileAvatar(user) {
    const img = document.getElementById('profile-avatar-img');
    const fb = document.getElementById('profile-avatar-fallback');
    if (!fb) return;
    const shopLabel = getDashboardShopDisplayName();
    const siteInitial = shopLabel.trim() ? shopLabel.trim().charAt(0).toUpperCase() : '?';
    const displayNameEl = document.getElementById('header-user-display-name');
    const roleEl = document.getElementById('header-user-role');
    const emailLocal = user?.email ? String(user.email).split('@')[0] : '';
    const headerName = user?.displayName?.trim?.()
        || (emailLocal ? emailLocal.replace(/[._]/g, ' ') : '')
        || shopLabel
        || 'Admin User';
    if (displayNameEl) displayNameEl.textContent = headerName;
    if (roleEl) roleEl.textContent = user ? 'Super Admin' : 'Guest';
    if (user?.photoURL && img) {
        img.src = user.photoURL;
        img.classList.remove('hidden');
        fb.classList.add('hidden');
    } else {
        if (img) {
            img.removeAttribute('src');
            img.classList.add('hidden');
        }
        fb.classList.remove('hidden');
        const di = user?.displayName?.trim?.();
        fb.textContent = di ? di.charAt(0).toUpperCase() : siteInitial;
    }
}

let chartLibraryPromise = null;
function ensureChartLibraryLoaded() {
    if (typeof Chart !== 'undefined') return Promise.resolve();
    if (chartLibraryPromise) return chartLibraryPromise;
    chartLibraryPromise = new Promise((resolve, reject) => {
        const existing = document.querySelector('script[data-chartjs-loader="dashboard"]');
        if (existing) {
            existing.addEventListener('load', () => resolve(), { once: true });
            existing.addEventListener('error', reject, { once: true });
            return;
        }
        const script = document.createElement('script');
        script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
        script.defer = true;
        script.dataset.chartjsLoader = 'dashboard';
        script.onload = () => resolve();
        script.onerror = (err) => reject(err);
        document.head.appendChild(script);
    });
    return chartLibraryPromise;
}

let dashboardChartsUpdateTimeout = null;
const DASHBOARD_CHARTS_DEBOUNCE_MS = 1000;

/** Batches heavy chart/home recomputation after rapid Firebase onValue events (products/orders/visitors). */
function scheduleDashboardUpdate() {
    if (dashboardChartsUpdateTimeout) clearTimeout(dashboardChartsUpdateTimeout);
    dashboardChartsUpdateTimeout = setTimeout(() => {
        dashboardChartsUpdateTimeout = null;
        if (!isPanelActive('home')) return;
        const visitorSource = (homeVisitorData && Object.keys(homeVisitorData).length > 0) ? homeVisitorData : visitorData;
        const chartData = UI.processDashboardData(completedOrdersData, allProducts, visitorSource, siteSettings);
        window.__dashboardChartData = chartData;

        const dr = document.getElementById('dashboard-date-range-text');
        if (dr && chartData.currentPeriodRangeLabel) dr.textContent = chartData.currentPeriodRangeLabel;

        const vs = chartData.comparisonRangeLabel || '';
        ['sales', 'income', 'orders', 'visitors'].forEach((k) => {
            const el = document.getElementById(`kpi-vs-${k}`);
            if (el && vs) el.textContent = `vs ${vs}`;
        });
        formatTrendChip(document.getElementById('kpi-trend-sales'), chartData.kpiTrendSalesPct);
        formatTrendChip(document.getElementById('kpi-trend-income'), chartData.kpiTrendIncomePct);
        formatTrendChip(document.getElementById('kpi-trend-orders'), chartData.kpiTrendOrdersPct);
        formatTrendChip(document.getElementById('kpi-trend-visitors'), chartData.kpiTrendVisitorsPct);

        if (typeof Chart !== 'undefined') {
            UI.renderSparkline('sparkline-sales', chartData.dailySales, chartData.labels7Days, '#3B82F6');
            UI.renderSparkline('sparkline-income', chartData.dailyIncome, chartData.labels7Days, '#F97316');
            UI.renderSparkline('sparkline-orders', chartData.dailyOrders, chartData.labels7Days, '#8B5CF6');
            UI.renderSparkline('sparkline-visitors', chartData.dailyVisitors, chartData.labels7Days, '#14B8A6');
        }

        animateDashboardHomeKpis(chartData);

        const crTotal = document.getElementById('chart-revenue-total');
        if (crTotal) crTotal.textContent = chartData.totalSales.toLocaleString() + ' ৳';
        const coTotal = document.getElementById('chart-order-total');
        if (coTotal) coTotal.textContent = chartData.paidOrders;

        scheduleHomeChartsHeavy(chartData);

        const fsSales = document.getElementById('footer-stat-sales');
        if (fsSales) fsSales.textContent = chartData.totalSales.toLocaleString() + ' ৳';
        const fsIncome = document.getElementById('footer-stat-income');
        if (fsIncome) fsIncome.textContent = chartData.totalIncome.toLocaleString() + ' ৳';
        const fsOrders = document.getElementById('footer-stat-orders');
        if (fsOrders) fsOrders.textContent = String(chartData.paidOrders);
        const fsVisitors = document.getElementById('footer-stat-visitors');
        if (fsVisitors) {
            fsVisitors.textContent = String(chartData.totalVisitors);
        }
        const fsUpdated = document.getElementById('footer-stat-updated');
        const syncStr = new Date().toLocaleString();
        if (fsUpdated) fsUpdated.textContent = syncStr;
        const homeSync = document.getElementById('dashboard-home-last-sync');
        if (homeSync) homeSync.textContent = syncStr;

        schedulePublishDashboardSummary(db, CURRENT_CLIENT_ID, chartData);
        schedulePublishDashboardAnalytics(db, CURRENT_CLIENT_ID, chartData);
    }, DASHBOARD_CHARTS_DEBOUNCE_MS);
}

// ============================================================
// 4. BUSINESS LOGIC (CONTROLLER)
// ============================================================

// --- Live Ads (Facebook Marketing API) ---
function expandLiveAdsSidebarGroup(open) {
    const g = document.getElementById('sidebar-group-live-ads');
    const btn = document.getElementById('sidebar-live-ads-toggle');
    if (!g) return;
    g.classList.toggle('sidebar-group-open', !!open);
    if (btn) btn.setAttribute('aria-expanded', open ? 'true' : 'false');
}

// --- Marketers Brain (dashboard panel; data-panel ai-ads-manager) ---
function setAiAdsDashGenerateStatus(msg, isError = false) {
    const el = document.getElementById('ai-ads-dash-generate-status');
    if (!el) return;
    el.textContent = msg || '';
    el.classList.remove('text-red-300', 'text-red-400', 'text-gray-600', 'text-violet-100', 'text-violet-100/95', 'text-violet-200');
    if (isError) el.classList.add('text-red-300');
    else el.classList.add(msg ? 'text-violet-100' : 'text-violet-200');
}

function refreshAiAdsDashProductSelect() {
    const sel = document.getElementById('ai-ads-dash-product-select');
    if (!sel) return;
    const prev = sel.value;
    sel.innerHTML = '<option value="">— Select a product —</option>';
    const products = allProducts || {};
    Object.entries(products).forEach(([id, p]) => {
        if (!p || !p.name) return;
        const o = document.createElement('option');
        o.value = id;
        const price = p.salePrice != null && p.salePrice !== '' ? ` (৳${p.salePrice})` : '';
        o.textContent = `${p.name}${price}`;
        sel.appendChild(o);
    });
    if (prev) {
        let found = false;
        for (let i = 0; i < sel.options.length; i++) {
            if (sel.options[i].value === prev) {
                found = true;
                break;
            }
        }
        if (found) sel.value = prev;
    }
}

function renderAiAdsDashInterestTags(interests) {
    const wrap = document.getElementById('ai-ads-dash-interests');
    if (!wrap) return;
    wrap.innerHTML = '';
    const list = Array.isArray(interests) ? interests : [];
    if (!list.length) {
        wrap.innerHTML = '<span class="text-slate-400 italic">—</span>';
        return;
    }
    list.slice(0, 12).forEach((tag) => {
        const t = String(tag || '').trim();
        if (!t) return;
        const span = document.createElement('span');
        span.className = 'inline-flex items-center px-2 py-1 rounded-md bg-indigo-50 text-indigo-800 text-xs font-medium border border-indigo-100';
        span.textContent = t;
        wrap.appendChild(span);
    });
}

function setAiAdsDashAudienceBudget(data = {}) {
    const audienceEl = document.getElementById('ai-ads-dash-audience-angle');
    const imagePromptEl = document.getElementById('ai-ads-dash-image-prompt');
    const budgetDailyEl = document.getElementById('ai-ads-dash-budget-daily');
    const budgetMonthlyEl = document.getElementById('ai-ads-dash-budget-monthly');
    const schedulingHintEl = document.getElementById('ai-ads-dash-scheduling-hint');
    if (audienceEl) audienceEl.textContent = String(data.audienceAngle || '—');
    if (imagePromptEl) imagePromptEl.value = String(data.imagePrompt || '');
    if (budgetDailyEl) budgetDailyEl.textContent = Number.isFinite(Number(data.dailyBudgetBdt)) ? `৳${Number(data.dailyBudgetBdt).toLocaleString()}` : '—';
    if (budgetMonthlyEl) budgetMonthlyEl.textContent = Number.isFinite(Number(data.monthlyBudgetBdt)) ? `৳${Number(data.monthlyBudgetBdt).toLocaleString()}` : '—';
    if (schedulingHintEl) schedulingHintEl.textContent = String(data.schedulingHint || '—');
}

function setAiAdsDashVariantData(variant) {
    const v = variant && typeof variant === 'object' ? variant : {};
    const key = String(v.label || 'A').toUpperCase();
    const primaryEl = document.getElementById(`ai-ads-dash-primary-text-${key.toLowerCase()}`);
    const headlineEl = document.getElementById(`ai-ads-dash-headline-${key.toLowerCase()}`);
    const ctaEl = document.getElementById(`ai-ads-dash-cta-${key.toLowerCase()}`);
    if (primaryEl) primaryEl.value = String(v.primaryText || '');
    if (headlineEl) headlineEl.value = String(v.headline || '');
    if (ctaEl) ctaEl.value = String(v.cta || '');
}

function switchAiVariantTab(variant) {
    const target = String(variant || 'A').toUpperCase();
    document.querySelectorAll('.ai-variant-tab').forEach((btn) => {
        const isActive = (btn.getAttribute('data-variant') || 'A').toUpperCase() === target;
        btn.classList.toggle('bg-white', isActive);
        btn.classList.toggle('text-slate-900', isActive);
        btn.classList.toggle('shadow-sm', isActive);
        btn.classList.toggle('text-slate-600', !isActive);
    });
    document.querySelectorAll('.ai-variant-panel').forEach((panel) => {
        const p = (panel.getAttribute('data-variant-panel') || 'A').toUpperCase();
        panel.classList.toggle('hidden', p !== target);
    });
}

function initAiVariantTabs() {
    if (aiVariantTabBound) return;
    aiVariantTabBound = true;
    document.addEventListener('click', (e) => {
        const btn = e.target instanceof Element ? e.target.closest('.ai-variant-tab') : null;
        if (!btn) return;
        e.preventDefault();
        switchAiVariantTab(btn.getAttribute('data-variant') || 'A');
    });
    switchAiVariantTab('A');
}

function renderMbChatThread() {
    const thread = document.getElementById('mb-chat-thread');
    if (!thread) return;
    if (!Array.isArray(mbChatMessages) || mbChatMessages.length === 0) {
        thread.innerHTML = '<p class="text-sm text-slate-500 italic">Start a conversation with your marketing assistant.</p>';
        return;
    }
    thread.innerHTML = mbChatMessages.map((m) => {
        const role = m.role === 'assistant' ? 'assistant' : 'user';
        const cls = role === 'assistant'
            ? 'bg-white border border-slate-200 text-slate-700'
            : 'bg-indigo-600 text-white border border-indigo-600 ml-6';
        return `<div class="rounded-xl px-3 py-2 text-sm ${cls}"><p class="text-[10px] uppercase tracking-wider font-bold ${role === 'assistant' ? 'text-slate-400' : 'text-indigo-100'} mb-1">${role}</p><div class="whitespace-pre-wrap">${escapeHtmlTextLocal(String(m.content || ''))}</div></div>`;
    }).join('');
    thread.scrollTop = thread.scrollHeight;
}

async function sendMbChatMessage(rawText) {
    const text = String(rawText || '').trim();
    if (!text || marketersBrainChatBusy) return;
    if (!CURRENT_CLIENT_ID) {
        UI.showToast('Client not ready. Refresh and try again.', false);
        return;
    }
    const input = document.getElementById('mb-chat-input');
    const sendBtn = document.getElementById('mb-chat-send-btn');
    marketersBrainChatBusy = true;
    if (sendBtn) sendBtn.disabled = true;
    mbChatMessages.push({ role: 'user', content: text });
    renderMbChatThread();
    if (input) input.value = '';
    try {
        const url = new URL('api/openai-chat.php', window.location.href).href;
        const response = await fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            credentials: 'same-origin',
            body: JSON.stringify({
                clientId: CURRENT_CLIENT_ID,
                messages: mbChatMessages.slice(-12),
                extraContext: {
                    selectedProductId: document.getElementById('ai-ads-dash-product-select')?.value || ''
                }
            })
        });
        const data = await response.json().catch(() => null);
        if (!response.ok || !data || data.status !== 'success' || !data.message || !data.message.content) {
            throw new Error((data && data.message) ? String(data.message) : `Chat failed (${response.status})`);
        }
        mbChatMessages.push({ role: 'assistant', content: String(data.message.content || '') });
        if (mbChatMessages.length > 30) mbChatMessages = mbChatMessages.slice(-30);
        renderMbChatThread();
    } catch (err) {
        UI.showToast(err.message || String(err), false);
    } finally {
        marketersBrainChatBusy = false;
        if (sendBtn) sendBtn.disabled = false;
    }
}

function bindMarketersBrainChatHandlers() {
    if (marketersBrainChatBound) return;
    marketersBrainChatBound = true;
    document.getElementById('mb-chat-send-btn')?.addEventListener('click', () => {
        const input = document.getElementById('mb-chat-input');
        sendMbChatMessage(input?.value || '');
    });
    document.getElementById('mb-chat-input')?.addEventListener('keydown', (e) => {
        if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
            e.preventDefault();
            sendMbChatMessage(e.target.value || '');
        }
    });
    document.getElementById('mb-chat-input')?.addEventListener('input', (e) => {
        const el = e.target;
        el.style.height = 'auto';
        el.style.height = `${Math.min(220, el.scrollHeight)}px`;
    });
    document.getElementById('mb-chat-clear-btn')?.addEventListener('click', () => {
        mbChatMessages = [];
        renderMbChatThread();
    });
    document.querySelectorAll('.mb-chat-quick-btn').forEach((btn) => {
        btn.addEventListener('click', () => {
            const prompt = btn.getAttribute('data-prompt') || '';
            sendMbChatMessage(prompt);
        });
    });
    renderMbChatThread();
}

async function handleAiAdsDashGenerate() {
    const selectedProductId = document.getElementById('ai-ads-dash-product-select')?.value || '';
    if (!selectedProductId) {
        setAiAdsDashGenerateStatus('Select a product first.', true);
        return;
    }
    if (!CURRENT_CLIENT_ID) {
        setAiAdsDashGenerateStatus('Client ID missing. Refresh and try again.', true);
        return;
    }
    const product = (allProducts || {})[selectedProductId];
    if (!product || !product.name) {
        setAiAdsDashGenerateStatus('Product data not found.', true);
        return;
    }

    const btn = document.getElementById('ai-ads-dash-generate-btn');
    const span = btn ? btn.querySelector('span') : null;
    const oldText = span ? span.textContent : '';
    if (btn) btn.disabled = true;
    if (span) span.textContent = 'Thinking…';
    setAiAdsDashGenerateStatus('Marketers Brain is generating your copy…');

    try {
        const url = new URL('api/openai-campaign-pack.php', window.location.href).href;
        const response = await fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            credentials: 'same-origin',
            body: JSON.stringify({
                clientId: CURRENT_CLIENT_ID,
                product: {
                    id: selectedProductId,
                    name: String(product.name || ''),
                    description: String(product.description || ''),
                    salePrice: Number(product.salePrice || 0),
                    regularPrice: Number(product.regularPrice || 0),
                    categories: Array.isArray(product.categories)
                        ? product.categories
                        : (product.category ? [product.category] : [])
                }
            })
        });
        const data = await response.json().catch(() => null);
        if (!response.ok || !data || data.status !== 'success') {
            throw new Error((data && data.message) ? String(data.message) : `AI request failed (${response.status})`);
        }
        const variants = Array.isArray(data.variants) ? data.variants : [];
        ['A', 'B', 'C'].forEach((key) => {
            const row = variants.find((v) => String(v.label || '').toUpperCase() === key) || { label: key };
            setAiAdsDashVariantData(row);
        });
        renderAiAdsDashInterestTags(data.suggestedInterests || []);
        setAiAdsDashAudienceBudget(data);
        switchAiVariantTab('A');
        setAiAdsDashGenerateStatus('Copy ready — refine in Review & Refine, then launch when Meta is connected.');
    } catch (err) {
        setAiAdsDashGenerateStatus(err.message || String(err), true);
    } finally {
        if (btn) btn.disabled = false;
        if (span) span.textContent = oldText || 'Generate Magic';
    }
}

function getShopSalesTodayAndMonth() {
    const orders = completedOrdersData || {};
    const now = new Date();
    const todayStr = now.toLocaleDateString('en-GB');
    const month = now.getMonth();
    const year = now.getFullYear();
    let today = 0;
    let monthTotal = 0;
    Object.values(orders).forEach((o) => {
        if (o.status === 'Canceled') return;
        const d = new Date(o.createdAt || o.timestamp || 0);
        const t = parseFloat(o.totalBill || 0);
        if (Number.isNaN(t)) return;
        if (d.getMonth() === month && d.getFullYear() === year) monthTotal += t;
        if (d.toLocaleDateString('en-GB') === todayStr) today += t;
    });
    return { today, monthTotal };
}

async function loadLiveAdsData(which) {
    const token = (siteSettings?.facebookConfig?.accessToken || '').trim();
    const overviewLoading = document.getElementById('live-ads-overview-loading');
    const overviewNo = document.getElementById('live-ads-overview-no-token');
    const overviewContent = document.getElementById('live-ads-overview-content');
    const fbLoading = document.getElementById('live-ads-fb-loading');
    const fbNo = document.getElementById('live-ads-fb-no-token');
    const fbContent = document.getElementById('live-ads-fb-content');

    const showOverviewShell = (hasToken) => {
        LiveAdsUI.showEl(overviewLoading, false);
        LiveAdsUI.showEl(overviewNo, !hasToken);
        LiveAdsUI.showEl(overviewContent, !!hasToken);
    };
    const showFbShell = (hasToken) => {
        LiveAdsUI.showEl(fbLoading, false);
        LiveAdsUI.showEl(fbNo, !hasToken);
        LiveAdsUI.showEl(fbContent, !!hasToken);
    };

    if (which === 'overview') {
        LiveAdsUI.showEl(overviewLoading, true);
        LiveAdsUI.showEl(overviewNo, false);
        LiveAdsUI.showEl(overviewContent, false);
    } else {
        LiveAdsUI.showEl(fbLoading, true);
        LiveAdsUI.showEl(fbNo, false);
        LiveAdsUI.showEl(fbContent, false);
    }

    if (!token) {
        if (which === 'overview') showOverviewShell(false);
        else showFbShell(false);
        return;
    }

    try {
        const configured = (siteSettings?.facebookConfig?.adAccountId || '').trim();
        const { accountId, accounts } = await FBAds.resolveAdAccountId(token, configured);
        const raw = await FBAds.fetchCampaignsWithInsights(token, accountId);
        const rows = FBAds.normalizeCampaignRows(raw);
        const totals = FBAds.aggregateTotals(rows);
        let currency = 'USD';
        if (accounts && accounts.length) {
            const match = accounts.find((a) => FBAds.normalizeAdAccountId(a.account_id) === accountId);
            if (match?.currency) currency = match.currency;
        } else {
            currency = await FBAds.fetchAdAccountCurrency(token, accountId);
        }
        if (which === 'overview') {
            showOverviewShell(true);
            const errEl = document.getElementById('live-ads-overview-error');
            LiveAdsUI.showEl(errEl, false);
            const { today, monthTotal } = getShopSalesTodayAndMonth();
            const tStr = today.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
            const mStr = monthTotal.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
            LiveAdsUI.setText('live-ads-expense-today', `৳ ${tStr}`);
            LiveAdsUI.setText('live-ads-expense-month', `৳ ${mStr}`);
            const spendStr = FBAds.formatMoney(totals.spend, currency);
            const spendHeadline = spendStr.startsWith('$') ? spendStr.replace('$', '$ ') : spendStr;
            LiveAdsUI.setText('live-ads-spend-total-line', spendHeadline);
            LiveAdsUI.setText('live-ads-spend-fb', spendStr);

            const ovLoad = document.getElementById('live-ads-overview-fb-loading');
            const ovWrap = document.getElementById('live-ads-overview-fb-table-wrap');
            LiveAdsUI.showEl(ovLoad, false);
            LiveAdsUI.showEl(ovWrap, true);
            const tbody = document.getElementById('live-ads-overview-fb-tbody');
            LiveAdsUI.renderCampaignTableRows(tbody, rows, currency, { showActions: false });
        } else {
            showFbShell(true);
            const errEl = document.getElementById('live-ads-fb-error');
            LiveAdsUI.showEl(errEl, false);
            LiveAdsUI.setText('live-ads-fb-card-spend', FBAds.formatMoney(totals.spend, currency));
            LiveAdsUI.setText('live-ads-fb-card-impr', totals.impressions.toLocaleString());
            LiveAdsUI.setText('live-ads-fb-card-clicks', totals.clicks.toLocaleString());
            LiveAdsUI.setText(
                'live-ads-fb-card-cpc',
                totals.clicks > 0 ? FBAds.formatMoney(totals.avgCpc, currency) : '—'
            );
            LiveAdsUI.setText('live-ads-fb-card-purchases', (totals.purchases || 0).toLocaleString());

            const tblLoad = document.getElementById('live-ads-fb-table-loading');
            const tblWrap = document.getElementById('live-ads-fb-table-wrap');
            LiveAdsUI.showEl(tblLoad, false);
            LiveAdsUI.showEl(tblWrap, true);
            const tbody = document.getElementById('live-ads-fb-tbody');
            LiveAdsUI.renderCampaignTableRows(tbody, rows, currency, { showActions: true });
        }
    } catch (err) {
        console.error('Live Ads load error:', err);
        const msg = err?.message || 'Failed to load Facebook Ads data.';
        if (which === 'overview') {
            showOverviewShell(true);
            const errEl = document.getElementById('live-ads-overview-error');
            if (errEl) {
                errEl.textContent = msg;
                LiveAdsUI.showEl(errEl, true);
            }
            LiveAdsUI.showEl(document.getElementById('live-ads-overview-fb-loading'), false);
            LiveAdsUI.showEl(document.getElementById('live-ads-overview-fb-table-wrap'), false);
        } else {
            showFbShell(true);
            const errEl = document.getElementById('live-ads-fb-error');
            if (errEl) {
                errEl.textContent = msg;
                LiveAdsUI.showEl(errEl, true);
            }
            LiveAdsUI.showEl(document.getElementById('live-ads-fb-table-loading'), false);
            LiveAdsUI.showEl(document.getElementById('live-ads-fb-table-wrap'), false);
        }
        UI.showToast(msg, false);
    }
}

async function maybeAutoPostProductToFacebookPage(productKey, data) {
    const cfg = siteSettings.facebookPagePost;
    if (!cfg?.autoPost) return;
    if (!cfg.pageId?.trim() || !cfg.pageAccessToken?.trim()) return;
    if (!SITE_INFO?.subdomain) return;
    const basePath = window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1);
    const link = FBPagePost.buildProductPublicUrl({
        basePath,
        subdomain: SITE_INFO.subdomain,
        productId: productKey,
        productData: data
    });
    const template =
        cfg.postTemplate != null && String(cfg.postTemplate).trim() !== ''
            ? cfg.postTemplate
            : 'New Product!\n\n{name}\n{price}\n{link}\n\n{description}';
    const message = FBPagePost.applyPostTemplate(template, {
        name: data.name || '',
        price: FBPagePost.formatPriceForPost(data.salePrice),
        link,
        description: FBPagePost.stripHtml(data.description || '')
    });
    await FBPagePost.postToPageFeed({
        pageId: cfg.pageId.trim(),
        accessToken: cfg.pageAccessToken.trim(),
        message,
        link
    });
    UI.showToast('Also posted to your Facebook Page.', true);
}

async function handleLiveAdsCampaignToggle(btn) {
    const token = (siteSettings?.facebookConfig?.accessToken || '').trim();
    const id = btn?.dataset?.campaignId;
    const next = btn?.dataset?.nextStatus;
    if (!token || !id || !next) return;
    if (!window.confirm(`Change campaign status to ${next}?`)) return;
    btn.disabled = true;
    try {
        await FBAds.setCampaignStatus(token, id, next);
        UI.showToast('Campaign updated.', true);
        await loadLiveAdsData('facebook');
        if (document.getElementById('dashboard-live-ads-overview')?.classList.contains('active')) {
            await loadLiveAdsData('overview');
        }
    } catch (e) {
        UI.showToast(e?.message || 'Could not update campaign.', false);
    } finally {
        btn.disabled = false;
    }
}

function refreshOrderDetailPanelIfVisible() {
    if (!currentOrderDetailId) return;
    const panel = document.getElementById('dashboard-order-detail');
    const content = document.getElementById('order-detail-content');
    if (!panel?.classList.contains('active') || !content) return;
    const order = completedOrdersData[currentOrderDetailId];
    if (!order) {
        content.innerHTML = '<div class="p-6 text-center text-red-600">This order is no longer available.</div>';
        return;
    }
    content.innerHTML = UI.generateCompletedOrderDetailHTML(currentOrderDetailId, order, CURRENT_CLIENT_ID, completedOrdersData);
}

function showOrderDetailPage(orderId, addHistory = true) {
    if (!orderId) {
        UI.showToast('Invalid order.', false);
        return;
    }
    closeAdminShellEmbedQuiet();
    if (!isDashboardPanelAccessAllowed('order-detail')) {
        UI.showToast('You do not have access to order details.', false);
        return;
    }
    currentOrderDetailId = orderId;
    document.querySelectorAll('.dashboard-panel').forEach((p) => p.classList.remove('active'));
    const panel = document.getElementById('dashboard-order-detail');
    if (!panel) return;
    panel.classList.add('active');
    manageRealtimeSubscriptionsForPanel('order-detail');
    const content = document.getElementById('order-detail-content');
    const order = completedOrdersData[orderId];
    if (content) {
        if (!order) {
            content.innerHTML = '<div class="p-6 text-black text-center">Loading order…</div>';
        } else {
            content.innerHTML = UI.generateCompletedOrderDetailHTML(orderId, order, CURRENT_CLIENT_ID, completedOrdersData);
        }
    }
    document.querySelectorAll('.sidebar-link').forEach((link) => {
        link.classList.remove('active');
        if (link.dataset.panel === 'completed-orders') link.classList.add('active');
    });
    UI.toggleSidebar(false);
    syncDashboardContentFitViewportClass();
    if (typeof UI.disconnectDashboardHomeChartResizeObservers === 'function') {
        UI.disconnectDashboardHomeChartResizeObservers();
    }
    if (addHistory) {
        const enc = encodeURIComponent(orderId);
        history.pushState({ panel: 'order-detail', orderId }, '', `#order-detail/${enc}`);
    }
}

// --- Website Customization sidebar tab styles ---
function syncCustomizationTabVisualState(activeTabId) {
    const nav = document.getElementById('customization-nav');
    if (!nav) return;
    const inactiveBtnClasses = ['text-black', 'font-medium', 'hover:bg-white', 'hover:text-black', 'border-transparent', 'bg-transparent'];
    const activeBtnClasses = ['bg-indigo-50', 'text-indigo-700', 'font-semibold', 'shadow-sm', 'ring-1', 'ring-indigo-100', 'border-indigo-100'];
    nav.querySelectorAll('.customization-tab-btn').forEach((btn) => {
        const isActive = btn.dataset.customizationTab === activeTabId;
        inactiveBtnClasses.forEach((c) => btn.classList.remove(c));
        activeBtnClasses.forEach((c) => btn.classList.remove(c));
        if (isActive) {
            activeBtnClasses.forEach((c) => btn.classList.add(c));
        } else {
            inactiveBtnClasses.forEach((c) => btn.classList.add(c));
        }
        const icon = btn.querySelector('.customization-tab-icon') || btn.querySelector('i');
        if (icon) {
            icon.classList.remove('text-indigo-600', 'text-black');
            icon.classList.add(isActive ? 'text-indigo-600' : 'text-black');
        }
    });
}

function syncIntegrationsTabVisualState(activeTabId) {
    const tabButtons = document.querySelectorAll('.integrations-tab-btn');
    tabButtons.forEach((btn) => {
        const active = btn.dataset.integrationsTab === activeTabId;
        btn.classList.toggle('bg-indigo-600', active);
        btn.classList.toggle('text-white', active);
        btn.classList.toggle('bg-gray-100', !active);
        btn.classList.toggle('text-black', !active);
    });
}

function activateIntegrationsTab(activeTabId) {
    const tabId = activeTabId || 'tracking';
    syncIntegrationsTabVisualState(tabId);
    document.querySelectorAll('.integration-tab-panel').forEach((panel) => {
        panel.classList.toggle('hidden', panel.dataset.integrationsTabPanel !== tabId);
    });
}

// --- Detective Brain (wealth segment aggregates) ---
function detectiveSegmentKey(wealthClass) {
    const s = String(wealthClass || '');
    if (s.includes('Elite')) return 'Elite';
    if (s.includes('Aspiring') || s.includes('Middle Class')) return 'Aspiring';
    return 'Standard';
}

/** Same normalization rules as VisitorSpy.processData (all visitors). */
function normalizeVisitorsForDetective(visitorData) {
    const now = Date.now();
    const onlineThreshold = 5 * 60 * 1000;
    return Object.entries(visitorData || {}).map(([id, visitor]) => {
        const isOnline = (now - visitor.lastActive) < onlineThreshold;
        const logs = Object.values(visitor.logs || {});
        const meta = visitor.meta || {};
        let intentLevel = 'browsing';
        let hasCart = false;
        let hasCheckout = false;
        logs.forEach((log) => {
            const act = (log.action || '').toLowerCase();
            const pg = (log.page || '').toLowerCase();
            if (act.includes('add') || act.includes('cart')) hasCart = true;
            if (pg.includes('checkout') || act.includes('checkout') || act.includes('purchase')) hasCheckout = true;
        });
        if (hasCheckout) intentLevel = 'checkout';
        else if (hasCart) intentLevel = 'cart_activity';
        const wealthClass = visitor.wealthClass || meta.wealthClass || 'Standard';
        const wealthScore = visitor.wealthScore || meta.wealthScore || 0;
        return {
            id,
            isOnline,
            intentLevel,
            wealthClass,
            wealthScore,
            lastActiveTime: visitor.lastActive || 0,
            meta,
        };
    });
}

function renderDetectiveBrainTopList(el, pairs) {
    if (!el) return;
    el.textContent = '';
    if (!pairs.length) {
        const p = document.createElement('p');
        p.className = 'text-xs text-slate-400 italic';
        p.textContent = 'No data yet.';
        el.appendChild(p);
        return;
    }
    pairs.forEach(([k, v]) => {
        const row = document.createElement('div');
        row.className = 'flex justify-between gap-2 text-xs py-1 border-b border-slate-100 last:border-0';
        const label = document.createElement('span');
        label.className = 'text-slate-600 truncate';
        label.textContent = k;
        label.title = k;
        const count = document.createElement('span');
        count.className = 'font-bold text-slate-800 shrink-0';
        count.textContent = String(v);
        row.appendChild(label);
        row.appendChild(count);
        el.appendChild(row);
    });
}

function topAggregatesFromRows(rows, getLabel, maxN) {
    const m = {};
    rows.forEach((r) => {
        const raw = getLabel(r);
        const k = String(raw || 'Unknown').trim().slice(0, 56) || 'Unknown';
        m[k] = (m[k] || 0) + 1;
    });
    return Object.entries(m).sort((a, b) => b[1] - a[1]).slice(0, maxN);
}

function renderDetectiveBrain() {
    const rows = normalizeVisitorsForDetective(visitorData);
    const total = rows.length;
    let online = 0;
    const seg = { Elite: [], Aspiring: [], Standard: [] };
    let missingExplicitWealth = 0;
    let intelPendingCount = 0;
    rows.forEach((r) => {
        if (r.isOnline) online++;
        seg[detectiveSegmentKey(r.wealthClass)].push(r);
        const raw = visitorData && visitorData[r.id] ? visitorData[r.id] : null;
        if (raw) {
            if (raw.intelPending === true) intelPendingCount++;
            const hasTop = Object.prototype.hasOwnProperty.call(raw, 'wealthClass');
            const hasMetaWc = raw.meta && Object.prototype.hasOwnProperty.call(raw.meta, 'wealthClass');
            if (!hasTop && !hasMetaWc) missingExplicitWealth++;
        }
    });
    if (missingExplicitWealth || intelPendingCount) {
        console.debug('[Detective] wealth field gaps (missing explicit class / intel pending)', {
            missingExplicitWealth,
            intelPendingCount,
            total
        });
    }

    const setTxt = (id, t) => {
        const e = document.getElementById(id);
        if (e) e.textContent = t;
    };

    setTxt('detective-total-visitors', String(total));
    setTxt('detective-online-now', String(online));

    const enriched = enrichVisitorsForDetective(visitorData, incompleteOrdersData);
    const bridge = enriched.filter((v) => v.identifiedProfile).length;
    setTxt('detective-bridge-count', String(bridge));

    ['Elite', 'Aspiring', 'Standard'].forEach((key) => {
        const list = seg[key];
        const c = list.length;
        const on = list.filter((x) => x.isOnline).length;
        const avg = c ? Math.round(list.reduce((s, x) => s + (Number(x.wealthScore) || 0), 0) / c) : 0;
        const hi = list.filter((x) => x.intentLevel === 'checkout' || x.intentLevel === 'cart_activity').length;
        const hiPct = c ? Math.round((hi / c) * 100) : 0;
        const slug = key.toLowerCase();
        setTxt(`detective-segment-${slug}-count`, String(c));
        setTxt(`detective-${slug}-online`, String(on));
        setTxt(`detective-${slug}-avg-score`, String(avg));
        setTxt(`detective-${slug}-high-intent-pct`, `${hiPct}%`);
        renderDetectiveBrainTopList(
            document.getElementById(`detective-top-cities-${slug}`),
            topAggregatesFromRows(list, (r) => r.meta?.city || r.meta?.location || 'Unknown', 5)
        );
        renderDetectiveBrainTopList(
            document.getElementById(`detective-top-gpus-${slug}`),
            topAggregatesFromRows(list, (r) => r.meta?.gpu || 'Unknown', 5)
        );
    });

    const pct = (n) => (total ? Math.round((n / total) * 100) : 0);
    setTxt('detective-pct-elite', `${pct(seg.Elite.length)}% of traffic`);
    setTxt('detective-pct-aspiring', `${pct(seg.Aspiring.length)}% of traffic`);
    setTxt('detective-pct-standard', `${pct(seg.Standard.length)}% of traffic`);
}

// --- Firebase usage (Cloud Monitoring via api/firebase-usage-metrics.php) ---
let firebaseUsageTimer = null;

function formatUsageBytes(n) {
    if (n == null || Number.isNaN(Number(n))) return '—';
    const x = Number(n);
    if (x < 0) return '—';
    if (x < 1024) return `${x.toLocaleString()} B`;
    const units = ['KB', 'MB', 'GB', 'TB'];
    let v = x;
    let i = -1;
    do {
        v /= 1024;
        i++;
    } while (v >= 1024 && i < units.length - 1);
    const decimals = i <= 0 ? 0 : i === 1 ? 1 : 2;
    return `${v.toFixed(decimals)} ${units[i]}`;
}

function stopFirebaseUsageRefresh() {
    if (firebaseUsageTimer) {
        clearInterval(firebaseUsageTimer);
        firebaseUsageTimer = null;
    }
}

function setFirebaseUsageUiLoading() {
    const ids = ['firebase-usage-dl-24h', 'firebase-usage-rtdb-stored', 'firebase-usage-connections', 'firebase-usage-storage'];
    ids.forEach((id) => {
        const el = document.getElementById(id);
        if (el) el.textContent = '…';
    });
    const st = document.getElementById('firebase-usage-status');
    if (st) st.textContent = '';
}

function setFirebaseUsageError(msg) {
    const st = document.getElementById('firebase-usage-status');
    if (st) st.textContent = msg || '';
    const ids = ['firebase-usage-dl-24h', 'firebase-usage-rtdb-stored', 'firebase-usage-connections'];
    ids.forEach((id) => {
        const el = document.getElementById(id);
        if (el) el.textContent = '—';
    });
    const sg = document.getElementById('firebase-usage-storage');
    if (sg) sg.textContent = '—';
}

async function refreshFirebaseUsagePanel() {
    const section = document.getElementById('firebase-usage-section');
    if (!section || !CURRENT_CLIENT_ID) return;
    const user = auth.currentUser;
    if (!user) {
        setFirebaseUsageError('Sign in to load Firebase usage.');
        return;
    }
    try {
        const idToken = await user.getIdToken();
        const url = new URL('api/firebase-usage-metrics.php', window.location.href).href;
        const res = await fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ clientId: CURRENT_CLIENT_ID, idToken }),
        });
        const data = await res.json().catch(() => ({}));
        if (!res.ok || !data.ok) {
            const msg = (data && data.message) || (data && data.error) || `HTTP ${res.status}`;
            setFirebaseUsageError(String(msg));
            const up = document.getElementById('firebase-usage-updated');
            if (up) up.textContent = 'Error';
            return;
        }
        const st = document.getElementById('firebase-usage-status');
        if (st) st.textContent = '';

        const dl = document.getElementById('firebase-usage-dl-24h');
        if (dl) dl.textContent = formatUsageBytes(data.rtdb?.downloadBytesLast24h);
        const stb = document.getElementById('firebase-usage-rtdb-stored');
        if (stb) stb.textContent = formatUsageBytes(data.rtdb?.storedBytes);
        const cn = document.getElementById('firebase-usage-connections');
        if (cn) {
            const c = data.rtdb?.activeConnections;
            cn.textContent = c != null ? String(c) : '—';
        }
        const sg = document.getElementById('firebase-usage-storage');
        const sgh = document.getElementById('firebase-usage-storage-hint');
        if (data.storage && data.storage.bucketName) {
            if (sg) sg.textContent = formatUsageBytes(data.storage.totalBytes);
            if (sgh) sgh.textContent = data.storage.bucketName;
        } else {
            if (sg) sg.textContent = '—';
            if (sgh) sgh.textContent = 'Optional: set gcp_storage_bucket_name in api/firebase-admin-bootstrap.local.php';
        }
        const up = document.getElementById('firebase-usage-updated');
        if (up) {
            const t = data.lastUpdated ? new Date(Number(data.lastUpdated)) : new Date();
            up.textContent = `Updated ${t.toLocaleString()}`;
        }
    } catch (e) {
        setFirebaseUsageError(e && e.message ? String(e.message) : 'Could not load usage.');
    }
}

function startFirebaseUsageRefresh() {
    stopFirebaseUsageRefresh();
    if (!FIREBASE_USAGE_SECTION_ENABLED) return;
    if (!document.getElementById('firebase-usage-section')) return;
    setFirebaseUsageUiLoading();
    refreshFirebaseUsagePanel().catch(() => {});
    firebaseUsageTimer = setInterval(() => {
        if (isPanelActive('home')) refreshFirebaseUsagePanel().catch(() => {});
    }, 90000);
}

// --- Panel Navigation ---
function showDashboardPanel(panelId, addHistory = true) {
    panelId = normalizePanelId(panelId);
    if (panelId === 'order-detail') return;

    closeAdminShellEmbedQuiet();

    if (panelId === 'theme') {
        if (!isDashboardPanelAccessAllowed('theme')) {
            UI.showToast('You do not have access to this section.', false);
            showDashboardPanel('home', false);
            return;
        }
        let currentTheme = siteSettings.layout?.activeDesign || 'ghorerbazar';
        if (currentTheme === 'swapno') currentTheme = 'classic';
        const radio = document.querySelector(`#theme-change-modal input[value="${currentTheme}"]`);
        if(radio) radio.checked = true;
        UI.toggleModal('theme-change-modal', true);
        return;
    }

    if (!isDashboardPanelAccessAllowed(panelId)) {
        UI.showToast('You do not have access to this section.', false);
        showDashboardPanel('home', false);
        return;
    }

    currentOrderDetailId = null;
    if (panelId === 'completed-orders') dedupeCompletedOrdersPanelDom();

    let targetPanel = document.getElementById(`dashboard-${panelId}`);
    if (!targetPanel && !dashboardPanelsLoaded.settings) {
        ensureSettingsPanelsLoaded()
            .then(() => showDashboardPanel(panelId, addHistory))
            .catch(() => {
                UI.showToast('Could not load settings panel.', false);
                restoreHomePanelAsSafeFallback();
            });
        return;
    }

    targetPanel = targetPanel || document.getElementById(`dashboard-${panelId}`);
    if (!targetPanel && panelId !== 'home') {
        console.warn(`[Dashboard] Panel not found for id: ${panelId}`);
        UI.showToast(`Panel "${panelId}" not found. Redirected to Home.`, false);
    }

    const resolvedPanelId = targetPanel ? panelId : 'home';
    const panelToActivate = targetPanel || document.getElementById('dashboard-home');

    if (resolvedPanelId !== 'home') {
        stopFirebaseUsageRefresh();
    }

    // Hide all, show target
    document.querySelectorAll('.dashboard-panel').forEach(p => p.classList.remove('active'));
    manageRealtimeSubscriptionsForPanel(resolvedPanelId);
    if (panelToActivate) {
        panelToActivate.classList.add('active');
        
        // Push to History (SPA Navigation)
        if (addHistory) {
            const newUrl = resolvedPanelId === 'home' ? window.location.pathname : `#${resolvedPanelId}`;
            history.pushState({ panel: resolvedPanelId }, '', newUrl);
        }
    } else {
        // Fallback to home if panel not found
        restoreHomePanelAsSafeFallback();
    }
    
    // Update Sidebar Active State
    document.querySelectorAll('.sidebar-link').forEach(link => {
        link.classList.remove('active');
        if(link.dataset.panel === resolvedPanelId) link.classList.add('active');
    });

    UI.toggleSidebar(false);

    syncDashboardContentFitViewportClass();
    if (resolvedPanelId !== 'home' && typeof UI.disconnectDashboardHomeChartResizeObservers === 'function') {
        UI.disconnectDashboardHomeChartResizeObservers();
    }

    // Logic for specific panels
    if (resolvedPanelId === 'completed-orders') { 
        localStorage.setItem(`last_viewed_${CURRENT_CLIENT_ID}`, Object.keys(completedOrdersData).length); 
        updateOrderNotification(); 
        renderCompletedOrders(); 
    } 
    else if (resolvedPanelId === 'incomplete-orders') { 
        renderIncompleteOrders(); 
    }
    else if (resolvedPanelId === 'visitor-spy') { 
        if (SESSION_REPLAY_ENABLED && !sessionMonitorInitialized) initSessionMonitor();
        if (!visitorSpyModule) visitorSpyModule = new VisitorSpy('spy-insights-container');
        const container = document.getElementById('spy-insights-container');
        if(container) container.classList.remove('hidden');
        visitorSpyModule.update(visitorData);
        if (!spyIntelligenceModule) spyIntelligenceModule = new SpyIntelligence();
        spyIntelligenceModule.update(visitorData, incompleteOrdersData);
    }
    else if (resolvedPanelId === 'hosting') { 
        renderHostingPanel(); 
    }
    else if (resolvedPanelId === 'customers') {
        customerProfiles = processCustomerData(completedOrdersData);
        UI.renderCustomerList(customerProfiles);
    }
    else if (resolvedPanelId === 'customization') {
        const tabId = pendingCustomizationTabId || 'theme';
        pendingCustomizationTabId = null;
        const panels = document.querySelectorAll('.customization-tab-panel');
        syncCustomizationTabVisualState(tabId);
        panels.forEach(panel => {
            panel.classList.toggle('hidden', panel.dataset.tab !== tabId);
        });
        refreshHeaderCategoriesSelector();
        const scrollId = pendingCustomizationScrollElId;
        pendingCustomizationScrollElId = null;
        if (scrollId) {
            requestAnimationFrame(() => {
                document.getElementById(scrollId)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
            });
        }
    }
    else if (resolvedPanelId === 'products') {
        // Refresh category checkboxes so they are always populated when user opens Products panel
        if (allCategories && typeof UI.populateCategoryDropdown === 'function') {
            UI.populateCategoryDropdown(allCategories);
        }
        UI.renderProducts(allProducts);
    }
    else if (resolvedPanelId === 'add-category') {
        UI.renderCategories(allCategories, categoryOrder);
    }
    else if (resolvedPanelId === 'live-ads-overview') {
        expandLiveAdsSidebarGroup(true);
        loadLiveAdsData('overview');
    }
    else if (resolvedPanelId === 'live-ads-facebook') {
        expandLiveAdsSidebarGroup(true);
        loadLiveAdsData('facebook');
    }
    else if (resolvedPanelId === 'ai-ads-manager') {
        refreshAiAdsDashProductSelect();
        initAiVariantTabs();
        bindMarketersBrainChatHandlers();
        setAiAdsDashGenerateStatus('');
    }
    else if (resolvedPanelId === 'detective-brain') {
        renderDetectiveBrain();
    }
    else if (resolvedPanelId === 'notifications') {
        refreshPushSubscriberCount().catch(() => {});
    }
    else if (resolvedPanelId === 'integrations') {
        activateIntegrationsTab('tracking');
        bindOpenAiSettingsHandlers();
        if (!blockedIpsLoadedOnce) {
            blockedIpsLoadedOnce = true;
            refreshBlockedIpsUI().catch(() => {});
        }
    }
    else if (resolvedPanelId === 'home') {
        if (SESSION_REPLAY_ENABLED && !sessionMonitorInitialized) initSessionMonitor();
        bindDashboardHomeUx();
        scheduleDashboardUpdate();
        startFirebaseUsageRefresh();
    }
}

function dedupeCompletedOrdersPanelDom() {
    if (typeof document === 'undefined') return;
    const panelNodes = Array.from(document.querySelectorAll('#dashboard-completed-orders'));
    if (panelNodes.length > 1) {
        let keep = panelNodes.find((n) => n.querySelector('#order-status-chips')) || panelNodes[panelNodes.length - 1];
        panelNodes.forEach((n) => { if (n !== keep) n.remove(); });
    }
}

function searchTextIncludes(haystack, needle) {
    return String(haystack || '').toLowerCase().includes(String(needle || '').toLowerCase());
}

function getAdminSearchResults(queryRaw) {
    const query = String(queryRaw || '').trim().toLowerCase();
    if (!query || query.length < 2) return [];

    const staticMatches = ADMIN_SEARCH_PANEL_ENTRIES.filter((item) => {
        if (searchTextIncludes(item.title, query)) return true;
        if (searchTextIncludes(item.type, query)) return true;
        if (searchTextIncludes(item.panelId, query)) return true;
        return Array.isArray(item.keywords) && item.keywords.some((k) => searchTextIncludes(k, query));
    }).map((item) => ({ ...item, score: 10 }));

    const productMatches = Object.entries(allProducts || {})
        .filter(([, product]) => {
            if (!product || typeof product !== 'object') return false;
            const categories = Array.isArray(product.categories) ? product.categories.join(' ') : '';
            const tags = Array.isArray(product.tags) ? product.tags.join(' ') : '';
            return [product.name, product.category, categories, product.subcategory, tags].some((part) => searchTextIncludes(part, query));
        })
        .slice(0, 8)
        .map(([id, product]) => ({
            type: 'Product',
            title: product?.name || `Product ${id}`,
            subtitle: product?.category || '',
            icon: 'fa-tag',
            panelId: 'products',
            productId: id,
            score: 8
        }));

    const completedOrderMatches = Object.entries(completedOrdersData || {})
        .filter(([id, order]) => {
            const customer = order?.customerInfo || {};
            return [id, customer.name, customer.phone, customer.address].some((part) => searchTextIncludes(part, query));
        })
        .slice(0, 6)
        .map(([id, order]) => ({
            type: 'Order',
            title: `Order #${id.slice(-8)}`,
            subtitle: order?.customerInfo?.name || order?.customerInfo?.phone || '',
            icon: 'fa-receipt',
            actionType: 'openOrder',
            orderId: id,
            panelId: 'completed-orders',
            score: 9
        }));

    const incompleteOrderMatches = Object.entries(incompleteOrdersData || {})
        .filter(([id, order]) => [id, order?.name, order?.phone, order?.address].some((part) => searchTextIncludes(part, query)))
        .slice(0, 4)
        .map(([id, order]) => ({
            type: 'Incomplete Order',
            title: `Incomplete #${id.slice(-8)}`,
            subtitle: order?.name || order?.phone || '',
            icon: 'fa-box-open',
            panelId: 'incomplete-orders',
            score: 7
        }));

    const merged = [...staticMatches, ...productMatches, ...completedOrderMatches, ...incompleteOrderMatches].filter(isAdminSearchResultAccessAllowed);
    merged.sort((a, b) => b.score - a.score || String(a.title).localeCompare(String(b.title)));
    return merged.slice(0, 20);
}

function clearSearchHighlight() {
    if (!currentSearchHighlightEl) return;
    currentSearchHighlightEl.classList.remove(
        'ring-4',
        'ring-red-500',
        'ring-opacity-70',
        'transition-all',
        'bg-red-50'
    );
    currentSearchHighlightEl.removeEventListener('focusin', clearSearchHighlight);
    currentSearchHighlightEl.removeEventListener('click', clearSearchHighlight);
    currentSearchHighlightEl = null;
}

function applySearchFocusHighlight(targetId) {
    if (!targetId) return;
    const targetEl = document.getElementById(targetId);
    if (!targetEl) return;
    clearSearchHighlight();
    targetEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
    targetEl.classList.add('ring-4', 'ring-red-500', 'ring-opacity-70', 'transition-all', 'bg-red-50');
    currentSearchHighlightEl = targetEl;
    targetEl.addEventListener('focusin', clearSearchHighlight);
    targetEl.addEventListener('click', clearSearchHighlight);
    setTimeout(clearSearchHighlight, 10000);
}

function activateCustomizationTabIfNeeded(tabId) {
    if (!tabId) return;
    const tabBtn = document.querySelector(`.customization-tab-btn[data-customization-tab="${tabId}"]`);
    if (tabBtn) tabBtn.click();
}

function openProductEditorFromSearch(productId) {
    if (!productId) return;
    showDashboardPanel('products');
    setTimeout(() => {
        const safeId = String(productId).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
        const editBtn = document.querySelector(`[data-action="editProduct"][data-id="${safeId}"]`);
        if (editBtn) {
            editBtn.click();
            return;
        }
        const data = allProducts && allProducts[productId];
        if (data) UI.showToast(`Found product: ${data.name || productId}. Scroll list or use Edit button.`);
    }, 250);
}

function handleAdminSearchResultClick(result) {
    if (!result) return;
    if (!isAdminSearchResultAccessAllowed(result)) {
        UI.showToast('You do not have access to this section.', false);
        showDashboardPanel('home', false);
        return;
    }
    if (result.actionType === 'openOrder' && result.orderId) {
        showOrderDetailPage(result.orderId, true);
        return;
    }
    if (result.type === 'Product' && result.productId) {
        openProductEditorFromSearch(result.productId);
        return;
    }

    const panelId = result.panelId || 'home';
    showDashboardPanel(panelId);

    setTimeout(() => {
        activateCustomizationTabIfNeeded(result.customizationTab);
        setTimeout(() => applySearchFocusHighlight(result.targetId), 80);
    }, 180);
}

function renderGlobalAdminSearchResults(results, queryRaw) {
    const container = document.getElementById('global-search-results');
    if (!container) return;
    const query = String(queryRaw || '').trim();

    if (!query || query.length < 2) {
        container.classList.add('hidden');
        container.innerHTML = '';
        globalSearchSelectedIndex = -1;
        return;
    }

    if (!results.length) {
        container.innerHTML = `<div class="px-4 py-3 text-sm text-gray-400 text-center">No results found for "${escapeHtmlTextLocal(query)}"</div>`;
        container.classList.remove('hidden');
        globalSearchSelectedIndex = -1;
        return;
    }

    container.innerHTML = results.map((result) => {
        const title = escapeHtmlTextLocal(result.title || 'Untitled');
        const subtitle = escapeHtmlTextLocal(result.subtitle || `${result.type || 'Result'} -> ${result.panelId || 'home'}`);
        const icon = escapeHtmlTextLocal(result.icon || 'fa-magnifying-glass');
        return `
            <button type="button" class="global-search-result-item w-full text-left px-4 py-3 border-b border-gray-800 last:border-b-0 hover:bg-gray-800 transition flex items-start gap-3" data-search-result="${escapeHtmlTextLocal(JSON.stringify(result))}">
                <span class="w-9 h-9 rounded-lg bg-gray-800 text-indigo-400 flex items-center justify-center shrink-0 mt-0.5 ring-1 ring-gray-700"><i class="fa-solid ${icon} text-sm"></i></span>
                <span class="min-w-0">
                    <span class="block text-sm font-semibold text-gray-100 truncate">${title}</span>
                    <span class="block text-xs text-gray-400 truncate">${subtitle}</span>
                </span>
            </button>
        `;
    }).join('');
    container.classList.remove('hidden');
    globalSearchSelectedIndex = -1;
}

function setActiveGlobalSearchResult(resultsContainer, nextIndex) {
    const items = Array.from(resultsContainer.querySelectorAll('.global-search-result-item'));
    if (!items.length) {
        globalSearchSelectedIndex = -1;
        return;
    }
    const maxIndex = items.length - 1;
    const clamped = Math.max(0, Math.min(maxIndex, nextIndex));
    globalSearchSelectedIndex = clamped;
    items.forEach((el, idx) => {
        const active = idx === clamped;
        el.classList.toggle('bg-gray-800', active);
        el.classList.toggle('ring-1', active);
        el.classList.toggle('ring-inset', active);
        el.classList.toggle('ring-gray-700', active);
    });
    items[clamped].scrollIntoView({ block: 'nearest' });
}

function bindGlobalAdminSearch() {
    if (globalAdminSearchBound) return;
    const input = document.getElementById('global-admin-search');
    const resultsContainer = document.getElementById('global-search-results');
    if (!input || !resultsContainer) return;
    globalAdminSearchBound = true;

    input.addEventListener('input', (e) => {
        const query = e.target.value || '';
        const results = getAdminSearchResults(query);
        renderGlobalAdminSearchResults(results, query);
    });

    input.addEventListener('keydown', (e) => {
        if ((e.ctrlKey || e.metaKey) && String(e.key || '').toLowerCase() === 'k') {
            e.preventDefault();
            input.focus();
            if (input.value) input.dispatchEvent(new Event('input'));
            return;
        }
        if (e.key === 'Escape') {
            resultsContainer.classList.add('hidden');
            globalSearchSelectedIndex = -1;
            return;
        }
        if (e.key === 'ArrowDown') {
            e.preventDefault();
            const start = globalSearchSelectedIndex < 0 ? 0 : globalSearchSelectedIndex + 1;
            setActiveGlobalSearchResult(resultsContainer, start);
            return;
        }
        if (e.key === 'ArrowUp') {
            e.preventDefault();
            const start = globalSearchSelectedIndex < 0 ? 0 : globalSearchSelectedIndex - 1;
            setActiveGlobalSearchResult(resultsContainer, start);
            return;
        }
        if (e.key === 'Enter') {
            const items = Array.from(resultsContainer.querySelectorAll('.global-search-result-item'));
            const selected = (globalSearchSelectedIndex >= 0 && globalSearchSelectedIndex < items.length)
                ? items[globalSearchSelectedIndex]
                : items[0];
            if (selected) {
                e.preventDefault();
                selected.click();
            }
        }
    });

    document.addEventListener('keydown', (e) => {
        if ((e.ctrlKey || e.metaKey) && String(e.key || '').toLowerCase() === 'k') {
            const tag = (e.target && e.target.tagName) ? e.target.tagName.toUpperCase() : '';
            if (tag !== 'INPUT' && tag !== 'TEXTAREA') e.preventDefault();
            input.focus();
            if (input.value) input.dispatchEvent(new Event('input'));
        }
    });

    resultsContainer.addEventListener('click', (e) => {
        const item = e.target.closest('.global-search-result-item[data-search-result]');
        if (!item) return;
        const raw = item.getAttribute('data-search-result') || '';
        let parsed = null;
        try { parsed = JSON.parse(raw); } catch (_) { parsed = null; }
        if (!parsed) return;

        resultsContainer.classList.add('hidden');
        input.value = '';
        globalSearchSelectedIndex = -1;
        handleAdminSearchResultClick(parsed);
    });

    document.addEventListener('click', (e) => {
        const target = e.target instanceof Element ? e.target : null;
        if (!target) return;
        if (target.closest('#global-admin-search') || target.closest('#global-search-results')) return;
        resultsContainer.classList.add('hidden');
        globalSearchSelectedIndex = -1;
    });
}

// --- CRM / Customer Logic ---
function processCustomerData(orders) {
    const customersMap = {};

    Object.entries(orders).forEach(([orderId, order]) => {
        const phone = order.customerInfo?.phone;
        if (!phone) return;

        if (!customersMap[phone]) {
            customersMap[phone] = {
                name: order.customerInfo.name || 'Unknown',
                phone: phone,
                address: order.customerInfo.address,
                totalSpent: 0,
                orderCount: 0,
                lastOrderDate: 0,
                firstSeen: order.createdAt || Date.now(),
                history: [],
                lastMeta: {},
                source: 'Direct'
            };
        }

        const c = customersMap[phone];
        c.totalSpent += parseFloat(order.totalBill || 0);
        c.orderCount++;
        c.lastOrderDate = Math.max(c.lastOrderDate, order.createdAt || 0);
        
        if (order.meta) {
            c.lastMeta = { ...c.lastMeta, ...order.meta };
        }
        
        if (order.clickId || order.fbclid) c.source = "Facebook Ads";

        c.history.push({
            type: 'order',
            title: `Order Placed (#${orderId.slice(-6)})`,
            details: `${order.items?.length || 0} items - ${order.totalBill} ৳`,
            timestamp: order.createdAt || Date.now()
        });
    });

    return Object.values(customersMap)
        .map(c => ({
            ...c,
            isVIP: c.totalSpent > 5000 || c.orderCount >= 3
        }))
        .sort((a, b) => b.lastOrderDate - a.lastOrderDate); 
}

// --- Order Rendering Logic ---
function syncOrderStatusChips() {
    const chips = document.getElementById('order-status-chips');
    if (!chips) return;
    const want = !orderState.statusFilter || orderState.statusFilter === 'All' ? 'All' : orderState.statusFilter;
    chips.querySelectorAll('.order-status-chip[data-order-status]').forEach((btn) => {
        const on = btn.dataset.orderStatus === want;
        btn.classList.toggle('bg-blue-600', on);
        btn.classList.toggle('text-white', on);
        btn.classList.toggle('border-blue-600', on);
        btn.classList.toggle('bg-white', !on);
        btn.classList.toggle('text-black', !on);
        btn.classList.toggle('border-gray-200', !on);
    });
}

function syncCompletedOrdersToolbar() {
    const pgs = document.getElementById('order-page-size');
    if (pgs) pgs.value = String(orderState.itemsPerPage);
    const df = document.getElementById('order-date-filter');
    if (df) df.value = orderState.dateYmd || '';
    syncOrderStatusChips();
}

function renderCompletedOrders() {
    UI.renderCompletedOrdersTableView({
        tbodyId: 'completed-orders-table-body',
        paginationId: 'completed-orders-list-pagination',
        data: completedOrdersData,
        state: orderState
    });
    syncCompletedOrdersToolbar();
}

function renderIncompleteOrders() {
    UI.renderMasterDetailView({ 
        containerId: 'incomplete-orders-list', 
        detailContainerId: 'incomplete-orders-detail', 
        data: incompleteOrdersData, 
        title: "Incomplete Orders", 
        itemRenderer: (id, order) => `
            <div class="master-item p-3 border-b border-l-4 border-transparent cursor-pointer hover:bg-gray-50 bg-white" data-id="${id}" data-action="viewIncompleteDetail">
                <p class="font-semibold text-sm text-black">${order.name || 'Unknown'}</p>
                <span class="text-xs text-black">${order.phone || 'No Phone'}</span>
                <div id="inline-details-${id}" class="order-inline-details hidden mt-3 border-t pt-3"></div>
            </div>`, 
        detailRenderer: UI.generateIncompleteOrderDetailHTML, 
        state: incompleteOrderState 
    });
}

// --- Action Handlers ---

function escapeCssAttrSelector(v) {
    const s = String(v ?? '');
    if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') return CSS.escape(s);
    return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}

function dashboardPublicApiFileUrl(fileName) {
    const f = String(fileName || '').replace(/^\/+/, '');
    const base =
        typeof window !== 'undefined' && window.SB_PUBLIC_API_BASE != null
            ? String(window.SB_PUBLIC_API_BASE).trim().replace(/\/$/, '')
            : '';
    if (base) return `${base}/${f}`;
    return new URL(`api/${f}`, window.location.href).href;
}

function fraudProxyUrl() {
    return dashboardPublicApiFileUrl('fraud-check-proxy.php');
}

/** Set to false to re-enable live FraudChecker API calls from order detail. */
const FRAUD_CHECK_MAINTENANCE_MODE = true;

function showFraudCheckMaintenanceModalDashboard() {
    if (typeof document === 'undefined') return;
    let overlay = document.getElementById('fraud-maintenance-modal-overlay');
    if (overlay) {
        overlay.classList.remove('hidden');
        overlay.setAttribute('aria-hidden', 'false');
        return;
    }
    overlay = document.createElement('div');
    overlay.id = 'fraud-maintenance-modal-overlay';
    overlay.setAttribute('role', 'dialog');
    overlay.setAttribute('aria-modal', 'true');
    overlay.setAttribute('aria-labelledby', 'fraud-maintenance-modal-title');
    overlay.setAttribute('aria-hidden', 'false');
    overlay.className = 'fixed inset-0 z-[12000] flex items-center justify-center p-4 bg-slate-900/60 backdrop-blur-sm';
    overlay.innerHTML = `
        <div class="w-full max-w-md rounded-2xl border border-slate-200 bg-white p-6 shadow-2xl">
            <div class="flex h-12 w-12 items-center justify-center rounded-xl bg-amber-50 text-amber-600 mb-4">
                <i class="fa-solid fa-screwdriver-wrench text-xl" aria-hidden="true"></i>
            </div>
            <h2 id="fraud-maintenance-modal-title" class="text-lg font-bold text-slate-900 mb-2">সিস্টেম আপডেট চলছে</h2>
            <p class="text-sm text-slate-600 leading-relaxed mb-6">সিস্টেমটিকে আরও উন্নত ও উপকারী করার জন্য বর্তমানে আপডেট এর কাজ চলছে। সাময়িক অসুবিধার জন্য আমরা আন্তরিকভাবে দুঃখিত।</p>
            <button type="button" data-fraud-maintenance-dismiss class="w-full py-3 rounded-xl text-sm font-bold text-white bg-indigo-600 hover:bg-indigo-700 transition-colors">ঠিক আছে</button>
        </div>`;
    const closeModal = () => {
        overlay.classList.add('hidden');
        overlay.setAttribute('aria-hidden', 'true');
    };
    overlay.addEventListener('click', (e) => {
        if (e.target === overlay) closeModal();
    });
    overlay.querySelector('[data-fraud-maintenance-dismiss]').addEventListener('click', closeModal);
    document.body.appendChild(overlay);
}

function steadfastCreateOrderProxyUrl() {
    return dashboardPublicApiFileUrl('steadfast-create-order-proxy.php');
}

function pushSendApiUrl() {
    return dashboardPublicApiFileUrl('push-send.php');
}

function onlyDigits(str) { return String(str || '').replace(/\D/g, ''); }

function pickFraud(obj, keys) {
    if (!obj || typeof obj !== 'object') return undefined;
    for (let i = 0; i < keys.length; i++) {
        if (obj[keys[i]] !== undefined && obj[keys[i]] !== null) return obj[keys[i]];
    }
}

function extractCourierRowsFraud(data) {
    const candidates = ['courier_data', 'couriers', 'networks', 'parcel_by_courier', 'data'];
    for (let i = 0; i < candidates.length; i++) {
        const v = data[candidates[i]];
        if (Array.isArray(v) && v.length) return v;
    }
    if (data.result && typeof data.result === 'object') {
        for (let i = 0; i < candidates.length; i++) {
            const r = data.result[candidates[i]];
            if (Array.isArray(r) && r.length) return r;
        }
    }
    return [];
}

function normalizeFraudRow(raw) {
    const name = String(pickFraud(raw, ['name', 'courier', 'courier_name', 'network', 'title', 'bn_name']) || 'Unknown');
    const total = Number(pickFraud(raw, ['total', 'total_order', 'total_orders', 'orders', 'parcel', 'count'])) || 0;
    const success = Number(pickFraud(raw, ['success', 'successful', 'delivered', 'success_count'])) || 0;
    const ret = Number(pickFraud(raw, ['return', 'returns', 'cancel', 'cancelled', 'failed'])) || 0;
    let rate = Number(pickFraud(raw, ['success_rate', 'rate', 'percentage', 'percent'])) || 0;
    if (!rate && total > 0) rate = Math.round((success / total) * 1000) / 10;
    return { name, total, success, ret, rate };
}

function buildOrderFraudRiskModel(data, rows) {
    let total = 0, success = 0, ret = 0;
    rows.forEach((r) => {
        total += r.total || 0;
        success += r.success || 0;
        ret += r.ret || 0;
    });
    const isFraud = data?.is_fraud === true;
    const successRate = total > 0 ? (success / total) * 100 : (isFraud ? 20 : 75);
    const returnRate = total > 0 ? (ret / total) * 100 : (isFraud ? 65 : 20);
    const lowDataPenalty = total < 5 ? 10 : total < 15 ? 5 : 0;
    const fraudFlagPenalty = isFraud ? 28 : 0;
    const scoreRaw = (returnRate * 0.55) + ((100 - successRate) * 0.35) + lowDataPenalty + fraudFlagPenalty;
    const riskScore = Math.max(0, Math.min(100, Math.round(scoreRaw)));
    let verdict = 'Review manually';
    let action = 'Call once and reconfirm address before shipping.';
    if (riskScore < 35) {
        verdict = 'Safe to ship';
        action = 'Proceed with normal shipping.';
    } else if (riskScore >= 70) {
        verdict = 'High risk';
        action = 'Hold parcel or require strict pre-verification.';
    }
    return { riskScore, verdict, action, total, success, ret };
}

function setOrderFraudLoading(detailHost, orderId, loading) {
    const card = detailHost?.querySelector(`[data-fraud-card][data-id="${escapeCssAttrSelector(orderId)}"]`);
    if (!card) return { stop: () => {} };
    const btn = card.querySelector(`[data-action="runOrderFraudCheck"][data-id="${escapeCssAttrSelector(orderId)}"]`);
    const loadingBox = card.querySelector('[data-fraud-loading]');
    const loadingText = card.querySelector('[data-fraud-loading-text]');
    if (btn) btn.disabled = loading;
    if (loadingBox) loadingBox.classList.toggle('hidden', !loading);
    if (!loading) return { stop: () => {} };

    const steps = ['Validating number...', 'Contacting courier networks...', 'Calculating risk score...', 'Preparing recommendation...'];
    let idx = 0;
    if (loadingText) loadingText.textContent = steps[0];
    const timer = setInterval(() => {
        idx = (idx + 1) % steps.length;
        if (loadingText) loadingText.textContent = steps[idx];
    }, 900);
    return { stop: () => clearInterval(timer) };
}

function renderOrderFraudDecision(detailHost, orderId, model) {
    const card = detailHost?.querySelector(`[data-fraud-card][data-id="${escapeCssAttrSelector(orderId)}"]`);
    if (!card) return;
    const result = card.querySelector('[data-fraud-result]');
    const scoreEl = card.querySelector('[data-fraud-score]');
    const verdictEl = card.querySelector('[data-fraud-verdict]');
    const actionEl = card.querySelector('[data-fraud-action]');
    const badgeEl = card.querySelector('[data-fraud-badge]');
    const totalEl = card.querySelector('[data-fraud-total]');
    const deliveredEl = card.querySelector('[data-fraud-delivered]');
    const returnEl = card.querySelector('[data-fraud-return]');
    const courierBody = card.querySelector('[data-fraud-courier-body]');
    if (result) result.classList.remove('hidden');
    if (scoreEl) scoreEl.textContent = String(model.riskScore);
    if (verdictEl) verdictEl.textContent = model.verdict;
    if (actionEl) actionEl.textContent = model.action;
    if (totalEl) totalEl.textContent = String(model.total || 0);
    if (deliveredEl) deliveredEl.textContent = String(model.success || 0);
    if (returnEl) returnEl.textContent = String(model.ret || 0);
    if (courierBody) {
        const rows = Array.isArray(model.rows) ? model.rows : [];
        if (!rows.length) {
            courierBody.innerHTML = '<tr><td class="px-2 py-1.5 text-slate-500" colspan="4">No courier-wise data from API.</td></tr>';
        } else {
            courierBody.innerHTML = rows.map((r) => (
                `<tr>
                    <td class="px-2 py-1.5 text-slate-700">${String(r.name || 'Unknown')}</td>
                    <td class="px-2 py-1.5 text-right tabular-nums">${Number(r.total || 0)}</td>
                    <td class="px-2 py-1.5 text-right tabular-nums text-emerald-700">${Number(r.success || 0)}</td>
                    <td class="px-2 py-1.5 text-right tabular-nums text-red-600">${Number(r.ret || 0)}</td>
                </tr>`
            )).join('');
        }
    }
    if (!badgeEl || !result) return;
    if (model.riskScore >= 70) {
        result.className = 'rounded-lg border px-3 py-2 text-xs border-red-200 bg-red-50';
        badgeEl.className = 'inline-flex px-2 py-0.5 rounded-full border text-[11px] font-semibold border-red-200 text-red-700 bg-red-50';
        badgeEl.textContent = 'Block / Hold';
    } else if (model.riskScore >= 35) {
        result.className = 'rounded-lg border px-3 py-2 text-xs border-amber-200 bg-amber-50';
        badgeEl.className = 'inline-flex px-2 py-0.5 rounded-full border text-[11px] font-semibold border-amber-200 text-amber-700 bg-amber-50';
        badgeEl.textContent = 'Review';
    } else {
        result.className = 'rounded-lg border px-3 py-2 text-xs border-emerald-200 bg-emerald-50';
        badgeEl.className = 'inline-flex px-2 py-0.5 rounded-full border text-[11px] font-semibold border-emerald-200 text-emerald-700 bg-emerald-50';
        badgeEl.textContent = 'Ship';
    }
}

async function runOrderFraudCheck(orderId, detailHost) {
    const order = completedOrdersData?.[orderId];
    if (!order) { UI.showToast('Order not found.', false); return; }
    const phone = onlyDigits(order.customerInfo?.phone || '');
    if (phone.length !== 11) { UI.showToast('Customer phone must be 11 digits.', false); return; }
    if (FRAUD_CHECK_MAINTENANCE_MODE) {
        showFraudCheckMaintenanceModalDashboard();
        return;
    }
    const loadingCtl = setOrderFraudLoading(detailHost, orderId, true);
    try {
        const res = await fetch(fraudProxyUrl(), {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ phone }),
            credentials: 'same-origin'
        });
        const text = await res.text();
        let data = null;
        try { data = text ? JSON.parse(text) : null; } catch (_) { data = null; }
        if (!res.ok) {
            const msg = (data && typeof data === 'object' && data.message) ? String(data.message) : `Fraud check failed (${res.status}).`;
            UI.showToast(msg, false);
            return;
        }
        if (!data || typeof data !== 'object' || data.status !== 'success') {
            UI.showToast((data && data.message) ? String(data.message) : 'Invalid fraud-check response.', false);
            return;
        }
        const rows = extractCourierRowsFraud(data).map(normalizeFraudRow);
        const model = buildOrderFraudRiskModel(data, rows);
        model.rows = rows;
        renderOrderFraudDecision(detailHost, orderId, model);
        UI.showToast('Fraud check completed.', true);
    } catch (err) {
        console.error('order detail fraud check', err);
        UI.showToast('Network error while checking fraud.', false);
    } finally {
        loadingCtl.stop();
        setOrderFraudLoading(detailHost, orderId, false);
    }
}

// =========================================================
// UPDATED ORDER STATUS HANDLER WITH STOCK DEDUCTION
// =========================================================
async function updateOrderStatus(orderId, newStatus, triggerBtn = null) {
    let btn = null;
    if (triggerBtn instanceof Element && triggerBtn.getAttribute('data-action') === 'updateOrderStatus') {
        btn = triggerBtn;
    } else if (orderId != null && String(orderId).length) {
        try {
            btn = document.querySelector(`[data-action="updateOrderStatus"][data-id="${escapeCssAttrSelector(orderId)}"]`);
        } catch (_) {
            btn = null;
        }
    }
    if (btn) {
        btn.disabled = true;
        btn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i>';
    }
    
    try {
        const order = completedOrdersData[orderId];
        if (!order) throw new Error("Order data not found locally.");

        const updates = {};
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/status`] = newStatus;

        // --- STOCK UPDATE LOGIC ---
        // Only deduct stock if status is 'Confirmed' AND stock hasn't been updated yet
        if (newStatus === 'Confirmed' && !order.stock_updated) {
            // 1. Mark as updated to prevent double deduction
            updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/stock_updated`] = true;

            const prodSnap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/products`));
            const freshProducts = prodSnap.val() || {};
            const [purSnap, ledSnap] = await Promise.all([
                get(ref(db, `clients/${CURRENT_CLIENT_ID}/purchases`)),
                get(ref(db, `clients/${CURRENT_CLIENT_ID}/inventoryLedger`))
            ]);
            const { avgMap } = buildSkuAverageUnitCostMap(purSnap.val() || {}, ledSnap.val() || {});
            const ledgerEvents = [];

            // 2. Iterate items and calculate new stock (fresh snapshot + ledger)
            if (order.items && Array.isArray(order.items)) {
                for (const item of order.items) {
                    const product = freshProducts[item.id];
                    if (!product) continue;

                    const qtyRaw = item.quantity;
                    const qty = product.isWeighted
                        ? (parseFloat(qtyRaw) || 0)
                        : (parseInt(qtyRaw, 10) || 1);
                    if (!qty || qty <= 0) continue;

                    if (item.variantId && product.variants && product.variants[item.variantId]) {
                        const v = product.variants[item.variantId];
                        const curS = v.stock;
                        if (curS === null || curS === undefined || curS === '') continue;
                        const currentVarStock = product.isWeighted ? parseFloat(curS) : parseInt(curS, 10);
                        if (Number.isNaN(currentVarStock)) continue;
                        const newStock = currentVarStock - qty;
                        if (newStock < 0) {
                            throw new Error('NEGATIVE_STOCK_BLOCKED');
                        }
                        updates[`clients/${CURRENT_CLIENT_ID}/products/${item.id}/variants/${item.variantId}/stock`] = newStock;
                        const { unitCost, costMethod } = resolveUnitCostForSku(avgMap, item.id, item.variantId, product);
                        ledgerEvents.push(buildLedgerEvent('sale', {
                            productId: item.id,
                            variantId: item.variantId,
                            qtyDelta: -qty,
                            uom: product.isWeighted ? 'kg' : 'unit',
                            beforeQty: currentVarStock,
                            afterQty: newStock,
                            unitSell: Number(v.salePrice) || null,
                            unitCost: unitCost > 0 ? unitCost : null,
                            costMethod: unitCost > 0 ? costMethod : null,
                            sourceRef: { kind: 'online_order', orderId: String(orderId) },
                            note: 'Order confirmed (web)',
                            createdByUid: auth.currentUser?.uid || null
                        }));
                    } else {
                        const curS = product.stock;
                        if (curS === null || curS === undefined || curS === '') continue;
                        const currentStock = product.isWeighted ? parseFloat(curS) : parseInt(curS, 10);
                        if (Number.isNaN(currentStock)) continue;
                        const newStock = currentStock - qty;
                        if (newStock < 0) {
                            throw new Error('NEGATIVE_STOCK_BLOCKED');
                        }
                        updates[`clients/${CURRENT_CLIENT_ID}/products/${item.id}/stock`] = newStock;
                        const { unitCost, costMethod } = resolveUnitCostForSku(avgMap, item.id, null, product);
                        ledgerEvents.push(buildLedgerEvent('sale', {
                            productId: item.id,
                            variantId: null,
                            qtyDelta: -qty,
                            uom: product.isWeighted ? 'kg' : 'unit',
                            beforeQty: currentStock,
                            afterQty: newStock,
                            unitSell: Number(product.salePrice) || null,
                            unitCost: unitCost > 0 ? unitCost : null,
                            costMethod: unitCost > 0 ? costMethod : null,
                            sourceRef: { kind: 'online_order', orderId: String(orderId) },
                            note: 'Order confirmed (web)',
                            createdByUid: auth.currentUser?.uid || null
                        }));
                    }
                }
            }
            appendLedgerToRootUpdates(updates, { db, clientId: CURRENT_CLIENT_ID, ref, push, serverTimestamp }, ledgerEvents);
            UI.showToast('Order Confirmed & Stock Updated!', true);
        } else {
            UI.showToast('Status updated!', true);
        }
        // --------------------------

        // Perform the atomic update
        await update(ref(db), updates);
        
        // FB CAPI Logic
        if ((newStatus === 'Confirmed' || newStatus === 'Shipped' || newStatus === 'Processing') && fbCapiModule) {
            if (!order.fb_event_sent) {
                const result = await fbCapiModule.sendVerifiedPurchase(order, orderId);
                if (result.success) {
                    await update(ref(db, `clients/${CURRENT_CLIENT_ID}/orders/${orderId}`), { fb_event_sent: true });
                }
            }
        }
        
        const detailEl = document.getElementById('order-detail-content');
        if (detailEl && currentOrderDetailId === orderId && document.getElementById('dashboard-order-detail')?.classList.contains('active')) {
            detailEl.innerHTML = UI.generateCompletedOrderDetailHTML(orderId, completedOrdersData[orderId], CURRENT_CLIENT_ID, completedOrdersData);
        }

    } catch (error) { 
        console.error("Status Update Error:", error);
        if (error && error.message === 'NEGATIVE_STOCK_BLOCKED') {
            UI.showToast('স্টক যথেষ্ট নেই — নেগেটিভ স্টক ব্লক করা হয়েছে।', false);
        } else {
            UI.showToast('Failed to update status.', false);
        } 
    } 
    finally { 
        if(btn) {
            btn.disabled = false; 
            btn.innerHTML = 'Update'; 
        }
    }
}

async function sendToSteadfast(orderId) {
    const root = document.getElementById('dashboard-order-detail');
    const detailHost = root?.querySelector('#order-detail-content') || null;
    await sendOrderToCourier(orderId, detailHost, 'steadfast');
}

function readOrderCourierKey(detailHost, orderId, fallback = 'steadfast') {
    if (!detailHost) return fallback;
    try {
        const sel = detailHost.querySelector(`[data-courier-select][data-id="${escapeCssAttrSelector(orderId)}"]`);
        const v = String(sel?.value || fallback).trim().toLowerCase();
        if (v === 'steadfast' || v === 'pathao' || v === 'redx') return v;
    } catch (_) {}
    return fallback;
}

function setOrderCourierSending(detailHost, orderId, sending, label = 'Send to Courier') {
    if (!detailHost) return;
    try {
        const btn = detailHost.querySelector(`[data-action="sendToCourier"][data-id="${escapeCssAttrSelector(orderId)}"]`);
        if (!btn) return;
        btn.disabled = sending;
        btn.innerHTML = sending
            ? '<i class="fa-solid fa-spinner fa-spin mr-2"></i>Sending...'
            : `<i class="fa-solid fa-truck-fast mr-2"></i>${label}`;
    } catch (_) {}
}

function normalizeCourierPhone(phone) {
    return onlyDigits(phone || '');
}

function buildSteadfastInvoice(orderId) {
    let s = String(orderId || '').replace(/[^a-zA-Z0-9_-]/g, '_');
    if (!s) s = 'order';
    if (s.length > 191) s = s.slice(0, 191);
    return s;
}

function buildCourierBasePayload(orderId, orderData) {
    const items = Array.isArray(orderData?.items) ? orderData.items : Object.values(orderData?.items || {});
    const itemsLine = items.map(i => `${i.name} (x${i.quantity})`).join(', ');
    const note = `Items: ${itemsLine}`;
    return {
        invoice: buildSteadfastInvoice(orderId),
        recipient_name: String(orderData?.customerInfo?.name || '').trim(),
        recipient_phone: normalizeCourierPhone(orderData?.customerInfo?.phone || ''),
        recipient_address: String(orderData?.customerInfo?.address || '').trim(),
        cod_amount: Number(orderData?.totalBill) || 0,
        note,
        item_description: itemsLine
    };
}

function validateCourierBasePayload(payload) {
    if (!payload.recipient_name) return 'Customer name is missing.';
    if (!payload.recipient_address) return 'Customer address is missing.';
    if (payload.recipient_phone.length !== 11) return 'Customer phone must be 11 digits.';
    if (payload.cod_amount < 0) return 'Invalid COD amount.';
    return '';
}

async function parseJsonSafe(response) {
    const text = await response.text();
    if (!text) return null;
    try { return JSON.parse(text); } catch (_) { return null; }
}

/** Steadfast: POST to same-origin proxy with idToken; PHP loads keys from RTDB (see api/steadfast-create-order-proxy.php). */
async function submitToSteadfast(payload) {
    const user = auth.currentUser;
    if (!user) {
        throw new Error('Sign in required to send orders to courier.');
    }
    if (!CURRENT_CLIENT_ID) {
        throw new Error('Store not loaded. Refresh the dashboard and try again.');
    }
    const idToken = await user.getIdToken();
    const response = await fetch(steadfastCreateOrderProxyUrl(), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            ...payload,
            clientId: CURRENT_CLIENT_ID,
            idToken
        }),
        credentials: 'same-origin'
    });
    const data = await parseJsonSafe(response);
    if (data && data.status === 'error' && data.message) {
        throw new Error(String(data.message));
    }
    const okStatus = data && (Number(data.status) === 200 || data.status === 200);
    if (!response.ok || !okStatus || !data.consignment) {
        throw new Error((data && data.message) ? String(data.message) : `Steadfast error (${response.status}).`);
    }
    return {
        provider: 'steadfast',
        consignmentId: String(data.consignment.consignment_id || ''),
        trackingCode: String(data.consignment.tracking_code || ''),
        status: String(data.consignment.status || 'Created'),
        rawRef: String(data.consignment.consignment_id || '')
    };
}

async function submitToPathao(payload) {
    const cfg = siteSettings?.pathaoConfig || {};
    if (!cfg.createOrderUrl || !cfg.token) throw new Error('Pathao configuration is missing (URL/token).');
    const response = await fetch(String(cfg.createOrderUrl), {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${cfg.token}`
        },
        body: JSON.stringify(payload)
    });
    const data = await parseJsonSafe(response);
    if (!response.ok || !data) throw new Error((data && data.message) ? String(data.message) : 'Pathao API error.');
    const consignmentId = String(data.consignment_id || data.consignmentId || data.data?.consignment_id || '');
    const trackingCode = String(data.tracking_code || data.trackingCode || data.data?.tracking_code || consignmentId || '');
    const status = String(data.status_text || data.status || data.data?.status || 'Created');
    if (!consignmentId && !trackingCode) throw new Error('Pathao response missing tracking info.');
    return { provider: 'pathao', consignmentId, trackingCode, status, rawRef: consignmentId || trackingCode };
}

async function submitToRedx(payload) {
    const cfg = siteSettings?.redxConfig || {};
    if (!cfg.createOrderUrl || !cfg.apiKey) throw new Error('RedX configuration is missing (URL/API key).');
    const response = await fetch(String(cfg.createOrderUrl), {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Api-Key': String(cfg.apiKey),
            ...(cfg.secretKey ? { 'Secret-Key': String(cfg.secretKey) } : {})
        },
        body: JSON.stringify(payload)
    });
    const data = await parseJsonSafe(response);
    if (!response.ok || !data) throw new Error((data && data.message) ? String(data.message) : 'RedX API error.');
    const consignmentId = String(data.consignment_id || data.parcel_id || data.data?.consignment_id || '');
    const trackingCode = String(data.tracking_code || data.trackingId || data.data?.tracking_code || consignmentId || '');
    const status = String(data.status || data.data?.status || 'Created');
    if (!consignmentId && !trackingCode) throw new Error('RedX response missing tracking info.');
    return { provider: 'redx', consignmentId, trackingCode, status, rawRef: consignmentId || trackingCode };
}

async function sendOrderToCourier(orderId, detailHost, forceProvider = '') {
    const orderData = completedOrdersData?.[orderId];
    if (!orderData) { UI.showToast('Order not found.', false); return; }
    const payload = buildCourierBasePayload(orderId, orderData);
    const validationError = validateCourierBasePayload(payload);
    if (validationError) { UI.showToast(validationError, false); return; }

    const provider = forceProvider || readOrderCourierKey(detailHost, orderId, 'steadfast');
    setOrderCourierSending(detailHost, orderId, true);
    try {
        let booking = null;
        if (provider === 'pathao') booking = await submitToPathao(payload);
        else if (provider === 'redx') booking = await submitToRedx(payload);
        else booking = await submitToSteadfast(payload);

        await update(ref(db, `clients/${CURRENT_CLIENT_ID}/orders/${orderId}`), {
            status: 'Shipped',
            courierInfo: {
                provider: booking.provider,
                consignmentId: booking.consignmentId || '',
                trackingCode: booking.trackingCode || '',
                status: booking.status || 'Created',
                rawRef: booking.rawRef || '',
                createdAt: Date.now()
            }
        });
        UI.showToast(`Order sent to ${booking.provider.toUpperCase()}.`, true);
        renderCompletedOrders();
        refreshOrderDetailPanelIfVisible();
    } catch (error) {
        UI.showToast(error?.message || 'Courier entry failed.', false);
    } finally {
        setOrderCourierSending(detailHost, orderId, false);
    }
}

function copyOrderDetails(orderId) {
    const order = completedOrdersData[orderId]; if (!order) return;
    let btn = null;
    try {
        btn = document.querySelector(`[data-action="copyOrderDetails"][data-id="${escapeCssAttrSelector(orderId)}"]`);
    } catch (_) {
        btn = null;
    }
    if (!btn) return;
    const itemsText = "Items:\n" + order.items.map(item => `- ${item.name} (${item.quantity} x ${item.price}৳) = ${item.quantity * item.price}৳`).join('\n');
    const fullText = `Order Details:\nName: ${order.customerInfo.name}\nPhone: ${order.customerInfo.phone}\nAddress: ${order.customerInfo.address}\n---\n${itemsText}\n---\nSubtotal: ${order.subtotal}৳\nShipping: ${order.shipping.cost}৳\nTotal: ${order.totalBill}৳`;
    navigator.clipboard.writeText(fullText).then(() => { btn.innerHTML = '<i class="fa-solid fa-check mr-2"></i>Copied!'; setTimeout(() => { btn.innerHTML = '<i class="fa-solid fa-copy mr-2"></i>Copy for Courier'; }, 2000); });
}

// --- Product Management (Smart Variant System) ---

// Helper: Populate variantColors/variantSizes from saved product (for edit)
function populateVariantTagsFromProduct(p) {
    if (!p.hasVariants || !p.variants) return;
    const names = Object.values(p.variants).map(v => v.name || '').filter(Boolean);
    const attrs = p.variantAttributes || [];
    const hasColor = attrs.includes('color');
    const hasSize = attrs.includes('size');
    if (hasColor && hasSize) {
        const colors = new Set();
        const sizes = new Set();
        names.forEach(n => {
            if (n.includes(' - ')) {
                const parts = n.split(' - ');
                if (parts[0]) colors.add(parts[0].trim());
                if (parts[1]) sizes.add(parts[1].trim());
            }
        });
        variantColors = Array.from(colors);
        variantSizes = Array.from(sizes);
    } else if (hasColor) {
        variantColors = [...names];
        variantSizes = [];
    } else if (hasSize) {
        variantColors = [];
        variantSizes = [...names];
    } else {
        const isComposite = names.every(n => n.includes(' - '));
        if (isComposite) {
            const colors = new Set();
            const sizes = new Set();
            names.forEach(n => {
                const parts = n.split(' - ');
                if (parts[0]) colors.add(parts[0].trim());
                if (parts[1]) sizes.add(parts[1].trim());
            });
            variantColors = Array.from(colors);
            variantSizes = Array.from(sizes);
        } else {
            variantColors = [];
            variantSizes = [];
        }
    }
    renderVariantTags();
}

// Helper: Render Tags
function renderVariantTags() {
    const colorContainer = document.getElementById('variant-colors-container');
    const sizeContainer = document.getElementById('variant-sizes-container');
    
    if(colorContainer) {
        colorContainer.innerHTML = variantColors.map(c => `
            <span class="inline-flex items-center gap-1 bg-indigo-100 text-indigo-800 text-xs font-semibold px-2 py-1 rounded">
                ${c} <button type="button" class="remove-tag hover:text-red-500" data-type="color" data-val="${c}">&times;</button>
            </span>
        `).join('');
    }
    
    if(sizeContainer) {
        sizeContainer.innerHTML = variantSizes.map(s => `
            <span class="inline-flex items-center gap-1 bg-green-100 text-green-800 text-xs font-semibold px-2 py-1 rounded">
                ${s} <button type="button" class="remove-tag hover:text-red-500" data-type="size" data-val="${s}">&times;</button>
            </span>
        `).join('');
    }
}

// Helper: Generate Table Rows
function generateVariantMatrix() {
    const container = document.getElementById('product-variants-list');
    if (!container) return;
    
    container.innerHTML = '';
    const defaultPrice = document.getElementById('bulk-price').value;
    const defaultStock = document.getElementById('bulk-stock').value;

    let combinations = [];
    
    if (variantColors.length > 0 && variantSizes.length > 0) {
        variantColors.forEach(c => {
            variantSizes.forEach(s => combinations.push(`${c} - ${s}`));
        });
    } else if (variantColors.length > 0) {
        combinations = [...variantColors];
    } else if (variantSizes.length > 0) {
        combinations = [...variantSizes];
    } else {
        UI.showToast("Please add at least one color or size.", false);
        return;
    }

    combinations.forEach(name => {
        addSmartVariantRow({ name, salePrice: defaultPrice, stock: defaultStock });
    });
}

function normalizeProductBarcode(s) {
    return String(s || '').trim().toLowerCase();
}

/** Returns false if duplicate within list or conflicts with another product (excluding excludeProductId). */
function assertUniqueProductBarcodes(allProductsMap, excludeProductId, barcodeStrings) {
    const norms = barcodeStrings.map((s) => normalizeProductBarcode(s)).filter(Boolean);
    if (norms.length !== new Set(norms).size) {
        UI.showToast('Duplicate barcode on this product (two rows use the same code).', false);
        return false;
    }
    for (const n of norms) {
        for (const [pid, p] of Object.entries(allProductsMap || {})) {
            if (excludeProductId && pid === excludeProductId) continue;
            if (normalizeProductBarcode(p.barcode) === n) {
                UI.showToast(`Barcode already used on product: ${p.name || pid}`, false);
                return false;
            }
            if (p.variants) {
                for (const v of Object.values(p.variants)) {
                    if (normalizeProductBarcode(v.barcode) === n) {
                        UI.showToast(`Barcode already used on a variant of: ${p.name || pid}`, false);
                        return false;
                    }
                }
            }
        }
    }
    return true;
}

function collectUsedBarcodesNormExcluding(allProductsMap, excludeProductId) {
    const used = new Set();
    for (const [pid, p] of Object.entries(allProductsMap || {})) {
        if (excludeProductId && pid === excludeProductId) continue;
        if (!p) continue;
        const nb = normalizeProductBarcode(p.barcode);
        if (nb) used.add(nb);
        if (p.variants) {
            for (const v of Object.values(p.variants)) {
                const nv = normalizeProductBarcode(v?.barcode);
                if (nv) used.add(nv);
            }
        }
    }
    return used;
}

function generateNextProductBarcode(usedNormSet) {
    for (let attempt = 0; attempt < 80; attempt++) {
        const raw = 'INV' + Date.now().toString(36).toUpperCase() + Math.random().toString(36).substring(2, 6).toUpperCase() + String(attempt);
        const n = normalizeProductBarcode(raw);
        if (n && !usedNormSet.has(n)) {
            usedNormSet.add(n);
            return raw;
        }
    }
    const raw = 'INV' + Date.now() + Math.floor(Math.random() * 100000);
    const n = normalizeProductBarcode(raw);
    usedNormSet.add(n);
    return raw;
}

// Helper: Add Single Smart Row
function addSmartVariantRow(data = {}) {
    const container = document.getElementById('product-variants-list');
    const div = document.createElement('div');
    div.className = 'grid grid-cols-12 gap-2 items-center p-2 border-b bg-white hover:bg-gray-50 variant-row-smart';
    const uniqueId = 'var-img-' + Date.now() + Math.random().toString(36).substring(2);
    const variantKey = data.variantKey || '';
    const escBarcode = String(data.barcode || '').replace(/"/g, '&quot;');

    const imgUrl = data.image || '';
    const imgPreview = imgUrl ? `<img src="${imgUrl}" class="w-full h-full object-cover">` : '';
    const hidePreview = imgUrl ? '' : 'hidden';

    div.innerHTML = `
        <input type="hidden" class="variant-key" value="${variantKey.replace(/"/g, '&quot;')}">
        <div class="col-span-2 flex justify-center">
             <div class="relative w-10 h-10 border rounded bg-gray-50 flex items-center justify-center overflow-hidden group">
                <div id="preview-${uniqueId}" class="w-full h-full flex items-center justify-center">${imgPreview}</div>
                <input type="hidden" class="variant-img-input" id="${uniqueId}" value="${imgUrl}">
                <button type="button" onclick="triggerUpload(this)" data-target-input="#${uniqueId}" data-preview-container="#preview-${uniqueId}" data-upload-profile="product" class="absolute inset-0 bg-black/50 text-white opacity-0 group-hover:opacity-100 flex items-center justify-center transition">
                    <i class="fa-solid fa-upload text-xs"></i>
                </button>
             </div>
        </div>
        <div class="col-span-3">
            <input type="text" class="admin-form-input variant-name text-xs bg-transparent border-none p-0 font-semibold text-black" value="${data.name || ''}" readonly>
        </div>
        <div class="col-span-2">
            <input type="text" class="admin-form-input variant-barcode text-xs text-center" value="${escBarcode}" placeholder="Barcode" autocomplete="off">
        </div>
        <div class="col-span-2">
            <input type="number" class="admin-form-input variant-price text-xs text-center" value="${data.salePrice || ''}" placeholder="Price">
        </div>
        <div class="col-span-2">
            <input type="number" class="admin-form-input variant-stock text-xs text-center" value="${data.stock || ''}" placeholder="Stock">
        </div>
        <div class="col-span-1 text-center">
            <button type="button" class="remove-variant-btn text-red-400 hover:text-red-600 p-1"><i class="fa-solid fa-trash"></i></button>
        </div>
    `;
    container.appendChild(div);
    div.querySelector('.remove-variant-btn').addEventListener('click', () => div.remove());
}

async function handleProductSubmit(e) {
    e.preventDefault(); 
    const saveBtn = document.getElementById('save-product-btn'); 
    UI.setLoadingState(true, { button: saveBtn });
    
    try {
        const productId = document.getElementById('product-id').value;
        const hasVariants = document.getElementById('product-has-variants').checked;
        
        const categoriesContainer = document.getElementById('product-categories-container');
        const categories = categoriesContainer
            ? Array.from(document.querySelectorAll('#product-categories-container input[name="product-categories"]:checked')).map(c => c.value)
            : (document.getElementById('product-category')?.value ? [document.getElementById('product-category').value] : []);
        const subcategorySelect = document.getElementById('product-subcategory');
        const selectedSubOption = subcategorySelect ? subcategorySelect.options[subcategorySelect.selectedIndex] : null;
        const selectedSubName = selectedSubOption?.dataset?.subName || '';
        const selectedSubParent = selectedSubOption?.dataset?.parentName || '';
        const selectedSubKey = selectedSubOption?.value || '';
        const clickTarget = document.getElementById('product-click-target')?.value || 'product_detail';
        const landingPageSlug = clickTarget === 'landing_page' ? (document.getElementById('product-landing-page-slug')?.value || '') : '';
        const landingPageData = (clickTarget === 'landing_page' && landingPageSlug && landingPagesCache[landingPageSlug])
            ? landingPagesCache[landingPageSlug] : null;
        let data = {
            name: document.getElementById('product-name').value.trim(),
            categories: categories.length ? categories : [],
            category: categories[0] || '',
            subcategory: selectedSubName,
            subcategoryParent: selectedSubParent,
            subcategoryKey: selectedSubKey,
            imageUrl: document.getElementById('product-image-url').value.trim(),
            description: document.getElementById('product-description').value,
            hasVariants: hasVariants,
            galleryImageUrls: Array.from(document.querySelectorAll('.gallery-image-input')).map(input => input.value.trim()).filter(url => url),
            sizeChartUrl: (document.getElementById('product-size-chart')?.value || '').trim(),
            videoUrl: (document.getElementById('product-video-url')?.value || '').trim(),
            clickTarget: clickTarget,
            landingPageSlug: landingPageSlug,
            landingPageCustomDomain: landingPageData?.custom_domain || ''
        };

        if (!data.name || !data.imageUrl || !data.categories.length) {
            UI.showToast("Required fields missing.", false);
            if (!data.imageUrl) {
                const dm = document.getElementById('dashboard-details-media');
                if (dm) {
                    dm.open = true;
                    dm.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
                }
            }
            UI.setLoadingState(false, { button: saveBtn });
            return;
        }
        if (data.clickTarget === 'landing_page' && !data.landingPageSlug) {
            UI.showToast("Please select a landing page.", false);
            const dc = document.getElementById('dashboard-details-click');
            if (dc) {
                dc.open = true;
                dc.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
            }
            UI.setLoadingState(false, { button: saveBtn });
            return;
        }
        if (data.subcategory && !data.subcategoryParent) {
            UI.showToast("Invalid subcategory mapping. Please reselect sub category.", false);
            UI.setLoadingState(false, { button: saveBtn });
            return;
        }
        if (data.subcategoryParent && !data.categories.includes(data.subcategoryParent)) {
            UI.showToast("Selected sub category does not match selected main categories.", false);
            UI.setLoadingState(false, { button: saveBtn });
            return;
        }
        const productKey = productId || push(ref(db, `clients/${CURRENT_CLIENT_ID}/products`)).key;
        const usedBcAuto = collectUsedBarcodesNormExcluding(allProducts, productId || null);
        const productBarcodeEl = document.getElementById('product-barcode');
        const productBarcodeRaw = productBarcodeEl ? productBarcodeEl.value.trim() : '';

        if (hasVariants) {
            const variantRows = document.querySelectorAll('.variant-row-smart'); 
            if (variantRows.length === 0) { 
                UI.showToast("Add at least one variant combination.", false); 
                UI.setLoadingState(false, { button: saveBtn });
                return; 
            }
            
            data.variants = {}; 
            let allVariantsValid = true;
            const barcodeStrings = [];
            
            variantRows.forEach(row => { 
                const name = row.querySelector('.variant-name').value.trim(); 
                const salePrice = parseFloat(row.querySelector('.variant-price').value); 
                const stock = row.querySelector('.variant-stock').value;
                const image = row.querySelector('.variant-img-input').value;
                let vb = row.querySelector('.variant-barcode')?.value?.trim() || '';
                if (!vb) {
                    vb = generateNextProductBarcode(usedBcAuto);
                    const vinp = row.querySelector('.variant-barcode');
                    if (vinp) vinp.value = vb;
                }
                barcodeStrings.push(vb);

                if (!name || isNaN(salePrice) || salePrice <= 0) { 
                    allVariantsValid = false; 
                    return; 
                } 
                
                const existingVk = row.querySelector('.variant-key')?.value?.trim();
                const variantKey = existingVk || push(ref(db)).key; 
                data.variants[variantKey] = { 
                    name: name, 
                    salePrice: salePrice, 
                    regularPrice: salePrice, // Fallback
                    stock: stock === '' ? null : parseInt(stock, 10),
                    image: image,
                    barcode: vb
                }; 
            });

            if (!allVariantsValid) { 
                UI.showToast("Invalid variant data (Price required).", false); 
                UI.setLoadingState(false, { button: saveBtn });
                return; 
            } 
            if (!assertUniqueProductBarcodes(allProducts, productId || null, barcodeStrings)) {
                UI.setLoadingState(false, { button: saveBtn });
                return;
            }
            
            data.variantAttributes = [];
            if (variantColors.length) data.variantAttributes.push('color');
            if (variantSizes.length) data.variantAttributes.push('size');
            // Auto Set Base Price from Lowest Variant
            data.salePrice = Math.min(...Object.values(data.variants).map(v => v.salePrice));
            data.stock = null; 
            if (productBarcodeRaw) {
                UI.showToast('Clear product-level barcode when using variants (use per-variant barcodes).', false);
                UI.setLoadingState(false, { button: saveBtn });
                return;
            }
            data.barcode = null;

        } else {
            const salePrice = parseFloat(document.getElementById('product-sale-price').value); 
            if (isNaN(salePrice) || salePrice <= 0) { 
                UI.showToast("Invalid price.", false); 
                UI.setLoadingState(false, { button: saveBtn });
                return; 
            }
            data.regularPrice = parseFloat(document.getElementById('product-regular-price').value) || 0; 
            data.salePrice = salePrice; 
            data.stock = document.getElementById('product-stock').value === '' ? null : parseInt(document.getElementById('product-stock').value, 10);
            let pb = productBarcodeRaw;
            if (!pb) {
                pb = generateNextProductBarcode(usedBcAuto);
                if (productBarcodeEl) productBarcodeEl.value = pb;
            }
            if (!assertUniqueProductBarcodes(allProducts, productId || null, [pb])) {
                UI.setLoadingState(false, { button: saveBtn });
                return;
            }
            data.barcode = pb;
        }

        if (data.hasVariants && (!data.variants || Object.keys(data.variants).length === 0)) {
            UI.showToast('Variant products must include at least one valid variant.', false);
            UI.setLoadingState(false, { button: saveBtn });
            return;
        }

        const existingCreatedAt = productId ? (allProducts[productId]?.createdAt || null) : null;
        data.createdAt = existingCreatedAt || Date.now();
        const path = `clients/${CURRENT_CLIENT_ID}/products/${productKey}`;
        const isNewProduct = !productId;
        await set(ref(db, path), data);
        UI.showToast(`Product ${productId ? 'updated' : 'added'} successfully!`);
        if (isNewProduct) {
            maybeAutoPostProductToFacebookPage(productKey, data).catch((err) => {
                console.error('Facebook Page auto-post:', err);
                UI.showToast(`Product saved. Facebook post failed: ${err?.message || 'Unknown error'}`, false);
            });
        }
        resetProductForm();

    } catch (error) { 
        console.error("Error saving product:", error); 
        UI.showToast("Error saving product.", false); 
    } finally { 
        UI.setLoadingState(false, { button: saveBtn }); 
    }
}

function resetProductForm() {
    const form = document.getElementById('product-form'); if(!form) return;
    form.reset(); 
    document.getElementById('product-id').value = ''; 
    document.getElementById('product-form-title').textContent = 'Add a new product'; 
    document.querySelector('#save-product-btn .button-text').textContent = 'Save Product';
    
    // Clear Variants, Tags & Media
    document.getElementById('product-variants-list').innerHTML = ''; 
    document.getElementById('gallery-images-container').innerHTML = '';
    document.getElementById('product-size-chart').value = '';
    document.getElementById('product-size-chart-preview').innerHTML = '';
    document.getElementById('product-video-url').value = '';
    const pbcReset = document.getElementById('product-barcode');
    if (pbcReset) pbcReset.value = '';

    // Reset Click Behavior
    const clickTargetSelR = document.getElementById('product-click-target');
    if (clickTargetSelR) clickTargetSelR.value = 'product_detail';
    document.getElementById('landing-page-selector-block')?.classList.add('hidden');
    const landingSlugSelR = document.getElementById('product-landing-page-slug');
    if (landingSlugSelR) landingSlugSelR.innerHTML = '<option value="">-- Select a landing page --</option>';

    variantColors = [];
    variantSizes = [];
    renderVariantTags();

    const hasVariantsCheckbox = document.getElementById('product-has-variants'); 
    hasVariantsCheckbox.checked = false; 
    hasVariantsCheckbox.dispatchEvent(new Event('change'));
    
    document.getElementById('product-image-preview').innerHTML = '';
    UI.populateProductSubcategoryDropdown([]);
    document.getElementById('product-cancel-btn').classList.add('hidden'); 
    window.scrollTo({ top: 0, behavior: 'smooth' });
}

async function handleCategorySubmit(e) {
    e.preventDefault(); const saveBtn = e.target.querySelector('button[type="submit"]'); UI.setLoadingState(true, { button: saveBtn });
    try {
        const categoryId = document.getElementById('category-id').value;
        const listingBannerUrlEl = document.getElementById('category-listing-banner-url');
        const listingBannerEnEl = document.getElementById('category-listing-banner-enabled');
        const data = {
            name: document.getElementById('category-name').value.trim(),
            imageUrl: document.getElementById('category-image-url').value.trim(),
            description: (document.getElementById('category-description')?.value || '').trim(),
            subcategories: UI.getSubcategoriesFromDOM(),
            listingBannerUrl: listingBannerUrlEl ? listingBannerUrlEl.value.trim() : '',
            listingBannerEnabled: !(listingBannerEnEl && listingBannerEnEl.checked === false)
        };
        if (!data.name || !data.imageUrl) { UI.showToast("Required fields missing.", false); UI.setLoadingState(false, { button: saveBtn }); return; }
        const categoriesRef = ref(db, `clients/${CURRENT_CLIENT_ID}/categories`);
        const categoryOrderRef = ref(db, `clients/${CURRENT_CLIENT_ID}/categoryOrder`);
        const newId = categoryId || push(categoriesRef).key;
        const path = `clients/${CURRENT_CLIENT_ID}/categories/${newId}`;
        await set(ref(db, path), data);
        if (!categoryId) {
            const orderSnap = await get(categoryOrderRef);
            const order = normalizeCategoryOrder(orderSnap.val());
            await set(categoryOrderRef, [newId, ...order]);
        }
        UI.showToast(`Category ${categoryId ? 'updated' : 'added'} successfully!`); UI.resetCategoryForm();
    } catch (error) { console.error("Error saving category:", error); UI.showToast("Error saving category.", false); } finally { UI.setLoadingState(false, { button: saveBtn }); }
}

// --- Hosting & Settings ---

function renderHostingPanel() {
    const balanceEl = document.getElementById('hosting-wallet-balance');
    if (balanceEl) balanceEl.textContent = currentBalance.toFixed(2);
    const activeView = document.getElementById('active-hosting-view');
    const activateView = document.getElementById('activate-hosting-view');
    
    activeView.classList.toggle('hidden', !isHostingActive);
    activateView.classList.toggle('hidden', isHostingActive);
    
    if (isHostingActive) {
        document.getElementById('active-plan-name').textContent = HOSTING_PACKAGES[clientHostingInfo.planId]?.name || 'Unknown Plan';
        document.getElementById('hosting-expiry-date').textContent = new Date(clientHostingInfo.expiresAt).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' });
    }
}

async function handleActivateHosting(planId, button) {
    const plan = HOSTING_PACKAGES[planId];
    if (!plan) { UI.showToast("Invalid plan selected.", false); return; }
    if (currentBalance < plan.price) { 
        document.getElementById('required-balance').textContent = `${plan.price.toFixed(2)} ৳`;
        document.getElementById('current-user-balance').textContent = `${currentBalance.toFixed(2)} ৳`;
        UI.toggleModal('insufficient-balance-modal', true);
        return; 
    }

    button.disabled = true; button.innerHTML = '<div class="spinner spinner-white mx-auto"></div>';
    try {
        const newTransactionRef = push(ref(db, `clients/${CURRENT_CLIENT_ID}/wallet/transactions`));
        const activatedAt = Date.now();
        const expiresAt = activatedAt + (plan.durationDays * 24 * 60 * 60 * 1000);
        const updates = {};
        updates[`clients/${CURRENT_CLIENT_ID}/hosting`] = { status: 'active', planId, activatedAt, expiresAt, price: plan.price };
        updates[`clients/${CURRENT_CLIENT_ID}/wallet/transactions/${newTransactionRef.key}`] = { amount: -plan.price, status: 'approved', timestamp: serverTimestamp(), type: 'hosting_activation', details: `Activated ${plan.name}` };
        updates[`clients/${CURRENT_CLIENT_ID}/wallet/currentBalance`] = increment(-plan.price);
        await update(ref(db), updates);
        UI.showToast(`${plan.name} activated successfully!`);
        clientHostingInfo = { status: 'active', planId, activatedAt, expiresAt, price: plan.price };
        isHostingActive = true;
        handleUserNudgesAndLocks();
        renderHostingPanel();
    } catch (error) { console.error("Hosting activation failed:", error); UI.showToast("Activation failed.", false); } 
    finally { button.disabled = false; button.textContent = 'Activate Now'; }
}

/** @returns {Promise<boolean>} true if RTDB update succeeded */
async function saveSettingsSection(dataToSave, sectionName) {
    try {
        await update(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`), dataToSave);
        siteSettings = { ...(siteSettings || {}), ...dataToSave };
        if (
            ['imageUploadProvider', 'imgbbApiKey', 'daimanApiKey'].some((k) =>
                Object.prototype.hasOwnProperty.call(dataToSave, k)
            )
        ) {
            const merged = { ...(siteSettings || {}), ...dataToSave };
            setUploadConfig(merged.imageUploadProvider, merged.imgbbApiKey, merged.daimanApiKey);
        }
        refreshIntegrationStatusSummary();
        UI.showToast(`${sectionName} saved successfully!`);
        return true;
    } catch (err) {
        const code = err && err.code ? String(err.code) : '';
        const msg = err && (err.message || err.code) ? String(err.message || err.code) : '';
        const detail = [code && code !== msg ? code : '', msg].filter(Boolean).join(' — ') || '';
        UI.showToast(detail ? `Error saving ${sectionName}: ${detail}` : `Error saving ${sectionName}.`, false);
        console.error(`saveSettingsSection (${sectionName}):`, err);
        return false;
    }
}

function setIntegrationChip(id, label, configured, extraText = '') {
    const el = document.getElementById(id);
    if (!el) return;
    const suffix = extraText ? ` (${extraText})` : '';
    el.textContent = `${label}: ${configured ? 'Configured' : 'Not set'}${suffix}`;
    el.classList.remove('text-gray-600', 'text-red-700', 'bg-white', 'bg-red-50', 'border-red-200', 'bg-emerald-50', 'border-emerald-200', 'text-emerald-700');
    if (configured) {
        el.classList.add('bg-emerald-50', 'border-emerald-200', 'text-emerald-700');
    } else {
        el.classList.add('bg-red-50', 'border-red-200', 'text-red-700');
    }
}

function refreshIntegrationStatusSummary(pushCount = null) {
    const s = siteSettings || {};
    const tiktok = s.tiktokConfig || {};
    const fbApi = s.facebookConfig || {};
    const pushCfg = s.pushConfig || {};
    const courier = s.steadfastConfig || {};
    const fbConfigured = Boolean((s.pixelId && String(s.pixelId).trim()) || (fbApi.accessToken && String(fbApi.accessToken).trim()));
    const tiktokOk = Boolean(tiktok.enabled && tiktok.pixelId && tiktok.accessToken);
    const pushOk = Boolean(pushCfg.enabled && pushCfg.vapidPublicKey);
    const pushExtra = pushCount == null ? '' : `${pushCount} subs`;
    setIntegrationChip('tiktok-status-chip', 'TikTok', tiktokOk);
    setIntegrationChip('integration-status-facebook', 'Facebook', fbConfigured);
    setIntegrationChip('push-status-chip', 'Push', pushOk, pushExtra);
    setIntegrationChip('integration-status-courier', 'Courier', Boolean(courier.apiKey && courier.secretKey));
}

function setOpenAiStatus(msg, isError = false) {
    const el = document.getElementById('openai-status');
    if (!el) return;
    el.textContent = String(msg || '');
    el.classList.remove('text-black', 'text-emerald-700', 'text-red-600');
    if (!msg) el.classList.add('text-black');
    else el.classList.add(isError ? 'text-red-600' : 'text-emerald-700');
}

function bindOpenAiSettingsHandlers() {
    if (openAiSettingsHandlersBound) return;
    openAiSettingsHandlersBound = true;
    document.getElementById('openai-api-key-toggle-btn')?.addEventListener('click', (e) => {
        const input = document.getElementById('openai-api-key-dash');
        if (!input) return;
        const nextType = input.type === 'password' ? 'text' : 'password';
        input.type = nextType;
        e.currentTarget.textContent = nextType === 'password' ? 'Show' : 'Hide';
    });
    document.getElementById('openai-save-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        const apiKey = document.getElementById('openai-api-key-dash')?.value?.trim() || '';
        const model = document.getElementById('openai-model-dash')?.value?.trim() || 'gpt-4o-mini';
        if (!apiKey) {
            setOpenAiStatus('OpenAI API key is required.', true);
            return;
        }
        UI.setLoadingState(true, { button: btn });
        try {
            await saveSettingsSection({ openaiApiKey: apiKey, openaiModel: model }, 'OpenAI Settings');
            setOpenAiStatus('OpenAI settings saved.');
        } catch (_) {
            setOpenAiStatus('Failed to save OpenAI settings.', true);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });
    document.getElementById('openai-test-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });
        setOpenAiStatus('Testing OpenAI connection...');
        try {
            const url = new URL('api/openai-test.php', window.location.href).href;
            const response = await fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                credentials: 'same-origin',
                body: JSON.stringify({ clientId: CURRENT_CLIENT_ID })
            });
            const data = await response.json().catch(() => null);
            if (!response.ok || !data || data.status !== 'success') {
                throw new Error((data && data.message) ? String(data.message) : `OpenAI test failed (${response.status})`);
            }
            setOpenAiStatus(`Connection OK (${String(data.model || 'model')}).`);
        } catch (err) {
            setOpenAiStatus(err.message || 'Could not test OpenAI connection.', true);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });
}

async function refreshPushSubscriberCount() {
    const el = document.getElementById('push-subscriber-count');
    if (!el || !CURRENT_CLIENT_ID) return;
    try {
        const snap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/pushSubscribers`));
        const map = snap.val() || {};
        const total = Object.values(map).filter((s) => s && s.active !== false).length;
        el.textContent = `Active: ${total}`;
        refreshIntegrationStatusSummary(total);
    } catch (_) {
        el.textContent = 'Active: --';
        refreshIntegrationStatusSummary(null);
    }
}

async function sendTikTokTestEvent() {
    const user = auth.currentUser;
    if (!user) { UI.showToast('Please sign in first.', false); return; }
    const pixelId = document.getElementById('tiktok-pixel-id')?.value?.trim() || '';
    const accessToken = document.getElementById('tiktok-access-token')?.value?.trim() || '';
    if (!pixelId || !accessToken) {
        UI.showToast('Save Pixel ID and Access Token first.', false);
        return;
    }
    const idToken = await user.getIdToken();
    const eventId = `dashboard_test_${Date.now()}`;
    const response = await fetch(tiktokProxyUrl(), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'same-origin',
        body: JSON.stringify({
            clientId: CURRENT_CLIENT_ID,
            idToken,
            event_name: 'CompletePayment',
            event_id: eventId,
            event_time: Math.floor(Date.now() / 1000),
            event_source_url: window.location.origin,
            test_event_code: document.getElementById('tiktok-test-event-code')?.value?.trim() || '',
            custom_data: { value: 1, currency: 'BDT' },
            user_data: {}
        })
    });
    const data = await response.json().catch(() => null);
    if (!response.ok || !data || data.status !== 'success') {
        UI.showToast((data && data.message) ? String(data.message) : 'TikTok test failed.', false);
        return;
    }
    UI.showToast('TikTok test event sent.');
}

async function sendPushCampaign() {
    const user = auth.currentUser;
    if (!user) { UI.showToast('Please sign in first.', false); return; }
    const title = document.getElementById('push-title')?.value?.trim() || '';
    const message = document.getElementById('push-message')?.value?.trim() || '';
    const clickUrl = document.getElementById('push-url')?.value?.trim() || '';
    const iconUrl = document.getElementById('push-icon-url')?.value?.trim() || '';
    const audience = document.getElementById('push-audience')?.value || 'all';
    const resultEl = document.getElementById('push-last-result');
    if (!title || !message) { UI.showToast('Title and message are required.', false); return; }
    const idToken = await user.getIdToken();
    const res = await fetch(pushSendApiUrl(), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'same-origin',
        body: JSON.stringify({
            clientId: CURRENT_CLIENT_ID,
            idToken,
            title,
            message,
            clickUrl,
            iconUrl,
            audience
        })
    });
    const data = await res.json().catch(() => null);
    if (!res.ok || !data || data.status !== 'success') {
        UI.showToast((data && data.message) ? String(data.message) : 'Push send failed.', false);
        if (resultEl) resultEl.textContent = `Failed: ${(data && data.message) ? String(data.message) : `HTTP ${res.status}`}`;
        return;
    }
    const sent = Number(data.sent || 0);
    const failed = Number(data.failed || 0);
    UI.showToast(`Push sent. Success ${sent}, failed ${failed}.`, true);
    if (resultEl) resultEl.textContent = `Last send: success ${sent}, failed ${failed}${data.campaignId ? `, campaign ${data.campaignId}` : ''}`;
    refreshPushSubscriberCount().catch(() => {});
}

async function handleSaveBanners(e) {
    const btn = e.target.closest('button');
    UI.setLoadingState(true, { button: btn });
    try {
        const rows = document.querySelectorAll('.main-slide-row');
        const bannerSlides = [];
        const mainSlides = [];
        rows.forEach(row => {
            const urlInput = row.querySelector('.main-slide-input');
            const linkInput = row.querySelector('.main-slide-link');
            const url = urlInput ? urlInput.value.trim() : '';
            const linkUrl = linkInput ? linkInput.value.trim() : '';
            if (url) {
                mainSlides.push(url);
                bannerSlides.push({ imageUrl: url, linkUrl: linkUrl || '' });
            }
        });
        const smallBanners = [document.getElementById('small-banner-1-url').value.trim(), document.getElementById('small-banner-2-url').value.trim(), document.getElementById('small-banner-3-url').value.trim()];
        const smallBannerLinks = [
            (document.getElementById('small-banner-1-link') && document.getElementById('small-banner-1-link').value.trim()) || '',
            (document.getElementById('small-banner-2-link') && document.getElementById('small-banner-2-link').value.trim()) || '',
            (document.getElementById('small-banner-3-link') && document.getElementById('small-banner-3-link').value.trim()) || ''
        ];
        const promoBanner1Url = document.getElementById('promo-banner-1-url').value.trim();
        const promoBanner2Url = document.getElementById('promo-banner-2-url').value.trim();
        const promoBanner1Link = (document.getElementById('promo-banner-1-link') && document.getElementById('promo-banner-1-link').value.trim()) || '';
        const promoBanner2Link = (document.getElementById('promo-banner-2-link') && document.getElementById('promo-banner-2-link').value.trim()) || '';
        const visibility = {
            mainSlider: document.getElementById('visibility-main-slider').checked,
            smallBanners: document.getElementById('visibility-small-banners').checked,
            promoBanner1: document.getElementById('visibility-promo-1').checked,
            promoBanner2: document.getElementById('visibility-promo-2').checked
        };
        const currentLayout = siteSettings.layout || {};
        const bannerHeightDesktop = document.getElementById('banner-height-desktop');
        const bannerHeightMobile = document.getElementById('banner-height-mobile');
        const bannerSpaceDesktop = document.getElementById('banner-space-desktop');
        const bannerSpaceMobile = document.getElementById('banner-space-mobile');
        const bannerDesktopContentSideGap = document.getElementById('banner-desktop-content-side-gap');
        const bannerDesktopShellMaxWidth = document.getElementById('banner-desktop-shell-max-width');
        const bannerMainHeroPresetEl = document.getElementById('banner-main-hero-preset');
        const mainHeroPresetRaw = bannerMainHeroPresetEl && bannerMainHeroPresetEl.value;
        const mainHeroPreset = ['fabrilife', 'standard', 'custom'].includes(mainHeroPresetRaw) ? mainHeroPresetRaw : 'standard';
        const bannerDesktopMainSliderLayoutEl = document.getElementById('banner-desktop-main-slider-layout');
        const bannerMobileMainSliderLayoutEl = document.getElementById('banner-mobile-main-slider-layout');
        let desktopMainSliderLayout;
        let mobileMainSliderLayout;
        if (mainHeroPreset === 'fabrilife') {
            desktopMainSliderLayout = 'fullBleed';
            mobileMainSliderLayout = 'fullBleed';
        } else if (mainHeroPreset === 'standard') {
            desktopMainSliderLayout = 'inset';
            mobileMainSliderLayout = 'inset';
        } else {
            const desktopMainSliderLayoutRaw = bannerDesktopMainSliderLayoutEl && bannerDesktopMainSliderLayoutEl.value;
            desktopMainSliderLayout = ['inset', 'fullBleed'].includes(desktopMainSliderLayoutRaw) ? desktopMainSliderLayoutRaw : 'inset';
            const mobileMainSliderLayoutRaw = bannerMobileMainSliderLayoutEl && bannerMobileMainSliderLayoutEl.value;
            mobileMainSliderLayout = ['inset', 'fullBleed'].includes(mobileMainSliderLayoutRaw) ? mobileMainSliderLayoutRaw : 'inset';
        }
        const bannerTopDesktop = document.getElementById('banner-top-space-desktop');
        const bannerBottomDesktop = document.getElementById('banner-bottom-space-desktop');
        const smallBannerCountEl = document.getElementById('small-banner-count');
        const smallBannerHeightDesktop = document.getElementById('small-banner-height-desktop');
        const smallBannerHeightMobile = document.getElementById('small-banner-height-mobile');
        const promoBannerHeightDesktop = document.getElementById('promo-banner-height-desktop');
        const promoBannerHeightMobile = document.getElementById('promo-banner-height-mobile');
        const shapeRadio = document.querySelector('input[name="category-shape"]:checked');
        const catSizeDesktop = document.getElementById('category-size-desktop');
        const catSizeMobile = document.getElementById('category-size-mobile');
        const catSpaceBetween = document.getElementById('category-space-between');
        const catRowsDesktop = document.getElementById('category-rows-desktop');
        const catRowsMobile = document.getElementById('category-rows-mobile');
        const catProductSpacingEnabledEl = document.getElementById('cat-product-spacing-enabled');
        const catProductSidePaddingEl = document.getElementById('cat-product-side-padding');
        const catProductCardGapEl = document.getElementById('cat-product-card-gap');
        const catListingHMobEl = document.getElementById('category-listing-banner-max-height-mobile');
        const catListingHDeskEl = document.getElementById('category-listing-banner-max-height-desktop');
        const prevCat = currentLayout.categoryConfig || {};
        const listingMobRaw = catListingHMobEl ? parseInt(catListingHMobEl.value, 10) : NaN;
        const listingDeskRaw = catListingHDeskEl ? parseInt(catListingHDeskEl.value, 10) : NaN;
        const categoryConfig = {
            ...prevCat,
            layoutType: prevCat.layoutType || 'swiper',
            cardStyle: prevCat.cardStyle || 'default',
            shape: (shapeRadio && shapeRadio.value === 'square') ? 'square' : 'round',
            sizeDesktop: catSizeDesktop ? Math.min(250, Math.max(100, parseInt(catSizeDesktop.value) || 170)) : 170,
            sizeMobile: catSizeMobile ? Math.min(140, Math.max(56, parseInt(catSizeMobile.value) || 96)) : 96,
            spaceBetween: catSpaceBetween ? Math.min(40, Math.max(0, parseInt(catSpaceBetween.value) || 10)) : 10,
            rowsDesktop: catRowsDesktop ? Math.min(5, Math.max(1, parseInt(catRowsDesktop.value) || 1)) : 1,
            rowsMobile: catRowsMobile ? Math.min(5, Math.max(1, parseInt(catRowsMobile.value) || 1)) : 1,
            productSpacingEnabled: !!(catProductSpacingEnabledEl && catProductSpacingEnabledEl.checked),
            productSidePaddingPx: catProductSidePaddingEl ? Math.min(80, Math.max(0, parseInt(catProductSidePaddingEl.value, 10) || 0)) : 0,
            productCardGapPx: catProductCardGapEl ? Math.min(40, Math.max(0, parseInt(catProductCardGapEl.value, 10) || 10)) : 10,
            listingBannerMaxHeightMobile: Number.isFinite(listingMobRaw) ? Math.min(600, Math.max(80, listingMobRaw)) : (prevCat.listingBannerMaxHeightMobile != null ? prevCat.listingBannerMaxHeightMobile : 200),
            listingBannerMaxHeightDesktop: Number.isFinite(listingDeskRaw) ? Math.min(800, Math.max(100, listingDeskRaw)) : (prevCat.listingBannerMaxHeightDesktop != null ? prevCat.listingBannerMaxHeightDesktop : 240)
        };
        const smallBannerCount = (smallBannerCountEl && ['1','2'].includes(smallBannerCountEl.value)) ? parseInt(smallBannerCountEl.value, 10) : 2;
        const parseBoundedInt = (el, min, max, fallback) => {
            if (!el) return fallback;
            const raw = String(el.value ?? '').trim();
            if (raw === '') return fallback;
            const parsed = parseInt(raw, 10);
            if (!Number.isFinite(parsed)) return fallback;
            return Math.min(max, Math.max(min, parsed));
        };
        const desktopContentSideGapPx = parseBoundedInt(bannerDesktopContentSideGap, 0, 120, null);
        const desktopShellMaxWidthPx = parseBoundedInt(bannerDesktopShellMaxWidth, 1100, 1800, null);
        const homeLayoutModeEl = document.getElementById('classic-home-layout-mode');
        const homeLayoutMode = (homeLayoutModeEl && homeLayoutModeEl.value === 'boxed') ? 'boxed' : 'full';
        const forceDesktopFullBleed = desktopContentSideGapPx === 0 && homeLayoutMode !== 'boxed';
        const updatedLayout = {
            ...currentLayout,
            desktopContentSideGapPx,
            desktopShellMaxWidthPx,
            bannerConfig: {
                desktopHeight: parseBoundedInt(bannerHeightDesktop, 120, 800, 420),
                mobileHeight: parseBoundedInt(bannerHeightMobile, 80, 400, 140),
                sideSpacingDesktop: parseBoundedInt(bannerSpaceDesktop, 0, 80, 32),
                sideSpacingMobile: parseBoundedInt(bannerSpaceMobile, 0, 40, 12),
                topSpacingDesktop: parseBoundedInt(bannerTopDesktop, 0, 60, 16),
                bottomSpacingDesktop: parseBoundedInt(bannerBottomDesktop, 0, 60, 16),
                desktopMainSliderLayout: forceDesktopFullBleed ? 'fullBleed' : desktopMainSliderLayout,
                mobileMainSliderLayout,
                mainHeroPreset
            },
            smallBannerConfig: {
                count: smallBannerCount,
                desktopHeight: smallBannerHeightDesktop ? Math.min(300, Math.max(80, parseInt(smallBannerHeightDesktop.value) || 150)) : 150,
                mobileHeight: smallBannerHeightMobile ? Math.min(180, Math.max(60, parseInt(smallBannerHeightMobile.value) || 80)) : 80
            },
            promoBannerConfig: {
                desktopHeight: promoBannerHeightDesktop ? Math.min(400, Math.max(80, parseInt(promoBannerHeightDesktop.value) || 150)) : 150,
                mobileHeight: promoBannerHeightMobile ? Math.min(250, Math.max(60, parseInt(promoBannerHeightMobile.value) || 120)) : 120
            },
            categoryConfig,
            activeDesign: 'classic'
        };
        const homeAnnEnabledEl = document.getElementById('home-announcement-strip-enabled');
        const homeAnnTitleEl = document.getElementById('home-announcement-strip-title');
        const homeAnnBodyEl = document.getElementById('home-announcement-strip-body');
        const homeAnnCtaTextEl = document.getElementById('home-announcement-strip-cta-text');
        const homeAnnCtaUrlEl = document.getElementById('home-announcement-strip-cta-url');
        const homeAnnouncementStrip = {
            enabled: !!(homeAnnEnabledEl && homeAnnEnabledEl.checked),
            title: homeAnnTitleEl ? homeAnnTitleEl.value.trim() : '',
            body: homeAnnBodyEl ? homeAnnBodyEl.value.trim() : '',
            ctaText: homeAnnCtaTextEl ? homeAnnCtaTextEl.value.trim() : '',
            ctaUrl: homeAnnCtaUrlEl ? homeAnnCtaUrlEl.value.trim() : ''
        };
        const homeNewArrivalBandEnabledEl = document.getElementById('home-new-arrival-band-enabled');
        const homeNewArrivalBandLabelEl = document.getElementById('home-new-arrival-band-label');
        const homeNarFabGridEl = document.getElementById('home-nar-fabrilife-cat-grid-enabled');
        const homeNarFabLimitEl = document.getElementById('home-nar-fabrilife-cat-grid-limit');
        const homeNarFabPostBannersEn = document.getElementById('home-nar-fab-post-banners-enabled');
        const homeNarFabB1Url = document.getElementById('home-nar-fab-post-b1-url');
        const homeNarFabB1Link = document.getElementById('home-nar-fab-post-b1-link');
        const homeNarFabB1Cap = document.getElementById('home-nar-fab-post-b1-caption');
        const homeNarFabB2Url = document.getElementById('home-nar-fab-post-b2-url');
        const homeNarFabB2Link = document.getElementById('home-nar-fab-post-b2-link');
        const homeNarFabB2Cap = document.getElementById('home-nar-fab-post-b2-caption');
        let fabCatLimit = homeNarFabLimitEl ? parseInt(homeNarFabLimitEl.value, 10) : 8;
        if (!Number.isFinite(fabCatLimit)) fabCatLimit = 8;
        fabCatLimit = Math.min(24, Math.max(4, fabCatLimit));
        const homeNewArrivalBand = {
            enabled: !!(homeNewArrivalBandEnabledEl && homeNewArrivalBandEnabledEl.checked),
            label: homeNewArrivalBandLabelEl ? homeNewArrivalBandLabelEl.value.trim() : '',
            fabrilifeCategoryGridEnabled: !!(homeNarFabGridEl && homeNarFabGridEl.checked),
            fabrilifeCategoryGridLimit: fabCatLimit,
            fabrilifePostGridBannersEnabled: !!(homeNarFabPostBannersEn && homeNarFabPostBannersEn.checked),
            fabrilifePostGridBanners: [
                {
                    imageUrl: homeNarFabB1Url ? homeNarFabB1Url.value.trim() : '',
                    linkUrl: homeNarFabB1Link ? homeNarFabB1Link.value.trim() : '',
                    caption: homeNarFabB1Cap ? homeNarFabB1Cap.value.trim() : ''
                },
                {
                    imageUrl: homeNarFabB2Url ? homeNarFabB2Url.value.trim() : '',
                    linkUrl: homeNarFabB2Link ? homeNarFabB2Link.value.trim() : '',
                    caption: homeNarFabB2Cap ? homeNarFabB2Cap.value.trim() : ''
                }
            ]
        };

        const updates = {
            bannerSlides,
            bannerUrls: mainSlides,
            smallBanners,
            smallBannerLinks,
            promoBanner1Url,
            promoBanner2Url,
            promoBanner1Link,
            promoBanner2Link,
            bannerVisibility: visibility,
            layout: updatedLayout,
            homeAnnouncementStrip,
            homeNewArrivalBand
        };
        await update(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`), updates);
        UI.showToast('All banners saved successfully!');
    } catch (error) { console.error("Banner Save Error:", error); UI.showToast("Failed to save banners.", false); }
    finally { UI.setLoadingState(false, { button: btn }); }
}

// --- Order Editing Logic (UPDATED) ---

function openEditOrderModal(orderId) {
    const order = completedOrdersData[orderId];
    if (!order) { UI.showToast("Order not found.", false); return; }
    
    // Set Basic Info
    document.getElementById('edit-order-id').value = orderId;
    document.getElementById('edit-order-name').value = order.customerInfo?.name || '';
    document.getElementById('edit-order-phone').value = order.customerInfo?.phone || '';
    document.getElementById('edit-order-address').value = order.customerInfo?.address || '';
    document.getElementById('edit-order-shipping').value = order.shipping?.cost !== undefined ? order.shipping.cost : 0;
    
    // Initialize Editing Items State
    currentEditingItems = order.items ? (Array.isArray(order.items) ? [...order.items] : Object.values(order.items)) : [];
    
    // Populate Product Dropdown
    const select = document.getElementById('edit-order-product-select');
    select.innerHTML = '<option value="">Select product to add...</option>';
    
    Object.entries(allProducts).forEach(([pId, p]) => {
        const option = document.createElement('option');
        option.value = pId;
        option.textContent = `${p.name} - ${p.salePrice}৳`;
        select.appendChild(option);
    });

    // Render Items and Calculate
    renderEditOrderItems();
    recalculateEditOrderTotal();

    UI.toggleModal('edit-order-modal', true);
}

function renderEditOrderItems() {
    const container = document.getElementById('edit-order-items-container');
    if(!container) return;

    if (currentEditingItems.length === 0) {
        container.innerHTML = '<p class="text-xs text-center text-black italic bg-gray-50 p-2 rounded">No items in this order.</p>';
        return;
    }

    container.innerHTML = currentEditingItems.map((item, index) => `
        <div class="flex items-center justify-between bg-white p-2 rounded border border-gray-100 shadow-sm">
            <div class="flex-grow">
                <p class="text-xs font-semibold text-black truncate w-40">${item.name}</p>
                <p class="text-[10px] text-black">${item.price} ৳</p>
            </div>
            <div class="flex items-center gap-2">
                <input type="number" class="w-12 text-xs p-1 border rounded text-center edit-item-qty" value="${item.quantity}" min="1" data-index="${index}">
                <button type="button" class="text-red-500 hover:text-red-700 remove-edit-item-btn" data-index="${index}">
                    <i class="fa-solid fa-times"></i>
                </button>
            </div>
        </div>
    `).join('');
}

function recalculateEditOrderTotal() {
    const shipping = parseFloat(document.getElementById('edit-order-shipping').value) || 0;
    const subtotal = currentEditingItems.reduce((sum, item) => sum + (parseFloat(item.price) * parseInt(item.quantity)), 0);
    const total = subtotal + shipping;
    
    document.getElementById('edit-order-total').value = total;
}

function addItemToEditOrder() {
    const select = document.getElementById('edit-order-product-select');
    const productId = select.value;
    if (!productId) return;

    const product = allProducts[productId];
    if (product) {
        currentEditingItems.push({
            id: productId,
            name: product.name,
            price: product.salePrice,
            quantity: 1,
            image: product.imageUrl
        });
        renderEditOrderItems();
        recalculateEditOrderTotal();
        select.value = ""; // Reset select
    }
}

async function handleEditOrderSubmit(e) {
    e.preventDefault();
    const saveBtn = document.getElementById('save-order-changes-btn');
    UI.setLoadingState(true, { button: saveBtn });
    
    const orderId = document.getElementById('edit-order-id').value;
    const name = document.getElementById('edit-order-name').value.trim();
    const phone = document.getElementById('edit-order-phone').value.trim();
    const address = document.getElementById('edit-order-address').value.trim();
    const shippingCost = parseFloat(document.getElementById('edit-order-shipping').value) || 0;
    const totalBill = parseFloat(document.getElementById('edit-order-total').value) || 0;
    const subtotal = currentEditingItems.reduce((sum, item) => sum + (parseFloat(item.price) * parseInt(item.quantity)), 0);

    try {
        const updates = {};
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/customerInfo/name`] = name;
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/customerInfo/phone`] = phone;
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/customerInfo/address`] = address;
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/shipping/cost`] = shippingCost;
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/totalBill`] = totalBill;
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/subtotal`] = subtotal;
        updates[`clients/${CURRENT_CLIENT_ID}/orders/${orderId}/items`] = currentEditingItems;

        await update(ref(db), updates);
        
        // Update Local State Immediately for UI Refresh
        if(completedOrdersData[orderId]) {
            completedOrdersData[orderId].customerInfo = { name, phone, address };
            completedOrdersData[orderId].shipping.cost = shippingCost;
            completedOrdersData[orderId].totalBill = totalBill;
            completedOrdersData[orderId].subtotal = subtotal;
            completedOrdersData[orderId].items = [...currentEditingItems];
            
            const detailEl = document.getElementById('order-detail-content');
            if (detailEl && currentOrderDetailId === orderId && document.getElementById('dashboard-order-detail')?.classList.contains('active')) {
                detailEl.innerHTML = UI.generateCompletedOrderDetailHTML(orderId, completedOrdersData[orderId], CURRENT_CLIENT_ID, completedOrdersData);
            }
        }

        UI.showToast("Order details updated successfully!");
        UI.toggleModal('edit-order-modal', false);
        
    } catch (error) { 
        console.error("Update failed:", error); 
        UI.showToast("Failed to update order.", false); 
    } 
    finally { UI.setLoadingState(false, { button: saveBtn }); }
}

// --- Utils ---
function updateOrderNotification() {
    const totalOrders = Object.keys(completedOrdersData).length;
    const lastViewedCount = parseInt(localStorage.getItem(`last_viewed_${CURRENT_CLIENT_ID}`) || '0', 10);
    const newOrders = totalOrders - lastViewedCount;
    const badge = document.getElementById('new-orders-badge');
    if (badge) { badge.textContent = newOrders; badge.classList.toggle('hidden', newOrders <= 0); }
}

function handleUserNudgesAndLocks() {
    const hasReachedMilestone = localStorage.getItem(`${CURRENT_CLIENT_ID}_productMilestone`);
    
    if (isHostingActive) {
        document.querySelectorAll('.locked-feature-btn').forEach(btn => { 
            btn.classList.remove('grayscale', 'opacity-75', 'cursor-not-allowed'); 
            btn.querySelector('.lock-icon-overlay')?.classList.add('hidden'); 
        });
        return;
    }
    
    document.querySelectorAll('.locked-feature-btn').forEach(btn => { 
        btn.classList.add('grayscale', 'opacity-75', 'cursor-not-allowed'); 
        btn.querySelector('.lock-icon-overlay')?.classList.remove('hidden'); 
    });
    
    if (productCount >= 5 && !hasReachedMilestone) {
        document.getElementById('force-hosting-title').textContent = "Showcase Your Hard Work!";
        document.getElementById('force-hosting-message').textContent = `You've added ${productCount} products. It's time to go live.`;
        document.getElementById('go-to-hosting-btn').textContent = "Activate Hosting";
        UI.toggleModal('force-hosting-modal', true);
        localStorage.setItem(`${CURRENT_CLIENT_ID}_productMilestone`, 'true');
    }
}

function handleLogout() { 
    const user = auth.currentUser;
    if (user) {
        signOut(auth).catch((error) => { console.error("Logout Failed:", error); UI.showToast("Logout failed.", false); });
    } else {
        localStorage.removeItem('siteInfo');
        window.location.href = 'setup.html';
    }
}

async function handlePasswordChange(e) {
    e.preventDefault();
    const currentPassword = document.getElementById('current-password').value;
    const newPassword = document.getElementById('new-password').value;
    const confirmPassword = document.getElementById('confirm-new-password').value;
    const errorEl = document.getElementById('password-change-error');
    const updateBtn = document.getElementById('update-password-btn');
    errorEl.textContent = '';
    
    if (newPassword.length < 6) { errorEl.textContent = 'New password must be at least 6 characters.'; return; }
    if (newPassword !== confirmPassword) { errorEl.textContent = 'New passwords do not match.'; return; }
    
    UI.setLoadingState(true, { button: updateBtn });
    const user = auth.currentUser;
    
    if (!user) { errorEl.textContent = 'Authentication error. Please log in again.'; UI.setLoadingState(false, { button: updateBtn }); return; }
    
    try {
        const credential = EmailAuthProvider.credential(user.email, currentPassword);
        await reauthenticateWithCredential(user, credential);
        await updatePassword(user, newPassword);
        UI.showToast("Password updated successfully!");
        UI.toggleModal('profile-modal', false);
        e.target.reset();
    } catch (error) { 
        console.error("Password change error:", error); 
        if (error.code === 'auth/wrong-password') { errorEl.textContent = 'Incorrect current password.'; } 
        else { errorEl.textContent = 'An error occurred.'; } 
    } finally { 
        UI.setLoadingState(false, { button: updateBtn }); 
    }
}

// ============================================================
// 5. EVENT LISTENERS SETUP
// ============================================================
// SESSION MONITOR (Live Replay on Home)
// ============================================================

function getShopUrlForReplay() {
    if (!SITE_INFO || !SITE_INFO.subdomain) return '';
    const base = window.location.origin + (window.location.pathname.endsWith('/') ? window.location.pathname : window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/') + 1));
    // Load design page directly so monitor always shows main shop, not shop.html preview interstitial
    let designPage = 'shop-default.html';
    const ad = siteSettings && siteSettings.layout && siteSettings.layout.activeDesign;
    if (ad === 'classic' || ad === 'swapno') designPage = 'shop-classic.html';
    return base + designPage + '?site=' + encodeURIComponent(SITE_INFO.subdomain) + '&replay=1';
}

const SESSION_GAP_MS = 30 * 60 * 1000;
const LIVE_THRESHOLD_MS = 2 * 60 * 1000;

function getDeviceLabel(v) {
    const meta = v && (v.meta || v);
    const deviceType = (meta && (meta.deviceType || meta.device)) || 'Device';
    let ua = (meta && meta.userAgent) || '';
    if (typeof ua !== 'string') ua = '';
    let browser = '';
    if (ua.includes('Chrome') && !ua.includes('Edg')) browser = 'Chrome';
    else if (ua.includes('Safari') && !ua.includes('Chrome')) browser = 'Safari';
    else if (ua.includes('Firefox')) browser = 'Firefox';
    else if (ua.includes('Edg')) browser = 'Edge';
    else if (ua.includes('Samsung')) browser = 'Samsung';
    if (browser) return deviceType + ' – ' + browser;
    return deviceType;
}

function updateSessionMonitorDropdown() {
    if (!SESSION_REPLAY_ENABLED) return;
    const sel = document.getElementById('session-monitor-visitor-select');
    if (!sel) return;
    const currentVal = sel.value;
    const now = Date.now();
    const list = Object.entries(visitorData || {}).map(([id, v]) => ({
        id,
        lastActive: v.lastActive || 0,
        label: getDeviceLabel(v),
        isLive: (now - (v.lastActive || 0)) < LIVE_THRESHOLD_MS
    })).sort((a, b) => (b.lastActive || 0) - (a.lastActive || 0));
    sel.innerHTML = '<option value="">Select visitor...</option>' + list.slice(0, 50).map(v => {
        const text = (v.isLive ? '🟢 ' : '') + v.label + ' – ' + v.id.slice(-8);
        const val = String(v.id).replace(/"/g, '&quot;');
        return `<option value="${val}">${text.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</option>`;
    }).join('');
    if (currentVal && list.some(l => l.id === currentVal)) sel.value = currentVal;
}

function updateSessionMonitorUI() {
    if (!SESSION_REPLAY_ENABLED) return;
    const s = sessionReplayState;
    const tl = document.getElementById('session-monitor-timeline');
    const timeEl = document.getElementById('session-monitor-time');
    const maxIdx = Math.max(0, (s.events && s.events.length) ? s.events.length - 1 : 0);
    const idx = Math.min(Math.max(0, s.currentIndex), maxIdx);
    if (tl) {
        tl.min = 0;
        tl.max = maxIdx;
        tl.value = idx;
    }
    if (timeEl) {
        if (!s.events || s.events.length === 0) {
            timeEl.textContent = '0:00 / 0:00';
            return;
        }
        const firstTs = s.events[0].timestamp;
        const currentTs = s.events[idx].timestamp;
        const lastTs = s.events[s.events.length - 1].timestamp;
        const toSec = (ts) => { if (ts == null) return 0; const n = Number(ts); return n > 1e12 ? n / 1000 : n; };
        const fmt = (sec) => { const m = Math.floor(Math.max(0, sec) / 60); const ss = Math.floor(Math.max(0, sec) % 60); return m + ':' + String(ss).padStart(2, '0'); };
        const firstSec = toSec(firstTs);
        const currentElapsed = Math.max(0, toSec(currentTs) - firstSec);
        const totalElapsed = Math.max(0, toSec(lastTs) - firstSec);
        timeEl.textContent = fmt(currentElapsed) + ' / ' + fmt(totalElapsed);
    }
}

function applyReplayEvent(evt, wrap) {
    if (!SESSION_REPLAY_ENABLED) return;
    const iframe = document.getElementById('session-monitor-iframe');
    const dot = document.getElementById('session-monitor-click-dot');
    const shopUrl = getShopUrlForReplay();
    if (!iframe || !shopUrl) return;
    if (evt.type === 'pageview') {
        const rawPath = (evt.path || '').trim();
        const path = rawPath === '' || rawPath === '#' ? '#/shop' : (rawPath.startsWith('#') ? rawPath : '#' + rawPath);
        iframe.src = shopUrl + path;
        if (dot) dot.classList.add('hidden');
        iframe.onload = function() {
            iframe.onload = null;
            const s = sessionReplayState;
            const list = s.events || [];
            const pathStr = (evt.path || '').trim();
            const pathMatch = (p) => (p || '').trim() === pathStr || (pathStr === '' && ((p || '').trim() === '' || (p || '').trim() === '#' || (p || '').trim() === '#/shop'));
            let sx = 0, sy = 0;
            for (let i = s.currentIndex + 1; i < list.length; i++) {
                if (list[i].type === 'pageview') break;
                if (list[i].type === 'scroll' && pathMatch(list[i].path)) { sx = Number(list[i].scrollX) || 0; sy = Number(list[i].scrollY) || 0; }
            }
            try { if (iframe.contentWindow && !isNaN(sx) && !isNaN(sy)) iframe.contentWindow.scrollTo(sx, sy); } catch (e) {}
        };
    } else if (evt.type === 'scroll') {
        try {
            const x = Number(evt.scrollX);
            const y = Number(evt.scrollY);
            if (iframe.contentWindow && !isNaN(x) && !isNaN(y)) iframe.contentWindow.scrollTo(x, y);
        } catch (e) {}
    } else if (evt.type === 'click' && wrap) {
        const cartInd = document.getElementById('session-monitor-cart-indicator');
        if (cartInd) cartInd.classList.add('hidden');
        const vw = Math.max(1, Number(evt.viewportW) || 400);
        const vh = Math.max(1, Number(evt.viewportH) || 300);
        const scaleX = wrap.offsetWidth / vw;
        const scaleY = (wrap.offsetHeight || 220) / vh;
        if (dot) {
            dot.style.left = (evt.x * scaleX) + 'px';
            dot.style.top = (evt.y * scaleY) + 'px';
            dot.classList.remove('hidden');
            setTimeout(() => dot.classList.add('hidden'), 600);
        }
    } else if (evt.type === 'cart') {
        const cartInd = document.getElementById('session-monitor-cart-indicator');
        if (dot) dot.classList.add('hidden');
        if (cartInd) {
            cartInd.classList.remove('hidden');
            setTimeout(() => cartInd.classList.add('hidden'), 1500);
        }
    }
}

const REPLAY_MIN_DELAY_MS = 40;
const REPLAY_SKIP_GAP_MS = 5000;
const REPLAY_SKIP_CAP_MS = 1500;

function advanceSessionReplay() {
    if (!SESSION_REPLAY_ENABLED) return;
    const s = sessionReplayState;
    const len = (s.events && s.events.length) || 0;
    if (len === 0) { pauseSessionReplay(); return; }
    s.currentIndex = Math.min(Math.max(0, s.currentIndex), len - 1);
    const evt = s.events[s.currentIndex];
    const wrap = document.getElementById('session-monitor-screen-wrap');
    if (evt) applyReplayEvent(evt, wrap);
    updateSessionMonitorUI();
    s.currentIndex++;
    if (s.currentIndex >= len) { pauseSessionReplay(); return; }
    const nextEvt = s.events[s.currentIndex];
    const evtTs = evt && (evt.timestamp != null) ? Number(evt.timestamp) : 0;
    const nextTs = nextEvt && (nextEvt.timestamp != null) ? Number(nextEvt.timestamp) : evtTs;
    let diff = nextTs - evtTs;
    if (diff < 0) diff = 0;
    const speed = Math.max(0.25, s.speed || 1);
    let delayMs = diff / speed;
    if (s.skipInactivity && diff > REPLAY_SKIP_GAP_MS) delayMs = Math.min(delayMs, REPLAY_SKIP_CAP_MS);
    delayMs = Math.max(REPLAY_MIN_DELAY_MS, Math.min(12000, delayMs));
    s.timerId = setTimeout(advanceSessionReplay, delayMs);
}

function playSessionReplay() {
    if (!SESSION_REPLAY_ENABLED) return;
    const s = sessionReplayState;
    if (s.events.length === 0) return;
    s.isPlaying = true;
    document.getElementById('session-monitor-play')?.classList.add('hidden');
    document.getElementById('session-monitor-pause')?.classList.remove('hidden');
    advanceSessionReplay();
}

function pauseSessionReplay() {
    const s = sessionReplayState;
    s.isPlaying = false;
    if (s.timerId) { clearTimeout(s.timerId); s.timerId = null; }
    if (!SESSION_REPLAY_ENABLED) return;
    document.getElementById('session-monitor-play')?.classList.remove('hidden');
    document.getElementById('session-monitor-pause')?.classList.add('hidden');
}

async function loadSessionReplay(visitorId) {
    if (!SESSION_REPLAY_ENABLED) return;
    if (!CURRENT_CLIENT_ID || !visitorId) return;
    pauseSessionReplay();
    const placeholder = document.getElementById('session-monitor-placeholder');
    const iframe = document.getElementById('session-monitor-iframe');
    const overlay = document.getElementById('session-monitor-replay-overlay');
    const controls = document.getElementById('session-monitor-controls');
    if (placeholder) placeholder.classList.add('hidden');
    if (iframe) { iframe.classList.remove('hidden'); iframe.src = ''; }
    if (overlay) overlay.classList.remove('hidden');
    if (controls) controls.classList.remove('hidden');
    try {
        const snap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/visitors/${visitorId}/logs`));
        const raw = snap.val() || {};
        let events = Object.entries(raw).map(([k, v]) => ({ ...v, key: k })).filter(e => e.timestamp != null);
        const firstTs = events.length ? Number(events[0].timestamp) : 0;
        if (events.length && firstTs > 0 && firstTs < 1e11) {
            events.forEach(e => { e.timestamp = Number(e.timestamp) * 1000; });
        }
        events.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));
        let startIdx = 0;
        for (let i = 1; i < events.length; i++) {
            const gap = (events[i].timestamp || 0) - (events[i - 1].timestamp || 0);
            if (gap > SESSION_GAP_MS) startIdx = i;
        }
        events = events.slice(startIdx);
        const skipChk = document.getElementById('session-monitor-skip-inactivity');
        sessionReplayState = { events, currentIndex: 0, isPlaying: false, speed: Number(document.getElementById('session-monitor-speed')?.value) || 1, timerId: null, visitorId, skipInactivity: skipChk ? !!skipChk.checked : true };
        if (events.length === 0) {
            if (placeholder) { placeholder.classList.remove('hidden'); placeholder.textContent = 'No session data for this visitor.'; }
            if (iframe) iframe.classList.add('hidden');
            if (overlay) overlay.classList.add('hidden');
            if (controls) controls.classList.add('hidden');
            return;
        }
        const tl = document.getElementById('session-monitor-timeline');
        if (tl) { tl.max = Math.max(0, events.length - 1); tl.value = 0; }
        updateSessionMonitorUI();
        applyReplayEvent(events[0], document.getElementById('session-monitor-screen-wrap'));
    } catch (e) {
        console.error('Session replay load error:', e);
        if (placeholder) { placeholder.classList.remove('hidden'); placeholder.textContent = 'Could not load session.'; }
        if (iframe) iframe.classList.add('hidden');
        if (document.getElementById('session-monitor-replay-overlay')) document.getElementById('session-monitor-replay-overlay').classList.add('hidden');
        if (controls) controls.classList.add('hidden');
    }
}

function applySessionMonitorDeviceView(view) {
    if (!SESSION_REPLAY_ENABLED) return;
    const wrap = document.getElementById('session-monitor-screen-wrap');
    if (!wrap) return;
    if (view === 'mobile') wrap.classList.add('session-monitor-view-mobile');
    else wrap.classList.remove('session-monitor-view-mobile');
}

function toggleSessionMonitorFullscreen(enter) {
    if (!SESSION_REPLAY_ENABLED) return;
    const section = document.getElementById('session-monitor-section');
    const fullscreenBtn = document.getElementById('session-monitor-fullscreen');
    const exitBtn = document.getElementById('session-monitor-exit-fullscreen');
    if (!section) return;
    if (enter) {
        section.requestFullscreen?.()?.then(() => {}).catch(() => {});
    } else {
        document.exitFullscreen?.();
    }
}

function initSessionMonitor() {
    if (!SESSION_REPLAY_ENABLED) {
        sessionMonitorInitialized = true;
        return;
    }
    const sel = document.getElementById('session-monitor-visitor-select');
    const playBtn = document.getElementById('session-monitor-play');
    const pauseBtn = document.getElementById('session-monitor-pause');
    const speedSel = document.getElementById('session-monitor-speed');
    const timeline = document.getElementById('session-monitor-timeline');
    const deviceViewSel = document.getElementById('session-monitor-device-view');
    const fullscreenBtn = document.getElementById('session-monitor-fullscreen');
    const exitFullscreenBtn = document.getElementById('session-monitor-exit-fullscreen');
    if (!sel) return;
    sel.addEventListener('change', (e) => {
        const v = e.target.value;
        if (!v) {
            document.getElementById('session-monitor-placeholder')?.classList.remove('hidden');
            document.getElementById('session-monitor-iframe')?.classList.add('hidden');
            document.getElementById('session-monitor-replay-overlay')?.classList.add('hidden');
            document.getElementById('session-monitor-controls')?.classList.add('hidden');
            document.getElementById('session-monitor-placeholder').textContent = 'Select a visitor from the dropdown to watch session replay.';
            return;
        }
        loadSessionReplay(v);
    });
    deviceViewSel?.addEventListener('change', (e) => { applySessionMonitorDeviceView(e.target.value); });
    applySessionMonitorDeviceView(deviceViewSel?.value || 'desktop');
    fullscreenBtn?.addEventListener('click', () => toggleSessionMonitorFullscreen(true));
    exitFullscreenBtn?.addEventListener('click', () => toggleSessionMonitorFullscreen(false));
    document.addEventListener('fullscreenchange', () => {
        const isFs = !!document.fullscreenElement;
        fullscreenBtn?.classList.toggle('hidden', isFs);
        exitFullscreenBtn?.classList.toggle('hidden', !isFs);
    });
    playBtn?.addEventListener('click', playSessionReplay);
    pauseBtn?.addEventListener('click', pauseSessionReplay);
    speedSel?.addEventListener('change', (e) => { sessionReplayState.speed = Number(e.target.value) || 1; });
    document.getElementById('session-monitor-skip-inactivity')?.addEventListener('change', (e) => { sessionReplayState.skipInactivity = !!e.target.checked; });
    timeline?.addEventListener('input', (e) => {
        pauseSessionReplay();
        const raw = parseInt(e.target.value, 10);
        const events = sessionReplayState.events || [];
        const maxIdx = Math.max(0, events.length - 1);
        const idx = Math.min(Math.max(0, isNaN(raw) ? 0 : raw), maxIdx);
        sessionReplayState.currentIndex = idx;
        const evt = events[idx];
        if (evt) applyReplayEvent(evt, document.getElementById('session-monitor-screen-wrap'));
        updateSessionMonitorUI();
    });
    document.addEventListener('keydown', (e) => {
        const controls = document.getElementById('session-monitor-controls');
        if (!controls || controls.classList.contains('hidden')) return;
        const tag = (e.target && e.target.tagName) ? e.target.tagName.toUpperCase() : '';
        if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;
        const s = sessionReplayState;
        if (!s.events || s.events.length === 0) return;
        if (e.code === 'Space') { e.preventDefault(); (s.isPlaying ? pauseSessionReplay : playSessionReplay)(); return; }
        if (e.code === 'ArrowLeft') { e.preventDefault(); pauseSessionReplay(); s.currentIndex = Math.max(0, s.currentIndex - 1); const evt = s.events[s.currentIndex]; if (evt) applyReplayEvent(evt, document.getElementById('session-monitor-screen-wrap')); updateSessionMonitorUI(); return; }
        if (e.code === 'ArrowRight') { e.preventDefault(); pauseSessionReplay(); s.currentIndex = Math.min(s.events.length - 1, s.currentIndex + 1); const evt = s.events[s.currentIndex]; if (evt) applyReplayEvent(evt, document.getElementById('session-monitor-screen-wrap')); updateSessionMonitorUI(); return; }
    });
    updateSessionMonitorDropdown();
    sessionMonitorInitialized = true;
}

// ============================================================

/** Bind forms that live in lazily fetched `dashboard-settings.html` (not present when `setupEventListeners` first runs). Idempotent. */
function bindDashboardLazySettingsPanelListeners() {
    const once = (el, event, handler) => {
        if (!el || el.dataset.sbLazyBound === '1') return;
        el.dataset.sbLazyBound = '1';
        el.addEventListener(event, handler);
    };

    once(document.getElementById('product-form'), 'submit', handleProductSubmit);

    const pct = document.getElementById('product-click-target');
    if (pct && pct.dataset.sbLazyBound !== '1') {
        pct.dataset.sbLazyBound = '1';
        pct.addEventListener('change', function () {
            const block = document.getElementById('landing-page-selector-block');
            if (!block) return;
            if (this.value === 'landing_page') {
                block.classList.remove('hidden');
                loadLandingPagesIntoSelect('product-landing-page-slug');
            } else {
                block.classList.add('hidden');
            }
        });
    }

    once(document.getElementById('dashboard-print-labels-btn'), 'click', () => {
        const pid = document.getElementById('product-id')?.value?.trim();
        if (!pid) {
            UI.showToast('Save the product first, then print labels.', false);
            return;
        }
        const base = window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1);
        window.open(`${base}labels.html?ids=${encodeURIComponent(pid)}`, '_blank', 'noopener');
    });

    once(document.getElementById('category-form'), 'submit', handleCategorySubmit);
    once(document.getElementById('edit-order-form'), 'submit', handleEditOrderSubmit);
    once(document.getElementById('password-change-form'), 'submit', handlePasswordChange);

    once(document.getElementById('pixel-form'), 'submit', async (e) => {
        e.preventDefault();
        const raw = document.getElementById('pixel-id')?.value?.trim() || '';
        const pixelId = raw.replace(/\s+/g, '');
        if (pixelId && !/^\d{15,16}$/.test(pixelId)) {
            UI.showToast('Facebook Pixel ID should be 15–16 digits (numbers only). Leave empty to clear.', false);
            return;
        }
        const capiChk = document.getElementById('fb-capi-enabled');
        const patch = { pixelId };
        if (capiChk) {
            const prev = siteSettings.facebookConfig || {};
            patch.facebookConfig = { ...prev, capiEnabled: capiChk.checked };
        }
        if (!(await saveSettingsSection(patch, 'Pixel ID'))) return;
    });

    once(document.getElementById('tiktok-form'), 'submit', async (e) => {
        e.preventDefault();
        const enabled = Boolean(document.getElementById('tiktok-enabled')?.checked);
        const pixelId = document.getElementById('tiktok-pixel-id')?.value?.trim() || '';
        const accessToken = document.getElementById('tiktok-access-token')?.value?.trim() || '';
        if (enabled && (!pixelId || !accessToken)) {
            UI.showToast('When TikTok is enabled, Pixel ID and Access Token are required.', false);
            return;
        }
        if (
            !(await saveSettingsSection(
                {
                    tiktokConfig: {
                        pixelId,
                        accessToken,
                        testEventCode: document.getElementById('tiktok-test-event-code')?.value?.trim() || '',
                        enabled
                    }
                },
                'TikTok Tracking'
            ))
        )
            return;
    });

    once(document.getElementById('test-tiktok-btn'), 'click', () => {
        sendTikTokTestEvent().catch((err) => {
            console.error('tiktok test', err);
            UI.showToast('TikTok test failed.', false);
        });
    });

    once(document.getElementById('image-upload-provider'), 'change', () => {
        UI.syncImageUploadProviderFields();
    });

    once(document.getElementById('imgbb-form'), 'submit', (e) => {
        e.preventDefault();
        const providerEl = document.getElementById('image-upload-provider');
        const provider = providerEl && providerEl.value === 'daiman' ? 'daiman' : 'imgbb';
        const imgbbKey = document.getElementById('imgbb-api-key')?.value.trim() ?? '';
        const daimanKey = document.getElementById('daiman-api-key')?.value.trim() ?? '';
        saveSettingsSection(
            { imageUploadProvider: provider, imgbbApiKey: imgbbKey, daimanApiKey: daimanKey },
            'Upload API settings'
        );
    });

    once(document.getElementById('steadfast-form'), 'submit', (e) => {
        e.preventDefault();
        const apiKey = document.getElementById('steadfast-api-key').value.trim();
        const secretKey = document.getElementById('steadfast-secret-key').value.trim();
        if (!apiKey || !secretKey) {
            UI.showToast('Steadfast API Key and Secret Key are required.', false);
            return;
        }
        const baseUrlEl = document.getElementById('steadfast-api-base-url');
        const baseUrl = baseUrlEl ? baseUrlEl.value.trim() : '';
        if (baseUrl && !/^https?:\/\//i.test(baseUrl)) {
            UI.showToast('Steadfast base URL must start with http:// or https://', false);
            return;
        }
        saveSettingsSection(
            {
                steadfastConfig: {
                    apiKey,
                    secretKey,
                    baseUrl
                }
            },
            'Steadfast Credentials'
        );
    });

    once(document.getElementById('fb-token-form'), 'submit', async (e) => {
        e.preventDefault();
        const prev = siteSettings.facebookConfig || {};
        const adIdRaw = document.getElementById('fb-ad-account-id')?.value?.trim() || '';
        const next = {
            ...prev,
            accessToken: document.getElementById('fb-access-token').value.trim(),
            adAccountId: adIdRaw
        };
        if (!(await saveSettingsSection({ facebookConfig: next }, 'Facebook Token'))) return;
        siteSettings.facebookConfig = next;
    });

    once(document.getElementById('save-blocked-visitor-message-btn'), 'click', async () => {
        const ta = document.getElementById('blocked-visitor-message');
        const text = ta?.value != null ? String(ta.value) : '';
        const prevSec = siteSettings.security || {};
        try {
            await saveSettingsSection({ security: { ...prevSec, blockedVisitorMessage: text } }, 'Blocked visitor message');
            siteSettings.security = { ...prevSec, blockedVisitorMessage: text };
        } catch (err) {
            console.error(err);
        }
    });

    once(document.getElementById('blocked-ip-manual-add-btn'), 'click', () => {
        handleManualBlockIp();
    });

    once(document.getElementById('fb-page-post-form'), 'submit', async (e) => {
        e.preventDefault();
        const btn = document.getElementById('save-fb-page-post-btn');
        UI.setLoadingState(true, { button: btn });
        try {
            const prev = siteSettings.facebookPagePost || {};
            const next = {
                ...prev,
                pageId: document.getElementById('fb-page-id').value.trim(),
                pageAccessToken: document.getElementById('fb-page-access-token').value.trim(),
                pageName: document.getElementById('fb-page-name').value.trim(),
                autoPost: document.getElementById('fb-page-auto-post').checked,
                postTemplate: document.getElementById('fb-page-post-template').value
            };
            await saveSettingsSection({ facebookPagePost: next }, 'Facebook Page Post');
            siteSettings.facebookPagePost = next;
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    once(document.getElementById('gtm-form'), 'submit', (e) => {
        e.preventDefault();
        saveSettingsSection({ gtmId: document.getElementById('gtm-id').value.trim() }, 'GTM ID');
    });

    once(document.getElementById('push-config-form'), 'submit', (e) => {
        e.preventDefault();
        const enabled = Boolean(document.getElementById('push-enabled')?.checked);
        const vapidPublicKey = document.getElementById('push-vapid-public-key')?.value?.trim() || '';
        const defaultIconUrl = document.getElementById('push-default-icon')?.value?.trim() || '';
        if (enabled && !vapidPublicKey) {
            UI.showToast('VAPID public key is required when push is enabled.', false);
            return;
        }
        if (defaultIconUrl && !/^https?:\/\//i.test(defaultIconUrl)) {
            UI.showToast('Default icon URL must start with http:// or https://', false);
            return;
        }
        saveSettingsSection(
            {
                pushConfig: {
                    enabled,
                    vapidPublicKey,
                    defaultIconUrl
                }
            },
            'Push Config'
        );
    });

    once(document.getElementById('push-campaign-form'), 'submit', (e) => {
        e.preventDefault();
        sendPushCampaign().catch((err) => {
            console.error('push campaign', err);
            UI.showToast('Push send failed.', false);
        });
    });

    once(document.getElementById('test-push-btn'), 'click', () => {
        const audienceEl = document.getElementById('push-audience');
        const prevAudience = audienceEl ? audienceEl.value : 'all';
        if (audienceEl) audienceEl.value = 'latest';
        sendPushCampaign()
            .catch((err) => {
                console.error('push test', err);
                UI.showToast('Push test failed.', false);
            })
            .finally(() => {
                if (audienceEl) audienceEl.value = prevAudience;
            });
    });

    once(document.getElementById('save-policies-btn'), 'click', (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });

        const policies = {
            privacy: document.getElementById('policy-privacy').value,
            terms: document.getElementById('policy-terms').value,
            refund: document.getElementById('policy-refund').value,
            shipping: document.getElementById('policy-shipping').value
        };

        saveSettingsSection({ policies }, 'Legal Policies').then(() => UI.setLoadingState(false, { button: btn }));
    });

    refreshIntegrationStatusSummary();
    refreshPushSubscriberCount().catch(() => {});
}

function setupEventListeners() {
    if (listenersBound) return;
    try {
        bindDashboardChromeUI();
        UI.setupColorPickerSync();
        UI.setupOptionalContentTabControls();
        bindGlobalAdminSearch();

    // --- NEW: Initialize Logo Size Sync ---
    function setupLogoSizeSync() {
        const sync = (sliderId, inputId, displayId) => {
            const slider = document.getElementById(sliderId);
            const input = document.getElementById(inputId);
            const disp = document.getElementById(displayId);
            if(!slider || !input) return;

            slider.addEventListener('input', () => { input.value = slider.value; if(disp) disp.textContent = slider.value; });
            input.addEventListener('input', () => { slider.value = input.value; if(disp) disp.textContent = input.value; });
        };
        sync('slider-desktop-h', 'logo-height-desktop', 'disp-desktop-h');
        sync('slider-mobile-h', 'logo-height-mobile', 'disp-mobile-h');
        sync('slider-footer-logo-h', 'footer-logo-height', 'disp-footer-logo-h');
    }
    setupLogoSizeSync();

    // --- History API Popstate Listener (Handle Browser Back Button) ---
    window.addEventListener('popstate', (event) => {
        const st = event.state;
        const hash = window.location.hash.substring(1);
        if (hash.startsWith('admin-embed=')) {
            let u = '';
            try {
                u = decodeURIComponent(hash.slice('admin-embed='.length));
            } catch (_) {
                u = '';
            }
            if (u) openAdminShellEmbed(u, false);
            return;
        }
        closeAdminShellEmbedQuiet();
        if (st?.panel === 'order-detail' && st?.orderId) {
            showOrderDetailPage(st.orderId, false);
            return;
        }
        if (hash.startsWith('order-detail/')) {
            const oid = decodeURIComponent(hash.slice('order-detail/'.length));
            if (oid) {
                showOrderDetailPage(oid, false);
                return;
            }
        }
        currentOrderDetailId = null;
        const panelId = normalizePanelId(st?.panel || (hash ? hash.split('/')[0] : 'home'));
        let pid = panelId;
        if (pid === 'order-detail') pid = 'completed-orders';
        showDashboardPanel(pid, false);
    });

    // Global Click Delegation
    document.addEventListener('click', (e) => {
        const clickEl = e.target instanceof Element ? e.target : e.target.parentElement;
        const sidebarToggle = clickEl?.closest('.sidebar-group-toggle');
        if (sidebarToggle) {
            e.preventDefault();
            const controlsId = sidebarToggle.getAttribute('aria-controls');
            const g = sidebarToggle.closest('.sidebar-nav-group');
            if (g) {
                const open = g.classList.toggle('sidebar-group-open');
                sidebarToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
            }
            if (controlsId) {
                const submenu = document.getElementById(controlsId);
                if (submenu) submenu.setAttribute('aria-hidden', g && g.classList.contains('sidebar-group-open') ? 'false' : 'true');
            }
            return;
        }

        const adminEmb = clickEl?.closest('a[data-admin-embed]');
        if (adminEmb) {
            const raw = adminEmb.getAttribute('data-admin-embed');
            if (raw) {
                e.preventDefault();
                openAdminShellEmbed(raw, true);
            }
            return;
        }

        if (clickEl?.closest('#live-ads-overview-refresh')) {
            e.preventDefault();
            loadLiveAdsData('overview');
            return;
        }
        if (clickEl?.closest('#live-ads-facebook-refresh')) {
            e.preventDefault();
            loadLiveAdsData('facebook');
            return;
        }
        if (clickEl?.closest('#order-refresh-btn')) {
            e.preventDefault();
            renderCompletedOrders();
            return;
        }
        if (clickEl?.closest('#order-detail-back-btn')) {
            e.preventDefault();
            showDashboardPanel('completed-orders', true);
            return;
        }
        const statusChipBtn = clickEl?.closest('#order-status-chips .order-status-chip[data-order-status]');
        if (statusChipBtn) {
            e.preventDefault();
            orderState.statusFilter = statusChipBtn.dataset.orderStatus || 'All';
            orderState.currentPage = 1;
            renderCompletedOrders();
            return;
        }
        const orderPageBtn = clickEl?.closest('#completed-orders-list-pagination .pagination-btn');
        if (orderPageBtn && !orderPageBtn.disabled) {
            e.preventDefault();
            orderState.currentPage = parseInt(orderPageBtn.dataset.page, 10);
            renderCompletedOrders();
            return;
        }

        const detectiveSpyBtn = clickEl?.closest('[data-detective-open-spy]');
        if (detectiveSpyBtn) {
            e.preventDefault();
            const w = detectiveSpyBtn.getAttribute('data-detective-open-spy') || 'all';
            showDashboardPanel('visitor-spy');
            if (visitorSpyModule && typeof visitorSpyModule.setWealthFilter === 'function') {
                visitorSpyModule.setWealthFilter(w);
            }
            return;
        }
        const campToggle = clickEl?.closest('.live-ads-campaign-toggle');
        if (campToggle) {
            e.preventDefault();
            handleLiveAdsCampaignToggle(campToggle);
            return;
        }

        const blockIpEl = clickEl?.closest('[data-action="blockCustomerIp"]');
        if (blockIpEl) {
            e.preventDefault();
            const oid = blockIpEl.getAttribute('data-id') || '';
            const ip = blockIpEl.getAttribute('data-ip') || '';
            handleBlockCustomerIp(oid, ip);
            return;
        }

        const unblockIpEl = clickEl?.closest('[data-action="unblockCustomerIp"]');
        if (unblockIpEl) {
            e.preventDefault();
            const key = unblockIpEl.getAttribute('data-ip-key');
            if (!key || !CURRENT_CLIENT_ID) return;
            if (!confirm('Remove this IP from the block list?')) return;
            remove(ref(db, `clients/${CURRENT_CLIENT_ID}/security/blockedIps/${key}`))
                .then(() => {
                    UI.showToast('IP unblocked.');
                    refreshBlockedIpsUI().catch(() => {});
                })
                .catch(() => UI.showToast('Failed to unblock.', false));
            return;
        }

        // Customization tabs: show only the clicked tab's panel
        const tabBtn = clickEl?.closest('.customization-tab-btn');
        if (tabBtn && tabBtn.dataset.customizationTab) {
            const tabId = tabBtn.dataset.customizationTab;
            const panels = document.querySelectorAll('.customization-tab-panel');
            syncCustomizationTabVisualState(tabId);
            panels.forEach(panel => {
                if (panel.dataset.tab === tabId) panel.classList.remove('hidden');
                else panel.classList.add('hidden');
            });
            if (tabId === 'category-display') refreshHeaderCategoriesSelector();
            return;
        }

        const integrationsTabBtn = clickEl?.closest('.integrations-tab-btn');
        if (integrationsTabBtn && integrationsTabBtn.dataset.integrationsTab) {
            e.preventDefault();
            activateIntegrationsTab(integrationsTabBtn.dataset.integrationsTab);
            return;
        }

        let target = clickEl?.closest('[data-panel], [data-hash], [data-action], .remove-edit-item-btn, .remove-tag');
        const ordersTbody = document.getElementById('completed-orders-table-body');
        if (ordersTbody && clickEl && ordersTbody.contains(clickEl)) {
            const orderRow = clickEl.closest('tr.order-master-row[data-action="viewOrderDetail"]');
            if (orderRow) target = orderRow;
        }

        // Handle Item Removal Inside Edit Modal
        if (clickEl?.closest('.remove-edit-item-btn')) {
            const btn = clickEl.closest('.remove-edit-item-btn');
            const index = parseInt(btn.dataset.index, 10);
            currentEditingItems.splice(index, 1);
            renderEditOrderItems();
            recalculateEditOrderTotal();
            return;
        }

        // Handle Variant Tag Removal
        if (clickEl?.closest('.remove-tag')) {
            const btn = clickEl.closest('.remove-tag');
            const type = btn.dataset.type;
            const val = btn.dataset.val;
            if(type === 'color') variantColors = variantColors.filter(c => c !== val);
            if(type === 'size') variantSizes = variantSizes.filter(s => s !== val);
            renderVariantTags();
            return;
        }

        if (!target) return;
        
        const { panel, hash, action, id } = target.dataset;
        
        if (target.classList.contains('locked-feature-btn') && !isHostingActive) { 
            e.preventDefault(); e.stopPropagation(); 
            UI.toggleModal('feature-locked-modal', true); 
            return; 
        }

        // Navigation
        if (panel) {
            e.preventDefault();
            showDashboardPanel(panel);
            if (panel === 'visitor-spy' && target.dataset.filterWealth && visitorSpyModule && typeof visitorSpyModule.setWealthFilter === 'function') {
                visitorSpyModule.setWealthFilter(target.dataset.filterWealth);
            }
            if (normalizePanelId(panel) === 'customization' && target.dataset.customizationTarget) {
                const tabKey = target.dataset.customizationTarget;
                const scrollToId = (target.dataset.customizationScroll || '').trim();
                requestAnimationFrame(() => {
                    const tabBtn = document.querySelector(`.customization-tab-btn[data-customization-tab="${tabKey}"]`);
                    if (tabBtn) tabBtn.click();
                    if (scrollToId) {
                        requestAnimationFrame(() => {
                            document.getElementById(scrollToId)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
                        });
                    }
                });
            }
        }
        
        // Iframe Admin
        else if (hash) {
            const iframe = document.getElementById('admin-panel-iframe');
            if (iframe && SITE_INFO) {
                iframe.src = `admin.html?id=${SITE_INFO.clientId}${hash}`;
                UI.toggleModal('iframe-modal', true);
            }
        }
        
        // --- CRM Actions ---
        else if (action === 'viewCustomer') {
            const phone = target.dataset.phone;
            const profile = customerProfiles.find(c => c.phone === phone);
            UI.renderCustomerDetails(profile);
        }
        
        // Order Actions
        else if (action === 'viewOrderDetail') { 
            if (clickEl?.closest('select, input, button, .pagination-btn, a[href], label')) return;
            const oid = target.getAttribute('data-id') || id;
            if (oid) showOrderDetailPage(oid, true);
        }
        else if (action === 'viewIncompleteDetail') { 
            if (clickEl?.closest('select, input, button, .pagination-btn, a[href], label')) return;

            if (window.innerWidth < 1024) {
                const inlineContainer = document.getElementById(`inline-details-${id}`); 
                const isHidden = inlineContainer.classList.contains('hidden'); 
                document.querySelectorAll('.order-inline-details').forEach(el => el.classList.add('hidden')); 
                document.querySelectorAll('.master-item').forEach(el => el.classList.remove('bg-indigo-50', 'border-indigo-400'));
                if (isHidden) { 
                    inlineContainer.innerHTML = UI.generateIncompleteOrderDetailHTML(id, incompleteOrdersData[id]); 
                    inlineContainer.classList.remove('hidden'); 
                    target.classList.add('bg-indigo-50', 'border-indigo-400'); 
                }
            } else { 
                document.querySelectorAll('#incomplete-orders-list .master-item').forEach(el => el.classList.remove('bg-indigo-50', 'border-indigo-400')); 
                target.classList.add('bg-indigo-50', 'border-indigo-400'); 
                document.getElementById('incomplete-orders-detail').innerHTML = UI.generateIncompleteOrderDetailHTML(id, incompleteOrdersData[id]); 
            }
        }
        else if (action === 'updateOrderStatus') {
            const oid = target.getAttribute('data-id') || id;
            const wrap = target.closest('[data-order-status-row]') || target.parentElement;
            const selectElement = wrap?.querySelector('select');
            if (selectElement && oid) {
                updateOrderStatus(oid, selectElement.value, target);
            }
        }
        else if (action === 'copyOrderDetails') copyOrderDetails(id);
        else if (action === 'sendToSteadfast') sendToSteadfast(id);
        else if (action === 'sendToCourier') {
            const detailHost = clickEl?.closest('#order-detail-content') || document.getElementById('order-detail-content');
            if (detailHost) sendOrderToCourier(id, detailHost);
        }
        else if (action === 'runOrderFraudCheck') {
            const detailHost = clickEl?.closest('#order-detail-content') || document.getElementById('order-detail-content');
            if (detailHost) runOrderFraudCheck(id, detailHost);
        }
        else if (action === 'editOrder') openEditOrderModal(id);
        else if (action === 'deleteOrder') {
            if (confirm("⚠️ Are you sure you want to DELETE this order permanently? This cannot be undone.")) {
                remove(ref(db, `clients/${CURRENT_CLIENT_ID}/orders/${id}`))
                    .then(() => {
                        UI.showToast("Order deleted successfully.");
                        currentOrderDetailId = null;
                        const oc = document.getElementById('order-detail-content');
                        if (oc) oc.innerHTML = '';
                        showDashboardPanel('completed-orders', true);
                    })
                    .catch(err => UI.showToast("Failed to delete order.", false));
            }
        }
        
        // Product Actions
        else if (action === 'editProduct') { 
            const data = allProducts[id]; 
            if (data) { 
                resetProductForm(); 
                document.getElementById('product-id').value = id;
                document.getElementById('product-name').value = data.name;
                const catContainer = document.getElementById('product-categories-container');
                const cats = data.categories || (data.category ? [data.category] : []);
                if (catContainer) {
                    catContainer.querySelectorAll('input[name="product-categories"]').forEach(cb => { cb.checked = cats.includes(cb.value); });
                    UI.refreshProductSubcategoryDropdown(allCategories);
                    const currentSubValue = data.subcategoryKey || ((data.subcategoryParent && data.subcategory) ? `${data.subcategoryParent}|||${data.subcategory}` : (data.subcategory || ''));
                    const subSelect = document.getElementById('product-subcategory');
                    if (subSelect) UI.populateProductSubcategoryDropdown(
                        Array.from(subSelect.options).slice(1).map((opt) => ({
                            key: opt.value,
                            parent: opt.dataset.parentName || '',
                            name: opt.dataset.subName || ''
                        })),
                        currentSubValue
                    );
                } else {
                    const sel = document.getElementById('product-category');
                    if (sel) sel.value = data.category || (data.categories && data.categories[0]) || '';
                }
                document.getElementById('product-image-url').value = data.imageUrl; 
                document.getElementById('product-description').value = data.description || '';
                UI.updateImagePreview('#product-image-url', '#product-image-preview'); 
                
                // NEW: Populate Size Chart URL & Preview
                document.getElementById('product-size-chart').value = data.sizeChartUrl || '';
                UI.updateImagePreview('#product-size-chart', '#product-size-chart-preview');

                // NEW: Populate Video URL
                document.getElementById('product-video-url').value = data.videoUrl || '';

                // Click Behavior
                const clickTargetSel = document.getElementById('product-click-target');
                const landingSlugSel = document.getElementById('product-landing-page-slug');
                const landingBlock = document.getElementById('landing-page-selector-block');
                if (clickTargetSel) {
                    clickTargetSel.value = data.clickTarget || 'product_detail';
                    if (data.clickTarget === 'landing_page') {
                        if (landingBlock) landingBlock.classList.remove('hidden');
                        loadLandingPagesIntoSelect('product-landing-page-slug', data.landingPageSlug || '');
                    } else {
                        if (landingBlock) landingBlock.classList.add('hidden');
                    }
                }

                document.getElementById('gallery-images-container').innerHTML = ''; 
                if (data.galleryImageUrls && Array.isArray(data.galleryImageUrls)) { 
                    data.galleryImageUrls.forEach(url => UI.addGalleryImageRow(url)); 
                } 
                const hasVariantsCheckbox = document.getElementById('product-has-variants'); 
                hasVariantsCheckbox.checked = data.hasVariants; 
                hasVariantsCheckbox.dispatchEvent(new Event('change')); 
                
                if (data.hasVariants && data.variants) { 
                    // Populate Smart Variants Table
                    document.getElementById('product-variants-list').innerHTML = '';
                    Object.entries(data.variants).forEach(([k, v]) => addSmartVariantRow({ ...v, variantKey: k }));
                    populateVariantTagsFromProduct(data);
                } else { 
                    document.getElementById('product-regular-price').value = data.regularPrice || ''; 
                    document.getElementById('product-sale-price').value = data.salePrice || ''; 
                    document.getElementById('product-stock').value = data.stock ?? ''; 
                } 
                const pbc = document.getElementById('product-barcode');
                if (pbc) pbc.value = (!data.hasVariants && data.barcode) ? data.barcode : '';
                document.getElementById('product-form-title').textContent = `Editing: ${data.name}`; 
                document.querySelector('#save-product-btn .button-text').textContent = 'Update Product'; 
                document.getElementById('product-cancel-btn').classList.remove('hidden'); 
                window.scrollTo({ top: 0, behavior: 'smooth' }); 
            } 
        }
        else if (action === 'printProductLabels') {
            const pid = target.getAttribute('data-id') || id;
            if (!pid) return;
            const base = window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1);
            window.open(`${base}labels.html?ids=${encodeURIComponent(pid)}`, '_blank', 'noopener');
        }
        else if (action === 'deleteProduct') { 
            if (confirm(`Delete "${allProducts[id]?.name}"?`)) { 
                remove(ref(db, `clients/${CURRENT_CLIENT_ID}/products/${id}`))
                    .then(() => UI.showToast('Product deleted.'))
                    .catch(() => UI.showToast('Failed to delete.', false)); 
            } 
        }
        
        // Hosting
        else if (action === 'activateHosting') handleActivateHosting(target.dataset.planId, target);
        else if (action === 'downloadWebsiteIframeFile') downloadWebsiteIframeFile();
        else if (action === 'downloadAdminIframeFile') downloadAdminIframeFile();
        
        // Categories
        else if (action === 'editCategory') { 
            const data = allCategories[id]; 
            if (data) { 
                document.getElementById('category-id').value = id; 
                document.getElementById('category-name').value = data.name; 
                document.getElementById('category-image-url').value = data.imageUrl; 
                const descEl = document.getElementById('category-description');
                if (descEl) descEl.value = (data.description != null) ? String(data.description) : '';
                const lbEn = document.getElementById('category-listing-banner-enabled');
                if (lbEn) lbEn.checked = data.listingBannerEnabled !== false;
                const lbUrl = document.getElementById('category-listing-banner-url');
                if (lbUrl) lbUrl.value = (data.listingBannerUrl != null && String(data.listingBannerUrl).trim()) ? String(data.listingBannerUrl).trim() : '';
                UI.renderSubcategoryList(data.subcategories || {});
                UI.updateImagePreview('#category-image-url', '#category-image-preview'); 
                UI.updateImagePreview('#category-listing-banner-url', '#category-listing-banner-preview'); 
                document.getElementById('category-form-title').textContent = 'Edit Category'; 
                document.querySelector('#save-category-btn .button-text').textContent = 'Update Category'; 
                document.getElementById('category-cancel-btn').classList.remove('hidden'); 
            } 
        }
        else if (action === 'deleteCategory') { 
            if (confirm(`Delete this category?`)) { 
                const categoryOrderRef = ref(db, `clients/${CURRENT_CLIENT_ID}/categoryOrder`);
                remove(ref(db, `clients/${CURRENT_CLIENT_ID}/categories/${id}`))
                    .then(() => get(categoryOrderRef))
                    .then((snap) => {
                        const order = normalizeCategoryOrder(snap.val()).filter((oid) => oid !== id);
                        return set(categoryOrderRef, order);
                    })
                    .then(() => UI.showToast('Category deleted.'))
                    .catch(() => UI.showToast('Failed to delete.', false)); 
            } 
        }
    });

    function normalizeCategoryOrder(val) {
        if (Array.isArray(val)) return val;
        if (val && typeof val === 'object') return Object.keys(val).sort((a, b) => Number(a) - Number(b)).map(k => val[k]).filter(Boolean);
        return [];
    }
    // --- Category order: arrow up/down (click = move + save to Firebase) ---
    document.addEventListener('click', (e) => {
        const upBtn = e.target.closest('.category-move-up');
        const downBtn = e.target.closest('.category-move-down');
        if (!upBtn && !downBtn) return;
        const container = document.getElementById('category-list-container');
        if (!container) return;
        const id = (upBtn || downBtn).dataset.categoryId;
        const order = JSON.parse(container.dataset.order || '[]');
        const idx = order.indexOf(id);
        if (idx === -1) return;
        let newOrder;
        if (upBtn && idx > 0) {
            newOrder = [...order];
            [newOrder[idx - 1], newOrder[idx]] = [newOrder[idx], newOrder[idx - 1]];
        } else if (downBtn && idx < order.length - 1) {
            newOrder = [...order];
            [newOrder[idx], newOrder[idx + 1]] = [newOrder[idx + 1], newOrder[idx]];
        } else return;
        const categoryOrderRef = ref(db, `clients/${CURRENT_CLIENT_ID}/categoryOrder`);
        set(categoryOrderRef, newOrder).then(() => UI.showToast('Order updated.')).catch(() => UI.showToast('Failed to save order.', false));
    });

    // --- Helper function to handle input tags (New Mobile Friendly Logic) ---
    function addTagsFromInput(inputId, type) {
        const input = document.getElementById(inputId);
        if(!input) return;

        const rawValue = input.value.trim();
        if(!rawValue) return;

        // Split by comma, filter empty
        const newTags = rawValue.split(',').map(t => t.trim()).filter(t => t);

        newTags.forEach(tag => {
            if (type === 'color' && !variantColors.includes(tag)) variantColors.push(tag);
            if (type === 'size' && !variantSizes.includes(tag)) variantSizes.push(tag);
        });

        renderVariantTags();
        input.value = '';
    }

    // --- Variant Tag & Generator Events ---
    ['variant-color-input', 'variant-size-input'].forEach(id => {
        const el = document.getElementById(id);
        if(!el) return;
        const type = id.includes('color') ? 'color' : 'size';

        // Handle Enter and Comma
        el.addEventListener('keydown', (e) => {
            if(e.key === 'Enter' || e.key === ',') {
                e.preventDefault();
                addTagsFromInput(id, type);
            }
        });

        // Handle Blur (User clicks away)
        el.addEventListener('blur', () => addTagsFromInput(id, type));
    });

    document.getElementById('generate-variants-btn')?.addEventListener('click', () => {
        // Force process pending inputs first
        addTagsFromInput('variant-color-input', 'color');
        addTagsFromInput('variant-size-input', 'size');
        generateVariantMatrix();
    });

    document.getElementById('add-variant-btn')?.addEventListener('click', () => addSmartVariantRow()); // Manual Add

    // Handle Quantity Change in Edit Modal
    document.addEventListener('input', (e) => {
        if (e.target.classList.contains('edit-item-qty')) {
            const index = parseInt(e.target.dataset.index, 10);
            const newQty = parseInt(e.target.value, 10);
            if (newQty > 0) {
                currentEditingItems[index].quantity = newQty;
                recalculateEditOrderTotal();
            }
        }
    });

    // CRM Search Filter
    document.getElementById('crm-search-input')?.addEventListener('input', (e) => {
        const term = e.target.value.toLowerCase();
        const filtered = customerProfiles.filter(c => 
            c.name.toLowerCase().includes(term) || 
            c.phone.toLowerCase().includes(term)
        );
        UI.renderCustomerList(filtered);
    });

    bindDashboardLazySettingsPanelListeners();

    document.getElementById('save-general-settings-btn')?.addEventListener('click', async () => { 
        // --- NEW: Social Links Handling ---
        const socialLinks = {
            facebook: document.getElementById('social-facebook').value.trim(),
            instagram: document.getElementById('social-instagram').value.trim(),
            youtube: document.getElementById('social-youtube').value.trim(),
            tiktok: document.getElementById('social-tiktok').value.trim()
        };

        // NEW: Capture Logo Config
        const logoConfig = {
            desktopHeight: parseInt(document.getElementById('logo-height-desktop').value) || 50,
            mobileHeight: parseInt(document.getElementById('logo-height-mobile').value) || 40
        };

        const footerLogoHeightEl = document.getElementById('footer-logo-height');
        const footerLogoHeight = footerLogoHeightEl
            ? Math.min(120, Math.max(16, parseInt(footerLogoHeightEl.value, 10) || 40))
            : 40;
        const showFooterLogoEl = document.getElementById('show-footer-logo');
        const invertFooterLogoEl = document.getElementById('invert-footer-logo');
        const footerLogoConfig = {
            height: footerLogoHeight,
            show: showFooterLogoEl ? Boolean(showFooterLogoEl.checked) : true,
            invert: invertFooterLogoEl ? Boolean(invertFooterLogoEl.checked) : true
        };
        const footerLogoUrlEl = document.getElementById('footer-logo-url');
        const footerLogoUrl = footerLogoUrlEl ? footerLogoUrlEl.value.trim() : '';

        const fsEl = document.querySelector('.free-shipping-threshold-input') || document.getElementById('free-shipping-threshold');
        const freeShippingThreshold = fsEl ? Math.max(0, parseInt(fsEl.value, 10) || 0) : 0;

        const dupEl = document.getElementById('prevent-duplicate-orders');
        const preventDuplicateOrders24h = dupEl ? Boolean(dupEl.checked) : false;
        const dupHoursEl = document.getElementById('duplicate-order-hours');
        const duplicateOrderHours = dupHoursEl
            ? Math.min(8760, Math.max(1, parseInt(dupHoursEl.value, 10) || 24))
            : 24;

        const dataToSave = { 
            siteName: document.getElementById('site-name').value, 
            logoUrl: document.getElementById('logo-url').value, 
            logoConfig: logoConfig, // Added Logo Config
            footerLogoUrl,
            footerLogoConfig,
            freeShippingThreshold,
            preventDuplicateOrders24h,
            duplicateOrderHours,
            textContent: { 
                ...siteSettings.textContent, 
                topBarText: document.getElementById('topbar-text').value, 
                aboutTitle: document.getElementById('about-title').value, 
                aboutDescription: document.getElementById('about-description').value, 
                aboutImageUrl: document.getElementById('about-image-url').value, 
                copyright: document.getElementById('copyright-text').value, 
                developerCredit: document.getElementById('developer-credit').value 
            },
            socialLinks: socialLinks // Saving Social Links
        }; 
        const ok = await saveSettingsSection(dataToSave, 'General Settings');
        if (ok) syncDashboardShopNameUi();
    });
    
    // --- UPDATED COLOR SETTINGS SAVE LOGIC (empty = use default so Classic theme always gets valid colors) ---
    const classicColorDefaults = { body_bg: '#f9fafb', text_primary: '#111827', text_secondary: '#6b7280', accent_color: '#006837', header_bg: '#ffffff', header_text: '#1f2937', search_icon_color: '#ffffff', search_btn_bg: '#ffd400', search_btn_text: '#111111', menu_bg: '#ffffff', menu_text: '#374151', category_pill_text: '#000000', category_pill_bg: '#ffffff', category_card_label_text: '#000000', category_card_label_bg: '#facc15', cbs_tab_active_bg: '#facc15', cbs_tab_active_text: '#111827', cbs_tab_inactive_bg: '#ffffff', cbs_tab_inactive_text: '#374151', btn_primary_bg: '#006837', btn_primary_text: '#ffffff', btn_secondary_bg: '#111827', btn_secondary_text: '#ffffff', card_bg: '#ffffff', card_border: '#e5e7eb', price_text: '#1f2937', footer_bg: '#111827', footer_text: '#e5e7eb', top_bar_bg: '#e6f4ed', top_bar_text: '#374151' };
    const colorInput = (id) => { const el = document.getElementById(id); return (el && el.value && el.value.trim()) ? el.value.trim() : null; };
    document.getElementById('save-color-settings-btn')?.addEventListener('click', () => {
        const primaryText = colorInput('color-text-primary') || classicColorDefaults.text_primary;
        const accent = colorInput('color-accent') || classicColorDefaults.accent_color;
        const colors = {
            body_bg: colorInput('color-body-bg') || classicColorDefaults.body_bg,
            text_primary: primaryText,
            text_secondary: colorInput('color-text-secondary') || classicColorDefaults.text_secondary,
            accent_color: accent,
            header_bg: colorInput('color-header-bg') || classicColorDefaults.header_bg,
            header_text: colorInput('color-header-text') || classicColorDefaults.header_text,
            header_icon_color: colorInput('color-header-text') || classicColorDefaults.header_text,
            search_icon_color: colorInput('color-search-icon') || classicColorDefaults.search_icon_color,
            search_btn_bg: colorInput('color-search-btn-bg') || classicColorDefaults.search_btn_bg,
            search_btn_text: colorInput('color-search-btn-text') || classicColorDefaults.search_btn_text,
            menu_bg: colorInput('color-menu-bg') || classicColorDefaults.menu_bg,
            menu_text: colorInput('color-menu-text') || classicColorDefaults.menu_text,
            category_pill_text: colorInput('color-category-pill-text') || classicColorDefaults.category_pill_text,
            category_pill_bg: colorInput('color-category-pill-bg') || classicColorDefaults.category_pill_bg,
            category_card_label_text: colorInput('color-category-card-label-text') || classicColorDefaults.category_card_label_text,
            category_card_label_bg: colorInput('color-category-card-label-bg') || classicColorDefaults.category_card_label_bg,
            cbs_tab_active_bg: colorInput('color-cbs-tab-active-bg') || classicColorDefaults.cbs_tab_active_bg,
            cbs_tab_active_text: colorInput('color-cbs-tab-active-text') || classicColorDefaults.cbs_tab_active_text,
            cbs_tab_inactive_bg: colorInput('color-cbs-tab-inactive-bg') || classicColorDefaults.cbs_tab_inactive_bg,
            cbs_tab_inactive_text: colorInput('color-cbs-tab-inactive-text') || classicColorDefaults.cbs_tab_inactive_text,
            top_bar_bg: colorInput('color-top-bar-bg') || classicColorDefaults.top_bar_bg,
            top_bar_text: colorInput('color-top-bar-text') || classicColorDefaults.top_bar_text,
            btn_primary_bg: colorInput('color-btn-primary-bg') || classicColorDefaults.btn_primary_bg,
            btn_primary_text: colorInput('color-btn-primary-text') || classicColorDefaults.btn_primary_text,
            btn_secondary_bg: colorInput('color-btn-secondary-bg') || classicColorDefaults.btn_secondary_bg,
            btn_secondary_text: colorInput('color-btn-secondary-text') || classicColorDefaults.btn_secondary_text,
            card_bg: colorInput('color-card-bg') || classicColorDefaults.card_bg,
            card_border: classicColorDefaults.card_border,
            price_text: colorInput('color-price-text') || classicColorDefaults.price_text,
            section_title_color: primaryText,
            footer_bg: colorInput('color-footer-bg') || classicColorDefaults.footer_bg,
            footer_text: colorInput('color-footer-text') || classicColorDefaults.footer_text,
            footer_accent: accent
        };
        saveSettingsSection({ colors }, 'Theme Colors');
    });

    document.getElementById('save-shipping-settings-btn')?.addEventListener('click', () => { const shippingOptions = Array.from(document.querySelectorAll('#shipping-options-admin-list > div')).map(row => ({ label: row.querySelector('.shipping-label-input').value.trim(), cost: Number(row.querySelector('.shipping-cost-input').value) })).filter(opt => opt.label && !isNaN(opt.cost)); saveSettingsSection({ shippingOptions }, 'Shipping Methods'); });
    
    document.getElementById('save-product-design-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });
        try {
            const settingsSnap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`));
            const snapVal = settingsSnap.val() || {};
            const currentLayout = snapVal.layout && typeof snapVal.layout === 'object' ? { ...snapVal.layout } : {};

            const cardEl = document.getElementById('section-design-product-card');
            const productDisplayStyle = (cardEl && ['classic', 'app', 'minimal', 'imageFocus', 'chaldal', 'daraz', 'shwapno', 'orderCall'].includes(cardEl.value)) ? cardEl.value : 'classic';
            const detailLayoutEl = document.getElementById('section-design-product-detail-layout');
            const productDetailLayout =
                detailLayoutEl && ['mobileCommerceV1', 'mobileCommerceV2'].includes(detailLayoutEl.value)
                    ? detailLayoutEl.value
                    : 'standard';
            const classicSizeEl = document.getElementById('section-design-classic-card-size');
            const classicWEl = document.getElementById('section-design-classic-card-width-px');
            const classicHEl = document.getElementById('section-design-classic-card-height-px');
            const appHeightEl = document.getElementById('section-design-app-card-height');
            const appWidthEl = document.getElementById('section-design-app-card-width');
            const classicCardSize = (classicSizeEl && ['small', 'medium', 'large'].includes(classicSizeEl.value)) ? classicSizeEl.value : 'medium';
            let classicCardWidthPx = null;
            let classicCardHeightPx = null;
            if (classicWEl && classicHEl && classicWEl.value.trim() !== '' && classicHEl.value.trim() !== '') {
                const w = parseInt(classicWEl.value, 10);
                const h = parseInt(classicHEl.value, 10);
                if (!isNaN(w) && !isNaN(h)) {
                    classicCardWidthPx = Math.min(500, Math.max(80, w));
                    classicCardHeightPx = Math.min(600, Math.max(100, h));
                }
            }
            const appStyleCardHeight = (appHeightEl && ['small', 'medium', 'large'].includes(appHeightEl.value)) ? appHeightEl.value : 'medium';
            const appStyleCardWidth = (appWidthEl && ['small', 'medium', 'large'].includes(appWidthEl.value)) ? appWidthEl.value : 'medium';
            const readOrderCallHex = (hexId) => {
                const hexEl = document.getElementById(hexId);
                const h = hexEl && hexEl.value ? hexEl.value.trim() : '';
                if (!h) return null;
                const v = h.startsWith('#') ? h : `#${h}`;
                return /^#[0-9A-Fa-f]{6}$/i.test(v) ? v : null;
            };
            let orderCallOrderNowBg = currentLayout.orderCallOrderNowBg ?? null;
            let orderCallOrderNowText = currentLayout.orderCallOrderNowText ?? null;
            if (productDisplayStyle === 'orderCall') {
                orderCallOrderNowBg = readOrderCallHex('order-call-order-now-bg-hex');
                orderCallOrderNowText = readOrderCallHex('order-call-order-now-text-hex');
            }
            const upsellEnabledEl = document.getElementById('section-design-upsell-enabled');
            const upsellEnabled = !!(upsellEnabledEl && upsellEnabledEl.checked);

            const productGridColsDesktopEl = document.getElementById('product-grid-cols-desktop');
            const productGridColsMobileEl = document.getElementById('product-grid-cols-mobile');
            const productSpacingEnabledEl = document.getElementById('cat-product-spacing-enabled');
            const productSidePaddingEl = document.getElementById('cat-product-side-padding');
            const productCardGapEl = document.getElementById('cat-product-card-gap');
            const prevCat = { ...(currentLayout.categoryConfig || {}) };
            const categoryConfig = {
                ...prevCat,
                productSpacingEnabled: !!(productSpacingEnabledEl && productSpacingEnabledEl.checked),
                productSidePaddingPx: productSidePaddingEl ? Math.min(80, Math.max(0, parseInt(productSidePaddingEl.value, 10) || 0)) : 0,
                productCardGapPx: productCardGapEl ? Math.min(40, Math.max(0, parseInt(productCardGapEl.value, 10) || 10)) : 10
            };
            const productGridConfig = {
                ...(currentLayout.productGridConfig || {}),
                columnsDesktop: productGridColsDesktopEl ? Math.min(8, Math.max(2, parseInt(productGridColsDesktopEl.value, 10) || 5)) : 5,
                columnsMobile: productGridColsMobileEl ? Math.min(5, Math.max(2, parseInt(productGridColsMobileEl.value, 10) || 3)) : 3
            };
            const newLayout = {
                ...currentLayout,
                productDisplayStyle,
                productDetailLayout,
                classicCardSize,
                classicCardWidthPx,
                classicCardHeightPx,
                appStyleCardHeight,
                appStyleCardWidth,
                orderCallOrderNowBg,
                orderCallOrderNowText,
                upsellEnabled,
                categoryConfig,
                productGridConfig
            };

            const mbCountRaw = document.getElementById('mobile-bottom-bar-btn-count')?.value;
            const buttonCount = parseInt(mbCountRaw, 10) === 1 ? 1 : 2;
            const primaryAct = document.getElementById('mobile-bottom-primary-action')?.value;
            const secondaryAct = document.getElementById('mobile-bottom-secondary-action')?.value;
            const deliveryRaw = (document.getElementById('delivery-time-text')?.value || '').trim();

            await saveSettingsSection({
                layout: newLayout,
                contactInfo: {
                    phoneNumber: document.getElementById('contact-phone')?.value || '',
                    hotlineNumber: document.getElementById('contact-hotline')?.value || '',
                    whatsappNumber: document.getElementById('contact-whatsapp')?.value || '',
                    messengerPageId: document.getElementById('contact-messenger')?.value || '',
                    address: document.getElementById('contact-address')?.value || ''
                },
                productPageText: {
                    feature1Title: document.getElementById('feature1-title')?.value || '',
                    feature1Subtitle: document.getElementById('feature1-subtitle')?.value || '',
                    feature2Title: document.getElementById('feature2-title')?.value || '',
                    feature2Subtitle: document.getElementById('feature2-subtitle')?.value || '',
                    feature3Title: document.getElementById('feature3-title')?.value || '',
                    feature3Subtitle: document.getElementById('feature3-subtitle')?.value || '',
                    relatedProductsTitle: document.getElementById('related-products-title')?.value || ''
                },
                mobileBottomBar: {
                    captionAbove: (document.getElementById('mobile-bottom-bar-caption')?.value || '').trim(),
                    buttonCount,
                    primaryLabel: (document.getElementById('mobile-bottom-primary-label')?.value || '').trim() || 'Add to Cart',
                    primaryAction: primaryAct === 'buyNow' ? 'buyNow' : 'addToCart',
                    secondaryLabel: (document.getElementById('mobile-bottom-secondary-label')?.value || '').trim() || 'Buy Now',
                    secondaryAction: secondaryAct === 'addToCart' ? 'addToCart' : 'buyNow'
                },
                deliveryTimeText: deliveryRaw || null
            }, 'Product design');
            UI.populateSiteSettings(siteSettings);
        } catch (err) {
            console.error('Product design save error:', err);
            UI.showToast('Failed to save product design.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    document.getElementById('save-homepage-features-btn')?.addEventListener('click', async () => {
        const defaultHomepageFeatures = [
            { icon: 'fa-solid fa-truck-fast', title: '60 Mins Delivery', subtitle: 'Free shipping over 1500tk' },
            { icon: 'fa-solid fa-shield-halved', title: 'Authorized Products', subtitle: 'Within 30 days for an exchange' },
            { icon: 'fa-solid fa-headset', title: 'Customer Service Support', subtitle: '8am to 10pm' },
            { icon: 'fa-solid fa-credit-card', title: 'Flexible Payments', subtitle: 'Pay with multiple credit cards' }
        ];
        const readText = (id, fallback) => {
            const el = document.getElementById(id);
            const value = el ? String(el.value || '').trim() : '';
            return value || fallback;
        };
        const items = defaultHomepageFeatures.map((defaults, idx) => ({
            icon: readText(`homepage-feature-${idx + 1}-icon`, defaults.icon),
            title: readText(`homepage-feature-${idx + 1}-title`, defaults.title),
            subtitle: readText(`homepage-feature-${idx + 1}-subtitle`, defaults.subtitle)
        }));
        const enabled = !!document.getElementById('homepage-features-enabled')?.checked;
        const currentLayout = (siteSettings && siteSettings.layout && typeof siteSettings.layout === 'object')
            ? { ...siteSettings.layout }
            : {};
        const readOptionalContentHex = (hexId) => {
            const el = document.getElementById(hexId);
            const t = el ? String(el.value || '').trim() : '';
            if (!t) return undefined;
            const n = UI.normalizeOptionalContentCssColor(t);
            return n || undefined;
        };
        const styles = {};
        const cardBg = readOptionalContentHex('optional-content-card-bg-hex');
        if (cardBg) styles.cardBg = cardBg;
        const cardBorder = readOptionalContentHex('optional-content-card-border-hex');
        if (cardBorder) styles.cardBorder = cardBorder;
        const iconBg = readOptionalContentHex('optional-content-icon-bg-hex');
        if (iconBg) styles.iconBg = iconBg;
        const iconBorder = readOptionalContentHex('optional-content-icon-border-hex');
        if (iconBorder) styles.iconBorder = iconBorder;
        const iconColor = readOptionalContentHex('optional-content-icon-fg-hex');
        if (iconColor) styles.iconColor = iconColor;
        const titleColor = readOptionalContentHex('optional-content-title-color-hex');
        if (titleColor) styles.titleColor = titleColor;
        const subtitleColor = readOptionalContentHex('optional-content-subtitle-color-hex');
        if (subtitleColor) styles.subtitleColor = subtitleColor;
        const shadowEl = document.getElementById('optional-content-card-shadow');
        const shadowNorm = UI.normalizeOptionalContentShadow(shadowEl ? shadowEl.value : '');
        if (shadowNorm) styles.cardShadow = shadowNorm;
        const gapEl = document.getElementById('optional-content-grid-gap');
        const gapRaw = gapEl ? String(gapEl.value || '').trim() : '';
        if (gapRaw !== '') {
            const n = Number(gapRaw);
            if (Number.isFinite(n) && n >= 0 && n <= 48) styles.gridGapPx = Math.round(n);
        }
        const hasStyles = Object.keys(styles).length > 0;
        currentLayout.homepageFeatures = hasStyles ? { enabled, items, styles } : { enabled, items };

        await saveSettingsSection({ layout: currentLayout }, 'Optional Content');
        UI.populateSiteSettings(siteSettings);
    });

    document.getElementById('save-home-page-design-btn')?.addEventListener('click', async () => {
        const currentLayout =
            siteSettings && siteSettings.layout && typeof siteSettings.layout === 'object'
                ? { ...siteSettings.layout }
                : {};
        const recEnabled = !!document.getElementById('recommended-enabled')?.checked;
        const recTitleRaw = (document.getElementById('recommended-title')?.value || '').trim();
        const recTitle = recTitleRaw || 'Recommended For You';
        const maxItemsEl = document.getElementById('recommended-max-items');
        let recMax = 12;
        if (maxItemsEl && String(maxItemsEl.value || '').trim() !== '') {
            const n = parseInt(maxItemsEl.value, 10);
            if (Number.isFinite(n)) recMax = Math.min(24, Math.max(1, n));
        }
        const recWrap = document.getElementById('recommended-product-checkboxes');
        const recIds = recWrap
            ? [
                  ...new Set(
                      Array.from(recWrap.querySelectorAll('input[name="recommended-product"]:checked')).map((cb) =>
                          String(cb.value || '').trim()
                      )
                  )
              ].filter(Boolean).slice(0, RECOMMENDED_PRODUCTS_SAVE_CAP)
            : [];
        const fallbackRadio = document.querySelector('input[name="recommended-fallback-when-disabled"]:checked');
        const fallbackWhenDisabled =
            fallbackRadio && fallbackRadio.value === 'featuredProducts' ? 'featuredProducts' : 'none';
        const fallbackTitleRaw = (document.getElementById('recommended-fallback-title')?.value || '').trim();
        const fallbackTitle = fallbackTitleRaw || null;
        const suppressMainFlashWhenRecommendedFallback = !!document.getElementById(
            'recommended-suppress-main-flash'
        )?.checked;
        currentLayout.recommendedSection = {
            enabled: recEnabled,
            title: recTitle,
            maxItems: recMax,
            productIds: recIds,
            fallbackWhenDisabled,
            ...(fallbackTitle ? { fallbackTitle } : {}),
            suppressMainFlashWhenRecommendedFallback
        };

        const cbsWrap = document.getElementById('cbs-category-checkboxes');
        const cbsEnabled = !!document.getElementById('cbs-enabled')?.checked;
        const cbsTitleRaw = (document.getElementById('cbs-section-title')?.value || '').trim();
        const cbsTitle = cbsTitleRaw || '';
        const maxProdEl = document.getElementById('cbs-max-products');
        let cbsMax = 10;
        if (maxProdEl && String(maxProdEl.value || '').trim() !== '') {
            const n = parseInt(maxProdEl.value, 10);
            if (Number.isFinite(n)) cbsMax = Math.min(24, Math.max(1, n));
        }
        const orderedIdsForCbs = (Array.isArray(categoryOrder) ? categoryOrder : []).filter((id) => allCategories && allCategories[id]);
        const categoryNamesForCbs = [];
        orderedIdsForCbs.forEach((id) => {
            const cb = cbsWrap
                ? Array.from(cbsWrap.querySelectorAll('input[name="cbs-category"]')).find((el) => el.value === String(id))
                : null;
            if (!cb || !cb.checked) return;
            const nm = String(allCategories[id]?.name || '').trim();
            if (nm) categoryNamesForCbs.push(nm);
        });
        const cbsNamesDeduped = [...new Set(categoryNamesForCbs)].slice(0, CBS_CATEGORY_SAVE_CAP);
        const defCatRaw = (document.getElementById('cbs-default-category')?.value || '').trim();
        const defaultCategoryName =
            defCatRaw && cbsNamesDeduped.includes(defCatRaw) ? defCatRaw : null;
        const bannerImageUrl = (document.getElementById('cbs-banner-image-url')?.value || '').trim();
        const bannerLinkUrl = (document.getElementById('cbs-banner-link-url')?.value || '').trim();
        const bannerAlt = (document.getElementById('cbs-banner-alt')?.value || '').trim();
        const hideWhenNoProducts = !!document.getElementById('cbs-hide-when-no-products')?.checked;

        currentLayout.categoryBannerSection = {
            enabled: cbsEnabled,
            ...(cbsTitle ? { title: cbsTitle } : {}),
            categoryNames: cbsNamesDeduped,
            maxProductsPerCategory: cbsMax,
            ...(defaultCategoryName ? { defaultCategoryName } : {}),
            bannerImageUrl,
            ...(bannerLinkUrl ? { bannerLinkUrl } : {}),
            ...(bannerAlt ? { bannerAlt } : {}),
            hideWhenNoProducts
        };

        const homeRowsModeManual = !!document.getElementById('home-cat-rows-mode-manual')?.checked;
        const prevHcr =
            currentLayout.homeCategoryRowsSection && typeof currentLayout.homeCategoryRowsSection === 'object'
                ? { ...currentLayout.homeCategoryRowsSection }
                : {};
        if (!homeRowsModeManual) {
            currentLayout.homeCategoryRowsSection = {
                ...prevHcr,
                mode: 'category'
            };
        } else {
            const manualTitleRaw = (document.getElementById('home-cat-rows-manual-title')?.value || '').trim();
            const editorEl = document.getElementById('home-cat-rows-tabs-editor');
            const defaultTabRaw = (document.getElementById('home-cat-rows-default-tab')?.value || '').trim();
            const tabRows = editorEl ? [...editorEl.querySelectorAll('[data-home-tab-row]')] : [];
            const manualTabs = [];
            for (const row of tabRows) {
                const id = String(row.getAttribute('data-home-tab-row') || '').trim();
                const label = (row.querySelector('.home-cat-rows-tab-label')?.value || '').trim();
                const maxN = parseInt(row.querySelector('.home-cat-rows-tab-max')?.value, 10);
                const maxItems = Number.isFinite(maxN) ? Math.min(24, Math.max(1, maxN)) : 10;
                const wrap = row.querySelector('.home-cat-rows-tab-checkboxes');
                const ids = wrap
                    ? [
                          ...new Set(
                              Array.from(wrap.querySelectorAll('.home-cat-rows-prod-cb:checked')).map((cb) =>
                                  String(cb.getAttribute('data-product-id') || '').trim()
                              )
                          )
                      ]
                          .filter(Boolean)
                          .slice(0, HOME_MANUAL_TAB_PRODUCTS_CAP)
                    : [];
                if (!id) continue;
                if (!label) {
                    try {
                        UI.showToast('ম্যানুয়াল মোডে প্রতিটি ট্যাবের একটি নাম দিন।', false);
                    } catch (_) { /* noop */ }
                    return;
                }
                manualTabs.push({ id, label, maxItems, productIds: ids });
            }
            if (!manualTabs.length) {
                try {
                    UI.showToast('কমপক্ষে একটি ম্যানুয়াল ট্যাব যোগ করুন।', false);
                } catch (_) { /* noop */ }
                return;
            }
            const defaultManualTabId =
                defaultTabRaw && manualTabs.some((t) => t.id === defaultTabRaw) ? defaultTabRaw : manualTabs[0].id;
            currentLayout.homeCategoryRowsSection = {
                ...prevHcr,
                mode: 'manualTabs',
                ...(manualTitleRaw ? { manualTitle: manualTitleRaw } : {}),
                manualTabs,
                defaultManualTabId
            };
        }

        const prevHf =
            currentLayout.homepageFeatures && typeof currentLayout.homepageFeatures === 'object'
                ? { ...currentLayout.homepageFeatures }
                : {};
        const serviceStripOn = !!document.getElementById('home-design-service-strip-enabled')?.checked;
        currentLayout.homepageFeatures = { ...prevHf, enabled: serviceStripOn };

        await saveSettingsSection({ layout: currentLayout }, 'Home page design');
        UI.populateSiteSettings(siteSettings);
    });
    
    // UPDATED: Save Banners with Visibility
    document.getElementById('save-banners-btn')?.addEventListener('click', handleSaveBanners);

    // Section designs (Customization tab) – bind after panels loaded; merge with latest from DB
    document.getElementById('save-section-designs-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });
        try {
            const headerEl = document.getElementById('section-design-header');
            const bannerEl = document.getElementById('section-design-banner');
            const footerEl = document.getElementById('section-design-footer');
            const sectionHeaderEl = document.getElementById('section-design-section-header');
            const smallBannersEl = document.getElementById('section-design-small-banners');
            const promoBannerEl = document.getElementById('section-design-promo-banner');
            const featuredEl = document.getElementById('section-design-featured');
            const categoryRowsEl = document.getElementById('section-design-category-rows');
            const bottomNavEnabledEl = document.getElementById('section-design-bottom-nav-enabled');
            const bottomNavEl = document.getElementById('section-design-bottom-nav');
            const cartDrawerEl = document.getElementById('section-design-cart-drawer');
            const cartBagEl = document.getElementById('section-design-cart-bag');
            const groceryTopEl = document.getElementById('grocery-cart-top-color');
            const groceryBottomEl = document.getElementById('grocery-cart-bottom-color');
            const hamburgerEl = document.getElementById('section-design-hamburger-menu');
            const pcLayoutStyleEl = document.getElementById('section-design-pc-layout-style');
            const checkoutAddrEl = document.getElementById('checkout-address-form-mode');
            const checkoutAddressForm = (checkoutAddrEl && ['simple', 'structured'].includes(checkoutAddrEl.value)) ? checkoutAddrEl.value : 'simple';
            const homeLayoutEl = document.getElementById('classic-home-layout-mode');
            const homeLayoutMode = (homeLayoutEl && ['full', 'boxed'].includes(homeLayoutEl.value)) ? homeLayoutEl.value : 'full';
            const headerDesign = (headerEl && ['default','minimal','shwapno','centerTrade'].includes(headerEl.value)) ? headerEl.value : 'default';
            const hamburgerMenuStyle = (hamburgerEl && ['default','shwapnoPcView'].includes(hamburgerEl.value)) ? hamburgerEl.value : 'default';
            const pcLayoutStyle = (pcLayoutStyleEl && ['default', 'shwapnoLeftMenu'].includes(pcLayoutStyleEl.value)) ? pcLayoutStyleEl.value : 'default';
            const cartIconStyle = (cartBagEl && ['default','groceryCart'].includes(cartBagEl.value)) ? cartBagEl.value : 'default';
            const groceryCartTopColor = (groceryTopEl && groceryTopEl.value.trim()) ? groceryTopEl.value.trim() : '#dc2626';
            const groceryCartBottomColor = (groceryBottomEl && groceryBottomEl.value.trim()) ? groceryBottomEl.value.trim() : '#1f2937';
            const bannerDesign = (bannerEl && ['full','split'].includes(bannerEl.value)) ? bannerEl.value : 'full';
            const footerDesign = (footerEl && ['columns','centered'].includes(footerEl.value)) ? footerEl.value : 'columns';
            const sectionHeaderDesign = (sectionHeaderEl && ['default','centered','underline'].includes(sectionHeaderEl.value)) ? sectionHeaderEl.value : 'default';
            const smallBannersLayout = (smallBannersEl && ['equal','bigSmall'].includes(smallBannersEl.value)) ? smallBannersEl.value : 'equal';
            const promoBannerDesign = (promoBannerEl && ['default','fullBleed','card'].includes(promoBannerEl.value)) ? promoBannerEl.value : 'default';
            const featuredSectionDesign = (featuredEl && ['default','compact','grid'].includes(featuredEl.value)) ? featuredEl.value : 'default';
            const categoryRowsDesign = (categoryRowsEl && ['default','card','minimal'].includes(categoryRowsEl.value)) ? categoryRowsEl.value : 'default';
            const bottomNavEnabled = bottomNavEnabledEl ? !!bottomNavEnabledEl.checked : true;
            const bottomNavDesign = (bottomNavEl && ['default','centerProminent','iconsOnly','hidden'].includes(bottomNavEl.value)) ? bottomNavEl.value : 'default';
            const cartDrawerDesign = (cartDrawerEl && ['default','sheet','minimal'].includes(cartDrawerEl.value)) ? cartDrawerEl.value : 'default';
            const settingsSnap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`));
            const currentLayout = (settingsSnap.val() && settingsSnap.val().layout) ? settingsSnap.val().layout : {};
            const slantedCb = document.getElementById('center-trade-slanted-tabs-enabled');
            const slantedLabelEl = document.getElementById('center-trade-slanted-tab-first-label');
            let slantedTabNavEnabled = !!currentLayout.slantedTabNavEnabled;
            let slantedTabFirstLabel = (currentLayout.slantedTabFirstLabel != null && String(currentLayout.slantedTabFirstLabel).trim() !== '') ? String(currentLayout.slantedTabFirstLabel).trim() : '';
            if (headerDesign === 'centerTrade') {
                slantedTabNavEnabled = !!(slantedCb && slantedCb.checked);
                slantedTabFirstLabel = (slantedLabelEl && slantedLabelEl.value.trim()) ? slantedLabelEl.value.trim() : '';
            }
            const hmShop = document.getElementById('hm-link-shop');
            const hmFeatured = document.getElementById('hm-link-featured');
            const hmWishlist = document.getElementById('hm-link-wishlist');
            const hmAccount = document.getElementById('hm-link-account');
            const hmSupport = document.getElementById('hm-link-support');
            const hamburgerLinks = {
                shop: hmShop ? !!hmShop.checked : true,
                featured: hmFeatured ? !!hmFeatured.checked : true,
                wishlist: hmWishlist ? !!hmWishlist.checked : true,
                account: hmAccount ? !!hmAccount.checked : true,
                support: hmSupport ? !!hmSupport.checked : true
            };
            const desktopHeaderHeightEl = document.getElementById('section-design-desktop-header-height');
            const mobileHeaderHeightEl = document.getElementById('section-design-mobile-header-height');
            const parseLayoutHeaderPx = (el, minPx, maxPx) => {
                if (!el || !String(el.value || '').trim()) return null;
                const n = parseInt(String(el.value).trim(), 10);
                if (!Number.isFinite(n)) return null;
                return Math.min(maxPx, Math.max(minPx, n));
            };
            const headerHeight = parseLayoutHeaderPx(desktopHeaderHeightEl, 48, 200);
            const mobileHeaderHeight = parseLayoutHeaderPx(mobileHeaderHeightEl, 36, 120);
            const searchBarWidthEl = document.getElementById('section-design-desktop-search-max-width');
            const searchBarWidth = parseLayoutHeaderPx(searchBarWidthEl, 200, 1200);
            const headerMainGapPx = parseLayoutHeaderPx(document.getElementById('section-design-header-main-gap'), 4, 64);
            const headerNavGapPx = parseLayoutHeaderPx(document.getElementById('section-design-header-nav-gap'), 4, 64);
            const headerIconGapPx = parseLayoutHeaderPx(document.getElementById('section-design-header-icon-gap'), 4, 64);
            const headerIconSizePcPx = parseLayoutHeaderPx(document.getElementById('section-design-header-icon-size-pc'), 10, 48);
            const headerIconSizeMobilePx = parseLayoutHeaderPx(document.getElementById('section-design-header-icon-size-mobile'), 10, 48);
            const shwapnoGapMainPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-main'), 4, 64);
            const shwapnoGapAppPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-app'), 4, 64);
            const shwapnoGapLangPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-lang'), 4, 64);
            const shwapnoGapAuthPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-auth'), 0, 48);
            const shwapnoGapLogoLocPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-logo'), 0, 64);
            const shwapnoGapRightPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-right'), 0, 48);
            const shwapnoAuthFontSizePx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-auth-font-size'), 10, 24);
            const shwapnoAppImgUrlRaw = (document.getElementById('shwapno-app-img-url')?.value || '').trim();
            const shwapnoAppLinkUrlRaw = (document.getElementById('shwapno-app-link-url')?.value || '').trim();
            const shwapnoAppImgUrl = shwapnoAppImgUrlRaw || null;
            const shwapnoAppLinkUrl = shwapnoAppLinkUrlRaw || null;
            const newLayout = { ...currentLayout, homeLayoutMode, headerDesign, bannerDesign, footerDesign, sectionHeaderDesign, smallBannersLayout, promoBannerDesign, featuredSectionDesign, categoryRowsDesign, bottomNavEnabled, bottomNavDesign, cartDrawerDesign, cartIconStyle, groceryCartTopColor, groceryCartBottomColor, hamburgerMenuStyle, pcLayoutStyle, hamburgerLinks, checkoutAddressForm, slantedTabNavEnabled, slantedTabFirstLabel, headerHeight, mobileHeaderHeight, searchBarWidth, headerMainGapPx, headerNavGapPx, headerIconGapPx, headerIconSizePcPx, headerIconSizeMobilePx, shwapnoGapMainPx, shwapnoGapAppPx, shwapnoGapLangPx, shwapnoGapAuthPx, shwapnoGapLogoLocPx, shwapnoGapRightPx, shwapnoAuthFontSizePx, shwapnoAppImgUrl, shwapnoAppLinkUrl };
            await update(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`), { layout: newLayout });
            siteSettings.layout = newLayout;
            UI.showToast('Section designs saved! Refresh store page to see changes.');
        } catch (err) {
            console.error('Section designs save error:', err);
            UI.showToast('Failed to save section designs.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    const clampTypoPx = (raw) => {
        const x = Number(String(raw ?? '').trim());
        if (!Number.isFinite(x)) return null;
        const n = Math.round(x);
        if (n < 8 || n > 40) return null;
        return n;
    };

    document.getElementById('save-header-design-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });
        try {
            const settingsSnap = await get(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`));
            const snapVal = settingsSnap.val() || {};
            const currentLayout = snapVal.layout && typeof snapVal.layout === 'object' ? { ...snapVal.layout } : {};

            const headerEl = document.getElementById('section-design-header');
            const headerDesign = (headerEl && ['default', 'minimal', 'shwapno', 'centerTrade'].includes(headerEl.value)) ? headerEl.value : 'default';

            const parseLayoutHeaderPx = (el, minPx, maxPx) => {
                if (!el || !String(el.value || '').trim()) return null;
                const n = parseInt(String(el.value).trim(), 10);
                if (!Number.isFinite(n)) return null;
                return Math.min(maxPx, Math.max(minPx, n));
            };
            const desktopHeaderHeightEl = document.getElementById('section-design-desktop-header-height');
            const mobileHeaderHeightEl = document.getElementById('section-design-mobile-header-height');
            const searchBarWidthEl = document.getElementById('section-design-desktop-search-max-width');
            const headerHeight = parseLayoutHeaderPx(desktopHeaderHeightEl, 48, 200);
            const mobileHeaderHeight = parseLayoutHeaderPx(mobileHeaderHeightEl, 36, 120);
            const searchBarWidth = parseLayoutHeaderPx(searchBarWidthEl, 200, 1200);
            const headerMainGapPx = parseLayoutHeaderPx(document.getElementById('section-design-header-main-gap'), 4, 64);
            const headerNavGapPx = parseLayoutHeaderPx(document.getElementById('section-design-header-nav-gap'), 4, 64);
            const headerIconGapPx = parseLayoutHeaderPx(document.getElementById('section-design-header-icon-gap'), 4, 64);
            const headerIconSizePcPx = parseLayoutHeaderPx(document.getElementById('section-design-header-icon-size-pc'), 10, 48);
            const headerIconSizeMobilePx = parseLayoutHeaderPx(document.getElementById('section-design-header-icon-size-mobile'), 10, 48);
            const shwapnoGapMainPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-main'), 4, 64);
            const shwapnoGapAppPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-app'), 4, 64);
            const shwapnoGapLangPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-lang'), 4, 64);
            const shwapnoGapAuthPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-auth'), 0, 48);
            const shwapnoGapLogoLocPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-logo'), 0, 64);
            const shwapnoGapRightPx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-gap-right'), 0, 48);
            const shwapnoAuthFontSizePx = parseLayoutHeaderPx(document.getElementById('section-design-shwapno-auth-font-size'), 10, 24);
            const shwapnoAppImgUrlRaw = (document.getElementById('shwapno-app-img-url')?.value || '').trim();
            const shwapnoAppLinkUrlRaw = (document.getElementById('shwapno-app-link-url')?.value || '').trim();
            const shwapnoAppImgUrl = shwapnoAppImgUrlRaw || null;
            const shwapnoAppLinkUrl = shwapnoAppLinkUrlRaw || null;

            const slantedCb = document.getElementById('center-trade-slanted-tabs-enabled');
            const slantedLabelEl = document.getElementById('center-trade-slanted-tab-first-label');
            let slantedTabNavEnabled = !!currentLayout.slantedTabNavEnabled;
            let slantedTabFirstLabel = (currentLayout.slantedTabFirstLabel != null && String(currentLayout.slantedTabFirstLabel).trim() !== '') ? String(currentLayout.slantedTabFirstLabel).trim() : '';
            if (headerDesign === 'centerTrade') {
                slantedTabNavEnabled = !!(slantedCb && slantedCb.checked);
                slantedTabFirstLabel = (slantedLabelEl && slantedLabelEl.value.trim()) ? slantedLabelEl.value.trim() : '';
            }

            const menuConfig = buildMenuConfigFromHeaderNavRadios(currentLayout);

            const typography = { ...(currentLayout.typography || {}) };
            const pcNav = clampTypoPx(document.getElementById('typo-nav-pc')?.value);
            const mobileNav = clampTypoPx(document.getElementById('typo-nav-mobile')?.value);
            if (pcNav != null || mobileNav != null) {
                typography.nav = {
                    pc: pcNav != null ? pcNav : '',
                    mobile: mobileNav != null ? mobileNav : ''
                };
            } else {
                delete typography.nav;
            }

            const newLayout = {
                ...currentLayout,
                headerDesign,
                headerHeight,
                mobileHeaderHeight,
                searchBarWidth,
                headerMainGapPx,
                headerNavGapPx,
                headerIconGapPx,
                headerIconSizePcPx,
                headerIconSizeMobilePx,
                shwapnoGapMainPx,
                shwapnoGapAppPx,
                shwapnoGapLangPx,
                shwapnoGapAuthPx,
                shwapnoGapLogoLocPx,
                shwapnoGapRightPx,
                shwapnoAuthFontSizePx,
                shwapnoAppImgUrl,
                shwapnoAppLinkUrl,
                slantedTabNavEnabled,
                slantedTabFirstLabel,
                menuConfig,
                typography
            };
            if (!Object.keys(typography).length) {
                delete newLayout.typography;
            }

            const prevColors = { ...(siteSettings?.colors || {}) };
            const hb = colorInput('color-header-bg') || classicColorDefaults.header_bg;
            const ht = colorInput('color-header-text') || classicColorDefaults.header_text;
            const sbBg = colorInput('color-search-btn-bg') || classicColorDefaults.search_btn_bg;
            const sbTx = colorInput('color-search-btn-text') || classicColorDefaults.search_btn_text;
            const newColors = { ...prevColors, header_bg: hb, header_text: ht, header_icon_color: ht, search_btn_bg: sbBg, search_btn_text: sbTx };

            const logoUrl = (document.getElementById('logo-url')?.value || '').trim();

            await saveSettingsSection({ layout: newLayout, colors: newColors, logoUrl }, 'Header design');
            UI.populateSiteSettings(siteSettings);
            const mismatch = typeof UI.countUnmatchedHeaderCustomCategoryNames === 'function'
                ? UI.countUnmatchedHeaderCustomCategoryNames(allCategories)
                : 0;
            if (mismatch > 0) {
                setTimeout(() => {
                    UI.showToast(
                        `Note: ${mismatch} custom strip label(s) are not in your inventory category list yet.`,
                        false
                    );
                }, 400);
            }
        } catch (err) {
            console.error('Header design save error:', err);
            UI.showToast('Failed to save header design.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    document.getElementById('save-typography-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });
        try {
            const typography = {};
            WEBSITE_TYPOGRAPHY_GROUPS.forEach((g) => {
                const pcEl = document.getElementById(`typo-${g}-pc`);
                const mobEl = document.getElementById(`typo-${g}-mobile`);
                const pc = clampTypoPx(pcEl?.value);
                const mobile = clampTypoPx(mobEl?.value);
                if (pc != null || mobile != null) {
                    typography[g] = {
                        pc: pc != null ? pc : '',
                        mobile: mobile != null ? mobile : ''
                    };
                }
            });
            const currentLayout = siteSettings?.layout && typeof siteSettings.layout === 'object' ? { ...siteSettings.layout } : {};
            if (Object.keys(typography).length) currentLayout.typography = typography;
            else delete currentLayout.typography;
            await saveSettingsSection({ layout: currentLayout }, 'Typography');
            UI.populateSiteSettings(siteSettings);
        } catch (err) {
            console.error('Typography save error:', err);
            UI.showToast('Failed to save typography.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    document.getElementById('reset-typography-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        if (!confirm('Remove all custom font sizes and use theme defaults?')) return;
        UI.setLoadingState(true, { button: btn });
        try {
            const currentLayout = siteSettings?.layout && typeof siteSettings.layout === 'object' ? { ...siteSettings.layout } : {};
            delete currentLayout.typography;
            await saveSettingsSection({ layout: currentLayout }, 'Typography');
            UI.populateSiteSettings(siteSettings);
        } catch (err) {
            console.error('Typography reset error:', err);
            UI.showToast('Failed to reset typography.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    document.getElementById('section-design-header')?.addEventListener('change', function () {
        const ctWrap = document.getElementById('center-trade-header-options-wrap');
        if (ctWrap) ctWrap.classList.toggle('hidden', this.value !== 'centerTrade');
        const layout = siteSettings?.layout || {};
        UI.refreshHeaderHeightInputsFromLayout(layout, this.value);
        UI.refreshSearchWidthInputFromLayout(layout, this.value);
    });
    document.querySelectorAll('input[name="header-nav-type"]').forEach((el) => {
        el.addEventListener('change', () => {
            UI.syncHeaderNavCustomCategoriesVisibility();
            window.__refreshHeaderCategoryLinksUi?.();
        });
    });
    UI.syncHeaderNavCustomCategoriesVisibility();
    window.__refreshHeaderCategoryLinksUi?.();
    document.getElementById('section-design-product-card')?.addEventListener('change', function () {
        const style = this.value || 'classic';
        const classicWrap = document.getElementById('section-design-classic-card-size-wrap');
        const appWrap = document.getElementById('section-design-app-card-size-wrap');
        const ocWrap = document.getElementById('order-call-order-now-colors-wrap');
        if (classicWrap) classicWrap.classList.toggle('hidden', style === 'app' || style === 'orderCall');
        if (appWrap) appWrap.classList.toggle('hidden', !['app'].includes(style));
        if (ocWrap) ocWrap.classList.toggle('hidden', style !== 'orderCall');
    });
    document.getElementById('section-design-cart-bag')?.addEventListener('change', function () {
        const wrap = document.getElementById('grocery-cart-colors-wrap');
        if (wrap) wrap.classList.toggle('hidden', this.value !== 'groceryCart');
    });
    document.getElementById('cat-product-spacing-enabled')?.addEventListener('change', () => {
        UI.syncCategoryProductSpacingInputs();
    });
    UI.syncCategoryProductSpacingInputs();

    // Category Display (standalone panel) save
    document.getElementById('save-category-display-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        const layoutRadio = document.querySelector('input[name="cat-display-layout"]:checked');
        const shapeRadio = document.querySelector('input[name="cat-display-shape"]:checked');
        const cardStyleRadio = document.querySelector('input[name="cat-display-card-style"]:checked');
        const sizeDesktop = document.getElementById('cat-display-size-desktop');
        const sizeMobile = document.getElementById('cat-display-size-mobile');
        const spaceBetween = document.getElementById('cat-display-space-between');
        const rowsDesktopEl = document.getElementById('cat-display-rows-desktop');
        const rowsMobileEl = document.getElementById('cat-display-rows-mobile');
        const perRowDesktopEl = document.getElementById('cat-display-per-row-desktop');
        const perRowMobileEl = document.getElementById('cat-display-per-row-mobile');
        const equalTabsCountEl = document.getElementById('cat-equal-tabs-category-count');
        const equalTabsCountRaw = equalTabsCountEl ? parseInt(equalTabsCountEl.value, 10) : 4;
        const selectedHeaderCategories = Array.from(document.querySelectorAll('input[name="header-categories"]:checked'))
            .map((el) => String(el.value || '').trim())
            .filter(Boolean);
        const selectedHomeThumbnailCategories = Array.from(document.querySelectorAll('input[name="home-thumbnail-categories"]:checked'))
            .map((el) => String(el.value || '').trim())
            .filter(Boolean);
        const headerCategoryIcons = {};
        document.querySelectorAll('input[name="header-category-icons"]').forEach((el) => {
            const key = String(el.dataset.categoryName || '').trim();
            const val = String(el.value || '').trim();
            if (key && val) headerCategoryIcons[key] = val;
        });
        UI.setLoadingState(true, { button: btn });
        try {
            const currentLayout = siteSettings.layout || {};
            const categoryConfig = {
                ...(currentLayout.categoryConfig || {}),
                layoutType: (layoutRadio && layoutRadio.value === 'grid') ? 'grid' : 'swiper',
                cardStyle: (cardStyleRadio && ['chaldal','shwapno'].includes(cardStyleRadio.value)) ? cardStyleRadio.value : 'default',
                shape: (shapeRadio && shapeRadio.value === 'square') ? 'square' : 'round',
                sizeDesktop: sizeDesktop ? Math.min(250, Math.max(100, parseInt(sizeDesktop.value) || 170)) : 170,
                sizeMobile: sizeMobile ? Math.min(140, Math.max(56, parseInt(sizeMobile.value) || 96)) : 96,
                spaceBetween: spaceBetween ? Math.min(40, Math.max(0, parseInt(spaceBetween.value) || 10)) : 10,
                rowsDesktop: rowsDesktopEl ? Math.min(5, Math.max(1, parseInt(rowsDesktopEl.value) || 1)) : 1,
                rowsMobile: rowsMobileEl ? Math.min(5, Math.max(1, parseInt(rowsMobileEl.value) || 1)) : 1,
                categoriesPerRowDesktop: perRowDesktopEl ? Math.min(8, Math.max(2, parseInt(perRowDesktopEl.value) || 4)) : 4,
                categoriesPerRowMobile: perRowMobileEl ? Math.min(6, Math.max(1, parseInt(perRowMobileEl.value) || 3)) : 3,
                mobileHeroEqualTabsEnabled: !!(document.getElementById('cat-equal-tabs-enabled')?.checked),
                mobileHeroEqualTabsFirstLabel: (document.getElementById('cat-equal-tabs-first-label')?.value || '').trim(),
                mobileHeroEqualTabsCategoryCount: Math.min(8, Math.max(1, !isNaN(equalTabsCountRaw) ? equalTabsCountRaw : 4)),
                headerCategories: selectedHeaderCategories,
                headerCategoryIcons,
                homeThumbnailCategoryNames: selectedHomeThumbnailCategories,
                categoryPageBannerEnabled: !!(document.getElementById('cat-category-page-banner-enabled')?.checked),
                showCategoryDescription: !!(document.getElementById('cat-show-category-description')?.checked)
            };
            const menuRadio = document.querySelector('input[name="menu-show-categories"]:checked');
            const showCategoriesInMenu = menuRadio && menuRadio.value === 'yes';
            const menuConfig = buildMenuConfigFromHeaderNavRadios(currentLayout);
            menuConfig.showCategoriesInMenu = showCategoriesInMenu;
            const activeDesign = 'classic';
            const newLayout = { ...currentLayout, categoryConfig, menuConfig, activeDesign };
            await update(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`), { layout: newLayout });
            siteSettings.layout = newLayout;
            refreshHeaderCategoriesSelector();
            UI.showToast('Category display saved!');
        } catch (err) {
            console.error(err);
            UI.showToast('Failed to save.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    // Website Icons save
    document.getElementById('save-website-icons-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });
        try {
            const iconConfig = {};
            UI.WEBSITE_ICON_SLOTS.forEach(slot => {
                const typeRadio = document.querySelector(`input[name="icon-type-${slot.id}"]:checked`);
                const type = typeRadio && typeRadio.value === 'custom' ? 'custom' : 'fontawesome';
                const presetEl = document.getElementById(`icon-preset-${slot.id}`);
                const customEl = document.getElementById(`icon-custom-${slot.id}`);
                const value = type === 'custom' && customEl && customEl.value.trim()
                    ? customEl.value.trim()
                    : (presetEl ? presetEl.value : slot.default);
                iconConfig[slot.id] = { type, value };
            });
            const currentLayout = siteSettings.layout || {};
            const newLayout = { ...currentLayout, iconConfig, activeDesign: currentLayout.activeDesign || 'classic' };
            await update(ref(db, `clients/${CURRENT_CLIENT_ID}/siteSettings`), { layout: newLayout });
            siteSettings.layout = newLayout;
            UI.showToast('Website icons saved!');
        } catch (err) {
            console.error(err);
            UI.showToast('Failed to save icons.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    // Dynamic Form Elements
    document.getElementById('add-gallery-image-btn')?.addEventListener('click', () => UI.addGalleryImageRow());
    document.getElementById('add-shipping-option-btn')?.addEventListener('click', () => UI.addShippingOptionRow());
    document.getElementById('add-main-slide-btn')?.addEventListener('click', () => UI.addMainSlideRow());
    UI.initMainSliderBannerPreviewListeners();
    UI.initBannersSubNav();

    // Edit Order Event Listeners
    document.getElementById('edit-order-add-item-btn')?.addEventListener('click', addItemToEditOrder);
    document.getElementById('edit-order-shipping')?.addEventListener('input', recalculateEditOrderTotal);
    
    document.getElementById('product-has-variants')?.addEventListener('change', (e) => { 
        const isChecked = e.target.checked; 
        document.getElementById('product-non-variant-options').classList.toggle('hidden', isChecked); 
        document.getElementById('product-variant-options').classList.toggle('hidden', !isChecked); 
        document.getElementById('product-sale-price').required = !isChecked; 
    });

    // Inputs & Search (delegated for lazy-loaded settings panel)
    document.addEventListener('input', (e) => {
        const target = e.target;
        if (!(target instanceof Element)) return;
        if (target.id !== 'order-search') return;
        orderState.searchTerm = target.value;
        orderState.currentPage = 1;
        renderCompletedOrders();
    });
    document.addEventListener('change', (e) => {
        const target = e.target;
        if (!(target instanceof Element)) return;
        if (target.id === 'order-page-size') {
            orderState.itemsPerPage = parseInt(target.value, 10) || 20;
            orderState.currentPage = 1;
            renderCompletedOrders();
            return;
        }
        if (target.id === 'order-date-filter') {
            orderState.dateYmd = target.value || '';
            orderState.currentPage = 1;
            renderCompletedOrders();
        }
    });
    // UI Toggles
    document.getElementById('open-sidebar-btn')?.addEventListener('click', () => UI.toggleSidebar(true));
    document.getElementById('close-sidebar-btn')?.addEventListener('click', () => UI.toggleSidebar(false));
    document.getElementById('sidebar-overlay')?.addEventListener('click', () => UI.toggleSidebar(false));
    document.body.addEventListener('click', (e) => {
        if (e.target.closest('#logout-btn') || e.target.closest('#logout-sidebar-btn')) { e.preventDefault(); handleLogout(); return; }
        if (e.target.closest('#profile-btn')) {
            e.preventDefault();
            openProfileModalWithAdminPrep();
        }
    });
    document.getElementById('share-btn')?.addEventListener('click', () => UI.toggleModal('share-modal', true));

    // Swapno full theme (layout + colors) — dedicated panel / button when present
    document.getElementById('apply-swapno-preset-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });
        try {
            const patch = UI.buildSwapnoThemePresetUpdate(siteSettings);
            await saveSettingsSection(patch, 'Swapno Theme');
            normalizeLegacySwapnoActiveDesignInSiteSettings(siteSettings);
            UI.populateSiteSettings(siteSettings);
        } catch (err) {
            console.error(err);
            UI.showToast('Swapno theme save failed.', false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });

    // Theme Save Listener
    document.getElementById('save-theme-btn')?.addEventListener('click', async (e) => {
        const btn = e.target.closest('button');
        UI.setLoadingState(true, { button: btn });

        try {
            const selectedTheme = document.querySelector('input[name="layout-design"]:checked')?.value;
            if (!selectedTheme) {
                UI.showToast("Please select a theme.", false);
                return;
            }

            const dataToSave = {
                layout: {
                    ...siteSettings.layout,
                    activeDesign: selectedTheme
                }
            };

            await saveSettingsSection(dataToSave, 'Theme Settings');
            UI.toggleModal('theme-change-modal', false);

        } catch (error) {
            console.error(error);
            UI.showToast("Failed to save theme.", false);
        } finally {
            UI.setLoadingState(false, { button: btn });
        }
    });
    
    // Modal Closers
    document.querySelectorAll('[id^="close-"][id$="-btn"], [id^="cancel-"]').forEach(btn => { 
        btn.addEventListener('click', () => {
            const modal = btn.closest('.fixed');
            if(modal) UI.toggleModal(modal.id, false);
        }); 
    });
    
    document.getElementById('copy-link-btn')?.addEventListener('click', (e) => { 
        navigator.clipboard.writeText(document.getElementById('website-link-input').value); 
        e.target.textContent = 'Copied!'; 
        setTimeout(() => e.target.textContent = 'Copy', 2000); 
    });
    
    document.getElementById('go-to-hosting-btn')?.addEventListener('click', () => { UI.toggleModal('force-hosting-modal', false); showDashboardPanel('hosting'); });
    document.getElementById('go-to-hosting-from-lock-btn')?.addEventListener('click', () => { UI.toggleModal('feature-locked-modal', false); showDashboardPanel('hosting'); });
    document.getElementById('image-upload-input')?.addEventListener('change', e => { if (e.target.files[0]) UI.handleImageUpload(e.target.files[0]); });
    
    // Cancel Buttons
    document.getElementById('category-cancel-btn')?.addEventListener('click', UI.resetCategoryForm);
    document.getElementById('add-subcategory-btn')?.addEventListener('click', UI.addSubcategoryFromInput);
    document.getElementById('subcategory-name-input')?.addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
            e.preventDefault();
            UI.addSubcategoryFromInput();
        }
    });
    document.addEventListener('change', (e) => {
        if (e.target && e.target.name === 'product-categories') {
            UI.refreshProductSubcategoryDropdown(allCategories);
        }
    });
    UI.renderSubcategoryList([]);
    UI.populateProductSubcategoryDropdown([]);
    document.getElementById('product-cancel-btn')?.addEventListener('click', resetProductForm);

    document.getElementById('ai-ads-dash-generate-btn')?.addEventListener('click', (e) => {
        e.preventDefault();
        handleAiAdsDashGenerate();
    });
    document.getElementById('ai-ads-dash-copy-image-prompt-btn')?.addEventListener('click', async () => {
        const field = document.getElementById('ai-ads-dash-image-prompt');
        const text = field?.value?.trim() || '';
        if (!text) {
            UI.showToast('No image prompt to copy.', false);
            return;
        }
        try {
            await navigator.clipboard.writeText(text);
            UI.showToast('Image prompt copied.');
        } catch (_) {
            UI.showToast('Could not copy image prompt.', false);
        }
    });
        document.getElementById('ai-ads-dash-launch-btn')?.addEventListener('click', (e) => {
            e.preventDefault();
            UI.showToast('Marketers Brain: Facebook Marketing API launch is coming soon. Use Integrations for token & ad account.', false);
        });
        bindAdminTeamManagementUi();
        listenersBound = true;
    } catch (err) {
        listenersBound = false;
        console.error('setupEventListeners failed:', err);
        UI.showToast('Some dashboard actions failed to initialize. Please refresh.', false);
        throw err;
    }
}

// --- 6. LOADER & AUTH CHECK ---

async function ensureSettingsPanelsLoaded() {
    if (dashboardPanelsLoaded.settings) {
        dedupeCompletedOrdersPanelDom();
        return true;
    }
    if (settingsPanelsLoadingPromise) return settingsPanelsLoadingPromise;
    const host = document.getElementById('dashboard-content');
    if (!host) return false;
    settingsPanelsLoadingPromise = (async () => {
        try {
            const settingsResponse = await fetch('dashboard-settings.html', { cache: 'default' });
            if (!settingsResponse.ok) throw new Error('Failed to load settings panels');
            const settingsHTML = await settingsResponse.text();
            host.insertAdjacentHTML('beforeend', settingsHTML);
            dedupeCompletedOrdersPanelDom();
            dashboardPanelsLoaded.settings = true;
            bindDashboardLazySettingsPanelListeners();
            applySidebarPermissionVisibility();
            try {
                if (siteSettings && typeof siteSettings === 'object' && Object.keys(siteSettings).length) {
                    UI.populateSiteSettings(siteSettings);
                }
            } catch (hydrateErr) {
                console.warn('populateSiteSettings after settings panels load:', hydrateErr);
            }
            if (isPanelActive('completed-orders')) renderCompletedOrders();
            return true;
        } catch (error) {
            console.error('Error loading settings panels:', error);
            throw error;
        } finally {
            settingsPanelsLoadingPromise = null;
        }
    })();
    return settingsPanelsLoadingPromise;
}

/** Shared header-spacing docs modal — single file `assets/spacing-docs-modal.html` (avoid duplicating IDs in HTML shells). */
async function injectSpacingDocsModalInto(container) {
    if (!container || container.querySelector('#spacing-docs-modal')) return;
    try {
        const r = await fetch('assets/spacing-docs-modal.html', { cache: 'default' });
        if (!r.ok) return;
        const html = (await r.text()).trim();
        if (!html) return;
        container.insertAdjacentHTML('afterbegin', html);
    } catch (e) {
        console.warn('[Dashboard] Could not load spacing-docs modal fragment:', e);
    }
}

async function loadDashboardPanels() {
    try {
        if (typeof window !== 'undefined' && window.location.protocol === 'file:') {
            console.warn('[Dashboard] Serve over HTTP (e.g. live-server), not file:// — fetch of dashboard-main.html may fail.');
        }
        document.querySelectorAll('body > #add-new-menu').forEach((el) => el.remove());
        const mainResponse = await fetch('dashboard-main.html', { cache: 'default' });
        if (!mainResponse.ok) throw new Error('Failed to load dashboard shell');
        const mainHTML = await mainResponse.text();
        const host = document.getElementById('dashboard-content');
        host.innerHTML = mainHTML;
        await injectSpacingDocsModalInto(host);
        reorderHomeSectionsSafely();
        dashboardPanelsLoaded.main = true;
        syncDashboardContentFitViewportClass();
        bindDashboardChromeUI();
        // Lazy load settings after first paint/idle.
        const lazyLoadSettings = () => ensureSettingsPanelsLoaded().catch(() => {});
        if (typeof requestIdleCallback === 'function') requestIdleCallback(lazyLoadSettings, { timeout: 1800 });
        else setTimeout(lazyLoadSettings, 600);
    } catch (error) {
        console.error('Error loading dashboard panels:', error);
        document.getElementById('dashboard-content').innerHTML = '<p class="text-center text-red-500 p-8">Error loading components. Please refresh.</p>';
    }
}

async function initializeAppOnLoad() {
    const forceHideLoader = () => {
        const loader = document.getElementById('dashboard-loader');
        if (!loader) return;
        loader.style.pointerEvents = 'none';
        loader.style.visibility = 'hidden';
        loader.classList.add('opacity-0');
        loader.style.display = 'none';
    };
    const fadeOutLoader = () => {
        const loader = document.getElementById('dashboard-loader');
        if (!loader) return;
        loader.style.pointerEvents = 'none';
        loader.style.visibility = 'hidden';
        loader.classList.add('opacity-0');
        setTimeout(() => {
            loader.style.display = 'none';
        }, 300);
    };

    const loaderTimeout = setTimeout(() => {
        const loader = document.getElementById('dashboard-loader');
        if(loader && loader.style.display !== 'none') {
            console.warn("Loader timeout - forcing display");
            forceHideLoader();
        }
    }, 10000);

    onAuthStateChanged(auth, async (user) => {
        try {
            if (user) {
                const savedSiteInfo = localStorage.getItem('siteInfo');
                if (!savedSiteInfo) { console.error("Auth state inconsistency."); handleLogout(); return; }
                SITE_INFO = JSON.parse(savedSiteInfo);
                const authorized = await verifySiteInfoAuthorizedAdmin(user);
                if (!authorized) {
                    console.error("siteInfo.clientId does not match this user as client admin.");
                    localStorage.removeItem('siteInfo');
                    await signOut(auth);
                    window.location.href = 'setup.html';
                    return;
                }
                await loadDashboardPanels();
                setupEventListeners();
                await prepareAndShowDashboard();
                
            } else { 
                localStorage.clear(); 
                window.location.href = 'setup.html'; 
            }
        } catch (e) {
            console.error("Initialization Error:", e);
            UI.showToast("Error loading dashboard. Check console.", false);
        } finally {
            clearTimeout(loaderTimeout);
            fadeOutLoader();
        }
    });
}

// Run App
initializeAppOnLoad();